/* Stand-in type: Archivo and Chivo Mono (SIL Open Font License) until GT America is licensed.
   Archivo at 62% width, black italic, stands in for GT America Compressed Black Italic. */
@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-latin-wdth-normal.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
}
@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-latin-wdth-italic.woff2") format("woff2");
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
}
@font-face {
  font-family: "Chivo Mono";
  src: url("/fonts/chivo-mono-latin-wght-normal.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Warm-black ramp built from the brand amber (docs/research/raw/final.md, visual_system). */
  --abyss: #0a0806;
  --deep: #13110c;
  /* Two weights of line and no more. The old single line (#2b2215) measured 1.28:1 against the
     ground and did not show on an office laptop, so the page's structure was invisible.
     --line is the quiet one, inside a list or between lines of one subject (1.8:1).
     --line-strong marks a change of subject, and only that (2.3:1). */
  --line: #413b31;
  --line-strong: #514a40;
  --text: #efe9dc;   /* 16.5:1 on abyss */
  --text-2: #a89e8a; /* 7.5:1 */
  --text-3: #8e8778; /* 5.6:1, the quietest text allowed */
  --amber: #dd9a33;  /* sampled from the logo files */
  /* The brand amber with the lamp on it. Used only for line work the light is falling on, such
     as the lit copy of the creature on the services plate. Never for text. */
  --amber-lit: #f3b45a;
  --ink: #1a1712;    /* text on amber, 8.3:1 */

  /* The one pale section on the site: a printed record page in the middle of deep water.
     Neutral grey paper, not the warm cream that generated sites default to. */
  --paper: #f0f0ee;
  --paper-ink: #1a1712; /* 15.7:1 on paper */
  --paper-2: #5e5647;   /* 6.3:1 */
  --bronze: #7a5419;    /* 5.9:1, the focus ring and the few accents on paper */

  --font-display: "Archivo", "Arial Narrow", Impact, sans-serif;
  --font-text: "Archivo", "Segoe UI", Arial, sans-serif;
  --font-data: "Chivo Mono", ui-monospace, Menlo, Consolas, monospace;

  /* One spacing scale. --band is the air between sections, --gutter the page margin. */
  --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;
  --band: clamp(64px, 11svh, 136px);
  --gutter: max(16px, 5vw);

  /* One type scale. The text steps carry reading; the display steps carry rank.
     The scale used to run from 14px straight to 46px in eight small steps and then jump to one
     92px title on every page, so nothing on a page could outrank anything else. The deck and
     the three display steps fill that gap. At 1440 the ladder reads 14 15 17 18 22 27 46 52 72
     144; each step clears the one under it by at least a fifth. */
  --t-data: 0.875rem;
  --t-small: 0.9375rem;
  --t-read: 1.0625rem;
  --t-body: 1.125rem;
  --t-lead: clamp(1.125rem, 1.5vw, 1.375rem);
  --t-h3: clamp(1.3125rem, 1.9vw, 1.6875rem);
  --t-h2: clamp(1.625rem, 3.1vw, 2.875rem);
  --t-statement: clamp(1.375rem, 2.5vw, 2.125rem);
  /* one large sentence that opens a document, bigger than a section heading, smaller than a title */
  --t-deck: clamp(1.75rem, 3.6vw, 3.25rem);
  /* the home headline keeps its own size (home.css); a page title is half of it; a chapter or
     group word is a step under the title, so the two never read as the same thing */
  /* an inner page's title, on the floor of its opening (components.css, .opening-title) */
  --display-1: min(clamp(2.75rem, 6vw, 5.75rem), 11svh);
  --display-2: min(clamp(2.5rem, 5vw, 4.5rem), 10svh);
  --display-3: min(clamp(2rem, 3.4vw, 2.875rem), 6.5svh);
  /* how the inner-page titles are drawn: upright, the text face's own width, heavy. The home
     headline and the home chapter words keep the compressed italic, which is where it has the
     weight to carry (docs/decisions.md). */
  --title-style: normal;
  --title-stretch: 100%;
  --title-weight: 700;
  --title-tracking: -0.028em;
  --measure: 62ch;

  /* Motion. Colour changes only, never position, so nothing moves under a reader's pointer.
     Short for a press, a little longer for a hover, longest for something opening. */
  --d-press: 70ms;
  --d-hover: 140ms;
  --d-open: 240ms;
  --e-standard: cubic-bezier(0.4, 0.14, 0.3, 1);

  color-scheme: dark;
}

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

html {
  background: var(--abyss);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--abyss);
  color: var(--text);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Every link and control answers a pointer: the underline brightens on hover and thickens on
   press. Colour and thickness only, so nothing moves. The focus ring is not in this list: it
   shows at once (below), because a ring that fades in reads as lag to a keyboard user. */
a,
button,
summary {
  transition:
    color var(--d-hover) var(--e-standard),
    background-color var(--d-hover) var(--e-standard),
    border-color var(--d-hover) var(--e-standard),
    text-decoration-color var(--d-hover) var(--e-standard);
}
a:active {
  text-decoration-color: var(--text);
  text-decoration-thickness: 2px;
  transition-duration: var(--d-press);
}

::selection {
  background: var(--amber);
  color: var(--ink);
}

/* The focus ring shows instantly; only the glow behind it glides (lure-light.ts). */
:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: 8px;
  left: var(--gutter);
  z-index: 10;
  padding: 10px 14px;
  background: var(--amber);
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus {
  transform: none;
}

/* The main button: near-black on amber. */
.button-primary {
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-sm);
  min-height: 44px;
  padding: 0 18px;
  background: var(--amber);
  color: var(--ink);
  font-size: var(--t-small);
  font-weight: 600;
  text-decoration: none;
}
@media (hover: hover) {
  .button-primary:hover {
    background: #e9ad50;
  }
}
/* Pressed, it goes darker, not lighter: 5.9:1 for the text on it. */
.button-primary:active {
  background: #c9871f;
  transition-duration: var(--d-press);
}
@media (forced-colors: active) {
  .button-primary:active {
    text-decoration: underline;
  }
}

/* The grid pages are placed on. Opt in with .grid; nothing is placed on it until a page asks.
   Six columns from 900px, twelve from 1200px, one 16px gap. The steps are in em so that text-only
   zoom lets a page fall back to one column instead of squeezing. A measure is never set in ch on
   this site: in Archivo 1ch is 1.2 to 1.4 real characters, so 62ch is an 83-character line. */
@media screen and (min-width: 56.25em) {
  .grid {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    column-gap: var(--s-4);
    align-items: start;
  }
  .grid > * {
    min-width: 0;
  }
}
@media screen and (min-width: 75em) {
  .grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
  }
}

/* Keep the outgoing page opaque while the incoming page fades over it.
   One complete picture stays underneath throughout the transition. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-new(root) {
  animation: page-arrival 220ms ease-out both;
  mix-blend-mode: normal;
}

@keyframes page-arrival {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
  :root {
    --d-press: 0.01ms;
    --d-hover: 0.01ms;
    --d-open: 0.01ms;
  }
}
/* The parts every page is built from: dark sections the light shows through, white sections that
   slide over it, containers, icon chips, and the shared blocks more than one page uses. Loaded on
   every page by src/layouts/Page.astro. Page-only shapes live beside the page (src/home/home.css,
   src/approach/approach.css and so on).
   Every text colour below was measured against its own container, not against the scene.

   .sec .sec-white   a section; a white one carries its own ground over the light
   .wrap             the page's width and margin
   .sec-head         a section's label with its icon, its title, and sometimes a line under it
   .chip .card       an icon in a small rounded square; the container that holds a block of text
   .grid-2 .grid-3   grids of cards
   .pills            short facts in a row, each with its icon
   .opening          the opening of an inner page (PageOpening.astro)
   .onpage           the section menu that holds at the top of a long page (SectionMenu.astro)
   .split            a lead sentence beside the paragraphs that follow it
   .record-card      the record a buyer checks (RecordCard.astro)
   .contact-lines    the email, the number and the address, each with its icon (a list, or one
                     line on its own)
   .family-card      one company of the CIS family with its mark (FamilyCards.astro) */

:root {
  --radius: 12px;
  --radius-sm: 8px;

  /* Dark containers: lifted from the ground by tone, with a faint lit top edge. Nine tenths
     opaque, so the light still warms them a little as it passes behind. */
  --card: rgb(22 17 12 / 0.9);
  --card-solid: #16110c;
  --card-edge: rgb(239 233 220 / 0.1);
  --card-top: rgb(255 255 255 / 0.07);

  /* White sections. Warm white, not grey paper and not cream. */
  --white: #f8f6f1;
  --white-card: #ffffff;
  --white-edge: #e5dfd3;
  --white-ink: #1a1712;
  --white-ink-2: #5a5244; /* 7.1:1 on the white ground, 7.7:1 on a card */
  --white-accent: #8a5a14; /* the amber, darkened until it reads on white: 5.5:1 */
  --white-shadow: 0 1px 2px rgb(26 23 18 / 0.06), 0 12px 32px -14px rgb(26 23 18 / 0.22);
}

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

/* White ones carry their own ground, so the fixed light behind the page is hidden while they
   pass and comes back in the dark ones. */
.sec {
  position: relative;
  padding-block: clamp(64px, 8vw, 104px);
}
.sec-white {
  background: var(--white);
  color: var(--white-ink);
}
.sec-white :focus-visible {
  outline-color: var(--bronze);
}
/* A section menu sits at the top of the screen on the long pages: a jump to a section must not
   land underneath it (WCAG 2.4.11). */
.sec[id],
.sec [id] {
  scroll-margin-top: 76px;
}

.wrap {
  max-width: 1600px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Section head: a small label with its icon, a title, and sometimes one line under it. */
.sec-head {
  display: grid;
  gap: 16px;
  max-width: 56rem;
  margin-bottom: clamp(36px, 5vw, 60px);
}
.sec-label {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--amber);
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1.2;
}
.sec-white .sec-label {
  color: var(--white-accent);
}
/* a heading set as the label: it takes the label's size and colour */
.sec-label-text {
  margin: 0;
  color: inherit;
  font: inherit;
}
/* a title with its icon beside it (never inside it: a heading is one colour) */
.sec-title-row {
  display: flex;
  align-items: center;
  gap: 16px;
}
.sec-title {
  margin: 0;
  font-size: var(--t-h2);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.022em;
  text-wrap: balance;
}
/* a whole sentence in the title's place: a step smaller, so it reads as a sentence */
.sec-title.is-sentence {
  font-size: clamp(1.5rem, 2.5vw, 2.25rem);
  font-weight: 600;
  line-height: 1.22;
  letter-spacing: -0.016em;
  text-wrap: pretty;
}
/* One line under a title. Full strength on a dark section, because the light travels over it and
   the quiet colour does not hold 4.5:1 where the pool is brightest. */
.sec-intro {
  max-width: 44rem;
  margin: 0;
  color: var(--text);
  font-size: var(--t-read);
  line-height: 1.55;
  text-wrap: pretty;
}
.sec-white .sec-intro {
  color: var(--white-ink-2);
}

/* ------------------------------------------------------------------------ chips and cards */

/* Icon chip: a small rounded square holding one icon. */
.chip {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: rgb(221 154 51 / 0.1);
  box-shadow: inset 0 0 0 1px rgb(221 154 51 / 0.28);
  color: var(--amber);
}
.chip-sm {
  width: 32px;
  height: 32px;
  border-radius: 7px;
}
.sec-white .chip {
  background: rgb(221 154 51 / 0.14);
  box-shadow: inset 0 0 0 1px rgb(138 90 20 / 0.22);
  color: var(--white-accent);
}

/* Card: the container that holds a block of text. */
.card {
  position: relative;
  border-radius: var(--radius);
  padding: clamp(22px, 2.2vw, 32px);
  background: var(--card);
  box-shadow:
    inset 0 0 0 1px var(--card-edge),
    inset 0 1px 0 var(--card-top);
}
.sec-white .card {
  background: var(--white-card);
  box-shadow:
    inset 0 0 0 1px var(--white-edge),
    var(--white-shadow);
}
@media (forced-colors: active) {
  .card,
  .chip {
    border: 1px solid CanvasText;
  }
}

/* a card whose icon sits over its title and words */
.card-stack {
  display: grid;
  gap: 14px;
  align-content: start;
}
.card-title {
  margin: 0;
  font-size: clamp(1.1875rem, 1.45vw, 1.375rem);
  font-weight: 650;
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
.card-body {
  margin: 0;
  color: var(--text-2);
  font-size: 1rem;
  line-height: 1.6;
  text-wrap: pretty;
}
.sec-white .card-body {
  color: var(--white-ink-2);
}
/* a card that is one line of weight, with no title over it */
.card-line {
  margin: 0;
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  font-weight: 600;
  line-height: 1.4;
  text-wrap: pretty;
}
/* a card's label: its icon and a small heading beside it */
.card-label {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
}
.card-label-text {
  margin: 0;
  color: var(--amber);
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1.25;
}
.sec-white .card-label-text {
  color: var(--white-accent);
}

/* Lines inside a card, each on its own hairline. */
.card-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.card-list li {
  padding: 12px 0;
  box-shadow: inset 0 1px 0 var(--card-edge);
  font-size: var(--t-read);
  line-height: 1.45;
  text-wrap: pretty;
}
.card-list li:first-child {
  padding-top: 0;
  box-shadow: none;
}
.card-list li:last-child {
  padding-bottom: 0;
}
.sec-white .card-list li {
  box-shadow: inset 0 1px 0 var(--white-edge);
}
.sec-white .card-list li:first-child {
  box-shadow: none;
}

/* Grids of cards. One column on a phone, then two, then three. */
.grid-2,
.grid-3 {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(16px, 1.6vw, 24px);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 720px) {
  .grid-2,
  .grid-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1080px) {
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
/* Five cards: three over two on a wide screen, so the last row is not one card alone. */
.grid-5 {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(16px, 1.6vw, 24px);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 720px) {
  .grid-5 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1080px) {
  .grid-5 {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
  .grid-5 > :nth-child(-n + 3) {
    grid-column: span 2;
  }
  .grid-5 > :nth-child(n + 4) {
    grid-column: span 3;
  }
}

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

/* The second button: an outline, for the action beside the main one. */
.button-ghost {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 18px;
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 1px rgb(239 233 220 / 0.42);
  color: var(--text);
  font-size: var(--t-small);
  font-weight: 600;
  text-decoration: none;
}
@media (hover: hover) {
  .button-ghost:hover {
    box-shadow: inset 0 0 0 1px var(--text);
    background: rgb(239 233 220 / 0.06);
  }
}
.sec-white .button-ghost {
  box-shadow: inset 0 0 0 1px rgb(26 23 18 / 0.35);
  color: var(--white-ink);
}
@media (forced-colors: active) {
  .button-ghost {
    border: 1px solid ButtonText;
  }
}
/* a row of buttons */
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0;
}

/* ------------------------------------------------------------------------ pictures */

/* A lead sentence beside the paragraphs that follow it: one column on a phone, two on a wide
   screen, with the wider one for the lead. Two children, the lead first. */
.split {
  display: grid;
  gap: clamp(24px, 4vw, 64px);
  align-items: start;
}
@media (min-width: 1000px) {
  .split {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }
}

.icon {
  flex: none;
}

/* ------------------------------------------------------------------------------ pills */

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.pills li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  padding: 0 14px 0 12px;
  border-radius: 999px;
  background: rgb(22 17 12 / 0.82);
  box-shadow: inset 0 0 0 1px var(--card-edge);
  font-size: var(--t-small);
  font-weight: 600;
  white-space: nowrap;
}
.pills .icon {
  color: var(--amber);
}
@media (forced-colors: active) {
  .pills li {
    border: 1px solid CanvasText;
  }
}

/* ---------------------------------------------------------------------- inner-page opening */

/* Built like the home hero: the words on the floor of the first screen, over the page's own
   view of the creature, the buttons under them and the pills on the right. Above 1080px the
   header lies over the top of the page, so the opening clears it; below, the header takes its
   own place in the page (chrome.css) and the opening only needs air under it. */
.opening {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-block: clamp(124px, 16svh, 168px) clamp(48px, 8svh, 88px);
}
@media screen {
  .opening-tall {
    min-height: 84svh;
  }
}
@media screen and (max-width: 1079px) {
  .opening {
    padding-top: clamp(40px, 8svh, 80px);
  }
  .opening-tall {
    min-height: 62svh;
  }
}
.opening-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 28px 48px;
  width: 100%;
}
.opening-lead {
  display: grid;
  justify-items: start;
  gap: clamp(18px, 2.4svh, 26px);
  max-width: 56rem;
}
.opening-eyebrow {
  margin: 0;
  color: var(--amber);
  font-size: var(--t-read);
  font-weight: 600;
  line-height: 1.3;
}
.opening-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--display-1);
  font-stretch: var(--title-stretch);
  font-style: var(--title-style);
  font-weight: var(--title-weight);
  line-height: 0.98;
  letter-spacing: var(--title-tracking);
  text-wrap: balance;
}
.opening-lede {
  max-width: 40rem;
  margin: 0;
  font-size: clamp(1.1875rem, 1.6vw, 1.5rem);
  line-height: 1.4;
  text-wrap: pretty;
}
/* the quieter paragraph under the line: smaller, never dimmer, because it sits over the light */
.opening-note {
  max-width: 40rem;
  margin: 0;
  font-size: var(--t-read);
  line-height: 1.55;
  text-wrap: pretty;
}
.opening-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 4px;
}
.opening-chips {
  max-width: 44rem;
}

/* ------------------------------------------------------------------------- section menu */

.onpage {
  position: sticky;
  top: 0;
  z-index: 5;
  background: rgb(10 8 6 / 0.95);
  box-shadow: 0 1px 0 var(--card-edge);
}
.onpage ul {
  display: flex;
  gap: 4px;
  margin: 0;
  padding: 10px 0;
  list-style: none;
  overflow-x: auto;
  scrollbar-width: none;
}
.onpage ul::-webkit-scrollbar {
  display: none;
}
.onpage a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  font-size: var(--t-small);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
@media (hover: hover) {
  .onpage a:hover {
    background: rgb(239 233 220 / 0.08);
  }
}
.onpage .icon {
  color: var(--amber);
}
/* When the row is wider than the screen, the edge that has more behind it fades out, so the cut
   reads as "keep scrolling" and not as a mistake. The fade is driven by the row's own scroll
   position, so with nothing to scroll there is no fade: the timeline is idle and the row keeps
   its plain styles. Browsers without scroll-driven animations (Firefox today) simply show the
   row cut at the edge, which is what it did before. */
@supports (animation-timeline: scroll()) {
  .onpage ul {
    animation: onpage-edges linear both;
    animation-timeline: scroll(self inline);
  }
  @keyframes onpage-edges {
    0% {
      mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent);
    }
    15%,
    85% {
      mask-image: linear-gradient(to right, transparent, #000 56px, #000 calc(100% - 56px), transparent);
    }
    100% {
      mask-image: linear-gradient(to right, transparent, #000 56px);
    }
  }
}
@media (forced-colors: active) {
  .onpage ul {
    animation: none;
  }
}

.sec-more {
  margin: clamp(24px, 3vw, 40px) 0 0;
}

/* ----------------------------------------------------------------------------- the record */

/* One card: a ruled row per fact on the left, the badge and what goes with it on the right. */
.record-card {
  display: grid;
  gap: clamp(28px, 3vw, 48px);
}
@media (min-width: 1000px) {
  .record-card.has-side {
    grid-template-columns: minmax(0, 1fr) 18rem;
    align-items: start;
  }
}
.record-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* On a phone: the icon and the label on one line, the value under both. From 720px: the icon,
   the label and the value side by side. A row with no label puts its words beside the icon. */
.record-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  align-items: center;
  gap: 8px 12px;
  padding: 16px 0;
  box-shadow: inset 0 -1px 0 var(--card-edge);
}
.sec-white .record-row {
  box-shadow: inset 0 -1px 0 var(--white-edge);
}
.record-row:first-child {
  padding-top: 0;
}
.record-label {
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: 600;
}
.sec-white .record-label {
  color: var(--white-ink-2);
}
.record-value {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.record-row.is-whole .record-value {
  grid-column: 2 / -1;
}
@media (min-width: 720px) {
  .record-row {
    grid-template-columns: 32px 13.5rem minmax(0, 1fr);
    column-gap: 12px;
  }
  .record-value {
    grid-column: auto;
    padding-left: 12px;
  }
  .record-row.is-whole .record-value {
    padding-left: 0;
  }
}
.record-value.is-data {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}
.record-side {
  display: grid;
  gap: 18px;
  justify-items: start;
  padding: clamp(20px, 2vw, 28px);
  border-radius: var(--radius-sm);
  background: rgb(239 233 220 / 0.03);
  box-shadow: inset 0 0 0 1px var(--card-edge);
}
.sec-white .record-side {
  background: var(--white);
  box-shadow: inset 0 0 0 1px var(--white-edge);
}
.record-badge {
  width: 96px;
  height: auto;
}
.record-supports {
  margin: 0;
  color: var(--text-2);
  font-size: 1rem;
  line-height: 1.55;
  text-wrap: pretty;
}
.sec-white .record-supports {
  color: var(--white-ink-2);
}

/* --------------------------------------------------------------------------- contact lines */

.contact-lines {
  display: grid;
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* each line: a list item, or a paragraph when there is only the one */
.contact-lines > * {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0;
  font-size: clamp(1rem, 1.8vw, 1.5rem);
  overflow-wrap: anywhere;
}
.contact-lines a {
  text-decoration-color: var(--text-3);
}
.sec-white .contact-lines a {
  text-decoration-color: var(--white-ink-2);
}
.contact-phone {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
/* the smaller set, inside a card that is about something else */
.contact-lines.is-small > * {
  font-size: var(--t-read);
}

/* ---------------------------------------------------------------------------- icon lists */

/* Lines each with its icon in a small chip, on hairlines: a panel of a sheet, a list of reasons. */
.icon-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.icon-list li {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  box-shadow: inset 0 1px 0 var(--card-edge);
  font-size: var(--t-read);
  line-height: 1.45;
  text-wrap: pretty;
}
.icon-list li:first-child {
  padding-top: 0;
  box-shadow: none;
}
.icon-list li:last-child {
  padding-bottom: 0;
}
.sec-white .icon-list li {
  box-shadow: inset 0 1px 0 var(--white-edge);
}
.sec-white .icon-list li:first-child {
  box-shadow: none;
}

/* ------------------------------------------------------------------------ the CIS family */

/* The parent across the full width, the other three in a row under it. */
.family-cards {
  display: grid;
  gap: clamp(16px, 1.6vw, 24px);
}
.family-card {
  display: grid;
  align-content: start;
  gap: 18px;
}
.family-mark {
  width: auto;
  height: 64px;
}
.family-name {
  margin: 0;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.012em;
}
.family-role {
  margin: 8px 0 0;
  color: var(--amber);
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1.35;
}
.family-work {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 18px 0 0;
  box-shadow: inset 0 1px 0 var(--card-edge);
  list-style: none;
}
.family-work li {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--t-read);
  line-height: 1.35;
}
.family-work .icon {
  color: var(--amber);
}
.family-card.is-parent .family-mark {
  height: 88px;
}
@media (min-width: 900px) {
  .family-card.is-parent {
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.2fr);
    align-items: center;
    column-gap: clamp(24px, 3vw, 48px);
    padding: clamp(28px, 3vw, 44px);
  }
  .family-card.is-parent .family-work {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding: 0 0 0 clamp(24px, 3vw, 48px);
    box-shadow: inset 1px 0 0 var(--card-edge);
  }
}
/* What the site looks like on paper. A buyer prints a capability statement, so this is not an
   afterthought: black on white, US Letter, no menus, no light, nothing that only makes sense on a
   screen. The two capability statements add their own rules on top of these, so each comes out on
   one page (src/capability/capability.css). */
@media print {
  @page {
    size: letter;
    margin: 14mm;
  }

  html,
  body {
    background: #fff;
    color: #000;
    font-size: 10.5pt;
    line-height: 1.4;
  }

  /* The light, the header, the footer and the skip link are already hidden by their own
     stylesheets. This catches the layer they sit on. */
  .page {
    display: block;
    min-height: 0;
  }

  /* Anything that only makes sense on a screen: the moving strip of marks, the section menu, the
     buttons and the pills. */
  .marks,
  .onpage,
  .chip,
  .icon,
  .pills,
  .actions,
  .opening-actions,
  .button-primary,
  .button-ghost,
  .service-more > summary {
    display: none;
  }

  /* Sections and containers become paper: no grounds, no shadows, no corners. */
  .sec,
  .sec-white {
    padding: 6mm 0 0;
    background: none;
    color: #000;
  }
  .wrap {
    max-width: none;
    padding: 0;
  }
  .card {
    padding: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    color: #000;
  }
  .grid-2,
  .grid-3,
  .grid-5,
  .family-cards,
  .split,
  .record-card,
  .contact-grid {
    display: block;
  }
  .grid-2 > * + *,
  .grid-3 > * + *,
  .grid-5 > * + *,
  .family-cards > * + * {
    margin-top: 4mm;
  }

  /* The opening of a page. */
  .opening {
    display: block;
    min-height: 0;
    padding: 0 0 4mm;
  }
  .opening-lead {
    display: block;
    max-width: none;
  }
  .opening-title {
    font-size: 22pt;
    line-height: 1;
  }
  .opening-eyebrow,
  .opening-lede,
  .opening-note,
  .sec-label,
  .card-label-text,
  .card-body,
  .record-label,
  .record-supports,
  .sec-intro,
  .family-role {
    color: #000;
  }
  .opening-lede {
    max-width: none;
    margin-top: 2mm;
    font-size: 12pt;
  }
  .opening-note {
    max-width: none;
    margin-top: 2mm;
    font-size: 10pt;
  }

  .sec-head {
    margin-bottom: 3mm;
  }
  .sec-title {
    font-size: 13pt;
  }
  .card-title,
  .family-name {
    font-size: 11pt;
  }
  .card-label {
    margin-bottom: 2mm;
  }

  /* Hairlines are pale on a screen and would print as a smudge. */
  .card-list li,
  .icon-list li,
  .record-row,
  .family-work,
  .chapter-head,
  .service + .service {
    box-shadow: none;
    border-top: 1px solid #999;
  }
  .record-row {
    border-top: 0;
    border-bottom: 1px solid #999;
  }

  /* Nothing on paper is a link you can press, and a heading never sits alone at the foot of a
     page. */
  a {
    color: #000;
    text-decoration: none;
  }
  h1,
  h2,
  h3,
  h4,
  dt {
    break-after: avoid;
  }
  li,
  dd,
  p,
  .card,
  .record-row {
    break-inside: avoid;
  }

  /* A paragraph behind a disclosure is still part of the document on paper. */
  .service-more::details-content {
    content-visibility: visible;
    display: block;
  }

  .opening-lede,
  .sheet-lede-text,
  .card-body,
  .check-note,
  .util-text {
    max-width: none;
  }
}
/* The parts that are on every page: the layer the words sit on, the header and the footer.
   Same rules as the rest of the site: square corners, no shadows, no cards. Hairlines and
   space do the dividing. */
.page {
  position: relative;
  z-index: 1;
  display: flex;
  min-height: 100svh;
  flex-direction: column;
}

.page > main {
  flex: 1 0 auto;
}

/* Header. A bar the width of the page with a hairline under it. It lies over the first screen
   rather than following the reader down, so nothing is ever between the reader and the light;
   every page can be left from the footer, which carries the same links and more.
   The page you are on is marked by the fish's own lamp (Azhar's pick, Sep 15, night; the three
   cones it was chosen from are in docs/prototype/2026-09-15/nav-cone). The rules the light was
   drawn to: the lamp is the brightest thing on the bar and everything else is lit by it; the
   beam is brightest near the lamp and down its middle, with no hard edge; what it touches is lit
   (the name, a short stretch of the hairline, a little spill onto the page) and what it misses
   stays dim; warm white at the lamp, amber at the foot, like the big lure. */
.site-header {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  z-index: 2;
  display: flex;
  align-items: stretch;
  gap: var(--s-4) clamp(16px, 2vw, 28px);
  min-height: 88px;
  padding: 0 var(--gutter);
  border-bottom: 1px solid var(--line);
  background: linear-gradient(to bottom, rgb(10 8 6 / 0.82), rgb(10 8 6 / 0.55));
}

/* The mark, the page names and the button sit on one line low in the bar. The room above them
   is the lamp's: 10px of stalk, 24px of cup, and the beam from there to the hairline. */
.brand,
.site-header .button-primary,
.site-header .button-here {
  align-self: flex-end;
  margin-bottom: 7px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 44px;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
}
.brand-mark {
  flex: none;
  width: 36px;
  height: 36px;
}
.brand-disc {
  fill: var(--amber);
}
.brand-fish {
  fill: var(--abyss);
}

/* The page names take the space between the mark and the controls, and sit in the middle of it.
   Each link is the full height of the bar, so the lamp and the beam can be placed against it:
   the beam runs from the foot of the lamp to the link's own bottom edge, which is the hairline. */
.site-nav {
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
}

.site-nav ul {
  display: flex;
  height: 100%;
  gap: 0 clamp(6px, 1.2vw, 16px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-nav li {
  display: flex;
}
.site-nav a {
  position: relative;
  z-index: 0;
  display: flex;
  align-items: center;
  padding: 30px 14px 0;
  color: var(--text-2);
  font-size: var(--t-small);
  text-decoration: none;
}
.site-nav a:hover {
  color: var(--text);
}
/* The link is the whole tall cell, so the focus ring goes on the word instead. */
.site-nav a:focus-visible {
  outline: none;
}
.site-nav a:focus-visible .nav-word {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
}
/* The page you are on: lit warm white, in the beam. */
.site-nav a[aria-current='page'] {
  color: #fff6e6;
  text-shadow: 0 0 10px rgb(255 214 150 / 0.35);
}

/* The stalk, from the top edge, lit near the lamp. */
.nav-lamp-stalk {
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  height: 11px;
  margin-left: -1px;
  background: linear-gradient(to bottom, #2e2519, #86694a);
  pointer-events: none;
}
/* The lamp: the traced cup in the hero's own warm white, and its bloom. */
.nav-lamp {
  position: absolute;
  top: 10px;
  left: 50%;
  width: 14px;
  height: 24px;
  transform: translateX(-50%);
  pointer-events: none;
}
.nav-lamp svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffe6bf;
}
.nav-lamp::before {
  content: '';
  position: absolute;
  top: 55%;
  left: 50%;
  width: 56px;
  height: 56px;
  margin: -28px 0 0 -28px;
  border-radius: 50%;
  background: radial-gradient(
    closest-side,
    rgb(255 240 214 / 0.75),
    rgb(255 222 170 / 0.32) 26%,
    rgb(221 154 51 / 0.1) 58%,
    transparent
  );
}
/* The beam: a blurred triangle the width of the name, behind the word, from the foot of the
   lamp to the hairline. It is an SVG rather than a CSS shape because a clipped gradient has a
   hard edge and light does not. It needs its height said in full: an absolutely placed SVG with
   a top and a bottom but no height keeps its own square height and runs past the line. */
.nav-beam {
  position: absolute;
  z-index: -1;
  top: 30px;
  left: -4px;
  width: calc(100% + 8px);
  height: calc(100% - 29px);
  overflow: visible;
  pointer-events: none;
}
/* The pool: the hairline lit across the word, with a little spill onto the page below it. */
.site-nav a[aria-current='page']::after,
.button-here::after {
  content: '';
  position: absolute;
  right: 2px;
  bottom: -2px;
  left: 2px;
  height: 2px;
  background: linear-gradient(
    90deg,
    transparent,
    rgb(255 226 180 / 0.9) 30%,
    rgb(255 226 180 / 0.9) 70%,
    transparent
  );
  box-shadow:
    0 0 12px 1px rgb(243 180 90 / 0.4),
    0 8px 26px 5px rgb(221 154 51 / 0.15);
  pointer-events: none;
}

/* On the contact page the button becomes this: the same words in the same place, with no amber
   and nothing to press, so the one button on the site always leads somewhere. It is the page you
   are on, so the lamp hangs over it: the same tall cell as a page name, lit the same way. */
.site-header .button-here {
  position: relative;
  z-index: 0;
  display: inline-flex;
  align-items: center;
  align-self: stretch;
  margin-bottom: 0;
  padding-top: 30px;
  color: #fff6e6;
  font-size: var(--t-small);
  font-weight: 600;
  text-shadow: 0 0 10px rgb(255 214 150 / 0.35);
}

/* Windows High Contrast: the light goes and the lamp is a plain mark over the page you are on,
   which is also underlined, since the colours that set it apart are gone. */
@media (forced-colors: active) {
  .site-header {
    background: Canvas;
  }
  .site-nav a[aria-current='page'],
  .button-here {
    text-decoration: underline;
    text-underline-offset: 5px;
  }
  .nav-lamp-stalk,
  .nav-lamp::before,
  .nav-beam,
  .site-nav a[aria-current='page']::after,
  .button-here::after {
    display: none;
  }
}

/* Below this the five page names go on their own row under the mark and the button, because
   squeezing them in next to both leaves nothing readable. The row has its own hairline above it
   and the lamp hangs from that line. */
@media (max-width: 1079px) {
  .site-header {
    flex-wrap: wrap;
    row-gap: 0;
    min-height: 0;
    padding-top: 10px;
  }
  .brand,
  .site-header .button-primary,
  .site-header .button-here {
    align-self: center;
    margin-bottom: 0;
  }
  /* The contact marker shares the first row with the mark, and there is no room for a lamp
     above it there, so it goes back to plain lit words. */
  .site-header .button-here {
    min-height: 44px;
    padding-top: 0;
  }
  .button-here .nav-beam,
  .button-here .nav-lamp-stalk,
  .button-here .nav-lamp,
  .button-here::after {
    display: none;
  }
  .site-nav {
    order: 3;
    flex-basis: 100%;
    justify-content: flex-start;
    margin-top: 6px;
    border-top: 1px solid var(--line);
  }
  /* With the page names on their own row, the button keeps the right edge of the first row
     instead of sitting against the name. This was a phone-only rule once, and between 620 and
     1080px the button was glued to the name. */
  .site-header .button-primary,
  .site-header .button-here {
    margin-left: auto;
  }
  .site-nav ul {
    flex-wrap: wrap;
    height: 68px;
  }
  .site-nav a {
    padding: 28px 12px 0;
    font-size: 0.8125rem;
  }
  /* Wrapped, the header is two or three rows and its height depends on the width, so on an inner
     page it takes its place in the page instead of lying over it: a title can then start right
     under it at any width or zoom without being covered. The home page keeps it over the scene,
     because its headline sits on the floor of the first screen, well clear. */
  body:not([data-view='home']) .site-header {
    position: relative;
  }
}

/* On a phone the five names take two rows, each row tall enough for the lamp above its word.
   The mark keeps its name: a federal buyer arriving on a page whose only identifying thing is an
   unfamiliar fish in a circle has no idea whose site it is, so the name shrinks instead of
   disappearing. */
@media (max-width: 620px) {
  .site-nav ul {
    height: auto;
  }
  .site-nav a {
    height: 58px;
  }
  .brand {
    gap: var(--s-2);
    font-size: 0.875rem;
  }
  .brand-mark {
    width: 30px;
    height: 30px;
  }
}

/* Footer. The creature sinks out of frame: its traced head is drawn big as line art across the
   foot of the page and cut off by the bottom edge, its lamp lit at the right; three columns of
   plain text sit over the water beside it, then the build stamp (Azhar's pick, Sep 15 night,
   docs/decisions.md). No margin above it: the last section's own padding is the air before the
   hairline. The ground is nearly solid so the moving light never sits behind the small print. */
.site-footer {
  position: relative;
  overflow: hidden;
  padding: 72px var(--gutter) 40px;
  border-top: 1px solid var(--line);
  background: rgb(10 8 6 / 0.94);
}

/* The drawing: the same traced logo the light layer uses (#cis-fish-body and #cis-fish-cup
   from src/lure/LureStage.astro), a quiet copy and a warm copy shown around the lamp. */
.footer-art {
  position: absolute;
  right: 3%;
  bottom: -34%;
  width: min(860px, 90vw);
  aspect-ratio: 1;
  pointer-events: none;
}
@media (max-width: 899px) {
  .footer-art {
    right: auto;
    left: -20vw;
    bottom: -40%;
    width: 140vw;
  }
}
.footer-drawing {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
/* the traced paths sit under potrace's scale(0.1): 50 here is 5 units of the 3334 box.
   Quieter than the plate's copy on the home page (0.2): between 900 and 1100px wide the
   small print in the first column sits over the head, and at 0.2 it measured 4.6:1, a
   tenth over the floor. */
.footer-fish {
  fill: none;
  stroke: rgb(239 233 220 / 0.14);
  stroke-width: 50;
  stroke-linejoin: round;
}
.footer-fish.is-lit {
  stroke: var(--amber-lit);
  stroke-width: 60;
}
.footer-cup {
  filter: drop-shadow(0 0 140px rgb(255 214 150 / 0.75));
}
/* Between about 900 and 1440 the grid's third column lands inside the lamp's lit circle: the
   columns reach the gutter plus 880px while the lamp sits at 85.5% of the drawing, and the two
   meet. The small print there measured 4.4:1 against the 4.5 floor on every page (Sep 17), the
   worst pixel rgb(132, 101, 57). Quieten the whole drawing across that band rather than move the
   columns, which keeps the composition and the lamp where they were. Above 1440 the columns
   clear the lit circle on their own and the drawing stays at full strength. */
@media (min-width: 900px) and (max-width: 1439px) {
  .footer-art {
    opacity: 0.5;
  }
}
.footer-bloom {
  position: absolute;
  left: 85.5%;
  top: 57.5%;
  width: 60%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgb(255 214 150 / 0.3), rgb(221 154 51 / 0.12) 35%, transparent 68%);
}

/* The columns keep to the left so the lamp has open water; on a wide screen they take at most
   880px and the footer is tall enough for the head to show. */
.footer-grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 48px clamp(24px, 4vw, 64px);
  align-items: start;
}
@media (min-width: 900px) {
  .footer-grid {
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    max-width: 880px;
    min-height: 420px;
  }
}
@media (min-width: 560px) and (max-width: 899px) {
  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.footer-identity p {
  margin: 0;
}
.footer-name {
  font-size: var(--t-h3);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.footer-parent {
  max-width: 34ch;
  margin-top: 10px !important;
  color: var(--text-2);
  font-size: var(--t-small);
  text-wrap: balance;
}
/* the credentials band as its items, a hairline between each */
.footer-credentials {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 0;
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-data);
  font-weight: 500;
}
.footer-credentials li {
  padding-right: 12px;
  margin-right: 12px;
  border-right: 1px solid var(--line-strong);
}
.footer-credentials li:last-child {
  border-right: 0;
  margin-right: 0;
  padding-right: 0;
}
.footer-reach {
  margin-top: 26px !important;
  font-size: var(--t-small);
  line-height: 1.9;
}
.footer-phone {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
.footer-address {
  margin-top: 8px !important;
  color: var(--text-2);
  font-size: var(--t-small);
  line-height: 1.9;
}

.footer-nav h2 {
  margin: 0 0 14px;
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: 500;
}
.footer-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer-nav li + li {
  margin-top: 10px;
}
.footer-nav a,
.footer-reach a {
  font-size: var(--t-small);
  text-decoration-color: var(--text-3);
  text-underline-offset: 4px;
}

/* In High Contrast the light goes and the drawing is plain lines in the text colour. */
@media (forced-colors: active) {
  .footer-fish,
  .footer-fish.is-lit {
    stroke: CanvasText;
  }
  .footer-cup {
    fill: CanvasText;
    filter: none;
  }
  .footer-bloom {
    display: none;
  }
}

@media print {
  .site-header,
  .site-footer,
  .skip-link {
    display: none;
  }
}
/* Shared canvas layers for the approved material treatments. */
[hidden] { display: none !important; }
.sculpture-art { position: absolute; inset: 0; z-index: -1; }
.sculpture-art picture, .sculpture-art img { display: block; width: 100%; height: 100%; }
.sculpture-art picture { position: absolute; inset: 0; }
.sculpture-art img { object-fit: cover; object-position: right center; }
.live-viewport { position: absolute; inset: 0; opacity: 0; pointer-events: none; transition: opacity 450ms ease; }
.live-viewport canvas { display: block; width: 100%; height: 100%; touch-action: pan-y; }
.rendered-art { transition: opacity 450ms ease; }
.is-live .live-viewport { opacity: 1; pointer-events: auto; }
.is-live .rendered-art { opacity: 0; }

.sculpture-shade { position: absolute; inset: 0; background: linear-gradient(90deg, #090907 0%, #090907e8 25%, #09090780 47%, transparent 70%), linear-gradient(0deg, #090907 0%, transparent 22%); pointer-events: none; }
html.motion-hidden *, html.motion-hidden *::before, html.motion-hidden *::after { animation-play-state: paused !important; }
@media (prefers-reduced-motion: reduce) {
  .sculpture-art *, [data-material-surface], [data-material-surface] * { animation: none !important; transition: none !important; }
}
@media (forced-colors: active) {
  .sculpture-art { display: none; }
}
@media print {
  .sculpture-art { display: none !important; }
}
/* The light layer. The square logo box is sized (--fs) and placed so the view's anchor point
   lands at (--ax, --ay) of the screen, and the pool of light rests on that same anchor.
   Every number here is mirrored in src/lure/geometry.ts, which is what the script reads;
   change both together. The frame has to be placed in CSS, not in script, because the page
   has to be finished with no scripts at all. */
.logo-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.lure-stage {
  /* defaults, overridden per view below */
  --fs: max(76vw, 118vh); /* side of the square logo box */
  --ax: 0.86;
  --ay: 0.4;
  --anchor-u: 0.8629; /* the lure (geometry.ts, LURE) */
  --anchor-v: 0.4865;
  --pool: max(48.64vw, 75.52vh);
  --rest-k: 0.55; /* how far the pool is open where no script moves it */
  --lift: 1; /* how strong the pool is on this page: see the note above .lure-pool */

  /* With no scripts the scene sits in the first screen and scrolls away with it, so the lure
     never ends up behind text further down the page. The script pins it (.js below) and takes
     over the job of keeping the light off the words. */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 100svh;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  contain: strict;
}
.js .lure-stage {
  position: fixed;
  inset: 0;
  height: auto;
}

/* One view of the creature per page. The same animal is present everywhere and no two pages
   show the same part of it: the head and the lure on the home page, the gill curls on
   services, the lure over the opening on approach (the creature then swims past), the head big
   with the lure at the middle on family, a low horizon under the capability statements, the
   stalk arcing out of frame on contact, and open water on the page that has nothing to show. The reasoning is in docs/decisions.md. */
.lure-stage[data-view='services'] {
  /* A close-up of the two gill curls and the back edge of the head. It is framed tight on
     purpose: pulled back even a little, the cheek plates below come into frame, and cropped by
     the right edge they read as a row of fangs. Nothing here is cut by an edge. */
  --fs: max(180vw, 290vh);
  --ax: 0.72;
  --ay: 0.42;
  --anchor-u: 0.09;
  --anchor-v: 0.405;
  --pool: max(34vw, 40vh);
  --rest-k: 1;
  /* Damped, because this page draws its own lit creature on top of the scene: see the note on
     VIEWS.services in geometry.ts. Change both together. */
  --lift: 0.7;
}
.lure-stage[data-view='approach'] {
  /* The lure over the opening, the head arriving from the left. /approach moves this frame
     with the scroll so the creature swims forward past the reader (src/approach/approach.css);
     at the top of the page it sits here. */
  --fs: max(105vw, 135vh);
  --ax: 0.66;
  --ay: 0.32;
  --anchor-u: 0.8629;
  --anchor-v: 0.4865;
  --pool: max(48.64vw, 75.52vh);
  --rest-k: 0.55;
  --lift: 2.2;
}
.lure-stage[data-view='family'] {
  /* The head big, the lure at the middle of the screen: the family is placed around the light
     (src/family/FamilyOpening.astro). Sized so the whole head fits left of the lure on a wide
     screen and inside the height on a short one. Home strength, because the still is behind
     it, as on the home page. */
  --fs: min(66vw, 118vh);
  --ax: 0.54;
  --ay: 0.52;
  --anchor-u: 0.8629;
  --anchor-v: 0.4865;
  --pool: max(48.64vw, 75.52vh);
  --rest-k: 0.55;
  /* a step above home: the pool has to show through the window in each chapter card */
  --lift: 1.3;
}
.lure-stage[data-view='record'] {
  /* The light is low and wide here rather than small: measured, the old pool left these four
     pages at 55 out of 255 at their brightest, which is not a dark page but an unlit one. It
     still sits under the data and never becomes the subject. */
  --fs: max(110vw, 140vh);
  --ax: 0.55;
  --ay: 0.86;
  --anchor-u: 0.3449;
  --anchor-v: 0.2459;
  --pool: max(46vw, 52vh);
  --rest-k: 1;
  --lift: 2;
}
.lure-stage[data-view='contact'] {
  --fs: max(130vw, 160vh);
  --ax: 0.55;
  --ay: 0.55;
  --anchor-u: 0.7289;
  --anchor-v: 0.15;
  --pool: max(48vw, 54vh);
  --rest-k: 1;
  --lift: 1.8;
}
.lure-stage[data-view='void'] {
  --fs: max(90vw, 110vh);
  --ax: 0.12;
  /* Low and a little closed, so the light rests on this page's two lines rather than above them.
     The creature is off frame here, so moving the light does not move anything else. The page
     used to ask the script to put the light on its line, which meant the page and the script
     disagreed about the only screen it has: measured, the band the words sit in read 89 out of
     1000 with the script and 72 without it, and the difference showed as a jump the moment the
     script started. At 0.85 and 0.6 it reads 87 either way. */
  --ay: 0.85;
  --anchor-u: 1.4;
  --anchor-v: 0.5;
  --pool: max(34vw, 38vh);
  --rest-k: 0.6;
  /* held below the other unlit views: the page points the light at its one line, so the pool's
     brightest part sits under the words. See VIEWS.void in geometry.ts. */
  --lift: 1.25;
}

/* A portrait screen shows one column of text at full width, so the creature is framed higher
   and further away and the light is held back to nearly its home strength: on a phone a line
   of type can end up anywhere. */
@media (max-aspect-ratio: 1/1) {
  .lure-stage {
    --fs: 150vw;
    --ax: 0.84;
    --ay: 0.26;
    --pool: 96vw;
  }
  .lure-stage[data-view='services'] {
    --fs: 260vw;
    --ax: 0.72;
    --ay: 0.26;
    --pool: 62vw;
    /* damped for the plate, as above */
    --lift: 0.7;
  }
  .lure-stage[data-view='approach'] {
    /* the lure clear under the two rows of the top bar, beside the title's eyebrow */
    --fs: 150vw;
    --ax: 0.7;
    --ay: 0.3;
    --pool: 96vw;
    --lift: 1.3;
  }
  .lure-stage[data-view='family'] {
    /* the head at the top of the page with the lure to the right, a little smaller than on the
       home page so more of the head is on screen; the family reads as a column under it. The
       lure hangs between the page names and the title, where the title is short and the
       headline under it has not started: at 0.3 it sat behind the end of the headline. */
    --fs: 110vw;
    --ax: 0.8;
    --ay: 0.19;
    --pool: 96vw;
    --rest-k: 0.55;
    --lift: 1.3;
  }
  .lure-stage[data-view='record'] {
    --fs: 150vw;
    --ax: 0.5;
    --ay: 0.9;
    --pool: 78vw;
    --lift: 1.3;
  }
  .lure-stage[data-view='contact'] {
    --fs: 200vw;
    --ax: 0.6;
    --ay: 0.32;
    --pool: 74vw;
    --lift: 1.3;
  }
  .lure-stage[data-view='void'] {
    --fs: 130vw;
    --ax: 0.15;
    --ay: 0.4;
    --pool: 56vw;
    --lift: 1.3;
  }
}

.lure-frame {
  position: absolute;
  width: var(--fs);
  height: var(--fs);
  left: calc(var(--ax) * 100% - var(--anchor-u) * var(--fs));
  top: calc(var(--ay) * 100% - var(--anchor-v) * var(--fs));
}

/* The light that moves. It rests on the view's anchor; lure-light.ts glides it from there to
   each section's stop. Peak strength is 17% amber times --lift. The home page is held at 17%
   because the Blender still behind it is already bright and text crosses the lit part; the
   pages with no still behind them go up to about twice that, which still leaves full-strength
   text at better than 8:1. Measured, not guessed: tools/qa/contrast.mjs. */
.lure-pool {
  position: absolute;
  left: calc(var(--anchor-u) * 100%);
  top: calc(var(--anchor-v) * 100%);
  width: var(--pool);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(
    closest-side,
    rgb(221 154 51 / calc(0.17 * var(--lift))),
    rgb(221 154 51 / calc(0.13 * var(--lift))) 20%,
    rgb(221 154 51 / calc(0.08 * var(--lift))) 40%,
    rgb(221 154 51 / calc(0.035 * var(--lift))) 60%,
    rgb(221 154 51 / calc(0.011 * var(--lift))) 80%,
    transparent
  );
  transform: translate(-50%, -50%) scale(var(--rest-k));
  will-change: transform;
}

/* The lure's own glow, its cup and its bloom. These stay on the lure wherever the frame goes,
   so they are only on screen on the views that have the lure in frame. No text sits here. */
.lure-halo,
.lure-bloom {
  position: absolute;
  left: 86.29%;
  top: 48.65%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.lure-halo {
  width: 26%;
  background: radial-gradient(
    closest-side,
    rgb(255 222 170 / 0.5),
    rgb(221 154 51 / 0.3) 14%,
    rgb(221 154 51 / 0.14) 32%,
    rgb(221 154 51 / 0.06) 52%,
    rgb(221 154 51 / 0.018) 76%,
    transparent
  );
  will-change: opacity, transform;
}

.fish-silhouette {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: var(--abyss);
}

.lure-cup {
  position: absolute;
  left: calc(2600 / 3334 * 100%);
  top: calc(1330 / 3334 * 100%);
  width: calc(470 / 3334 * 100%);
  height: calc(820 / 3334 * 100%);
  fill: #ffe6bf;
  /* shrink to 45% around the end of the stalk (2912, 1354 in logo units) and drop it
     55 units, so the tapered tip drawn in LureStage.astro can join the two */
  transform: translateY(calc(55 / 820 * 100%)) scale(0.45);
  transform-origin: calc(312 / 470 * 100%) calc(24 / 820 * 100%);
  will-change: opacity;
}

/* The lure's own bloom, over the cup: a bright light washes over what is next to it. */
.lure-bloom {
  width: 9%;
  background: radial-gradient(
    closest-side,
    rgb(255 236 205 / 0.55),
    rgb(255 214 150 / 0.22) 35%,
    rgb(221 154 51 / 0.06) 70%,
    transparent
  );
  will-change: opacity;
}

/* Optional Blender still behind the light, placed so its lure sits on ours
   (its lure is at 69.8% across, 32% down the 16:9 frame). */
.lure-backdrop img {
  position: absolute;
  width: 130%;
  max-width: none;
  height: auto;
  left: calc(86.29% - 0.698 * 130%);
  top: calc(48.65% - 0.32 * 130% * 0.5625);
  -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent);
  mask-image: radial-gradient(closest-side, #000 55%, transparent);
}

.specks-still,
.specks-live {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 1.4s ease-out;
}
.specks-live {
  opacity: 0;
}
.lure-stage.is-live .specks-live {
  opacity: 1;
}
.lure-stage.is-live .specks-still {
  opacity: 0;
}

/* One still 128px tile of grain over the whole scene. It only ever darkens a pixel, so it
   cannot push text under its contrast floor, and it stops the one gradient on the site from
   banding on an 8-bit screen. Never animated. Built by tools/grain.py. */
.lure-grain {
  position: absolute;
  inset: 0;
  background-image: url('/grain.png');
  background-repeat: repeat;
  opacity: 0.55;
}

@media (forced-colors: active) {
  .lure-stage {
    display: none;
  }
}
@media print {
  .lure-stage {
    display: none;
  }
}
/* These additions belong only to the in-context previews. Existing routes keep their look. */
.evolution-bar {
  position: fixed; z-index: 80; inset: auto 16px 16px;
  width: max-content; max-width: calc(100% - 32px); margin-inline: auto;
  display: flex; align-items: center; gap: 20px; padding: 12px 18px;
  background: #13110c; border: 1px solid var(--line-strong); border-radius: 6px;
  box-shadow: 0 12px 40px #0009; font-size: 12px; color: var(--text);
}
.evolution-bar nav { display: flex; gap: 5px; }
.evolution-bar a { color: var(--text); text-decoration: none; padding: 8px 10px; min-height: 36px; }
.evolution-bar a:hover { color: var(--amber-lit); }
.evolution-bar [aria-current] { background: var(--amber); color: var(--ink); border-radius: 3px; }
.evolution-bar .evolution-index { color: var(--amber-lit); padding-left: 0; }
[data-evolution] .site-footer { padding-bottom: 130px; }
[data-evolution] .onpage { scroll-margin-bottom: 110px; }

/* Services: each category is an entrance into the real service list. */
[data-evolution='services'] .plate-key-link {
  display: block; color: inherit; text-decoration: none; padding: 12px 16px;
  border-radius: 4px; outline-offset: 6px;
  background: linear-gradient(90deg, #0a0806ed, #0a080688);
}
[data-evolution='services'] .plate-key-link:hover,
[data-evolution='services'] .plate-key-link:focus-visible { background: #19140dee; }
[data-evolution='services'] .plate-key-link:is(:hover,:focus-visible) .plate-word { color: var(--amber-lit); }
[data-evolution='services'] .plate-fish path { transition: opacity 220ms ease-out; }
[data-evolution='services'] .plate:has(.plate-key-link:is(:hover,:focus-visible)) .plate-fish:not(.is-lit) path { opacity: .48; }
[data-evolution='services'] .plate-leaders polyline { transition: stroke 160ms ease-out; }
[data-evolution='services'] .plate:has(.is-track .plate-key-link:is(:hover,:focus-visible)) .plate-leaders polyline:nth-child(1),
[data-evolution='services'] .plate:has(.is-unveil .plate-key-link:is(:hover,:focus-visible)) .plate-leaders polyline:nth-child(2),
[data-evolution='services'] .plate:has(.is-protect .plate-key-link:is(:hover,:focus-visible)) .plate-leaders polyline:nth-child(3),
[data-evolution='services'] .plate:has(.is-prevail .plate-key-link:is(:hover,:focus-visible)) .plate-leaders polyline:nth-child(4) { stroke: var(--amber-lit); stroke-width: 2.5px; }
[data-evolution='services'] .plate:has(.is-track .plate-key-link:is(:hover,:focus-visible)) .plate-dot:nth-of-type(1),
[data-evolution='services'] .plate:has(.is-unveil .plate-key-link:is(:hover,:focus-visible)) .plate-dot:nth-of-type(2),
[data-evolution='services'] .plate:has(.is-protect .plate-key-link:is(:hover,:focus-visible)) .plate-dot:nth-of-type(3),
[data-evolution='services'] .plate:has(.is-prevail .plate-key-link:is(:hover,:focus-visible)) .plate-dot:nth-of-type(4) { fill: var(--amber-lit); r: 24; }
[data-evolution='services'] .tile:target { outline: 2px solid var(--amber); outline-offset: 5px; }

/* Family: the active branch remains attached to the lamp, and the marks stay in place. */
[data-evolution='family'] .fam-lines polyline { transition: stroke 180ms ease-out, stroke-width 180ms ease-out; }
[data-evolution='family'] .fam-opening:has(.fam-link:is(:hover,:focus-visible)) .fam-lines polyline { stroke: #dd9a3326; }
[data-evolution='family'] .fam-opening:has(.fam-member:nth-child(1) .fam-link:is(:hover,:focus-visible)) .fam-lines polyline:nth-child(1),
[data-evolution='family'] .fam-opening:has(.fam-member:nth-child(2) .fam-link:is(:hover,:focus-visible)) .fam-lines polyline:nth-child(2),
[data-evolution='family'] .fam-opening:has(.fam-member:nth-child(3) .fam-link:is(:hover,:focus-visible)) .fam-lines polyline:nth-child(3),
[data-evolution='family'] .fam-opening:has(.fam-member:nth-child(4) .fam-link:is(:hover,:focus-visible)) .fam-lines polyline:nth-child(4) { stroke: #f3b45a; stroke-width: 2; }
[data-evolution='family'] .fam-link:is(:hover,:focus-visible) .fam-mark { filter: drop-shadow(0 8px 14px #dd9a3340); }
[data-evolution='family'] .fam-link:is(:hover,:focus-visible) .fam-name { color: var(--amber-lit); }

/* Capability: the pale surface is confined to the record, surrounded by existing dark water. */
[data-evolution='capability-statement'] .cred {
  --text: #1a1712; --text-2: #5e5647; --amber: #7a5419; --card-edge: #c6c2b8;
  color: var(--text); border-radius: 12px;
  background: radial-gradient(ellipse at var(--lx) var(--ly), #fff 0, #f0f0ee 48%, #d9d8d2 100%);
  box-shadow: inset 0 1px #fff, 0 28px 70px -30px #000c;
}
[data-evolution='capability-statement'] .cred-line-value.is-data { color: var(--text); }
[data-evolution='capability-statement'] .cred-facts { background: #f0f0eee8; padding: 16px; border-radius: 4px; }
[data-evolution='capability-statement'] .cred-fish-shadow { fill: #b5b3ab; translate: 3px 5px; }
[data-evolution='capability-statement'] .cred-fish-base { fill: #e9e8e2; filter: drop-shadow(-2px -2px 1px #fff); }
[data-evolution='capability-statement'] .cred-fish-lit { fill: #fffdf4; opacity: .9; }
[data-evolution='capability-statement'] .cred::before { background-image: linear-gradient(#85765712 1px,transparent 1px),linear-gradient(90deg,#85765712 1px,transparent 1px); }
[data-evolution='capability-statement'] .cred-org { color: #514838; background: #f0f0eee8; padding: 5px 8px; }

/* Approach: a slower near pass, with separate movement in the light and the surrounding water. */
@supports (animation-timeline: scroll()) {
 @media(prefers-reduced-motion:no-preference) {
  html.js:not(.motion-paused) [data-evolution='approach'] .lure-frame {
    animation: evolution-swim linear both; animation-timeline: scroll(root);
    transform-origin: 70% 50%;
  }
  html.js:not(.motion-paused) [data-evolution='approach'] .dive-sec {
    view-timeline-name: --principle-passage; view-timeline-axis: block;
  }
  html.js:not(.motion-paused) [data-evolution='approach'] .dive-sec .card {
    animation: evolution-page-depth linear both; animation-timeline: --principle-passage;
    animation-range: entry 0% exit 100%;
  }
  html.js:not(.motion-paused) [data-evolution='services'] .plate-art {
    view-timeline-name: --anatomy; view-timeline-axis: block;
  }
  html.js:not(.motion-paused) [data-evolution='services'] .plate-leaders {
    animation: evolution-leaders linear both; animation-timeline: --anatomy;
    animation-range: entry 15% entry 95%; stroke-dasharray: 1;
  }
 }
}
@keyframes evolution-swim {
  0% { translate: 0 0; rotate: 0deg; scale: 1; }
  28% { translate: 36vw 16vh; rotate: -3deg; scale: 1.07; }
  58% { translate: 76vw 30vh; rotate: 2deg; scale: 1.12; }
  100% { translate: 125vw 40vh; rotate: 0deg; scale: 1; }
}
@keyframes evolution-page-depth { from { transform: translateY(16px); } to { transform: translateY(-16px); } }
@keyframes evolution-leaders { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@media(max-width:900px) {
 [data-evolution='capability-statement'] .cred .card-label { padding-right: 48px; }
 .evolution-bar { inset: auto 8px 8px; max-width: calc(100% - 16px); padding: 7px 10px; gap: 6px; flex-wrap: wrap; justify-content: space-between; }
 .evolution-bar nav { order: 3; width: 100%; justify-content: space-between; gap: 0; }
 .evolution-bar a { padding: 6px 8px; font-size: 11px; min-height: 30px; }

}
@media(max-aspect-ratio:1/1) {
 @keyframes evolution-swim {
  0% { translate: 0 0; rotate: 0deg; scale: 1; }
  48% { translate: 56vw 10vh; rotate: -2deg; scale: 1.05; }
  100% { translate: 150vw 16vh; rotate: 0deg; scale: 1; }
 }
}
@media(prefers-reduced-motion:reduce) { [data-evolution] .lure-frame, [data-evolution] .dive-sec .card { animation: none!important; } }
html.motion-paused [data-evolution] .lure-frame, html.motion-paused [data-evolution] .dive-sec .card { animation: none!important; }
@media print { .evolution-bar { display:none!important; } [data-evolution='capability-statement'] .cred-facts {padding:0;background:none;} }
@media(forced-colors:active) { .evolution-bar {border:1px solid CanvasText;} }
