/* Perception portal kit.
   The law: 00 CLAUDE/design-systems/perception/system.md. Tokens: /portal/tokens.css (load it first).
   Ported from the Forge: tools/style-guide/system.css (sections), shared/elements.css (SG1b, BT9b),
   tools/elements (PB1, IX8c). Every value is a token or a number the law names. */

/* ---------- Fonts ---------- */
@font-face { font-family: 'Monument Extended'; src: url('/portal/fonts/Monument-Extended-w300.otf') format('opentype'); font-weight: 300; font-display: swap; }
@font-face { font-family: 'Monument Extended'; src: url('/portal/fonts/Monument-Extended-w900.otf') format('opentype'); font-weight: 900; font-display: swap; }
@font-face { font-family: 'NH Display XXThin'; src: url('/portal/fonts/NH-Display-XXThin-w100.ttf') format('truetype'); font-weight: 100; font-display: swap; }
@font-face { font-family: 'Satoshi'; src: url('/portal/fonts/Satoshi-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Satoshi'; src: url('/portal/fonts/Satoshi-Medium.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Satoshi'; src: url('/portal/fonts/Satoshi-Bold.woff2') format('woff2'); font-weight: 700; font-display: swap; }

/* Law 7: the values tokens.css leaves out, plus motion (law 10). */
:root {
  --p-white-pure: #FFFFFF;
  --ink-light-2: rgb(14 14 14 / .64);
  --line-light: rgb(14 14 14 / .14);
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-hover: 200ms;
  --dur-reveal: 400ms;
  --dur-surface: 900ms;
  --client-color: var(--p-red);
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font-body); font-weight: 400; font-size: var(--t-body); line-height: 1.6;
  background: var(--p-black); color: var(--p-white);
  -webkit-font-smoothing: antialiased; overflow-x: clip;
}
img, svg, canvas, video { display: block; max-width: 100%; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--p-red); outline-offset: 3px; }
ul, ol { list-style: none; }
.vh { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ---------- Law 9: surfaces ---------- */
.surface-dark, .surface-charcoal, .surface-light, .surface-white { background: var(--bg); color: var(--ink); }
.surface-dark     { --bg: var(--p-black); --ink: var(--p-white); --ink-2: var(--p-gray-light); --line: var(--p-gray); }
.surface-charcoal { --bg: var(--p-dark);  --ink: var(--p-white); --ink-2: var(--p-gray-light); --line: var(--p-gray); }
.surface-light    { --bg: var(--p-white); --ink: var(--p-black); --ink-2: var(--ink-light-2); --line: var(--line-light); }
.surface-white    { --bg: var(--p-white-pure); --ink: var(--p-black); --ink-2: var(--ink-light-2); --line: var(--line-light); }
body, .surface-dark, .surface-charcoal { --lnk-c: var(--p-red); --lnk-w: #FFFFFF;
  --xb-shade: transparent; --xb-sf: #0E0E0E; --xb-si: #FFFFFF; --xb-sb: #888888; --xb-sr: #5F5F5F; --xb-sbm: #888888; }
.surface-light, .surface-white { --lnk-c: var(--p-blue); --lnk-w: #0E0E0E;
  --xb-shade: rgba(0, 0, 0, .4); --xb-sf: #FFFFFF; --xb-si: #0E0E0E; --xb-sb: #0E0E0E; --xb-sr: #C4C4C4; --xb-sbm: #7F7F7F; }
.muted { color: var(--ink-2); }

/* ---------- Law 6: type ---------- */
.t-display, .t-display-2 {
  font-family: var(--font-headline); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0; overflow-wrap: normal; hyphens: none;
}
.t-display   { font-size: var(--t-display);   line-height: .92; }
.t-display-2 { font-size: var(--t-display-2); line-height: .95; }
.t-statement { font-family: var(--font-hairline); font-weight: 100; font-size: var(--t-statement); line-height: 1.08; letter-spacing: 0; max-width: 30ch; }
.t-title { font-family: var(--font-headline); font-weight: 300; font-size: var(--t-title); line-height: 1.15; text-transform: uppercase; letter-spacing: 0; }
.t-body  { font-family: var(--font-body); font-weight: 400; font-size: var(--t-body); line-height: 1.6; max-width: 65ch; }
.t-small { font-family: var(--font-body); font-weight: 400; font-size: var(--t-small); line-height: 1.35; }
.t-bold  { font-weight: 700; }
.t-short { line-height: 1.35; }
.t-display, .t-display-2, .t-statement, .t-title { text-wrap: balance; }
.prose > * + * { margin-top: var(--gap-grouped); }
.prose p, .prose li { max-width: 65ch; }
.prose strong { font-weight: 500; }

/* ---------- Law 2: grid ---------- */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  column-gap: var(--grid-gutter);
  padding-inline: var(--grid-margin);
  max-width: calc(var(--grid-max) + 2 * var(--grid-margin));
  margin-inline: auto;
}
.grid > * { grid-column: 1 / -1; min-width: 0; }

/* ---------- Law 3: widths ---------- */
.w-narrow, .w-normal, .w-wide { grid-column: 1 / -1; }
.w-bleed { width: 100%; }
@media (min-width: 744px) {
  .w-narrow { grid-column: 1 / span 6; }
  .w-narrow.w-center { grid-column: 2 / span 6; }
}
@media (min-width: 1200px) {
  .w-normal { grid-column: 1 / span 8; }
  .w-normal.w-center { grid-column: 3 / span 8; }
  .w-narrow.w-center { grid-column: 4 / span 6; }
}

/* Law 2: one axis per section. Centered sections center every child. */
.sec--center { text-align: center; }
.sec--center .t-statement, .sec--center .t-body, .sec--center .t-display-2 { margin-inline: auto; }
.sec--center .actions { justify-content: center; }

/* ---------- Law 4: proximity ---------- */
.sec { padding-block: var(--gap-sections); }
.sec--bleed { padding-block: 0; }
.sec:has(+ .sec--joined) { padding-bottom: var(--gap-blocks); }
.sec--joined { padding-top: 0; }
.surface-dark.sec + .surface-dark.sec,
.surface-charcoal.sec + .surface-charcoal.sec,
.surface-light.sec + .surface-light.sec,
.surface-white.sec + .surface-white.sec { padding-top: 0; }
.sec > .grid { row-gap: var(--gap-blocks); }
.flow-blocks   > * + * { margin-top: var(--gap-blocks); }
.flow-siblings > * + * { margin-top: var(--gap-siblings); }
.flow-grouped  > * + * { margin-top: var(--gap-grouped); }
.flow-bound    > * + * { margin-top: var(--gap-bound); }
.head-group > * + * { margin-top: var(--gap-grouped); }

/* ---------- Law 12.1: Hero ---------- */
.hero-type { padding-top: var(--gap-sections); }
.hero-over { position: relative; }
.hero-over > img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.hero-over .grid { position: absolute; left: 0; right: 0; bottom: var(--gap-blocks); color: var(--p-white); }
@media (min-width: 744px) { .hero-over > img { aspect-ratio: 21 / 9; } }

/* ---------- Law 12.3: Text split ---------- */
.grid.split { row-gap: var(--gap-grouped); }
@media (min-width: 1200px) {
  .split__head { grid-column: 1 / span 5; }
  .split__body { grid-column: 7 / span 6; }
  /* Law 2 column gaps: the head stays inside its five columns so column 6 stays empty.
     One step under display-2, and it wraps (portal.js never joins its words). */
  .split__head.t-display-2 { font-size: clamp(32px, 3.4vw, 56px); }
}

/* ---------- Law 8: images ---------- */
.fig img, img.fig, .fig video { width: 100%; object-fit: cover; }
.r-21x9 { aspect-ratio: 21 / 9; }
.r-16x9 { aspect-ratio: 16 / 9; }
.r-3x2  { aspect-ratio: 3 / 2; }
.r-4x5  { aspect-ratio: 4 / 5; }
.r-1x1  { aspect-ratio: 1 / 1; }
.fig figcaption { margin-top: var(--gap-bound); font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- Law 12.5: Media + text ---------- */
.grid.media { row-gap: var(--gap-grouped); align-items: center; }
@media (min-width: 1200px) {
  .media__img  { grid-column: 1 / span 6; }
  .media__text { grid-column: 8 / span 5; }
  .media--mirror .media__img  { grid-column: 7 / span 6; grid-row: 1; }
  .media--mirror .media__text { grid-column: 1 / span 5; grid-row: 1; }
}

/* ---------- Law 5 and 12.6: Set ---------- */
.set { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-siblings); }
.item { display: flex; flex-direction: column; }
.item > * + * { margin-top: var(--gap-bound); }
.item > .fig + * { margin-top: var(--gap-grouped); }
.item .t-title, .item .cap { white-space: nowrap; }
.cap { font-size: var(--t-body); line-height: 1.35; color: var(--ink-2); }
.desc { font-size: var(--t-body); line-height: 1.6; color: var(--ink-2); }
@media (min-width: 744px) { .set--2, .set--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) {
  .set--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .set--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------- Law 9 and 12.7: Rows ---------- */
.rows > li, .rows > .row { border-top: 1px solid var(--line); padding-block: calc(var(--gap-siblings) / 2); }
.rows > :first-child { border-top: 0; padding-top: 0; }
.rows > :last-child { padding-bottom: 0; }
.row { display: grid; grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr)); column-gap: var(--grid-gutter); row-gap: var(--gap-bound); align-items: center; }
.row > * { grid-column: 1 / -1; min-width: 0; }
.row .row__mark { width: 64px; height: 64px; margin-bottom: var(--gap-grouped); }
.row .row__title, .row .cap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (min-width: 744px) {
  .row .row__mark  { grid-column: 1 / span 1; margin-bottom: 0; }
  .row .row__title { grid-column: 2 / span 2; }
  .row .cap        { grid-column: 4 / -1; }
}
@media (min-width: 1200px) {
  .row .row__mark  { grid-column: 1 / span 2; width: 88px; height: 88px; }
  .row .row__title { grid-column: 3 / span 3; }
  .row .cap        { grid-column: 6 / -1; }
}

/* Portal rows: an item, a link or a file. Title, kind, date (or detail), and the lock mark where it applies.
   The whole row is the link. Mobile: title, then one caption line. */
.prow { color: inherit; text-decoration: none; }
.prow .prow__title { grid-column: 1 / -1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prow .prow__meta  { grid-column: 1 / -1; display: flex; gap: var(--gap-grouped); align-items: center; font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); white-space: nowrap; }
.prow .prow__lock  { width: 16px; height: 16px; flex: none; color: var(--ink-2); }
.prow .prow__title { transition: color var(--dur-hover) var(--ease); }
@media (hover: hover) { a.prow:hover .prow__title { color: var(--lnk-c); } }
a.prow:focus-visible { outline-offset: 8px; }
@media (min-width: 744px) {
  .prow .prow__title { grid-column: 1 / span 5; }
  .prow .prow__meta  { grid-column: 6 / -1; justify-content: space-between; }
}
@media (min-width: 1200px) {
  .prow .prow__title { grid-column: 1 / span 7; }
  .prow .prow__meta  { grid-column: 8 / -1; }
}
.prow__meta > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.prow__kind { flex: 1 1 0; }
.prow__date { flex: 0 0 auto; }
.prow__end  { flex: 0 0 16px; display: flex; justify-content: flex-end; }

/* ---------- Law 12.8: Figures ---------- */
.figs { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-siblings); }
.figs > div > * + * { margin-top: var(--gap-bound); }
.figs .t-small { white-space: nowrap; color: var(--ink-2); }
.figs .is-result { color: var(--p-green); }
@media (min-width: 744px) {
  .figs--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .figs--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1200px) { .figs--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ---------- Law 12.9: Quote ---------- */
.quote blockquote { font-family: var(--font-hairline); font-weight: 100; font-size: var(--t-statement); line-height: 1.08; max-width: 30ch; }
.quote figcaption { margin-top: var(--gap-grouped); font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); }
.sec--center .quote blockquote { margin-inline: auto; }

/* ---------- Law 12.10: Gallery ---------- */
.gal { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gutter); }
.gal img { width: 100%; object-fit: cover; }
@media (min-width: 744px) {
  .gal--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gal--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .gal--pair { grid-template-columns: repeat(8, minmax(0, 1fr)); }
  .gal--pair > :first-child { grid-column: 1 / span 5; }
  .gal--pair > :last-child  { grid-column: 6 / span 3; position: relative; }
  .gal--pair > :last-child img { position: absolute; inset: 0; height: 100%; }
}
@media (min-width: 1200px) {
  .gal--pair { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .gal--pair > :first-child { grid-column: 1 / span 8; }
  .gal--pair > :last-child  { grid-column: 9 / span 4; }
}

/* ---------- Brand: a client's own swatch is subject matter, framed like an image (1:1, square corners) ---------- */
.swatch { width: 100%; aspect-ratio: 1 / 1; background: var(--sw, #888888); }
.surface-dark .swatch--edge, .surface-charcoal .swatch--edge { outline: 1px solid var(--p-gray); outline-offset: -1px; }
.surface-light .swatch--edge, .surface-white .swatch--edge { outline: 1px solid var(--line-light); outline-offset: -1px; }

/* ---------- Charts (Chart.js 4.4.7 draws into these) ---------- */
.chart { position: relative; width: 100%; aspect-ratio: 16 / 9; }
.chart--3x2 { aspect-ratio: 3 / 2; }
.chart--1x1 { aspect-ratio: 1 / 1; }
@media (max-width: 743px) { .chart { aspect-ratio: 4 / 5; } }
.chart canvas { width: 100% !important; height: 100% !important; }
/* Ranked bars size to their count, so six bars are never a mostly empty box: a 24px bar and 16px of air each.
   --bars is set by the chart code (INTEL.hbar), never by hand. */
.chart.chart--bars { aspect-ratio: auto; height: calc(var(--bars, 6) * 40px); }

/* ---------- Tables (data that can't be a chart) ---------- */
.tbl { width: 100%; border-collapse: collapse; font-size: var(--t-small); line-height: 1.35; font-variant-numeric: tabular-nums; }
.tbl th { text-align: left; font-weight: 700; color: var(--ink-2); padding: 0 var(--gap-grouped) var(--gap-grouped) 0; }
.tbl td, .tbl tbody th { border-top: 1px solid var(--line); padding: var(--gap-grouped) var(--gap-grouped) var(--gap-grouped) 0; }
/* A row's first cell is its header (th scope="row"). It reads as data, in full ink. */
.tbl tbody th { font-weight: 400; color: var(--ink); }
.tbl tr.muted > * { color: var(--ink-2); }
.tbl .num { text-align: right; }
.tbl-wrap { overflow-x: auto; }

/* ---------- Law 12.11: Action ---------- */
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-grouped) var(--gap-siblings); }

/* SG1b link: Satoshi 700 in the link color, no underline. The flicker comes from portal.js. */
.lnk, .link, .prose a:not([class]) {
  --fl-to: var(--lnk-c, #E5223B); --fl-w: var(--lnk-w, #FFFFFF);
  color: var(--fl-to); font-weight: 700; text-decoration: none;
}
.link { font-size: var(--t-small); line-height: 1.35; background: none; border: 0; padding: 0; cursor: pointer; }
.lnk:focus-visible, .link:focus-visible { outline: 2px solid #E5223B; outline-offset: 3px; }
.fe-go { animation: fe-flick 840ms both; }
@keyframes fe-flick {
  0%      { color: var(--fl-w, #FFFFFF); animation-timing-function: step-end; }
  6.548%  { color: #5BBA47; animation-timing-function: step-end; }
  13.095% { color: #E5223B; animation-timing-function: step-end; }
  19.643% { color: #0359A7; animation-timing-function: step-end; }
  26.19%  { color: var(--fl-w, #FFFFFF); animation-timing-function: step-end; }
  32.738% { color: #5BBA47; animation-timing-function: step-end; }
  39.286% { color: #E5223B; animation-timing-function: step-end; }
  45.833% { color: #0359A7; animation-timing-function: step-end; }
  52.381% { color: #0359A7; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  100%    { color: var(--fl-to, #E5223B); }
}

/* ---------- PB1 Portal button (Forge tools/elements, .bx.pri.bt7) ----------
   Outlined at rest. Hover, focus or tap: the red traces the edge (four sides, 140ms each), then fills.
   The click waits for the trace, then the view dives into the red (portal.js). */
.pb {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  height: 56px; padding: 0 32px; border-radius: 0; overflow: visible; white-space: nowrap;
  background: transparent; border: 1px solid var(--p-white-pure); color: var(--p-white-pure);
  font: 700 var(--t-small)/1 var(--font-body); text-decoration: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-hover) var(--ease);
}
.surface-light .pb, .surface-white .pb { border-color: var(--p-black); color: var(--p-black); }
.pb .pb__l { position: relative; z-index: 2; display: inline-block; }
.pb::before { content: ""; position: absolute; inset: -1px; background: #E5223B; opacity: 0; z-index: 1; transition: opacity 260ms var(--ease) 0ms; }
.pb .pb__t { position: absolute; background: #E5223B; z-index: 3; transition: transform 140ms cubic-bezier(.4, 0, .6, 1); }
.pb .pb__tt { top: -1px; left: -1px; right: -1px; height: 1px; transform: scaleX(0); transform-origin: left center; transition-delay: 670ms; }
.pb .pb__tr { top: -1px; right: -1px; bottom: -1px; width: 1px; transform: scaleY(0); transform-origin: center top; transition-delay: 530ms; }
.pb .pb__tb { bottom: -1px; left: -1px; right: -1px; height: 1px; transform: scaleX(0); transform-origin: right center; transition-delay: 390ms; }
.pb .pb__tl { top: -1px; left: -1px; bottom: -1px; width: 1px; transform: scaleY(0); transform-origin: center bottom; transition-delay: 250ms; }
.pb:hover .pb__tt, .pb:focus-visible .pb__tt, .pb.tap .pb__tt { transform: scaleX(1); transition-delay: 0ms; }
.pb:hover .pb__tr, .pb:focus-visible .pb__tr, .pb.tap .pb__tr { transform: scaleY(1); transition-delay: 140ms; }
.pb:hover .pb__tb, .pb:focus-visible .pb__tb, .pb.tap .pb__tb { transform: scaleX(1); transition-delay: 280ms; }
.pb:hover .pb__tl, .pb:focus-visible .pb__tl, .pb.tap .pb__tl { transform: scaleY(1); transition-delay: 420ms; }
.pb:hover::before, .pb:focus-visible::before, .pb.tap::before { opacity: 1; transition-delay: 560ms; }
.surface-light .pb:hover, .surface-light .pb:focus-visible, .surface-light .pb.tap,
.surface-white .pb:hover, .surface-white .pb:focus-visible, .surface-white .pb.tap { color: var(--p-white-pure); transition: color 200ms var(--ease) 560ms; }
/* Law 10: a phone has no hover, so the trace plays as the button scrolls into view (portal.js adds .tap). */

/* The dive layer: red grows from the button, falls to black. */
.fe-portal { position: fixed; inset: 0; z-index: 2147483000; background: #E5223B; pointer-events: auto; }

/* ---------- BT9b Extrude (shared/elements.css .xb) ---------- */
@property --xz { syntax: '<length>'; inherits: true; initial-value: 6px; }
button.xb, a.xb {
  --xz: 6px;
  --xf: #E5223B; --xi: #FFFFFF; --xr: #C81D33; --xbm: #821321; --xline: transparent;
  --xs: var(--xb-shade, transparent);
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  box-sizing: border-box; height: 44px; min-height: 44px; padding: 0 22px; margin: 0;
  border: 0; border-radius: 0; overflow: visible;
  background-color: var(--xf);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='.07'/></svg>");
  background-blend-mode: overlay;
  color: var(--xi);
  font: 900 11px/1 'Monument Extended', 'Arial Black', sans-serif; letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; white-space: nowrap; text-align: center;
  cursor: pointer; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  transform: translate(calc(6px - var(--xz)), calc(6px - var(--xz)));
  box-shadow: inset 0 0 0 1px var(--xline), calc(var(--xz) * 2) calc(var(--xz) * 2) 0 var(--xs);
  transition: --xz 280ms cubic-bezier(.16, 1, .3, 1), opacity 200ms cubic-bezier(.4, 0, .2, 1);
}
:is(button, a).xb::before, :is(button, a).xb::after {
  content: ""; position: absolute; left: 0; top: 0; pointer-events: none;
  width: calc(100% + var(--xz)); height: calc(100% + var(--xz));
}
:is(button, a).xb::before { background: var(--xr); clip-path: polygon(calc(100% - var(--xz)) 0, 100% var(--xz), 100% 100%, calc(100% - var(--xz)) calc(100% - var(--xz))); }
:is(button, a).xb::after { background: var(--xbm); clip-path: polygon(0 calc(100% - var(--xz)), calc(100% - var(--xz)) calc(100% - var(--xz)), 100% 100%, var(--xz) 100%); }
:is(button, a).xb.xb--sec {
  --xf: var(--xb-sf, #0E0E0E); --xi: var(--xb-si, #FFFFFF); --xline: var(--xb-sb, #888888);
  --xr: var(--xb-sr, #5F5F5F); --xbm: var(--xb-sbm, #888888);
}
@media (hover: hover) { :is(button, a).xb:not(:disabled):not([aria-disabled="true"]):hover { --xz: 8px; } }
:is(button, a).xb:not(:disabled):not([aria-disabled="true"]):focus-visible { --xz: 8px; outline: 2px solid #E5223B; outline-offset: 4px; }
:is(button, a).xb:not(:disabled):not([aria-disabled="true"]):active,
:is(button, a).xb.is-down:not(:disabled):not([aria-disabled="true"]) { --xz: 0px; transition-duration: 90ms; transition-timing-function: cubic-bezier(.4, 0, .2, 1); }
:is(button, a).xb:disabled, :is(button, a).xb[aria-disabled="true"] { opacity: .45; cursor: default; }
:is(button, a).xb[hidden] { display: none !important; }

/* ---------- IX8c Name lights (Forge tools/elements .nl) ----------
   Outlined Monument 900 caps; the glow layer behind the letters breathes in the client's own color.
   .lit fills the name white, left to right. Wraps safely: every layer shares the same box. */
.nl {
  position: relative; display: inline-block; isolation: isolate;
  color: transparent; -webkit-text-stroke: 0.8px #FFFFFF; letter-spacing: 0.04em;
}
@media (max-width: 743px) { .nl { -webkit-text-stroke-width: 0.5px; } }
.nl__g { position: absolute; inset: 0; z-index: -1; pointer-events: none; -webkit-text-stroke: 0; transition: opacity 300ms var(--ease); }
.nl__gi {
  display: block; color: #0E0E0E; opacity: 0.25;
  filter: drop-shadow(0 0 6px var(--client-color)) drop-shadow(0 0 18px var(--client-color));
  animation: nl-breathe 3.6s ease-in-out infinite;
}
@keyframes nl-breathe { 0%, 100% { opacity: 0.25; } 50% { opacity: 0.85; } }
.nl::after {
  content: attr(data-t); position: absolute; inset: 0; color: #FFFFFF; -webkit-text-stroke: 0;
  clip-path: inset(0 100% 0 0); transition: clip-path 700ms var(--ease-out);
}
.nl.lit::after { clip-path: inset(0 0 0 0); }
.nl.lit .nl__g { opacity: 0; }
.nl.lit-now::after { transition: none; }
/* The name never overflows a phone: --name-fit is the longest word's letter count (set by the generator).
   1.1em a letter covers Monument Extended 900 caps with the 0.04em tracking, widest letters included. */
.hero-name { display: block; font-size: min(var(--t-display), calc((100vw - 2 * var(--grid-margin)) / (var(--name-fit, 6) * 1.1))); }
.hero-name .nl { max-width: 100%; }

/* ---------- Form field (law 7: inputs sit on the raised dark surface) ---------- */
.field { display: flex; flex-direction: column; }
.field > * + * { margin-top: var(--gap-bound); }
.field__label { font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); }
.field__input {
  width: 100%; height: 56px; padding: 0 var(--gap-grouped);
  background: var(--p-dark); color: var(--p-white); border: 1px solid var(--p-gray); border-radius: 0;
  font: 400 var(--t-body)/1.35 var(--font-body);
  transition: border-color var(--dur-hover) var(--ease);
}
.surface-light .field__input, .surface-white .field__input { background: var(--p-white-pure); color: var(--p-black); border-color: var(--line-light); }
.field__input::placeholder { color: var(--p-gray-light); opacity: 1; }
.field__input:focus { outline: none; border-color: var(--p-white); }
.field__input:focus-visible { outline: 2px solid var(--p-red); outline-offset: 3px; }
textarea.field__input { height: auto; min-height: 168px; padding-block: var(--gap-grouped); line-height: 1.6; resize: vertical; }
.field__error { font-size: var(--t-small); line-height: 1.35; font-weight: 700; color: var(--p-white); min-height: 1.35em; }
.form > * + * { margin-top: var(--gap-grouped); }
.form > .xb, .form > .form__submit { margin-top: var(--gap-blocks); }

/* ---------- Login: Narrow, centered on the grid, one left axis inside (law 2) ---------- */
.login { min-height: 100svh; display: flex; align-items: center; padding-block: var(--gap-blocks); }
.login .grid { width: 100%; }
.login__inner > * + * { margin-top: var(--gap-blocks); }
.login .form > .xb { margin-top: var(--gap-grouped); }

/* ---------- Law 12.12: Footer ---------- */
.foot-sec { padding-block: var(--gap-blocks); }
.grid.foot { row-gap: var(--gap-grouped); align-items: center; }
.foot__mark { width: 200px; color: var(--ink); }
.foot__mark svg { width: 100%; height: auto; }
.foot__links { display: flex; flex-wrap: wrap; gap: var(--gap-grouped) var(--space-lg); font-size: var(--t-small); line-height: 1.35; align-items: center; }
.foot__links a, .foot__links button { font-weight: 700; color: var(--lnk-c, var(--p-red)); text-decoration: none; background: none; border: 0; padding: 0; cursor: pointer; font-size: var(--t-small); line-height: 1.35; }
.foot__links form { display: inline; }
@media (min-width: 744px) {
  .foot__mark  { grid-column: 1 / span 3; }
  .foot__links { grid-column: 5 / -1; justify-content: flex-end; flex-wrap: nowrap; }
}
@media (min-width: 1200px) { .foot__links { grid-column: 7 / -1; } }

/* ---------- Slim preview bar (also in bar.css for pages that load no kit) ---------- */
.ppbar { position: sticky; top: 0; z-index: 2147482000; height: 44px; background: #0E0E0E; color: #F5F5F5; }

/* ---------- Deck: one idea per screen ---------- */
.deck .slide { min-height: 100svh; display: flex; align-items: center; padding-block: var(--gap-blocks); }
.deck .slide > .grid { width: 100%; row-gap: var(--gap-blocks); }
@media (min-width: 744px) {
  html.deck-snap { scroll-snap-type: y mandatory; }
  .deck .slide { scroll-snap-align: start; scroll-snap-stop: always; height: 100svh; overflow: hidden; }
}
.deck__count { position: fixed; right: var(--grid-margin); bottom: var(--gap-grouped); z-index: 10; font-size: var(--t-small); line-height: 1.35; color: var(--p-gray-light); font-variant-numeric: tabular-nums; pointer-events: none; }
@media (max-width: 743px) { .deck__count { display: none; } }

/* ---------- Report slides (law 4, Report slides): <body class="report-slides"> ----------
   Every main > .sec is a slide, and so is a div.slide holding a section and the .sec--joined sections that
   finish its thought. From 744 up a slide is one screen under the report bar, the page snaps slide to slide,
   and portal.js moves one slide on PageUp, PageDown, the arrows and space. On a phone slides flow at their
   natural height. Inside a slide the ladder steps down a tier: blocks are spaced by Siblings, not Blocks. */
.report-slides main > .sec, .report-slides main > .slide { padding-block: var(--gap-blocks); }
.report-slides main > .slide > .sec { padding-block: 0; }
.report-slides main > .slide > .sec + .sec { margin-top: var(--gap-siblings); }
/* The hero's statement is its sub (Grouped). On a phone the hero, statement, menu and switch fit about one screen. */
.report-slides main > .slide > .hero-type + .sec { margin-top: var(--gap-grouped); }
.report-slides main > .slide:first-child { padding-top: var(--gap-siblings); }
.report-slides main .sec > .grid:not(.split):not(.media) { row-gap: var(--gap-siblings); }
.report-slides .tbl td, .report-slides .tbl tbody th { padding-block: var(--gap-bound); }
.report-slides .tbl thead th { padding-bottom: var(--gap-bound); }
@media (min-width: 744px) {
  html:has(> body.report-slides) { scroll-snap-type: y mandatory; }
  /* --fit: what a slide has left for its one big block after the air above and below, one headline and its gap.
     .fit-half on a block gives it half, for two blocks sharing a slide. */
  body.report-slides {
    --slide-h: calc(100svh - var(--rbar-h, 0px));
    --fit-base: calc(var(--slide-h) - 3 * var(--gap-siblings) - var(--t-display-2));
    --fit: var(--fit-base);
  }
  body.report-slides:has(.rbar) { --rbar-h: 44px; }
  .report-slides main > .sec, .report-slides main > .slide {
    min-height: var(--slide-h); padding-block: var(--gap-grouped);
    display: flex; flex-direction: column; justify-content: center;
    scroll-snap-align: start;
  }
  .report-slides main > .slide:first-child { min-height: 100svh; padding-top: var(--gap-grouped); }
  .report-slides main > .sec > .grid, .report-slides main > .slide > .sec { width: 100%; }
  /* Each slide keeps its own air, even next to a slide on the same surface. */
  .report-slides main > .surface-dark.sec + .surface-dark.sec,
  .report-slides main > .surface-charcoal.sec + .surface-charcoal.sec,
  .report-slides main > .surface-light.sec + .surface-light.sec,
  .report-slides main > .surface-white.sec + .surface-white.sec { padding-top: var(--gap-grouped); }
  .report-slides > footer { scroll-snap-align: end; }
  .report-slides .fit-half { --fit: calc((var(--fit-base) - var(--gap-siblings)) / 2); }
  /* Charts take the height their slide has left (less the caption line), never more than 16:9 of their width.
     --fit-h is the measured share (PP.fit, portal.js); the formula is the fallback until it's measured. */
  .report-slides .fig { container-type: inline-size; }
  .report-slides .chart { aspect-ratio: auto; height: min(56.25cqi, var(--fit-h, calc(var(--fit) - var(--gap-bound) - 1.35 * var(--t-small)))); }
  .report-slides .chart--3x2 { height: min(66.667cqi, var(--fit-h, calc(var(--fit) - var(--gap-bound) - 1.35 * var(--t-small)))); }
  .report-slides .chart--1x1 { height: min(100cqi, var(--fit-h, calc(var(--fit) - var(--gap-bound) - 1.35 * var(--t-small)))); }
  .report-slides .chart.chart--bars { height: min(var(--bars, 6) * 40px, var(--fit-h, calc(var(--fit) - var(--gap-bound) - 1.35 * var(--t-small)))); }
  .report-slides .scroller { max-height: var(--fit-h, var(--fit)); overflow: auto; }
  .report-slides .has-note > .scroller { max-height: var(--fit-h, calc(var(--fit) - var(--gap-grouped) - 1.35 * var(--t-small))); }
}

/* ---------- The scroller (law 4, Report slides): anything taller than its slide scrolls inside it ----------
   PP.scroller(el) (portal.js) keeps the state: .is-up and .is-down fade an edge only while there's more that way,
   --head holds the sticky header's height so the top fade starts under it, and the region is a named tab stop
   only while it scrolls. It never traps the wheel: at its end the page takes over and moves to the next slide.
   A fade is one table row tall, so it only ever covers the row that's half in. At either end it's gone. */
.scroller { --head: 0px; --fade: calc(2 * var(--gap-bound) + 1.35 * var(--t-small)); -webkit-mask-image: var(--mask, none); mask-image: var(--mask, none); }
.scroller.is-up { --mask: linear-gradient(to bottom, #000 var(--head), transparent var(--head), #000 calc(var(--head) + var(--fade))); }
.scroller.is-down { --mask: linear-gradient(to bottom, #000 calc(100% - var(--fade)), transparent); }
.scroller.is-up.is-down { --mask: linear-gradient(to bottom, #000 var(--head), transparent var(--head), #000 calc(var(--head) + var(--fade)), #000 calc(100% - var(--fade)), transparent); }
.scroller .tbl thead th { position: sticky; top: 0; z-index: 2; background: var(--bg); box-shadow: inset 0 -1px 0 var(--line); }
.scroller .tbl tbody tr:first-child > * { border-top: 0; }
/* Thin, square, ink on nothing (law 9: no rounded corners). */
.scroller::-webkit-scrollbar { width: 6px; height: 6px; }
.scroller::-webkit-scrollbar-track, .scroller::-webkit-scrollbar-corner { background: transparent; }
.scroller::-webkit-scrollbar-thumb { background: var(--ink); border-radius: 0; }
@supports not selector(::-webkit-scrollbar) { .scroller { scrollbar-width: thin; scrollbar-color: var(--ink) transparent; } }
/* The mask would clip a ring drawn on the scroller, so its holder carries the ring. */
.scroller:focus-visible { outline: none; }
:has(> .scroller:focus-visible) { outline: 2px solid var(--p-red); outline-offset: 3px; }

/* ---------- Report bar (law 4, Report slides): the window or filter control and the date range, pinned ----------
   44 tall, on its own dark surface. PP.rbar(bar, control) slides it in once the page's own control has
   scrolled away. On a phone it holds the control only. */
.rbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100; height: 44px;
  box-shadow: inset 0 -1px 0 var(--line);
  transform: translateY(-100%); visibility: hidden;
  transition: transform var(--dur-hover) var(--ease), visibility 0s linear var(--dur-hover);
}
.rbar.is-on { transform: none; visibility: visible; transition: transform var(--dur-hover) var(--ease); }
.rbar > .grid, .rbar__in { height: 100%; }
.rbar__in { display: flex; align-items: center; justify-content: space-between; column-gap: var(--gap-siblings); min-width: 0; }
/* Controls on the left (rbar__start), what's on screen on the right (rbar__end: the range, then which slide). */
.rbar__start, .rbar__end { display: flex; align-items: center; height: 100%; min-width: 0; }
.rbar__start { flex: none; column-gap: var(--gap-siblings); }
.rbar__end { flex: 1 1 auto; justify-content: flex-end; column-gap: var(--gap-grouped); }
.rbar__range { min-width: 0; font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rbar__count { flex: none; font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
html:has(.rbar) { scroll-padding-top: 44px; }
@media (max-width: 743px) { .rbar__range, .rbar__count { display: none; } }

/* Segmented switch: small text buttons in ink, the current one over a red mark
   (law 7: red is the active state; a 2px mark clears 3:1 on black and charcoal, where red 14px text doesn't clear 4.5:1). */
.seg { display: flex; height: 100%; }
.seg__b {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 44px; padding: 0 var(--gap-grouped); background: none; border: 0; border-radius: 0;
  color: var(--ink); font: 700 var(--t-small)/1.35 var(--font-body); white-space: nowrap; cursor: pointer;
}
.seg__b:first-child { padding-left: 0; }
.seg__b::after { content: ""; position: absolute; left: var(--gap-grouped); right: var(--gap-grouped); bottom: 0; height: 2px; background: transparent; transition: background-color var(--dur-hover) var(--ease); }
.seg__b:first-child::after { left: 0; }
.seg__b[aria-pressed="true"]::after { background: var(--p-red); }
@media (hover: hover) { .seg__b:not([aria-pressed="true"]):hover::after { background: var(--ink-2); } }
.seg__b:focus-visible { outline-offset: -2px; }
@media (max-width: 743px) { .seg__unit { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }

/* ---------- Skip link: the first thing a keyboard reaches, out of sight until it has focus ---------- */
.skip {
  position: absolute; top: var(--gap-bound); left: var(--grid-margin); z-index: 2147482500;
  padding: var(--gap-bound) var(--gap-grouped); background: var(--p-black); color: var(--p-white);
  font: 700 var(--t-small)/1.35 var(--font-body); text-decoration: none;
  transform: translateY(calc(-100% - 2 * var(--gap-bound)));
}
.skip:focus { transform: none; }
[tabindex="-1"]:focus { outline: none; }

/* ---------- Cross-document trip (PB1): the next page mists in out of a blur ---------- */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: pp-mist 1100ms var(--ease-out) both; }
@keyframes pp-mist { from { filter: blur(28px); opacity: 0; transform: scale(1.04); } to { filter: blur(0); opacity: 1; transform: scale(1); } }

/* ---------- Law 10: reduced motion makes every change instant ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  .nl__gi { opacity: 0.55; }
}

/* ---------- Front page: work cards (law 12.6 set, law 8 images). Space carries the structure, no boxes ---------- */
.works { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: var(--grid-gutter); row-gap: var(--gap-siblings); }
@media (min-width: 744px) { .works--2, .works--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .works--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.works > *, .work__text > * { min-width: 0; }
.work { display: block; min-width: 0; color: inherit; text-decoration: none; }
.work__img { display: block; width: 100%; object-fit: cover; object-position: top center; background: var(--p-dark); outline: 1px solid var(--line); outline-offset: -1px; }
.work__text { display: flex; flex-direction: column; gap: var(--gap-bound); margin-top: var(--gap-grouped); }
.work__title { transition: color var(--dur-hover) var(--ease); }
.work__cap { font-size: var(--t-body); line-height: 1.35; color: var(--ink-2); }
.work__meta { display: flex; align-items: center; gap: var(--gap-grouped); font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); }
.work .prow__lock { width: 16px; height: 16px; flex: none; }
@media (min-width: 744px) { .work__title, .work__cap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } }
@media (hover: hover) { a.work:hover .work__title { color: var(--lnk-c); } }
a.work:focus-visible { outline-offset: 8px; }
@media (min-width: 1200px) {
  .work--feature { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--grid-gutter); align-items: end; }
  .work--feature .work__img { grid-column: 1 / span 8; }
  .work--feature .work__text { grid-column: 9 / -1; margin-top: 0; }
  .work--feature .work__title, .work--feature .work__cap { white-space: normal; }
}
