/*
Theme Name: NewPad
Theme URI: https://www.newpadbuildingco.com
Author: John Vance
Description: Custom block theme for NewPad Building Company. The design lives in theme.json —
             colors, typography and spacing are defined once and used everywhere.
Version: 1.31.0
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 8.1
Text Domain: newpad
*/

/* Block themes style themselves through theme.json. This file exists because WordPress
   requires it for theme metadata. Put only genuine exceptions here — anything that belongs
   to the design system belongs in theme.json instead, where the Site Editor can reach it.

   What qualifies as an exception: a class theme.json has no way to name. theme.json styles
   elements, blocks and block variations; it cannot say `.newpad-section__heading`, so the
   sitewide patterns in this file live here. Every value in them is still read from theme.json
   as a custom property, so a colour or a size changed there moves them too.

   ⚠ TICKET 31 (the restyle, 2026-10-06) added most of what is below: the sticky header and its
   phone pill, the page header band, the centred section head, the bands, the card and testimonial
   block styles, the trust chips, the hero and the home page's two-column grid. Every radius is
   `--wp--custom--radius--*` and every shadow `--wp--preset--shadow--*` from theme.json, so the
   cards in inventory.css and the map panel in map.css round the same way as the groups here.
   ONE GREEN, #7cb928, and nothing here puts paper text on it. */

/* -------------------------------------------------------------------------
 * Fragment links under a sticky header
 * ---------------------------------------------------------------------- */

/*
 * The header sticks (below), so an in-page jump — "All 23 photos", the hero's "Text us", a
 * thumbnail into the strip — would land with its target under the header. 7rem clears the
 * desktop header with room to spare; a phone's is shorter, and extra padding there is harmless.
 */
html {
	scroll-padding-top: 7rem;
}

/*
 * ⚠ THE 24px PAPER STRIP UNDER THE HEADER — found on staging 2026-10-07. WordPress gives the
 * top-level blocks of a page its block gap (`.wp-site-blocks > * + *`), so <main> began 1.5rem
 * under the header's hairline. Every page used to be paper on paper there and nobody saw it; the
 * hero and the page header band are smoke, and the strip read as a mistake. The header's hairline
 * is the separation; <main> starts under it. (0,1,1) outranks core's (0,1,0).
 */
.wp-site-blocks > main {
	margin-block-start: 0;
}

/* -------------------------------------------------------------------------
 * The spacing scale on a phone
 * ---------------------------------------------------------------------- */

/*
 * ⚠ THE LARGEST RUNG STEPS DOWN ON A PHONE, AND IT IS THE PRESET THAT STEPS, NOT THE RULES THAT
 * READ IT. Every band on the front page carries `padding-top: var(--wp--preset--spacing--50)` as
 * an INLINE style written by the seed, which no stylesheet rule can override without `!important`
 * — and the same token is the space above every titled section, the More homes band and the home
 * page's grid. Six bands at 64px top and bottom on a 375px phone was a lot of thumb (John,
 * 2026-10-07, ticket 32). Redefining the custom property at this width moves every one of them at
 * once, on every page, with no seed and no bang: the honest statement that the scale steps down
 * on a phone.
 *
 * `html:root` outranks the `:root` WordPress prints the presets on (0,1,1 against 0,1,0), so this
 * holds whichever stylesheet prints last. ⚠ scripts/migrate/typography.py reads the DESKTOP value
 * off the page's own preset block, which this does not touch: 4rem is still what theme.json says
 * and what the page prints.
 */
@media (max-width: 30rem) {
	html:root {
		--wp--preset--spacing--50: 3rem;
	}
}

/* -------------------------------------------------------------------------
 * The prose measure inside a page header band
 * ---------------------------------------------------------------------- */

/* Inventory pages run on the wide 1200px measure so the heading, the intro copy and the card grid
   share one left edge. A 760px heading sitting above a 1200px grid does not read as two measures,
   it reads as a mistake, and it is the first thing anyone notices on the page.

   Prose still needs a readable line, though, so the running text is held back to a prose measure
   while the grid keeps the full width. This is the kind of thing theme.json cannot express — it
   has one content width per layout, not one per block — which is why it is here rather than there. */
/* Capping the paragraphs, not the wrapper they sit in. WordPress's constrained layout centres a
   direct child with `margin-left: auto !important`, so a max-width on the wrapper wins the width
   and loses the left edge — measured live at left 345 under a heading at left 113. The wrapper
   keeps the full measure and the prose inside it is held back instead, which needs no !important
   of our own to undo core's.

   Since ticket 31 the title and the intro sit inside the page header band, so the selectors read
   through it rather than through <main>. */
.is-style-page-head .wp-block-post-content > p,
.is-style-page-head .wp-block-term-description > p {
	max-width: 46rem;
	color: var(--wp--preset--color--muted);
}

/* A URL spelled out in running text is one unbreakable word. The Terms of Service carries the
   privacy policy's address in full, 353px wide at 375, and the page scrolled 2px sideways on it —
   ticket 32's walk, held for this bump. `anywhere` rather than `break-word`, because a URL has no
   word boundary to prefer and `break-word` is allowed to overflow before it breaks. */
.wp-block-post-content a {
	overflow-wrap: anywhere;
}

/* -------------------------------------------------------------------------
 * The site header
 * ---------------------------------------------------------------------- */

/*
 * The site header's own padding — ⚠ IN THIS FILE RATHER THAN INLINE ON THE TEMPLATE, AND THAT IS
 * WHAT MAKES THE MEDIA QUERY BELOW POSSIBLE AT ALL. It used to be a `style="padding-top:..."` on
 * the group in parts/header.html, and an inline style beats any stylesheet rule that is not
 * `!important` — so the phone override could only have been won with a bang, which is the trap
 * this file already documents one section down. Moving the declaration here costs nothing and
 * leaves the reasoning next to the numbers.
 *
 * ⚠ STICKY SINCE TICKET 31, AND THE BLUR IS ON A PSEUDO-ELEMENT FOR A REASON THAT IS NOT TASTE.
 * `backdrop-filter` on the header itself would make the header the containing block for every
 * `position: fixed` descendant — which is the navigation block's phone menu, `position: fixed;
 * inset: 0` when open. Filtered, that overlay would be confined to the header's own box. On a
 * pseudo-element it filters only what is behind it and contains nothing.
 *
 * ⚠ THE BACKGROUND MOVED OUT OF parts/header.html FOR THE SAME CLASS OF REASON: a `backgroundColor`
 * attribute writes `.has-paper-background-color`, which WordPress prints with `!important`, and a
 * 92% paper under a blur cannot be had through that. color-mix() keeps it a token.
 *
 * `top` is the admin bar's height for anyone logged in and 0 for everyone else; z-index 30 sits
 * above <main> and below the navigation's own overlay, which stacks inside the header.
 */
.newpad-site-header {
	position: sticky;
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: 30;
	padding-top: var(--wp--preset--spacing--30);
	padding-bottom: var(--wp--preset--spacing--30);
	border-bottom: 1px solid var(--wp--preset--color--sage);
}

.newpad-site-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: color-mix(in srgb, var(--wp--preset--color--paper) 92%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
}

/*
 * ⚠ THE MOBILE HEADER TRIM — John, 2026-09-13, so a home's photograph reaches the fold.
 *
 * Measured on a 375x667 phone before this: banner 54px + header 199px = 253px, 38% of the screen,
 * before a single word of the page. And 96px of that header was ONE ROW that had wrapped — a 200px
 * logo will not sit beside the phone number and the menu button in 327px, so the phone number fell
 * to a second line and took a 25px gap with it.
 *
 * Capping the logo at 150px is what unwraps it, and unwrapping is worth 62px where trimming the
 * padding is worth 16. The header now measures 127px and the hero photograph begins at 338 instead
 * of 675 — above the fold on every phone rather than below it on all of them.
 *
 * ⚠ SO THE LOGO CAP IS LOAD-BEARING, NOT COSMETIC. Raising it back past about 160px re-wraps the
 * row and silently gives the 62px back. ⚠ AND IT IS WHY THE PHONE PILL BELOW STARTS AT 30rem: a
 * pill's padding is another 32px in the same 327px row, and the row wraps again.
 */
@media (max-width: 30rem) {
	.newpad-site-header {
		padding-top: var(--wp--preset--spacing--20);
		padding-bottom: var(--wp--preset--spacing--20);
	}

	.wp-block-site-logo img {
		max-width: 150px;
		height: auto;
	}
}

/* The phone number in the header.

   Lives here rather than in inventory.css because that stylesheet is enqueued per block, for the
   blocks that draw listing cards — the header is on every page, including pages that have no
   listings on them at all, so a per-block stylesheet would leave the number unstyled exactly
   where somebody most needs to tap it.

   Placed BEFORE the navigation on purpose: the nav collapses to an overlay menu on mobile, so the
   header reads logo | phone | menu, and the number stays one tap away without opening anything.
   For a builder whose leads arrive by phone, that ordering is the whole point of putting it here. */
.newpad-header-phone {
	margin: 0;
	white-space: nowrap;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
}

/*
 * ⚠ INK, NOT GREEN, AND THIS IS THE ONE THAT MATTERS MOST. The number sat at brand green on paper —
 * 2.37:1 at 0.875rem bold, and 1.63:1 before the green was settled — which made the single element
 * a builder whose leads arrive by phone most needs a visitor to read the hardest thing on the page
 * to read. Ink is 15.7:1.
 *
 * Not navy either, though navy is this theme's link colour: the navigation beside it is navy, and a
 * phone number that matches the nav stops being the thing your eye goes to. Ink at 700 in the
 * display face is distinct from both the nav and the body text without leaning on a colour.
 */
.newpad-header-phone a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
	/* The tap target — see the block below. An inline-block takes the 22px line box, not the
	   18px of glyphs, so 11px above and below is what measures 44. */
	display: inline-block;
	padding: 11px 0.5rem;
	margin: -11px -0.5rem;
}

.newpad-header-phone a:hover,
.newpad-header-phone a:focus {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/*
 * The sage pill — ticket 31, the reference's one header control — from 30rem up. Below that the
 * number stays the plain link above, because the pill's padding re-wraps the phone header row
 * (see the logo cap). The icon is a mask so its colour is the text's, read from a token.
 */
@media (min-width: 30.0625rem) {
	.newpad-header-phone a {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		min-height: 44px;
		margin: 0;
		padding: 0 1rem;
		background-color: var(--wp--preset--color--sage);
		border-radius: 999px;
	}

	.newpad-header-phone a::before {
		--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1.9.4 1.8.7 2.6a2 2 0 0 1-.5 2.1L8 9.7a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.8.3 1.7.5 2.6.7a2 2 0 0 1 1.7 2z'/%3E%3C/svg%3E");
		content: "";
		flex: none;
		width: 16px;
		height: 16px;
		background-color: currentColor;
		-webkit-mask: var(--newpad-icon) center / contain no-repeat;
		mask: var(--newpad-icon) center / contain no-repeat;
	}

	.newpad-header-phone a:hover,
	.newpad-header-phone a:focus {
		text-decoration: none;
		background-color: color-mix(in srgb, var(--wp--preset--color--sage) 85%, var(--wp--preset--color--ink));
	}
}

/*
 * The current page, underlined in the green — the reference's one piece of navigation feedback.
 * WordPress marks the item when the link's URL is the page being viewed; on a page it does not
 * mark, nothing is underlined, which is the correct nothing.
 */
.newpad-site-header .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content {
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--brand-green);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.35em;
}

/*
 * ⚠ THE TWO MOBILE TAP TARGETS — ticket 24. Measured at 375x812 on 2026-10-05: the menu toggle was
 * 24x24 and the phone link 18px tall, both under the 44px floor every other control on this site
 * was measured against, on the width most of its traffic uses.
 *
 * PADDING THE LAYOUT NEVER SEES. Each gets the padding that takes it to 44px and a negative margin
 * of the same size, so the box a thumb can hit grows while the box the header lays out does not.
 * Measured with the rules applied, same viewport: toggle 44x44, phone link 44px, header row still
 * 36px, <main> still starting at 131px, document still 375px wide — so the logo cap above stays
 * load-bearing and the hero photograph stays where ticket 28 put it. The toggle's extra 10px each
 * side sits inside the header's own 24px side padding and 16px top and bottom. The phone link's
 * rule is folded into its colour rule above.
 *
 * Scoped to the header so it outranks core's own `.wp-block-navigation__responsive-container-open
 * { padding: 0 }` on specificity rather than on which stylesheet happens to print last.
 */
.newpad-site-header .wp-block-navigation__responsive-container-open {
	padding: 10px;
	margin: -10px;
}

/*
 * And the links inside the open phone menu: 26px tall, measured on staging 2026-10-07 (and noted
 * as pre-existing when ticket 16 measured the header). 9px above and below the 26px line box is
 * what measures 44, on the one screen where every link is a thumb target.
 */
.newpad-site-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	display: inline-block;
	padding-top: 9px;
	padding-bottom: 9px;
}

/* -------------------------------------------------------------------------
 * Putting back the first-child margin reset theme.json out-specifies
 * ---------------------------------------------------------------------- */

/*
 * theme.json now gives every core Heading more space above than below, which is the single thing
 * that makes a run of prose read as sections rather than as one column. The cost is a cascade
 * collision, and it is invisible until you look at the top of a coloured band.
 *
 * WordPress zeroes the block-start margin of a flow or constrained layout's FIRST child, from
 * `:where(body .is-layout-flow) > :first-child` — specificity 0,1,0, because :where() contributes
 * nothing. theme.json compiles a block style to `:root :where(.wp-block-heading)`, which is also
 * 0,1,0. A tie, decided by whichever stylesheet WordPress happens to print second — and it prints
 * per-block styles after the layout rules, so the heading wins and a heading at the top of a group
 * gains 2.5rem nobody asked for, on top of the group's own padding.
 *
 * ⚠ SO THIS IS A CORE WORKAROUND, NOT A DESIGN DECISION, which is the test for whether a rule
 * belongs in this file. 0,2,0 settles it in the direction core intended, and it stays correct if a
 * future release changes the print order back.
 */
:where(.is-layout-flow, .is-layout-constrained) > .wp-block-heading:first-child {
	margin-top: 0;
}

/* -------------------------------------------------------------------------
 * One section pattern
 * ---------------------------------------------------------------------- */

/*
 * A section is a heading, the space above it, and a hairline under the heading. That is all of it,
 * and the smallness is the point: before this, .newpad-collection__group, .newpad-featured__heading
 * and .newpad-more__heading each picked their own margins — close enough to look accidental and
 * different enough to look untidy — and one of them knocked an <h2> down to body size, which is
 * why a floor plan page had no visible sections at all.
 *
 * ⚠ THE PATTERN SETS NO SIZE. A section heading takes its size from its heading LEVEL, off
 * theme.json's scale, so the page reads as one document rather than as a set of components that
 * each chose a size. Pick the right level and the size follows; override the size and you are back
 * where this started.
 *
 * ⚠ AND IT SETS NO WIDTH, deliberately. Capping a section wrapper is the trap the prose rule above
 * documents: WordPress's constrained layout centres a direct child with `margin-left: auto
 * !important`, so a max-width here would win the width and lose the left edge. Cap prose, never
 * its container.
 */
.newpad-section:not(:first-child) {
	margin-top: var(--wp--preset--spacing--50);
}

.newpad-section__heading {
	margin: 0 0 var(--wp--preset--spacing--30);
	padding-bottom: var(--wp--preset--spacing--10);
	border-bottom: 1px solid var(--wp--preset--color--sage);
}

/* The rule is the optional half. A section inside a panel that already has its own edges — the
   tour form's card is the live case — gets a second line it does not need. */
.newpad-section__heading--plain {
	padding-bottom: 0;
	border-bottom: 0;
}

/*
 * The centred half — ticket 31. A heading over a lead line, centred, no hairline: the shape every
 * section on the reference takes and the shape the front page's sections take now. The head is a
 * wrapper so the heading and the lead share one measure and one margin below; the lead is `lead`,
 * muted, and 46rem wide at most, because a centred line longer than that stops reading as a line.
 *
 * Capping the head rather than the section is the rule above, kept: the head is prose, the
 * section is its container.
 */
.newpad-section__head {
	max-width: 46rem;
	margin: 0 auto var(--wp--preset--spacing--40);
	text-align: center;
}

/* On a phone the head sits 24px over its cards rather than 40 — ticket 32, with the bands. The
   core-paragraph lead on the front page already keeps 24px to what follows, by the block gap. */
@media (max-width: 30rem) {
	.newpad-section__head {
		margin-bottom: var(--wp--preset--spacing--30);
	}
}

.newpad-section--centred .newpad-section__heading {
	margin-bottom: var(--wp--preset--spacing--10);
	padding-bottom: 0;
	border-bottom: 0;
}

.newpad-section__lead {
	margin: 0;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--lead);
}

/*
 * The same lead line when the team writes it as a core Paragraph on the front page. An element
 * selector on top of the class so it outranks the constrained layout's max-width on children
 * (0,1,0) rather than relying on print order; the layout's own auto margins then centre it.
 */
p.newpad-lead {
	max-width: 46rem;
}

/* A run of prose that should not stretch across a wide band — the trade partners' two lines. */
.wp-block-group.newpad-prose {
	max-width: 42rem;
}

/* -------------------------------------------------------------------------
 * The FAQ's questions — core's Details block as a list of disclosures (ticket 39)
 * ---------------------------------------------------------------------- */

/*
 * One question per Details block, a hairline under each, the question itself a lead-size display
 * line with a 44px tap target. No script: <details> opens and closes natively, is keyboard-
 * operable, and the team adds a question by adding a Details block in the editor. The weight is
 * stated because the display family ships only its 700 (CLAUDE.md on the font budget), and the
 * size is `lead`, not a heading rung, for the reason a card title is: a question is a line of
 * prose, not a section. ⚠ No width is set anywhere here, so the vertical padding cannot widen a
 * content-box wrapper (CLAUDE.md on box-sizing). No green on text, either: Brand Green on paper
 * is 2.4:1 and fails every floor, so the open and hover states are an underline.
 */
.wp-block-details {
	border-bottom: 1px solid var(--wp--preset--color--sage);
}

.wp-block-details + .wp-block-details {
	margin-top: 0;
}

.wp-block-details > summary {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 700;
	line-height: 1.3;
	min-height: 44px;
	padding: var(--wp--preset--spacing--20) 0;
	cursor: pointer;
}

.wp-block-details > summary:hover,
.wp-block-details > summary:focus-visible,
.wp-block-details[open] > summary {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.wp-block-details > :not(summary) {
	margin-top: 0;
	margin-bottom: var(--wp--preset--spacing--20);
	max-width: 46rem;
}

/* -------------------------------------------------------------------------
 * The page header band — a Group block style, and the top of three templates
 * ---------------------------------------------------------------------- */

/*
 * Smoke, a hairline under it, the title and the intro inside it, the controls that go with the
 * page at its foot. page-inventory.html, taxonomy.html and single-property.html open with one; it
 * is reachable in the editor as a Group block style ("Page header") so a page the team composes
 * can open the same way. The band is `alignfull` in the template and carries the wide measure
 * inside it, so the title keeps the one left edge the prose rule above argues for.
 *
 * ⚠ THE TEMPLATE'S <main> HAS NO TOP PADDING WHEN IT OPENS WITH ONE OF THESE — the band provides
 * its own, and paper above smoke under the header reads as a gap in the page.
 */
.wp-block-group.is-style-page-head {
	padding-top: var(--wp--preset--spacing--40);
	padding-bottom: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--smoke);
	border-bottom: 1px solid var(--wp--preset--color--sage);
}

/* Only the top tightens on a phone. The bottom keeps its 2.5rem because browser.css pulls the
   filter card 1.75rem up into it, and at 1.5rem the card would sit 4px over the segment pills. */
@media (max-width: 30rem) {
	.wp-block-group.is-style-page-head {
		padding-top: var(--wp--preset--spacing--30);
	}
}

/*
 * A home's own band is the exception, and single-property.html marks it. Nothing is pulled up
 * into it, and on a phone it is the badge and the address before the first photograph — ticket
 * 33 moved the price and Call and Text under the pictures on John's word, and ticket 37 moved the
 * town row after them too (John, 2026-10-09); ticket 32 had trimmed the band from 394px to 331 at
 * 375 wide with all five in it. 16px above the badge is the header's own phone rhythm, 24px
 * under the address is the gap the tiles already keep; the rest of the trim is inventory.css's.
 */
@media (max-width: 30rem) {
	.wp-block-group.is-style-page-head.newpad-property__band {
		padding-top: var(--wp--preset--spacing--20);
		padding-bottom: var(--wp--preset--spacing--30);
	}
}

/* -------------------------------------------------------------------------
 * Bands — a block that draws its own full-width ground
 * ---------------------------------------------------------------------- */

/*
 * For a block that renders nothing when it has nothing to show and must not leave a tinted strip
 * behind when it does — More homes at the foot of a home page is the caller. The block carries
 * `newpad-band` when the template aligns it full, pads itself, and puts its content back on the
 * wide measure with the root padding the alignment removed. A Group around the block in the
 * template could not do this: the Group would stay when the block went.
 */
.newpad-band {
	padding-top: var(--wp--preset--spacing--50);
	padding-bottom: var(--wp--preset--spacing--50);
}

.newpad-band--smoke {
	background-color: var(--wp--preset--color--smoke);
}

.newpad-band__inner {
	box-sizing: border-box;
	max-width: var(--wp--style--global--wide-size);
	margin-left: auto;
	margin-right: auto;
	padding-left: var(--wp--style--root--padding-left);
	padding-right: var(--wp--style--root--padding-right);
}

/* -------------------------------------------------------------------------
 * Buttons beyond theme.json's one
 * ---------------------------------------------------------------------- */

/*
 * theme.json defines THE button: Brand Green with ink text, 12px corners, the display face. That
 * reaches every core Button and every `.wp-element-button` the plugins render. The reference has
 * two more faces, and both are variations rather than new buttons:
 *
 *   ink     — the page's second action: "Text us" in the hero, "See every home" under the
 *             featured strip. Paper text on ink is 15.7:1.
 *   outline — core's own `is-style-outline`, which takes its colour from the text around it: ink on
 *             a pale band, paper on the ink band. Nothing to add.
 *
 * ⚠ NO PAPER TEXT ON EITHER GREEN. There is deliberately no "green with white text" variation.
 */
.wp-block-button.is-style-ink > .wp-block-button__link,
.wp-element-button.newpad-button--ink {
	background-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.wp-block-button.is-style-ink > .wp-block-button__link:hover,
.wp-block-button.is-style-ink > .wp-block-button__link:focus,
.wp-element-button.newpad-button--ink:hover,
.wp-element-button.newpad-button--ink:focus {
	background-color: color-mix(in srgb, var(--wp--preset--color--ink) 85%, var(--wp--preset--color--paper));
	color: var(--wp--preset--color--paper);
}

/* A plugin-rendered button is a link, and a link underlines on hover by theme.json. A button does
   not. */
.wp-element-button.newpad-button--ink {
	display: inline-block;
	text-decoration: none;
}

.wp-element-button:focus-visible {
	outline: 3px solid var(--wp--preset--color--brand-green);
	outline-offset: 2px;
}

/* -------------------------------------------------------------------------
 * The card — a Group block style
 * ---------------------------------------------------------------------- */

/*
 * Paper, a hairline, the card radius and the card shadow — the surface the listing card in
 * inventory.css is drawn on, available to the team as a Group block style ("Card") so the Why
 * NewPad tiles are three groups rather than three custom blocks. The radius and the shadow are the
 * same tokens every card on the site reads, which is what makes a Group styled this way and a
 * listing card beside it look like the same object.
 */
.wp-block-group.is-style-card {
	box-sizing: border-box;
	height: 100%;
	padding: var(--wp--preset--spacing--30);
	background-color: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--sage);
	border-radius: var(--wp--custom--radius--card);
	box-shadow: var(--wp--preset--shadow--card);
}

/*
 * The icon tile at the top of a Why NewPad card: a Spacer block carrying a class, 52px square on
 * sage, with the icon a CSS mask so it is aria-hidden by the block and coloured by a token. SVG
 * upload is disabled on purpose (see docs/media-conventions.md), so the icons live here.
 */
.wp-block-spacer.newpad-icon {
	display: grid;
	place-items: center;
	width: 52px;
	margin: 0;
	background-color: var(--wp--preset--color--sage);
	border-radius: var(--wp--custom--radius--button);
}

.wp-block-spacer.newpad-icon::before {
	content: "";
	width: 26px;
	height: 26px;
	background-color: var(--wp--preset--color--ink);
	-webkit-mask: var(--newpad-icon) center / contain no-repeat;
	mask: var(--newpad-icon) center / contain no-repeat;
}

.newpad-icon--finishes {
	--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 3 1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z'/%3E%3Cpath d='M19 17l.8 2.2L22 20l-2.2.8L19 23l-.8-2.2L16 20l2.2-.8z'/%3E%3C/svg%3E");
}

.newpad-icon--locations {
	--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0z'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3C/svg%3E");
}

.newpad-icon--warranty {
	--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E");
}

/* -------------------------------------------------------------------------
 * The testimonial card — a Quote block style
 * ---------------------------------------------------------------------- */

/*
 * A paper card with a pulled line, the rest of the quote, and the name under a hairline — in
 * place of theme.json's left-ruled blockquote, which stays the default for a quote in prose. The
 * card fills its column and the body stretches, so six cards in two rows put their names on one
 * line.
 *
 * ⚠ THE STAR ROW IS JOHN'S CALL, MADE TWICE. On 2026-10-06 he dropped it — the six are quotes
 * lifted verbatim with no rating attached, and a star row is a claim the quotes do not carry — and
 * on 2026-10-08, looking at the live cards, asked for it back. It is drawn here, in CSS, as five
 * stars in the green above the pulled line: no seed changes, no glyph in the page, and one rule
 * to delete if the call changes a third time. Being a pseudo-element it is seen and not read, and
 * nothing in the markup or the schema claims a rating. ⚠ AND NO ITALIC: the font budget is
 * Montserrat 700 and Lato 400/700, upright, so an italic here would be synthesised by the
 * browser — the pulled line is set in the display face with curly quotes instead.
 */
.wp-block-quote.is-style-card {
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
	height: 100%;
	margin: 0;
	padding: var(--wp--preset--spacing--30);
	background-color: var(--wp--preset--color--paper);
	border: 0;
	border-radius: var(--wp--custom--radius--card);
	box-shadow: var(--wp--preset--shadow--card);
}

/*
 * Five stars, one mask repeated: the star sits in the left 24 of a 28-unit box, so the repeat
 * carries its own gap, and the row is five boxes less the trailing gap. The first flex item in the
 * card, above the pulled line, in the green the chips' checks use.
 */
.wp-block-quote.is-style-card::before {
	--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 24' fill='black'%3E%3Cpath d='M12 2.5l2.9 6.2 6.8.8-5 4.7 1.3 6.8L12 17.6 6 21l1.3-6.8-5-4.7 6.8-.8z'/%3E%3C/svg%3E");
	content: "";
	flex: none;
	width: 102px;
	height: 18px;
	background-color: var(--wp--preset--color--brand-green);
	-webkit-mask: var(--newpad-icon) left center / 21px 18px repeat-x;
	mask: var(--newpad-icon) left center / 21px 18px repeat-x;
}

.wp-block-quote.is-style-card > .wp-block-heading {
	margin: 0;
	line-height: 1.3;
}

.wp-block-quote.is-style-card > p {
	flex: 1;
	margin: 0;
}

.wp-block-quote.is-style-card cite {
	display: block;
	padding-top: var(--wp--preset--spacing--20);
	border-top: 1px solid var(--wp--preset--color--sage);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--medium);
}

/* -------------------------------------------------------------------------
 * The footer part — flush against whatever ends the page
 * ---------------------------------------------------------------------- */

/*
 * ⚠ A 24px STRIP OF PAPER BETWEEN THE FRONT PAGE'S INK BAND AND THE INK FOOTER — John, 2026-10-09,
 * circled. `main` and the footer template part are siblings at the template's root, so the root
 * layout gives the footer the block gap as a top margin, and on a page whose last block is an ink
 * band that gap is a pale line across the full width (measured on staging: band bottom 6962,
 * footer top 6986). The footer is its own ink block with 4rem of padding inside, so it needs no
 * air from outside: on a paper page the strip was paper on paper and invisible, and removing it
 * changes nothing there.
 */
footer.wp-block-template-part {
	margin-block-start: 0;
}

/* -------------------------------------------------------------------------
 * Trust chips — a List block style
 * ---------------------------------------------------------------------- */

/*
 * "1-2-6 warranty · New construction · Fort Worth and around": a row of short facts, each with a
 * check, under the hero and on the closing band. A List block so the words are the team's to
 * edit; the check is a mask, in the green, decorative beside words.
 *
 * ⚠ NO margin-top HERE, ON PURPOSE — John, 2026-10-09: "the home page header still has weird
 * spacing", circled. This rule used to say `margin: 0`, which at 0,2,0 outranked the layout's
 * own `:where(.is-layout-constrained) > * + * { margin-block-start: var(--wp--style--block-gap) }`
 * and took the 24px every other row in the hero gets: measured at 1280, the lead sat 24px under
 * the headline and the buttons 24px under the lead, and the chips 0px under the buttons — a
 * caption glued to a button row, then 78px of empty hero. The closing band had the same 0px
 * between Call/Text and its chips. So the top margin is the layout's to set, as for any block,
 * and only the UA's bottom and side list margins are reset.
 */
.wp-block-list.is-style-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	margin-bottom: 0;
	margin-left: 0;
	margin-right: 0;
	padding: 0;
	list-style: none;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.4;
}

.wp-block-list.is-style-chips > li {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	margin: 0;
}

.wp-block-list.is-style-chips > li::before {
	--newpad-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m8 12 3 3 5-6'/%3E%3C/svg%3E");
	content: "";
	flex: none;
	width: 18px;
	height: 18px;
	background-color: var(--wp--preset--color--brand-green);
	-webkit-mask: var(--newpad-icon) center / contain no-repeat;
	mask: var(--newpad-icon) center / contain no-repeat;
}

.wp-block-list.is-style-chips.newpad-chips--centred {
	justify-content: center;
}

/* On the ink band the muted grey loses its contrast; sage is 11:1 on ink. */
.has-ink-background-color .wp-block-list.is-style-chips {
	color: var(--wp--preset--color--sage);
}

/* -------------------------------------------------------------------------
 * The hero — the front page's Cover block
 * ---------------------------------------------------------------------- */

/*
 * The photograph full bleed, the headline over a wash from the left so the house stays visible on
 * the right — Clear, as John chose it on 2026-10-06. The wash is theme.json's `hero-wash` gradient
 * preset, which the Cover block applies through `.has-hero-wash-gradient-background`; that class
 * carries WordPress's own `!important`, so on a phone, where the text sits above the photograph
 * and the wash has to run top to bottom, the PRESET'S CUSTOM PROPERTY is redefined on the hero
 * rather than the background fought. The span inherits the property and the class resolves it.
 *
 * The Cover's padding is the root padding, not core's 1em, so the headline shares the page's edge.
 *
 * ⚠ AS TALL AS ITS WORDS, NOT A FIXED 620px — John, 2026-10-08. Measured at 1280x600 the day
 * after ticket 32 went up: the hero was 620px, its content 517px centred inside, and 151px of
 * washed photograph followed the last chip on the left, where the wash is 97% smoke and nothing
 * shows through — "weird spacing", circled. The Cover block centres its content, so a minimum
 * height is paid at the bottom as much as at the top, and the left column under the chips is the
 * one place in the hero where there is nothing to see. No minimum (core's own 430px is
 * overridden too); the padding is the hero's whole height beyond its words, about 78px a side at
 * 1280 and 88 on a wide screen.
 */
.wp-block-cover.newpad-hero {
	min-height: 0;
	padding-left: var(--wp--style--root--padding-left);
	padding-right: var(--wp--style--root--padding-right);
	background-color: var(--wp--preset--color--smoke);
}

.newpad-hero .wp-block-cover__inner-container {
	padding-top: clamp(3.5rem, 2.5rem + 3vw, 5.5rem);
	padding-bottom: clamp(3.5rem, 2.5rem + 3vw, 5.5rem);
}

/*
 * Ink, not black. A Cover marked `is-light` sets its inner container to #000 and core makes the
 * headings inside inherit it (`.wp-block-cover .wp-block-cover__inner-container :where(h1, …)`,
 * 0,2,0), which outranks theme.json's heading colour (0,1,0). Measured on staging 2026-10-07:
 * the hero's h1 was rgb(0, 0, 0). 0,4,0 here puts the brand's ink back.
 */
.wp-block-cover.newpad-hero.is-light .wp-block-cover__inner-container {
	color: var(--wp--preset--color--ink);
}

/* The headline: bigger than the scale's top rung, as a hero's is, and tracked tighter — the one
   place -0.03em is right. Stated weight, because the display face ships at 700 only. */
.newpad-hero h1 {
	font-size: clamp(2.25rem, 1.5rem + 3vw, 4rem);
	font-weight: 700;
	letter-spacing: -0.03em;
	line-height: 1.05;
}

.newpad-hero .newpad-hero__lead {
	max-width: 32rem;
}

@media (max-width: 56.25em) {
	.wp-block-cover.newpad-hero {
		--wp--preset--gradient--hero-wash: var(--wp--preset--gradient--hero-wash-stacked);
	}

	/* Room under the words for the house to show through. */
	.newpad-hero .wp-block-cover__inner-container {
		padding-top: 3rem;
		padding-bottom: 11rem;
	}

	/*
	 * ⚠ THE CHIPS CARRY THEIR OWN GROUND WHERE THE WASH HAS FADED — John, 2026-10-08: "you can't
	 * read the text below that well". Under the stacked wash the chips are the last line of the
	 * hero's words and sit where the photograph has to show through for the hero not to read as
	 * empty (ticket 32); measured at 375x667 they were on about 30% smoke over the house. A 90%
	 * smoke pill under each chip is the same ground the headline has, so the wash can keep fading
	 * under them. Muted on smoke is 5.6:1. The desktop wash is 97% smoke the whole way down the
	 * left, so there the chips stay plain text.
	 */
	.newpad-hero .wp-block-list.is-style-chips > li {
		padding: 0.25rem 0.6rem;
		border-radius: 999px;
		background-color: color-mix(in srgb, var(--wp--preset--color--smoke) 90%, transparent);
	}
}

/*
 * ⚠ ONE COLUMN OF EQUAL PILLS ON A PHONE — John, 2026-10-09: make the hero's "bubbles" more
 * congruent with each other. At 360px the row wrapped two and one — 136 + 24 + 153 = 313 in 312,
 * so the second pill only just failed to join the first and the third sat alone under them, three
 * widths in two rows. A grid with one max-content column stretches every pill to the widest
 * (185px, "Fort Worth and around"), so the three read as one set: same width, same height, left
 * edge shared with the headline. The row returns above 30rem, where it fits.
 */
@media (max-width: 30rem) {
	.newpad-hero .wp-block-list.is-style-chips {
		display: grid;
		grid-template-columns: max-content;
		gap: 0.5rem;
	}
}

/*
 * ⚠ THE EMPTY BAND UNDER THE CHIPS — John, 2026-10-07, ticket 32. At 375x667 those 11rem left
 * 192px of washed photograph after the hero's last chip, and under a wash still 25% smoke at its
 * foot the house read as pale nothing. 4rem is room for the house now that the stacked wash in
 * theme.json ends transparent; a tablet keeps the 11rem, because at 768px wide the 1024px
 * photograph has a house in it to show.
 */
@media (max-width: 30rem) {
	.newpad-hero .wp-block-cover__inner-container {
		padding-bottom: 4rem;
	}
}

/* -------------------------------------------------------------------------
 * A home's page: the details beside the side card
 * ---------------------------------------------------------------------- */

/*
 * Two columns on a desktop — the details on the left; on the right the ask card (NewPad Core's
 * newpad/property-ask: price, specification, Request a tour, Text and Call, the two action rows)
 * with the tour form under it — and one column on a phone, where the ask is in flow directly
 * under the band and the form comes after the Overview. The blocks style themselves in
 * inventory.css; this is only the composition single-property.html asks for, which is the
 * theme's.
 *
 * ⚠ THE DOM ORDER IS THE PHONE'S AND THE GRID AREAS ARE THE DESKTOP'S — ticket 33. The ask
 * wrapper is the grid's first child so a phone reads the town, the price and the actions straight
 * after the photographs (ticket 37's band above them is the badge and the address alone — John,
 * 2026-10-09), and `grid-template-areas` puts it top right on a desktop with the details spanning
 * both rows.
 *
 * ⚠ THE ASK CARD IS STICKY INSIDE A WRAPPER THAT IS THE GRID ITEM, AND THE WRAPPER IS THE WHOLE
 * FIX — ticket 37. Ticket 33 made the card itself the grid item and wrote here that a sticky
 * element can only move inside its containing block, "for a grid item, its grid area". That is
 * what the specification says and NOT what Chromium does: measured on 2026-10-09 at 1280x700,
 * with the rows computing to the card's own height and the form's, the card was constrained by
 * the GRID CONTAINER and rode over the form — 65px into it at scrollY 1050, covering its top
 * entirely by 1350, and on until the grid ended. John: "The CTA box scrolls overtop of the tour
 * form." So `.newpad-home-grid__ask` is the grid item, stretched to its `1fr` row, and the card
 * is sticky INSIDE it: a sticky element moves within its nearest scrolling ancestor's box
 * clipped to its containing block, and a block wrapper is a containing block every engine
 * agrees on. The card travels down beside the details and stops at the wrapper's foot, which is
 * where the form's row begins; `1fr auto` still hands the wrapper everything the form's row does
 * not need, and the form sits at the foot of the right column, beside the end of the Overview —
 * where a phone reads it too. The form never scrolls inside anything. On a page whose details are
 * shorter than the card and the form together, the wrapper is exactly the card's height and the
 * card simply does not move — which is correct, and is what ticket 20 should see on 10504 Ruffin
 * Dr until its Overview grows.
 *
 * ⚠ AND IT IS NOT THE STICKY BAR JOHN REMOVED ON 2026-09-13: on a phone nothing here is sticky.
 *
 * `:has()` hides the form's card when the form did not render — the blocks plugin off — so there
 * is never a bordered frame around nothing; the same guard hides the ask wrapper when the block
 * printed nothing (it does so only with no price, no specification, no button, no pair and no
 * row), so a phone never pays a section's gap for an empty div.
 */
.wp-block-group.newpad-home-grid {
	margin-top: var(--wp--preset--spacing--40);
	margin-bottom: var(--wp--preset--spacing--50);
}

/* The flow layout's gap belongs between blocks in a column, not between the two columns. */
.wp-block-group.newpad-home-grid > * {
	margin-block-start: 0;
}

.newpad-home-aside {
	box-sizing: border-box;
	padding: var(--wp--preset--spacing--30);
	background-color: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--sage);
	border-radius: var(--wp--custom--radius--card);
	box-shadow: var(--wp--preset--shadow--raised);
}

.newpad-home-aside:not(:has(.newpad-tour)) {
	display: none;
}

.newpad-home-grid__ask:not(:has(.newpad-ask)) {
	display: none;
}

/* One column: the ask, the details, the form, a section's air between each. */
@media (max-width: 56.25em) {
	.wp-block-group.newpad-home-grid > * + * {
		margin-top: var(--wp--preset--spacing--40);
	}
}

@media (min-width: 56.3125em) {
	.wp-block-group.newpad-home-grid {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 380px;
		grid-template-rows: 1fr auto;
		grid-template-areas:
			"main ask"
			"main form";
		gap: var(--wp--preset--spacing--40);
		align-items: start;
	}

	.newpad-home-grid__main {
		grid-area: main;
	}

	.newpad-home-aside {
		grid-area: form;
	}

	/* The grid item the card sticks inside. `stretch` overrides the grid's `start`, so the
	   wrapper is as tall as its row rather than as tall as the card — and that height is the
	   distance the card is allowed to travel. */
	.newpad-home-grid__ask {
		grid-area: ask;
		align-self: stretch;
	}

	/* The card: the frame the form's aside wears at every width, worn here on a desktop only — on
	   a phone the ask is frameless, in flow under the photographs. `box-sizing` because nothing in
	   this theme sets it globally (CLAUDE.md), and 380px plus 48px of padding is a 428px column. */
	.newpad-home-grid__ask > .newpad-ask {
		position: sticky;
		top: calc(var(--wp-admin--admin-bar--height, 0px) + 7rem);
		box-sizing: border-box;
		padding: var(--wp--preset--spacing--30);
		background-color: var(--wp--preset--color--paper);
		border: 1px solid var(--wp--preset--color--sage);
		border-radius: var(--wp--custom--radius--card);
		box-shadow: var(--wp--preset--shadow--raised);
	}
}

/* -------------------------------------------------------------------------
 * The callout
 * ---------------------------------------------------------------------- */

/*
 * For the one thing on a page that should stop a reader: a live offer, a fact that changes what
 * somebody does next. There was no way to say that before — the announcement bar is sitewide and
 * /promotions/ has its own cards, and neither puts an offer in front of somebody standing on the
 * house they are considering. Ticket 30 is the first caller.
 *
 * ⚠ ONE PER PAGE, OR IT IS NOT A CALLOUT. Two things that stop a reader stop nobody. This is a
 * rule about editing rather than about CSS, which is exactly why it is written down here.
 *
 * ⚠ FAIR HOUSING APPLIES HARDEST HERE. A callout gives its copy the most prominent position on the
 * page. Describe the property or the offer, never the buyer — no family size, no age, no "ideal
 * for". Same rule as every field's `instructions` string, with more at stake.
 *
 * Available in the editor as a Group block style ("Callout") — see functions.php — so the team can
 * mark a paragraph without typing HTML, and as a plain class for blocks that render their own.
 */
.newpad-callout,
.wp-block-group.is-style-callout {
	margin: var(--wp--preset--spacing--40) 0;
	padding: var(--wp--preset--spacing--30);
	background-color: var(--wp--preset--color--sage);
	/* The left rule does the stopping. A full border would read as a card — something to look at
	   alongside the page — and this is meant to read as part of it, interrupted. */
	border-left: 4px solid var(--wp--preset--color--brand-green);
	border-radius: var(--wp--custom--radius--control);
}

/* No trailing gap inside the box: a callout whose last paragraph leaves a margin behind looks
   bottom-heavy at exactly the size these are usually written at. */
.newpad-callout > :last-child,
.wp-block-group.is-style-callout > :last-child {
	margin-bottom: 0;
}

.newpad-callout__heading {
	margin: 0 0 var(--wp--preset--spacing--10);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 700;
	line-height: 1.2;
}

/*
 * The quiet one. For something a reader needs to know that is not good news and is not a warning
 * either — an offer that has ended, a state the visitor arrived early for. Nothing has gone wrong,
 * and the green version would claim more attention than the fact deserves.
 */
.newpad-callout--quiet {
	background-color: var(--wp--preset--color--smoke);
	border-left-color: var(--wp--preset--color--muted);
}
