/*
 * The design's own base stylesheet (_design-source/_ds/.../styles.css)
 * opens with `*{box-sizing:border-box}`. WordPress core ships no such
 * reset, so every padded flex child (skill-card, proof-card, work-card)
 * was computing its `flex-basis` percentage against its content box only,
 * then adding padding and border on top — silently inflating it past the
 * intended share of the row and breaking the 2-/3-column grids below into
 * a single column. Porting the design's own reset, not inventing one.
 */
* {
	box-sizing: border-box;
}

/* A wave sits flush against the section above it. Core's blockGap would open
   a gap here, and it opens a *different* gap in the canvas than on the front
   end, so this rule carries an element and beats both. */
.wp-site-blocks .nr-section + div.nr-wave,
.editor-styles-wrapper .nr-section + div.nr-wave {
	margin-block-start: 0;
}

/*
 * Every top-level template block (the header part's wrapper group, the
 * post-title wrapper on page.html/nr-elsewhere.html/nr-say-hi.html,
 * post-content, the footer part's wrapper group) is a full-bleed colour
 * block by design — never a gap the root's own off-white
 * `styles.color.background` (theme.json) can show through. Core's default
 * root blockGap would otherwise open exactly that gap between them; every
 * *within*-section rhythm is its own pattern's explicit padding, never
 * this default, so zeroing it here is safe.
 */
.editor-styles-wrapper > * + *,
.wp-site-blocks > * + *,
.editor-styles-wrapper > .wp-site-blocks > * + * {
	margin-block-start: 0;
}

/*
 * Each template wraps its title and post-content in a `<main>` group
 * (`.nr-main`) so the page has a main landmark and core's skip link has a
 * target. That group is a flow layout, and core's flow rule
 * (`:root :where(.is-layout-flow) > * + *`, 0,1,0) would open the root
 * blockGap between its full-bleed children — the stripe the rule above
 * closes for the root. The element in this selector out-ranks it in both
 * contexts.
 */
.wp-site-blocks main.nr-main > * + *,
.editor-styles-wrapper main.nr-main > * + * {
	margin-block-start: 0;
}

/*
 * The rule above only zeroes the *root's* children's own margin — it does
 * nothing for a margin that collapses THROUGH one of those children from
 * further down the tree, which is a distinct bug with the same visual
 * symptom (a full-width off-white stripe under the `<h1>` on
 * page.html/nr-elsewhere.html/nr-say-hi.html, confirmed by forcing
 * `overflow:hidden` on `.wp-block-post-content` in a throwaway test and
 * watching the gap close). The actual chain: core's own
 * `.is-layout-constrained > *` rule (not `> * + *` — it targets every
 * child, including the first) gives elsewhere-intro.php/say-hi.php's
 * opening paragraph a margin-top; neither that paragraph's `.nr-section`
 * parent nor that section's own `.wp-block-post-content` parent has any
 * top padding/border, so the margin collapses straight through both,
 * shifting post-content's whole rendered box down — even though
 * `getComputedStyle()` on post-content and the section both still (and
 * correctly) report their OWN margin-top as 0, since a collapsed-through
 * margin is never attributed to the ancestor whose box it moves.
 * Cutting the chain at its source — the first child of any `.nr-section`
 * never gets a top margin — fixes it for every page in one rule, and
 * naturally covers hero.php's own first child too (already 0 via core's
 * heading-margin reset, so this is a no-op there, not a second fix).
 */
.editor-styles-wrapper .nr-section > *:first-child,
.wp-site-blocks .nr-section > *:first-child {
	margin-block-start: 0;
}

/*
 * Round 4, Finding 3 (second instance): the same hairline, between the
 * post-title wrapper (nr-elsewhere.html/nr-say-hi.html — both ink, same
 * colour as the ink section that follows in post-content) and
 * post-content itself. Same sub-pixel cause, same fix.
 */
.nr-title-wrap {
	margin-bottom: -1px;
}

.nr-wave {
	line-height: 0;
	/*
	 * Round 4, Finding 3: a hairline of the root's own background showing
	 * at the wave's bottom edge, against the section that follows — the
	 * box model itself measures flush (the wave's bottom and the next
	 * section's top land on the exact same fractional pixel,
	 * `getBoundingClientRect()` confirmed live), so this is sub-pixel
	 * rounding, not a real gap: `--section-pad-y`'s `clamp(...,10vw,...)`
	 * resolves to a non-integer value at most viewport widths, and two
	 * independently-flowed boxes that both land on that same fractional
	 * boundary can still round to *different* device pixels. A 1px
	 * overlap is invisible here on purpose — the wave's own fill at that
	 * edge is already the next section's exact background colour.
	 */
	margin-bottom: -1px;
}

.nr-wave > svg {
	display: block;
	width: 100%;
	height: 140px;
}

/*
 * The two SectionHeading text colours vendored components draw on a
 * coloured section: `--text-on-teal`/`--text-on-lime` (tokens.css —
 * Task 13 fix round 1, Finding 2). Deliberately a single-class selector
 * with no `!important`: `.has-text-color.has-{slug}-color` (the picker's
 * own output) is generated with `!important` — confirmed by reading the
 * editor canvas's own inline global-styles — so a plain rule here always
 * loses to an explicit colour choice made from the Styles panel, exactly
 * as it should: the owner's own pick on that heading always wins.
 */
.nr-heading-on-teal {
	color: var(--text-on-teal);
}

.nr-heading-on-lime {
	color: var(--text-on-lime);
}

/*
 * `core/site-title` wraps its text in an `<a>` (parts/footer.html links the
 * wordmark home). The root `styles.elements.link` colour (theme.json)
 * targets bare `<a>` elements directly, which beats the block's own
 * `has-off-white-color` class on the *ancestor* `<p>` — an explicit rule on
 * the element itself always wins over an inherited value, regardless of
 * the rule's (near-zero, `:where()`-wrapped) specificity. The design draws
 * this wordmark off-white, never rose.
 */
.wp-block-site-title a {
	color: inherit;
	text-decoration: none;
}

/*
 * `core/post-title` (page.html/nr-elsewhere.html/nr-say-hi.html) keeps its
 * own default bottom margin even inside a `padding-bottom:0` ink wrapper
 * group. With no padding/border on that edge, the heading's margin
 * collapses straight through the group and reopens the exact off-white
 * gap Root Cause 2 closed everywhere else — this is the one place it is a
 * child margin, not the group's own, so `margin-block-start:0` above
 * (which only ever touches root-level siblings) does not reach it.
 */
.wp-block-post-title {
	margin: 0;
}

/*
 * `core/site-logo {"width":48}` (parts/header.html) never takes effect on
 * the uploaded SVG monogram. Root cause: `SeedCommand::sideload()` skips
 * `wp_generate_attachment_metadata()` for `image/svg+xml` (core has no SVG
 * dimension reader), so the attachment has no stored width/height.
 * `render_block_core_site_logo()`'s own width-scaling filter requires both
 * (`wp_get_attachment_image_src`'s `$image[1]`/`$image[2]`) to compute a
 * proportional height — with neither, it no-ops, and `get_custom_logo()`
 * emits a bare `<img>` with no width/height/style at all, so the browser
 * renders the SVG at its own intrinsic size (~513×448, the monogram's own
 * viewBox — roughly 600px tall on screen). A plain rule here, not an
 * `!important` clamp: it has ordinary specificity and simply supplies the
 * dimension the server-rendered markup is missing. Loaded in both contexts
 * (inc/assets.php's shared_files()), so the editor canvas matches.
 */
.wp-block-site-logo img {
	display: block;
	width: 48px;
	height: auto;
}

/*
 * NavHeader.dc.html's nav row, read properly this time (round 3, Findings
 * 1-3) — `_design-source/NavHeader.dc.html` is a separate vendored
 * component the build had never actually read.
 *
 * Finding 2: the link row is `display:flex;gap:32px`, and each link is
 * `font-family:var(--font-body);font-weight:500;font-size:1.05rem`.
 * `core/navigation` renders its own top-level list as
 * `.wp-block-navigation.is-layout-flex` directly (no separate container
 * div at this level), and nothing here ever set its `gap` or the link
 * typography — confirmed live: the rendered gap was 8px (a core default),
 * the font 16px/400 (the browser's own link default), not this file's
 * intended 32px/1.05rem/500.
 *
 * Finding 3 (round 3) put the border-bottom on `.nr-site-nav` itself —
 * still wrong (round 4, Finding 1): `.nr-site-nav` (the group inside
 * `parts/header.html`) sits inside the auto-generated
 * `<header class="wp-block-template-part">` wrapper `core/template-part`
 * emits, which is itself a *non-full* child of the genuinely full-bleed
 * ink group each template already wraps the header in — so `.nr-site-
 * nav`'s own `align:full` had nothing to escape *into*: measured live at
 * x:120, width:1200 on a 1440px viewport, not edge to edge. That outer
 * ink group is where each template already carried a `border-bottom`
 * *colour* (rose, or lime on nr-elsewhere.html) with no width — pre-
 * existing, never wired up, so invisible — every template above now adds
 * the missing `width:1px` there instead, and colour + width both render
 * inline (no CSS class needed, no page-template body-class rule either).
 */
.nr-site-nav .wp-block-navigation {
	gap: 32px;
}

.nr-site-nav .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--body);
	font-weight: 500;
	font-size: 1.05rem;
	opacity: 0.6;
	transition: opacity var(--duration-standard) var(--ease-standard);
}

.nr-site-nav .wp-block-navigation-item__content:hover,
.nr-site-nav .wp-block-navigation-item__content:focus-visible,
.nr-site-nav .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content {
	opacity: 1;
}

/*
 * The mobile overlay (core/navigation's responsive container) is ours, not
 * the design's: the artboard draws no mobile menu. Its colours are the
 * block's own overlay controls in parts/header.html (ink background,
 * off-white text) — never CSS here. At 60% opacity the non-current links
 * measure 6.4:1 on ink; the current page also carries an underline, so it
 * is not told apart by lightness alone.
 */
.nr-site-nav .wp-block-navigation__responsive-container.is-menu-open .current-menu-item > .wp-block-navigation-item__content {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 6px;
}

/*
 * The design declares ZERO breakpoints (docs/design-digest.md §
 * Breakpoints) — this is an inferred value, recorded there, not a
 * vendored one: the 140px wave shrinks so its crest never overwhelms a
 * narrow viewport.
 */

@media (max-width: 560px) {

	.nr-wave > svg {
		height: 80px;
	}
}

/*
 * Button rows (say-hi.php, lets-connect.php) are `gap:16px` in the design.
 * Each row is a `.nr-button-row` flex group holding the page's own
 * `core/buttons` and the "Download CV" synced pattern's, so the same 16px
 * applies between the two groups as within each.
 * theme.json sets no blockGap, so core falls back to its zero-specificity
 * `:where(.is-layout-flex){gap:0.5em}` — 8px. Any class beats `:where()`,
 * in the canvas and on the front end alike.
 */
.wp-block-buttons,
.nr-button-row {
	gap: 16px;
}

/*
 * Sticky footer. Every page here is a stack of full-bleed colour sections,
 * so a page shorter than the viewport — Say Hi once the form is sent and
 * replaced by its thank-you — ended with the root's own off-white showing
 * under the ink footer. The chain matters: the flex grow has to reach the
 * *section*, or the grown space belongs to a transparent ancestor and the
 * same stripe appears one level up.
 */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
	min-height: 100dvh;
}

.wp-site-blocks > main.nr-main {
	display: flex;
	flex: 1 0 auto;
	flex-direction: column;
}

.wp-site-blocks main.nr-main > .wp-block-post-content {
	display: flex;
	flex: 1 0 auto;
	flex-direction: column;
}

.wp-site-blocks main.nr-main > .wp-block-post-content > .nr-section:last-child {
	flex: 1 0 auto;
}

/*
 * Sticky header (owner direction, 2026-09-23). The class sits on the ink
 * wrapper group each template puts the header part in, not on the part
 * itself: the wrapper is the full-bleed colour band and the rose rule, so
 * sticking it keeps both. `.wp-site-blocks` is a flex column, and a sticky
 * flex child still sticks to the scrollport; the z-index only has to beat
 * the sections, since dialogs render in the browser's top layer.
 */
.nr-header-wrap {
	position: sticky;
	top: 0;
	z-index: 20;
}
