/**
 * BEATS GROUP — Base styles + utility classes.
 *
 * 1:1 port of the design tokens from the approved Astro PoC
 * (src/styles/global.css) onto the block theme. Uses exclusively preset
 * variables from theme.json (--wp--preset--…), no hex values.
 *
 * Loaded via functions.php on enqueue_block_assets — so it takes effect
 * identically in frontend AND block-editor iframe.
 */

/* ------------------------------------------------------------------ */
/* Base (reset/baseline behavior) — deliberately NOT wrapped in       */
/* :where(), since these are global element rules analogous to the    */
/* PoC.                                                                */
/* ------------------------------------------------------------------ */

/* ------------------------------------------------------------------ */
/* Breakpoint-aware dimensions.                                        */
/*                                                                     */
/* Tailwind switches hard at its breakpoints (px-4 sm:px-6), but a     */
/* WordPress spacing slug only knows a single value. The jump therefore*/
/* lives here, and theme.json resp. the patterns only reference the    */
/* variable. sm = 40rem, md = 48rem, lg = 64rem (Tailwind 4).          */
/* ------------------------------------------------------------------ */

:root {
	--bg-gutter: 1rem;         /* px-4  → sm:px-6   (every container)   */
	--bg-sec: 4rem;            /* py-16 → sm:py-24  (standard section)  */
	--bg-sec-sm: 4rem;         /* py-16 → sm:py-20  (logo band, team, …) */
	--bg-hero-bottom: 2.5rem;  /* pb-10 → sm:pb-14  (HeroFlat)          */
	--bg-lead-y: 3rem;         /* pb-12 → sm:pb-16  (landing hero, CTA) */
	--bg-band: 3.5rem;         /* py-14 → sm:py-16  (food formula)      */
	--bg-cta-x: 1.5rem;        /* px-6  → sm:px-12  (CTA box)           */
	--bg-card-p: 1.5rem;       /* p-6   → sm:p-8    (list/people cards) */
	--bg-card-p-sm: 1.5rem;    /* p-6   → sm:p-7    (service cards)     */
}

@media (min-width: 40rem) {
	:root {
		--bg-gutter: 1.5rem;
		--bg-sec: 6rem;
		--bg-sec-sm: 5rem;
		--bg-hero-bottom: 3.5rem;
		--bg-lead-y: 4rem;
		--bg-band: 4rem;
		--bg-cta-x: 3rem;
		--bg-card-p: 2rem;
		--bg-card-p-sm: 1.75rem;
	}
}

html {
	scroll-behavior: smooth;
}

body {
	-webkit-font-smoothing: antialiased;
}

/* line-height 1.05 sits on the heading elements, not on the display
   classes — matching the PoC (site/src/styles/global.css:33-40). The
   display classes below deliberately no longer set line-height: a
   non-heading element that borrows a display class (e.g. the Foodformel
   <p class="display-section"> in service-page-concepts.php) must inherit
   body's 1.6 the same way its PoC counterpart does. */
h1,
h2,
h3,
h4 {
	text-wrap: balance;
	line-height: 1.05;
}

::selection {
	background-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--on-dark);
}

:focus-visible {
	outline: 3px solid var(--wp--preset--color--accent);
	outline-offset: 3px;
}

/* ------------------------------------------------------------------ */
/* Display typography utilities (Archivo, variable "wdth" axis)       */
/* ------------------------------------------------------------------ */

:root :where(.display-hero) {
	font-family: var(--wp--preset--font-family--archivo);
	font-variation-settings: "wdth" 118;
	font-weight: 900;
	text-transform: uppercase;
	letter-spacing: -0.01em;
	font-size: var(--wp--preset--font-size--hero);
}

:root :where(.display-section) {
	font-family: var(--wp--preset--font-family--archivo);
	font-variation-settings: "wdth" 112;
	font-weight: 800;
	font-size: var(--wp--preset--font-size--section);
}

:root :where(.display-card) {
	font-family: var(--wp--preset--font-family--archivo);
	font-variation-settings: "wdth" 110;
	font-weight: 800;
	font-size: var(--wp--preset--font-size--card);
}

/* Header, page content and footer sit flush against each other (as in the
   PoC). WordPress otherwise inserts the global block gap between the root
   blocks (24px light gap below the header and above the footer). The
   sections bring their own spacing via their padding. body prefix, so
   the rule wins against the core rule `.wp-site-blocks > * + *`
   regardless of load order. */
body .wp-site-blocks > * + * {
	margin-block-start: 0;
}

/* ------------------------------------------------------------------ */
/* Narrow viewports: long compound words must not widen the page       */
/* ------------------------------------------------------------------ */

/* The inner container of a cover block is a flex item and, via
   min-width:auto, refuses to shrink below its min-content width. A
   heading like "Franchise-/Lizenzberatung" thereby pulls the whole
   document wider than the screen — the browser zooms out and horizontal
   scrolling appears. In the Astro PoC the same container is a plain
   block element and therefore stays narrow. */
.wp-block-cover__inner-container {
	min-width: 0;
}

/* Second line of defense for headings without a cover (e.g.
   "Datenschutzerklärung"): hyphenate instead of overflow. German
   hyphenation patterns apply via lang="de-DE" on <html>. */
:root :where(.display-section, .display-card) {
	hyphens: auto;
	overflow-wrap: break-word;
	/* Customer feedback Z28: "es ist nicht schön, dass in den Überschriften so
	   oft die Worte getrennt werden müssen. getrennte Worte lassen sich
	   schlechter lesen." Auto-hyphenation stays as the overflow guard the
	   comment above describes, but only for words that genuinely need it:
	   nothing under 14 characters breaks at all ("Expansion", "persönlich",
	   "Qualität"), and what does break keeps at least six characters on each
	   side. A long compound that fits on its own line is never split, because
	   hyphenation only ever fires on a line that does not fit.

	   14 is the ceiling, not a round number: measured at 21, the theme drops
	   "Markenpositionierung" past the hyphenation dictionary and the
	   overflow-wrap:break-word above takes over instead - the card then reads
	   "Markenpositionierun / g und -kommunikation", a silent mid-word break
	   with no hyphen at all. A dictionary break point beats that.
	   Counterpart: site/src/styles/global.css. */
	hyphenate-limit-chars: 14 6 6;
}

/* Heroes hyphenate ONLY at set points: auto-hyphenation picked ugly
   dictionary break points at large sizes ("SYSTEMGAS-TRONOMIE",
   "DATENSCHUTZER-KLÄRUNG").

   overflow-wrap is deliberately set to normal — as in the PoC. With
   break-word, Chrome wrapped every one of the five hero headings one
   line earlier than the prototype (measured: 168 instead of 252px on
   four service pages). The overflow protection this rule once existed
   for now comes from min-width:0 on the cover container further up;
   it's only needed below the narrowest measured width, where
   "Datenschutzerklärung" also runs off frame in the PoC. */
:root :where(.display-hero) {
	hyphens: manual;
	overflow-wrap: normal;
}

@media (max-width: 374.98px) {
	:root :where(.display-hero) {
		overflow-wrap: break-word;
	}
}

/* ------------------------------------------------------------------ */
/* Column parity with the PoC (Tailwind sm=40rem, md=48rem, lg=64rem)  */
/* ------------------------------------------------------------------ */

/* WP's auto-fill grids don't know breakpoints: the 3-card rows stood at
   two columns at 768px, the PoC jumps straight from 1 to 3 at lg. The
   classes come from the patterns; minimumColumnWidth stays as a fallback
   in the markup. body prefix beats the generated .wp-container-*
   rules. */
body .is-layout-grid:where(.grid-3-lg, .grid-2-sm, .grid-2-md, .grid-4-lg) {
	grid-template-columns: minmax(0, 1fr);
}

body .is-layout-grid.logo-band {
	grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (min-width: 40rem) {
	body .is-layout-grid:where(.grid-2-sm, .grid-4-lg) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	body .is-layout-grid.logo-band {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

@media (min-width: 48rem) {
	body .is-layout-grid.grid-2-md {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64rem) {
	body .is-layout-grid.grid-3-lg {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	body .is-layout-grid.grid-4-lg {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	body .is-layout-grid.logo-band {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}
}

:root :where(.big-number) {
	font-family: var(--wp--preset--font-family--archivo);
	font-variation-settings: "wdth" 120;
	font-weight: 900;
	font-size: clamp(3rem, 6vw, 5rem);
	line-height: 1;
	color: var(--wp--preset--color--accent);
}

/* ------------------------------------------------------------------ */
/* Scroll reveal — subtle, activated via JS (assets/js/main.js sets   */
/* the class "js" on <html> and toggles "is-visible" via observer).   */
/* Without JS/under reduced motion, everything stays visible          */
/* immediately.                                                        */
/* ------------------------------------------------------------------ */

:root :where(.reveal) {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: no-preference) {
	/* html is itself :root — so select directly on html.js. */
	html.js :where(.reveal) {
		opacity: 0;
		transform: translateY(16px);
		transition:
			opacity 0.6s ease,
			transform 0.6s ease;
	}

	html.js :where(.reveal.is-visible) {
		opacity: 1;
		transform: none;
	}
}

/* ------------------------------------------------------------------ */
/* Logo band — grayscale, color on hover                              */
/* ------------------------------------------------------------------ */

:root :where(.logo-band img) {
	filter: grayscale(1);
	opacity: 0.7;
	transition:
		filter 0.3s ease,
		opacity 0.3s ease;
}

:root :where(.logo-band img:hover) {
	filter: none;
	opacity: 1;
}

/* ------------------------------------------------------------------ */
/* Button block style "Outline" (core/button, is-style-outline-ink)   */
/* see inc/block-styles.php                                           */
/* ------------------------------------------------------------------ */

/* Higher specificity needed: theme.json button styles (global styles) load after base.css. */
.wp-block-button.is-style-outline-ink > .wp-block-button__link {
	background-color: transparent;
	color: var(--wp--preset--color--ink);
	border: 2px solid color-mix(in srgb, var(--wp--preset--color--ink) 20%, transparent);
	border-radius: 9999px;
	transition:
		border-color 0.2s ease,
		color 0.2s ease;
}

.wp-block-button.is-style-outline-ink > .wp-block-button__link:hover {
	background-color: transparent;
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--accent);
}

/* ------------------------------------------------------------------ */
/* Sticky header                                                      */
/* ------------------------------------------------------------------ */

:root :where(.site-header-sticky) {
	position: sticky;
	top: 0;
	z-index: 40;
	backdrop-filter: blur(8px);
	background: color-mix(in srgb, var(--wp--preset--color--bg) 90%, transparent);
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--ink) 10%, transparent);
}

/* Header: logo/title link and nav inherit ink, no underline (PoC). */
:root :where(.site-header-sticky a:not(.wp-block-button__link)) {
	color: inherit;
	text-decoration: none;
}

/* As long as the burger is active (below 72rem since 22.09.2026, see
   chrome.css "Umschaltpunkt"), core/navigation opens its menu as a
   position:fixed overlay. But backdrop-filter on the header creates a
   containing block and traps exactly this overlay at header height —
   only the first menu item then stays visible. Hence no blur there, but
   an opaque background instead, so the header still stays visually
   separated from the content. The range MUST match the burger band. */
@media (width < 72rem) {
	:root :where(.site-header-sticky) {
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
		background: var(--wp--preset--color--bg);
	}
}

/* ------------------------------------------------------------------ */
/* Text dimming.                                                       */
/*                                                                     */
/* The prototype dims body text with Tailwind's opacity modifier       */
/* (text-ink/80, text-on-dark/85). Only the full color had been ported */
/* so far — which is why lead-ins and card text in the theme looked    */
/* consistently too harsh. color-mix against transparent scales only   */
/* the alpha channel, so it is exactly the same as rgb(… / .8), and    */
/* unlike opacity it only affects the text, not child elements.        */
/* ------------------------------------------------------------------ */

/* Tailwind mixes in oklab; the same color space here, otherwise the tone
   drifts measurably. Double class (0,2,0), because the card and cover
   rules of the other files would otherwise win — these paragraphs are
   spared color presets, their attribute has been removed (see CLAUDE.md:
   has-*-color comes with !important and cannot be beaten by any theme
   rule). */

.ink-80.ink-80 {
	color: color-mix(in oklab, var(--wp--preset--color--ink) 80%, transparent);
}

.ink-75.ink-75 {
	color: color-mix(in oklab, var(--wp--preset--color--ink) 75%, transparent);
}

.on-dark-85.on-dark-85 {
	color: color-mix(in oklab, var(--wp--preset--color--on-dark) 85%, transparent);
}

.on-dark-75.on-dark-75 {
	color: color-mix(in oklab, var(--wp--preset--color--on-dark) 75%, transparent);
}

/* Team teaser and membership cards carry both display-card AND text-lg in
   the PoC — i.e. 18px/28px instead of the full card size. Tailwind's
   text-* sets both, hence the line height sits here too. Double class,
   because .display-card carries the same weight. */
.card-title-lg.card-title-lg {
	font-size: 1.125rem;
	line-height: 1.75rem;
}

/* ------------------------------------------------------------------ */
/* core/columns wrap point.                                             */
/*                                                                     */
/* Core always stacks columns at 782px — the PoC uses Tailwind's        */
/* breakpoints (sm 640, md 768, lg 1024). Without these classes the     */
/* footer stood single-column at 768px (the page was 667px taller       */
/* there than the prototype) and so did the team teaser. Same           */
/* systematics as the grid-* classes further up, just for flex          */
/* columns.                                                             */
/* ------------------------------------------------------------------ */

body .wp-block-columns:where(.cols-sm, .cols-md, .cols-lg) {
	flex-wrap: wrap !important;
}

body .wp-block-columns:where(.cols-sm, .cols-md, .cols-lg) > .wp-block-column {
	flex-basis: 100% !important;
	flex-grow: 0 !important;
}

@media (min-width: 40rem) {
	body .wp-block-columns.cols-sm {
		flex-wrap: nowrap !important;
	}

	body .wp-block-columns.cols-sm > .wp-block-column {
		flex-basis: 0 !important;
		flex-grow: 1 !important;
	}
}

@media (min-width: 48rem) {
	body .wp-block-columns.cols-md {
		flex-wrap: nowrap !important;
	}

	body .wp-block-columns.cols-md > .wp-block-column {
		flex-basis: 0 !important;
		flex-grow: 1 !important;
	}
}

@media (min-width: 64rem) {
	body .wp-block-columns.cols-lg {
		flex-wrap: nowrap !important;
	}

	body .wp-block-columns.cols-lg > .wp-block-column {
		flex-basis: 0 !important;
		flex-grow: 1 !important;
	}

	/* Image/text sections with the image on the right: in the PoC the
	   image always sits first in the DOM and only shifts right from lg
	   onward — stacked, it therefore sits on top. */
	.beats-group-media-right > .wp-block-column:first-child {
		order: 2;
	}
}

/* "Datenschutzerklärung" doesn't fit on one line on narrow screens — in
   the PoC the heading there runs 248px off frame. The theme hyphenates
   instead. A literal soft hyphen in the text used to handle this; that
   cost a whole line at 1440px, because Chrome uses the break point even
   when the word fits. As a rule it only takes effect where it's
   needed. */
@media (max-width: 767.98px) {
	:root :where(.hero-trennen-schmal) {
		hyphens: auto;
		overflow-wrap: break-word;
	}
}

/* Role under a team card's name: text-sm in the PoC, i.e. 14px/20px. */
.card-role.card-role {
	font-size: 0.875rem;
	line-height: 1.25rem;
}
