/**
 * Silvalue — patterns.css
 *
 * Small, dependency-free layout rules the block editor's own block
 * attributes cannot express, needed by the bildlose Startseiten-Muster
 * (docs/entscheidungen/leistungsstruktur.md, docs/nz/home-plan.md 5.2.C).
 * Colour, type and spacing values stay tokens (referenced from the
 * patterns themselves via var(--wp--preset--...)); only the grid/order
 * mechanics live here, exactly like assets/css/header.css already does
 * for the desktop/mobile logo swap.
 */

/* ---------------------------------------------------------------------
 * Proof bar (silvalue/proof-bar-de, silvalue/proof-bar-en)
 * 3 columns desktop, 2 from 782px down, 1 from 600px down
 * (docs/nz/home-plan.md 5.2.B) — a plain CSS grid, since core/columns
 * only supports a single stack breakpoint, not this two-step layout.
 *
 * Column count corrected 2026-09-13 (was `repeat(4, 1fr)`): the reference
 * mockup (design/silvalue-at-design-v3.html, `.panel`) was built for four
 * fields, but this project's own approved content (CLAUDE.md Abschnitt 4)
 * has always had exactly three. With four defined columns and three real
 * items, the grid still auto-placed them one-per-column at an EQUAL
 * width each — confirmed by measuring the live rendered page, not
 * assumed: all three were exactly 319.5px wide at 1440px viewport width —
 * but that left a whole fourth 319.5px column empty on the right, so the
 * three items only filled three quarters of the bar, not the full width
 * evenly split into thirds. Three columns for three items fixes this
 * directly.
 *
 * Second bug, 2026-09-13, same symptom the 2026-09-02 fix (below) only
 * partly addressed: items 2 and 3 sat 32px lower than item 1, sharing
 * its BOTTOM edge instead of starting level with it — confirmed by
 * measuring the live page, not assumed. Cause, confirmed the same way:
 * `.sv-proof-bar` itself carries WordPress's own `is-layout-flow` class
 * (every block with `"layout":{"type":"default"}` gets it) alongside
 * this file's `display:grid` override — and WordPress's global rule for
 * that class (`:root :where(.is-layout-flow) > *{margin-block-start:
 * var(--wp--preset--spacing--md)}`, exempting only the first child) still
 * applies a real, unconditional top MARGIN to every child but the first,
 * regardless of that block's own "blockGap" attribute (which the
 * 2026-09-02 fix below removed — a different, opt-in source of the same
 * kind of margin, not this unconditional default one). Grid layout does
 * not cancel an item's own margin: `align-items`/`gap` only govern
 * spacing and sizing *within* the grid's own box model, so this stray
 * `margin-block-start: 32px` (the theme's "md" spacing at this viewport)
 * on items 2/3 only stacked on top of that. Zeroed below, on the items
 * themselves this time — the existing `.sv-proof-bar__item > * {
 * margin-block-start: 0}` rule (further down) only ever reached each
 * item's own *children*, never the items themselves.
 *
 * `align-items: stretch` added 2026-09-13: every item's box now fills
 * the shared row height, and normal block content always starts flowing
 * from the top of its own box regardless of that box's height — so
 * mark/stat/context now start at the same row position in all three
 * items no matter how the context line wraps, and the column-divider
 * borders (`.sv-proof-bar__item`, below) now span the full, equal row
 * height in every item too instead of stopping wherever that one item's
 * own shorter content happened to end. */
.sv-proof-bar {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	align-items: stretch;
	/* Real CSS gap, not the block's own "blockGap" spacing attribute —
	   added 2026-09-02, reviewer finding. The outer group's block layout
	   type is "default" (flow), so a "blockGap" attribute makes WordPress
	   emit a flow-style ">*{margin-block-start:...}" rule instead of a
	   grid "gap" — harmless while this was flow-laid-out visually, but
	   once "display:grid" is applied here, that stray margin pushes item
	   2 and 3 down against item 1 instead of spacing all three evenly in
	   the grid's own inline direction, so the three items no longer lined
	   up. The attribute is removed from the pattern files; this "gap" is
	   the only spacing mechanism between items now. (This turned out to
	   be one of two sources of the same kind of stray margin, not the
	   only one — see the second bug noted above, fixed 2026-09-13.) */
	gap: var(--wp--preset--spacing--md);
	/* Overlaps the hero's bottom edge (silvalue/home-hero-de/-en) — value
	   matches the approved reference implementation's own overlap amount
	   (design/silvalue-at-design-v3.html, .panel-wrap), not an invented
	   number. position/z-index make sure the card visually sits on top of
	   the hero rather than being clipped underneath it. */
	position: relative;
	z-index: 5;
	margin-top: -72px;
}

@media (max-width: 781px) {
	.sv-proof-bar {
		margin-top: -40px;
	}
}

/* NACHTRAG 2026-09-28 — Betreiberauftrag "gestalterische Vereinheitlichung
 * und responsive Qualitätsprüfung" (Prompt 3), Punkt 3: bei 768px wirkten
 * die drei Kennzahlen unbeabsichtigt wie "zwei Elemente plus isoliertes
 * drittes Element" — Ursache war die vorherige Zwischenstufe hier
 * (max-width:781px, repeat(2,1fr)): Element 3 rutschte dadurch allein in
 * eine zweite Zeile, exakt so breit wie Element 1 in der Zeile darüber,
 * optisch unausgewogen.
 *
 * Live nachgemessen bei 768px: drei gleich breite Spalten (repeat(3,1fr),
 * die Grundeinstellung oben, jetzt bis hier unverändert wirksam) ergeben
 * pro Feld ca. 211px — spürbar mehr Platz als die ebenfalls dreispaltigen
 * Leistungskarten direkt darunter (dort bereits 204px pro Karte, dort
 * bereits mit Bild+Titel+Auszug ohne Umbruchprobleme). Die Zwischenstufe
 * war damit nicht nötig, um Platzmangel zu vermeiden — sie hat das
 * Problem erst erzeugt. Entfernt (nicht nur die Spaltenzahl, sondern die
 * gesamte 781px-Sonderregel für die Spaltenzahl): jetzt bleiben es drei
 * gleichmäßige Spalten von 782px bis hinunter zu 600px, danach greift
 * unverändert die bestehende 599px-Einspaltenregel unten. */
@media (max-width: 599px) {
	.sv-proof-bar {
		grid-template-columns: 1fr;
	}
}

/* Proof bar item structure — 2026-09-02, built to match the approved
   reference (design/silvalue-at-design-v3.html, .panel b/span at the
   time): the stat in its own larger/bolder element, then the context
   line smaller and muted — two separate elements, not one paragraph.
   Previously each item was a single wp:paragraph combining both parts in
   one font-size, which is why the longest one (the hectare figure)
   wrapped across four lines instead of reading as a short stat.
   The wording itself is untouched — CLAUDE.md section 4's exact approved
   phrases are only split at an existing word boundary between the two
   elements (e.g. "54.000 ha" / "kumuliert über zwei Jahrzehnte
   Projekterfahrung"), never reworded or shortened.
   A third element, a short accent mark above the stat (`.sv-proof-bar__mark`,
   matching the reference's `.panel i`), was part of this same 2026-09-02
   build and removed again 2026-09-13, `[FEST]` — pure decoration, no
   longer wanted (see design/silvalue-at-design-v3.html for the discarded-
   reference note). */

/* Zeroes the stray `margin-block-start` WordPress's global "is-layout-
   flow" default puts on every `.sv-proof-bar__item` but the first (see
   the long note on `.sv-proof-bar` above, added 2026-09-13, for the full
   diagnosis) — this is the item itself, not its children (the very
   similar-looking rule below handles those separately). Without this,
   `align-items: stretch` above cannot do its job: a real top margin
   still shifts items 2 and 3 down inside their own grid row regardless
   of how the row's items are aligned/stretched.
 *
 * `display: flex` + `flex-direction: column` + `justify-content: center`
 * added 2026-09-14, Betreiberwunsch: stat and context line centred both
 * horizontally and vertically within each field, not left/top-aligned.
 * `text-align: center` handles the horizontal part, including a context
 * line that wraps to a second line. `justify-content: center` handles
 * the vertical part — it centres the two paragraphs as a group within
 * whatever height `align-items: stretch` (on `.sv-proof-bar` above) has
 * given this item, which is the *same* height in all three items
 * regardless of their own content. Deliberately not `align-items`
 * on this flex container: its default, "stretch", is exactly what is
 * wanted here too — each paragraph still spans the item's full width, so
 * `text-align: center` centres wrapped text within that full width
 * rather than within an already content-width-shrunk box. */
.sv-proof-bar__item {
	margin-block-start: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	text-align: center;
}

/* Item-internal spacing (stat -> context line), added 2026-09-02,
   reviewer finding: each item group has no blockGap attribute of its own,
   so its children fell back to the theme's *global* blockGap default
   (styles.spacing.blockGap in theme.json, "md" = 24-32px, WordPress's
   own ":root :where(.is-layout-flow) > *{margin-block-start:...}" rule)
   instead of the reference's tight 9px rhythm (design/silvalue-at-
   design-v3.html, ".panel span{margin-top:9px}") — stat and context line
   read as two loosely related lines instead of one stat. Zeroed here and
   reset explicitly below; this class-based selector already beats the
   global rule's ":where()" (zero specificity) without needing
   "!important". (Originally "mark -> stat -> context line" while the now-
   removed accent mark, above, was still part of this pattern.) */
.sv-proof-bar__item > * {
	margin-block-start: 0;
}

.sv-proof-bar__item > p + p {
	margin-top: 9px;
}

/* Context-line size — one step down from "sm", added 2026-09-13,
 * Betreiberentscheidung: the context line read too large next to the
 * stat above it. The obvious next step down in the named scale is `ui`
 * (13px) — deliberately NOT used here: CLAUDE.md Abschnitt 6 reserves
 * `ui` exclusively for controls/navigation precisely so that reservation
 * stays meaningful, and a context line under a stat is body text, not a
 * control. The scale otherwise has no step between `ui` (13px) and `sm`
 * (14-15px, `clamp(0.875rem, 0.849rem + 0.11vw, 0.9375rem)`) — CLAUDE.md
 * Abschnitt 6 now documents that gap explicitly, so the next case that
 * wants something smaller than `sm` doesn't reach for `ui` by default
 * either. 13.5px is a one-off value for this exact use, not a new named
 * token: a scale entry would invite reuse in places `ui`'s reservation
 * is meant to rule out just as much as `ui` itself would have.
 *
 * Plain, unqualified declaration is enough — no `!important` needed:
 * this class carries no font-size at all otherwise (the paragraph no
 * longer carries a `fontSize` block attribute/`has-*-font-size` class,
 * which WordPress always renders with `!important` and which a plain
 * override here would otherwise have to out-fight). */
.sv-proof-bar__context {
	font-size: 13.5px;
}

/* Column dividers between items — desktop: vertical line to the right of
   every item but the last (matching the reference's own ".panel div
   {border-right}" + ":last-child{border-right:0}" exactly, rather than a
   mirrored "border-left on every item but the first": with three items in
   a grid that can hold 2 or 4 columns, the two are not equivalent — the
   reference's approach leaves the item that wraps onto its own new row
   without a stray divider, since it is always the true last child
   regardless of which row it lands on).
   The vertical divider is kept through the 781px 2-column breakpoint too
   (reviewer finding: the reference keeps it at its own mobile breakpoint,
   ".page.mobile .panel div" only *adds* a bottom border, it does not
   remove the right one) and only replaced by a horizontal one once the
   grid itself drops to a single column at 599px, where a right-hand line
   would no longer sit next to anything. */
.sv-proof-bar__item {
	padding-right: var(--wp--preset--spacing--sm);
}

.sv-proof-bar__item:not(:last-child) {
	border-right: 1px solid var(--wp--preset--color--sv-line-soft);
}

@media (max-width: 781px) {
	.sv-proof-bar__item:not(:last-child) {
		border-bottom: 1px solid var(--wp--preset--color--sv-line-soft);
		padding-bottom: var(--wp--preset--spacing--sm);
	}
}

@media (max-width: 599px) {
	.sv-proof-bar__item {
		padding-right: 0;
	}

	.sv-proof-bar__item:not(:last-child) {
		border-right: none;
	}
}

/* ---------------------------------------------------------------------
 * Approach section (silvalue/home-approach-de, -en)
 * "Bild rechts Desktop, oben mobil" (docs/nz/home-plan.md 5.2.C): the
 * media column is written first in the pattern's own markup so it is
 * naturally on top once the columns stack on mobile; this rule only
 * reorders the two columns visually from 782px up, so the image lands on
 * the right on desktop without changing the underlying DOM order.
 * ------------------------------------------------------------------- */
@media (min-width: 782px) {
	.sv-approach-media-col {
		order: 2;
	}

	.sv-approach-text-col {
		order: 1;
	}
}

/* ---------------------------------------------------------------------
 * Hero (silvalue/home-hero-de, silvalue/home-hero-en)
 *
 * CLAUDE.md section 6, "Hero-Konzept, präzisiert 2026-08-22" (Variante A —
 * photo leads, contour lines are an accent on top of it, never the other
 * way round). Stack, bottom to top: sv-hero__photo (background photo or
 * its missing-photo placeholder fill) -> sv-hero__contour (the existing
 * silvalue_render_contour_overlay(), see below for opacity/fade) ->
 * sv-hero__scrim (the left-to-right darkening gradient) -> sv-hero__inner
 * (the actual, editable copy). All three backdrop layers are absolutely
 * positioned inside sv-hero__backdrop, which itself sits inside sv-hero
 * (position: relative) — this is plain CSS layering, not a page-builder
 * grid.
 * ------------------------------------------------------------------- */
.sv-hero {
	position: relative;
	overflow: hidden;
	/* Raised from 620px to 760px, 2026-09-02 — real hero photo is
	   2400x1058px (ratio ~2.2684:1, verified against the actual Media
	   Library attachment, not assumed). Width tracks the viewport while
	   this min-height stays fixed, so background-size:cover crops
	   vertically off the top (background-position:center bottom, see
	   .sv-hero__photo below) whenever viewport-width > min-height x
	   photo-ratio. At 620px that crop-free point was ~1406px — most real
	   desktop widths (1440, 1920, 2560) already crop enough off the top to
	   lose the "Gegenhang" (the far hillside) the photo was chosen for. At
	   760px the crop-free point moves to ~1724px, so 1440px and 1024px
	   (both required test widths) show the photo with zero vertical crop;
	   even 1920px only loses ~10% off the top instead of ~27%. Chosen over
	   a value tuned to remove all cropping at 1920px (~846px) as a
	   deliberately smaller increase — enough headroom past the two
	   required desktop widths without making the section unusually tall
	   on the many laptop screens in the 1300-1700px range.

	   Coupled to the viewport height, 2026-09-03 — Betreiberbefund: a
	   fixed 760px pushes .sv-proof-bar (which overlaps this section's
	   bottom edge by -72px, see that rule below) entirely below the fold
	   on common laptop screens (1366x768, 1280x800 — effective browser
	   viewport height after chrome is well under header height 95px +
	   760px). docs/at/home-plan.md assigns the Proof Bar the job of
	   "sofortige Substantiierung, bevor der Besucher scrollt" — invisible
	   before scrolling fails that outright, on exactly the screen sizes
	   most desktop visitors actually have. clamp() with three parts:
	     - floor 480px: never shrinks the copy column below the height its
	       own content needs. Verified on a real, disposable test page at
	       very short viewports (see chat log 2026-09-03) — H1 (2 lines,
	       4xl), subline (2 lines, lg) and button still read with normal
	       spacing at 480px, nothing overlaps or gets clipped.
	     - preferred calc(100vh - var(--sv-header-height)): shrinks the
	       hero to exactly fill the viewport below the fixed-height header,
	       so the hero's own bottom edge sits right at the fold. Because
	       .sv-proof-bar overlaps upward by 72px, that leaves the top 72px
	       of the proof bar (padding + accent marks + the start of each
	       figure) visible above the fold on any screen shorter than
	       760px + header — a deliberately partial, "cut off" reveal
	       (Betreiber: "ein sichtbarer Rand genügt"), not full visibility.
	     - ceiling 760px: the value tuned above for the Gegenhang crop —
	       tall viewports must not grow the hero past what that crop
	       calculation assumes. */
	min-height: clamp(480px, calc(100vh - var(--sv-header-height)), 760px);
}

@media (max-width: 781px) {
	.sv-hero {
		min-height: 520px;
	}
}

.sv-hero__backdrop {
	position: absolute;
	inset: 0;
	z-index: 0;
}

/*
 * `background-position: center bottom` (changed from plain `center`,
 * 2026-08-27) — the hero's height is fixed (`.sv-hero{min-height:...}`,
 * see that rule above for the current value and the crop-free viewport
 * width it implies — not repeated here to avoid a second, driftable copy
 * of the same number, CLAUDE.md Abschnitt 11 Punkt 7) while its width
 * tracks the full viewport, so above that crop-free width `cover` must
 * crop vertically to fill the box. Found on the real rendered page:
 * with plain `center`, that crop removed equal amounts off the top and
 * the bottom — cutting off a forest path at the photo's bottom edge that
 * was the entire reason that photo was chosen. Anchoring to the bottom
 * instead means any vertical crop always comes off the top, so whatever
 * sits at the bottom of the source photo is never cropped, regardless of
 * viewport width. This is a permanent constraint on which photos work
 * here, not just a one-off CSS fix — see CLAUDE.md section 6, "Hero-Foto
 * — Motiv gehört in die untere Bildhälfte".
 */
.sv-hero__photo {
	position: absolute;
	inset: 0;
	background-repeat: no-repeat;
	background-position: center bottom;
	background-size: cover;
}

/* B1 (2026-10-08): the photo is now an <img> inside this wrapper (see
   silvalue_render_hero_photo_layer()); same crop rule as the old
   background-position:center bottom / background-size:cover. */
.sv-hero__photo {
	overflow: hidden;
}

.sv-hero__photo picture {
	display: block;
	width: 100%;
	height: 100%;
}

.sv-hero__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center bottom;
}

/* Unmissable stand-in while no Customizer photo is set yet (CLAUDE.md
   Arbeitsregel 3) — a plain sv-ink fill here would be indistinguishable
   from a deliberately dark photo, so this gets its own visible pattern
   in addition to the real, non-hidden placeholder paragraph the pattern
   file prints in the copy column. */
.sv-hero__photo--missing {
	background-color: var(--wp--preset--color--sv-ink);
	background-image: repeating-linear-gradient(
		45deg,
		rgba(255, 255, 255, 0.08) 0,
		rgba(255, 255, 255, 0.08) 2px,
		transparent 2px,
		transparent 16px
	);
}

/* Left-to-right fade, added 2026-08-27: the lines used to run unmasked
   straight through the headline, competing with the text there. Values
   below are plain CSS custom properties (not `--wp--preset--...` design
   tokens), grouped here for easy retuning without touching the rules
   themselves:
     --sv-hero-contour-opacity     peak opacity, reached at the fade's
                                    right-hand end (fade-end below).
                                    History, all 2026-08-27: 34% (original)
                                    -> 20% ("more subdued" request, together
                                    with a lower stroke-width and the new
                                    fade below — too much reduced at once)
                                    -> 45% (corrected once, still read as
                                    too weak on the real rendered page,
                                    stroke-width/fade left alone) -> 60%
                                    (corrected again, same day, this time
                                    the only variable changed). This is the
                                    number to retune first if it still needs
                                    adjusting; leave stroke-width (base.css)
                                    and the fade shape below alone unless
                                    there's a specific reason — changing one
                                    variable at a time is how both
                                    overcorrections above were diagnosed.
     --sv-hero-contour-fade-start  where the fade begins leaving full
                                    transparency (as a % of hero width)
     --sv-hero-contour-fade-end    where it reaches --sv-hero-contour-
                                    opacity fully — 30%/80% put the whole
                                    left half at a small fraction of peak
                                    opacity ("practically invisible" per
                                    the operator's wording) and stay fully
                                    visible from 80% on, roughly following
                                    the shape (not the exact stops) of
                                    .sv-hero__scrim's own 86%->32% left-
                                    to-right darkening below — the two
                                    gradients are deliberately not required
                                    to share exact percentages, only the
                                    same left-dark/right-light direction.
                                    Confirmed still correct 2026-08-27 —
                                    the mask itself was never the problem,
                                    only the combination with the lower
                                    opacity/stroke-width above. */
:root {
	--sv-hero-contour-opacity: 0.6; /* 0.45 still read as too weak on the
	                                   real rendered page, 2026-08-27 —
	                                   raised again; stroke-width and the
	                                   fade shape left untouched this time,
	                                   one variable at a time. */
	--sv-hero-contour-fade-start: 30%;
	--sv-hero-contour-fade-end: 80%;
}

.sv-hero__contour {
	position: absolute;
	inset: 0;
	opacity: var(--sv-hero-contour-opacity);
	-webkit-mask-image: linear-gradient(
		90deg,
		transparent 0%,
		transparent var(--sv-hero-contour-fade-start),
		black var(--sv-hero-contour-fade-end),
		black 100%
	);
	mask-image: linear-gradient(
		90deg,
		transparent 0%,
		transparent var(--sv-hero-contour-fade-start),
		black var(--sv-hero-contour-fade-end),
		black 100%
	);
}

/* Narrow viewports: .sv-hero__scrim below flattens to a uniform top-to-
   bottom wash instead of a left-right one, since the copy column is no
   longer set beside a wide, mostly-empty left area — the same reasoning
   applies here, so the left-right contour fade is dropped in favour of a
   uniform, unmasked opacity at the same breakpoint. */
@media (max-width: 781px) {
	.sv-hero__contour {
		-webkit-mask-image: none;
		mask-image: none;
	}
}

.sv-hero__contour svg {
	display: block;
	width: 100%;
	height: 100%;
}

/* Literal black, deliberately not the sv-ink token: the contrast maths
   quoted in patterns/home-hero-de.php and -en.php ("sv-white text stays
   >=15.6:1 over any photo, as long as this layer does not drop under
   ~53.5%/~41.6% opacity at the text's location") was computed against a
   pure black scrim, not the dark-teal sv-ink colour. 86% -> 32% left to
   right, matching the exact figures handed down for this pattern. */
.sv-hero__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(90deg, rgba(0, 0, 0, 0.86) 0%, rgba(0, 0, 0, 0.32) 100%);
}

/* Narrow viewports: the left-aligned copy column takes up a much larger
   share of the image width there, so simply scaling the same two-stop
   85%/32% curve down is not guaranteed to keep the required contrast
   under the actual text (see the pattern file's contrast note). Flatten
   the gradient to a uniformly dark scrim instead. tester must re-measure
   contrast on a real, uploaded photo at mobile widths — this rule only
   controls the scrim, not the photo itself. */
@media (max-width: 781px) {
	.sv-hero__scrim {
		background: linear-gradient(180deg, rgba(0, 0, 0, 0.86) 0%, rgba(0, 0, 0, 0.8) 100%);
	}
}

/*
 * The outer .sv-hero group deliberately uses "layout":{"type":"default"}
 * (no "constrained"/"wide" child-clamping) — nesting the absolutely
 * positioned wp:html backdrop inside a "constrained" parent would make it
 * a target of WordPress's own generated ">  :where(:not(.alignfull)...)"
 * width-clamp rule for that container's direct children, fighting the
 * "position:absolute;inset:0" full-bleed sizing above. With "default"
 * layout no such ambient rule exists, so .sv-hero__inner instead gets its
 * gutter manually here, from the same global custom properties every
 * other "constrained"/"wide" block on the site already resolves to
 * (--wp--style--global--content-size, set from theme.json
 * settings.layout.contentSize) — same effective width as the rest of the
 * page, no duplicated/invented number.
 */
.sv-hero__inner {
	position: relative;
	z-index: 1;
	max-width: var(--wp--style--global--content-size, 1280px);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--sm);
	padding-top: var(--wp--preset--spacing--xl);
	padding-bottom: var(--wp--preset--spacing--xl);
	/* Same stray-margin mechanism as the header-to-content fix in
	   header.css (`.wp-site-blocks > .sv-header + *`, added 2026-09-15) —
	   WordPress's global blockGap rule (`:where(.is-layout-flow) > *
	   {margin-block-start: var(--wp--preset--spacing--md)}`) exempts only
	   the DOM's actual first child, which here is `.sv-hero__backdrop`
	   (position:absolute, out of flow but still first in the DOM) — so
	   `.sv-hero__inner`, the true second child, took an unwanted ~32px top
	   margin on top of this rule's own deliberate `xl` padding-top above.
	   Confirmed on the live rendered page, not assumed (Betreiberfeedback
	   "Hero sieht etwas gedrängt aus", 2026-09-15) — zeroed here so the
	   copy column's actual top offset is exactly the intended padding. */
	margin-block-start: 0;
}

@media (max-width: 781px) {
	.sv-hero__inner {
		padding-top: var(--wp--preset--spacing--lg);
		padding-bottom: var(--wp--preset--spacing--lg);
	}
}

.sv-hero__copy {
	/* Already 720px before the 2026-09-02 request to raise it from "rund
	   600" to "etwa 720" — verified against this file and against the live
	   rendered page (screenshot, 1440px), no competing rule anywhere else
	   narrows it. Left unchanged; the actual fix for the three-line H1
	   below is the font-size reduction only. */
	max-width: 720px;
}

/* H1 lowered from the global 5xl to 4xl, scoped to the hero only — NOT a
   change to styles.elements.h1 in theme.json, which stays 5xl for every
   other page's H1 (post-title). 2026-09-02, target: "Den Wert Ihres
   Waldes erkennen und erhalten." wraps to two lines, not three, at
   1440px.
   Deliberately NOT done via the block's own "fontSize":"4xl" attribute:
   tested via render_block() against a real WordPress bootstrap first —
   for a digit-prefixed slug ("4xl", same class as "2xl"/"3xl"/"5xl"),
   the block-supports code emits the class "has-4xl-font-size" (no
   hyphen), but wp_get_global_stylesheet() only ever defines a rule for
   "has-4-xl-font-size" (with the hyphen) — the same digit-before-letters
   hyphen-insertion this codebase already hit for hand-typed
   var(--wp--preset--...) strings (theme.json h1/h2/h3, this file's own
   .sv-hero__missing-note, page-token-demo.html), except this time it is
   WordPress's OWN attribute-to-class generator that disagrees with its
   OWN stylesheet generator, not a hand-typed literal. The attribute is
   silently dropped on render — confirmed empirically, not assumed. Using
   a plain scoped selector with the verified-correct hyphenated custom
   property sidesteps the mismatch entirely. */
.sv-hero__copy h1 {
	font-size: var(--wp--preset--font-size--4-xl);
}

/* Visible, non-decorative placeholder chip (see functions.php,
   silvalue_get_hero_photo()) — sv-accent is fine here as a border/line
   colour per CLAUDE.md's colour rules; the chip's text is a normal <p>
   inside the sv-ink-background group, so it already inherits sv-white
   automatically via the has-sv-ink-background-color mechanism below,
   no manual colour needed. */
.sv-hero__missing-note {
	display: inline-block;
	margin-bottom: var(--wp--preset--spacing--sm);
	/* "3-xs"/"2-xs", not "3xs"/"2xs" — corrected 2026-08-30, same class of
	   bug as the h1/h2/h3 font-size fix in theme.json: WordPress inserts a
	   hyphen before "xs"/"xl" when a preset slug starts with a digit
	   (--wp--preset--spacing--3-xs is the variable that actually exists).
	   The unhyphenated form silently resolved to nothing, so this chip
	   rendered with no padding. */
	padding: var(--wp--preset--spacing--3-xs) var(--wp--preset--spacing--2-xs);
	border: 1px dashed var(--wp--preset--color--sv-accent);
}

/* ---------------------------------------------------------------------
 * Home services (silvalue/home-services-de, -en)
 * CLAUDE.md Abschnitt 6, Gleichrangigkeits-Regel — gleiche Kartengröße,
 * gleiche Bildhöhe, gleiche Gewichtung. core/query's own "grid"
 * post-template layout already stretches every <li> to the row's tallest
 * item (CSS Grid's default align-items: stretch); the rules below make
 * each card's own content (image -> title -> excerpt) actually fill that
 * stretched height as a flex column, and pin the title area to a fixed
 * two-line height so the excerpt always starts at the same vertical
 * position across all three cards regardless of whether a given title
 * wraps to one or two lines ("Links auf gleicher Höhe").
 * ------------------------------------------------------------------- */
.sv-services-card {
	display: flex;
	flex-direction: column;
	height: 100%;
}

.sv-services-card__title {
	/* Reserves space for two lines of the h3 heading style (font-size
	   2xl, line-height 1.15 — theme.json styles.elements.heading/h3) in
	   em units of that same element, regardless of how many lines this
	   particular title actually needs. */
	min-height: calc(2 * 1.15em);
}

/* ---------------------------------------------------------------------
 * Services overview list (silvalue/services-index-de, -en), added
 * 2026-09-12 — every Leistung/Service as one row (title, excerpt, and
 * now optionally a thumbnail), not the grid of three the home page uses
 * (.sv-services-card above): this is the full list of however many
 * children the Leistungen/Services page has, not a fixed count.
 *
 * A row with no featured image must take the FULL row width, not leave
 * a gap where the image would have been — confirmed against WordPress
 * core's actual behaviour (not assumed): `core/post-featured-image`
 * renders nothing at all when the current post has no featured image
 * (no empty `<figure>`, no wrapper — the element is simply absent from
 * the DOM). With `.sv-services-index-item` as a flex row, a text column
 * with `flex: 1 1 auto` therefore already fills the whole row on its own
 * whenever the image sibling does not exist — no `:empty` check or JS
 * needed, the same "vanishing sibling" effect an unset flex-basis on a
 * lone remaining flex child always has.
 * ------------------------------------------------------------------- */
.sv-services-index-item {
	display: flex;
	gap: var(--wp--preset--spacing--md);
	align-items: flex-start;
}

.sv-services-index-item__media {
	flex: 0 0 200px;
}

.sv-services-index-item__text {
	flex: 1 1 auto;
	/* Without this, a flex item's automatic min-width is "auto" (i.e. its
	   content's own intrinsic width), which can keep a long, unbreakable
	   title/excerpt from shrinking below that width — pushing the row
	   wider than its container instead of wrapping. */
	min-width: 0;
}

@media (max-width: 781px) {
	.sv-services-index-item {
		flex-direction: column;
	}

	.sv-services-index-item__media {
		flex-basis: auto;
		width: 100%;
	}
}

.sv-services-card__excerpt {
	/* Grows to fill whatever height remains in the stretched card, so a
	   card with a shorter excerpt still ends at the same bottom edge as
	   one with a longer excerpt. */
	flex: 1 1 auto;
}

/* ---------------------------------------------------------------------
 * AT Leistungsübersicht — Kartenstil "Option B" + Akkordeon, added
 * 2026-09-21 (docs/entscheidungen/leistungsstruktur.md Abschnitt 14).
 * services-index-de.php only — services-index-en.php (NZ) keeps using
 * the plain `.sv-services-index-item`/`__media`/`__text` rules above
 * unchanged, hence the deliberately separate `sv-services-index-card*`
 * prefix rather than adding to or renaming those existing classes
 * (14.2, "vorab geprüft"): those three classes are shared, cross-market
 * theme code, and NZ still renders the flat, imaged list they support.
 *
 * All literal px/em values below (border-radius, padding, margin,
 * font-size, letter-spacing) are taken verbatim from 14.1/14.2, already
 * finalised with the operator after two rounds of live feedback on a
 * design preview — not invented here and not mapped onto the nearest
 * spacing/font-size token, so a later reviewer does not "correct" them
 * back toward a token that was deliberately not used.
 * ------------------------------------------------------------------- */
.sv-services-index-card {
	background: #ffffff;
	border: 1px solid var(--wp--preset--color--sv-line);
	border-radius: 6px;
	padding: 24px 28px;
	margin-bottom: 14px;
}

/* `<summary>` is the whole card's click/tap target (title + chevron),
   native disclosure triangle removed in both the WebKit/Blink pseudo-
   element form and the standard `::marker` form — `list-style:none`
   alone only ever removed the standard one in every browser this was
   checked against, the WebKit-prefixed rule is still needed. Without
   both, the browser's own triangle would sit doubled up next to the
   custom SVG chevron below. */
.sv-services-index-card__summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	cursor: pointer;
	list-style: none;
}

.sv-services-index-card__summary::-webkit-details-marker {
	display: none;
}

.sv-services-index-card__summary::marker {
	content: "";
}

.sv-services-index-card__summary:focus-visible {
	outline: 2px solid var(--wp--preset--color--sv-accent);
	outline-offset: 2px;
}

/* margin-block-start/end:0 added 2026-09-21, found on the real rendered
   page, not assumed: WordPress's layout-support mechanism (the same
   `is-layout-flex`-on-first-tag quirk documented at length in
   header.css) lands its `is-layout-flow`/`wp-block-post-template-is-
   layout-flow` classes on whichever `<summary>` happens to be first in
   a given `core/post-template`'s rendered output — one per group's
   query, five in this pattern, not every card's `<summary>`. Core's own
   global `:root :where(.is-layout-flow) > *:first-child{margin-block-
   start:0}` rule then wins outright (an actual `:first-child`
   pseudo-class carries real specificity, 0-1-0) over this theme's
   global default heading margin (theme.json, wrapped in its own
   zero-specificity `:where()`) — but only on those five affected
   `<summary>`/title pairs. The other six titles keep the theme's
   default ~18px heading margin untouched, so five cards rendered a
   visibly compact ~21px summary row and six rendered a ~57px row,
   measured on the live page (CDP, computed styles) — the exact kind of
   "unruhig" inconsistency already flagged once by the operator on this
   same page (Abschnitt 14.1 b). Setting the margin explicitly here
   (0-2-0 specificity, beats both competing sources outright, same
   technique as header.css's `.sv-brand .sv-logo-desktop`, no
   `!important`) makes every card's row height identical regardless of
   which one core happens to tag. */
.sv-services-index-card .wp-block-post-title {
	font-size: 18px;
	font-weight: 600;
	margin-block-start: 0;
	margin-block-end: 0;
}

.sv-services-index-card__chevron {
	/* Flex-shrink:0 keeps the icon at its own size when a long title
	   pushes the row close to the card's edge — flex's default shrink
	   behaviour would otherwise squash the SVG's viewBox instead of
	   only the title text wrapping. */
	flex-shrink: 0;
	color: var(--wp--preset--color--sv-slate);
	transition: transform 0.2s ease;
}

details[open] .sv-services-index-card__chevron {
	transform: rotate(180deg);
}

.sv-services-index-card__panel {
	margin-top: 16px;
	padding-top: 16px;
	border-top: 1px solid var(--wp--preset--color--sv-line);
}

/* The `core/read-more` block's own `.wp-block-read-more` class carries
   no theme styling of its own yet — it inherits the page's default link
   colour/weight, which reads fine directly under an excerpt without
   further overrides, so no rule is added for it specifically here. */

/* Kicker-style group headings ("Planung & Bewertung" etc.), replacing
   the page's default <h2> styling — scoped to this one class, not a
   change to styles.elements.heading/h2 in theme.json, so every other
   H2 on the site (CLAUDE.md-governed global heading scale) is
   untouched. The small accent-coloured rule above each heading is a
   `::before` pseudo-element rather than markup in the pattern file —
   one less block-editor element per section, and it cannot end up
   read out by a screen reader the way a decorative empty element
   sometimes can if a future edit gives it stray content. */
.sv-services-index-group-heading {
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sv-slate);
}

.sv-services-index-group-heading::before {
	content: "";
	display: block;
	width: 28px;
	height: 2px;
	margin-bottom: var(--wp--preset--spacing--2-xs);
	background: var(--wp--preset--color--sv-accent);
}

/* ---------------------------------------------------------------------
 * Kontaktformular (SiteOrigin Contact Form Widget, Entscheidung 3.10,
 * silvalue/contact-cta-de/-en)
 * ---------------------------------------------------------------------
 * Kurskorrektur 2026-08-29: Ursprünglich war vorgesehen, die Feldrahmen
 * ausschliesslich über die eigenen Design-Einstellungen des Widgets zu
 * setzen (Design -> Fields -> Border Color), ohne Theme-CSS. An der
 * gerenderten AT-Seite zeigte sich dabei ein reales Verwechslungsrisiko:
 * Das Widget führt "Container" und "Fields" als zwei separate
 * Unterabschnitte mit identisch benannten Border-Feldern - der Container
 * hatte am Ende sv-line-strong, die eigentlichen Felder blieben beim
 * Plugin-Standard (#c0c0c0). Deshalb jetzt vollständig über Theme-CSS
 * gelöst: ein Satz, in beiden Installationen gleich, ohne dass der
 * Betreiber die passende Design-Unterseite im Widget wiederfinden muss.
 * Alle Selektoren unten sind bewusst instanz-unabhängig (kein
 * ".so-widget-sow-contact-form-default-<hash>"-Präfix, der sich je
 * Widget-Instanz und Installation unterscheidet) - "!important" ist
 * nötig, weil das Widget seine eigene, gleich oder höher spezifische
 * Instanz-CSS-Datei zur Laufzeit erzeugt (verifiziert an der
 * ausgelieferten Datei .../uploads/siteorigin-widgets/sow-contact-form-
 * default-<hash>.css) und ein reiner Spezifitäts-Wettlauf gegen einen
 * variablen Hash nicht zuverlässig zu gewinnen wäre.
 *
 * CLAUDE.md Abschnitt 6: Rahmenfarbe von Formularfeldern, Checkboxen und
 * Select-Elementen ausschliesslich sv-line-strong (WCAG 1.4.11, 3:1).
 * ------------------------------------------------------------------- */
.sow-contact-form {
	background: transparent !important;
	border: none !important;
	padding: 0 !important;
}

/* Seitlicher Innenabstand des Kontaktabschnitts (silvalue/contact-cta-
   de/-en), ergänzt 2026-08-29 — NICHT als Blockattribut/Inline-Style auf
   der umgebenden Gruppe lösbar: WordPress' "has-global-padding"-Mechanismus
   setzt padding-left/-right einer verschachtelten constrained-Gruppe
   automatisch auf 0 zurück, weil sie innerhalb einer bereits gepolsterten
   Vorfahren-Ebene (main/post-content) liegt. Ein erster Versuch, das per
   Inline-Style auf genau dieser Gruppe zu setzen, ging beim nächsten
   Speichern der Seite im Blockeditor (z. B. wegen einer reinen
   Widget-Einstellungsänderung) wieder verloren, weil Gutenberg beim
   Speichern den gesamten Blockinhalt aus seinem eigenen, den Fix nie
   kennenden Zustand neu schreibt — jede Korrektur, die nur im
   Blockinhalt einer bereits eingefügten Seite steckt, ist gegen genau
   das nicht haltbar. Deshalb hier stattdessen rein strukturell über
   ":has()" verankert: trifft jede Gruppe, die irgendwo ein
   Kontaktformular enthält, unabhängig von Klassen oder Attributen dieser
   Gruppe selbst, die ein Editor-Speichervorgang verändern könnte. Wert
   sm ist derselbe Token, der global als --wp--style--root--padding-
   left/right dient (theme.json styles.spacing.padding) — kein neu
   erfundener Wert. "!important" zusätzlich gegen die genannte
   WordPress-Regel, die ohne eigenes "!important" auskommt, aber als
   spätere, gleich- oder höherspezifische Kernregel sonst gewinnen könnte. */
.wp-block-group:has(.sow-contact-form) {
	padding-left: var(--wp--preset--spacing--sm) !important;
	padding-right: var(--wp--preset--spacing--sm) !important;
}

.sow-text-field,
.sow-form-field-select select {
	border: 1px solid var(--wp--preset--color--sv-line-strong) !important;
}

/* Feldhöhe, ergänzt 2026-09-15, Betreiberfeedback am gerenderten lokalen
 * Stand ("Felder für Name/Email/Organisation zu wenig hoch, sollten nicht
 * dieselbe Breite wie das Nachrichtenfeld haben") — der Breite-Teil davon
 * ist unten neu gelöst, siehe dortigen Kommentar (2026-09-17).
 *
 * Ursache Feldhöhe: `.sow-text-field`/das Select trugen bisher nur die
 * Rahmenfarbe oben (2026-08-29); Innenabstand, Schriftgröße und
 * Zeilenhöhe blieben auf dem Browser-Standard des jeweiligen
 * Eingabeelements (an der echten Seite gemessen: ~1px/2px Padding, 19px
 * Gesamthöhe) — sichtbar niedriger als der Formulartext selbst und als
 * das (unverändert gelassene, bereits mehrzeilige) Nachrichtenfeld.
 * box-sizing:border-box, da die Breite unten teils in Prozent gesetzt
 * wird und Padding sie sonst überschreiten würde.
 */
.sow-text-field,
.sow-form-field-select select {
	box-sizing: border-box;
	padding: 10px 12px !important;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.4;
}

/* Ursache Breite, ergänzt 2026-09-15: Name/Email/Organisation und das
 * Nachrichtenfeld sind im Widget-Markup gleichrangige, jeweils volle
 * Formularbreite einnehmende Felder (kein eigener "Zeilen"-Wrapper) — an
 * der echten Seite gemessen, alle vier exakt gleich breit.
 *
 * Zwischenstand 2026-09-15 hatte die drei kurzen Einzeilen-Felder zu einer
 * Reihe nebeneinander gesetzt (`display:flex` auf `.sow-contact-form`).
 * Betreiberentscheidung 2026-09-17, revidiert: stattdessen sollen Name/
 * Email/Telefonnummer (Organisation wurde durch ein Telefonnummer-Feld
 * ersetzt, Betreiberänderung im Widget selbst) **untereinander** stehen,
 * nur schmaler als das Nachrichtenfeld — nicht nebeneinander. Der
 * Flex-Container ist damit wieder entfernt (die Felder folgen wieder der
 * normalen Blockfolge des Formulars, jedes auf eigener Zeile); die
 * schmalere Breite kommt jetzt vom Eingabeelement selbst, nicht vom
 * Feld-Wrapper, damit Label/Beschreibung/Fehlermeldung weiterhin die volle
 * Feldbreite nutzen können und nur das eigentliche Eingabefeld schmaler
 * wirkt.
 *
 * Nebeneffekt der Flex-Version, dabei gefunden und mit entfernt: Das
 * Widget druckt vor den Feldern einen klassenlosen `<p>Felder markiert
 * mit * sind Pflichtfelder</p>`-Absatz direkt als Kind von
 * `.sow-contact-form` — der geriet in der Flex-Reihe (kein eigenes
 * `flex-basis`, Standard `auto`) mit in die erste Zeile neben das
 * Namensfeld statt darüber zu stehen. Ohne den Flex-Container betrifft
 * ihn das nicht mehr, er ist wieder ein normaler, voll breiter Absatz.
 */
.sow-form-field-name .sow-text-field,
.sow-form-field-email .sow-text-field,
.sow-form-field-tel .sow-text-field {
	max-width: 420px;
}

@media (max-width: 599px) {
	.sow-form-field-name .sow-text-field,
	.sow-form-field-email .sow-text-field,
	.sow-form-field-tel .sow-text-field {
		max-width: none;
	}
}

.sow-form-field-checkboxes input[type="checkbox"] {
	width: 1.1em;
	height: 1.1em;
	border: 1px solid var(--wp--preset--color--sv-line-strong);
	accent-color: var(--wp--preset--color--sv-accent);
}

/* Absende-Schaltfläche wie die primäre Schaltfläche im Hero
   (theme.json styles.elements.button): sv-accent-Fläche, sv-ink-Text,
   600 Gewicht, 2px Rundung, ui-Schriftgröße (13px), dieselben
   Innenabstände wie das Hero-CTA (11px oben/unten, 18px links/rechts,
   siehe .sv-hero__copy .wp-block-button__link-Ausgabe). Ersetzt den
   Plugin-Standard (grauer Verlauf, eigener Rahmen, Inset-Highlight). */
.sow-submit {
	background: var(--wp--preset--color--sv-accent) !important;
	color: var(--wp--preset--color--sv-ink) !important;
	border: none !important;
	border-radius: 2px !important;
	box-shadow: none !important;
	font-size: var(--wp--preset--font-size--ui) !important;
	font-weight: 600 !important;
	text-decoration: none !important;
	padding: 11px 18px !important;
	cursor: pointer;
}

.sow-submit:hover,
.sow-submit:focus {
	background: var(--wp--preset--color--sv-ink) !important;
	color: var(--wp--preset--color--sv-white) !important;
}

/* ---------------------------------------------------------------------
 * H2 auf Leistungs-Detailseiten (silvalue/service-detail-de/-en),
 * ergänzt 2026-09-01, Betreiberentscheidung
 * ---------------------------------------------------------------------
 * Auf Seiten mit durchlaufendem Fließtext (mehrere Abschnitte)
 * dominierten Zwischenüberschriften in der globalen H2-Größe (3xl,
 * 34-44px) den Fließtext (md, 16-18px unveraendert) statt ihn zu
 * gliedern. Bewusst NICHT die globale H2-Regel in theme.json geändert
 * (träfe auch die Startseite, wo je eine H2 einzeln zwischen großen
 * Abschnitten steht und die aktuelle Größe richtig bleibt) — stattdessen
 * hier eng auf die Klasse "sv-service-detail" begrenzt, die
 * ausschließlich die äußere Gruppe dieses einen Musters trägt.
 *
 * Geprüfte Alternative — Fließtext auf lg (19-21px) anheben statt H2 zu
 * senken — verworfen: Verhältnis zu H2 3xl bliebe bei 1,79-2,10, an der
 * oberen Grenze weiterhin dominant und über den Viewport-Bereich
 * ungleichmäßiger. H2 auf 2xl (28-34px) gegen den unveränderten
 * Fließtext (md) ergibt 1,75-1,89 — spürbar kleiner und über den
 * gesamten Viewport-Bereich gleichmäßiger als beide anderen geprüften
 * Kombinationen (aktuell/unverändert: 2,13-2,44). */
.sv-service-detail h2 {
	font-size: var(--wp--preset--font-size--2-xl);
}

/* ---------------------------------------------------------------------
 * NACHTRAG 2026-09-28 — Betreiberauftrag "Breiten-/Abstands-System
 * vereinheitlichen" (Prompt 2), Punkt 1 (Leistungsdetailseiten)
 * ---------------------------------------------------------------------
 * Bisher hatte der Fließtext auf Leistungsdetailseiten GAR keine eigene
 * Zeilenlängen-Begrenzung — Absätze und Listen liefen auf die volle
 * .sv-service-detail-Rahmenbreite (1.280px, theme.json-Standardmaß,
 * unverändert vom Auftrag: "Der äußere Inhaltsrahmen darf 1.280px breit
 * bleiben"), gemessen deutlich über 100 Zeichen pro Zeile (siehe Bericht).
 *
 * Selektor bewusst auf DIREKTE Kinder von .sv-service-detail begrenzt
 * (">"), nicht auf alle Nachfahren: nur so bleiben Überschriften, Bilder,
 * Tabellen, Prozessmodule und Callouts unangetastet und dürfen wie im
 * Auftrag verlangt "bei Bedarf die breitere Content-Spalte nutzen" — ein
 * in ein Prozessmodul/Callout (eigene wp:group) eingebetteter Absatz ist
 * ein ENKEL, kein direktes Kind, und bleibt dadurch automatisch
 * unbegrenzt. H2/H3 sind hier ebenfalls nicht aufgeführt, aus demselben
 * Grund.
 *
 * --sv-prose-max (780px, layout-tokens.css) statt einer neuen Einzelzahl
 * — identischer Wert wie die bereits auf "Über Silvalue" geprüfte und vom
 * Betreiber als "grundsätzlich gut" bestätigte 780px-Spalte
 * (content-page-redesign.css), jetzt sitebreit derselbe Token.
 *
 * margin-left:0 aus demselben Grund wie bei "Über Silvalue"
 * (content-page-redesign.css, dortiger Kommentar): .sv-service-detail
 * trägt "layout":{"type":"constrained"}, WordPress-Kern zentriert jedes
 * direkte Kind einzeln per margin-left/right:auto innerhalb der
 * 1.280px-Gruppe — ohne diese Korrektur stünden schmalere Absätze/Listen
 * mittig statt an derselben linken Kante wie die (hier unangetastet
 * bleibenden, weiterhin linksbündigen) Überschriften. */
.sv-service-detail > p,
.sv-service-detail > ul,
.sv-service-detail > ol {
	max-width: var(--sv-prose-max);
	margin-left: 0 !important;
}

/* ---------------------------------------------------------------------
 * NACHTRAG 2026-09-28 — Betreiberauftrag "Breiten-/Abstands-System
 * vereinheitlichen" (Prompt 2), Punkt 2 (Impressum und
 * Datenschutzerklärung)
 * ---------------------------------------------------------------------
 * Beide Seiten (Impressum, Seite-ID 161; Datenschutzrichtlinie, Seite-ID
 * 172) bestehen aus einem einzigen "wp:html"-Block mit eigenem,
 * fest-kodiertem Wrapper (<div class="impressum">/
 * <div class="datenschutzerklaerung">, siehe jeweiliger Seiteninhalt) —
 * bisher ohne jede Zeilenlängen-Begrenzung, Fließtext lief auf die volle
 * 1.280px-Rahmenbreite dieses Divs. Der Auftrag verlangt ausdrücklich nur
 * die Absätze/Rechtstexte zu begrenzen, NICHT die Seitenüberschrift (H1,
 * separates wp:post-title außerhalb dieses Divs) — die bleibt unverändert
 * am 1.280px-Raster (theme.json-Standardmaß, hier nicht berührt), ebenso
 * bleiben Inhalte und Überschriftenhierarchie innerhalb des Divs (h2/h3)
 * vollständig unverändert, nur die Absätze/Listen werden schmaler.
 *
 * Kein margin-left:0 nötig wie bei .sv-service-detail/.sv-content-page:
 * .impressum/.datenschutzerklaerung sind einfache, nicht von WordPress'
 * Block-Layout-System verwaltete <div>-Elemente (Ausgabe eines
 * Shortcode-/HTML-Blocks) — ihre Kinder bekommen KEIN automatisches
 * "margin-left/right:auto" von WordPress-Kern und bleiben daher bereits
 * mit dem Standard-Blockverhalten (margin:0) linksbündig. */
.impressum p,
.impressum li,
.datenschutzerklaerung p,
.datenschutzerklaerung li {
	max-width: var(--sv-prose-max);
}

/* ---------------------------------------------------------------------
 * Abschlussblock der Leistungs-Detailseiten (silvalue/service-detail-de),
 * NACHTRAG 2026-09-26 — Betreiberfeedback: der bisherige Abschlussblock
 * (schlichte weiße Box, ein Fließtext-Satz mit reinem Text-Link) "passt
 * nicht mehr zum Design der Seite und wirkt auch nicht gut". Umgesetzt:
 * "Vorschlag 1" aus der gezeigten Vorschau — Akzent-Zeile mit 45°-Pfeil-
 * Link, kleinster Eingriff, nutzt denselben Pfeil-Mechanismus wie die
 * Leistungs-Zeilen der Übersichtsseite (services-redesign.css,
 * .sv-service-row__arrow) und dieselbe zweispaltige space-between-
 * Verteilung wie Proof-Bar/Länderwechsel-Zeile (home-redesign.css) —
 * Linktext bewusst auf sv-text (dunkel) statt sv-accent/sv-accent-deep
 * gesetzt — Kontrastprüfung: sv-accent nur 2,23:1 auf sv-line-soft bzw.
 * 2,78:1 auf Weiß, sv-accent-deep 3,65:1 auf sv-line-soft bzw. 4,55:1 auf
 * Weiß (beide unter/grenzwertig zum AA-Minimum 4,5:1 für Fließtext-
 * Größe). Die Akzentfarbe bleibt daher auf den Pfeil selbst beschränkt —
 * rein dekoratives Element neben bereits sicher lesbarem Linktext, siehe
 * CLAUDE.md-Konvention "sv-accent nur als Rahmen-/Akzentfarbe, nicht als
 * Fließtext-Farbe". Der Linktext selbst bleibt unverändert bei sv-text.
 *
 * .sv-service-closing__arrow wird vom Shortcode selbst erzeugt (nur bei
 * Angabe von arrow="…", functions.php) und liegt INNERHALB des <a> —
 * Pfeil und Linktext teilen sich dadurch Klickziel und Hover-Zustand.
 *
 * NACHTRAG 2026-09-28 — Betreiberauftrag "gestalterische
 * Vereinheitlichung" (Prompt 3), Punkt 2: bisher bewusst auf den
 * ORIGINAL-Farbtoken (sv-accent-deep) statt den redesign-exklusiven
 * sv-r-*-Token, mit der Begründung "dieses Muster gilt sitewide, nicht
 * nur auf body.home/is_page('leistungen')" — diese Begründung war eine
 * reine Geltungsbereichs-Abgrenzung, keine gestalterische Entscheidung
 * gegen den neueren Farbton. Der jetzige Auftrag verlangt ausdrücklich
 * das Gegenteil: Unterseiten sollen sich sichtbar mit der Startseite
 * verbinden. Pfeilfarbe und Hover-Farbe unten deshalb auf sv-r-accent-deep
 * (#087E7D) umgestellt — denselben gedeckteren Türkiston, den Startseite
 * und Leistungsübersicht bereits für Akzente verwenden (sv-accent-deep
 * #00838A war die hellere Ausgangsfarbe). Nur diese rein dekorativen
 * Verwendungen (Pfeil, Hover) geändert; der AA-sicher dunkle Linktext
 * (sv-text) bleibt in jedem Zustand unverändert, keine
 * Kontrastverschlechterung. Zusätzlich ein dünner Akzentstrich oben auf
 * dem gesamten Abschlussblock (2px, dieselbe Farbe) — ein einziges, sich
 * nicht je Abschnitt wiederholendes Signal statt vieler kleiner
 * Linien/Eyebrows über die ganze Seite verteilt, bewusst zurückhaltend
 * gehalten (Auftrag: "keine dekorative Überladung"). */
.sv-service-closing {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	flex-wrap: wrap;
	background-color: var(--wp--preset--color--sv-line-soft);
	border-top: 2px solid var(--wp--preset--color--sv-r-accent-deep);
	padding: 28px 32px;
}

.sv-service-closing__text,
.sv-service-closing__link {
	margin: 0;
}

.sv-service-closing__link a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--sm);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sv-text) !important;
	text-decoration: none;
	white-space: nowrap;
}

.sv-service-closing__arrow {
	display: inline-block;
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1;
	color: var(--wp--preset--color--sv-r-accent-deep);
	transform: rotate(-45deg);
	transition: transform 0.15s ease;
}

.sv-service-closing__link a:hover {
	color: var(--wp--preset--color--sv-r-accent-deep) !important;
}

.sv-service-closing__link a:hover .sv-service-closing__arrow {
	transform: rotate(-45deg) translateX(4px);
}

/* NACHTRAG 2026-09-26 — dieselbe "Vorschlag 1"-Umgestaltung wie oben,
 * jetzt auch für den Abschlussblock von silvalue/content-page-de
 * (Betreiberwunsch: "baue diesen Abschluss auch auf der Seite Über
 * Silvalue ein"). Dieser Abschluss hat zusätzlich eine Eyebrow-Zeile
 * ("Kontakt") vor dem Fließtext, die service-detail nicht kennt — daher
 * zwei weitere, eigene Klassen statt einer weiteren Sonderregel auf
 * .sv-service-closing__text: .sv-service-closing__body bündelt Eyebrow
 * und Satz zu EINEM senkrecht gestapelten Flex-Kind, .sv-service-
 * closing__link bleibt unverändert das zweite — .sv-service-closing
 * selbst (space-between, siehe oben) bleibt dadurch für beide Muster
 * identisch wiederverwendbar. */
.sv-service-closing__body {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.sv-service-closing__eyebrow {
	margin: 0;
	font-size: var(--wp--preset--font-size--sm);
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--sv-slate);
}

/* ---------------------------------------------------------------------
 * Generic content-page pattern (silvalue/content-page-de/-en), added
 * 2026-09-10 for "Über Silvalue" and future flowing-text pages (Kontakt
 * etc.) — same problem as service-detail above (H2 dominates multi-
 * section flowing text), same fix. Added as a second selector on the
 * SAME rule rather than renaming .sv-service-detail: a pattern is copied
 * into the page on insert (CLAUDE.md Abschnitt 9), so the three already-
 * published service pages still carry the old class name in their saved
 * content — renaming it here would silently stop reaching them. The new,
 * generically-named class is for pages built with the new pattern going
 * forward; both resolve to the identical value, so there is exactly one
 * font-size to maintain, not two. */
.sv-content-page h2 {
	font-size: var(--wp--preset--font-size--2-xl);
}

/* Visible, non-decorative placeholder for an inline content image (e.g.
 * a portrait photo) on a LIGHT background — the light-background
 * counterpart to .sv-hero__missing-note above. That class only works on
 * the dark sv-ink hero because it relies on the has-sv-ink-background-
 * color light-text automatism (assets/css/base.css); this one is a plain
 * bordered note for pages on the normal paper/white background. CLAUDE.md
 * Arbeitsregel 3: a missing asset must show an unmissable hint, never a
 * silent gap. sv-accent is fine here as a border colour only (CLAUDE.md
 * Farben-Regel) — the note's own text stays sv-text-soft.
 *
 * Deliberately carries NO width rule of its own (see
 * .sv-content-page__portrait below for that) — this class is only the
 * "nothing set yet" dashed box, meant to be removed by hand once a real
 * photo replaces it (same convention as the hero's missing-photo note),
 * not to persist onto the finished page. */
.sv-content-page__image-placeholder {
	display: block;
	margin: 0 0 var(--wp--preset--spacing--md);
	padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--md);
	border: 1px dashed var(--wp--preset--color--sv-accent);
	color: var(--wp--preset--color--sv-text-soft);
}

/* Width limit for an inline content image sitting DIRECTLY IN THE TEXT
 * FLOW (e.g. a portrait photo with no column layout around it) — added
 * 2026-09-11, half the text column, for a portrait-oriented photo
 * (operator's own request; not a value derived from anywhere else).
 *
 * NOT for an image placed in its own wp:column next to a text column
 * (e.g. "Über Silvalue", "Werdegang", since 2026-09-11 a 66/33
 * wp:columns split — see content-page-de.php's "Bildplatzhalter" note)
 * — there, the column's own width (e.g. 33%) already constrains the
 * image, and adding this class on top would shrink it a second time (to
 * half of an already-narrow column, roughly a sixth of the original text
 * width). Use this class only for an image with no column of its own.
 *
 * Kept as its OWN class, separate from .sv-content-page__image-placeholder
 * above: that class carries the dashed "missing asset" styling, which
 * must NOT persist onto a real photo, while this width limit should
 * persist onto the real photo. Once a real photo replaces the placeholder
 * paragraph, add ONLY "sv-content-page__portrait" to the new Image block
 * by hand (block Settings sidebar -> Advanced -> "Additional CSS
 * class(es)") — replacing one block with another never carries a class
 * over automatically. */
.sv-content-page__portrait {
	display: block;
	max-width: 50%;
	margin: 0 auto var(--wp--preset--spacing--md);
}
