/* ==========================================================================
   BLITZ Campaign — base
   Tokens come from theme.json as --wp--preset--* / --wp--custom--*.
   Never hardcode a colour or a font size here.
   ========================================================================== */

/* --- Short aliases. Convenience only; every value traces to theme.json. ---- */
:root {
	--ink:        var(--wp--preset--color--ink);
	--ink-raised: var(--wp--preset--color--ink-raised);
	--ink-line:   var(--wp--preset--color--ink-line);
	--paper:      var(--wp--preset--color--paper);
	--paper-dim:  var(--wp--preset--color--paper-dim);
	--paper-warm: var(--wp--preset--color--paper-warm);
	--card:       var(--wp--preset--color--card);
	--ink-soft:   var(--wp--preset--color--ink-soft);
	--accent:     var(--wp--preset--color--accent);
	--accent-deep:var(--wp--preset--color--accent-deep);
	--accent-wash:var(--wp--custom--accent-wash);
	--accent-hover: var(--wp--custom--accent-hover);

	--ff-display: var(--wp--preset--font-family--display);
	--ff-ui:      var(--wp--preset--font-family--ui);
	--ff-mono:    var(--wp--preset--font-family--mono);

	--gutter:      var(--wp--custom--gutter);
	--gutter-wide: var(--wp--custom--gutter-wide);
	--container:var(--wp--custom--container);
	--read:     var(--wp--custom--read);
	--radius:   var(--wp--custom--radius);
	--measure:  var(--wp--custom--measure);

	--ease:   var(--wp--custom--motion--ease);
	--t-fast: var(--wp--custom--motion--fast);
	--t-base: var(--wp--custom--motion--base);
	--t-slow: var(--wp--custom--motion--slow);
	--t-reveal: var(--wp--custom--motion--reveal);

	--tr-eyebrow: var(--wp--custom--tracking--eyebrow);

	--header-h:      var(--wp--custom--header--height);
	--header-h-cond: var(--wp--custom--header--height-condensed);

	color-scheme: dark;
}

/* --- Reset-ish -------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
	margin: 0;
	background-color: var(--ink);
	color: var(--paper);
	font-family: var(--ff-ui);
	font-synthesis-weight: none;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	/*
	 * `clip`, not `hidden`. `overflow-x: hidden` makes the body a scroll
	 * container, and a scroll container between a sticky element and the viewport
	 * is one of the two ways position:sticky silently stops working. `clip`
	 * prevents the same horizontal overflow without creating one.
	 */
	overflow-x: clip;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Tabular figures wherever a number must not reflow. */
.blitz-tnum, .blitz-metric__value { font-variant-numeric: tabular-nums; }

/* --- Focus. Visible, always, on both surfaces. ------------------------ */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 3px;
	border-radius: var(--radius);
}
.blitz-section--light :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline-color: var(--ink);
}

/* --- Skip link -------------------------------------------------------- */
.blitz-skip-link {
	position: absolute;
	left: var(--gutter);
	top: -100px;
	z-index: 1000;
	padding: 0.75rem 1.25rem;
	background: var(--accent);
	color: var(--ink);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--body-s);
	text-decoration: none;
	transition: top var(--t-fast) var(--ease);
}
.blitz-skip-link:focus { top: 0.75rem; }

/* --- Screen-reader-only ---------------------------------------------- */
.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden; clip-path: inset(50%);
	white-space: nowrap; border: 0;
}

/* --- Layout ----------------------------------------------------------- */
.blitz-container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}
.blitz-read { max-width: var(--read); margin-inline: auto; }

/* Section surfaces. The rhythm/padding rules live in the editorial layout
   system at the end of this file. */
.blitz-section--light :is(h1,h2,h3,h4,h5,h6) { color: var(--ink); }
.blitz-section--light a { color: var(--accent-deep); }
.blitz-section--raised { background: var(--ink-raised); }

/* Body copy measure. */
.blitz-prose p, .blitz-prose li { max-width: var(--measure); }

/* --- Typography helpers ---------------------------------------------- */
.blitz-eyebrow {
	font-family: var(--ff-ui);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: var(--tr-eyebrow);
	color: var(--paper-dim);
	margin: 0 0 var(--wp--preset--spacing--s);
}
/*
 * --warm belongs on this line too, same as it already is for the eyebrow's
 * own ::before/::after further down (see .blitz-section--light/--warm
 * .blitz-eyebrow--numbered rules below) and for headings in
 * .blitz-section--warm :is(h1..h6). Missing it here left the eyebrow at its
 * dark-surface default (--paper-dim, a light grey) on a warm paper
 * background — verified live on the homepage ("Where to start", "Working
 * together": text/background contrast ratio ~1.3, effectively invisible).
 */
.blitz-section--light .blitz-eyebrow,
.blitz-section--warm .blitz-eyebrow,
.blitz-inner-section--light .blitz-eyebrow,
.blitz-inner-section--warm .blitz-eyebrow,
.blitz-reading-shell .blitz-eyebrow,
.blitz-collection-card .blitz-eyebrow,
.blitz-collection-foundation .blitz-eyebrow,
.blitz-contact-card .blitz-eyebrow { color: var(--accent-deep); }

.blitz-display {
	font-family: var(--ff-display);
	font-weight: 700;
	font-stretch: 112%;
	line-height: 0.98;
	letter-spacing: var(--wp--custom--tracking--display);
	margin: 0;
}

.blitz-lead {
	font-size: var(--wp--preset--font-size--body-l);
	line-height: 1.5;
	color: var(--paper-dim);
	max-width: var(--measure);
}
.blitz-section--light .blitz-lead { color: var(--ink); opacity: 0.75; }

/* --- Buttons ---------------------------------------------------------- */
/* Buttons.
   Generous on desktop, still 48px minimum on touch. The label carries the
   weight; there is no shadow, no gradient and no rounding beyond a 2px radius
   — the accent fill is loud enough on its own. */
.blitz-btn {
	--_bg: var(--accent);
	--_fg: var(--ink);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	padding: 0.9rem 1.6rem;
	min-height: 48px;
	background: var(--_bg);
	color: var(--_fg);
	border: 1px solid var(--_bg);
	border-radius: var(--radius);
	font-family: var(--ff-ui);
	font-size: var(--wp--preset--font-size--body-s);
	font-weight: 600;
	letter-spacing: 0;
	text-decoration: none;
	cursor: pointer;
	transition: background var(--t-fast) var(--ease),
	            border-color var(--t-fast) var(--ease),
	            letter-spacing var(--t-fast) var(--ease),
	            color var(--t-fast) var(--ease);
}
.blitz-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); letter-spacing: 0.01em; }

/* Tighter, for the header — where a full-size CTA shouts over the navigation.
   44px, not less: it is still a tap target on a 64px mobile header. */
.blitz-btn--sm { padding: 0.65rem 1.1rem; min-height: 44px; }

/* Larger, for the hero and the closing prompt. */
.blitz-btn--lg { padding: 1.05rem 2rem; font-size: var(--wp--preset--font-size--body); }

.blitz-btn--ghost {
	--_bg: transparent;
	--_fg: var(--paper);
	border-color: var(--paper);
}
.blitz-btn--ghost:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); letter-spacing: 0.01em; }

/* Ghost buttons on a light surface invert: the border and label become ink. */
.blitz-section--light .blitz-btn--ghost,
.blitz-section--warm  .blitz-btn--ghost { --_fg: var(--ink); border-color: rgba(5, 7, 8, 0.35); }
.blitz-section--light .blitz-btn--ghost:hover,
.blitz-section--warm  .blitz-btn--ghost:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* --- Body links ------------------------------------------------------- */
.blitz-prose a,
.blitz-link {
	color: inherit;
	text-decoration: none;
	background-image: linear-gradient(currentColor, currentColor);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 180ms var(--ease), color var(--t-fast) var(--ease);
	padding-bottom: 1px;
}
.blitz-prose a { color: var(--accent); background-size: 100% 1px; }
.blitz-section--light .blitz-prose a { color: var(--accent-deep); }
.blitz-link:hover, .blitz-link:focus-visible { background-size: 100% 1px; color: var(--accent); }
.blitz-section--light .blitz-link:hover { color: var(--accent-deep); }

/* --- Rules ------------------------------------------------------------ */
.blitz-rule { height: 1px; background: var(--ink-line); border: 0; margin: 0; }
.blitz-section--light .blitz-rule { background: rgba(5, 7, 8, 0.14); }

/* --- Entrance motion --------------------------------------------------
   Three options, chosen once for the whole site under Appearance → Brand
   settings → Entrance motion, and applied as a class on <body>:

     blitz-motion-none  content is simply there
     blitz-motion-fade  opacity only
     blitz-motion-rise  a short fade and a 14px lift (default)

   One global choice rather than a control on every block. Three sections
   animating differently on one page is noise, and a per-block setting is a
   per-block opportunity to get it wrong.

   Two guards matter more than the effect itself:

     .no-js   — if app.js never runs, nothing ever gets .is-revealed. Without
                this rule every revealed element would sit at opacity 0 for
                ever, and the page would be blank. The animation is the
                enhancement; the content is not.

     reduced  — prefers-reduced-motion is handled once, globally, in the block
                below. No component has to remember it.
   ----------------------------------------------------------------------- */
.blitz-motion-rise [data-blitz-reveal],
.blitz-motion-fade [data-blitz-reveal] {
	opacity: 0;
	transition: opacity var(--t-reveal) var(--ease), transform var(--t-reveal) var(--ease);
	will-change: opacity, transform;
}
.blitz-motion-rise [data-blitz-reveal] { transform: translateY(14px); }
[data-blitz-reveal].is-revealed { opacity: 1; transform: none; }

/* Staggered children. 80ms steps, inside the 90ms ceiling — beyond that the
   last card in a row arrives noticeably after the visitor has read the first. */
.blitz-motion-rise [data-blitz-reveal-stagger] > *,
.blitz-motion-fade [data-blitz-reveal-stagger] > * {
	opacity: 0;
	transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.blitz-motion-rise [data-blitz-reveal-stagger] > * { transform: translateY(12px); }
[data-blitz-reveal-stagger].is-revealed > * { opacity: 1; transform: none; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(1) { transition-delay: 0ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(2) { transition-delay: 80ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(3) { transition-delay: 160ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(4) { transition-delay: 240ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(5) { transition-delay: 320ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(6) { transition-delay: 400ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(7) { transition-delay: 480ms; }
[data-blitz-reveal-stagger].is-revealed > *:nth-child(8) { transition-delay: 560ms; }

/* JavaScript unavailable: show everything, immediately, always. */
.no-js [data-blitz-reveal],
.no-js [data-blitz-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }

/* ==========================================================================
   THE GLOBAL REDUCED-MOTION GUARD
   PROJECT-PLAN.md §8.3 — implemented once, globally, so no component can
   forget it. Anything animated anywhere is covered by this block.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		transition-delay: 0ms !important;
		scroll-behavior: auto !important;
	}
	[data-blitz-reveal],
	[data-blitz-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   EDITORIAL LAYOUT SYSTEM
   Added in Phase 3. The Phase 2 build stacked every component in a single
   centred column, which is why it read as a component demo rather than a page.
   The fix is not more decoration — it is a grid with deliberate asymmetry, a
   section rhythm with more than one density, and section headers that occupy
   two columns instead of one.
   ========================================================================== */

/* --- The 12-column grid ------------------------------------------------ */
.blitz-grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--m);
}

/* Every child spans the full width by default.
   Without this, a child carrying only a desktop span class (.blitz-col-8) gets
   grid's default of one column at mobile — so three stacked sections end up
   side by side in three narrow strips, overlapping and unreadable. Mobile-first
   means the base case is the full width, and the spans are the exception. */
.blitz-grid > * { grid-column: 1 / -1; }
@media (min-width: 768px)  { .blitz-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: var(--wp--preset--spacing--l); } }
@media (min-width: 1024px) { .blitz-grid { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--wp--preset--spacing--l) var(--wp--preset--spacing--l); } }

/* Column spans. Mobile is always full width — asymmetry at 375px is just
   cramped, not editorial. */
@media (min-width: 1024px) {
	.blitz-col-3  { grid-column: span 3; }
	.blitz-col-4  { grid-column: span 4; }
	.blitz-col-5  { grid-column: span 5; }
	.blitz-col-6  { grid-column: span 6; }
	.blitz-col-7  { grid-column: span 7; }
	.blitz-col-8  { grid-column: span 8; }
	.blitz-col-9  { grid-column: span 9; }
	.blitz-col-12 { grid-column: span 12; }
	.blitz-start-2  { grid-column-start: 2; }
	.blitz-start-4  { grid-column-start: 4; }
	.blitz-start-6  { grid-column-start: 6; }
	.blitz-start-7  { grid-column-start: 7; }
	.blitz-start-8  { grid-column-start: 8; }
}
@media (min-width: 768px) and (max-width: 1023px) {
	.blitz-col-3, .blitz-col-4 { grid-column: span 4; }
	.blitz-col-5, .blitz-col-6, .blitz-col-7, .blitz-col-8, .blitz-col-9, .blitz-col-12 { grid-column: span 8; }
}

/* --- Section rhythm ----------------------------------------------------
   Three densities, used on purpose. A page where every section has identical
   padding reads as a list; varying it is most of what makes a page feel paced. */
.blitz-section          { padding-block: var(--wp--preset--spacing--section); }
.blitz-section--tight   { padding-block: var(--wp--preset--spacing--section-tight); }
.blitz-section--loose   { padding-block: var(--wp--preset--spacing--section-loose); }
.blitz-section--flush-top    { padding-top: 0; }
.blitz-section--flush-bottom { padding-bottom: 0; }

.blitz-section--light { background: var(--paper); color: var(--ink); }
.blitz-section--warm  { background: var(--paper-warm); color: var(--ink); }
.blitz-section--warm :is(h1,h2,h3,h4,h5,h6) { color: var(--ink); }
.blitz-section--soft  { background: var(--ink-soft); }

/* A hairline where two dark sections meet, so the rhythm is legible without
   changing background. Cheaper than alternating colour on every section. */
.blitz-section--ruled { border-top: 1px solid var(--ink-line); }

/* --- Editorial section header ------------------------------------------
   Eyebrow + heading on the left, lead paragraph offset right. This one pattern
   does more for "designed rather than stacked" than any amount of decoration. */
.blitz-sechead {
	display: grid;
	gap: var(--wp--preset--spacing--m);
	margin-bottom: var(--wp--preset--spacing--2xl);
}
@media (min-width: 1024px) {
	.blitz-sechead {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--l);
		align-items: end;
	}
	.blitz-sechead__main { grid-column: 1 / span 6; }
	.blitz-sechead__aside { grid-column: 8 / span 5; padding-bottom: 0.35rem; }
	.blitz-sechead--wide .blitz-sechead__main { grid-column: 1 / span 7; }
	.blitz-sechead--wide .blitz-sechead__aside { grid-column: 9 / span 4; }
}
.blitz-sechead__title {
	font-family: var(--ff-display);
	font-weight: 700;
	font-stretch: 106%;
	font-size: var(--wp--preset--font-size--display-m);
	line-height: 1;
	letter-spacing: var(--wp--custom--tracking--display);
	margin: 0;
	text-wrap: balance;
}
.blitz-sechead__aside p { margin: 0; }

/* --- Numbered eyebrow --------------------------------------------------- */
.blitz-eyebrow--numbered {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}
.blitz-eyebrow--numbered::before {
	content: attr(data-num);
	color: var(--accent);
	font-variant-numeric: tabular-nums;
}
.blitz-eyebrow--numbered::after {
	content: "";
	flex: 1 1 auto;
	max-width: 88px;
	height: 1px;
	background: var(--ink-line);
}
.blitz-section--light .blitz-eyebrow--numbered::before,
.blitz-section--warm .blitz-eyebrow--numbered::before,
.blitz-inner-section--light .blitz-eyebrow--numbered::before,
.blitz-inner-section--warm .blitz-eyebrow--numbered::before,
.blitz-collection-card .blitz-eyebrow--numbered::before,
.blitz-collection-foundation .blitz-eyebrow--numbered::before { color: var(--accent-deep); }
.blitz-section--light .blitz-eyebrow--numbered::after,
.blitz-section--warm .blitz-eyebrow--numbered::after,
.blitz-inner-section--light .blitz-eyebrow--numbered::after,
.blitz-inner-section--warm .blitz-eyebrow--numbered::after,
.blitz-collection-card .blitz-eyebrow--numbered::after,
.blitz-collection-foundation .blitz-eyebrow--numbered::after { background: rgba(5, 7, 8, 0.16); }

/* --- Button group ------------------------------------------------------- */
.blitz-actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--s);
	margin-top: var(--wp--preset--spacing--l);
}
/* Phones: the primary goes full width, the secondary stays inline beneath it.
   Two identical full-width buttons give equal weight to unequal choices —
   which is how a secondary action ends up taking half the clicks. */
@media (max-width: 599px) {
	.blitz-actions { flex-direction: column; align-items: flex-start; gap: var(--wp--preset--spacing--xs); }
	.blitz-actions > *:first-child .blitz-btn { width: 100%; }
	.blitz-actions .blitz-btn--ghost { width: auto; padding-inline: 0; border-color: transparent; min-height: 44px; }
	.blitz-actions .blitz-btn--ghost:hover,
	.blitz-actions .blitz-btn--ghost:focus-visible { background: none; color: var(--accent); }
	.blitz-section--light .blitz-actions .blitz-btn--ghost:hover { color: var(--accent-deep); }
	.blitz-actions .blitz-btn--ghost::after { content: " →"; }
}

/* --- The editorial marker ----------------------------------------------
   Applied by editors from the toolbar ("Editorial marker"), which wraps the
   selection in <mark class="blitz-marker">. This rule is what makes it look
   like anything, so the treatment can be changed in one place and moved to a
   different word without touching CSS.

   A browser's default <mark> is a solid yellow background box. That is
   overridden here rather than tolerated: the brand mark is a thin underline in
   the lock-up's yellow, and it is the only place that yellow appears in the
   interface. Green is reserved for things a visitor can act on. */
mark,
.blitz-marker {
	background: none;
	color: inherit;
	box-shadow: inset 0 -0.16em 0 var(--wp--preset--color--marker);
}
/* On a light surface the same stroke needs slightly more weight to read. */
.blitz-section--light mark,
.blitz-section--warm mark { box-shadow: inset 0 -0.18em 0 var(--wp--preset--color--marker); }

/* --- Text helpers ------------------------------------------------------- */
.blitz-balance { text-wrap: balance; }
.blitz-pretty  { text-wrap: pretty; }

/* ==========================================================================
   WORDPRESS LAYOUT NEUTRALISER — defensive, not a bug fix

   Every pattern section is a core/group, so WordPress adds `is-layout-flow`
   and with it a `margin-block-start` on subsequent children. Measured on the
   live site, that margin currently computes to 0 inside these containers, so
   nothing is broken today — the theme's stylesheets happen to load after
   core's.

   "Happen to" is the problem. Stylesheet order is not something a theme
   controls: a plugin, a caching layer that concatenates CSS, or a core change
   can flip it, and the failure would be silent extra spacing inside every grid.

   These containers own their spacing through `gap`. This states that outright
   instead of relying on load order.
   ========================================================================== */
.blitz-grid > *,
.blitz-sechead > *,
.blitz-actions > *,
.blitz-solve__grid > *,
.blitz-how__grid > *,
.blitz-feature__grid > *,
.blitz-contact__grid > *,
.blitz-academy__grid > *,
.blitz-testi__grid > *,
.blitz-triangle-section__grid > *,
.blitz-diag-section__grid > *,
.blitz-think > *,
.blitz-think__col > *,
.blitz-map__inner > *,
.blitz-logos > *,
.blitz-main > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/*
 * Plain class selectors, deliberately — NOT :where().
 *
 * Core's rule is `:where(.is-layout-flow) > *`, which has zero specificity, so
 * a :where() neutraliser here would tie with it and the winner would be decided
 * by stylesheet order. On this site the theme happens to load after core, but
 * that ordering is not something a theme controls — a plugin, a caching layer
 * or a core change could flip it. A real class selector wins on specificity and
 * stops depending on luck.
 */
