/**
 * Global Styles — NISA Investment Advisors
 *
 * Site-wide styles that extend theme.json.
 * No hardcoded hex values — use var(--wp--preset--color--).
 * No hardcoded font stacks — use var(--wp--preset--font-family--).
 */

/* -----------------------------------------------
   Spacing system — sections own their spacing (blockGap-first)

   Nested content spacing comes from theme.json blockGap (settings + per-group
   overrides), NOT a global margin-rhythm. This replaces the previous
   `.wp-block-heading + *` margin system (removed 2026-07-21 to match the WULR
   architecture) which required zeroing blockGap and fighting it with !important.
   ----------------------------------------------- */

/* Prevent 100vw alignfull blocks from causing a horizontal scrollbar */
body {
	overflow-x: hidden;
	/* Grayscale antialiasing so light-weight IvyPresto headings render as thin
	   as they do in Figma. Without this, macOS/Chrome subpixel smoothing makes
	   type look heavier and darker than the design. */
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* WP renders the root blockGap as margin-block-start on each top-level block.
   Zero it in all three contexts (front end, editor canvas, post-content) so
   full-width sections sit flush and each owns its breathing room via its
   `section` padding + per-section blockGap. Content NESTED inside a section
   still gets blockGap rhythm (WP's is-layout-flow rule is left intact). */
.wp-site-blocks > *,
.editor-styles-wrapper > .is-root-container > *,
.entry-content > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* Header & footer are chrome — they own their internal spacing via header.css /
   footer.css, NOT the content blockGap. Neutralize the blockGap WP applies to
   flow/constrained/flex/grid layouts inside template parts. This rule loads after
   WP's global styles (so it wins the leaked gap) but before header.css/footer.css
   (so their explicit gaps still win). Without it, the non-zero content blockGap
   leaks vertical gaps above/below the header and footer. */
.wp-block-template-part :where(.is-layout-flow) > *,
.wp-block-template-part :where(.is-layout-constrained) > * {
	/* Only margin-block-START — that's all WP's blockGap sets. Leaving margin-block-end
	   alone preserves intentional negative bottom margins in chrome (e.g. the footer
	   subscribe image's -2rem bleed). */
	margin-block-start: 0;
}
.wp-block-template-part :where(.is-layout-flex),
.wp-block-template-part :where(.is-layout-grid) {
	gap: 0;
}

/* Prose opt-in — restore block-gap rhythm for long-form content. Section-based
   pages (homepage, landing pages) own their spacing and are excluded (body has
   `page`, not `single`); posts and CPT singles get flowing rhythm. When a
   text-heavy PAGE template is built, add its body class here. */
.single .entry-content > * + * {
	margin-block-start: var(--wp--style--block-gap);
	margin-block-end: 0;
}

/* -----------------------------------------------
   Lenis smooth scroll (required base CSS)
   ----------------------------------------------- */

/* Lenis adds these classes to <html>. `lenis-stopped { overflow: hidden }` is what
   makes lenis.stop() actually lock the page while an overlay is open. */
html.lenis,
html.lenis body {
	height: auto;
}

.lenis.lenis-smooth {
	scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
	overscroll-behavior: contain;
}

.lenis.lenis-stopped {
	overflow: hidden;
}

.lenis.lenis-scrolling iframe {
	pointer-events: none;
}

/* -----------------------------------------------
   Button Tokens
   ----------------------------------------------- */

:root {
	/* Spacing tokens — vertical rhythm */
	--nisa-space-xs: clamp(0.4rem, 0.8vw, 0.8rem);
	--nisa-space-sm: clamp(0.8rem, 1.6vw, 1.2rem);
	--nisa-space-md: clamp(1.2rem, 2.4vw, 2rem);
	--nisa-space-lg: clamp(2.4rem, 4.8vw, 4rem);

	/* Button tokens */
	--nisa-btn-radius: 0.25rem;
	--nisa-btn-padding: 1rem 2rem;
	--nisa-btn-font-size: var(--wp--preset--font-size--sm);
	--nisa-btn-font-weight: 500;
	--nisa-btn-line-height: 1;
	--nisa-btn-letter-spacing: 0.75px;
	--nisa-btn-transition: 0.25s ease;

	/* Shadow tokens */
	--nisa-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
	--nisa-shadow-md: 0 4px 24px rgba(0, 0, 0, 0.08);
	--nisa-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12);
}

/* -----------------------------------------------
   Button Base
   ----------------------------------------------- */

.nisa-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: var(--nisa-btn-padding);
	border-radius: var(--nisa-btn-radius);
	font-family: var(--wp--preset--font-family--primary);
	font-size: var(--nisa-btn-font-size);
	font-weight: var(--nisa-btn-font-weight);
	line-height: var(--nisa-btn-line-height);
	letter-spacing: var(--nisa-btn-letter-spacing);
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--nisa-btn-transition), color var(--nisa-btn-transition), opacity var(--nisa-btn-transition);
}

.nisa-btn:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	/* Two-tone ring (WCAG 2.4.7 / 1.4.11): a white halo fills the 2px offset gap
	   inside the accent outline. On light backgrounds it disappears (white on
	   white) and the ring looks as before; on navy the accent alone was 1.58:1,
	   the white halo is ~13:1. Same idea as .nisa-video-band__pause-btn. */
	box-shadow: 0 0 0 4px var(--wp--preset--color--secondary);
}

.nisa-btn--outline {
	border: 1px solid rgba(10, 10, 10, 0.2);
	background: none;
	color: var(--wp--preset--color--primary);
}

.nisa-btn--outline:hover {
	background-color: var(--wp--preset--color--muted);
}

.nisa-btn--filled {
	border: 1px solid var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--secondary);
}

.nisa-btn--filled:hover {
	background-color: color-mix(in srgb, var(--wp--preset--color--primary) 85%, black);
	border-color: color-mix(in srgb, var(--wp--preset--color--primary) 85%, black);
}

/* -----------------------------------------------
   Core Button — Hover & Focus States
   (Base styles in theme.json: styles.elements.button
   + styles.blocks.core/button.variations.outline)
   ----------------------------------------------- */

.wp-block-button .wp-block-button__link {
	transition: background-color 0.25s ease, opacity 0.25s ease, border-color 0.25s ease;
}

/* Filled (dark buttons): darken the background on hover — never opacity.
   Opacity is background-dependent and lowers both text/background and
   button/page contrast; darkening a dark button only ever RAISES the contrast
   of its light text. Tool buttons (light bg, dark text) are excluded here and
   lightened below; pills carry their own !important hover (→ primary). The
   outline Pill + Play fills accent on hover instead (custom.css). */
.wp-block-button:not(.is-style-outline):not(.is-style-nisa-pill-play):not(.is-style-nisa-tool-listen):not(.is-style-nisa-tool-download) .wp-block-button__link:hover {
	background-color: color-mix(in srgb, var(--wp--preset--color--primary) 85%, black);
	border-color: color-mix(in srgb, var(--wp--preset--color--primary) 85%, black);
}

/* Tool buttons (light bg, dark text): lighten on hover so the navy text's
   contrast only ever increases. */
.wp-block-button:is(.is-style-nisa-tool-listen, .is-style-nisa-tool-download) .wp-block-button__link:hover {
	background-color: color-mix(in srgb, var(--wp--preset--color--light-blue) 60%, white);
}

/* Outline: tint background on hover */
.wp-block-button.is-style-outline .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--muted);
	border-color: rgba(10, 10, 10, 0.35);
}

/* Focus ring for keyboard navigation */
.wp-block-button .wp-block-button__link:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	/* Two-tone ring (WCAG 2.4.7 / 1.4.11): a white halo fills the 2px offset gap
	   inside the accent outline. On light backgrounds it disappears (white on
	   white) and the ring looks as before; on navy the accent alone was 1.58:1,
	   the white halo is ~13:1. Same idea as .nisa-video-band__pause-btn. */
	box-shadow: 0 0 0 4px var(--wp--preset--color--secondary);
}

@media (prefers-reduced-motion: reduce) {
	.wp-block-button .wp-block-button__link {
		transition: none;
	}
}

/* -----------------------------------------------
   Pause/Play Button
   ----------------------------------------------- */

/* Shared pause/play toggle for any animated component.
   Uses CSS custom properties so each context can set colors.
   Default: light background (dark icon on subtle tint). */

.nisa-pause-btn {
	--_pause-bg: rgba(0, 0, 0, 0.5);
	--_pause-bg-hover: rgba(0, 0, 0, 0.7);
	--_pause-color: var(--wp--preset--color--secondary);

	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: none;
	border-radius: 0.5rem;
	background: var(--_pause-bg);
	color: var(--_pause-color);
	cursor: pointer;
	transition: background-color 0.25s ease;
}

.nisa-pause-btn:hover {
	background: var(--_pause-bg-hover);
}

.nisa-pause-btn:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	/* Two-tone ring — see .wp-block-button__link:focus-visible above. */
	box-shadow: 0 0 0 4px var(--wp--preset--color--secondary);
}

.nisa-pause-btn svg {
	width: 1rem;
	height: 1rem;
	fill: currentColor;
}

/* Light-background variant — subtle tint with muted icon */
.nisa-pause-btn--light {
	--_pause-bg: rgba(10, 10, 10, 0.06);
	--_pause-bg-hover: rgba(10, 10, 10, 0.12);
	--_pause-color: rgba(10, 10, 10, 0.4);
}

.nisa-pause-btn--light:hover {
	color: rgba(10, 10, 10, 0.6);
}

@media (prefers-reduced-motion: reduce) {
	.nisa-pause-btn {
		transition: none;
	}
}

/* -----------------------------------------------
   Carousel Nav Buttons (Shared)
   ----------------------------------------------- */

/* Shared prev/next control for any scroll-based carousel.
   Uses CSS custom properties so each context can set colors.
   Chromeless: the arrow art IS the control — no border, no disc. The arrows
   inherit --_carousel-color through `stroke: currentColor`, which is what the
   hover swap below recolors. */

.nisa-carousel-btn {
	/* Enabled arrows use the accent navy (~8:1 on the cream section); the
	   disabled state swaps to the comp's grey below. The colour is applied to
	   the SVG stroke (see below), NOT `color` — Gravity Forms' global
	   [type="button"] reset (pulled in site-wide by the subscribe form) hijacks
	   `color`, but never touches the stroke. */
	--_carousel-color: var(--wp--preset--color--accent);

	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	min-width: 44px;
	min-height: 44px;
	padding: 0;
	border: none;
	background: transparent;
	cursor: pointer;
}

.nisa-carousel-btn:hover {
	--_carousel-color: var(--wp--preset--color--primary);
}

.nisa-carousel-btn:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	/* Two-tone ring — see .wp-block-button__link:focus-visible above. */
	box-shadow: 0 0 0 4px var(--wp--preset--color--secondary);
}

.nisa-carousel-btn:disabled {
	--_carousel-color: #969696; /* lint-allow: exact disabled-arrow grey from the comp, no palette token matches */
	pointer-events: none;
}

/* NISA arrow art (16x15 viewBox), sized up for visibility + a comfortable
   target. Its <line>s carry no stroke, so they inherit this var-driven stroke. */
/* The visible arrow is smaller than the 44px button — the button keeps the full
   accessible target (WCAG 2.5.5) while the icon reads at a comfortable size.
   No `transition` on the stroke: the colour is driven by a var() and a
   transition on a var-fed property freezes at the old value across state
   changes (enabled↔disabled), so the recolour is instant. */
.nisa-carousel-btn svg {
	width: 20px;
	height: 19px;
	fill: none;
	stroke: var(--_carousel-color);
	stroke-width: 1.25;
}

/* Prev points left — the art is a right arrow, so flip it. */
.nisa-carousel-btn--prev svg {
	transform: rotate(180deg);
}

/* Dark-background variant — white arrows. */
.nisa-carousel-btn--dark {
	--_carousel-color: var(--wp--preset--color--secondary);
}

/* -----------------------------------------------
   Eyebrow / Label
   ----------------------------------------------- */

.nisa-eyebrow {
	font-family: var(--wp--preset--font-family--inter);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 500;
	color: var(--wp--preset--color--accent);
	text-transform: uppercase;
	letter-spacing: 0.08em;
	line-height: 1.2;
}

/* -----------------------------------------------
   Shared utilities
   ----------------------------------------------- */

/* Flush-left for max-width text (editor-max-width.js "Flush left" toggle).
   Defeats WP constrained-layout's `margin-inline: auto !important` auto-center
   on children narrower than contentSize (FOOTGUNS.md #1). Inline margins ONLY
   (hard-constraints margin exception #2); margin-block stays with blockGap.

   The start margin is NOT 0 — it re-adds the content-column offset so the
   element flushes to the CONTENT column's left edge, not the section padding
   edge. `margin-inline-start: 0` broke out ~half-the-gutter left in a
   full-width constrained section (the content column is centred with empty
   side margins); it only looked right in nested/narrow containers where the
   offset computes to 0. `max(0px, …)` keeps those nested cases at 0.
   Class doubled on purpose (0,2,0) so it beats WP's auto-center `:where()`
   rule outright — a single class ties on specificity and the last-loaded wins,
   which rendered flush on the front end but centred in the editor. Matches the
   Kogent/WashU fix. (Content-size fix, 2026-08-18.) */
.atomic-flush-left.atomic-flush-left {
	margin-inline-start: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-inline-end: auto !important;
}

/* rotated writing-mode elements need physical props — core sets those on them */
.atomic-flush-left--physical.atomic-flush-left--physical {
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

/* -----------------------------------------------
   Screen Reader Utilities
   ----------------------------------------------- */

.screen-reader-text {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: #fff;
	clip: auto !important;
	clip-path: none;
	color: #000;
	display: block;
	font-size: 1rem;
	height: auto;
	left: 5px;
	line-height: normal;
	padding: 15px 23px 14px;
	text-decoration: none;
	top: 5px;
	width: auto;
	z-index: 100000;
}

/* -----------------------------------------------
   Cover — Site Padding pass-through
   ----------------------------------------------- */

/* WP core cancels has-global-padding on the cover's inner container.
   When the editor toggle adds has-global-padding to the cover itself,
   route the padding to the inner container so the background stays
   full-bleed while content respects site margins. */
.wp-block-cover.has-global-padding {
	padding-left: 0;
	padding-right: 0;
}

.wp-block-cover.has-global-padding > .wp-block-cover__inner-container {
	padding-right: var(--wp--style--root--padding-right);
	padding-left: var(--wp--style--root--padding-left);
}

/* -----------------------------------------------
   Shared utilities
   ----------------------------------------------- */

/* Restore heading color inheritance for raw HTML inside core/html blocks
   (hard-constraints.md → text color inheritance). Apply .atomic-html-inherit
   to a core/html wrapper whose <h1>–<h6> should take the parent block's
   textColor instead of the global heading color. */
.atomic-html-inherit h1,
.atomic-html-inherit h2,
.atomic-html-inherit h3,
.atomic-html-inherit h4,
.atomic-html-inherit h5,
.atomic-html-inherit h6 {
	color: inherit;
}

/* -----------------------------------------------
   Scroll reveal — pre-paint start state
   ----------------------------------------------- */

/* custom.js reveals content in groups (a card, a heading+copy+button cluster)
   as they scroll in. It is a FOOTER script, so when it also owned the hidden
   start state the browser painted the content first and then blanked it — the
   flash this rule removes. Everything the reveal can touch therefore starts
   hidden HERE, before first paint.

   custom.js drops this whole blanket by adding .nisa-reveal-ready to <html> in
   the same synchronous block that puts real start states on the units, so no
   paint happens in between. Anything the blanket hid that is NOT a unit (text
   inside a card, the self-animating carousels) becomes visible at that moment —
   which is why the selector list can be broad without needing to match the
   resolver exactly.

   Guards: html.js (no-JS visitors never hide anything) and no-preference
   (custom.js returns early under reduced motion, so it must not hide either).
   An inline <head> timer (functions.php → atomic_js_class_script) adds
   .nisa-reveal-ready after 4s as a failsafe, so a JS error cannot strand the
   page blank. Scoped to main so site chrome always paints immediately. */
@media (prefers-reduced-motion: no-preference) {
	html.js:not(.nisa-reveal-ready) main :is(
		.wp-block-heading,
		.wp-block-paragraph,
		.wp-block-list,
		.wp-block-buttons,
		.wp-block-image,
		.wp-block-quote,
		.nisa-section-label,
		.wp-block-post,
		.wp-block-post-title,
		.wp-block-post-excerpt,
		.wp-block-post-date,
		.wp-block-post-featured-image,
		.wp-block-post-terms,
		.wp-block-read-more,
		[class*="card"]
	):not(.nisa-dir *) {
		/* .nisa-dir (Team page People Directory) is excluded from the reveal in
		   custom.js, so it must not start hidden either. */
		opacity: 0;
	}
}

/* Approach icon draw-on — pre-paint start state.
   The "Our Distinguished Approach" pillar icons draw their strokes on when the
   pillar scrolls in (custom.js). Hide the icon pre-paint like the reveal
   blanket so the line never flashes fully drawn: custom.js measures each path
   and sets the dash start state before dropping .nisa-reveal-ready, in the same
   synchronous frame. Same html.js + no-preference guards as the blanket, so
   no-JS and reduced-motion visitors see the icons drawn and static. */
@media (prefers-reduced-motion: no-preference) {
	html.js:not(.nisa-reveal-ready) main .nisa-approach__icon svg {
		opacity: 0;
	}
}

/* Hero line art draw-on — pre-paint start state.
   Same contract as the approach icons above: custom.js measures the strokes and
   sets the dash start state before dropping .nisa-reveal-ready, so the art never
   paints fully drawn and then blank. This one is above the fold, so it draws on
   load rather than on scroll. Same html.js + no-preference guards, so no-JS and
   reduced-motion visitors get the finished art, static. */
@media (prefers-reduced-motion: no-preference) {
	html.js:not(.nisa-reveal-ready) main .nisa-hero-art svg {
		opacity: 0;
	}
}
