/* 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; }
/* The panel's own CTA; desktop has the one in .masthead-cta. */
.masthead-nav > .nav-cta { display: none; }

.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,
.siteftr .colophon nav button {
  color: #7b8797; font-size: .75rem; text-decoration: none;
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}
/* "Cookie preferences" is a button (it opens the cookie card in place), set
   to read as one more link in the row. */
.siteftr .colophon nav button {
  background: none; border: 0; border-radius: 0; padding: 0;
  line-height: inherit; cursor: pointer;
}
.siteftr .colophon nav a:hover,
.siteftr .colophon nav button: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); }

  /* No header CTA on mobile: the toggle takes the right edge on its own. */
  .masthead-cta { display: none; }

  .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; }
  .masthead-nav > .nav-cta {
    display: flex; justify-content: center; min-height: 44px;
    margin: .75rem 0 .6rem; font-size: .9375rem;
  }

  /* 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's links just join
     the list, with no card and no "Resources" label: the label kept the
     look of a dropdown trigger but opened nothing, since the links are
     always shown. */
  .has-sub { padding-bottom: 0; margin-bottom: 0; position: static; }
  .has-sub > button { display: none; }
  /* The open states are listed too, because the desktop rule for them
     (.has-sub:hover .sub) outranks a bare .has-sub .sub. A tap on
     Resources sets :hover, and its translateX(-50%) slid every link
     175px off the left edge, so the group vanished when touched. */
  .has-sub .sub,
  .has-sub:hover .sub,
  .has-sub:focus-within .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 and the wordmark 36px, both under the 44px minimum. */
  .siteftr nav a,
  .siteftr .colophon nav a,
  .siteftr .colophon nav button { min-height: 44px; display: flex; align-items: center; }
  .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; }
