/* Type scale. Three ramps had grown independently — the homepage, the
   template-owned pages, and the about document — and three pairs had landed
   0.8px apart doing different jobs: 3.2/3.15rem, 2.6/2.55rem and 1.5/1.45rem.
   Those are not two decisions, they are one decision made twice. Every
   heading on the site now draws a step from here. Comments give the size at
   a desktop width; the clamps carry the small screens. */
:root {
  --t-1: clamp(2.6rem, 5vw, 4.15rem);    /* 66  hero */
  --t-2: clamp(2.1rem, 4vw, 3.15rem);    /* 50  page title, feature section */
  --t-3: clamp(1.75rem, 3vw, 2.55rem);   /* 41  section, document title */
  --t-4: clamp(1.7rem, 3.4vw, 2.35rem);  /* 38  reference page title */
  --t-5: clamp(1.55rem, 3vw, 2.1rem);    /* 34  subsection */
  --t-6: 1.5rem;                         /* 24  document section */
  --t-7: 1.25rem;                        /* 20  small heading */
  --t-8: 1.125rem;                       /* 18  label heading */
}

/* Radius scale. Seven values were in use across these stylesheets (2, 3, 4,
   6, 7, 10, 12) for three jobs, with 6/7 and 10/12 doing the same work at
   one pixel apart. Three tiers, defined here because shell.css is the one
   stylesheet both layouts load; custom properties resolve at computed-value
   time, so load order does not matter. The 2px on :focus-visible is left
   alone: it tracks the outline, not the surface. */
:root {
  --r-chip:    4px;   /* severity badges, small markers */
  --r-control: 7px;   /* buttons, menu items, scrollbar thumb */
  --r-panel:  12px;   /* dropdown panels, cards, figure zones */
}

/* Shared site shell: header and footer, one definition for every layout.
   Loaded by both the dark homepage layout and the default layout, so the
   navigation cannot differ between pages the way it did when each layout
   carried its own. Tokens mirror alt-home.css / dark.css. */

/* .wrap is the shell's container. It was defined only in alt-home.css, so
   the shared header sat flush to the viewport edge on every page that does
   not load that file. It belongs here, with the shell that uses it. */
.masthead .wrap, .siteftr .wrap {
  width: min(1240px, 100% - clamp(1.25rem, 4vw, 4rem) * 2);
  margin-inline: auto;
}

.masthead {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, #0b1017 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid rgba(226,234,245,.07);
}
.masthead-in { display: flex; align-items: center; gap: 1.5rem; min-height: 62px; }
.wordmark-link { display: inline-flex; align-items: center; }
/* 36px, not 30. The wordmark was the shortest anchor in a bar where the
   CTA button stands 39px, so the brand read as subordinate to its own
   button. The 2x asset is 309x105 real pixels, which stays sharp on a
   retina display up to about 52px, so this costs nothing in crispness. */
.wordmark-img { height: 36px; width: auto; display: block; }

.masthead-nav { display: flex; align-items: center; gap: 1.5rem; margin-left: auto; }
.masthead-nav > a,
.masthead-nav .has-sub > button {
  color: #aab6c6; text-decoration: none; font-size: .9375rem;
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: inherit; white-space: nowrap;
}
.masthead-nav > a:hover, .masthead-nav .has-sub:hover > button { color: #e6edf6; }

/* The .5rem the panel hangs below the trigger is padding ON the trigger,
   cancelled by an equal negative margin so the nav's vertical alignment is
   unchanged. This makes the offset part of .has-sub itself, so there is no
   strip of empty space between button and panel for the pointer to cross —
   the menu no longer closes when you move down toward it. Placing the gap
   outside .has-sub (a bare `top: calc(100% + .5rem)`) is what broke it. */
.has-sub { position: relative; padding-bottom: .5rem; margin-bottom: -.5rem; }
.has-sub > button::after { content: ""; display: inline-block; margin-left: .35rem;
  border: 4px solid transparent; border-top-color: currentColor; transform: translateY(2px); }
.has-sub .sub {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%) translateY(-4px);
  min-width: 13rem; padding: .4rem; border-radius: var(--r-panel);
  background: #121a24; border: 1px solid rgba(226,234,245,.13);
  box-shadow: 0 18px 44px -18px rgba(0,0,0,.85);
  display: flex; flex-direction: column; gap: .1rem;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 150ms cubic-bezier(.2,.7,.3,1), transform 150ms cubic-bezier(.2,.7,.3,1);
}
.has-sub:hover .sub, .has-sub:focus-within .sub {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.has-sub .sub a {
  color: #aab6c6; text-decoration: none; font-size: .875rem;
  padding: .5rem .65rem; border-radius: var(--r-control); white-space: nowrap;
}
.has-sub .sub a:hover { color: #e6edf6; background: #1b2531; }

.masthead-cta { display: flex; align-items: center; gap: 1rem; }
.masthead-cta > a:not(.btn) { color: #aab6c6; text-decoration: none; font-size: .9375rem; }
.masthead-cta > a:not(.btn):hover { color: #e6edf6; }
.masthead .btn {
  display: inline-flex; align-items: center; padding: .52rem .95rem; border-radius: var(--r-control);
  background: #e6edf6; color: #0b1017; font-weight: 700; font-size: .875rem;
  text-decoration: none; border: 0;
  transition: background 160ms cubic-bezier(.2,.7,.3,1);
}
.masthead .btn:hover { background: #fff; color: #0b1017; }

.siteftr { border-top: 1px solid rgba(226,234,245,.13); background: #0b1017; }
.siteftr-in { display: grid; gap: 2rem; padding-block: clamp(2.5rem, 5vw, 3.75rem); align-items: start; }
@media (min-width: 56rem) { .siteftr-in { grid-template-columns: 1.5fr 1fr 1fr 1fr; } }
.siteftr nav { display: flex; flex-direction: column; gap: .55rem; }
.siteftr nav a { color: #aab6c6; text-decoration: none; font-size: .9375rem; width: fit-content; }
.siteftr nav a:hover { color: #e6edf6; text-decoration: underline; text-underline-offset: .22em; }
.siteftr-note { color: #7b8797; font-size: .875rem; margin-top: .7rem; max-width: 34ch; }
.siteftr .colophon {
  border-top: 1px solid rgba(226,234,245,.07); padding-block: 1.4rem;
  color: #7b8797; font-size: .75rem;
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .6rem 1.5rem;
}
/* Legal sits with the copyright, which is where a reader looks for it, and
   keeps that bar's voice rather than the nav column's — the outranked rule
   is .siteftr nav a. */
/* row, not column: .siteftr nav stacks its links, which is right in the
   link columns above and wrong in a single-line bar. */
.siteftr .colophon nav { display: flex; flex-direction: row; gap: 1.25rem; }
.siteftr .colophon nav a {
  color: #7b8797; font-size: .75rem; text-decoration: none;
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}
.siteftr .colophon nav a:hover { color: #e6edf6; text-decoration: underline; text-underline-offset: .22em; }

/* The toggle is a mobile control; desktop never shows it. */
.nav-toggle { display: none; }

@media (max-width: 60rem) {
  /* The row used to stay a row and scroll sideways. Nine links laid out to
     773px inside a 389px viewport, so most of the site was off-screen with
     nothing indicating it, and every link was a 24px tap target against a
     44px minimum. It is a panel now. */
  .masthead-in { flex-wrap: wrap; padding-block: .6rem; gap: .75rem; }

  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin-left: auto;
    background: none; border: 1px solid rgba(226,234,245,.13);
    border-radius: var(--r-control); cursor: pointer; padding: 0;
  }
  .nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
    display: block; width: 17px; height: 2px; border-radius: 2px;
    background: #e6edf6; content: "";
  }
  .nav-toggle-bars { position: relative; }
  .nav-toggle-bars::before { position: absolute; top: -6px; }
  .nav-toggle-bars::after  { position: absolute; top: 6px; }
  .nav-toggle[aria-expanded="true"] { background: rgba(226,234,245,.08); }

  .masthead-cta { order: 2; margin-left: 0; }

  .masthead-nav {
    order: 3; width: 100%; margin-left: 0;
    display: none; flex-direction: column; align-items: stretch; gap: 0;
    border-top: 1px solid rgba(226,234,245,.07); margin-top: .35rem;
  }
  .nav-open .masthead-nav { display: flex; }

  /* 44px minimum, and the whole row is the target rather than the glyphs. */
  .masthead-nav > a,
  .has-sub .sub a {
    display: flex; align-items: center; min-height: 44px;
    padding: 0 .1rem; font-size: 1rem; white-space: normal;
  }

  /* The desktop panel is a floating card. Here the group is just a labelled
     run of links in the list, so it loses the card and keeps the heading. */
  .has-sub { padding-bottom: 0; margin-bottom: 0; position: static; }
  .has-sub > button {
    display: flex; align-items: center; min-height: 44px; width: 100%;
    font-size: .75rem; letter-spacing: .09em; text-transform: uppercase;
    color: #7b8797; cursor: default; padding: .6rem .1rem 0;
  }
  .has-sub > button::after { display: none; }
  .has-sub .sub {
    position: static; transform: none; opacity: 1; visibility: visible;
    pointer-events: auto; box-shadow: none; border: 0; background: none;
    padding: 0; min-width: 0; flex-direction: column; gap: 0;
    transition: none;
  }
  .has-sub .sub a { padding-left: .1rem; border-radius: 0; }

  /* The rest of the touch targets. The footer's link columns were 24px
     rows, the header CTA 39px and the wordmark 36px, all under the 44px
     minimum. */
  .siteftr nav a,
  .siteftr .colophon nav a { min-height: 44px; display: flex; align-items: center; }
  .masthead .btn { min-height: 44px; }
  .wordmark-link { min-height: 44px; }
}

/* the compiled theme title-cases every .btn; the shell writes its own labels */
.masthead .btn, .siteftr a, .masthead-nav a, .masthead-nav button { text-transform: none !important; }

/* Anchor navigation glides rather than cuts. The compiled theme declares
   this, but only the default layout loads that stylesheet, so nav links
   scrolled smoothly on every page except the homepage, which jumped.
   shell.css is the one stylesheet both layouts load, so it belongs here.
   Wrapped in the motion query: a visitor who has asked for reduced motion
   gets the instant jump, which is the accessible behaviour. */
@media (prefers-reduced-motion: no-preference) {
  :root { scroll-behavior: smooth; }
}


/* ---- quotes ----------------------------------------------------------
   Shared, because the about page shows the same three testimonials the
   homepage does and was rendering them through the template's swiper
   carousel instead — a different presentation of identical content, with
   two light-theme blur images behind it. Literal colours here because
   shell.css is loaded by both layouts and their palettes define different
   token names for the same values. */
.quotes { display: grid; gap: 1.75rem; margin-top: 2.25rem; }
@media (min-width: 56rem) { .quotes { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }
.quotes blockquote { margin: 0; padding-top: 1.1rem; border-top: 1px solid rgba(226, 234, 245, .13); }
.quotes p { color: #e6edf6; font-size: 1.0625rem; line-height: 1.55; max-width: none; }
/* Sans, for the same reason the spec terms are: mono on this site means a
   machine value, and a person's name and job title are neither. It was
   also the only mono left that named a human being. */
.quotes footer { margin-top: .85rem; color: #7b8797; font-size: .8125rem; letter-spacing: -.01em; }
/* the person is the attribution; the role qualifies it. An unattributed
   quote is a weaker claim, so the name carries the brighter weight. */
.quotes footer .qname { display: block; color: #aab6c6; font-size: .9375rem; font-weight: 600; }
