﻿/* ==========================================================================
   NSi4 brand layer
   Values, families, shapes and usage rules: /knowledge/design-system
   (NSi4 Design System, version 6 "midnight ink", signed off 2026-09-30).

   Layers, in cascade order:
     1. Tokens          every value the system names, on :root
     2. Fonts           self-hosted IBM Plex, metric-matched fallbacks
     3. Worlds          one body class per product page sets the accent
     4. Base            the .nsi4 wrapper
     5. Type scale      the ten styles in the system's Parts
     6. Components      the system's Composition
     7. Page layout     the shells the rebuilt pages compose from
     8. Legacy          the pre-redesign class names, kept working
     9. Icons           the Lucide sprite
    10. Phoenix         scoped overrides so Phoenix lands on tokens
    11. Motion guard
    12. View transitions   page-to-page crossfade, Chromium only

   No hex literal appears below layer 1. This sheet is linked after
   theme.min.css, so an equal-specificity rule here wins on source order.
   ========================================================================== */

/* ==========================================================================
   1. Tokens
   ========================================================================== */
:root {
	color-scheme: dark;

	/* Surfaces */
	--nsi4-ground: #0A0D14;
	--nsi4-surface: #11151E;
	--nsi4-raised: #181C27;
	--nsi4-hairline: rgba(255, 255, 255, 0.08);
	--nsi4-control-border: #6A7080;

	/* Text levels */
	--nsi4-text: #EDEFF3;
	--nsi4-text-2: #A0A6B3;
	--nsi4-text-3: #838A98;
	--nsi4-focus: var(--nsi4-text);

	/* Brand */
	--nsi4-brand-cyan: #20B7E0;
	--nsi4-brand-purple: #8B2092;
	--nsi4-cta-start: #0E7DB8;
	--nsi4-cta-end: #B02DC0;
	--nsi4-on-cta: #FFFFFF;

	/* Product worlds */
	--nsi4-world-wrs: #FF6B2C;
	--nsi4-world-trinity: #2BE38A;
	--nsi4-world-fromscratch: #4D7CFE;
	--nsi4-world-tycho: #22D3EE;
	--nsi4-world-alivemd: #F0609E;
	--nsi4-on-world: var(--nsi4-ground);

	/* Accent: the corporate shell is the quiet default */
	--nsi4-accent: var(--nsi4-text);

	/* Evidence-component colours from the PO-04 mockup: named here so every
	   hex stays in this block. */
	--nsi4-redaction: #2A3040;
	--nsi4-diff-minus: #F08080;

	/* Spacing. Index is the multiple of 4px (8px grid with a 4px half-step):
	   space-6 = 24, space-8 = 32, space-12 = 48, space-16 = 64, space-24 = 96,
	   space-40 = 160. */
	--nsi4-space-1: 4px;
	--nsi4-space-2: 8px;
	--nsi4-space-3: 12px;
	--nsi4-space-4: 16px;
	--nsi4-space-6: 24px;
	--nsi4-space-8: 32px;
	--nsi4-space-12: 48px;
	--nsi4-space-16: 64px;
	--nsi4-space-24: 96px;
	--nsi4-space-40: 160px;

	/* Radii. No pills. */
	--nsi4-radius-sm: 4px;
	--nsi4-radius-md: 8px;
	--nsi4-radius-lg: 12px;

	/* Depth. The only shadow in the system. */
	--nsi4-highlight-top: inset 0 1px 0 rgba(255, 255, 255, 0.04);

	/* Layout */
	--nsi4-content-max: 1200px;
	--nsi4-gutter: 16px;
	/* A sticky rail or guide sits 96px from the viewport top, clear of the
	   64px nav. The case guide reads it today; anything else that sticks under
	   the nav is meant to read the same offset rather than restate it. */
	--nsi4-sticky-top: 96px;
	/* Section spacing. Full sections take --nsi4-section-pad; a section whose
	   body measures under 240px tall at 1280px takes --nsi4-section-pad-compact:
	   56/40 on a phone, the clamp and 56 from 900px (media query below). */
	--nsi4-section-pad: 56px;
	--nsi4-section-pad-compact: 40px;
	--nsi4-measure: 50ch;
	--nsi4-touch-min: 44px;
	/* Hero top padding: the hero copy's top edge sits this far below the
	   band's top. .nsi4-hero's own padding-block start reads it, and so do
	   the hero texture's mask and the Trinity ticker strip — the two must
	   not paint inside the copy. Moves to 120px with the two-column hero
	   (media query below), and the three must move together. */
	--nsi4-hero-pad-top: var(--nsi4-space-16);

	/* Motion */
	--nsi4-dur: 160ms;
	--nsi4-ease: cubic-bezier(0.2, 0.8, 0.2, 1);

	/* Families */
	--nsi4-font-sans: "IBM Plex Sans", "IBM Plex Sans Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
	--nsi4-font-mono: "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, "SF Mono", Consolas, monospace;

	/* Type scale: size / line / weight / tracking.
	   display-xl and display-l are the two responsive styles; the desktop
	   half is applied in the media query below. */
	--nsi4-fs-display-xl: 40px;
	--nsi4-lh-display-xl: 44px;
	--nsi4-fw-display-xl: 600;
	--nsi4-ls-display-xl: -0.02em;

	--nsi4-fs-display-l: 36px;
	--nsi4-lh-display-l: 42px;
	--nsi4-fw-display-l: 600;
	--nsi4-ls-display-l: -0.02em;

	--nsi4-fs-heading-2: 32px;
	--nsi4-lh-heading-2: 40px;
	--nsi4-fw-heading-2: 600;
	--nsi4-ls-heading-2: -0.01em;

	--nsi4-fs-heading-3: 24px;
	--nsi4-lh-heading-3: 32px;
	--nsi4-fw-heading-3: 600;
	--nsi4-ls-heading-3: 0;

	--nsi4-fs-lede: 20px;
	--nsi4-lh-lede: 30px;
	--nsi4-fw-lede: 400;
	--nsi4-ls-lede: 0;

	--nsi4-fs-body: 17px;
	--nsi4-lh-body: 27px;
	--nsi4-fw-body: 400;
	--nsi4-ls-body: 0;

	--nsi4-fs-small: 15px;
	--nsi4-lh-small: 22px;
	--nsi4-fw-small: 400;
	--nsi4-ls-small: 0;

	--nsi4-fs-eyebrow: 13px;
	--nsi4-lh-eyebrow: 16px;
	--nsi4-fw-eyebrow: 500;
	--nsi4-ls-eyebrow: 0.08em;

	--nsi4-fs-data: 15px;
	--nsi4-lh-data: 22px;
	--nsi4-fw-data: 400;
	--nsi4-ls-data: 0;

	--nsi4-fs-data-xl: 40px;
	--nsi4-lh-data-xl: 44px;
	--nsi4-fw-data-xl: 500;
	--nsi4-ls-data-xl: -0.01em;

	/* Texture defaults — each world overrides these (layer 3) */
	--nsi4-texture-image: none;
	--nsi4-texture-size: auto;
	--nsi4-texture-opacity: 0.14;
}

@media (min-width: 480px) {
	:root {
		--nsi4-fs-display-xl: 64px;
		--nsi4-lh-display-xl: 68px;
		--nsi4-fs-display-l: 48px;
		--nsi4-lh-display-l: 54px;
	}
}

@media (min-width: 768px) {
	:root {
		--nsi4-gutter: 24px;
	}
}

@media (min-width: 900px) {
	:root {
		--nsi4-section-pad: clamp(72px, 8vw, 112px);
		--nsi4-section-pad-compact: 56px;
	}
}

/* The hero takes its tall desktop padding with its two-column split
   (page layout, below): 120px over the copy. */
@media (min-width: 1000px) {
	:root {
		--nsi4-hero-pad-top: 120px;
	}
}

/* ==========================================================================
   2. Fonts
   IBM Plex Sans 400/500/600 and IBM Plex Mono 400/500, self-hosted as woff2
   and split by unicode-range so a page fetches only the subset it renders.
   ========================================================================== */
@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-ext-400-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-ext-500-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "IBM Plex Sans";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans-latin-ext-600-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "IBM Plex Mono";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "IBM Plex Mono";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "IBM Plex Mono";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono-latin-ext-400-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "IBM Plex Mono";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono-latin-ext-500-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Metric-matched fallbacks, so a swap to the webfont shifts nothing.
   Overrides derived from the two fonts' own tables (IBM Plex Sans
   xWidthAvg 451/1000 against Arial 913/2048; IBM Plex Mono 600/1000
   against Courier New 1229/2048), not estimated. */
@font-face {
	font-family: "IBM Plex Sans Fallback";
	src: local("Arial"), local("ArialMT");
	ascent-override: 101.3184%;
	descent-override: 27.183%;
	line-gap-override: 0%;
	size-adjust: 101.1663%;
}

@font-face {
	font-family: "IBM Plex Mono Fallback";
	src: local("Courier New"), local("CourierNewPSMT");
	ascent-override: 102.5167%;
	descent-override: 27.5045%;
	line-gap-override: 0%;
	size-adjust: 99.9837%;
}

/* ==========================================================================
   3. Product worlds
   One class sets the accent and the hero texture. Quiet shell, loud
   products: the accent marks eyebrows, callout markers, the world button and
   in-text links; it never fills a section background.
   ========================================================================== */
.world-wrs {
	--nsi4-accent: var(--nsi4-world-wrs);
	--nsi4-texture-image: radial-gradient(circle, var(--nsi4-accent) 1px, transparent 1.5px);
	--nsi4-texture-size: 6px 6px;
}

.world-trinity {
	--nsi4-accent: var(--nsi4-world-trinity);
	--nsi4-texture-image: linear-gradient(to bottom, var(--nsi4-accent) 1px, transparent 1px);
	--nsi4-texture-size: 100% 8px;
}

.world-fromscratch {
	--nsi4-accent: var(--nsi4-world-fromscratch);
	--nsi4-texture-image: radial-gradient(circle, var(--nsi4-accent) 1.2px, transparent 1.6px);
	--nsi4-texture-size: 16px 16px;
}

.world-tycho {
	--nsi4-accent: var(--nsi4-world-tycho);
	--nsi4-texture-image: linear-gradient(to bottom, var(--nsi4-accent) 1px, transparent 1px), linear-gradient(to right, var(--nsi4-accent) 1px, transparent 1px);
	--nsi4-texture-size: 24px 24px, 24px 24px;
	--nsi4-texture-opacity: 0.1;
}

.world-alivemd {
	--nsi4-accent: var(--nsi4-world-alivemd);
	--nsi4-texture-image: linear-gradient(to bottom, transparent 26px, var(--nsi4-accent) 26px, var(--nsi4-accent) 27px);
	--nsi4-texture-size: 100% 27px;
}

/* ==========================================================================
   4. Base
   ========================================================================== */
.nsi4 {
	background: var(--nsi4-ground);
	color: var(--nsi4-text);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.nsi4 :focus-visible {
	outline: 2px solid var(--nsi4-focus);
	outline-offset: 2px;
}

.nsi4-shell {
	max-width: var(--nsi4-content-max);
	margin-inline: auto;
	padding-inline: var(--nsi4-gutter);
}

.nsi4-measure {
	max-width: var(--nsi4-measure);
}

.nsi4-section {
	padding-block: var(--nsi4-section-pad);
}

/* ==========================================================================
   5. Type scale
   ========================================================================== */
.nsi4-type-display-xl {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-display-xl);
	line-height: var(--nsi4-lh-display-xl);
	font-weight: var(--nsi4-fw-display-xl);
	letter-spacing: var(--nsi4-ls-display-xl);
	text-wrap: balance;
}

.nsi4-type-display-l {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-display-l);
	line-height: var(--nsi4-lh-display-l);
	font-weight: var(--nsi4-fw-display-l);
	letter-spacing: var(--nsi4-ls-display-l);
	text-wrap: balance;
}

.nsi4-type-heading-2 {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-2);
	line-height: var(--nsi4-lh-heading-2);
	font-weight: var(--nsi4-fw-heading-2);
	letter-spacing: var(--nsi4-ls-heading-2);
	text-wrap: balance;
}

.nsi4-type-heading-3 {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-3);
	line-height: var(--nsi4-lh-heading-3);
	font-weight: var(--nsi4-fw-heading-3);
	letter-spacing: var(--nsi4-ls-heading-3);
}

.nsi4-type-lede {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-lede);
	line-height: var(--nsi4-lh-lede);
	font-weight: var(--nsi4-fw-lede);
	letter-spacing: var(--nsi4-ls-lede);
	color: var(--nsi4-text-2);
	max-width: var(--nsi4-measure);
}

.nsi4-type-body {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	font-weight: var(--nsi4-fw-body);
	letter-spacing: var(--nsi4-ls-body);
	max-width: var(--nsi4-measure);
}

.nsi4-type-small {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	font-weight: var(--nsi4-fw-small);
	letter-spacing: var(--nsi4-ls-small);
}

.nsi4-type-eyebrow {
	margin: 0;
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

.nsi4-type-data {
	margin: 0;
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data);
	line-height: var(--nsi4-lh-data);
	font-weight: var(--nsi4-fw-data);
	letter-spacing: var(--nsi4-ls-data);
}

.nsi4-type-data-xl {
	margin: 0;
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data-xl);
	line-height: var(--nsi4-lh-data-xl);
	font-weight: var(--nsi4-fw-data-xl);
	letter-spacing: var(--nsi4-ls-data-xl);
	font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   6. Components
   ========================================================================== */

/* Buttons */
.nsi4-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--nsi4-space-2);
	min-height: var(--nsi4-touch-min);
	padding: 0 20px;
	border: 1px solid transparent;
	border-radius: var(--nsi4-radius-md);
	font-family: var(--nsi4-font-sans);
	font-size: 16px;
	font-weight: 600;
	line-height: 20px;
	text-decoration: none;
	cursor: pointer;
	transition: filter var(--nsi4-dur) var(--nsi4-ease), transform var(--nsi4-dur) var(--nsi4-ease), border-color var(--nsi4-dur) var(--nsi4-ease), background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-btn:active {
	transform: translateY(1px);
}

.nsi4-btn--primary {
	background: linear-gradient(90deg, var(--nsi4-cta-start), var(--nsi4-cta-end));
	/* The shorthand leaves background-origin at padding-box, so under the 1px
	   transparent border the gradient re-enters from its far end and paints a
	   1px sliver on each edge. Sized to the border box, the stops run edge to
	   edge at 1x and 2x. */
	background-origin: border-box;
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
	color: var(--nsi4-on-cta);
}

.nsi4-btn--primary:hover {
	filter: brightness(1.12);
}

.nsi4-btn--secondary {
	background: transparent;
	color: var(--nsi4-text);
	border-color: var(--nsi4-control-border);
}

.nsi4-btn--secondary:hover {
	border-color: var(--nsi4-text);
	background: var(--nsi4-raised);
}

.nsi4-btn--world {
	background: var(--nsi4-accent);
	color: var(--nsi4-on-world);
}

.nsi4-btn--world:hover {
	filter: brightness(1.08);
}

.nsi4-btn[aria-disabled="true"] {
	opacity: 0.45;
	pointer-events: none;
}

/* The mirror's Rules put in-text links under the accent; the corporate
   accent is the text colour, so this is the same colour there and the world
   accent on a product page. */
.nsi4-link {
	color: var(--nsi4-accent);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	text-decoration-color: var(--nsi4-control-border);
}

.nsi4-link:hover {
	color: var(--nsi4-text);
	text-decoration-color: var(--nsi4-accent);
}

/* Eyebrow and badge */
.nsi4-eyebrow {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

.nsi4-eyebrow--world {
	color: var(--nsi4-accent);
}

/* Brand strings keep the casing they are written in — fromScratch, AliveMD,
   NSi4 — so the eyebrow's uppercase does not restate them. Applied to the
   five product hero eyebrows and the home hero's; section eyebrows ("01
   Problem") keep their uppercase. The class does not depend on the eyebrow,
   so a dt or dd naming a product can take the same one. */
.nsi4-keep-case {
	text-transform: none;
}

.nsi4-badge {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: var(--nsi4-space-1) var(--nsi4-space-2);
	border: 1px solid var(--nsi4-control-border);
	border-radius: var(--nsi4-radius-sm);
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--nsi4-text-2);
}

/* The chip uppercases its own text, which would restate the brand as NSI4 —
   so a chip whose status carries the brand name takes the case-keeping
   modifier as well, and this compound form is what beats the uppercase above
   (the bare .nsi4-keep-case sits earlier in the sheet at equal specificity). */
.nsi4-badge.nsi4-keep-case {
	text-transform: none;
}

.nsi4-badge__dot {
	width: 8px;
	height: 8px;
	border-radius: 2px;
	background: var(--nsi4-accent);
}

/* Crop frame — an annotated 2x crop with numbered callouts */
.nsi4-crop {
	margin: 0;
	display: grid;
	gap: var(--nsi4-space-4);
}

.nsi4-crop__frame {
	position: relative;
	overflow: hidden;
	border-radius: var(--nsi4-radius-lg);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	box-shadow: var(--nsi4-highlight-top);
}

.nsi4-crop__frame img {
	display: block;
	width: 100%;
	height: auto;
}

.nsi4-crop__marker {
	position: absolute;
	transform: translate(-50%, -50%);
	width: 24px;
	height: 24px;
	display: grid;
	place-items: center;
	border-radius: var(--nsi4-radius-sm);
	border: 2px solid var(--nsi4-ground);
	background: var(--nsi4-accent);
	color: var(--nsi4-on-world);
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	font-weight: 500;
	line-height: 1;
}

.nsi4-crop__notes {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--nsi4-space-3);
	counter-reset: note;
}

/* The marker is taken out of flow so the label and the body stay one text run:
   in flow, a grid makes the <b> and the text after it two separate items. */
.nsi4-crop__notes li {
	position: relative;
	padding-left: calc(24px + var(--nsi4-space-3));
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

.nsi4-crop__notes li::before {
	position: absolute;
	top: 0;
	left: 0;
	counter-increment: note;
	content: counter(note);
	width: 24px;
	height: 24px;
	display: grid;
	place-items: center;
	border-radius: var(--nsi4-radius-sm);
	border: 1px solid var(--nsi4-accent);
	color: var(--nsi4-accent);
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	font-weight: 500;
	line-height: 1;
}

.nsi4-crop__notes b {
	color: var(--nsi4-text);
	font-weight: 600;
}

@media (min-width: 900px) {
	.nsi4-crop--side {
		grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
		align-items: start;
		gap: var(--nsi4-space-8);
	}
}

/* Spec block */
.nsi4-spec {
	margin: 0;
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
}

.nsi4-spec__row {
	display: grid;
	grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
	gap: var(--nsi4-space-4);
	padding: 14px var(--nsi4-space-6);
	border-top: 1px solid var(--nsi4-hairline);
}

.nsi4-spec__row:first-child {
	border-top: 0;
}

.nsi4-spec dt {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-data);
	font-weight: 500;
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

/* The press kit's product keys name brands, so a dt carrying PO-03's
   modifier keeps its own casing — this rule's specificity would otherwise
   outrank .nsi4-keep-case on its own. */
.nsi4-spec dt.nsi4-keep-case {
	text-transform: none;
}

/* Values read as prose — the keys stay mono above them. A literal technical
   token inside a value keeps the mono the document gives <code>. */
.nsi4-spec dd {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	font-weight: var(--nsi4-fw-small);
	color: var(--nsi4-text);
}

@media (max-width: 480px) {
	.nsi4-spec__row {
		grid-template-columns: 1fr;
		gap: var(--nsi4-space-1);
		padding: 12px var(--nsi4-space-4);
	}
}

/* Measured stat — for a number that has a source line */
.nsi4-stat {
	display: grid;
	gap: var(--nsi4-space-2);
	padding-top: var(--nsi4-space-4);
	border-top: 1px solid var(--nsi4-hairline);
}

.nsi4-stat__value {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data-xl);
	line-height: var(--nsi4-lh-data-xl);
	font-weight: var(--nsi4-fw-data-xl);
	letter-spacing: var(--nsi4-ls-data-xl);
	color: var(--nsi4-text);
	font-variant-numeric: tabular-nums;
}

.nsi4-stat__unit {
	font-size: 20px;
	color: var(--nsi4-text-2);
	margin-left: 4px;
}

.nsi4-stat__label {
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

.nsi4-stat__source {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: 400;
	color: var(--nsi4-text-3);
}

/* The source line as its own line: the one Armory line under RETRY's stat
   row, and the source in the RETRY card. The stat's .nsi4-stat__source is
   off /community/retry, so this carries the same type and colour as a link. */
.nsi4-source {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: 400;
	color: var(--nsi4-text-3);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	text-decoration-color: var(--nsi4-control-border);
}

.nsi4-source:hover {
	color: var(--nsi4-text-2);
	text-decoration-color: var(--nsi4-text-3);
}

/* The founding-partner card — the proof object in the Community and
   Partnerships heroes (Pages/Shared/_RetryCard.cshtml). The system's one
   card shape: surface, hairline, 12px radius, the 32px padding step. */
.nsi4-retry-card {
	display: grid;
	gap: var(--nsi4-space-6);
	align-content: start;
	padding: var(--nsi4-space-8);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
}

/* Case-study section shell */
.nsi4-case {
	padding-block: var(--nsi4-section-pad);
	display: grid;
	gap: var(--nsi4-space-8);
}

@media (min-width: 900px) {
	.nsi4-case {
		padding-block: var(--nsi4-section-pad);
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		gap: var(--nsi4-gutter);
	}
}

.nsi4-case__head {
	display: grid;
	gap: var(--nsi4-space-2);
	align-content: start;
}

.nsi4-case__head h2 {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-2);
	line-height: var(--nsi4-lh-heading-2);
	font-weight: var(--nsi4-fw-heading-2);
	letter-spacing: var(--nsi4-ls-heading-2);
	text-wrap: balance;
}

.nsi4-case__body {
	display: grid;
	gap: var(--nsi4-space-6);
	min-width: 0;
}

.nsi4-case__body p {
	margin: 0;
	max-width: var(--nsi4-measure);
}

/* A labelled sub-block inside a case-study body — a sub-heading over the grid
   it introduces (the WRS case study's Surfaces / What it does / The assistant).
   The body's own gap separates the blocks; this gap binds a sub-heading to what
   it labels, at the same 16px the tiles sit to each other. */
.nsi4-case__block {
	display: grid;
	gap: var(--nsi4-space-4);
}

/* The section guide: a guided section's head column carries the eyebrow, the
   h2, a short intro and — where the section runs to several groups — an index
   of them (03 What We Built). The modifier is set on the section, never on
   .nsi4-case__head: the head is the site-wide section shell (01/02/04/05, the
   RETRY page, the styleguide demo) and none of those may stick. From 900px the
   whole guide sticks 96px under the viewport top; a sticky grid item is held
   inside its own grid area, so it stops at the section's end instead of
   following the reader into the next one. */
@media (min-width: 900px) {
	.nsi4-case--guided .nsi4-case__head {
		position: sticky;
		top: var(--nsi4-sticky-top);
		align-self: start;
	}
}

/* Groups in a guided section sit 72px apart — the section's own rhythm from
   one labelled group to the next, between the 64px and 96px spacing steps. */
.nsi4-case--guided .nsi4-case__body {
	gap: 72px;
}

.nsi4-case__intro {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	color: var(--nsi4-text-2);
}

/* The group index: one anchor link per group, a wrapped row of links under the
   intro at every width. Without case-guide.js these are plain anchors and
   nothing is marked; with it the group being read carries aria-current and the
   world accent. Scrolling stays the browser's — theme.min.css holds the smooth
   scroll and its reduced-motion guard — so nothing here animates a jump. */
.nsi4-case__index {
	margin: var(--nsi4-space-4) 0 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--nsi4-space-2) var(--nsi4-space-4);
}

.nsi4-case__index a {
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-3);
	text-decoration: none;
}

.nsi4-case__index a:hover {
	color: var(--nsi4-text-2);
}

.nsi4-case__index a[aria-current="true"] {
	color: var(--nsi4-accent);
}

/* A group heading over a guided section's block: 18px/600 in the second text
   level, so it labels its group without competing with the section's h2. The
   size sits between the heading-3 and body steps and has no token. */
.nsi4-case__block > h3 {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	color: var(--nsi4-text-2);
}

/* 04 Evidence: the section guide in the left column (PO-02's, reused) and
   three blocks in the right — the screen, one component card, the numbers.
   Every override of a shared rule below is scoped by the section modifier,
   so the heroes' and the styleguide's crops keep the shared note tile and
   single-column notes, and the home page's and RETRY's stats keep theirs.
   The card classes themselves (.nsi4-evidence-card, .nsi4-trace,
   .nsi4-tasks, .nsi4-change, .nsi4-cascade) are new names that 04's markup
   opts into, like every component in this sheet, and appear on no other page
   today. */

/* 04's blocks sit 40px apart — the guided section's 72px group rhythm is 03's.
   This rule follows .nsi4-case--guided's in the sheet, so at equal
   specificity it wins. */
.nsi4-case--evidence .nsi4-case__body {
	gap: 40px;
}

/* The screen: the figure spans the right column once the side-by-side
   modifier is off it, and its three notes run three across from 900px (24px
   gap), one column below. The 04 tile is 22px with an accent fill instead of
   the shared outlined counter, and the note text drops to 14/22. The 5px tile
   radius and the 14px text have no token (the system's steps are 4/8/12 and
   the small size is 15) — literals, like PO-02's type sizes. */
@media (min-width: 900px) {
	.nsi4-case--evidence .nsi4-crop__notes {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--nsi4-space-6);
	}
}

.nsi4-case--evidence .nsi4-crop__notes li {
	padding-left: calc(22px + var(--nsi4-space-3));
	font-size: 14px;
	line-height: var(--nsi4-lh-small);
}

.nsi4-case--evidence .nsi4-crop__notes li::before {
	width: 22px;
	height: 22px;
	border-radius: 5px;
	border: 0;
	background: var(--nsi4-accent);
	color: var(--nsi4-ground);
}

/* The frame's hairline is the shared crop's 1px border, which would leave the
   <img> two pixels short of its column. In 04 the same line is an outward
   ring, so frame, figure and image all measure the column's width. */
.nsi4-case--evidence .nsi4-crop__frame {
	border: 0;
	box-shadow: var(--nsi4-highlight-top), 0 0 0 1px var(--nsi4-hairline);
}

/* The component card: the chat's shell (surface, hairline, 12px radius, the
   system's one inset highlight) with a header row — the label in the world
   eyebrow on the left, the capture marker in 12px mono on the right. The
   cards are pictures of an interface, so their lines run the card's width
   rather than the body measure. */
.nsi4-evidence-card {
	display: grid;
	min-width: 0;
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
	color: var(--nsi4-text);
}

.nsi4-evidence-card p {
	max-width: none;
}

.nsi4-evidence-card__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--nsi4-space-3);
}

.nsi4-evidence-card__marker {
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	line-height: var(--nsi4-lh-eyebrow);
	color: var(--nsi4-text-3);
}

/* Trinity · decision trace — a log table whose rows carry their own 24px
   gutters, so the card is unpadded and its rules run edge to edge. The .06
   row rule is the mockup's (the system hairline is .08) — a literal; the
   redaction fill reads --nsi4-redaction. Below 640px the table scrolls
   inside its focusable wrapper instead of moving the page. */
.nsi4-trace .nsi4-evidence-card__head {
	padding: var(--nsi4-space-4) var(--nsi4-space-6);
}

.nsi4-trace__scroll {
	overflow-x: auto;
}

.nsi4-trace__table {
	width: 100%;
	border-collapse: collapse;
	text-align: left;
	white-space: nowrap;
}

.nsi4-trace__table th {
	padding: 10px var(--nsi4-space-6);
	font-family: var(--nsi4-font-mono);
	font-size: 11px;
	line-height: 16px;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

.nsi4-trace__table td {
	padding: 10px var(--nsi4-space-6);
	border-top: 1px solid rgba(255, 255, 255, 0.06);
	font-family: var(--nsi4-font-mono);
	font-size: 13px;
	line-height: 20px;
}

.nsi4-trace__bar {
	display: inline-block;
	width: 34px;
	height: 12px;
	/* 2px radius sits below the system's 4px step — a literal. */
	border-radius: 2px;
	background: var(--nsi4-redaction);
	vertical-align: middle;
}

.nsi4-trace__pass {
	color: var(--nsi4-accent);
}

.nsi4-trace__muted {
	color: var(--nsi4-text-2);
}

.nsi4-trace__foot {
	margin: 0;
	padding: 14px var(--nsi4-space-6) 18px;
	font-size: 13px;
	line-height: 20px;
	color: var(--nsi4-text-2);
}

/* Tycho · one task, start to finish — a six-row tool-call log on the same
   full-bleed row rule. Below 640px the detail wraps under its action, so the
   row re-flows instead of scrolling sideways. */
.nsi4-tasks .nsi4-evidence-card__head {
	padding: var(--nsi4-space-4) var(--nsi4-space-6);
}

.nsi4-tasks__row {
	display: grid;
	grid-template-columns: 16px 200px minmax(0, 1fr) 64px;
	gap: var(--nsi4-space-3);
	padding: 9px var(--nsi4-space-6);
	border-top: 1px solid rgba(255, 255, 255, 0.06);
	font-family: var(--nsi4-font-mono);
	font-size: 13px;
	line-height: 20px;
}

.nsi4-tasks__mark {
	color: var(--nsi4-accent);
}

.nsi4-tasks__action {
	color: var(--nsi4-text);
}

.nsi4-tasks__detail {
	color: var(--nsi4-text-2);
	min-width: 0;
}

.nsi4-tasks__result {
	color: var(--nsi4-accent);
	text-align: right;
}

@media (max-width: 639.98px) {
	.nsi4-tasks__row {
		grid-template-columns: 16px minmax(0, 1fr) auto;
	}

	.nsi4-tasks__detail {
		grid-row: 2;
		grid-column: 2 / -1;
	}

	.nsi4-tasks__result {
		grid-row: 1;
		grid-column: 3;
	}
}

/* fromScratch · Oracle · a proposed change — the card a person accepts or
   rejects. Accept and Reject are pictures of controls: spans, never buttons,
   never focusable. The card takes the spec'd 24px padding and 16px rhythm;
   the diff's two tints are the mockup's rgba and have no token (a literal),
   and the removed sign reads --nsi4-diff-minus. */
.nsi4-change {
	padding: var(--nsi4-space-6);
	gap: var(--nsi4-space-4);
}

.nsi4-change__title {
	font-family: var(--nsi4-font-sans);
	font-size: 18px;
	line-height: 26px;
	font-weight: 600;
	color: var(--nsi4-text);
}

.nsi4-change__diff {
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-md);
	overflow: hidden;
}

.nsi4-change__row {
	display: grid;
	grid-template-columns: 24px 120px minmax(0, 1fr);
	padding: 10px var(--nsi4-space-4);
	font-family: var(--nsi4-font-mono);
	font-size: 13px;
	line-height: 20px;
	color: var(--nsi4-text);
}

.nsi4-change__row--minus {
	background: rgba(240, 96, 96, 0.08);
}

.nsi4-change__row--minus .nsi4-change__sign {
	color: var(--nsi4-diff-minus);
}

.nsi4-change__row--plus {
	background: rgba(77, 124, 254, 0.10);
}

.nsi4-change__row--plus .nsi4-change__sign {
	color: var(--nsi4-accent);
}

.nsi4-change__field {
	color: var(--nsi4-text-3);
}

.nsi4-change__why {
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

.nsi4-change__why b {
	color: var(--nsi4-text);
	font-weight: 600;
}

.nsi4-change__footer {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nsi4-space-3);
}

.nsi4-change__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 40px;
	padding: 0 20px;
	border-radius: var(--nsi4-radius-md);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	font-weight: 600;
	line-height: 20px;
}

.nsi4-change__accept {
	background: var(--nsi4-accent);
	color: var(--nsi4-on-world);
}

.nsi4-change__reject {
	border: 1px solid rgba(255, 255, 255, 0.16);
	color: var(--nsi4-text);
}

.nsi4-change__note {
	margin-left: auto;
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	line-height: var(--nsi4-lh-eyebrow);
	color: var(--nsi4-text-3);
	text-align: right;
}

/* AliveMD · status cascade — two task rows and the line between them. The
   card takes the spec'd 24px padding and a 12px rhythm; the completed chip's
   tint is 14% of the world accent and the blocked chip's outline the
   mockup's .16 — both literals, neither has a token. */
.nsi4-cascade {
	padding: var(--nsi4-space-6);
	gap: var(--nsi4-space-3);
}

.nsi4-cascade__task {
	display: grid;
	grid-template-columns: 72px minmax(0, 1fr) auto;
	gap: var(--nsi4-space-4);
	align-items: center;
	padding: 14px var(--nsi4-space-4);
	background: var(--nsi4-ground);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-md);
}

.nsi4-cascade__id {
	font-family: var(--nsi4-font-mono);
	font-size: 13px;
	color: var(--nsi4-text-3);
}

.nsi4-cascade__title {
	font-size: var(--nsi4-fs-small);
}

.nsi4-cascade__chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 10px;
	border-radius: var(--nsi4-radius-sm);
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	line-height: 16px;
}

.nsi4-cascade__chip--done {
	background: rgba(240, 96, 158, 0.14);
	color: var(--nsi4-accent);
}

.nsi4-cascade__chip--moved {
	border: 1px solid rgba(255, 255, 255, 0.16);
}

.nsi4-cascade__dot {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--nsi4-accent);
}

.nsi4-cascade__was {
	color: var(--nsi4-text-3);
	text-decoration: line-through;
}

.nsi4-cascade__now {
	color: var(--nsi4-text);
}

.nsi4-cascade__unblocks {
	margin: 0;
	padding-left: 104px;
	font-family: var(--nsi4-font-mono);
	font-size: 12px;
	line-height: var(--nsi4-lh-eyebrow);
	color: var(--nsi4-text-3);
}

.nsi4-cascade__caption {
	margin: 0;
	font-size: 13px;
	line-height: 20px;
	color: var(--nsi4-text-2);
}

/* The numbers: two stats side by side from 640px, 24px apart, ruled and
   spaced by the shared stat above. 04 re-specifies the value as the world
   accent at 600, the unit in full text, and the label and source one step
   smaller — only 04's stats; the home page's, RETRY's, the Partnerships' and
   the styleguide's keep theirs. The scoped gap out-ranks the shared
   .nsi4-stats gap (the shared pair rule below sets columns only), so the
   24px holds from 640px up. The phone block at the end of the page-layout
   layer takes it to 16px below 640px. */
.nsi4-case--evidence .nsi4-stats {
	gap: var(--nsi4-space-6);
}

.nsi4-case--evidence .nsi4-stat__value {
	font-weight: 600;
	color: var(--nsi4-accent);
}

.nsi4-case--evidence .nsi4-stat__unit {
	color: var(--nsi4-text);
}

.nsi4-case--evidence .nsi4-stat__label {
	font-size: 14px;
}

.nsi4-case--evidence .nsi4-stat__source {
	font-size: 12px;
}

@media (min-width: 640px) {
	.nsi4-case--evidence .nsi4-stats {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
/* Product card */
.nsi4-product {
	display: grid;
	gap: var(--nsi4-space-4);
	padding: var(--nsi4-space-6);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
	color: var(--nsi4-text);
	text-decoration: none;
	transition: background-color var(--nsi4-dur) var(--nsi4-ease), border-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-product:hover {
	background: var(--nsi4-raised);
	border-color: var(--nsi4-control-border);
}

.nsi4-product__name {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-3);
	line-height: var(--nsi4-lh-heading-3);
	font-weight: var(--nsi4-fw-heading-3);
}

.nsi4-product__claim {
	margin: 0;
	color: var(--nsi4-text-2);
}

.nsi4-product__proof {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: 400;
	color: var(--nsi4-text-3);
}

.nsi4-product__more {
	font-weight: 600;
	font-size: var(--nsi4-fs-small);
	color: var(--nsi4-text);
}

.nsi4-product__media {
	border-radius: var(--nsi4-radius-md);
	overflow: hidden;
	border: 1px solid var(--nsi4-hairline);
}

.nsi4-product__media img {
	display: block;
	width: 100%;
	height: auto;
}

/* World texture — product hero band only */
.nsi4-texture {
	position: relative;
	isolation: isolate;
}

.nsi4-texture::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: var(--nsi4-texture-opacity);
	background-image: var(--nsi4-texture-image);
	background-size: var(--nsi4-texture-size);
	mask-image: linear-gradient(to bottom, black, transparent);
	-webkit-mask-image: linear-gradient(to bottom, black, transparent);
}

/* On a hero band the texture stays out of the hero copy. By default it
   fades to transparent exactly at the copy's top edge (--nsi4-hero-pad-top
   is what .nsi4-hero pads above the copy), so only the strip above the
   copy paints. From 1000px the hero splits into a copy column and a crop,
   and on those heroes the texture paints only in the half of the band away
   from the copy column, faded out before it gets there: the copy column's
   right edge never comes closer than half the band's width from the right
   edge (524px of 1280px), so it always lands in the transparent side. A
   hero with no crop writes its copy as the only child spanning both
   columns — no half is free beside it, so it keeps the strip above the
   copy. */
.nsi4-hero-band.nsi4-texture::before {
	mask-image: linear-gradient(to bottom, black, transparent var(--nsi4-hero-pad-top));
	-webkit-mask-image: linear-gradient(to bottom, black, transparent var(--nsi4-hero-pad-top));
}

@media (min-width: 1000px) {
	.nsi4-hero-band.nsi4-texture:not(:has(.nsi4-hero__copy:only-child))::before {
		mask-image: linear-gradient(to left, black 40%, transparent 50%);
		-webkit-mask-image: linear-gradient(to left, black 40%, transparent 50%);
	}
}

/* Skip link — the first focusable element in the shell. It sits at the top of
   the document on a surface, moved out of view until it takes focus, so a
   keyboard user reaches the content without walking the navigation. */
.nsi4-skip-link {
	position: absolute;
	top: var(--nsi4-space-4);
	left: var(--nsi4-space-4);
	z-index: 1080;
	display: inline-flex;
	align-items: center;
	min-height: var(--nsi4-touch-min);
	padding: 0 var(--nsi4-space-4);
	background: var(--nsi4-surface);
	color: var(--nsi4-text);
	border: 1px solid var(--nsi4-control-border);
	border-radius: var(--nsi4-radius-md);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	font-weight: 600;
	text-decoration: none;
	transform: translateY(calc(-100% - var(--nsi4-space-8)));
	transition: transform var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-skip-link:focus {
	transform: translateY(0);
}

/* Touch targets — every chrome control reaches the 44px minimum in both
   directions. The hit area grows; the type size does not. */
.nsi4 .navbar-toggler {
	min-width: var(--nsi4-touch-min);
	min-height: var(--nsi4-touch-min);
}

.nsi4 .navbar .dropdown-item {
	display: flex;
	align-items: center;
	min-height: var(--nsi4-touch-min);
}

.nsi4 footer a {
	display: inline-flex;
	align-items: center;
	min-width: var(--nsi4-touch-min);
	min-height: var(--nsi4-touch-min);
}

.nsi4 footer a[aria-label] {
	justify-content: center;
}

/* Chrome — the nav and the footer frame every page, so their rules live here
   rather than in any one page's layout. The nav is the mockup's: 64px tall,
   the ground held at 92% so the page reads faintly through it, over a
   hairline. The transparency is mixed, not a second colour. */
.nsi4-nav {
	position: sticky;
	top: 0;
	z-index: 1020;
	background: color-mix(in srgb, var(--nsi4-ground) 92%, transparent);
	border-bottom: 1px solid var(--nsi4-hairline);
}

.nsi4-nav .navbar {
	min-height: 64px;
}

/* Contact rides the right edge of the bar, clear of the menu: the list's auto
   margin pushes it out to the shell's content edge and the collapse centres
   it on the bar. Secondary, so a page's own primary button is the only
   gradient on the first screen; 36px is the bar's button height — a scoped
   override, the 44px floor stays on every other control. */
.nsi4-nav .navbar .nsi4-btn {
	min-height: 36px;
	margin-inline-start: var(--nsi4-space-4);
}

.nsi4-nav .navbar-nav .nav-link {
	display: flex;
	align-items: center;
	min-height: var(--nsi4-touch-min);
	padding-inline: var(--nsi4-space-3);
	border-radius: var(--nsi4-radius-md);
	font-size: var(--nsi4-fs-small);
	font-weight: 500;
}

.nsi4-nav .navbar-nav .nav-link:hover,
.nsi4-nav .navbar-nav .nav-link[aria-current] {
	background: var(--nsi4-raised);
}

/* A menu already sits on the raised step, so the item the reader is on steps
   down to the ground rather than up another one. */
.nsi4-nav .dropdown-item[aria-current] {
	color: var(--nsi4-text);
	background: var(--nsi4-ground);
}

/* The footer is the mockup's four columns — brand, Products, Company,
   Elsewhere — over a base row. One column until 900px. */
.nsi4-footer {
	border-top: 1px solid var(--nsi4-hairline);
	padding-block: var(--nsi4-section-pad-compact);
}

.nsi4-footer__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-8);
}

/* Rows start at the top, so the logo's top edge meets the column headings'.
   The first gap is 0 because the link box is the 44px touch target with the
   mark at its top: the tagline then lands exactly 12px under the logo. */
.nsi4-footer__brand {
	display: grid;
	justify-items: start;
	align-content: start;
	gap: 0;
}

.nsi4 footer .nsi4-footer__brand a {
	align-items: flex-start;
}

.nsi4-footer__contact {
	margin: var(--nsi4-space-2) 0 0;
	color: var(--nsi4-text-3);
}

.nsi4-footer__contact + .nsi4-footer__contact {
	margin-top: 0;
}

.nsi4-footer__contact a {
	color: inherit;
	text-decoration: none;
}

.nsi4-footer__contact a:hover {
	text-decoration: underline;
}

.nsi4-footer__blurb {
	color: var(--nsi4-text-2);
	max-width: 34ch;
}

.nsi4-footer__col {
	display: grid;
	align-content: start;
	gap: var(--nsi4-space-2);
}

.nsi4-footer__col .nsi4-eyebrow {
	margin: 0;
}

.nsi4-footer__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--nsi4-space-2);
	line-height: var(--nsi4-lh-small);
}

.nsi4-footer__list a {
	color: var(--nsi4-text-2);
	text-decoration: none;
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
}

.nsi4-footer__list a:hover {
	color: var(--nsi4-text);
}

/* The footer's links are text, not controls: inline at their line's height.
   The 44px box stays on the logo mark and on every control in the nav. */
.nsi4 footer .nsi4-footer__list a,
.nsi4 footer .nsi4-footer__contact a {
	display: inline;
}

.nsi4-footer__base {
	margin: 0;
	margin-top: var(--nsi4-space-12);
	padding-top: var(--nsi4-space-8);
	border-top: 1px solid var(--nsi4-hairline);
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

/* On a phone the footer is two link columns: brand full width, Products and
   Company side by side, Elsewhere one inline row beneath them, over a base
   row on the tighter spacing pair — the whole block stays inside its 560px
   budget. */
@media (max-width: 899px) {
	.nsi4-footer__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--nsi4-space-6);
	}

	.nsi4-footer__brand,
	.nsi4-footer__col:last-child {
		grid-column: 1 / -1;
	}

	.nsi4-footer__col:last-child .nsi4-footer__list {
		display: flex;
		flex-wrap: wrap;
		gap: var(--nsi4-space-2) var(--nsi4-space-6);
	}

	.nsi4-footer__base {
		margin-top: var(--nsi4-space-6);
		padding-top: var(--nsi4-space-6);
	}
}

@media (min-width: 900px) {
	.nsi4-footer__grid {
		grid-template-columns: 4fr 2fr 2fr 2fr;
	}
}

/* ==========================================================================
   7. Page layout
   The shells the rebuilt pages compose from: the homepage and every page that
   follows it. The values are the signed-off mockups'. Everything the token
   block names is written as the token; the two the mockup fixes as raw values
   — the section head's 720px measure and the hero's 120px desktop padding —
   are written as raw values and do not move with the spacing scale.
   ========================================================================== */
.nsi4-hero {
	display: grid;
	gap: var(--nsi4-space-12);
	padding-block: var(--nsi4-hero-pad-top) var(--nsi4-space-12);
}

.nsi4-hero__copy {
	display: grid;
	gap: var(--nsi4-space-6);
	align-content: start;
}

/* A proof object that is more than one piece — the press kit's logo tile
   with its download and usage line — stacks the pieces on the copy's gap. */
.nsi4-hero__proof {
	display: grid;
	gap: var(--nsi4-space-6);
	align-content: start;
}

.nsi4-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nsi4-space-3);
}

/* The address belongs under its button, left-aligned with it — never beside. */
.nsi4-actions:has(.nsi4-mail) {
	flex-direction: column;
	align-items: flex-start;
	gap: var(--nsi4-space-2);
}

/* Below 420px the hero's buttons stack, and a stack that sizes each button
   to its own label reads ragged: every hero button takes the full content
   width there, so the stack lines up on both edges. */
@media (max-width: 419.98px) {
	.nsi4-hero__copy .nsi4-actions .nsi4-btn {
		width: 100%;
	}
}

/* A rule spans exactly the content column: it is drawn by an inset edge on
   the ruled element rather than by its border, which would run to the padded
   box and hang past the content. The inset is the shell gutter only on the
   element carrying the shell itself — a ruled section inside a shell already
   starts at the content edge. */
.nsi4-case,
.nsi4-rule {
	position: relative;
	border-top: 0;
}

.nsi4-case::before,
.nsi4-rule::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	border-top: 1px solid var(--nsi4-hairline);
}

.nsi4-shell.nsi4-case::before,
.nsi4-shell.nsi4-rule::before {
	left: var(--nsi4-gutter);
	right: var(--nsi4-gutter);
}

/* A ruled band stacks its head, its content grid and any crop on one gap, the
   same one the case-study shell uses. Scoped to .nsi4-rule, which only the
   rebuilt pages carry. */
.nsi4-section.nsi4-rule {
	display: grid;
	gap: var(--nsi4-space-8);
}

.nsi4-section__head {
	display: grid;
	gap: var(--nsi4-space-3);
	max-width: 720px;
}

.nsi4-stats {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-8);
}

.nsi4-products {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-gutter);
}

.nsi4-steps {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-6);
}

.nsi4-steps li {
	display: grid;
	gap: var(--nsi4-space-3);
	padding-top: var(--nsi4-space-4);
	border-top: 1px solid var(--nsi4-control-border);
}

/* The quick links — a row of surface cards, each a title and one line of
   text-2. The card is the link, so the whole card is the target. */
.nsi4-links {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-gutter);
}

.nsi4-link-card {
	display: grid;
	/* The title and the arrow share the first row: the arrow sits in the
	   auto column at the content's right edge, so a long title wraps before
	   it instead of running under it. */
	grid-template-columns: minmax(0, 1fr) auto;
	gap: var(--nsi4-space-2) var(--nsi4-space-4);
	align-content: start;
	padding: var(--nsi4-space-6);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
	color: var(--nsi4-text);
	text-decoration: none;
	transition: background-color var(--nsi4-dur) var(--nsi4-ease), border-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-link-card:hover {
	background: var(--nsi4-raised);
	border-color: var(--nsi4-control-border);
}

.nsi4-link-card__title {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-3);
	line-height: var(--nsi4-lh-heading-3);
	font-weight: var(--nsi4-fw-heading-3);
}

/* The affordance: the arrow at the card's top right, 16px, quiet until the
   card is hovered. */
.nsi4-link-card__arrow {
	grid-column: 2;
	grid-row: 1;
	align-self: start;
	width: 16px;
	height: 16px;
	color: var(--nsi4-text-3);
	transition: color var(--nsi4-dur) var(--nsi4-ease), transform var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-link-card:hover .nsi4-link-card__arrow {
	color: var(--nsi4-text);
}

.nsi4-link-card__body {
	grid-column: 1 / -1;
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

/* The arrow's 2px step runs only where motion is welcome; the reduced-motion
   guard kills every transition, and this keeps the transform away as well. */
@media (prefers-reduced-motion: no-preference) {
	.nsi4-link-card:hover .nsi4-link-card__arrow {
		transform: translateX(2px);
	}
}

/* The FAQ — native disclosure rows. A summary is a control, so it takes the
   44px minimum; its focus ring is the shell's own, drawn on everything inside
   body.nsi4. The chevron is a chevron-right turned on its side: the sprite
   carries no chevron-down. It turns with no transition, because the system's
   motion reach is hover and press, and a disclosure is neither. */
.nsi4-faq {
	display: grid;
	gap: var(--nsi4-space-3);
}

.nsi4-faq__row {
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
}

.nsi4-faq__question {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--nsi4-space-4);
	min-height: var(--nsi4-touch-min);
	padding: var(--nsi4-space-3) var(--nsi4-space-6);
	border-radius: var(--nsi4-radius-lg);
	list-style: none;
	color: var(--nsi4-text);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	font-weight: 600;
	cursor: pointer;
}

.nsi4-faq__question::-webkit-details-marker {
	display: none;
}

.nsi4-faq__question .nsi4-icon {
	color: var(--nsi4-text-2);
	transform: rotate(90deg);
}

.nsi4-faq__row[open] .nsi4-faq__question .nsi4-icon {
	transform: rotate(270deg);
}

.nsi4-faq__answer {
	padding: 0 var(--nsi4-space-6) var(--nsi4-space-6);
	max-width: var(--nsi4-measure);
}

.nsi4-faq__answer p {
	margin: 0;
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	color: var(--nsi4-text-2);
}

/* The closing band carries the section rhythm itself: the page writes it as
   the closing class and the rule, without the plain section class. */
.nsi4-closing {
	display: grid;
	gap: var(--nsi4-space-6);
	align-items: start;
	padding-block: var(--nsi4-section-pad);
}

.nsi4-mail {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data);
	line-height: var(--nsi4-lh-data);
	font-weight: 400;
	color: var(--nsi4-text-2);
}

/* A hero's mail line sits below its action group rather than in it, so the
   copy grid's own gap is pulled back to the 8px the closing bands pair
   button and address on. */
.nsi4-hero__copy > .nsi4-mail {
	margin-top: calc(var(--nsi4-space-2) - var(--nsi4-space-6));
}

@media (min-width: 700px) {
	.nsi4-stats {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--nsi4-gutter);
	}

	/* A two-stat row would leave the third column empty, so it takes two equal
	   columns instead. Keyed off the stat count, the same shape as the two-card
	   links row further down: the last child must also be the second, or a
	   three-stat row would match on its second stat and be laid out two across. */
	.nsi4-stats:has(> .nsi4-stat:nth-child(2):last-child) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 760px) {
	.nsi4-links {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.nsi4-products {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}

	.nsi4-products__wide,
	.nsi4-products__third {
		grid-column: span 3;
	}
}

@media (min-width: 900px) {
	.nsi4-steps {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		/* Three shared rows: each li subgrids them, so the eyebrow, the title
		   and the body hold one top edge across the three columns however many
		   lines a title takes — as separate grids the lis each absorbed their
		   own free space and the three levels drifted apart. The row gap is the
		   li's own 12px step: shared tracks take the parent's gutters. */
		grid-template-rows: repeat(3, auto);
		gap: var(--nsi4-space-3) var(--nsi4-gutter);
	}

	.nsi4-steps li {
		grid-row: span 3;
		grid-template-rows: subgrid;
		gap: var(--nsi4-space-3);
	}
}

/* The closing band stacks: the button sits under the copy, left-aligned with
   the heading, at every width. */

/* A section whose body measures under 240px tall at 1280px takes the compact
   half of the spacing pair. Declared after .nsi4-case and .nsi4-closing set
   their own padding so one rule wins over both; the modifier itself is
   applied per page, section by section. */
.nsi4-section--compact,
.nsi4-case--compact,
.nsi4-closing--compact {
	padding-block: var(--nsi4-section-pad-compact);
}

@media (min-width: 1000px) {
	.nsi4-hero {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		padding-block: var(--nsi4-hero-pad-top) var(--nsi4-space-24);
		align-items: center;
	}

	/* A hero with no crop writes one child; it spans the band rather than
	   sitting in the copy column with an empty track beside it. */
	.nsi4-hero__copy:only-child {
		grid-column: 1 / -1;
	}
}

/* A hero with a proof object reverses the split — the copy takes the wider
   track and the object sits wholly past the page's horizontal centre (at
   1280 the stock 5fr track starts at x=572 against a centre of 640). Both
   items start at the row top, and the object is pushed down the copy's own
   run up to the headline — the eyebrow line, its bottom margin and the copy
   grid's gap — so its top is level with the h1 rather than centred against
   the copy. Below 1000px there is no second track: the object follows the
   copy in the one column the hero still has. */
@media (min-width: 1000px) {
	.nsi4-hero.nsi4-hero--proof {
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		align-items: start;
	}

	.nsi4-hero--proof > :not(.nsi4-hero__copy) {
		margin-top: calc(var(--nsi4-lh-eyebrow) + var(--nsi4-space-4) + var(--nsi4-space-6));
	}
}

@media (min-width: 1100px) {
	.nsi4-products__third {
		grid-column: span 2;
	}
}

/* Product-page blocks. The hero band is the full-bleed strip a product page
   wraps its .nsi4-hero in; the platforms grid and the chat are the two content
   blocks the case sections are built from. */
.nsi4-hero-band {
	position: relative;
}

/* The band is full-bleed but its rule is not: inset from both edges by the
   shell's own offset, so the line starts and ends on the content column at
   every width. */
.nsi4-hero-band::after {
	content: "";
	position: absolute;
	bottom: 0;
	left: max(var(--nsi4-gutter), calc((100% - var(--nsi4-content-max)) / 2 + var(--nsi4-gutter)));
	right: max(var(--nsi4-gutter), calc((100% - var(--nsi4-content-max)) / 2 + var(--nsi4-gutter)));
	border-top: 1px solid var(--nsi4-hairline);
}

/* The band's own rule is the first case section's divider, so the two do not
   draw one above the other. */
.nsi4-hero-band + .nsi4-case::before {
	content: none;
}

/* The Trinity ticker — the page's one orchestrated motion. An ambient strip of
   pair and latency entries that runs across the top of the hero band, above the
   copy rather than under it, and carries no prices. The six items flow as one
   row inside the band's top padding — --nsi4-hero-pad-top, the copy's own top
   edge — so no label can land behind the copy at any width; where the six do
   not fit, the strip clips them at the band's edge. The stagger (durations and
   delays) is the live page's own. Its resting opacity is the texture level, so
   the copy below keeps its contrast with every item at full fade. It paints
   under the copy through the band's own stacking context (`.nsi4-texture`). */
.nsi4-ticker {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: var(--nsi4-hero-pad-top);
	z-index: -1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--nsi4-space-6);
	overflow: hidden;
	pointer-events: none;
	padding-inline: max(var(--nsi4-gutter), calc((100% - var(--nsi4-content-max)) / 2 + var(--nsi4-gutter)));
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	opacity: var(--nsi4-texture-opacity);
	color: var(--nsi4-text-3);
}

.nsi4-ticker__item {
	flex: none;
	white-space: nowrap;
	animation: nsi4-ticker-fade 4s ease-in-out infinite;
}

.nsi4-ticker__item--up {
	color: var(--nsi4-accent);
}

.nsi4-ticker__item:nth-child(2) {
	animation-duration: 5s;
	animation-delay: 1s;
}

.nsi4-ticker__item:nth-child(3) {
	animation-duration: 6s;
	animation-delay: 2s;
}

.nsi4-ticker__item:nth-child(4) {
	animation-duration: 4.5s;
	animation-delay: 1.5s;
}

.nsi4-ticker__item:nth-child(5) {
	animation-duration: 5.5s;
	animation-delay: 0.5s;
}

.nsi4-ticker__item:nth-child(6) {
	animation-duration: 6s;
	animation-delay: 2.5s;
}

@keyframes nsi4-ticker-fade {
	0%,
	100% {
		opacity: 0;
	}

	50% {
		opacity: 1;
	}
}

.nsi4-platforms {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-4);
}

.nsi4-platform {
	display: grid;
	gap: var(--nsi4-space-2);
	/* Cards in a row are equal height; the slack belongs at the card's foot.
	   Spread over the rows instead (the default), a stretched name row pushes
	   the body down and the bodies stop lining up across the row. */
	align-content: start;
	padding: var(--nsi4-space-6);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
}

.nsi4-platform__name {
	margin: 0;
	display: flex;
	/* Top-aligned to the name's first line: a centred icon drifts down a
	   wrapped or stretched name and no longer starts level with the text. */
	align-items: flex-start;
	gap: var(--nsi4-space-2);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	font-weight: 600;
}

.nsi4-platform__name .nsi4-icon {
	color: var(--nsi4-accent);
}

.nsi4-platform__body {
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

/* Definition list — the compact alternative to a row of cards, for a group's
   later parts (WRS's What it does and The assistant, Trinity's three parts).
   Name left, description right, a hairline above every row: no card, no icon.
   The name is the item's own heading (h4 under a group h3, h3 under the
   page's h2), not .nsi4-spec's mono key. The name column is about 12rem;
   below 640px the name sits over its description. */
.nsi4-definitions {
	display: grid;
}

.nsi4-definition {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-1);
	padding-block: var(--nsi4-space-4);
	border-top: 1px solid var(--nsi4-hairline);
}

.nsi4-definition__name {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: 16px;
	line-height: var(--nsi4-lh-small);
	font-weight: 600;
	color: var(--nsi4-text);
}

.nsi4-definition__body {
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

@media (min-width: 640px) {
	.nsi4-definition {
		grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
		gap: var(--nsi4-space-4);
	}
}

/* The people list — the team page's five ruled rows, one per person. The
   name and role sit left, what they work on and their profile links right,
   4/8 from 900px and stacked below it; 24px of padding on the row and a
   hairline between rows. The side is one flex row so no cell is left empty
   when a person has no profile links. */
.nsi4-people {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
}

.nsi4-person {
	display: grid;
	gap: var(--nsi4-space-4);
	align-content: start;
	padding-block: var(--nsi4-space-6);
}

.nsi4-person + .nsi4-person {
	border-top: 1px solid var(--nsi4-hairline);
}

.nsi4-person__id {
	display: grid;
	gap: var(--nsi4-space-3);
	align-content: start;
}

.nsi4-person__side {
	display: grid;
	gap: var(--nsi4-space-3);
	align-content: start;
	justify-items: start;
}

/* The name is the row's heading: 19/28 and 600 sit between the system's
   heading-3 (24/32) and body (17/27) steps, as a raw value. */
.nsi4-person__name {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: 19px;
	line-height: 28px;
	font-weight: 600;
}

.nsi4-person__role {
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

/* The products line beside the 'Works on' label, sharing its baseline. */
.nsi4-person__work {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--nsi4-space-4);
}

.nsi4-person__work .nsi4-eyebrow {
	margin: 0;
}

.nsi4-person__products {
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

/* The profile links at the row's right end. Icon-only, so the accessible
   name is the anchor's aria-label and the glyph carries none. The anchor is
   the target, not the 20px icon, so it takes the touch minimum in both
   directions. */
.nsi4-person__links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nsi4-space-2);
}

.nsi4-person__links a {
	display: grid;
	place-items: center;
	min-width: var(--nsi4-touch-min);
	min-height: var(--nsi4-touch-min);
	border-radius: var(--nsi4-radius-md);
	color: var(--nsi4-text-2);
	font-size: 20px;
	text-decoration: none;
	transition: color var(--nsi4-dur) var(--nsi4-ease), background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-person__links a:hover {
	color: var(--nsi4-text);
	background: var(--nsi4-raised);
}

@media (min-width: 900px) {
	.nsi4-person {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		gap: var(--nsi4-gutter);
		align-items: start;
	}

	.nsi4-person__side {
		display: flex;
		justify-content: space-between;
		gap: var(--nsi4-space-6);
		align-items: start;
	}
}

/* The AI conversation. It is a static transcript: no typing effect, no reveal.
   The column is sized explicitly so the bubbles' 88% cap resolves against the
   panel's own width rather than against an auto track's content. */
.nsi4-chat {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-3);
	padding: var(--nsi4-space-6);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
}

.nsi4-chat__labels {
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--nsi4-space-3);
}

/* Scoped to the chat: a bubble is a <p> inside .nsi4-case__body, so it is a
   body paragraph and takes the measure under its own 88% cap — a transcript
   line may not run wider than any other body line. */
.nsi4-chat .nsi4-bubble {
	max-width: min(88%, var(--nsi4-measure));
	margin: 0;
	padding: var(--nsi4-space-3) var(--nsi4-space-4);
	border-radius: var(--nsi4-radius-lg);
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
}

.nsi4-bubble--you {
	justify-self: end;
	background: var(--nsi4-raised);
	color: var(--nsi4-text);
	border-bottom-right-radius: var(--nsi4-radius-sm);
}

.nsi4-bubble--ai {
	justify-self: start;
	background: var(--nsi4-ground);
	border: 1px solid var(--nsi4-hairline);
	border-bottom-left-radius: var(--nsi4-radius-sm);
}

.nsi4-bubble--ai b {
	color: var(--nsi4-accent);
	font-weight: 600;
}

/* The program breakdown — a label over a list, the two abreast from 900px.
   The partnerships page composes the same block into its columns below. */
.nsi4-lists {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-8);
}

.nsi4-list-block {
	display: grid;
	gap: var(--nsi4-space-3);
	align-content: start;
}

.nsi4-list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--nsi4-space-2);
}

.nsi4-list li {
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

@media (min-width: 900px) {
	.nsi4-lists {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--nsi4-gutter);
	}
}

/* The ruled variant — the fromScratch Codex's six groups as a grid of ruled
   cells, three across from 900px, two from 640px, one below. Only the
   container gains a class: the cells and the lists are the shared
   program-breakdown ones above, which the partnerships columns use too. */
.nsi4-lists--ruled {
	gap: var(--nsi4-space-8) var(--nsi4-gutter);
}

.nsi4-lists--ruled .nsi4-list-block {
	border-top: 1px solid var(--nsi4-hairline);
	padding-top: var(--nsi4-space-4);
}

.nsi4-lists--ruled .nsi4-list li {
	color: var(--nsi4-text);
}

@media (min-width: 640px) {
	.nsi4-lists--ruled {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 900px) {
	.nsi4-lists--ruled {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* The partnerships programs — three columns from 900px, stacked below. Each
   column subgrids four shared rows (name, offer, look-for, action) over the
   parent's explicit grid, so the second list label and the three buttons
   hold one line across the three columns. The gap is written on both grids
   so the shared tracks read the same gutters either way it is resolved. */
.nsi4-programs {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-8);
}

.nsi4-program {
	display: grid;
	gap: var(--nsi4-space-8);
	align-content: start;
}

@media (min-width: 900px) {
	.nsi4-programs {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		grid-template-rows: repeat(4, auto);
		gap: var(--nsi4-space-8) var(--nsi4-gutter);
	}

	.nsi4-program {
		grid-row: span 4;
		grid-template-rows: subgrid;
		gap: var(--nsi4-space-8) var(--nsi4-gutter);
	}
}

/* A platform tile that is a link — the hub's three program tiles. The surface
   step and the hover are .nsi4-product's, which is also an anchor. */
a.nsi4-platform {
	color: var(--nsi4-text);
	text-decoration: none;
	transition: background-color var(--nsi4-dur) var(--nsi4-ease), border-color var(--nsi4-dur) var(--nsi4-ease);
}

a.nsi4-platform:hover {
	background: var(--nsi4-raised);
	border-color: var(--nsi4-control-border);
}

/* The logo preview on the press kit — the artwork at its own size, centred on
   the surface step. */
.nsi4-logo-frame {
	display: grid;
	place-items: center;
	padding: var(--nsi4-space-12);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-lg);
	box-shadow: var(--nsi4-highlight-top);
}

.nsi4-logo-frame img {
	display: block;
}

@media (min-width: 640px) {
	.nsi4-platforms {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* A row of exactly three tiles — the Community hub's partner programs, Team's
   principles. Two columns would leave the third tile orphaned
   under a pair, so a three-tile row skips that step: one column, then three
   equal columns at 900px. Keyed off the tile count, so no page carries a class
   for it. The third tile must also be the last, or a four-tile row would match
   on its third tile and be laid out three across. Every other tile count keeps
   the 640px step above. */
.nsi4-platforms:has(> .nsi4-platform:nth-child(3):last-child) {
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 900px) {
	.nsi4-platforms:has(> .nsi4-platform:nth-child(3):last-child) {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* The article page — the one shell the six posts and papers share. One 4/8
   grid from 900px, the tracks .nsi4-case takes: the rail holds the line and
   the facts about the piece, and the title and the body share the right
   column's left edge. Below 900px it is one column and order runs line,
   title, meta, body. */
.nsi4-article__grid {
	display: grid;
	/* One column that can shrink below its content: an implicit auto track
	   takes the min-content of what is inside it, so an unwrappable item — a
	   wide table cell, a long unbreakable run — would widen the whole page to
	   fit. The track is clamped at zero instead. */
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-6);
	/* The band the header used to be: the hero's top edge over a section's
	   foot, so the body meets the next band on the normal section rhythm. */
	padding-block: var(--nsi4-hero-pad-top) var(--nsi4-section-pad);
}

/* The rail writes no box of its own below 900px: display: contents hands its
   two children to the grid, and order puts the title between them. */
.nsi4-article__rail {
	display: contents;
}

.nsi4-article__rail > nav {
	order: 1;
}

.nsi4-article__head {
	order: 2;
}

.nsi4-article__rail dl {
	order: 3;
}

.nsi4-prose {
	order: 4;
}

/* The one line above the title: the eyebrow's metrics in the casing it is
   written in, because it names a place rather than a section — .nsi4-keep-case
   in the markup says that out loud, so no uppercase is declared here. The hub
   is the only link in it. */
.nsi4-article__line {
	margin: 0;
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	color: var(--nsi4-text-3);
}

.nsi4-article__line a {
	color: var(--nsi4-text-2);
	text-decoration: none;
	transition: color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-article__line a:hover {
	color: var(--nsi4-text);
}

/* The facts about the piece. On a phone they read as one wrapped line with no
   labels, every non-last pair closed by a middot; from 900px they are a
   labelled stack 24px under the line. The dl is flex at both widths because a
   whitespace-only text node between the pairs is not rendered as a flex item,
   and would otherwise open a line box of its own. The 24px leading has no step
   at the 15px small size, so it is a literal. */
.nsi4-article__rail dl {
	display: flex;
	flex-wrap: wrap;
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

.nsi4-article__rail dl > div {
	display: flex;
	flex-direction: column;
	gap: var(--nsi4-space-1);
}

.nsi4-article__rail dt {
	display: none;
}

.nsi4-article__rail dd {
	margin: 0;
}

.nsi4-article__rail dl > div:not(:last-child) dd::after {
	content: "·";
	margin-inline: var(--nsi4-space-2);
}

/* "Nicolas Siatras" over "CEO & Founder" on the rail; ", CEO & Founder"
   beside the name in the phone's one line. */
.nsi4-article__role::before {
	content: ", ";
}

@media (min-width: 900px) {
	.nsi4-article__grid {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		column-gap: var(--nsi4-gutter);
		grid-template-areas:
			"rail head"
			"rail body";
	}

	/* The rail sticks for as long as the article runs: a sticky grid item is
	   held inside its own area, so it stops when the body does. The offset is
	   the one PO-02's case guide already reads. */
	.nsi4-article__rail {
		display: grid;
		gap: var(--nsi4-space-6);
		grid-area: rail;
		position: sticky;
		top: var(--nsi4-sticky-top);
		align-self: start;
	}

	.nsi4-article__head {
		grid-area: head;
	}

	.nsi4-prose {
		grid-area: body;
	}

	.nsi4-article__rail dl {
		flex-direction: column;
		flex-wrap: nowrap;
		gap: var(--nsi4-space-4);
		color: var(--nsi4-text);
	}

	.nsi4-article__rail dt {
		display: block;
		font-family: var(--nsi4-font-mono);
		font-size: var(--nsi4-fs-eyebrow);
		line-height: var(--nsi4-lh-eyebrow);
		font-weight: var(--nsi4-fw-eyebrow);
		letter-spacing: var(--nsi4-ls-eyebrow);
		text-transform: uppercase;
		color: var(--nsi4-text-3);
	}

	.nsi4-article__rail dd {
		color: var(--nsi4-text);
	}

	.nsi4-article__rail dl > div:not(:last-child) dd::after {
		content: none;
	}

	/* "10 min" on the rail; the phone's line reads "10 min read". */
	.nsi4-article__read {
		display: none;
	}

	.nsi4-article__role {
		display: block;
		color: var(--nsi4-text-2);
	}

	.nsi4-article__role::before {
		content: none;
	}
}

/* The featured image is the page's largest element, so it loads eagerly. Only
   the block margins are declared: the figure now sits inside
   .nsi4-article__head in the grid's right-hand column, where it carries no
   shell and the theme's `figure { margin: 0 0 1rem }` has already left the
   inline half at zero. */
.nsi4-article__figure {
	margin-block: 0 var(--nsi4-space-12);
}

.nsi4-article__figure img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--nsi4-radius-lg);
}

/* The generated-art label, in the papers' caption style (.nsi4-figure figcaption)
   so a lead image and a figure caption read the same way. A label, never a sentence. */
.nsi4-article__figure figcaption {
	margin-block-start: var(--nsi4-space-3);
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

/* The article body. The pages write plain HTML — p, h2, h3, ul, ol, dl, table,
   figure, strong, a, code, sup — so the rhythm lives here rather than on every
   element, and the first and last children sit flush inside the shell. */
.nsi4-prose {
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	color: var(--nsi4-text);
	/* The article's body measure. --nsi4-measure (50ch, 510px here) reads 59
	   characters on the second body paragraph of /blog/trinity-philosophy at
	   1280px, under the 62-72 target, so the article sets its own width: at
	   530px the longest first full line across the six bodies is 71
	   characters. A literal with no step, like the section head's 720px. */
	max-width: 530px;
	/* min-width: 0 drops the automatic minimum a grid item would otherwise
	   take from its widest unwrappable line, which is what keeps the measure
	   on a phone instead of pushing the track out to it. */
	min-width: 0;
}

.nsi4-prose > :first-child {
	margin-block-start: 0;
}

.nsi4-prose > :last-child {
	margin-block-end: 0;
}

.nsi4-prose p {
	margin-block: 0 var(--nsi4-space-6);
}

/* The summary, scoped to the article: .nsi4-type-lede on a hub hero keeps its
   own step and colour. 19/29 on a phone and 22/34 from 900px — neither leading
   has a step in the scale, so both are literals — at full text brightness,
   with 40px under it before the first heading. */
.nsi4-prose .nsi4-type-lede {
	font-size: 19px;
	line-height: 29px;
	color: var(--nsi4-text);
	margin-block-end: 40px;
}

@media (min-width: 900px) {
	.nsi4-prose .nsi4-type-lede {
		font-size: 22px;
		line-height: 34px;
	}
}

/* The abstract: the eyebrow, then the summary the prose styles above, then in
   prompt-complexity's case the abstract paragraph itself at body size. 40px of
   clear space under the last paragraph, a hairline, then 40px before the body
   — 40 has no step (the scale runs 32 → 48), so both are literals. The padding
   reset is because the theme's bare `section` rule opens with 40px of its own. */
.nsi4-abstract {
	padding-block: 0 40px;
	margin-block-end: 40px;
	border-bottom: 1px solid var(--nsi4-hairline);
}

.nsi4-abstract > :last-child {
	margin-block-end: 0;
}

.nsi4-abstract > .nsi4-eyebrow {
	margin-block: 0 var(--nsi4-space-2);
}

/* Article headings sit a step under the sheet's: 24/32 is the heading-3 step,
   which keeps an h2 over its own section instead of over the page. The 56px
   above it has no step (the scale runs 48 → 64), so it is a literal. */
.nsi4-prose h2 {
	margin-block: 56px var(--nsi4-space-3);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-3);
	line-height: var(--nsi4-lh-heading-3);
	font-weight: var(--nsi4-fw-heading-3);
	letter-spacing: var(--nsi4-ls-heading-3);
}

/* 19/28 is a step under the heading-3 step and the scale names no token for
   it, so both values are literals. */
.nsi4-prose h3 {
	margin-block: var(--nsi4-space-8) var(--nsi4-space-2);
	font-family: var(--nsi4-font-sans);
	font-size: 19px;
	line-height: 28px;
	font-weight: 600;
	letter-spacing: 0;
}

.nsi4-prose ul,
.nsi4-prose ol {
	margin-block: 0 var(--nsi4-space-6);
	padding-inline-start: var(--nsi4-space-6);
}

.nsi4-prose li {
	margin-block-start: var(--nsi4-space-2);
}

.nsi4-prose li::marker {
	color: var(--nsi4-text-3);
}

.nsi4-prose strong {
	font-weight: 600;
	color: var(--nsi4-text);
}

.nsi4-prose a {
	color: var(--nsi4-accent);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	text-decoration-color: var(--nsi4-control-border);
}

.nsi4-prose a:hover {
	text-decoration-color: var(--nsi4-accent);
}

.nsi4-prose code {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data);
	line-height: var(--nsi4-lh-data);
}

/* Three box looks on one box element. Every box takes 40px clear above and
   below — the clearance target is 40 and the scale jumps 32 → 48, so it is a
   literal like the section head's 720px — and sibling margins collapse, which
   is what makes 40px hold under an h2's 12px and a paragraph's 24px alike.
   The note itself is the surface step with a hairline edge. */
.nsi4-note {
	margin-block: 40px;
	padding: var(--nsi4-space-6);
	background: var(--nsi4-surface);
	border: 1px solid var(--nsi4-hairline);
	border-radius: var(--nsi4-radius-md);
	box-shadow: var(--nsi4-highlight-top);
	/* Notes set their own text step: 16/26, one below the body. */
	font-size: 16px;
	line-height: 26px;
	color: var(--nsi4-text);
}

.nsi4-note > :first-child {
	margin-block-start: 0;
}

.nsi4-note > :last-child {
	margin-block-end: 0;
}

/* A box's title, whether it is written as a paragraph or as the box's own h3:
   the eyebrow's metrics, 8px above its text. The h3 rule is declared after
   .nsi4-prose h3 — equal specificity, so source order decides. */
.nsi4-note__title {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

.nsi4-note h3 {
	margin-block: 0 var(--nsi4-space-2);
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

/* The prose paragraph rhythm is a class plus a type selector, so the title needs
   a class on both sides of it to take the margin. */
.nsi4-note > .nsi4-note__title {
	margin-block: 0 var(--nsi4-space-2);
}

/* A finding is a ruled pull-out: no fill, no frame, a 2px rule down its left
   edge and text set a step above the body. */
.nsi4-note.nsi4-note--finding {
	padding: 4px 0 4px var(--nsi4-space-6);
	background: none;
	border: 0;
	border-left: 2px solid var(--nsi4-text);
	border-radius: 0;
	box-shadow: none;
	font-size: 21px;
	line-height: 32px;
	font-weight: 500;
	color: var(--nsi4-text);
}

/* A call to action is a raised panel and the article's last child: title, text,
   then the link as a button 24px under the text — the paragraph's own bottom
   margin is what opens that gap, and the button is left-aligned as any inline
   box in the flow would be. */
.nsi4-note.nsi4-note--cta {
	padding: var(--nsi4-space-8);
	background: var(--nsi4-raised);
	border-radius: var(--nsi4-radius-lg);
}

/* The prose link's underline and accent are for words inside a sentence; a
   button carries neither. */
.nsi4-note.nsi4-note--cta a.nsi4-btn {
	color: var(--nsi4-text);
	text-decoration: none;
}

/* Two boxes that stack below 768px need the 40px clearance between their
   borders, not the 16px gutter; side by side from 768px, the gutter returns. */
.nsi4-note-pair {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 40px;
	margin-block: 40px;
}

.nsi4-note-pair > .nsi4-note {
	margin-block: 0;
}

@media (min-width: 768px) {
	.nsi4-note-pair {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--nsi4-gutter);
	}
}

/* The unified formula as a display equation: the body's family at the lede's
   step, 32px clear above and below (a token) and indented 24px (a token). It
   wraps between terms — the phone's 343px column holds it with no scrolling
   and no clipping. The variables are italic, the exponent a real <sup>. */
.nsi4-equation {
	margin-block: var(--nsi4-space-8);
	padding-inline-start: var(--nsi4-space-6);
	font-family: var(--nsi4-font-sans);
	font-size: 20px;
	line-height: 32px;
	color: var(--nsi4-text);
	overflow-wrap: break-word;
}

/* Its three terms are unbreakable: the line can only break in the spaces
   between them, so no term splits across lines at either width. The phone's
   343px column holds the widest term on its own, so nothing overflows. */
.nsi4-equation__term {
	white-space: nowrap;
}

/* Figure 1 sits directly under the equation, in two generated geometries. The
   wide one fills the 530px column from 562px up, so its plot spans 69% of the
   figure; below that the compact one is capped at 400px, which is what keeps
   its labels between 11 and 14px at the phone's 343px column — one
   full-width figure would scale 1.55:1 between the two widths and no single
   label size lands inside the band. */
.nsi4-figure {
	margin-block: 0 40px;
}

.nsi4-figure svg {
	display: block;
	width: 400px;
	max-width: 100%;
	height: auto;
}

.nsi4-figure svg.nsi4-figure__wide {
	display: none;
	width: 100%;
}

@media (min-width: 562px) {
	.nsi4-figure svg.nsi4-figure__wide {
		display: block;
	}

	.nsi4-figure svg.nsi4-figure__compact {
		display: none;
	}
}

.nsi4-figure figcaption {
	margin-block-start: var(--nsi4-space-3);
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

/* One table component for the papers' data lists, scoped to the prose — the
   blog posts carry no table. Full column width; header cells on the eyebrow's
   metrics; body cells the small step at a 24px leading (the scale names no
   24 for 15px, so it is a literal); a hairline under every row; 12px of cell
   padding with 16px between columns and none outside the first and last. */
.nsi4-prose .nsi4-table {
	width: 100%;
	margin-block: 0 var(--nsi4-space-6);
	border-collapse: collapse;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text);
}

.nsi4-prose .nsi4-table th {
	padding: var(--nsi4-space-3) var(--nsi4-space-4);
	border-bottom: 1px solid var(--nsi4-hairline);
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	text-align: left;
	color: var(--nsi4-text-3);
	vertical-align: bottom;
}

.nsi4-prose .nsi4-table td {
	padding: var(--nsi4-space-3) var(--nsi4-space-4);
	border-bottom: 1px solid var(--nsi4-hairline);
	vertical-align: top;
}

.nsi4-prose .nsi4-table th:first-child,
.nsi4-prose .nsi4-table td:first-child {
	padding-inline-start: 0;
}

.nsi4-prose .nsi4-table th:last-child,
.nsi4-prose .nsi4-table td:last-child {
	padding-inline-end: 0;
}

/* Numeric columns read right, in mono with tabular figures so the digits
   stack. The header takes only its column's alignment, so it keeps the
   eyebrow's metrics above it. */
.nsi4-prose .nsi4-table td.nsi4-table__num {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data);
	font-variant-numeric: tabular-nums;
	text-align: right;
}

.nsi4-prose .nsi4-table th.nsi4-table__num {
	text-align: right;
}

/* A table that cannot fit scrolls inside its own wrapper rather than moving
   the page. The wrapper is focusable so the scroll region is reachable from
   the keyboard, and overflow-x: auto only ever scrolls when it has to. */
.nsi4-prose .nsi4-table__scroll {
	overflow-x: auto;
}

/* Core Dimensions' heading became its table's caption, in the eyebrow style a
   box title takes. */
.nsi4-prose .nsi4-table caption {
	caption-side: top;
	padding: 0 0 var(--nsi4-space-3);
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	text-align: left;
	color: var(--nsi4-text-3);
}

/* The papers' "Term: description" bullets as definition pairs: the term at
   600 16/24, its definition at the note's 16/26 step with no indent, and 16px
   between pairs — the step the rest of the shell stacks pairs on. */
.nsi4-terms {
	margin-block: 0 var(--nsi4-space-6);
}

.nsi4-terms > div + div {
	margin-block-start: var(--nsi4-space-4);
}

.nsi4-terms dt {
	font-family: var(--nsi4-font-sans);
	font-size: 16px;
	line-height: 24px;
	font-weight: 600;
	color: var(--nsi4-text);
}

.nsi4-terms dd {
	margin: 0;
	font-size: 16px;
	line-height: 26px;
	color: var(--nsi4-text-2);
}

/* Status and Published in a call to action's closing panel: the eyebrow labels
   over their values, stacked on a phone and side by side from 600px. */
.nsi4-note__meta {
	display: grid;
	gap: var(--nsi4-space-3);
	margin-block: var(--nsi4-space-3) var(--nsi4-space-6);
}

.nsi4-note__meta > div {
	display: grid;
	gap: var(--nsi4-space-1);
}

.nsi4-note__meta dt {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	line-height: var(--nsi4-lh-eyebrow);
	font-weight: var(--nsi4-fw-eyebrow);
	letter-spacing: var(--nsi4-ls-eyebrow);
	text-transform: uppercase;
	color: var(--nsi4-text-3);
}

.nsi4-note__meta dd {
	margin: 0;
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text);
}

@media (min-width: 600px) {
	.nsi4-note__meta {
		display: flex;
		gap: var(--nsi4-space-12);
	}
}

/* Two related cards would leave the third column of the links row empty. Keyed
   off the card count, the same shape as the three-tile platform row above. */
@media (min-width: 760px) {
	.nsi4-links:has(> .nsi4-link-card:nth-child(2):last-child) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* The article index — the blog and research hubs' table of contents. One row
   per article, newest first: date, category, title, excerpt, then read time on
   the blog and the status chip on research. Rows are separated by hairlines and
   the row's hover raises it one surface step. The title link carries the row:
   its ::after covers the whole item, so the date and that last line are part of
   the same click target. */
.nsi4-index {
	margin: 0;
	padding: 0;
	list-style: none;
}

.nsi4-index__item {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--nsi4-space-2);
	padding-block: var(--nsi4-space-6);
	border-top: 1px solid var(--nsi4-hairline);
	transition: background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-index__item:hover {
	background: var(--nsi4-raised);
}

/* The row's copy column: eyebrow, title, excerpt, then read time or the status
   chip, on the 8px half-step the rest of the shell stacks on. */
.nsi4-index__item > div {
	display: grid;
	gap: var(--nsi4-space-2);
	align-content: start;
}

.nsi4-index__item > div > .nsi4-eyebrow,
.nsi4-index__meta,
.nsi4-index__status {
	margin: 0;
}

.nsi4-index__date {
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-data);
	line-height: var(--nsi4-lh-data);
	color: var(--nsi4-text-2);
}

.nsi4-index__title {
	margin: 0;
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-heading-3);
	line-height: var(--nsi4-lh-heading-3);
	font-weight: var(--nsi4-fw-heading-3);
	letter-spacing: var(--nsi4-ls-heading-3);
}

.nsi4-index__title a {
	color: var(--nsi4-text);
	text-decoration: none;
}

.nsi4-index__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* The excerpt, the same sentence the article serves as its meta description.
   The 24px leading has no step at the 15px small size, so it is a literal. */
.nsi4-index__summary {
	margin: 0;
	max-width: 64ch;
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

.nsi4-index__meta {
	font-size: var(--nsi4-fs-small);
	line-height: var(--nsi4-lh-small);
	color: var(--nsi4-text-2);
}

/* The date takes a fixed first column from 768px and sits above the title
   below it. */
@media (min-width: 768px) {
	.nsi4-index__item {
		grid-template-columns: 12rem minmax(0, 1fr);
		align-items: start;
		gap: var(--nsi4-gutter);
	}
}

/* 03 and 04 on a phone.
   Both sections carry a guide in the head and a column of blocks in the body,
   and both are far taller at 375px than the same content at 1280px: the head
   stacks above the body instead of beside it, the 72px group rhythm and 40px
   block gap were set for a wide column, and every card, row and note carries
   the padding it has on a desktop. Nothing here changes the content, only the
   space around it, and the whole block is below 640px so the desktop is
   untouched by construction.

   Every selector is scoped by a section modifier rather than by the component,
   because the components are shared: .nsi4-platform also styles fromScratch
   01's three cards, .nsi4-lists the Partnerships page's program breakdown, and
   .nsi4-crop__notes every hero's crop. 03 and 04 both carry
   .nsi4-case--guided, and 04 carries .nsi4-case--evidence as well, so the two
   are not a partition — the rules for the head and the body are written
   against both on purpose, to survive a section that takes only one. The
   component rules below are keyed on .nsi4-case--guided alone because 03 is
   the only one of the two that renders cards, definition rows, a Codex grid or
   a group block; 04 holds a crop, a card and a stat row instead. No page
   outside the five product pages carries either modifier.

   Type never drops below the 15px small step: only the leading tightens, to
   20px, the step the sheet already uses for 13px mono. The sizes with no
   token — the 28px phone h2 and the 6px gaps — are literals, like the 18px
   group heading and the 13px mono above. */
@media (max-width: 639.98px) {
	/* The section takes the compact block padding the short sections already
	   use, and the head sits 24px from the body rather than 32. */
	.nsi4-case--guided,
	.nsi4-case--evidence {
		padding-block: var(--nsi4-section-pad-compact);
		gap: var(--nsi4-space-6);
	}

	/* The guide head: the index 12px under the intro and 6px above the head's
	   other parts, so a two-line intro and a one-row index cost less. The h2
	   keeps the heading-2 size, and the intro keeps the body leading — the two
	   research links in fromScratch's sit on adjacent lines inside that
	   paragraph, and tightening its leading pulls their centres 3px closer for
	   a few pixels of height. The h2 was briefly taken to 28/34 here and
	   reverted: it is a type change rather than one of this block's spacing
	   levers, and WRS 03 clears the target without it. */
	.nsi4-case--guided .nsi4-case__head,
	.nsi4-case--evidence .nsi4-case__head {
		gap: 6px;
	}

	.nsi4-case--guided .nsi4-case__index,
	.nsi4-case--evidence .nsi4-case__index {
		margin-top: var(--nsi4-space-3);
		gap: 6px var(--nsi4-space-3);
	}

	/* The group rhythm is the biggest single lever on a phone: 72px reads as a
	   broken page when three groups stack under a stacked head. 24px, against
	   12px from a group heading to its own content, keeps the two apart. */
	.nsi4-case--guided .nsi4-case__body {
		gap: var(--nsi4-space-6);
	}

	.nsi4-case--evidence .nsi4-case__body {
		gap: var(--nsi4-space-6);
	}

	.nsi4-case--guided .nsi4-case__block,
	.nsi4-case--guided .nsi4-platforms {
		gap: var(--nsi4-space-3);
	}

	/* A tile at 16px padding, 24/20 leading. */
	.nsi4-case--guided .nsi4-platform {
		padding: var(--nsi4-space-4);
		gap: 6px;
	}

	.nsi4-case--guided .nsi4-platform__name {
		line-height: 24px;
	}

	.nsi4-case--guided .nsi4-platform__body {
		line-height: 20px;
	}

	/* A definition row is a ruled line of text, not a card: 8px either side of
	   the name and the description, with the hairline doing the separating. */
	.nsi4-case--guided .nsi4-definition {
		padding-block: var(--nsi4-space-2);
	}

	.nsi4-case--guided .nsi4-definition__name,
	.nsi4-case--guided .nsi4-definition__body {
		line-height: 20px;
	}

	/* The Codex's six groups two across, so they read as three rows of two
	   instead of six rows of one. Each cell is about 160px, which wraps the
	   longer items to two lines — the price of halving the block. */
	.nsi4-case--guided .nsi4-lists--ruled {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--nsi4-space-4) var(--nsi4-space-3);
	}

	.nsi4-case--guided .nsi4-lists--ruled .nsi4-list-block {
		gap: var(--nsi4-space-2);
		padding-top: var(--nsi4-space-3);
	}

	.nsi4-case--guided .nsi4-lists--ruled .nsi4-list {
		gap: var(--nsi4-space-1);
	}

	/* 04: the screen's notes, the component cards and the numbers take the same
	   step down. The trace and the task log keep their full-bleed rows and
	   lose only their row padding. */
	.nsi4-case--evidence .nsi4-crop__notes {
		gap: var(--nsi4-space-2);
	}

	.nsi4-case--evidence .nsi4-chat {
		padding: var(--nsi4-space-4);
		gap: var(--nsi4-space-2);
	}

	.nsi4-case--evidence .nsi4-chat .nsi4-bubble {
		padding: var(--nsi4-space-2) var(--nsi4-space-3);
		line-height: 20px;
	}

	.nsi4-case--evidence .nsi4-change,
	.nsi4-case--evidence .nsi4-cascade {
		padding: var(--nsi4-space-4);
	}

	.nsi4-case--evidence .nsi4-trace .nsi4-evidence-card__head,
	.nsi4-case--evidence .nsi4-tasks .nsi4-evidence-card__head {
		padding: var(--nsi4-space-3) var(--nsi4-space-4);
	}

	.nsi4-case--evidence .nsi4-trace__table th,
	.nsi4-case--evidence .nsi4-trace__table td,
	.nsi4-case--evidence .nsi4-tasks__row,
	.nsi4-case--evidence .nsi4-change__row {
		padding-block: 6px;
	}

	.nsi4-case--evidence .nsi4-trace__foot {
		padding: var(--nsi4-space-3) var(--nsi4-space-4);
	}

	.nsi4-case--evidence .nsi4-cascade__task {
		padding: var(--nsi4-space-3);
	}

	.nsi4-case--evidence .nsi4-stats {
		gap: var(--nsi4-space-4);
	}

	.nsi4-case--evidence .nsi4-stat {
		gap: 6px;
		padding-top: var(--nsi4-space-3);
	}
}

/* The product mark: the artwork itself, one class for the 16px slots that sit
   in a flex row (the Products ledger's rows, the 404's list), plus an inline
   modifier for the nav menu, the footer and the press kit list, where the mark
   runs inside a text line. Replaces the 8px world dot AS-07 removed. Nothing
   here fixes a size: the img's width/height attributes carry the 16px, so the
   same class never fights the 48px hero or 32px card marks, which carry no
   class at all. */
.nsi4-product-mark {
	flex: 0 0 auto;
}

.nsi4-product-mark--inline {
	vertical-align: -3px;
	margin-inline-end: var(--nsi4-space-2);
}

/* The mark beside its status chip: the product hero's badge row (48px mark)
   and the product card's (32px mark), so both centre the pair on one line. */
.nsi4-mark-row {
	display: flex;
	align-items: center;
	gap: var(--nsi4-space-3);
}

/* The Products ledger — one row per product, the home cards' replacement on
   /products. Mobile-first: below 900px a row stacks as a grid — name and badge
   on one line, the job under them, then Since, Proof and Stack as label/value
   pairs, the labels standing in for the header row the stacked form hides;
   from 900px it is a six-column table with an eyebrow header over hairline-
   ruled rows. The whole row is the product link — the name's ::after covers
   it, the way the article index carries its title — and a hover raises the row
   one surface step. */
.nsi4-ledger {
	display: block;
	width: 100%;
	border-collapse: collapse;
	text-align: left;
}

.nsi4-ledger thead {
	display: none;
}

.nsi4-ledger tbody {
	display: block;
}

.nsi4-ledger tr {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--nsi4-space-3);
	padding-block: var(--nsi4-space-6);
	border-top: 1px solid var(--nsi4-hairline);
	transition: background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-ledger tr:hover {
	background: var(--nsi4-raised);
}

.nsi4-ledger td {
	display: block;
	padding: 0;
	border: 0;
}

/* The stacked layout's data cell is the one td that lays itself out: the td
   rule above outranks the bare class, so the pair's grid is declared on the
   compound — without it Since/Proof/Stack read as one run-on string. */
.nsi4-ledger td.nsi4-ledger__data {
	display: grid;
}

/* Name and badge hold the first line; the job and the three label/value pairs
   take the full width under them, in DOM order. */
.nsi4-ledger__product {
	grid-column: 1;
	grid-row: 1;
}

.nsi4-ledger__status {
	grid-column: 2;
	grid-row: 1;
	justify-self: end;
}

.nsi4-ledger__job {
	grid-column: 1 / -1;
	grid-row: 2;
	font-size: var(--nsi4-fs-small);
	/* The 15px small size has no 24px leading step — a literal, the same one
	   the article index's excerpt carries. */
	line-height: 24px;
	color: var(--nsi4-text-2);
}

.nsi4-ledger__data {
	display: grid;
	grid-column: 1 / -1;
	grid-template-columns: minmax(0, 5rem) minmax(0, 1fr);
	gap: var(--nsi4-space-3);
	align-items: baseline;
}

/* 13/20 mono has no step at that size — a literal with a comment, as the mockup's
   trace cells carry; the value keeps the text colour, the label steps down. */
.nsi4-ledger__label,
.nsi4-ledger__value {
	font-family: var(--nsi4-font-mono);
	font-size: 13px;
	line-height: 20px;
}

.nsi4-ledger__label {
	color: var(--nsi4-text-3);
}

.nsi4-ledger__value {
	color: var(--nsi4-text);
}

.nsi4-ledger__product a {
	display: flex;
	align-items: center;
	gap: var(--nsi4-space-2);
	color: var(--nsi4-text);
	text-decoration: none;
}

/* The name's link covers the row: the ::after's containing block is the row,
   which is the nearest positioned box. */
.nsi4-ledger__product a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.nsi4-ledger__name {
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	font-weight: 600;
	color: var(--nsi4-text);
}

@media (min-width: 900px) {
	.nsi4-ledger {
		display: table;
	}

	.nsi4-ledger thead {
		display: table-header-group;
	}

	.nsi4-ledger tbody {
		display: table-row-group;
	}

	.nsi4-ledger tr {
		display: table-row;
		padding-block: 0;
		border-top: 0;
	}

	.nsi4-ledger th {
		display: table-cell;
		padding-block: 0 var(--nsi4-space-3);
		padding-inline: var(--nsi4-space-4);
		border-bottom: 1px solid var(--nsi4-hairline);
		text-align: left;
		vertical-align: bottom;
	}

	.nsi4-ledger td {
		display: table-cell;
		vertical-align: top;
		padding-block: var(--nsi4-space-6);
		padding-inline: var(--nsi4-space-4);
		border-top: 1px solid var(--nsi4-hairline);
	}

	/* The table form takes the data cell back from the stacked grid above. */
	.nsi4-ledger td.nsi4-ledger__data {
		display: table-cell;
	}

	/* The first and last cells sit flush with the content column. */
	.nsi4-ledger th:first-child,
	.nsi4-ledger td:first-child {
		padding-inline-start: 0;
	}

	.nsi4-ledger th:last-child,
	.nsi4-ledger td:last-child {
		padding-inline-end: 0;
	}

	/* The header row carries the labels here; the stacked pairs keep theirs. */
	.nsi4-ledger__label {
		display: none;
	}
}

/* The 404 — a 4/8 split from 900px: the copy on the left, the five products
   on the right; the two stack below it. The min-height puts the footer's top
   edge at or below the viewport bottom: the chrome above main is the 64px bar
   plus its 1px hairline, measured at 65px. Both columns keep their content at
   the top — align-content: start — so the extra height the min-height creates
   is space at the bottom, not inflated gaps in the copy. */
.nsi4-notfound {
	display: grid;
	gap: var(--nsi4-space-8);
	/* 100svh is the smallest viewport height, so the footer clears the bottom
	   even where a phone browser's chrome is showing. */
	min-height: calc(100svh - 65px);
}

.nsi4-notfound__copy,
.nsi4-notfound__list {
	display: grid;
	gap: var(--nsi4-space-6);
	align-content: start;
}

.nsi4-notfound__items {
	margin: 0;
	padding: 0;
	list-style: none;
}

.nsi4-notfound__items li {
	position: relative;
	padding-block: var(--nsi4-space-6);
	border-top: 1px solid var(--nsi4-hairline);
	transition: background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-notfound__items li:hover {
	background: var(--nsi4-raised);
}

.nsi4-notfound__items a {
	display: grid;
	gap: var(--nsi4-space-2);
	color: var(--nsi4-text);
	text-decoration: none;
}

/* The row's link covers the row: the ::after's containing block is the list
   item, the nearest positioned box. */
.nsi4-notfound__items a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* The name line and the claim read as the ledger's product cell does: 17px 600
   in Sans over the claim at the small size's 24px leading (a literal there too). */
.nsi4-notfound__name {
	display: flex;
	align-items: center;
	gap: var(--nsi4-space-2);
	font-family: var(--nsi4-font-sans);
	font-size: var(--nsi4-fs-body);
	line-height: var(--nsi4-lh-body);
	font-weight: 600;
	color: var(--nsi4-text);
}

.nsi4-notfound__claim {
	font-size: var(--nsi4-fs-small);
	line-height: 24px;
	color: var(--nsi4-text-2);
}

@media (min-width: 900px) {
	.nsi4-notfound {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		gap: var(--nsi4-gutter);
	}
}

/* ==========================================================================
   8. Legacy class names
   Kept so every existing page keeps its hooks. Where a legacy class carried
   the brand gradient, it now renders in the signed-off language: the gradient
   appears only on the logo and the primary button.
   ========================================================================== */
.nsi4-product-title {
	color: var(--nsi4-accent);
}

.nsi4-border {
	border-color: var(--nsi4-hairline);
}

.nsi4-action-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: var(--nsi4-touch-min);
	background: linear-gradient(90deg, var(--nsi4-cta-start), var(--nsi4-cta-end));
	color: var(--nsi4-on-cta);
	border: none;
	border-radius: var(--nsi4-radius-md);
	transition: filter var(--nsi4-dur) var(--nsi4-ease), transform var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-action-button:hover {
	filter: brightness(1.12);
	background: linear-gradient(90deg, var(--nsi4-cta-start), var(--nsi4-cta-end));
	color: var(--nsi4-on-cta);
}

.nsi4-action-button:active {
	transform: translateY(1px);
}

.nsi4-secondary-action-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: var(--nsi4-touch-min);
	background: transparent;
	color: var(--nsi4-text);
	border: 1px solid var(--nsi4-control-border);
	border-radius: var(--nsi4-radius-md);
	transition: border-color var(--nsi4-dur) var(--nsi4-ease), background-color var(--nsi4-dur) var(--nsi4-ease);
}

.nsi4-secondary-action-button:hover {
	background: var(--nsi4-raised);
	color: var(--nsi4-text);
	border-color: var(--nsi4-text);
}

.nsi4-color-A,
.nsi4-color-B,
.nsi4-color-C {
	color: var(--nsi4-accent);
	border-color: var(--nsi4-accent);
}

.nsi4-bg-gradient {
	background: var(--nsi4-raised);
}

.nsi4-text-gradient {
	color: var(--nsi4-accent);
}

/* ==========================================================================
   9. Icons
   One system: Lucide, drawn from wwwroot/assets/img/icons/lucide-sprite.svg.
   Size follows font-size, so the existing sizing utilities keep working.
   ========================================================================== */
/* :where() keeps this at zero specificity, so the sizing and colour
   utilities already on the swapped markup keep winning. font-size is 1em —
   the parent's size, as the FontAwesome spans this replaced were — so each
   icon keeps the size its surrounding type gives it. */
:where(.nsi4-icon) {
	display: inline-block;
	width: 1em;
	height: 1em;
	font-size: 1em;
	flex: none;
	vertical-align: -0.125em;
	fill: none;
	stroke-width: 1.5;
	color: inherit;
}

/* In a control an icon is its own size, not the control's type size. */
:where(.nsi4-btn) :where(.nsi4-icon),
:where(.nsi4-action-button) :where(.nsi4-icon),
:where(.nsi4-secondary-action-button) :where(.nsi4-icon) {
	font-size: 20px;
}

:where(.nsi4-icon--content) {
	font-size: 24px;
}

/* ==========================================================================
   10. Phoenix override layer
   Each block names the theme.min.css selector it beats. Phoenix components
   land on token values; nothing here edits theme.min.css itself.
   ========================================================================== */
:root,
[data-bs-theme=dark] {
	/* theme.min.css :root --phoenix-font-sans-serif — the stack the whole
	   theme reads, including body via --phoenix-body-font-family */
	--phoenix-font-sans-serif: var(--nsi4-font-sans);
	/* theme.min.css :root --phoenix-font-monospace */
	--phoenix-font-monospace: var(--nsi4-font-mono);
	/* theme.min.css :root --phoenix-body-font-family, which is what body reads */
	--phoenix-body-font-family: var(--nsi4-font-sans);
	--phoenix-body-font-size: var(--nsi4-fs-body);
	--phoenix-body-font-weight: var(--nsi4-fw-body);
	--phoenix-body-line-height: 1.588;
	/* theme.min.css [data-bs-theme=dark] --phoenix-body-color / --phoenix-body-bg */
	--phoenix-body-color: var(--nsi4-text);
	--phoenix-body-color-rgb: 237, 239, 243;
	--phoenix-body-bg: var(--nsi4-ground);
	--phoenix-body-bg-rgb: 10, 13, 20;
	--phoenix-emphasis-color: var(--nsi4-text);
	--phoenix-emphasis-color-rgb: 237, 239, 243;
	--phoenix-heading-color: var(--nsi4-text);
	--phoenix-secondary-color: var(--nsi4-text-2);
	--phoenix-secondary-color-rgb: 160, 166, 179;
	--phoenix-tertiary-color: var(--nsi4-text-3);
	--phoenix-tertiary-color-rgb: 131, 138, 152;
	/* theme.min.css [data-bs-theme=dark] --phoenix-border-color */
	--phoenix-border-color: var(--nsi4-hairline);
	--phoenix-border-color-rgb: 255, 255, 255;
	--phoenix-border-color-translucent: var(--nsi4-hairline);
	/* theme.min.css :root --phoenix-border-radius* ; the pill token is
	   redefined because the system has no pills */
	--phoenix-border-radius: var(--nsi4-radius-md);
	--phoenix-border-radius-sm: var(--nsi4-radius-sm);
	--phoenix-border-radius-lg: var(--nsi4-radius-lg);
	--phoenix-border-radius-xl: var(--nsi4-radius-lg);
	--phoenix-border-radius-xxl: var(--nsi4-radius-lg);
	--phoenix-border-radius-2xl: var(--nsi4-radius-lg);
	--phoenix-border-radius-pill: var(--nsi4-radius-md);
	/* theme.min.css :root --phoenix-focus-ring* */
	--phoenix-focus-ring-width: 2px;
	--phoenix-focus-ring-opacity: 1;
	--phoenix-focus-ring-color: var(--nsi4-focus);
	/* theme.min.css :root --phoenix-box-shadow* ; the system's only shadow */
	--phoenix-box-shadow: var(--nsi4-highlight-top);
	--phoenix-box-shadow-sm: var(--nsi4-highlight-top);
	--phoenix-box-shadow-lg: var(--nsi4-highlight-top);
	--phoenix-box-shadow-inset: none;
}

/* These follow the page's world, so they sit on the wrapper rather than on
   :root, where the accent would freeze at its corporate value.
   theme.min.css [data-bs-theme=dark] --phoenix-link-color / -hover-color */
.nsi4 {
	--phoenix-link-color: var(--nsi4-accent);
	--phoenix-link-hover-color: var(--nsi4-text);
	--phoenix-link-decoration: underline;
	--phoenix-link-hover-decoration: underline;
}

/* theme.min.css .bg-body-emphasis — a surface, not a second ground */
.nsi4 .bg-body-emphasis {
	background-color: var(--nsi4-surface) !important;
}

/* theme.min.css .card */
.nsi4 .card {
	--phoenix-card-bg: var(--nsi4-surface);
	--phoenix-card-border-color: var(--nsi4-hairline);
	--phoenix-card-box-shadow: var(--nsi4-highlight-top);
	color: var(--nsi4-text);
}

/* theme.min.css .dropdown-menu / .modal-content / .offcanvas — the raised step */
.nsi4 .dropdown-menu,
.nsi4 .modal-content,
.nsi4 .offcanvas {
	--phoenix-dropdown-bg: var(--nsi4-raised);
	--phoenix-dropdown-border-color: var(--nsi4-hairline);
	--phoenix-modal-bg: var(--nsi4-raised);
	--phoenix-modal-border-color: var(--nsi4-hairline);
	--phoenix-offcanvas-bg: var(--nsi4-raised);
	border-color: var(--nsi4-hairline);
}

/* theme.min.css .badge — the system's badge shape, on the Phoenix variants */
.nsi4 .badge {
	border-radius: var(--nsi4-radius-sm);
	font-family: var(--nsi4-font-mono);
	font-size: var(--nsi4-fs-eyebrow);
	letter-spacing: 0.06em;
}

/* theme.min.css .btn, .form-control, .form-select */
.nsi4 .btn,
.nsi4 .form-control,
.nsi4 .form-select {
	border-radius: var(--nsi4-radius-md);
}

.nsi4 .form-control,
.nsi4 .form-select {
	background-color: var(--nsi4-surface);
	border-color: var(--nsi4-control-border);
	color: var(--nsi4-text);
}

/* theme.min.css .navbar — the nav is chrome, not content */
.nsi4 .navbar .nav-link {
	color: var(--nsi4-text-2);
}

.nsi4 .navbar .nav-link:hover,
.nsi4 .navbar .nav-link[aria-current] {
	color: var(--nsi4-text);
}

/* ==========================================================================
   11. Motion guard
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
	.nsi4 *,
	.nsi4 *::before,
	.nsi4 *::after {
		transition: none !important;
		animation: none !important;
	}
}

/* ==========================================================================
   12. View transitions

   Chromium crossfades one page into the next on a same-origin navigation
   instead of cutting. Opted in only where the reader has not asked for
   reduced motion: with no @view-transition at-rule in force the navigation
   is a plain cut, which is how every other browser behaves anyway.

   The nav carries its own name, so it is captured as its own snapshot and
   holds still while the rest of the page crossfades. The fade runs on the
   system's duration and easing, so a navigation moves at the same speed as
   a hover, and adds no keyframes beyond the default crossfade.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
	@view-transition {
		navigation: auto;
	}

	.nsi4-nav {
		view-transition-name: nsi4-nav;
	}

	::view-transition-old(root),
	::view-transition-new(root) {
		animation-duration: var(--nsi4-dur);
		animation-timing-function: var(--nsi4-ease);
	}
}
