/* Always Allow shared system. Extracted 2026-08-26 from the boards canvas
   (the homepage source of truth, FACTS Part D rulings 28-38). Other pages
   import this file; homepage-only moments (the animated hero, the glass band)
   live in homepage.css, not here.

   Tokens are the settled system: canvas near-white, bone on surfaces never the
   floor, blue-slate ink, Petrol accent as fills and markers never text, all
   Inter, and the four-part depth ladder (rest, raised, float). */

/* This file has to stand on its own. The homepage also loads a large inline
   style block lifted from a frozen review page, and several things this
   sheet appears to own were in fact only ever supplied by that block, so a
   page loading system.css alone rendered differently. The four below were
   found that way on 2026-08-26 and are now declared here. */
@import url("https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=Inter:wght@400;500;600;700;800&display=swap");

/* Exactly `*`, matching the frozen block, not the broader `*, *::before,
   *::after`. The wider form is the better rule in the abstract, but it
   changes pseudo-element sizing on the locked homepage: it took 3px off the
   dropdown caret, which is drawn from two borders on a ::after. Matching the
   existing behaviour keeps every page identical to the approved one. */
* { box-sizing: border-box; }

/* The full-viewport wash layers are centred on the content column, so each
   overflows by about half a scrollbar width. The homepage never showed it
   because the frozen block clips the document; a page without that block
   scrolls sideways immediately.

   clip rather than hidden, 2026-09-27, here and on .page-body. hidden made
   the body its own scroll box, one that never scrolls, so nothing on any page
   could stay pinned (the /contact and /wwbw panels, the brand kit header, the
   Tools Radar card) and every scroll-driven animation sat frozen. clip trims
   the same overflow without making a scroll box. hidden stays first for
   browsers that do not know clip. */
html, body { overflow-x: hidden; overflow-x: clip; }

:root {
  --canvas: #FEFDFB;
  --bone: #F0ECE6;
  --bone-deep: #E7E0D4;
  --hairline: #E3DDD2;
  --ink: #344650;
  --muted: #427294;
  --accent: #1D5372;
  --chip-gold: #F3E5C2;
  --sans: "Inter", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --serif: "DM Serif Display", Georgia, "Times New Roman", serif;
  --shadow-rest: 0 1px 2px rgba(28,45,58,0.06), 0 2px 8px rgba(28,45,58,0.05);
  --shadow-raised: 0 2px 4px rgba(28,45,58,0.07), 0 10px 24px rgba(28,45,58,0.09);
  --shadow-float: 0 4px 8px rgba(28,45,58,0.08), 0 24px 48px rgba(28,45,58,0.14);

  /* Layout contract. These are measured from the live site at desktop size.
     A page may arrange its own material, but it should not invent another
     shell, navigation height, type scale, or spacing rhythm. */
  --layout-shell: 1160px;
  --layout-artifact-stage: 1120px;
  --layout-gutter-total: 48px;
  --nav-h: 92px;
  --nav-pad-y: 26px;
  --space-copy: 12px;
  --space-control: 24px;
  --space-row: 48px;
  --space-opening: 64px;
  --space-section: 104px;
  --type-display: clamp(54px, 4.35vw, 62px);
  --type-page-title: clamp(34px, 3.4vw, 46px);
  --type-section: clamp(26px, 2.4vw, 34px);
  --type-item: 27px;
  --type-support: 20px;
  --measure-copy: 62ch;
  --photo-gap: 16px;
  --photo-ratio: 4 / 3;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; }

.shell, .page-shell { width: min(var(--layout-shell), calc(100% - var(--layout-gutter-total))); margin: 0 auto; }
.artifact-shell { width: min(var(--layout-artifact-stage), calc(100% - var(--layout-gutter-total))); margin: 0 auto; }
section { margin-top: var(--space-section); }
h2 { margin: 0; font-size: var(--type-section); font-weight: 700; letter-spacing: -0.018em; line-height: 1.15; }
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }
.lede { margin: var(--space-copy) 0 0; font-size: 17px; color: var(--muted); max-width: var(--measure-copy); text-wrap: balance; }

/* Three type roles, matching the three heading levels in the visual guide.
   Display is the only serif role. Section and item headings stay in Inter. */
.display-title {
  margin: 0; font-family: var(--serif); font-size: var(--type-display);
  font-weight: 400; letter-spacing: -0.02em; line-height: 1.03;
}
.section-title {
  margin: 0; font-family: var(--sans); font-size: var(--type-section);
  font-weight: 700; letter-spacing: -0.018em; line-height: 1.15;
}
.item-title {
  margin: 0; font-family: var(--sans); font-size: var(--type-item);
  font-weight: 700; letter-spacing: -0.02em; line-height: 1.2;
}
.support-label {
  margin: 0; font-family: var(--sans); font-size: var(--type-support);
  font-weight: 700; letter-spacing: -0.01em; line-height: 1.25;
}
.copy-measure { max-width: var(--measure-copy); }

/* Buttons. The primary is the accent as a fill, never as text. */
.btn {
  display: inline-block; font-family: var(--sans); font-size: 15px; font-weight: 500;
  padding: 11px 20px; border-radius: 8px; cursor: pointer; text-decoration: none;
  border: 1px solid var(--bone-deep); background: var(--bone); color: var(--ink);
  box-shadow: 0 1px 0 rgba(28,45,58,0.05);
  transition: transform 140ms ease, box-shadow 140ms ease;
}
.btn.on-bone { background: #FFFFFF; }
.btn.primary {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 84%, white),
    var(--accent) 55%,
    color-mix(in srgb, var(--accent) 86%, black));
  border-color: color-mix(in srgb, var(--accent) 86%, black);
  color: #FEFDFB;
  box-shadow: 0 1px 2px rgba(28,45,58,0.2), 0 4px 12px color-mix(in srgb, var(--accent) 30%, transparent);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-raised); border-bottom-width: 1px; }
.btn.small { font-size: 13.5px; padding: 8px 15px; }

/* Navigation: the brand keycap plus flat links, straight on the page. */
.aa-nav { display: flex; align-items: center; justify-content: space-between; padding: var(--nav-pad-y) 0; gap: var(--space-control); }
/* The lockup grew 4% on her ask 2026-08-26, so it carries more of the bar
   against the Join a workshop button. One number does it: the keycap sizes
   itself in em, so the mark and the words scale together. */
/* The brand lockup is the serif, everywhere. This rule used to say Inter 700 and
   the serif treatment lived only in assets/homepage.css, so the homepage rendered
   the lockup one way and About, Privacy and engagements rendered it another. Sarah
   caught it on two separate pages. Moving it here is what makes every page agree;
   homepage.css still carries its own identical .brand rule, which is now redundant
   rather than load-bearing. DM Serif Display ships one weight, 400, so asking for
   700 here produced a synthesised faux bold. */
.brand { display: flex; align-items: center; gap: 12px; font-size: 17.7px; font-family: "DM Serif Display", Georgia, "Times New Roman", serif; font-weight: 400; letter-spacing: -0.01em; color: var(--ink); text-decoration: none; }
/* The keycap, moved here from the homepage 2026-08-26 (ruling 63) so it
   travels to every page with its shimmer and its Easter egg. Its size and
   colour used to come from two leftover rules in the generated homepage's own
   inline block, which is why a page built on this file alone got a smaller
   ink-coloured key. Written at .brand .keycap so this file wins wherever
   those leftovers still load. */
/* The rendered logo master (/assets/mark.svg, the two-glyph command-and-enter
   keycap from the locked construction) replaces the CSS-drawn key on Sarah's
   2026-08-29 ask; she named the master over the one-glyph small cut after
   seeing both. The font-size pin is what makes the em sizing identical on
   every page: the generated homepage still carries a leftover 0.9em keycap
   rule that otherwise shrinks the mark there. Width is height times the
   SVG's own 1.2545 aspect, so the artwork is never stretched. */
.brand span.keycap {
  position: relative;
  /* inline-block is inert today, because every .brand is a flex container and
     a flex item is blockified anyway. It is here so the empty span's box does
     not depend on that: in any future non-flex context an inline span with no
     content collapses to zero width and the mark vanishes. */
  display: inline-block;
  width: 2.63em; height: 2.1em; font-size: 1em;
  background: url(/assets/mark.svg) center / contain no-repeat;
  cursor: pointer; top: 0; transition: top 120ms ease;
}
/* The discovery shimmer, her round-twenty ask: a sheen sweeps the key face
   and re-shines about every two seconds, so the eye finds the egg. */
/* The sheen is masked to the key face. Without the mask it is a plain rounded
   rectangle over the whole span box, and the mark does not fill that box: the
   key is drawn in perspective with an angled top-left, the Petrol slab sits
   below and right of the face, and the corners are transparent. So the shine
   painted white onto the page outside the artwork and washed the slab pale,
   which reads as a glow sitting around the two glyphs rather than a sheen
   crossing the face. Her report, 2026-08-31, on both the nav and footer keys.
   The path is the face outline lifted verbatim from mark.svg on that file's
   own viewBox, so re-lift it if the master is ever regenerated. It is inlined
   rather than pointing at mark.svg because masking to the whole mark still
   lets the shine cross the slab, and because this sheet has to stand on its
   own. */
.brand span.keycap::after {
  content: ""; position: absolute; inset: 0; border-radius: 10%; pointer-events: none;
  background: linear-gradient(115deg,
    transparent 32%, rgba(255,255,255,0.85) 44%,
    color-mix(in srgb, var(--accent) 20%, transparent) 52%, transparent 64%);
  background-size: 230% 100%; background-position: 180% 0;
  -webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-3.0 -4.9 519.1 413.8'><path d='M 82.97 25.67 L 420.03 12.83 Q 465.00 11.12 465.00 56.12 L 465.00 243.88 Q 465.00 288.88 420.00 288.88 L 60.00 288.88 Q 15.00 288.88 20.12 244.17 L 40.67 64.87 Q 45.00 27.12 82.97 25.67 Z' fill='%23fff'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-3.0 -4.9 519.1 413.8'><path d='M 82.97 25.67 L 420.03 12.83 Q 465.00 11.12 465.00 56.12 L 465.00 243.88 Q 465.00 288.88 420.00 288.88 L 60.00 288.88 Q 15.00 288.88 20.12 244.17 L 40.67 64.87 Q 45.00 27.12 82.97 25.67 Z' fill='%23fff'/></svg>") center / contain no-repeat;
  animation: keyShine 2.2s ease-in-out infinite;
}
@keyframes keyShine {
  0% { background-position: 180% 0; }
  38%, 100% { background-position: -80% 0; }
}
/* The press moves the key with top, never transform: a transform makes the
   keycap a stacking context, which lifts the wall in front of the face. */
.brand:hover span.keycap { top: 2px; }
.brand { position: relative; }
/* The hint and the three cursor states, the live one popped forward. */
.brand span.egg-hint {
  position: absolute; top: calc(100% + 10px); left: 0; white-space: nowrap;
  display: flex; align-items: center; gap: 8px;
  font-family: var(--sans); font-size: 0.9em; font-weight: 400;
  letter-spacing: 0.02em; color: var(--accent);
  opacity: 0; translate: 0 -3px; pointer-events: none;
  transition: opacity 200ms ease 250ms, translate 200ms ease 250ms;
}
.egg-words { font-size: 0.9em; }
.egg-cycle { display: inline-flex; align-items: center; gap: 6px; }
.egg-c {
  display: grid; place-items: center; width: 14px; height: 14px;
  opacity: 0.4; color: var(--muted);
  transition: opacity 180ms ease, transform 180ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.egg-c img, .egg-c svg { width: 11px; height: 11px; object-fit: contain; display: block; }
.egg-c.egg-on { opacity: 1; color: var(--ink); transform: scale(1.3); }
.brand:hover span.egg-hint { opacity: 1; translate: 0 0; }
.aa-foot .brand span.egg-hint { top: auto; bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%); }
/* The cursor states themselves. The Claude mark spins through sixteen
   pre-rotated frames swapped on a CSS variable; the static png is the
   fallback and the reduced-motion state. */
html.cursor-claude, html.cursor-claude * { cursor: var(--egg-cursor, url(/assets/cursor-claude.png) 4 4, auto) !important; }
html.cursor-openai, html.cursor-openai * { cursor: url(/assets/cursor-openai.svg) 4 4, auto !important; }
@media (prefers-reduced-motion: reduce) {
  .brand span.keycap::after { animation: none; }
  .brand span.keycap, .brand span.egg-hint { transition: none; }
}
.navlinks { display: flex; align-items: center; gap: var(--space-control); font-size: 14px; font-weight: 500; }
.navlinks a { color: var(--ink); }
.navlinks a:not(.btn):hover { border-bottom: 1.5px solid var(--ink); }
/* The Work together dropdown (2026-08-26): a native details element, no
   marker, a caret drawn in ink, and a floating glass panel in the depth
   ladder. The engagement routes live here; the panel links override the
   flat-link hover underline. */
.nav-menu { position: relative; }
.nav-menu summary {
  display: flex; align-items: center; gap: 6px; cursor: pointer; list-style: none;
  color: var(--ink);
}
.nav-menu summary::-webkit-details-marker { display: none; }
.nav-menu summary::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid var(--ink); border-bottom: 1.5px solid var(--ink);
  transform: rotate(45deg); transition: transform 160ms ease;
}
.nav-menu[open] summary::after { transform: rotate(225deg); margin-top: 3px; }
/* Her note 2026-08-26: the rounded card read as a box sitting on the page.
   It takes the returning nav bar's treatment instead, so it reads as the
   background going soft rather than a panel arriving.

   The bar can be a flat tint because it spans the viewport and has no side
   edges to show. A panel does, and a straight edge on a tone region is the
   thing ruling 38 forbids, so the tint and its blur live on a masked layer
   that feathers out in every direction. The layer sits behind the links
   rather than around them: masking the panel itself would fade the words
   at the edges too. */
/* backdrop-filter is reset explicitly. The frozen review page's own rule sets
   blur(18px) on this element, and dropping the background without dropping
   the filter left the panel blurring its own rectangle: that unfeathered box,
   clipped to the border box, was the straight edge in her screenshot, not the
   soft layer below. */
.nav-menu-panel {
  position: absolute; top: calc(100% + 6px); left: -20px; z-index: 50;
  min-width: 210px; display: grid; gap: 2px; padding: 14px 20px 18px;
  background: none; border: 0; border-radius: 0; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* The soft layer hangs off the menu, not off the panel. Measured 2026-08-26:
   as the panel's own ::before it was clipped to the panel's border box, so
   the blur stopped dead on a straight vertical line at the panel edge, which
   is the thing being removed. Out here nothing clips it, and it is wider and
   taller than the panel so the feather completes in the spare room.

   The ellipse also has to reach transparent INSIDE the layer: a mask sized
   past its own box stays opaque to the edge and draws the same hard line. */
.nav-menu[open]::after {
  content: ""; position: absolute; z-index: 49; pointer-events: none;
  left: -74px; width: 350px; top: calc(100% - 14px); height: 220px;
  background: color-mix(in srgb, var(--canvas) 70%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(1.15); backdrop-filter: blur(20px) saturate(1.15);
  /* The vertical radius must be at most half the height, because the centre
     sits at 48% and the transparent stop is at 96% of the radius: anything
     larger puts that stop outside the box and the layer terminates on a
     straight horizontal line instead of fading. Measured at 56%: the mask
     was still 21% opaque at the top edge and 6% at the bottom, so the blur
     ended on a visible line above the panel. At 48% both edges reach 0. */
  -webkit-mask-image: radial-gradient(52% 48% at 50% 48%, black 46%, transparent 96%);
  mask-image: radial-gradient(52% 48% at 50% 48%, black 46%, transparent 96%);
}
/* Written long enough to beat the flat-link hover, which is .navlinks
   a:not(.btn):hover and was still drawing a heavy underline under every
   panel row, and the old rounded-card hover, which was still filling the
   row with bone. A panel row moves in colour only. */
/* The markup this expects: .navlinks > details.nav-menu > .nav-menu-panel > a.
   Written that long deliberately, to beat the flat-link hover. font-size and
   text-stroke are declared rather than inherited because the frozen block
   supplies both on the homepage and nowhere else, so a page on this file
   alone rendered the rows a quarter larger and a half-weight lighter. */
.navlinks .nav-menu-panel a:not(.btn) {
  padding: 7px 0; border-radius: 0; background: none; border-bottom: 0;
  font-size: 11.2px; -webkit-text-stroke: 0;
  color: var(--ink); transition: color 140ms ease;
}
.navlinks .nav-menu-panel a:not(.btn):hover,
.navlinks .nav-menu-panel a:not(.btn):focus-visible {
  border-bottom: 0; background: none; color: var(--accent);
}
/* The trigger kept the browser's own focus ring after a click, a hard blue
   rectangle over the bar. Keyboard focus still gets a visible ring. */
.nav-menu summary:focus { outline: none; }
.nav-menu summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* The phone menu, her call 2026-08-27.

   The links used to be hidden below 940px with nothing to replace them, so a
   narrow window or any phone left Partnerships and About unreachable: they are
   not in the footer either. Measured, the whole lockup needs 635px and the
   shell is the viewport less 48, so the links fit down to about 683px; 940 was
   hiding them roughly 250px early. Below 720 they move into a sheet instead of
   disappearing.

   The sheet reaches both viewport edges, which is what lets it carry a flat
   tint: like the returning nav bar it has no side edges to show. Its bottom
   fades out on a layer behind the words, never on the words themselves. */
.nav-burger { display: none; }
@media (max-width: 720px) {
  .nav-burger {
    display: grid; gap: 4px; place-content: center;
    width: 44px; height: 40px; padding: 0; border-radius: 10px; cursor: pointer;
    border: 1px solid rgba(255,255,255,0.55);
    background: color-mix(in srgb, var(--canvas) 52%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(1.2); backdrop-filter: blur(16px) saturate(1.2);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.9), var(--shadow-rest);
  }
  .nav-burger span {
    display: block; width: 18px; height: 1.5px; border-radius: 1px;
    background: var(--ink); transition: transform 180ms ease, opacity 140ms ease;
  }
  .aa-nav.nav-open .nav-burger span:first-child { transform: translateY(5.5px) rotate(45deg); }
  .aa-nav.nav-open .nav-burger span:nth-child(2) { opacity: 0; }
  .aa-nav.nav-open .nav-burger span:last-child { transform: translateY(-5.5px) rotate(-45deg); }
  .nav-burger:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

  .aa-nav { position: relative; }
  .navlinks {
    position: absolute; top: calc(100% + 6px); left: -24px; right: -24px; z-index: 60;
    display: none; flex-direction: column; align-items: stretch; gap: 0;
    padding: 14px 24px 26px;
  }
  .aa-nav.nav-open .navlinks { display: flex; }
  /* The tint reaches both viewport edges, so it has no sides to show. It
     fades at the top as well as the bottom: starting flat below the bar drew
     a straight line across the page, which is the thing the tone rules are
     about. The ramps sit in the gap and the padding, not across the words,
     and the layer is behind them so the words never fade with it. */
  .navlinks::before {
    content: ""; position: absolute; left: 0; right: 0; top: -26px; bottom: 0;
    z-index: -1;
    background: color-mix(in srgb, var(--canvas) 78%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(1.15); backdrop-filter: blur(20px) saturate(1.15);
    -webkit-mask-image: linear-gradient(180deg, transparent 0, black 12%, black 76%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0, black 12%, black 76%, transparent 100%);
  }
  .navlinks a:not(.btn) { padding: 12px 0; font-size: 15px; border-bottom: 0; }
  .navlinks a:not(.btn):hover { border-bottom: 0; color: var(--accent); }
  .navlinks .btn.primary { margin-top: 14px; text-align: center; font-size: 15px; padding: 11px 20px; }
  /* The engagement routes read as a plain list in the sheet: a dropdown
     inside a dropdown is a second thing to open on a small screen. */
  .navlinks .nav-menu { position: static; }
  .navlinks .nav-menu summary { display: none; }
  .navlinks .nav-menu[open]::after { display: none; }
  .navlinks .nav-menu-panel {
    position: static; display: grid; gap: 0; min-width: 0; padding: 0;
  }
  .navlinks .nav-menu-panel a:not(.btn) { font-size: 15px; padding: 12px 0; }
  @media (prefers-reduced-motion: reduce) {
    .nav-burger span { transition: none; }
  }
}

/* Footer, the three-zone colophon: links and LGK left, the brand centred, the
   three marks right, copyright on its own line. This is the whole footer, as
   approved. It used to be split, with the flex version here and the grid
   version that actually renders living in homepage.css, so any page importing
   this file alone got a different footer and, worse, three inline SVGs with
   no size, which render at the replaced-element default of 300x150 each. */
.aa-foot { position: relative; margin-top: var(--space-section); border-top: 1px solid var(--hairline); padding: 30px 0 44px; }
.foot-grid { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-control); }
.foot-grid .brand { justify-self: center; }
.foot-meta { font-size: 12.5px; color: var(--muted); display: flex; gap: 14px; flex-wrap: wrap; align-items: center; justify-self: start; }
/* Footer links were 20px tall, under the 24px minimum touch target, which is
   a small thing to hit on a phone. Padding rather than font-size, so nothing
   about the footer's look changes. */
.foot-meta a { color: var(--muted); display: inline-block; padding: 2px 0; }
.foot-meta a:hover { color: var(--ink); }
.knicks-orange { color: #F58426; font-weight: 600; }
.knicks-blue { color: #006BB6; font-weight: 600; }
.foot-soc { display: flex; align-items: center; gap: 14px; justify-self: end; }
/* Padding to the 24px minimum target with a matching negative margin, so the
   row looks unchanged. */
.soc-icon { color: var(--muted); display: inline-flex; padding: 7px; margin: -7px; }
.soc-icon:hover { color: var(--ink); border-bottom: 0; }
.soc-icon svg { width: 15px; height: 15px; display: block; }
.foot-copy { margin-top: 12px; text-align: center; font-size: 12px; color: var(--muted); }
/* The hello@ address is a link on her 2026-08-29 ask, the one mailto the
   site allows. Muted like its line, ink on hover like the meta links. */
.foot-copy a { color: var(--muted); }
.foot-copy a:hover { color: var(--ink); }
.aa-foot > * { position: relative; z-index: 1; }
@media (max-width: 900px) {
  .foot-grid { grid-template-columns: 1fr; justify-items: center; gap: 14px; }
  .foot-meta, .foot-soc { justify-self: center; }
}

/* Prose links. The reset above kills every underline, which is right for nav
   items, buttons and footer links because each has its own treatment, and
   wrong for body copy: an inline link in a paragraph became indistinguishable
   from the text around it. Long-form pages opt in with .prose or .doc-body. */
.prose a, .doc-body a {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--ink) 32%, transparent);
  text-underline-offset: 3px;
}
.prose a:hover, .doc-body a:hover { text-decoration-color: var(--ink); }

/* Arrivals sharpen (ruling 38): scrolled-to content focuses in from a soft
   blur, the measured Riveter move. No effect where unsupported or unwanted.
   Scoped away from .motion-field: the hero's three carousel slides are
   sections too, and a blur-and-fade on the page's one loud moment is not
   what this was written for.

   Tied to scrolling only under html.scroll-motion, 2026-09-27. Until the
   overflow change at the top of this file, this and the staircase motion in
   homepage.css and playbook.css sat frozen at their finished look, and every
   page was approved looking that way. Without the class each animation
   finishes at once and holds its last frame, so nothing moves; adding
   scroll-motion to <html> turns the scroll motion on everywhere. */
@supports (animation-timeline: view()) {
  section:not(.motion-field), .patterns-grid { animation: arrive linear both; }
  html.scroll-motion section:not(.motion-field), html.scroll-motion .patterns-grid {
    animation-timeline: view();
    animation-range: entry 0% entry 55%;
  }
  @keyframes arrive {
    from { filter: blur(12px); opacity: 0.7; transform: translateY(14px); }
    to { filter: blur(0); opacity: 1; transform: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    section:not(.motion-field), .patterns-grid { animation: none; }
  }
}

/* Reduced motion, the transforms the first pass missed. */
@media (prefers-reduced-motion: reduce) {
  .btn, .egg-c, .nav-menu summary::after { transition: none; }
}

/* ---- kit page modules, absorbed 2026-08-27 after the homepage merge ----
   The document layout ruling 67 approved on the Privacy mockup: rows with the
   heading in a left column, a hairline spanning the full width above each,
   the three plain opening answers with no label, and the footer rule sitting
   at the section rhythm. The tonal walk at page amplitude (ruling 54): other
   pages reuse the homepage's walk quieter, one peak, quiet ends. Nothing here
   is used by the homepage, which carries its own inline chrome. */
.walk { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
/* The layer runs the whole page, and the lower pool is placed a fixed
   distance down rather than at a percentage of the layer.

   It used to be a 820px-tall box holding a pool centred at 78% of that
   height, so the pool was still 37% opaque where the box stopped and the
   background stepped 8 grey levels in one row: a straight line across the
   page, measured 2026-08-27. Growing the box could not fix it, because a
   percentage centre moves down with the box and stays cut. This is the
   same rule as the masks: a feather has to reach its transparent stop
   inside its own box. */
.walk::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  background:
    radial-gradient(880px 480px at 82% 0%, color-mix(in srgb, var(--accent) var(--amp1, 10%), transparent), transparent 68%),
    radial-gradient(720px 400px at 10% 640px, color-mix(in srgb, var(--accent) var(--amp2, 6%), transparent), transparent 72%);
}
/* The nav bar is fixed, so it takes no space in flow. Pages built on
   .page-content pad themselves by the bar's height to stay put at rest. The
   homepage does the same thing on .aa-hero and has no .page-content, so it is
   untouched by this rule. */
.page-content { position: relative; z-index: 1; padding-top: var(--nav-h); }
/* Anchor links have to clear the fixed bar. Without this, following #coaching or
   #workshops scrolls the section to y=0 and the bar sits on top of its heading,
   which is only invisible from within the page because the bar happens to be
   hidden while scrolling down. Arriving cold from another page shows it plainly:
   the heading lands at y=30 under a bar reaching y=68. Caught by Devin on PR 55.
   The extra 14px is breathing room so the heading is not flush against the bar. */
html { scroll-padding-top: calc(var(--nav-h) + 14px); }
.page-body { position: relative; background: var(--canvas); overflow-x: hidden; overflow-x: clip; min-height: 100vh; }

/* Shared page composition. These classes hold the proportions that repeat
   across the live site. Page CSS owns the arrangement inside one and interaction
   inside each region, not a second set of outer dimensions. */
.page-opening {
  margin-top: 0;
  padding: var(--space-opening) 0 var(--space-row);
}
.page-opening--artifact { padding-top: 46px; }
.page-section { margin-top: var(--space-section); }
.page-section--compact { margin-top: var(--space-opening); }
.section-intro {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-opening); margin-bottom: var(--space-row);
}
.section-intro > :last-child { max-width: 38ch; }
.utility-links {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-control); margin-top: var(--space-control);
}

/* A standard workshop-photo strip. The 4:3 cards, 16px gap, full image, corners and
   shadow are the measured About and Partnerships carousel treatment. */
.photo-strip { position: relative; width: 100%; min-width: 0; overflow: hidden; }
.photo-strip__track {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: calc((100% - (3 * var(--photo-gap))) / 4);
  gap: var(--photo-gap); overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  padding-bottom: 18px; margin-bottom: -18px;
}
.photo-strip__track::-webkit-scrollbar { display: none; }
.photo-strip__track:focus-visible { outline: 2px solid var(--accent); outline-offset: 5px; }
.photo-strip__item {
  display: block; width: 100%; aspect-ratio: var(--photo-ratio);
  object-fit: contain; border-radius: 14px; background: var(--bone);
  box-shadow: var(--shadow-raised); scroll-snap-align: start;
}
@media (max-width: 900px) {
  .section-intro { gap: var(--space-row); }
  .photo-strip__track { grid-auto-columns: calc((100% - var(--photo-gap)) / 2); }
}
@media (max-width: 620px) {
  .section-intro { display: block; }
  .section-intro > :last-child { max-width: none; margin-top: var(--space-copy); }
  .photo-strip__track { grid-auto-columns: 100%; }
}

.page-head { padding: var(--space-opening) 0 8px; }
.page-head h1 {
  margin: 0; font-size: var(--type-page-title); font-weight: 400;
  font-family: var(--serif);
  letter-spacing: -0.005em; line-height: 1.08; text-wrap: balance;
}
.page-updated { margin: 10px 0 0; font-size: 12.5px; color: var(--muted); }

.doc-shell { width: 100%; }
.doc-row {
  display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 56px;
  padding: 34px 0 38px; border-top: 1px solid var(--hairline);
}
.doc-row:first-of-type { border-top: 0; }
.doc-key .num {
  display: block; font-size: 12px; font-weight: 700; letter-spacing: 0.14em;
  color: var(--muted); font-variant-numeric: tabular-nums; margin-bottom: 10px;
}
.doc-key h2 {
  margin: 0; font-size: 24px; font-weight: 400; letter-spacing: 0;
  font-family: var(--serif); line-height: 1.25; text-wrap: balance;
}
.doc-key .mark {
  display: block; width: 34px; height: 3px; border-radius: 2px;
  background: var(--accent); margin-top: 14px;
}
.doc-body { max-width: 74ch; }
.doc-body p, .doc-body li { font-size: 16px; line-height: 1.7; color: var(--ink); text-wrap: pretty; }
.doc-body p { margin: 0 0 14px; }
.doc-body p:last-child { margin-bottom: 0; }
.doc-body ul { margin: 0 0 14px; padding-left: 20px; }
.doc-body li { margin-bottom: 5px; }
@media (max-width: 820px) {
  .doc-row { grid-template-columns: 1fr; gap: 18px; padding: 26px 0 30px; }
  .doc-body { max-width: none; }
}
.doc-page .aa-foot { margin-top: 0; border-top: 1px solid var(--hairline); }

/* margin-top 0: the global section rule above would otherwise add 104px
   of blank space before the opening answers. */
section.short-version { margin-top: 0; padding: 26px 0 42px; }
.sv-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; }
.sv-item { position: relative; padding: 4px 34px; }
.sv-item:first-child { padding-left: 0; }
.sv-item:last-child { padding-right: 0; }
.sv-item + .sv-item::before {
  content: ""; position: absolute; left: 0; top: -2px; bottom: -2px; width: 1px;
  background: linear-gradient(to bottom, transparent, rgba(52,70,80,0.17) 24%, rgba(52,70,80,0.17) 76%, transparent);
}
.sv-item h2 { margin: 0 0 8px; font-size: 15px; font-weight: 700; letter-spacing: -0.008em; line-height: 1.35; font-family: var(--sans); }
.sv-item p { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
.sv-item a {
  color: var(--muted); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--muted) 40%, transparent);
  text-underline-offset: 3px;
}
.sv-item a:hover { color: var(--ink); text-decoration-color: var(--ink); }
@media (max-width: 820px) {
  .sv-grid { grid-template-columns: 1fr; gap: 22px; }
  .sv-item { padding: 0; }
  .sv-item + .sv-item::before { display: none; }
}

/* The sponsor bar, lifted from assets/homepage.css so pages other than the
   homepage can use it. Identical values, so the homepage is unchanged: its own
   copy still loads after this one and wins with the same declarations. */
.sponsor {
  display: flex; align-items: center; justify-content: space-between; gap: 32px;
  background: var(--bone); border: 1px solid var(--bone-deep); border-radius: 14px;
  padding: 28px 32px; box-shadow: var(--shadow-rest);
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.sponsor:hover { transform: translateY(-4px); box-shadow: var(--shadow-float); }
@media (prefers-reduced-motion: reduce) { .sponsor { transition: none; } }
/* The family has to be pinned here, not inherited. The serif on a bare h2 is
   supplied only by homepage.css's `.aa-hero h1, h2`, which no other page loads,
   so lifting the bar without the face left the engagements sponsor heading in
   Inter while the identical homepage bar rendered the serif. Same shape as the
   .brand bug above. `.sponsor h2` at (0,1,1) beats that bare `h2` at (0,0,1)
   with identical values, so the homepage is unchanged. */
.sponsor h2 { font-size: 24px; margin: 0; font-family: var(--serif); font-weight: 400; letter-spacing: -0.005em; }
.sponsor p { font-size: 15px; margin: 4px 0 0; }
@media (max-width: 700px) { .sponsor { flex-direction: column; align-items: flex-start; gap: 18px; } }

/* The sticky nav bar, lifted from assets/homepage.css so every page has it and
   not just the homepage. About, Privacy, unsubscribe and engagements all carry
   the script that drives it and none of them carried the element or the styles,
   so the behaviour existed in code on four pages and ran on one. Identical
   values, and homepage.css still loads after this file on the homepage, so that
   page is unchanged. */
/* Fixed, not sticky (round thirteen): sticky was fenced inside the hero,
   so the scroll-up return only worked before the fold. The hero pads its
   top by the bar's height to keep the layout identical at rest. */
.nav-holder { position: fixed; top: 0; left: 0; right: 0; z-index: 40; transition: transform 260ms ease; }
/* The returning bar's glass. Round seventeen dropped the tint to 55% for her
   "harsh white line" note and she flagged the line again on 2026-08-29: the
   remaining hard edge was the backdrop blur itself, which cuts off in a razor
   line at the element's bottom. The glass now lives on this pseudo so a mask
   can fade tint, blur and shadow out together over the bottom padding, which
   holds no content. The mask cannot go on the holder itself: the Work
   together panel hangs below the holder's box and a holder mask erases it.
   Per the standing mask rule, the ramp reaches transparent inside the box. */
.nav-holder::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
}
.nav-holder.floating::before {
  background: color-mix(in srgb, var(--canvas) 55%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.15); backdrop-filter: blur(16px) saturate(1.15);
  box-shadow: 0 8px 24px rgba(28,45,58,0.05);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 16px), transparent calc(100% - 1px));
  mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 16px), transparent calc(100% - 1px));
}
.nav-holder.floating .aa-nav { padding: 14px 0; }
/* The hidden bar is only slid off the top, so its links stayed in the
   tab order while invisible: a keyboard user scrolling down and then
   tabbing landed on controls they could not see, inside a fixed element
   the browser cannot scroll into view. visibility takes it out of the
   tab order, delayed so the slide still plays on the way out and
   restored instantly on the way back in. The script also drops the
   hidden class on focusin, which covers focus arriving from a click. */
.nav-holder.hidden { transform: translateY(-100%); visibility: hidden; }
.nav-holder { visibility: visible; }
.nav-holder.hidden { transition: transform 260ms ease, visibility 0s linear 260ms; }
@media (prefers-reduced-motion: reduce) { .nav-holder, .nav-holder.hidden { transition: none; } }

/* ---- the contact form, added 2026-09-20 ----
   One form for the whole site, drawn by assets/contact-form.js wherever a page
   places <div data-contact-form>. Until this date /engagements and /partnerships
   each carried a copy of the form, its styles and its script (the partnerships
   copy said "verbatim from engagements"), so a change had to be made twice. The
   values below are the engagements ones, which both pages already matched.

   A page owns the card or column the form sits in and the class of its Send
   button (data-button-class). It does not own the fields. */
.contact-form {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px 20px;
  align-items: start; margin: 0;
}
.cf-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cf-field.cf-wide, .contact-form .cf-status, .contact-form button[type="submit"] { grid-column: 1 / -1; }
.cf-label {
  margin: 0; font-size: 11.5px; font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--accent);
}
/* The boundary was once a single hairline on white, about 1.35:1, so the fields
   did not read as fields. */
.cf-input {
  width: 100%; background: #FFFFFF;
  border: 1px solid color-mix(in srgb, var(--ink) 62%, white); border-radius: 8px;
  color: var(--ink); font-family: var(--sans); font-size: 15px; line-height: 1.4;
  padding: 10px 12px; box-shadow: inset 0 1px 2px rgba(28,45,58,.05);
}
.cf-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.cf-textarea { resize: vertical; min-height: 110px; }
/* The dropdown keeps the field's own look. The browser arrow is replaced by the
   same two-border caret the navigation menu draws, in ink. */
select.cf-input {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 36px;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'><path d='M1 1.5l5 5 5-5' fill='none' stroke='%23344650' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 11px 7px;
}
select.cf-input:invalid { color: color-mix(in srgb, var(--ink) 58%, white); }
.contact-form button[type="submit"] { justify-self: start; margin-top: 4px; }
.contact-form button[type="submit"]:disabled { opacity: .6; cursor: default; }
/* The honeypot stays off-screen rather than display:none or hidden, which some
   bots know to skip. api/contact.js returns success without writing a row when
   it comes back filled. */
.cf-trap { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
/* Styled for a standalone paragraph as well as a child of the form: on success
   the whole form is replaced with one .cf-status line. */
.cf-status { margin: 10px 0 0; font-size: 14px; color: var(--muted); min-height: 1.2em; }
@media (max-width: 600px) {
  .contact-form { grid-template-columns: 1fr; }
}

/* ---- the Playbooks hub's layout roles, added 2026-09-27 ----
   Five roles for the content hub at /playbooks, added here before any page
   uses them, as the layout contract asks (visual guide section 4): the
   sub-nav with the hub's one search, the breadcrumb, the tile grid, the
   filter chip row, and the Goes with block, plus the visually hidden rule
   and the jewel-tone tokens they need. Every selector is new; nothing above
   this line changes. Each role stands on its own on a page that loads only
   this file. None of them draws a border line, a hairline or a tinted band
   around a region: space separates them from the page (her cutoff-lines
   note, 2026-09-27). Hover only lifts, and nothing is found by hovering. */

/* Visually hidden but read aloud: the same rule every page that uses the
   class already carries in its own style block. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* The accent set by position (IconsColoursCharts section 2): Petrol,
   Garnet, Amber, Lagoon, Sapphire, Fern, Copper, handed out in that order
   and never tied to a concept, only to a thing that carries an approved
   icon and its name. A thing without one takes the neutral edge. */
:root {
  --tone-1: #1D5372; --tone-2: #B8304A; --tone-3: #DB8A06; --tone-4: #0B9AA8;
  --tone-5: #4274E8; --tone-6: #4E9A47; --tone-7: #C4562B;
  --tone-neutral: #C9D3DA;
}

/* 1. The sub-nav, .hub-subnav. A slim bar in the page flow directly under
   the fixed site nav, on every hub page, scrolling with the page. The hub's
   name at the left links home; the live sections follow as real links; the
   current one carries aria-current and the kit's ink underline, so it is
   never shown by colour alone; the hub's one search sits on the right and
   drops under the links when the row runs out of room. Below 720px, the
   site nav's own breakpoint, the links become one native disclosure whose
   summary names the current section, never a sideways strip.
   Markup: div.hub-subnav > div.shell.hub-subnav__bar > (nav.hub-subnav__nav
   > a.hub-subnav__home + ul.hub-subnav__links + details.hub-subnav__menu)
   + div.hub-search. */
.hub-subnav { position: relative; z-index: 30; }
.hub-subnav__bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 8px var(--space-control); min-height: 56px; padding: 8px 0;
}
.hub-subnav__nav { display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--space-row); min-width: 0; }
.hub-subnav__links {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--space-control);
  margin: 0; padding: 0; list-style: none;
}
.hub-subnav__home, .hub-subnav__links a, .hub-subnav__menu li a {
  display: inline-block; padding: 4px 0 3px; border-bottom: 1.5px solid transparent;
  font-family: var(--sans); font-size: 14px; font-weight: 500; line-height: 1.4; color: var(--ink);
  transition: transform 140ms ease;
}
.hub-subnav__home { font-weight: 700; letter-spacing: -0.005em; }
.hub-subnav a[aria-current] { border-bottom-color: var(--ink); }
.hub-subnav a:hover { transform: translateY(-1px); }
.hub-subnav a:focus-visible, .hub-subnav__menu summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 2px;
}
.hub-subnav__menu { display: none; }
.hub-subnav__menu summary {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; list-style: none;
  font-family: var(--sans); font-size: 15px; font-weight: 700; color: var(--ink);
}
.hub-subnav__menu summary::-webkit-details-marker { display: none; }
.hub-subnav__menu summary::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid var(--ink); border-bottom: 1.5px solid var(--ink);
  transform: rotate(45deg);
}
.hub-subnav__menu[open] summary::after { transform: rotate(225deg); margin-top: 3px; }
.hub-subnav__menu ul { display: grid; gap: 2px; margin: 0 0 8px; padding: 0; list-style: none; }
.hub-subnav__menu li a { font-size: 15px; padding: 9px 0 6px; }
/* The search field. Its results panel is the hub's own (hub.css), because
   only hub pages carry the search script. */
.hub-search { position: relative; flex: 0 1 260px; min-width: 200px; }
/* The field's face is the canvas, so its muted glyph and placeholder sit on
   the canvas, the one ground muted is for (Codex review, 2026-09-27; white
   and the canvas differ by one step). */
.hub-search__field {
  display: flex; align-items: center; gap: 9px; height: 40px; padding: 0 12px;
  background: var(--canvas); border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--ink) 30%, white);
  box-shadow: inset 0 1px 2px rgba(28,45,58,0.05);
}
.hub-search__field:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
.hub-search__field svg { width: 16px; height: 16px; flex: none; color: var(--muted); }
.hub-search__field input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: none;
  font-family: var(--sans); font-size: 15px; font-weight: 500; line-height: 1.4; color: var(--ink);
}
.hub-search__field input::placeholder { color: var(--muted); opacity: 1; }
.hub-search__results[hidden] { display: none; }
@media (max-width: 720px) {
  .hub-subnav__bar { flex-direction: column; align-items: stretch; gap: 4px; padding: 6px 0 10px; }
  .hub-subnav__nav { display: block; }
  .hub-subnav__home, .hub-subnav__links { display: none; }
  .hub-subnav__menu { display: block; }
  .hub-search { flex: none; width: 100%; min-width: 0; }
  /* 16px so a phone does not zoom the page when the field takes focus. */
  .hub-search__field input { font-size: 16px; }
}
/* The five-goal build (2026-09-28): the links are the hub name, five goals
   and Library. Measured, the name and the six links need 977px on one row
   and the bar at 1024px is 976px wide, so from 721px to 1100px the name sits
   the links' own gap (the control gap) from the first link instead of the
   row gap. The labels stay whole; shortening one needs her yes. */
@media (min-width: 721px) and (max-width: 1100px) {
  .hub-subnav__nav { column-gap: var(--space-control); }
}
@media (prefers-reduced-motion: reduce) {
  .hub-subnav__home, .hub-subnav__links a, .hub-subnav__menu li a { transition: none; }
}

/* 2. The breadcrumb, .hub-crumbs, on item pages: plain Inter, the kind of
   page it is ("Playbooks / Frameworks"), so no eyebrow label is needed.
   Markup: nav.hub-crumbs > div.shell > ol > li (> span.hub-crumbs__sep) > a. */
.hub-crumbs ol {
  display: flex; flex-wrap: wrap; align-items: center; margin: 0; padding: 14px 0 0; list-style: none;
  font-family: var(--sans); font-size: 14px; line-height: 1.5;
}
.hub-crumbs a {
  color: var(--ink); text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ink) 32%, transparent);
}
.hub-crumbs a:hover { text-decoration-color: var(--ink); }
.hub-crumbs a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.hub-crumbs__sep { margin: 0 10px; color: var(--muted); }

/* 3. The tile grid, .hub-tiles, and the tile, .hub-tile. Three across on a
   desktop, two on a tablet, one on a phone, on the kit's 24px control
   rhythm. A tile is one link: its title's link stretches over the whole
   tile, so buttons it carries (a copy button, a Get button) sit above it.
   It shows its title, its one line and a plain-case meta line at rest.
   Its face runs from white into a little bone and it stands on a 3px
   bottom edge, the neutral #C9D3DA unless it carries an approved icon and
   its name (data-pos 1 to 7 then gives the edge and the icon's pale tile
   the jewel tone at that position). No hairline border and no shadow of
   its own: space and the face separate one tile from the next.
   .hub-tile--bare drops the face and the edge, for a drawing that must sit
   on the canvas with no surface under it (the staircase, rulings 43, 44). */
.hub-tiles {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-control);
  margin: 0; padding: 0; list-style: none;
}
.hub-tile {
  --tile-edge: var(--tone-neutral);
  position: relative; display: flex; flex-direction: column; gap: 6px; min-width: 0;
  padding: 22px 24px; border-radius: 14px;
  background: linear-gradient(180deg, #FFFFFF 0%, color-mix(in srgb, var(--bone) 55%, #FFFFFF) 100%);
  box-shadow: 0 3px 0 var(--tile-edge);
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.hub-tile[data-pos="1"] { --tile-edge: var(--tone-1); --tile-pale: color-mix(in srgb, var(--tone-1) 16%, #FEFDFB); }
.hub-tile[data-pos="2"] { --tile-edge: var(--tone-2); --tile-pale: color-mix(in srgb, var(--tone-2) 16%, #FEFDFB); }
.hub-tile[data-pos="3"] { --tile-edge: var(--tone-3); --tile-pale: color-mix(in srgb, var(--tone-3) 16%, #FEFDFB); }
.hub-tile[data-pos="4"] { --tile-edge: var(--tone-4); --tile-pale: color-mix(in srgb, var(--tone-4) 16%, #FEFDFB); }
.hub-tile[data-pos="5"] { --tile-edge: var(--tone-5); --tile-pale: color-mix(in srgb, var(--tone-5) 16%, #FEFDFB); }
.hub-tile[data-pos="6"] { --tile-edge: var(--tone-6); --tile-pale: color-mix(in srgb, var(--tone-6) 16%, #FEFDFB); }
.hub-tile[data-pos="7"] { --tile-edge: var(--tone-7); --tile-pale: color-mix(in srgb, var(--tone-7) 16%, #FEFDFB); }
.hub-tile__pic { margin: 0 0 12px; min-width: 0; }
.hub-tile__icon {
  --icon-fill: var(--tile-pale, var(--bone));
  display: grid; place-items: center; width: 46px; height: 46px; margin-bottom: 8px;
  border-radius: 12px; background: var(--tile-pale, var(--bone));
}
.hub-tile__icon svg { width: 28px; height: 28px; display: block; }
.hub-tile__title {
  margin: 0; font-family: var(--sans); font-size: var(--type-support); font-weight: 700;
  letter-spacing: -0.01em; line-height: 1.25; color: var(--ink);
}
.hub-tile__link { color: var(--ink); }
.hub-tile__link::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.hub-tile__link:focus-visible { outline: none; }
.hub-tile__link:focus-visible::after { outline: 2px solid var(--accent); outline-offset: 4px; }
.hub-tile__line { margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink); max-width: 46ch; }
.hub-tile__line a {
  position: relative; z-index: 2; color: var(--ink); text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ink) 32%, transparent);
}
.hub-tile__meta { margin: auto 0 0; padding-top: 10px; font-size: 13px; font-weight: 600; line-height: 1.4; color: var(--ink); }
.hub-tile__actions { position: relative; z-index: 2; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin-top: 12px; }
.hub-tile:hover { transform: translateY(-3px); box-shadow: 0 5px 0 var(--tile-edge); }
.hub-tile--bare { padding: 0; background: none; box-shadow: none; }
.hub-tile--bare:hover { box-shadow: none; }
@media (max-width: 900px) { .hub-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .hub-tiles { grid-template-columns: minmax(0, 1fr); } }
@media (prefers-reduced-motion: reduce) { .hub-tile { transition: none; } }

/* 4. The filter chip row, .hub-chips: sentence-case chips, always visible,
   'All' first, each a real link that writes its filter into the address
   (?session=pick-your-fighter), so a view can be shared and a recap page
   can link straight to it. The chosen chip carries aria-current, a white
   face, bold words and a Petrol marker under them. Every item stays in the
   page; the hub's script only hides and shows them. */
.hub-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 var(--space-control); }
.hub-chip {
  display: inline-flex; align-items: center; min-height: 36px; padding: 6px 12px; border-radius: 8px;
  border: 1px solid var(--bone-deep); background: var(--bone); color: var(--ink);
  font-family: var(--sans); font-size: 13.5px; font-weight: 500; line-height: 1.25;
  transition: transform 140ms ease;
}
.hub-chip[aria-current] { background: #FFFFFF; font-weight: 700; box-shadow: inset 0 -2px 0 var(--accent); }
.hub-chip:hover { transform: translateY(-1px); }
.hub-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
[data-hub-item][hidden], [data-hub-group][hidden] { display: none; }
.hub-filter-empty { margin: var(--space-control) 0 0; color: var(--muted); }
.hub-filter-empty[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .hub-chip { transition: none; } }

/* 5. Goes with, .hub-goes-with: up to three tiles for the pieces that pair
   with this one, under one Inter section head, at the kit's section
   rhythm. Markup: section.hub-goes-with > h2.section-title + ul.hub-tiles. */
.hub-goes-with { margin-top: var(--space-section); }
.hub-goes-with > .section-title { margin: 0 0 var(--space-row); }
