/* ==========================================================================
   Aries Labs -- arieslabs.org -- v1
   Direction: "Split Meridian" (d2), with the token, type, spacing, card-grid
   and accent discipline grafted from "Faceted Monolith" (d1) and the derived
   line token and hero split-rule from "Editorial Premium" (d3).

   Dark only. No network requests. No build step. Hand written.
   Every colour is a token on :root. Nothing outside :root is a literal hex
   except the two inert SVG templates in the markup, which are geometry.
   ========================================================================== */

/* --------------------------------------------------------------------------
   UPGRADE SLOT -- self-hosted variable font.
   Leave this commented until the woff2 ships beside this file. The stack below
   resolves to a system geometric-humanist face until then, and the network
   stays silent either way. No @import. No font CDN. Ever.

@font-face {
  font-family: "Inter var";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/InterVariable.woff2") format("woff2");
}
   -------------------------------------------------------------------------- */

:root {
  color-scheme: dark;

  /* ---- surfaces (measured brand values) ---- */
  --canvas:   #1B1E25;
  --well:     #15181F;
  --raised:   #21252E;
  --hairline: #2E333E;

  /* ---- derived structural line ----
     --hairline is 1.21:1 on raised and 1.32:1 on canvas: decorative only.
     --line-strong is 3.54:1 on canvas and is the ONLY token allowed to carry
     a control or component boundary. AA for UI borders is 3:1. */
  --line-strong: #6B7484;

  /* ---- text ---- */
  --text-1: #F2F4F7;   /* 15.2:1 on canvas  -- headings, primary copy      */
  --text-2: #A8B0BD;   /*  7.48:1 on canvas -- secondary running copy      */
  --text-3: #7A8391;   /*  4.27:1 on canvas -- FAILS body on canvas.
                           4.64:1 on well   -- passes, and only used there */

  /* ---- ember ramp, light to deep ---- */
  --ember-0: #ED893E;  /* 6.44:1 on canvas -- the ONLY ember used as text */
  --ember-1: #E8703C;  /* 5.31:1 */
  --ember-2: #D84D3A;  /* 3.93:1 -- large text and rules only */
  --ember-3: #C53E38;
  --ember-4: #A41A33;
  --ember-5: #712B2F;

  /* ---- ice ramp, light to deep ---- */
  --ice-0: #A2DDD7;    /* 11.01:1 -- focus rings, link hover */
  --ice-1: #97D5D4;    /*  9.95:1 -- the Live status */
  --ice-2: #7FBBC6;    /*  7.65:1 */
  --ice-3: #629FB1;
  --ice-4: #5E91B0;
  --ice-5: #386C91;

  /* ---- the section accent in force; sections override ---- */
  --accent: var(--ice-0);

  /* ---- type scale: seven sizes, four line heights, nothing else ---- */
  --font: "Inter var", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --fs-eyebrow: 0.75rem;
  --fs-small:   0.875rem;
  --fs-body:    1.0625rem;
  --fs-lead:    clamp(1.125rem, 1rem + 0.6vw, 1.375rem);
  --fs-h3:      1.25rem;
  --fs-h2:      clamp(1.75rem, 1.3rem + 2vw, 2.625rem);
  --fs-display: clamp(2.5rem, 1.6rem + 4.6vw, 4.75rem);

  /* ---- spacing lattice ---- */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 144px;

  --gutter:  clamp(16px, 5vw, 56px);
  --content: 1120px;
  --measure: 62ch;
  --seam:    64px;          /* the centre column at desktop */

  --radius: 6px;
  --ease:   cubic-bezier(0.2, 0.7, 0.2, 1);
  --t-rev:  760ms;
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--text-1);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* No overflow-x rule on body. Clipping the overflow would satisfy the
   no-horizontal-scroll requirement by disabling the detector: any element that
   did overflow would be silently unreachable instead of visibly wrong. The
   layout is built so nothing overflows; if something ever does, it shows. */

img { display: block; max-width: 100%; height: auto; }
h1, h2, h3, p { margin: 0; }
ul, ol, dl, dd { margin: 0; padding: 0; }
ul { list-style: none; }

a { color: inherit; text-decoration-color: var(--text-3); text-underline-offset: 0.18em; }
a:hover { text-decoration-color: currentColor; }

:focus-visible { outline: 2px solid var(--ice-0); outline-offset: 4px; border-radius: 2px; }
::selection { background: var(--ice-3); color: var(--canvas); }

/* The skip link's destination takes focus without drawing a ring of its own. */
main:focus { outline: none; }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

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

.skip {
  position: absolute;
  left: var(--gutter);
  top: -120px;
  z-index: 30;
  padding: var(--s-2) var(--s-4);
  background: var(--text-1);
  color: var(--canvas);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  font-weight: 600;
  text-decoration: none;
}
.skip:focus { top: var(--s-3); }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   Type
   ========================================================================== */

h1, h2, h3 { font-weight: 600; line-height: 1.08; letter-spacing: -0.025em; }
h1 { font-size: var(--fs-display); letter-spacing: -0.035em; text-wrap: balance; }
h2 { font-size: var(--fs-h2); text-wrap: balance; }
h3 { font-size: var(--fs-h3); letter-spacing: -0.015em; line-height: 1.2; }

.eyebrow {
  display: block;
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--s-4);
}

.lead { font-size: var(--fs-lead); line-height: 1.5; color: var(--text-2); }
.prose { color: var(--text-2); line-height: 1.6; }
.prose p + p { margin-top: var(--s-4); }
.small { font-size: var(--fs-small); }

.pullout {
  margin-top: var(--s-6);
  font-size: var(--fs-lead);
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.35;
  color: var(--text-1);
  max-width: 28ch;
  padding-left: var(--s-5);
  border-left: 1px solid var(--accent);
}

/* ==========================================================================
   Buttons and links
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: 44px;
  padding: 0 var(--s-5);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--text-1);
  text-decoration: none;
  transition: border-color 200ms var(--ease), color 200ms var(--ease),
              background-color 200ms var(--ease);
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn--solid { background: var(--text-1); color: var(--canvas); border-color: var(--text-1); }
.btn--solid:hover { background: var(--accent); border-color: var(--accent); color: var(--canvas); }
.btn--sm { min-height: 36px; padding: 0 var(--s-4); font-size: var(--fs-small); }

.link {
  color: var(--text-1);
  text-decoration: underline;
  text-decoration-color: var(--text-3);
  text-decoration-thickness: 1px;
  transition: color 200ms var(--ease), text-decoration-color 200ms var(--ease);
  overflow-wrap: anywhere;
}
.link:hover { color: var(--ice-0); text-decoration-color: var(--ice-0); }

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  border-bottom: 1px solid var(--hairline);
  background: var(--canvas);
}
.site-header .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4);
  min-height: 68px;
}
.brand { display: inline-flex; align-items: center; text-decoration: none; }
/* The supplied wordmark raster is opaque, on a ground near #15181D. That is
   not --canvas, so on the header it would otherwise read as a faint darker
   plate. `lighten` resolves the ground to whichever surface is behind it --
   canvas in the header, well in the footer -- while the white glyphs, which
   are already the lighter value, are untouched. Replace this with a
   transparent PNG when one exists and the blend mode becomes a no-op. */
.brand img { width: 78px; height: auto; mix-blend-mode: lighten; }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero { padding-block: var(--s-7) var(--s-8); }
@media (min-width: 768px) { .hero { padding-block: var(--s-8) var(--s-9); } }

.hero-band {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  align-items: center;
  min-height: 220px;
}
@media (min-width: 768px) {
  .hero-band { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); min-height: 300px; }
}

/* The vertical seam: the meridian, running down through the mark's own split.
   It is the hero moment's first half; the horizontal rule below is its second. */
.hero-seam {
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 1px;
  margin-left: -0.5px;
  z-index: 1;
  background: linear-gradient(to bottom,
    rgba(237, 137, 62, 0) 0%,
    var(--ember-0) 34%,
    var(--ice-0) 100%);
  transform-origin: top center;
}

/* Abstract facet fields: angular planes, warm left, cool right. Never a ram.
   Hidden below 768px, where there is no room for them beside the mark. */
.facet { display: none; }
@media (min-width: 768px) {
  .facet { display: block; position: relative; align-self: stretch; min-height: 240px; overflow: hidden; }
  .facet svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
  .facet--warm {
    -webkit-mask-image: linear-gradient(to right, #000 26%, transparent 94%);
            mask-image: linear-gradient(to right, #000 26%, transparent 94%);
  }
  .facet--cool {
    -webkit-mask-image: linear-gradient(to left, #000 26%, transparent 94%);
            mask-image: linear-gradient(to left, #000 26%, transparent 94%);
  }
}

.mark {
  position: relative;
  z-index: 2;
  width: clamp(200px, 58vw, 360px);
  aspect-ratio: 642 / 506;
}
/* The left half is a decorative pseudo-element and the right half is the real
   <img>. One image element, one alt, one node in the accessibility tree -- and
   still two halves that can converge on the seam. A second <img> would need an
   empty alt, which duplicates the mark for assistive tech and fails the lane's
   image-alt rule. */
.mark::before {
  content: "";
  position: absolute; inset: 0;
  background-image: url("../img/aries-mark.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  clip-path: inset(0 50% 0 0);
}
.mark img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  clip-path: inset(0 0 0 50%);
}

.hero-copy {
  margin-top: var(--s-7);
  display: grid;
  justify-items: center;
  text-align: center;
}
.hero-copy h1 { max-width: 14ch; }

/* The one hero gradient moment: the mark's warm/cool split rendered as
   typographic furniture, crossing the seam at exactly 50%. */
.hero-rule {
  display: block;
  height: 2px;
  width: min(720px, 100%);
  margin-block: var(--s-6);
  background: linear-gradient(90deg,
    var(--ember-5) 0%, var(--ember-0) 38%, var(--ice-0) 62%, var(--ice-5) 100%);
  transform-origin: center;
}

.hero-copy .lead { max-width: 54ch; }
.hero-actions {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--s-3);
  margin-top: var(--s-6);
}

/* ==========================================================================
   The document spine and the split grid
   ========================================================================== */

.doc { position: relative; }

/* Below the hero the meridian resolves to a single hairline-weight line. The
   duality is a hero moment and a set of section accents, not an ambient wash. */
.spine { display: none; }
@media (min-width: 768px) {
  .spine {
    display: block;
    position: absolute;
    top: 0; bottom: 0; left: 50%;
    width: 1px;
    margin-left: -0.5px;
    background: var(--hairline);
    transform-origin: top center;
  }
}

.section { padding-block: var(--s-8); }
@media (min-width: 1024px) { .section { padding-block: var(--s-9); } }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: var(--s-7);
  align-items: start;
}
@media (min-width: 768px) {
  .split {
    grid-template-columns: minmax(0, 1fr) var(--seam) minmax(0, 1fr);
    column-gap: 0;
  }
  .split > .col-left  { grid-column: 1; }
  .split > .col-right { grid-column: 3; }
  .split > .col-wide  { grid-column: 1 / -1; }
}

/* A block that hangs off the meridian.
   Phone: a short accent rule above the eyebrow.
   Desktop: a tick that reaches the seam and a dot whose CENTRE is derived from
   the tick's endpoint by transform, never by a hand-tuned pixel offset.
   Column 1 ends at 50% - seam/2, so a tick of seam/2 lands exactly on 50%. */
.hang::before {
  content: "";
  display: block;
  width: 28px; height: 2px;
  background: var(--accent);
  margin-bottom: var(--s-4);
}
@media (min-width: 768px) {
  .hang { position: relative; }
  .hang::before {
    position: absolute;
    top: 0.6em;
    width: calc(var(--seam) / 2);
    height: 1px;
    margin: 0;
  }
  .hang::after {
    content: "";
    position: absolute;
    top: calc(0.6em - 2px);
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--accent);
  }
  .hang.col-left::before  { right: calc(var(--seam) / -2); }
  .hang.col-left::after   { right: calc(var(--seam) / -2); transform: translateX(50%); }
  .hang.col-right::before { left: calc(var(--seam) / -2); }
  .hang.col-right::after  { left: calc(var(--seam) / -2); transform: translateX(-50%); }
}

/* Section heads face the seam. Display type only -- running copy is never
   right-aligned, at any width. */
@media (min-width: 768px) {
  .head.col-left { text-align: right; }
  .head.col-left .eyebrow,
  .head.col-left h1,
  .head.col-left h2 { text-align: right; }
  .head.col-left .prose,
  .head.col-left .lead,
  .head.col-left p,
  .head.col-left dl,
  .head.col-left ul { text-align: left; margin-left: auto; }
}

/* Section accent assignment. Exactly one ember is ever used as text. */
.tone-warm { --accent: var(--ember-0); }
.tone-cool { --accent: var(--ice-0); }

/* ==========================================================================
   Definition lists (term / value pairs)
   ========================================================================== */

.facts {
  margin-top: var(--s-6);
  border-top: 1px solid var(--hairline);
  display: grid;
  grid-template-columns: minmax(0, 7rem) minmax(0, 1fr);
  column-gap: var(--s-4);
  font-size: var(--fs-small);
}
@media (min-width: 768px) { .facts { grid-template-columns: minmax(0, 9rem) minmax(0, 1fr); } }
.facts dt {
  grid-column: 1;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hairline);
  font-weight: 600;
  color: var(--text-1);
}
.facts dd {
  grid-column: 2;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--text-2);
}

/* ==========================================================================
   Product grid
   One declaration draws perfect single-pixel rules between cells: no double
   borders, no per-card arithmetic, correct at 1, 2 and 3 columns. The grid
   line carries structure, so it is --line-strong (3.54:1), not --hairline.
   ========================================================================== */

.cards {
  margin-top: var(--s-7);
  display: grid;
  gap: 1px;
  background: var(--line-strong);
  border: 1px solid var(--line-strong);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 640px)  { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.card {
  position: relative;
  background: var(--canvas);
  padding: var(--s-6) var(--s-5) var(--s-5);
  min-height: 280px;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: var(--s-4);
  align-content: start;
}
@media (min-width: 768px) { .card { padding: var(--s-6); } }

/* Hover signal is the section accent, drawn as a top edge. The rest state
   already has a boundary; hover adds meaning rather than supplying it. */
.card::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: -1px;
  height: 1px;
  background: var(--accent);
  opacity: 0;
  transition: opacity 260ms var(--ease);
}
.card--named:hover::before,
.card--named:focus-within::before { opacity: 1; }

.card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.card-ord {
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--text-2);
}

/* Status: a closed set, driven by an exact data-status value. The vocabulary
   cannot drift because there is one place to change it, and the attribute
   carries the sanctioned casing so nothing re-cases it for display. */
.status {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-2);
  white-space: nowrap;
}
.status::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.status[data-status="Live"]            { color: var(--ice-1); }
.status[data-status="Private era"]     { color: var(--text-1); }
.status[data-status="Private era"]::before { background: transparent; box-shadow: inset 0 0 0 1.5px currentColor; }
.status[data-status="Upcoming"]        { color: var(--ember-0); }
.status[data-status="In development"]  { color: var(--text-3); }

.card h3 { color: var(--text-1); }

.card-lines { display: grid; gap: var(--s-3); color: var(--text-2); font-size: var(--fs-small); line-height: 1.6; }
.card-lines p { max-width: 40ch; }
/* A figure line: a sanctioned value that should read with weight while staying
   one byte-exact, un-paraphrasable data value. */
.card-lines .figure {
  color: var(--text-1);
  font-weight: 500;
  font-size: var(--fs-body);
  letter-spacing: -0.01em;
}

.card-links {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-3) var(--s-5);
  align-self: end;
  padding-top: var(--s-3);
}
.card-links a { font-size: var(--fs-small); font-weight: 600; overflow-wrap: anywhere; }
.card-links a.is-primary { color: var(--text-1); text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
.card-links a.is-primary svg { width: 14px; height: 14px; transition: transform 220ms var(--ease); }
.card-links a.is-primary:hover { color: var(--ice-0); }
.card-links a.is-primary:hover svg { transform: translateX(3px); }

/* Teaser: the muted card is the one that recedes. Darker ground, quieter text,
   an abstract facet ghost, no anchors, no name, no description. */
.card--teaser { background: var(--well); }
.card--teaser .card-category {
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--text-2);
  line-height: 1.2;
}
.card--teaser .card-ord { color: var(--text-3); }
.facet-ghost { align-self: end; justify-self: start; width: 44px; height: 44px; opacity: 0.6; }

/* ==========================================================================
   Contact
   ========================================================================== */

.contact-list { display: grid; margin-top: var(--s-5); }
.contact-list > div {
  display: grid;
  grid-template-columns: minmax(84px, 140px) minmax(0, 1fr);
  gap: var(--s-2) var(--s-4);
  padding: var(--s-4) 0;
  border-top: 1px solid var(--hairline);
}
.contact-list > div:last-child { border-bottom: 1px solid var(--hairline); }
.contact-list dt {
  color: var(--text-2);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding-top: 2px;
}
.contact-list dd a { overflow-wrap: anywhere; }

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  background: var(--well);
  border-top: 1px solid var(--hairline);
  padding-block: var(--s-7) var(--s-8);
  margin-top: var(--s-8);
}
.site-footer .wrap { display: grid; gap: var(--s-5); }
.footer-row {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-4) var(--s-6);
}
.footer-row .brand img { width: 66px; }
.footer-nav { display: flex; gap: var(--s-5); }
.footer-nav a { font-size: var(--fs-small); color: var(--text-2); }
.footer-nav a:hover { color: var(--text-1); }
.footer-tagline { color: var(--text-2); font-size: var(--fs-small); }

.footer-legal { display: grid; gap: var(--s-3); max-width: 70ch; }
/* The non-affiliation clause is load-bearing mitigation. It does not sit at
   13px in the dimmest text on the page. */
.footer-legal .nonaffiliation {
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text-1);
}
.footer-legal .entity,
.footer-legal .copyright { font-size: var(--fs-small); color: var(--text-2); }

/* ==========================================================================
   Legal pages -- same system, a reading measure, numbered sections
   ========================================================================== */

.legal-page { padding-block: var(--s-7) var(--s-8); }
.legal-head { max-width: 68ch; }
.legal-head .back {
  display: inline-block;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-2);
  margin-bottom: var(--s-5);
}
.legal-head .back:hover { color: var(--text-1); }
.legal-head h1 { font-size: var(--fs-h2); }
.legal-head .doc-version {
  margin-top: var(--s-4);
  font-size: var(--fs-small);
  color: var(--text-2);
  letter-spacing: 0.04em;
}
.legal-head .hero-rule { width: min(560px, 100%); margin-block: var(--s-6); }

.notice {
  max-width: 68ch;
  margin-bottom: var(--s-6);
  padding: var(--s-5);
  background: var(--raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text-1);
  font-size: var(--fs-small);
  line-height: 1.6;
}
.notice strong { font-weight: 700; }
.notice + .notice { margin-top: calc(-1 * var(--s-3)); }

.legal-body { max-width: 68ch; }
.legal-body section { margin-top: var(--s-7); }
.legal-body h2 {
  font-size: var(--fs-h3);
  letter-spacing: -0.015em;
  line-height: 1.25;
  color: var(--text-1);
}
.legal-body h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.005em;
  margin-top: var(--s-5);
  color: var(--text-1);
}
.legal-body p {
  margin-top: var(--s-4);
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: 1.7;
}
.legal-body ul { margin-top: var(--s-4); display: grid; gap: var(--s-2); }
.legal-body li {
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: 1.7;
  padding-left: var(--s-5);
  position: relative;
}
.legal-body li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.72em;
  width: 6px; height: 1px;
  background: var(--line-strong);
}
.legal-body strong { color: var(--text-1); font-weight: 600; }
.legal-body a { color: var(--text-1); overflow-wrap: anywhere; }

/* ==========================================================================
   Reveal on scroll -- OPT IN, never opt out.
   Nothing is hidden unless the document element carries .js, which the inline
   head script sets before first paint. With JavaScript blocked or broken the
   page renders complete and final: no opacity:0, no empty containers.
   ========================================================================== */

.js .rv {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-rev) var(--ease), transform var(--t-rev) var(--ease);
}
.js .rv.is-in { opacity: 1; transform: none; }
.js .rv-d1 { transition-delay: 90ms; }
.js .rv-d2 { transition-delay: 180ms; }

.js .hero-seam { transform: scaleY(0); }
.js .hero-rule { transform: scaleX(0); }
.js .spine     { transform: scaleY(0); }
.js .mark::before { opacity: 0; transform: translateX(-24px); }
.js .mark img     { opacity: 0; transform: translateX(24px); }
.js .facet svg    { opacity: 0; }

@keyframes draw-y  { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes draw-x  { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes join-l  { from { transform: translateX(-24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes join-r  { from { transform: translateX(24px);  opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.js.is-ready .hero-seam { animation: draw-y 900ms var(--ease) 80ms forwards; }
.js.is-ready .mark::before { animation: join-l 1000ms var(--ease) 520ms forwards; }
.js.is-ready .mark img     { animation: join-r 1000ms var(--ease) 520ms forwards; }
.js.is-ready .facet svg    { animation: fade-in 1200ms var(--ease) 700ms forwards; }
.js.is-ready .hero-rule    { animation: draw-x 1000ms var(--ease) 1100ms forwards; }
.js.is-ready .spine        { animation: draw-y 1400ms var(--ease) 1300ms forwards; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .rv { opacity: 1; transform: none; transition: none; }
  .js .hero-seam, .js .spine, .js .hero-rule { transform: none; }
  .js .mark::before, .js .mark img { opacity: 1; transform: none; }
  .js .facet svg { opacity: 1; }
  .js.is-ready .hero-seam,
  .js.is-ready .mark::before,
  .js.is-ready .mark img,
  .js.is-ready .facet svg,
  .js.is-ready .hero-rule,
  .js.is-ready .spine { animation: none !important; }
  .btn, .link, .card::before, .card-links a.is-primary svg { transition: none; }
}
