/*
 * Home-page patterns (home-*.php) — supplemental selectors NOT in base.css.
 * All rules kept under :root :where(...) to stay at 0 specificity behind
 * utility overrides, and to avoid duplicating base.css classes
 * (.display-*, .big-number, .reveal).
 */

/* Hero: dark gradient (bottom → top) in addition to the cover block's dimRatio overlay. */
:root :where(.hero-gradient) {
	position: relative;
}

/* The rule this replaced (":root :where(.hero-gradient::after)") never
   matched anything, on any hero, anywhere: ":where()" does not accept a
   pseudo-element in its argument per the CSS Selectors specification, so
   the whole selector is invalid and gets dropped at parse time (confirmed
   live: document.styleSheets[...].cssRules never contained it, and
   getComputedStyle(section, '::after').content read "none" on every
   .hero-gradient cover). Scoped to ":not(.hero-video):not(.hero-cover-dim)" -
   the video hero (home-hero.php) already darkens via its own dimRatio:50
   overlay and would double up; the two Phase-6 cover baustiene carry their
   own contrast-measured ".hero-cover-dim::before" overlay (hero-cover.css,
   opacity tuned against a worst-case white test image) and only ONE
   "::before" rule can ever apply per element, so without this exclusion this
   rule's higher specificity (the extra ":not()" clause) silently overrode
   that calibrated overlay and dropped the baustein's own contrast probe from
   passing to 3.87:1 (measured via section-library-roundtrip.py after first
   shipping this rule without the exclusion - caught before commit, not
   assumed safe). The four service-detail heroes carry dimRatio:0 and no
   ".hero-cover-dim" class, so they are the only pages this rule actually
   reaches - had no darkening at all until now, measurably losing subline
   contrast against a busy photo (Plan 04-07, qa/shots/1440/expansion-{poc,wp}.png).
   Doubled class for specificity (0,3,0), the same trick as
   ".hero-cover-dim.hero-cover-dim::before" in hero-cover.css - a plain
   ":where()"-free selector is enough here since nothing else targets
   ".hero-gradient::before". z-index 1: measured (not assumed) that the
   cover's own background <img> sits at z-index 0 and its dimRatio overlay
   <span> plus ".wp-block-cover__inner-container" both already sit at
   z-index 1 - matching that level and relying on DOM order (this
   pseudo-element is the section's conceptual first child, the real
   content the last) keeps the gradient above the photo and below the
   heading/subline without needing a second, inner-container-side rule. */
.wp-block-cover.hero-gradient.hero-gradient:not(.hero-video):not(.hero-cover-dim)::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(to top, rgba(30, 27, 24, 0.85), rgba(30, 27, 24, 0.35) 55%, rgba(30, 27, 24, 0.1));
}

/* Team teaser (home-team-teaser.php): same squeeze bug as D-13's
   service-people-card (services.css) - the figure of the core/image block
   is the direct flex child, not the img inside it, and shrinks to make
   room for the name/role text next to it. This card carries no
   .service-people-card class (it is home-page-only markup, not part of
   the shared card family), so the services.css fix does not reach it -
   verified: at 768px "Porträt von Peter Zimmermann"/"Porträt von Martin
   Remspecher" measured 0.669/0.810 aspect ratio here despite the D-13 fix
   already applied on /ueber-uns/. Same remedy, scoped to this pattern. */
:root :where(.team-teaser-card figure.wp-block-image) {
	flex-shrink: 0;
}

/* Team teaser (home-team-teaser.php): the PoC's <li> sits in a CSS Grid row
   (ul.mt-10.grid.sm:grid-cols-3) that stretches every list item to the
   tallest sibling's height (Peter Zimmermann's two-line role text) and
   centers its own content within that stretched box (li.flex.items-center)
   - Harald Lichter's/Martin Remspecher's one-line role text leaves 16px of
   slack that the grid distributes evenly above/below their image and text
   (screenshot comparison Sektion 7, Plan 04-10, 768px). core/columns has no
   equivalent: .wp-block-column already stretches to the row height
   (Flexbox default align-items:stretch on .wp-block-columns, measured
   live: 96px on all three columns), but each column is a plain block box,
   so its .team-teaser-card child sits at the column's own top edge instead
   of centered within it - measured 8px vertical offset on Harald's/
   Martin's image and text. Scoped to columns that actually carry a
   .team-teaser-card - :has() is already used elsewhere in this codebase
   (sections.css). */
:root :where(.wp-block-column:has(> .team-teaser-card)) {
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* Hero: outline button on a dark background — is-style-outline-ink is designed for light
   surfaces, recast here to on-dark (border/text light, hover in accent color). */
:root :where(.hero-video .wp-block-button.is-style-outline-ink > .wp-block-button__link) {
	border-color: color-mix(in oklab, var(--wp--preset--color--on-dark) 40%, transparent);
	color: var(--wp--preset--color--on-dark);
}

:root :where(.hero-video .wp-block-button.is-style-outline-ink > .wp-block-button__link:hover) {
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--accent);
}

/* Hero: focus badge row — there is no "small" fontSize slug in the contract. */
:root :where(.badge-row) {
	display: block;
	font-size: 0.875rem;
	/* PoC: text-on-dark/70 — color dimming, not opacity. */
	color: color-mix(in oklab, var(--wp--preset--color--on-dark) 70%, transparent);
}

/* Service cards: .big-number scaled smaller (the default size is designed for methodology digits). */
:root :where(.big-number-sm) {
	font-size: clamp(1.75rem, 3vw, 2.5rem);
}

/* Principle/bullet lists (Warum Beats Group, Für wen wir arbeiten): hyphen marker instead of bullet. */
:root :where(.dash-list) {
	list-style: none;
	padding-left: 0;
	display: flex;
	flex-direction: column;
	gap: 0.625rem;
}

/* The bullet lists of the image/text blocks sit two pixels more spacious
   in the prototype than those of the list cards (space-y-3 against
   space-y-2.5). Must come after .dash-list - both rules have the same
   specificity. */
:root :where(.dash-list-lg) {
	gap: 0.75rem;
}

:root :where(.dash-list li) {
	display: flex;
	gap: 0.75rem;
}

:root :where(.dash-list li)::before {
	content: "-";
	flex-shrink: 0;
	font-weight: 700;
	color: var(--wp--preset--color--accent);
}

/* Small overline labels (eyebrows) before section headings. */
:root :where(.eyebrow) {
	display: block;
	margin-bottom: 0.75rem;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

/* Poster behind the hero video, always. The video file is 11.5 MB, so on a
   normal connection readyState stays 0 for several seconds and the cover would
   otherwise show nothing but its overlay colour - the prototype avoids this with
   a poster attribute on the element (HeroVideo.astro), which the hand-written
   cover markup cannot carry without tripping block validation. The video paints
   over this once it is ready; under reduced motion it never appears and the
   poster is what stays. */
:root :where(.hero-video) {
	background-image: url("../images/video/hero-poster.webp");
	background-size: cover;
	background-position: center;
}

@media (prefers-reduced-motion: reduce) {
	:root :where(.hero-video .wp-block-cover__video-background) {
		display: none;
	}
}

/* Max-width utilities analogous to Tailwind max-w-4xl / max-w-2xl (PoC line
   breaks). Double class for the max-width, because WP's constrained
   layout loads later.

   The !important is unavoidable, not an oversight: core centers every
   child of a constrained container with
     .is-layout-constrained > :where(…) { margin-left: auto !important }
   Without a counter-!important the box stays centered instead of
   left-aligned — that was exactly the case here before, the rule had no
   effect on margin-left. */
.mw-4xl.mw-4xl {
	max-width: 56rem;
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

.mw-2xl.mw-2xl {
	max-width: 42rem;
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

.mw-3xl.mw-3xl {
	max-width: 48rem;
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

/* Logo band: logos as in the PoC — max. 3.5rem tall, centered in the cell. */
:root :where(.logo-band figure) {
	display: flex;
	align-items: center;
	justify-content: center;
}

:root :where(.logo-band img) {
	max-height: 3.5rem;
	width: auto;
	max-width: 100%;
}

/* Bento/surface cards: the PoC clips the image via the card frame
   (rounded-3xl + overflow-hidden), not via its own image radius —
   otherwise the rounding at the top corners drifts measurably. */
:root :where(.wp-block-group.has-surface-background-color) {
	overflow: hidden;
}

:root :where(.wp-block-group.has-surface-background-color > .wp-block-image:first-child img) {
	width: 100%;
	object-fit: cover;
}

/* Bento cards: number pill on the image (PoC ServiceCard look). */
:root :where(.service-card) {
	position: relative;
}

/* Deliberately without :where() and with a doubled class (0,3,0): core's
   editor CSS sets .block-editor-block-list__layout
   .block-editor-block-list__block to position:relative (0,2,0) and would
   otherwise tip the pill into the text flow in the editor (full width
   above the headline). */
.service-card .big-number-sm.big-number-sm {
	position: absolute;
	top: 1rem;
	left: 1rem;
	z-index: 1;
	margin: 0;
	font-size: 0.875rem;
	line-height: 1.4;
	color: var(--wp--preset--color--on-dark);
	background: rgba(30, 27, 24, 0.7);
	padding: 0.25rem 0.75rem;
	border-radius: 9999px;
	backdrop-filter: blur(4px);
}

/* Team teaser: roles dimmed as in the PoC (text-sm, ink/60). */
:root :where(.role-muted) {
	color: color-mix(in oklab, var(--wp--preset--color--ink) 60%, transparent);
	font-size: 0.875rem;
}

/* Team teaser (screenshot comparison Sektion 7, Plan 04-10, 768px): the
   same core word-break trap already reset for .beats-group-footer-label/
   -link (chrome.css) and .display-hero (sections.css) - WordPress core's
   ".wp-block-column { word-break: break-word; overflow-wrap: break-word; }"
   force-splits "Geschäftsführender" mid-word ("Geschäftsführende"/"r") as
   soon as the narrower core/columns width no longer fits it whole, while
   the PoC's wider Tailwind grid column (154px vs 128px measured live at
   768px) keeps the compound intact and only wraps at the space before
   "Gesellschafter". Reset here so a word that already fits one line never
   needs the forced-break fallback, matching the PoC's default wrapping.
   Scoped to .team-teaser-card (not a bare .role-muted, unlike the block
   above) - .role-muted also appears verbatim on section-team-cards.php's
   "Baustein - Team-Karten" library block (card-role role-muted), which
   isn't rendered by any of the 9 live pages and whose own column is wider
   (minimumColumnWidth: 18rem) than the failure mode this rule fixes. A
   bare selector would have reset word-breaking there too without ever
   having been checked against a long real-world role string on that
   block (Code-Review WR-02, Review Round after Plan 04-10). This also
   means the two .role-muted blocks in this file no longer share the same
   selector (Code-Review IN-01, same round) - one is project-wide
   (colour/font-size), the other Team-Teaser-only (word-break). */
:root :where(.team-teaser-card .role-muted) {
	word-break: normal;
	overflow-wrap: normal;
}

/* margin-left: 0 meant "to the left edge of the parent element" — and on
   the legal and contact pages that is the full-width section, not the
   centered content area. The heading sat 144px too far left there. The
   max() expression shifts it inward by half the overhang and becomes 0
   as soon as the container is already only contentSize wide anyway — so
   in every case with its own content group and on narrow screens. */

/* The hero H1 no longer needs a special width: the PoC uses max-w-4xl,
   and that's exactly what .mw-4xl does. The earlier manual adjustment to
   50rem forced a different line break than the original. */

/* Dark-stage sections (footer, methodology): links inherit on-dark, hover accent. */
:root :where(.wp-block-group.has-dark-background-color a:not(.wp-block-button__link)) {
	color: inherit;
}

:root :where(.wp-block-group.has-dark-background-color a:not(.wp-block-button__link):hover) {
	color: var(--wp--preset--color--accent);
}

/* Footer/dark links without underline (PoC: only a color change on hover). */
:root :where(.wp-block-group.has-dark-background-color a:not(.wp-block-button__link)) {
	text-decoration: none;
}

/* Outline button in the dark hero: the light variant must beat the base.css rule. */
.hero-video .wp-block-button.is-style-outline-ink > .wp-block-button__link {
	border-color: color-mix(in oklab, var(--wp--preset--color--on-dark) 40%, transparent);
	color: var(--wp--preset--color--on-dark);
}

.hero-video .wp-block-button.is-style-outline-ink > .wp-block-button__link:hover {
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--accent);
}

/* Footer divider: on-dark at 10% (previously an invalid inline style on the separator). */
:root :where(hr.beats-group-footer-divider) {
	border-color: color-mix(in srgb, var(--wp--preset--color--on-dark) 10%, transparent);
	background: none;
}

/* ------------------------------------------------------------------ */
/* Hero cover: core defaults the PoC doesn't have.                     */
/* ------------------------------------------------------------------ */

/* core/cover brings a blanket padding:1em (18px at 1.125rem base font
   size). In the PoC the hero has no padding of its own — the page
   margin comes from the container everywhere, as usual. Without
   resetting it, the hero text sits 18px instead of 16/24px from the
   edge. */
.wp-block-cover.hero-video,
.wp-block-cover.hero-gradient {
	padding: 0;
}

/* Core's `.wp-block-cover:not(.has-text-color) { color: #fff }` (0,2,0)
   turns the hero heading pure white; the PoC uses on-dark (#F5F1EA).
   Same specificity, but this file loads later — hence without
   :where(). */
.wp-block-cover.hero-video,
.wp-block-cover.hero-gradient {
	color: var(--wp--preset--color--on-dark);
}

/* core/cover with contentPosition sets `width:auto` on the inner
   container — it thereby shrinks to the content width (measured 867
   instead of 1440px) and the hero text sticks to the left edge. In the
   PoC the hero container is `mx-auto w-full max-w-6xl`, i.e. full width
   with a centered content column. */
.wp-block-cover.hero-video > .wp-block-cover__inner-container,
.wp-block-cover.hero-gradient > .wp-block-cover__inner-container {
	width: 100%;
	max-width: 100%;
	/* The container is a flex item; width:100% alone isn't enough against
	   core's width:auto, flex-grow is. */
	flex-grow: 1;
	/* Page margin belongs on the container, not on the group inside it —
	   otherwise one and the same element carries both margin AND content
	   width and the text shifts one gutter too far inward (same effect
	   as with .legal-narrow). */
	padding-inline: var(--bg-gutter);
}

/* Counterpart to that: the group inside the hero no longer brings its
   own page margin, but the content width instead. A constrained
   container in WordPress only bounds its children, not itself — without
   this max-width the hero column would run the full window width
   instead of contentSize. */
.wp-block-cover.hero-video .wp-block-cover__inner-container > .has-global-padding,
.wp-block-cover.hero-gradient .wp-block-cover__inner-container > .has-global-padding {
	padding-left: 0;
	padding-right: 0;
	max-width: var(--wp--style--global--content-size);
	margin-inline: auto;
}

/* Section height in the small instead of the large viewport unit (D-10).
   The PoC calculates in svh (min-h-[92svh]/[60svh] in
   HeroVideo.astro/LandingLayout.astro), core/cover doesn't know svh in
   its attribute and would discard an unsupported value on save (pitfall
   5, 01-RESEARCH.md) - the attribute therefore stays at vh, the
   conversion runs exclusively via these class rules. WordPress renders
   the height as style="min-height" directly on the element; no class
   rule without !important can beat that - D-06, the prototype wins, the
   unidiomatic spot carries this justification. On real devices with an
   expanding/collapsing address bar, vh/svh is a visible difference that
   none of the three measurement sources sees - they all run in the same
   headless browser without a browser chrome bar, where both units are
   equal (the svh-vs-vh exception is thereby dropped with no
   replacement). Order matters: the home-page hero carries both classes,
   at equal specificity the later rule wins - hence .hero-video comes
   after .hero-gradient. */
.wp-block-cover.hero-gradient {
	min-height: 60svh !important;
}

.wp-block-cover.hero-video {
	min-height: 92svh !important;
}

/* Number pill: the PoC uses font-bold (700) without a width axis, but
   .big-number brings 900 and wdth 120. */
.service-card .big-number-sm.big-number-sm {
	font-weight: 700;
	font-variation-settings: normal;
}

/* Line heights for the text-* sizes (see comment in chrome.css). */
:root :where(.eyebrow),
:root :where(.role-muted),
:root :where(.badge-row) {
	line-height: 1.25rem;
}

.service-card .big-number-sm.big-number-sm {
	line-height: 1.25rem;
}

/* Lead-in paragraphs (PoC: text-xl = 1.25rem / 1.75rem). */
:root :where(.lead) {
	line-height: 1.75rem;
}

/* Centered max-width utilities (PoC: mx-auto max-w-3xl resp. max-w-xl in
   the CTA box). Unlike .mw-4xl/.mw-2xl these stay centered — hence a
   dedicated class instead of a margin override. */
.mw-3xl-c.mw-3xl-c {
	max-width: 48rem;
}

.mw-xl-c.mw-xl-c {
	max-width: 36rem;
}

/* ------------------------------------------------------------------ */
/* Service card — behavior as in the PoC.                               */
/*                                                                     */
/* In the prototype, the whole card is an <a> (ServiceCard.astro:17):  */
/* click area, shadow on hover, and an image zoom. inc/service-card-   */
/* anchor.php rebuilds exactly that on render — the card's own wrapper */
/* becomes the <a>, so no stretched-link pseudo-element is needed here */
/* anymore (that mechanism measurably never worked to begin with: the  */
/* overlay sat on .card-cta, a <p>, which has no click action).        */
/* ------------------------------------------------------------------ */

:root :where(.service-card) {
	/* The radius now clips itself, the image doesn't need its own. */
	overflow: hidden;
	transition: box-shadow 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* theme.json's global link color (elements.link, accent-text) now applies
   to the card itself, and CSS color is inherited - without this, the
   heading would turn accent-text too. The PoC never has this problem:
   its <a> carries no color at all (Tailwind's preflight resets links to
   color: inherit), so only the CTA span opts into text-accent-text
   explicitly. Body text stays unaffected - services.css already sets an
   explicit color on every card paragraph except .card-cta. */
:root :where(.service-card .display-card) {
	color: var(--wp--preset--color--ink);
}

/* Arrow as pseudo-element (PoC: SVG with group-hover:translate-x-1). The
   CTA is plain text now — inc/service-card-anchor.php removes the
   nested <a>, so the arrow's layout moves from the (removed) link to
   its wrapping paragraph. */
:root :where(.service-card .card-cta) {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
}

:root :where(.service-card .card-cta)::after {
	content: "→";
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

:root :where(.service-card .wp-block-image img) {
	transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Tailwind itself gates hover: variants behind this query — so this here
   is parity, not a deviation. */
@media (hover: hover) {
	:root :where(.service-card:hover) {
		box-shadow:
			0 10px 15px -3px rgb(0 0 0 / 0.1),
			0 4px 6px -4px rgb(0 0 0 / 0.1);
	}

	:root :where(.service-card:hover .wp-block-image img) {
		transform: scale(1.03);
	}

	:root :where(.service-card:hover .card-cta)::after {
		transform: translateX(0.25rem);
	}
}

/* Eyebrow defaults to accent-text in the PoC; only on a dark background
   do the patterns explicitly set accent (color preset classes win with !important). */
:root :where(.eyebrow) {
	color: var(--wp--preset--color--accent-text);
}

/* CTA box: text-center sits on the box itself in the PoC, not just on the children. */
:root :where(.cta-box) {
	text-align: center;
}

/* ------------------------------------------------------------------ */
/* Text dimming as in the PoC.                                         */
/*                                                                     */
/* Tailwind mixes opacity modifiers (ink/80) in oklab — the same       */
/* color space here, otherwise the tone drifts measurably.             */
/* ------------------------------------------------------------------ */

/* Bullet lists of the image/text blocks: text-ink/80 */
:root :where(.dash-list li) {
	color: color-mix(in oklab, var(--wp--preset--color--ink) 80%, transparent);
}

/* CTA text: text-ink/75 */
:root :where(.mw-xl-c) {
	color: color-mix(in oklab, var(--wp--preset--color--ink) 75%, transparent);
}
