@charset "UTF-8";
/* Generated by apps/tools/split-handoff-css.py from the handoff landlinie.css.
Edit the partials, not this list.
==========================================================================
LANDLINIE — Component stylesheet
Source of truth: Figma "Landlinie" › page "Concept" › sections
"Phase 3" (desktop, 1648px) and "Phase 3 Mobile" (mobile, 390px).

Naming: every CSS custom property maps 1:1 onto a Figma variable.
	 --p3-green-500   ==  Figma variable  p3/green/500
Every block class maps onto a Figma component name.
	 .ll-kategorie-card  ==  "P3 / Kategorie card v1.0.0"
							 "P3M / Kategorie card v1.0.0"

One breakpoint: 768px. Below it the mobile patterns apply.
Components are fluid; they never depend on a fixed pixel width.
========================================================================== */
/* --------------------------------------------------------------------------
0. FONTS — self-hosted, latin subset (SIL OFL). Handoff §3: never load Google Fonts.
Fraunces SemiBold = display, Inter variable 400–700 = text.
-------------------------------------------------------------------------- */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../../Fonts/Fraunces/Fraunces-SemiBold-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../../Fonts/Inter/Inter-Variable-latin.woff2") format("woff2");
}
/* --------------------------------------------------------------------------
1. TOKENS  (Figma collection "P3 Foundations")
-------------------------------------------------------------------------- */
:root {
  /* colour — p3/green/* */
  --p3-green-900: #0A3319; /* footer, deepest bands, hosts gold numerals */
  --p3-green-700: #145A2E; /* CTA band, search icon, links on light */
  --p3-green-500: #1E7A40; /* BRAND green: primary button, icons, hairlines */
  --p3-green-100: #E7F3EB; /* tint band */
  /* colour — p3/gold/* */
  --p3-gold-500: #C8962A; /* logo gold: numerals, badges, social rings */
  --p3-gold-700: #7E5A12; /* gold TEXT on light surfaces */
  --p3-gold-100: #FAEFD4; /* tint (Suchhilfe panel) */
  /* colour — neutrals */
  --p3-ink: #2A251D;
  --p3-ink-soft: #5A5347;
  --p3-paper: #FAF7F1;
  --p3-paper-deep: #F1EDE3;
  --p3-sand: #E3DDCF;
  --p3-white: #FFFFFF;
  /* radius — p3/radius/* */
  --p3-radius-card: 20px;
  --p3-radius-button: 12px;
  --p3-radius-pill: 999px;
  /* spacing — p3/space/* */
  --p3-space-4: 4px;
  --p3-space-8: 8px;
  --p3-space-16: 16px;
  --p3-space-24: 24px;
  --p3-space-40: 40px;
  --p3-space-64: 64px;
  --p3-space-100: 100px;
  /* layout — p3/layout/* */
  --p3-content-width: 1408px; /* inner container */
  --p3-board-width: 1648px; /* full board incl. 120px margins */
  --p3-gutter: 120px; /* desktop side margin */
  --p3-gutter-mobile: 16px;
  /* type families */
  --p3-font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --p3-font-text: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
  /* type scale — fluid between P3M/* (mobile) and P3/* (desktop) */
  --p3-display: clamp(2.25rem, 1.5rem + 3.2vw, 3.5rem); /* P3M/H1 32 → P3/Display 56 */
  --p3-h1: clamp(2rem, 1.5rem + 2.2vw, 2.75rem); /* P3M/H1 32 → P3/H1 44 */
  --p3-h2: clamp(1.625rem,1.3rem + 1.4vw, 2.1875rem); /* P3M/H2 26 → P3/H2 35 */
  --p3-h3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem); /* P3M/H3 20 → P3/H3 24 */
  --p3-stat: clamp(2.125rem,1.5rem + 2.4vw, 3.5rem); /* P3M/Stat 34 → P3/Stat 56 */
  --p3-year: clamp(1.5rem, 1.2rem + 1.1vw, 2.1875rem); /* P3M/Year 24 → P3/Year 35 */
  --p3-lead: clamp(1.125rem,1rem + 0.55vw, 1.375rem); /* P3M/Lead 18 → P3/Lead 22 */
  --p3-body: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); /* P3M/Body 16 → P3/Body 18 */
  --p3-small: clamp(0.875rem,0.85rem + 0.1vw, 0.9375rem); /* P3M/Small 14 → P3/Small 15 */
  --p3-label: clamp(0.875rem,0.85rem + 0.1vw, 0.9375rem); /* P3M/Label 14 → P3/Label 15 */
  --p3-eyebrow: clamp(0.75rem, 0.73rem + 0.1vw, 0.875rem); /* P3M/Eyebrow 12 → P3/Eyebrow 14 */
  /* motion */
  --p3-ease: cubic-bezier(0.2, 0, 0.2, 1);
  --p3-dur: 180ms;
}

/* --------------------------------------------------------------------------
2. BASE + LAYOUT PRIMITIVES
-------------------------------------------------------------------------- */
.ll-root {
  margin: 0;
  background: var(--p3-paper);
  color: var(--p3-ink);
  font-family: var(--p3-font-text);
  font-size: var(--p3-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.ll-root *, .ll-root *::before, .ll-root *::after {
  box-sizing: border-box;
}

/* Container: the 1408px content column with responsive gutters.
Bands go full-bleed; their INNER content uses .ll-container. */
.ll-container {
  width: 100%;
  max-width: var(--p3-content-width);
  margin-inline: auto;
  padding-inline: var(--p3-gutter-mobile);
}

@media (min-width: 768px) {
  .ll-container {
    padding-inline: var(--p3-space-40);
  }
}
@media (min-width: 1648px) {
  .ll-container {
    padding-inline: 0;
  }
}
/* Type helpers — one class per Figma text style */
.ll-display {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-display);
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin: 0;
}

.ll-h1 {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-h1);
  line-height: 1.14;
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}

.ll-h2 {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-h2);
  line-height: 1.2;
  margin: 0;
  text-wrap: balance;
}

.ll-h3 {
  font-family: var(--p3-font-text);
  font-weight: 600;
  font-size: var(--p3-h3);
  line-height: 1.33;
  margin: 0;
}

.ll-lead {
  font-size: var(--p3-lead);
  line-height: 1.55;
  color: var(--p3-ink-soft);
  margin: 0;
}

.ll-body {
  font-size: var(--p3-body);
  line-height: 1.67;
  margin: 0;
}

.ll-small {
  font-size: var(--p3-small);
  line-height: 1.57;
  margin: 0;
}

.ll-label {
  font-size: var(--p3-label);
  font-weight: 600;
  line-height: 1.33;
  margin: 0;
}

.ll-eyebrow {
  font-size: var(--p3-eyebrow);
  font-weight: 600;
  line-height: 1.43;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--p3-gold-700);
  margin: 0;
}

/* Icon sprite helper. SVGs use currentColor, so colour comes from CSS. */
.ll-icon {
  display: inline-block;
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.ll-icon--svg {
  width: 1.5rem;
  height: 1.5rem;
}

.ll-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* SAFETY NET — do not remove. The exported SVGs deliberately carry no
width/height attribute so CSS can scale them. Without a rule the browser
falls back to its 300x150 default and the icon blows up over the layout.
Every icon wrapper therefore sizes its own <svg> child. */
[class*=__icon] > svg,
[class*=__ring] > svg,
[class*=__play] > svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* --------------------------------------------------------------------------
3. BUTTON  ==  "P3 / Button v1.0.0" / "P3M / Button v1.0.0"
	  Variants: Style=Primary | Secondary | Login | Accent | OnDark
	  NOTE: gold NEVER carries white text (2.58:1). Accent/Login use ink.
-------------------------------------------------------------------------- */
.ll-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--p3-space-8);
  min-height: 44px; /* WCAG 2.5.8 touch target */
  padding: var(--p3-space-16) 28px;
  border: 1px solid transparent;
  border-radius: var(--p3-radius-button);
  font-family: var(--p3-font-text);
  font-size: var(--p3-label);
  font-weight: 600;
  line-height: 1.33;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--p3-dur) var(--p3-ease), border-color var(--p3-dur) var(--p3-ease), color var(--p3-dur) var(--p3-ease), transform var(--p3-dur) var(--p3-ease);
}

.ll-btn:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-btn:active {
  transform: translateY(1px);
}

.ll-btn[disabled], .ll-btn[aria-disabled=true] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.ll-btn--primary {
  background: var(--p3-green-500);
  color: var(--p3-white);
} /* white 5.37:1 */
.ll-btn--primary:hover {
  background: var(--p3-green-700);
}

.ll-btn--secondary {
  background: transparent;
  color: var(--p3-green-500);
  border-color: var(--p3-green-500);
}

.ll-btn--secondary:hover {
  background: var(--p3-green-500);
  color: var(--p3-white);
}

.ll-btn--login {
  background: var(--p3-gold-500);
  color: var(--p3-ink);
  font-size: var(--p3-body);
  padding-inline: 32px;
}

.ll-btn--login:hover {
  background: var(--p3-gold-700);
  color: var(--p3-white);
} /* white on gold-700 5.78:1 */
.ll-btn--accent {
  background: var(--p3-gold-500);
  color: var(--p3-ink);
} /* ink 5.88:1 */
.ll-btn--accent:hover {
  background: var(--p3-gold-700);
  color: var(--p3-white);
}

.ll-btn--ondark {
  background: transparent;
  color: var(--p3-white);
  border-color: var(--p3-white);
}

.ll-btn--ondark:hover {
  background: var(--p3-white);
  color: var(--p3-green-900);
}

.ll-btn--block {
  width: 100%;
}

@media (max-width: 767px) {
  .ll-btn {
    width: 100%;
  }
  .ll-btn--inline {
    width: auto;
  }
}
/* --------------------------------------------------------------------------
4. HEADER  ==  "P3 / Header v1.0.0" / "P3M / Header v1.0.0"
-------------------------------------------------------------------------- */
.ll-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--p3-paper);
  border-bottom: 1px solid var(--p3-sand);
}

.ll-header__inner {
  display: flex;
  align-items: center;
  gap: var(--p3-space-24);
  min-height: 64px;
}

.ll-header__logo {
  flex: none;
  display: block;
  height: 33px;
  width: auto;
}

.ll-header__nav {
  display: none;
}

.ll-header__actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--p3-space-8);
}

.ll-header__burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--p3-ink);
}

.ll-header__burger:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

@media (min-width: 768px) {
  .ll-header__inner {
    min-height: 110px;
    gap: var(--p3-space-40);
  }
  .ll-header__logo {
    height: 50px;
  }
  .ll-header__nav {
    display: flex;
    gap: 30px;
    flex-wrap: wrap;
  }
  .ll-header__burger {
    display: none;
  }
  .ll-header__actions {
    gap: var(--p3-space-16);
  }
}
.ll-header__link {
  color: var(--p3-ink);
  text-decoration: none;
  font-size: var(--p3-body);
  padding-block: 4px;
  border-bottom: 2px solid transparent;
  transition: border-color var(--p3-dur) var(--p3-ease);
}

.ll-header__link:hover, .ll-header__link[aria-current=page] {
  border-bottom-color: var(--p3-green-500);
}

.ll-header__link:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
5. NAV DRAWER  ==  "P3M / Nav drawer v1.0.0"  (mobile only)
-------------------------------------------------------------------------- */
.ll-drawer {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
}

.ll-drawer[data-open=true] {
  display: block;
}

.ll-drawer__scrim {
  position: absolute;
  inset: 0;
  background: rgba(42, 37, 29, 0.55);
  border: 0;
  width: 100%;
}

.ll-drawer__panel {
  position: relative;
  background: var(--p3-paper);
  padding: var(--p3-space-16) var(--p3-gutter-mobile) 32px;
}

.ll-drawer__head {
  display: flex;
  align-items: center;
  gap: var(--p3-space-16);
}

.ll-drawer__close {
  margin-left: auto;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--p3-ink);
}

.ll-drawer__item {
  display: flex;
  align-items: center;
  min-height: 60px; /* 60px tap target */
  padding-block: var(--p3-space-16);
  border-bottom: 1px solid var(--p3-sand);
  color: var(--p3-ink);
  text-decoration: none;
  font-size: var(--p3-lead);
}

.ll-drawer__item:hover {
  color: var(--p3-green-500);
}

.ll-drawer__foot {
  margin-top: var(--p3-space-24);
  display: grid;
  gap: var(--p3-space-16);
}

@media (min-width: 768px) {
  .ll-drawer {
    display: none !important;
  }
}
/* --------------------------------------------------------------------------
6. SECTION HEADER  ==  "P3 / Section header v1.0.0" / "P3M / …"
-------------------------------------------------------------------------- */
.ll-section-header {
  display: grid;
  gap: 10px;
  max-width: 760px;
}

.ll-section-header__lead {
  color: var(--p3-ink-soft);
  font-size: var(--p3-body);
}

@media (min-width: 768px) {
  .ll-section-header {
    gap: 14px;
  }
}
/* --------------------------------------------------------------------------
7. BAND  ==  "P3 / Band v1.0.0"  (Tone=Paper-deep|Green-100|Green-700|Green-900)
	  Full-bleed background; inner content uses .ll-container.
-------------------------------------------------------------------------- */
.ll-band {
  padding-block: var(--p3-space-40);
}

@media (min-width: 768px) {
  .ll-band {
    padding-block: var(--p3-space-64);
  }
}
.ll-band--paper-deep {
  background: var(--p3-paper-deep);
}

.ll-band--green-100 {
  background: var(--p3-green-100);
}

.ll-band--green-700 {
  background: var(--p3-green-700);
  color: var(--p3-white);
}

.ll-band--green-900 {
  background: var(--p3-green-900);
  color: var(--p3-white);
}

.ll-band--green-700 .ll-h2, .ll-band--green-900 .ll-h2,
.ll-band--green-700 .ll-body, .ll-band--green-900 .ll-body,
.ll-band--green-700 .ll-small, .ll-band--green-900 .ll-small {
  color: var(--p3-white);
}

/* the band directly above the footer sits FLUSH — no gap */
.ll-band + .ll-footer {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
8. KENNZAHLENLEISTE  ==  "P3 / Kennzahl v1.0.0" / "P3M / Kennzahl v1.0.0"
	  4-up on desktop, 2x2 on mobile — auto-fit, no breakpoint needed.
	  gold-500 numerals require green-900 behind them (4.79:1).
-------------------------------------------------------------------------- */
.ll-kennzahlenleiste {
  display: grid;
  gap: var(--p3-space-24) var(--p3-space-16);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.ll-kennzahl {
  display: grid;
  gap: var(--p3-space-4);
  align-content: start;
}

.ll-kennzahl__wert {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-stat);
  line-height: 1.1;
  color: var(--p3-gold-500);
}

.ll-kennzahl__regel {
  width: 48px;
  height: 2px;
  background: var(--p3-gold-500);
  border: 0;
  margin: 6px 0;
}

.ll-kennzahl__bezeichnung {
  font-size: var(--p3-small);
  color: var(--p3-white);
}

/* --------------------------------------------------------------------------
9. USP CHIP  ==  "P3 / USP chip v1.0.0"
-------------------------------------------------------------------------- */
.ll-usp-band {
  display: grid;
  gap: var(--p3-space-16);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.ll-usp-chip {
  display: flex;
  align-items: center;
  gap: var(--p3-space-16);
}

.ll-usp-chip__icon {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--p3-radius-pill);
  border: 1.5px solid var(--p3-gold-700);
  color: var(--p3-gold-700);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ll-usp-chip__icon svg {
  width: 22px;
  height: 22px;
}

.ll-usp-chip__titel {
  font-weight: 500;
  font-size: var(--p3-body);
}

.ll-usp-chip__detail {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
}

/* --------------------------------------------------------------------------
10. CARD SHELL — shared by every card component
-------------------------------------------------------------------------- */
.ll-card {
  background: var(--p3-paper-deep);
  border-radius: var(--p3-radius-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ll-card__media {
  position: relative;
  width: 100%;
  aspect-ratio: 16/11;
  background: var(--p3-sand);
  overflow: hidden;
}

.ll-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

/* Slot whose photography does not exist yet. Named in the showcase so the
missing shot is visible rather than silently grey. Not needed in TYPO3. */
.ll-card__media--todo {
  display: grid;
  place-items: center;
  text-align: center;
}

.ll-card__media--todo span {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  font-weight: 600;
  padding: var(--p3-space-8);
}

.ll-card__body {
  padding: var(--p3-space-16);
  display: grid;
  gap: 6px;
  align-content: start;
}

@media (min-width: 768px) {
  .ll-card__body {
    padding: var(--p3-space-24);
    gap: var(--p3-space-8);
  }
}
.ll-card__title {
  font-family: var(--p3-font-text);
  font-weight: 600;
  font-size: var(--p3-h3);
  line-height: 1.33;
  margin: 0;
}

.ll-card__text {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  margin: 0;
}

.ll-card__link {
  font-size: var(--p3-label);
  font-weight: 600;
  color: var(--p3-green-700);
  text-decoration: none;
  margin-top: auto;
}

.ll-card__link:hover {
  text-decoration: underline;
}

/* A card is frequently rendered as <a> (whole card clickable). Without this
it picks up the UA link style — blue + underline — and that underline
propagates to every child, because a descendant cannot remove an
ancestor's text-decoration. Applies to every card variant. */
a.ll-card {
  color: var(--p3-ink);
  text-decoration: none;
  transition: box-shadow var(--p3-dur) var(--p3-ease);
}

a.ll-card:hover {
  box-shadow: 0 4px 18px rgba(10, 51, 25, 0.12);
}

a.ll-card:hover .ll-card__link {
  text-decoration: underline;
}

a.ll-card:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 3px;
}

/* Card grid — auto-fit, so it reflows without a breakpoint */
.ll-card-grid {
  display: grid;
  gap: var(--p3-space-16);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}

@media (min-width: 768px) {
  .ll-card-grid {
    gap: var(--p3-space-40);
  }
}
/* --------------------------------------------------------------------------
11. KATEGORIE CARD  ==  "P3 / Kategorie card v1.0.0" (Size=Standard|Featured)
						   "P3M / Kategorie card v1.0.0" (Size=Full|Grid)
	   Category cards must stay SCANNABLE: 2-col grid on mobile, never stacked,
	   never a carousel.
-------------------------------------------------------------------------- */
.ll-kategorie-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 768px) {
  .ll-kategorie-grid {
    gap: var(--p3-space-40);
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  }
}
.ll-kategorie-card .ll-card__media {
  aspect-ratio: 3/2;
}

.ll-kategorie-card--featured {
  border-top: 4px solid var(--p3-gold-700);
}

.ll-kategorie-card--featured .ll-card__media {
  aspect-ratio: 16/11;
}

@media (max-width: 767px) {
  .ll-kategorie-card .ll-card__body {
    padding: 12px;
    gap: var(--p3-space-4);
  }
  .ll-kategorie-card .ll-card__title {
    font-size: var(--p3-label);
  }
}
/* --------------------------------------------------------------------------
12. CAROUSEL  (mobile pattern for semantically grouped cards)
	   First card in full + a slice of the next, so the scroll is discoverable.
	   Above 768px it degrades to a normal grid.
-------------------------------------------------------------------------- */
.ll-carousel {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-inline: var(--p3-gutter-mobile);
  margin-inline: calc(-1 * var(--p3-gutter-mobile));
  scroll-padding-inline-start: var(--p3-gutter-mobile);
}

.ll-carousel::-webkit-scrollbar {
  display: none;
}

/* Peek arithmetic, against the track's padding box: visible room right of the
first card = 100% + right-gutter(16) - card - gap(12). Card = 100% - 40px
therefore leaves 40 + 16 - 12 = 44px of the next card showing, at every
viewport width. 82% drifted to 60px, which reads as a half-shown card. */
.ll-carousel > * {
  flex: 0 0 min(318px, 100% - 40px);
  scroll-snap-align: start;
}

@media (min-width: 768px) {
  .ll-carousel {
    display: grid;
    gap: var(--p3-space-40);
    overflow: visible;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    padding-inline: 0;
    margin-inline: 0;
  }
  .ll-carousel > * {
    flex: initial;
  }
}
/* --------------------------------------------------------------------------
13. ANSPRECHPARTNER CARD  ==  "P3 / Ansprechpartner card v1.0.0"
	   Desktop: photo on top. Mobile: photo left, details right.
-------------------------------------------------------------------------- */
.ll-ansprechpartner {
  flex-direction: row;
  align-items: stretch;
}

.ll-ansprechpartner .ll-card__media {
  flex: none;
  width: 112px;
  aspect-ratio: auto;
}

.ll-ansprechpartner__durchwahl {
  font-weight: 500;
  color: var(--p3-green-700);
  font-size: var(--p3-body);
}

@media (min-width: 768px) {
  .ll-ansprechpartner {
    flex-direction: column;
  }
  .ll-ansprechpartner .ll-card__media {
    width: 100%;
    aspect-ratio: 5/4;
  }
}
/* --------------------------------------------------------------------------
14. LIEFERANT CARD  ==  "P3 / Lieferant card v1.0.0"
-------------------------------------------------------------------------- */
.ll-lieferant {
  flex-direction: row;
  align-items: center;
  gap: var(--p3-space-16);
  padding: var(--p3-space-16);
}

.ll-lieferant .ll-card__media {
  flex: none;
  width: 72px;
  height: 72px;
  aspect-ratio: 1;
  border-radius: 12px;
}

.ll-lieferant__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.ll-lieferant__seit {
  font-size: var(--p3-small);
  color: var(--p3-gold-700);
}

@media (min-width: 768px) {
  .ll-lieferant {
    padding: var(--p3-space-24);
    gap: 20px;
  }
  .ll-lieferant .ll-card__media {
    width: 108px;
    height: 108px;
    border-radius: var(--p3-radius-card);
  }
}
/* --------------------------------------------------------------------------
15. KUNDENSTIMME  ==  "P3 / Kundenstimme v1.0.0"
-------------------------------------------------------------------------- */
.ll-kundenstimme {
  padding: var(--p3-space-16);
  gap: 12px;
}

@media (min-width: 768px) {
  .ll-kundenstimme {
    padding: var(--p3-space-24);
  }
}
.ll-kundenstimme__mark {
  font-family: var(--p3-font-display);
  font-size: var(--p3-h2);
  line-height: 1;
  color: var(--p3-gold-700);
} /* gold-700, not gold-500: 4.88:1 on paper-deep */
.ll-kundenstimme__zitat {
  font-size: var(--p3-body);
  margin: 0;
}

.ll-kundenstimme__zuordnung {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  margin: 0;
}

/* --------------------------------------------------------------------------
16. STEP CARD / HERKUNFT TILE / BULLET ROW
-------------------------------------------------------------------------- */
.ll-step {
  padding: var(--p3-space-16);
  gap: var(--p3-space-8);
}

@media (min-width: 768px) {
  .ll-step {
    padding: var(--p3-space-24);
    gap: 12px;
  }
}
.ll-step__badge {
  width: 44px;
  height: 44px;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-green-700);
  color: var(--p3-white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: var(--p3-label);
}

.ll-herkunft {
  background: var(--p3-green-100);
  padding: var(--p3-space-16);
  gap: var(--p3-space-8);
}

@media (min-width: 768px) {
  .ll-herkunft {
    padding: var(--p3-space-24);
  }
}
.ll-herkunft__icon {
  width: 44px;
  height: 44px;
  border-radius: var(--p3-radius-pill);
  border: 1.5px solid var(--p3-gold-700);
  color: var(--p3-gold-700);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ll-herkunft__icon svg {
  width: 22px;
  height: 22px;
}

.ll-herkunft__titel {
  color: var(--p3-green-900);
}

.ll-bullet-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
}

.ll-bullet {
  display: flex;
  align-items: flex-start;
  gap: var(--p3-space-16);
}

.ll-bullet::before {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  margin-top: 0.5em;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-gold-700);
}

/* --------------------------------------------------------------------------
17. ZEITLEISTE  ==  "P3 / Zeitleiste v1.0.0" (horizontal, rail behind)
					   "P3M / Zeitleiste v1.0.0" (vertical, rail at left)
-------------------------------------------------------------------------- */
.ll-zeitleiste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--p3-space-24);
  position: relative;
}

.ll-zeitleiste::before {
  content: "";
  position: absolute;
  left: 6px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--p3-gold-700);
}

.ll-meilenstein {
  display: grid;
  grid-template-columns: 14px 1fr;
  gap: 14px;
  align-items: start;
}

.ll-meilenstein__marker {
  width: 14px;
  height: 14px;
  margin-top: 6px;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-gold-700);
}

.ll-meilenstein__jahr {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-year);
  line-height: 1.16;
  color: var(--p3-green-500);
}

.ll-meilenstein__text {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
}

.ll-meilenstein__media {
  margin-top: var(--p3-space-8);
  border-radius: var(--p3-radius-card);
  overflow: hidden;
  background: var(--p3-sand);
  aspect-ratio: 13/9;
  display: none;
}

@media (min-width: 768px) {
  .ll-zeitleiste {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--p3-space-24);
  }
  .ll-zeitleiste::before {
    left: 0;
    right: 0;
    top: 62px;
    bottom: auto;
    width: auto;
    height: 1px;
  }
  .ll-meilenstein {
    grid-template-columns: 1fr;
    gap: 12px;
  }
  .ll-meilenstein__marker {
    margin-top: 0;
  }
  .ll-meilenstein__media {
    display: block;
  }
}
/* --------------------------------------------------------------------------
18. KANAL BUTTON  ==  "P3 / Kanal button v1.0.0"
	   Kanal=Telefon | WhatsApp | E-Mail | Live-Chat
	   Ring: 1.5px green-500 stroke, NO background fill.
-------------------------------------------------------------------------- */
.ll-kanal-row {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.ll-kanal {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 44px;
  padding: var(--p3-space-16);
  background: var(--p3-white);
  border: 1px solid var(--p3-sand);
  border-radius: var(--p3-radius-button);
  color: var(--p3-ink);
  text-decoration: none;
  transition: border-color var(--p3-dur) var(--p3-ease), box-shadow var(--p3-dur) var(--p3-ease);
}

.ll-kanal:hover {
  border-color: var(--p3-green-500);
  box-shadow: 0 0 0 1px var(--p3-green-500);
}

.ll-kanal:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-kanal__ring {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--p3-radius-pill);
  border: 1.5px solid var(--p3-green-500);
  color: var(--p3-green-500);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
}

.ll-kanal__ring svg {
  width: 24px;
  height: 24px;
}

.ll-kanal__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.ll-kanal__titel {
  font-size: var(--p3-label);
  font-weight: 600;
}

.ll-kanal__detail {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
}

/* --------------------------------------------------------------------------
19. FORM CONTROLS  ==  "P3 / Input field", "P3 / Dropdown field",
						  "P3 / Checkbox", "P3 / Checkbox group"
	   The form GRID is auto-fit: fields restack instead of clipping.
	   This is the fix for the Figma instances that clipped on resize.
-------------------------------------------------------------------------- */
.ll-form {
  background: var(--p3-paper-deep);
  border-radius: var(--p3-radius-card);
  padding: var(--p3-space-16);
  display: grid;
  gap: 14px;
}

@media (min-width: 768px) {
  .ll-form {
    padding: 48px;
    gap: var(--p3-space-24);
  }
}
/* Two columns on desktop, one below 768px — the design's own rhythm. An
auto-fit track was fluid but let a wide container spread the form over five
columns, which is wrong for a contact form. minmax(0,1fr) plus min-width:0
on the controls is what stops the fields clipping instead of restacking. */
.ll-form__grid {
  display: grid;
  gap: 14px;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 768px) {
  .ll-form__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 768px) {
  .ll-form__grid {
    gap: var(--p3-space-24) var(--p3-space-40);
  }
}
.ll-form__full {
  grid-column: 1/-1;
}

.ll-field {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.ll-field__label {
  font-size: var(--p3-small);
  font-weight: 600;
  color: var(--p3-ink);
}

.ll-input, .ll-select, .ll-textarea {
  width: 100%;
  min-width: 0; /* min-width:0 stops grid blowout */
  min-height: 52px;
  padding: 14px var(--p3-space-16);
  background: var(--p3-white);
  color: var(--p3-ink);
  border: 1px solid var(--p3-sand);
  border-radius: var(--p3-radius-button);
  font-family: var(--p3-font-text);
  font-size: var(--p3-body);
  line-height: 1.5;
  transition: border-color var(--p3-dur) var(--p3-ease), box-shadow var(--p3-dur) var(--p3-ease);
}

.ll-input::-moz-placeholder, .ll-textarea::-moz-placeholder {
  color: var(--p3-ink-soft);
}

.ll-input::placeholder, .ll-textarea::placeholder {
  color: var(--p3-ink-soft);
}

.ll-input:hover, .ll-select:hover, .ll-textarea:hover {
  border-color: var(--p3-ink-soft);
}

.ll-input:focus, .ll-select:focus, .ll-textarea:focus {
  outline: 0;
  border-color: var(--p3-gold-500);
  box-shadow: 0 0 0 3px var(--p3-gold-500);
}

.ll-input[aria-invalid=true] {
  border-color: #A83A20;
  box-shadow: 0 0 0 2px rgba(168, 58, 32, 0.25);
}

.ll-textarea {
  min-height: 104px;
  resize: vertical;
}

.ll-select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  padding-right: 44px;
  background-image: url("../svg/icon-chevron-down.svg");
  background-repeat: no-repeat;
  background-position: right var(--p3-space-16) center;
  background-size: 20px 20px;
}

.ll-checkbox-group {
  display: grid;
  gap: 12px;
}

.ll-checkbox-group__legend {
  font-size: var(--p3-label);
  font-weight: 600;
  padding: 0;
}

.ll-checkbox-group__options {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px;
}

.ll-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  cursor: pointer;
  font-size: var(--p3-small);
}

.ll-checkbox input {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1.5px solid var(--p3-sand);
  border-radius: 4px;
  background: var(--p3-white);
  cursor: pointer;
  transition: background-color var(--p3-dur) var(--p3-ease), border-color var(--p3-dur) var(--p3-ease);
}

.ll-checkbox input:hover {
  border-color: var(--p3-green-500);
}

.ll-checkbox input:checked {
  background: var(--p3-green-500);
  border-color: var(--p3-green-500);
  background-image: url("../svg/icon-check.svg");
  background-size: 14px;
  background-position: center;
  background-repeat: no-repeat;
}

.ll-checkbox input:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
20. FAQ SUCHFELD  ==  "P3 / FAQ Suchfeld v1.0.0" (State=Rest|Focus)
	   + SUCHHILFE  ==  "P3 / Suchhilfe v1.0.0" + "P3 / Hinweis-Pfeil v1.0.0"
-------------------------------------------------------------------------- */
.ll-faq-search {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 var(--p3-space-16);
  background: var(--p3-white);
  border: 1px solid var(--p3-sand);
  border-radius: var(--p3-radius-button);
  transition: border-color var(--p3-dur) var(--p3-ease), box-shadow var(--p3-dur) var(--p3-ease);
}

.ll-faq-search:focus-within {
  border-color: var(--p3-gold-500);
  box-shadow: 0 0 0 3px var(--p3-gold-500);
}

.ll-faq-search__icon {
  flex: none;
  width: 22px;
  height: 22px;
  color: var(--p3-green-700);
}

/* The input owns the vertical padding, so the full 50px field is the tap target
rather than only the 22px text line (WCAG 2.5.8). */
.ll-faq-search input {
  flex: 1;
  min-width: 0;
  padding-block: 14px;
  border: 0;
  outline: 0;
  background: none;
  font-family: var(--p3-font-text);
  font-size: var(--p3-body);
  color: var(--p3-ink);
}

.ll-suchhilfe {
  background: var(--p3-gold-100);
  border: 1px solid var(--p3-gold-700);
  border-radius: var(--p3-radius-card);
  padding: var(--p3-space-24);
  display: grid;
  gap: 10px;
  position: relative;
}

.ll-suchhilfe__titel {
  font-weight: 500;
  font-size: var(--p3-body);
}

.ll-suchhilfe__schritte {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
  font-size: var(--p3-small);
  counter-reset: schritt;
}

.ll-suchhilfe__schritte li::before {
  counter-increment: schritt;
  content: counter(schritt) ". ";
  font-weight: 600;
}

.ll-suchhilfe__alternative {
  font-size: var(--p3-small);
  color: var(--p3-gold-700);
}

.ll-hinweis-pfeil {
  display: none;
  position: absolute;
  left: -74px;
  top: 40px;
  width: 64px;
  height: 56px;
  color: var(--p3-gold-700);
}

@media (min-width: 1100px) {
  .ll-hinweis-pfeil {
    display: block;
  }
}
.ll-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
}

.ll-chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 12px 18px;
  border: 1px solid transparent;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-sand);
  color: var(--p3-ink);
  font-size: var(--p3-label);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--p3-dur) var(--p3-ease), color var(--p3-dur) var(--p3-ease);
}

.ll-chip:hover {
  background: var(--p3-gold-100);
  color: var(--p3-gold-700);
}

.ll-chip:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-chip[aria-pressed=true] {
  background: var(--p3-gold-100);
  color: var(--p3-gold-700);
  border-color: var(--p3-gold-700);
}

/* --------------------------------------------------------------------------
21. ACCORDION  ==  "P3 / Accordion row v1.0.0" (State=Collapsed|Expanded)
	   Uses <details>/<summary> so it works without JS; JS only animates.
-------------------------------------------------------------------------- */
.ll-accordion {
  display: grid;
}

.ll-accordion-row {
  border-bottom: 1px solid var(--p3-sand);
}

.ll-accordion-row__summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-block: 18px;
  cursor: pointer;
  list-style: none;
  min-height: 44px;
  font-size: var(--p3-body);
  font-weight: 500;
}

.ll-accordion-row__summary::-webkit-details-marker {
  display: none;
}

.ll-accordion-row__summary:hover {
  color: var(--p3-green-700);
}

.ll-accordion-row__summary:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-accordion-row__frage {
  flex: 1;
  min-width: 0;
}

.ll-accordion-row__schalter {
  flex: none;
  width: 24px;
  height: 24px;
  position: relative;
  color: var(--p3-gold-700);
}

.ll-accordion-row__schalter::before,
.ll-accordion-row__schalter::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
}

.ll-accordion-row__schalter::before {
  width: 16px;
  height: 2px;
}

.ll-accordion-row__schalter::after {
  width: 2px;
  height: 16px;
  transition: transform var(--p3-dur) var(--p3-ease), opacity var(--p3-dur) var(--p3-ease);
}

.ll-accordion-row[open] .ll-accordion-row__schalter::after {
  transform: rotate(90deg);
  opacity: 0;
}

.ll-accordion-row__antwort {
  padding-bottom: 18px;
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  max-width: 62ch;
}

.ll-accordion-row[data-animating] .ll-accordion-row__antwort {
  overflow: hidden;
}

/* --------------------------------------------------------------------------
22. BANDS WITH CONTENT — CTA / Webshop / Newsletter
-------------------------------------------------------------------------- */
.ll-cta-band__inner, .ll-webshop-band__inner {
  display: grid;
  gap: 14px;
  justify-items: start;
}

.ll-cta-band .ll-btn, .ll-webshop-band .ll-btn {
  margin-top: var(--p3-space-8);
}

.ll-webshop-band__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p3-space-16);
  width: 100%;
}

@media (min-width: 768px) {
  .ll-webshop-band__aktionen {
    width: auto;
  }
}
.ll-newsletter {
  background: var(--p3-green-100);
  border-radius: var(--p3-radius-card);
  padding: var(--p3-space-24);
  display: grid;
  gap: 14px;
}

@media (min-width: 768px) {
  .ll-newsletter {
    padding: 44px 48px;
    grid-template-columns: 1fr auto;
    align-items: center;
    -moz-column-gap: var(--p3-space-40);
    column-gap: var(--p3-space-40);
  }
}
.ll-newsletter__titel {
  color: var(--p3-green-900);
}

.ll-newsletter__form {
  display: grid;
  gap: 12px;
}

@media (min-width: 768px) {
  .ll-newsletter__form {
    grid-template-columns: minmax(240px, 420px) auto;
  }
}
.ll-newsletter__hinweis {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  grid-column: 1/-1;
}

/* --------------------------------------------------------------------------
23. VIDEO POSTER  ==  "P3 / Video poster v1.0.0"
	   Click-to-load: no third-party script until the user opts in.
-------------------------------------------------------------------------- */
.ll-video {
  position: relative;
  width: 100%;
  aspect-ratio: 5/2;
  background: var(--p3-sand);
  border-radius: var(--p3-radius-card);
  overflow: hidden;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
}

@media (max-width: 767px) {
  .ll-video {
    aspect-ratio: 16/10;
  }
}
.ll-video img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

.ll-video__ui {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 12px;
  text-align: center;
  padding: var(--p3-space-16);
}

.ll-video__play {
  width: 64px;
  height: 64px;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-green-700);
  color: var(--p3-white);
  display: inline-grid;
  place-items: center;
  transition: transform var(--p3-dur) var(--p3-ease);
}

.ll-video__play svg {
  width: 26px;
  height: 26px;
  margin-left: 3px;
}

.ll-video:hover .ll-video__play {
  transform: scale(1.06);
}

.ll-video:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

@media (min-width: 768px) {
  .ll-video__play {
    width: 96px;
    height: 96px;
  }
  .ll-video__play svg {
    width: 34px;
    height: 34px;
  }
}
.ll-video__titel {
  font-family: var(--p3-font-text);
  font-weight: 600;
  font-size: var(--p3-h3);
}

.ll-video__hinweis {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
  max-width: 44ch;
}

/* --------------------------------------------------------------------------
24. LIEFERGEBIET MAP  ==  "P3 / Liefergebiet map v1.0.0"
	   Static SVG — deliberately not an embedded map service, so no consent
	   category is needed. Zones are CSS-coloured.
-------------------------------------------------------------------------- */
.ll-liefergebiet {
  background: var(--p3-paper);
  border-radius: var(--p3-radius-card);
  padding: var(--p3-space-24);
  display: grid;
  gap: var(--p3-space-24);
}

.ll-liefergebiet__karte {
  width: 100%;
  max-width: 440px;
  height: auto;
  justify-self: center;
}

.karte__land {
  fill: var(--p3-sand);
}

.karte__zone {
  fill: var(--p3-green-500);
}

.karte__zone--erweitert {
  opacity: 0.14;
}

.karte__zone--kern {
  opacity: 0.3;
}

.karte__pin {
  fill: var(--p3-gold-500);
  stroke: var(--p3-ink);
  stroke-width: 0.5;
}

.ll-legende {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}

.ll-legende li {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
}

.ll-legende__swatch {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: var(--p3-sand);
}

.ll-legende__swatch--kern {
  background: color-mix(in srgb, var(--p3-green-500) 30%, var(--p3-paper));
}

.ll-legende__swatch--erweitert {
  background: color-mix(in srgb, var(--p3-green-500) 14%, var(--p3-paper));
}

/* --------------------------------------------------------------------------
25. ZERTIFIZIERUNG STRIP + LIEFERUNG PANEL
-------------------------------------------------------------------------- */
.ll-zertifizierung {
  display: grid;
  gap: var(--p3-space-16);
}

.ll-zertifizierung__siegel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 32px;
}

.ll-zertifizierung__siegel img {
  height: 40px;
  width: auto;
}

@media (min-width: 768px) {
  .ll-zertifizierung__siegel img {
    height: 50px;
  }
}
.ll-lieferung-panel {
  background: var(--p3-green-100);
  border-radius: var(--p3-radius-card);
  padding: var(--p3-space-24);
  display: grid;
  gap: 12px;
  align-content: start;
}

@media (min-width: 768px) {
  .ll-lieferung-panel {
    padding: 32px;
  }
}
.ll-lieferung-panel__titel {
  color: var(--p3-green-900);
}

.ll-lieferung-panel__abschluss {
  font-weight: 500;
  color: var(--p3-green-900);
  font-size: var(--p3-body);
}

/* Two-up: form + side panel. Stacks below 768 without clipping. */
.ll-form-layout {
  display: grid;
  gap: var(--p3-space-24);
}

@media (min-width: 900px) {
  .ll-form-layout {
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    gap: var(--p3-space-40);
    align-items: start;
  }
}
/* --------------------------------------------------------------------------
26. BREADCRUMB + BILD-PLATZHALTER
-------------------------------------------------------------------------- */
.ll-breadcrumb {
  font-size: var(--p3-small);
  color: var(--p3-ink-soft);
}

.ll-breadcrumb ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
}

.ll-breadcrumb li + li::before {
  content: "/ ";
  color: var(--p3-ink-soft);
}

.ll-breadcrumb a {
  color: var(--p3-ink-soft);
  text-decoration: none;
}

.ll-breadcrumb a:hover {
  color: var(--p3-green-700);
  text-decoration: underline;
}

.ll-bild-platzhalter {
  background: var(--p3-sand);
  border-radius: var(--p3-radius-card);
  aspect-ratio: 16/10;
  display: grid;
  place-items: center;
  overflow: hidden;
  color: var(--p3-ink-soft);
  font-size: var(--p3-small);
  text-align: center;
  padding: var(--p3-space-16);
}

.ll-bild-platzhalter img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
27. FOOTER  ==  "P3 / Footer v1.0.0" / "P3M / Footer v1.0.0"
-------------------------------------------------------------------------- */
.ll-footer {
  background: var(--p3-green-900);
  color: var(--p3-white);
  padding-block: 32px;
}

@media (min-width: 768px) {
  .ll-footer {
    padding-block: 64px;
  }
}
.ll-footer__inner {
  display: grid;
  gap: 20px;
}

@media (min-width: 768px) {
  .ll-footer__inner {
    grid-template-columns: minmax(240px, 1.2fr) repeat(3, minmax(140px, 1fr));
    gap: var(--p3-space-40);
  }
}
.ll-footer__logo {
  height: 34px;
  width: auto;
}

.ll-footer__adresse, .ll-footer__links {
  font-size: var(--p3-small);
}

.ll-footer__spaltentitel {
  font-size: var(--p3-label);
  font-weight: 600;
  color: var(--p3-gold-500);
  margin-bottom: var(--p3-space-8);
}

.ll-footer__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.ll-footer__links a {
  color: var(--p3-white);
  text-decoration: none;
}

.ll-footer__links a:hover {
  text-decoration: underline;
}

.ll-footer__social {
  display: flex;
  gap: 12px;
  margin-top: 20px;
}

.ll-footer__social a {
  width: 44px;
  height: 44px;
  border-radius: var(--p3-radius-pill);
  border: 1.5px solid var(--p3-gold-500);
  color: var(--p3-gold-500);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--p3-dur) var(--p3-ease), color var(--p3-dur) var(--p3-ease);
}

.ll-footer__social a:hover {
  background: var(--p3-gold-500);
  color: var(--p3-green-900);
}

.ll-footer__social svg {
  width: 22px;
  height: 22px;
}

.ll-footer__divider {
  border: 0;
  border-top: 1px solid var(--p3-gold-700);
  margin: 24px 0 0;
}

.ll-footer__copyright {
  font-size: var(--p3-small);
  margin-top: 20px;
}

/* --------------------------------------------------------------------------
28. ACCESSIBILITY + MOTION
-------------------------------------------------------------------------- */
.ll-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.ll-skip-link {
  position: absolute;
  left: -9999px;
}

.ll-skip-link:focus {
  left: var(--p3-space-16);
  top: var(--p3-space-16);
  z-index: 100;
  background: var(--p3-white);
  color: var(--p3-ink);
  padding: 12px var(--p3-space-16);
  border-radius: var(--p3-radius-button);
}

@media (prefers-reduced-motion: reduce) {
  .ll-root *, .ll-root *::before, .ll-root *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
/* --------------------------------------------------------------------------
29. DOCUMENT RESET  ==  NOT ported handoff CSS.
components.html's own showcase page supplies `body { margin: 0; background: #fff; }`
in its <style> block (line 12) — landlinie.css was split from the component
sections only, so that document-level reset never made it into any _01…_28
partial. Our TYPO3 page is the host now; it has to provide the same reset
itself, or the browser's default body margin leaves an 8px unstyled band
around .ll-root.
-------------------------------------------------------------------------- */
body {
  margin: 0;
  background: var(--p3-paper);
}

/* --------------------------------------------------------------------------
30. INTEGRATION OVERRIDES  ==  NOT ported handoff CSS.
landlinie.css does not define these classes; they are CSS the TYPO3
integration needs on top of the handoff design. Moved here (Task 1.9b) from
_04-header.scss, _05-nav-drawer.scss, _07-band.scss and _27-footer.scss,
where they had been appended directly onto ported partials, breaking the
byte-for-byte proof that those partials reproduce landlinie.css exactly.
Relocated verbatim — same selectors, same values, same media-query context.
-------------------------------------------------------------------------- */
/* from _04-header.scss: "Jetzt Kunde werden" only exists on desktop in the design (handoff JS: data-sc-desktop-only) */
.ll-header__actions .ll-btn--secondary {
  display: none;
}

@media (min-width: 768px) {
  .ll-header__actions .ll-btn--secondary {
    display: inline-flex;
  }
}
/* from _05-nav-drawer.scss */
.ll-drawer__kontakt {
  color: var(--p3-ink-soft);
}

/* The phone number became a tel: link (see Drawer.html) -- the handoff never styles a link
there either. Inherits the paragraph's own colour instead of browser-blue, underline on hover
only, matching .ll-footer__adresse a's treatment of the same kind of link. */
.ll-drawer__kontakt a {
  color: inherit;
  text-decoration: none;
}

.ll-drawer__kontakt a:hover {
  text-decoration: underline;
}

/* from _07-band.scss */
/* Design-diff 4.1/7.7 (2026-09-17): 64/128 at desktop and 40/80 at mobile read too generous
against Figma Phase 3 -- 40/80 desktop, 24/48 mobile. */
.ll-section {
  padding-block: 24px;
}

@media (min-width: 768px) {
  .ll-section {
    padding-block: var(--p3-space-40);
  }
}
/* Task 7.2 follow-up: the news detail view is the one page-level element that cannot be wrapped
in a band -- news_newsdetail is not in ll_band's allowedContentTypes, and it already emits its
own .ll-container (<article class="ll-container ll-artikel-detail">). It was therefore the last
element left with no vertical rhythm. Give it the same rhythm the section wrapper uses, rather
than widening the container allow-list to force a band around something already contained. */
.ll-artikel-detail {
  padding-block: 24px;
}

@media (min-width: 768px) {
  .ll-artikel-detail {
    padding-block: var(--p3-space-40);
  }
}
/* from _27-footer.scss */
.ll-footer__wortmarke {
  font: 600 20px/34px var(--p3-font-display);
  color: var(--p3-white);
}

/* Task 1.13: the copyright line's Initiativbewerbung link, added on Kostas's instruction (see
Footer.html) — the handoff never styles anything inside .ll-footer__copyright because it never
contains a link there. Matches the existing .ll-footer__links treatment (white on the green
footer, underline on hover) so it doesn't render browser-blue. */
.ll-footer__copyright a {
  color: var(--p3-white);
  text-decoration: none;
}

.ll-footer__copyright a:hover {
  text-decoration: underline;
}

/* The address block's email became a mailto: link when it was bot-obfuscated (see Footer.html,
config.spamProtectEmailAddresses in vv_base's setup.typoscript) — the handoff never styles a
link there either. Same treatment as .ll-footer__copyright a above. */
.ll-footer__adresse a {
  color: var(--p3-white);
  text-decoration: none;
}

.ll-footer__adresse a:hover {
  text-decoration: underline;
}

/* Task LAN-5 (ll/cta-band): the "Rückruf" band's phone number became a tel: link (see
01-wer-sind-wir.yaml, 03-kunde-werden.yaml, 06-service.yaml et al.) -- the handoff never
styles a link inside .ll-band--green-700/900 .ll-small, only the plain white text colour
(_07-band.scss). Same white-on-green, underline-on-hover treatment as .ll-footer__adresse a. */
.ll-band--green-700 .ll-small a, .ll-band--green-900 .ll-small a {
  color: inherit;
  text-decoration: none;
}

.ll-band--green-700 .ll-small a:hover, .ll-band--green-900 .ll-small a:hover {
  text-decoration: underline;
}

/* Task LAN-5 (ll/ansprechpartner): the Durchwahl line became a tel: link (Ansprechpartner
Fixtures) -- _13-ansprechpartner-card.scss already colours .ll-ansprechpartner__durchwahl
itself green-700, but that colour never reaches the <a> inside it (an anchor's own UA colour
beats an inherited one), so the whole "Durchwahl -12" rendered browser-blue instead. */
.ll-ansprechpartner__durchwahl a {
  color: inherit;
  text-decoration: none;
}

.ll-ansprechpartner__durchwahl a:hover {
  text-decoration: underline;
}

/* LAN-5: the card gained an email line (mailto: link, Ansprechpartner Fixtures) once real
addresses existed to show — same "not browser-blue" treatment as the Durchwahl link above,
since _13-ansprechpartner-card.scss has no rule of its own for this new element. */
.ll-ansprechpartner__email {
  font-size: var(--p3-body);
}

.ll-ansprechpartner__email a {
  color: var(--p3-green-700);
  text-decoration: none;
}

.ll-ansprechpartner__email a:hover {
  text-decoration: underline;
}

/* Task 2.15 (ll/liefergebiet): landlinie.css has no rule for a two-column text+map
layout — the Figma board places the quote/text/button beside the static map, but
that pairing is a TYPO3 content-block addition, not a class from the handoff. */
.ll-liefergebiet-layout {
  display: grid;
  gap: var(--p3-space-40);
}

.ll-liefergebiet-layout__text {
  display: grid;
  gap: var(--p3-space-16);
  align-content: center;
}

@media (min-width: 768px) {
  .ll-liefergebiet-layout {
    grid-template-columns: minmax(0, 1fr) 520px;
    gap: var(--p3-space-64);
  }
}
/* Task 2.17 (ll/newsletter): replaces the showcase's inline style="color:var(--p3-ink-soft)" */
.ll-newsletter__text {
  color: var(--p3-ink-soft);
}

/* LAN-5: post-signup feedback (NewsletterSubscribeMiddleware's ?newsletter=success|error) -- no
design-board precedent, so this reuses the two colours the site already treats as its "good" and
"bad" tones elsewhere (.ll-newsletter__titel's green-900, .ll-input[aria-invalid]'s #A83A20). */
.ll-newsletter__status {
  grid-column: 1/-1;
  font-size: var(--p3-small);
}

.ll-newsletter__status--success {
  color: var(--p3-green-900);
}

.ll-newsletter__status--error {
  color: #A83A20;
}

/* Task 2.18 (ll/zertifizierung): same reason as .ll-newsletter__text above */
.ll-zertifizierung__text {
  color: var(--p3-ink-soft);
}

/* Task 2.20 (ll/kanal-row): landlinie.css has no layout for the optional hint/action
row below the buttons — TYPO3 content-block additions. The block's markup also
carries a `.ll-kanal--<typ>` modifier per channel (no visual difference today; a hook
for future per-Kanal styling), deliberately left with no ruleset here. */
.ll-kanal-row__hinweis {
  color: var(--p3-ink-soft);
  margin-top: var(--p3-space-16);
}

.ll-kanal-row__aktion {
  margin-top: var(--p3-space-24);
}

/* Task 2.21 (ll/faq): landlinie.css has no wrapper for the search+Suchhilfe head above
the accordion (the showcase lays it out with an inline style="…") or for grouped
headings inside the list — TYPO3 content-block additions. */
.ll-faq-kopf {
  display: grid;
  gap: var(--p3-space-24);
  margin-bottom: var(--p3-space-40);
}

.ll-faq-kopf__reihe {
  display: grid;
  gap: 20px;
  align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.ll-accordion__gruppe {
  margin: var(--p3-space-40) 0 var(--p3-space-16);
}

.ll-accordion__leer[hidden] {
  display: none;
}

/* Task 2.22 (ll/ansprechpartner): `.ll-card-grid--karussell` is a TYPO3 modifier —
below 768px a `.ll-card-grid` becomes the same scroll-snap carousel as `.ll-carousel`
(same track rules, same child flex-basis / 44px peek); above 768px it is left as a
plain `.ll-card-grid` (no override needed here). Reused by tasks 2.23–2.26. */
@media (max-width: 767.98px) {
  .ll-card-grid--karussell {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-inline: var(--p3-gutter-mobile);
    margin-inline: calc(-1 * var(--p3-gutter-mobile));
    scroll-padding-inline-start: var(--p3-gutter-mobile);
  }
  .ll-card-grid--karussell::-webkit-scrollbar {
    display: none;
  }
  .ll-card-grid--karussell > * {
    flex: 0 0 min(318px, 100% - 40px);
    scroll-snap-align: start;
  }
}
/* Task 2.24 (ll/lieferanten-liste): replaces the showcase's inline
style="font-size:var(--p3-body)" on the Lieferant card's title. */
.ll-lieferant__name {
  font-size: var(--p3-body);
}

/* Task 4.1 (EXT:form rendering): the handoff's only error-state demo is a
label suffix with an inline style="color:#A83A20" (components.html:479) —
no full validation-message component exists in the design. #A83A20 is the
same colour already used for the invalid-input border/shadow in
_19-form-controls.scss, so this reuses it rather than introducing a new
accent — flagged for the designer since it is a TYPO3 addition, not a
ported handoff class. */
.ll-field__fehler {
  color: #A83A20;
  font-size: var(--p3-small);
}

/* Task LAN-5 (ll/video-poster): the handoff has no popover component for this. Title + hinweis
used to sit statically below the play icon at all times; moved into this popup instead (shown
on hover/focus of the whole poster button, not just the 64-96px play circle, so it's reachable
by keyboard and doesn't need pixel-precise pointer targeting), centred directly over the icon
(Kostas) rather than floating above it, relative to .ll-video__play.

Hidden with opacity + pointer-events only, NOT visibility:hidden -- title/hinweis are the
button's only real accessible name (the svg icon is aria-hidden), and visibility:hidden (unlike
opacity:0) removes an element from accessible-name computation in most browsers/ATs. That would
leave the button with no name at all outside of hover/focus.

width uses min() against 100vw so the popup can never overflow the viewport on a narrow screen
even though .ll-video itself may run edge-to-edge there -- the "also for responsive" part of
the ask; max-content is unbounded and 280px alone doesn't know how much room the viewport has. */
.ll-video__play {
  position: relative;
}

.ll-video__tooltip {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: -moz-max-content;
  width: max-content;
  max-width: min(280px, 100vw - 32px);
  display: grid;
  gap: 2px;
  background: var(--p3-ink);
  color: var(--p3-white);
  line-height: 1.4;
  padding: var(--p3-space-8) var(--p3-space-16);
  border-radius: var(--p3-radius-card);
  text-align: center;
  opacity: 0;
  transition: opacity var(--p3-dur) var(--p3-ease);
  pointer-events: none;
  z-index: 1;
}

.ll-video:hover .ll-video__tooltip,
.ll-video:focus-visible .ll-video__tooltip {
  opacity: 1;
}

/* .ll-video__titel/__hinweis default to the poster's own large, always-visible styling
(_23-video-poster.scss) -- rescaled here for a compact popup instead. */
.ll-video__tooltip .ll-video__titel {
  font-family: var(--p3-font-text);
  font-weight: 600;
  font-size: var(--p3-body);
}

.ll-video__tooltip .ll-video__hinweis {
  font-size: var(--p3-small);
  color: var(--p3-sand);
  max-width: none;
}

/* Task LAN-5 (ll/video-poster): the play icon wasn't actually vertically centred on the photo.
.ll-video is "display:grid; place-items:center" over TWO children -- the <picture> and
.ll-video__ui -- and only the <img> inside <picture> is position:absolute (_23-video-poster.scss);
<picture> itself stays in normal flow, so it's a real (if content-less) grid row alongside
.ll-video__ui, and the two rows split the available height instead of .ll-video__ui alone being
centred in all of it. Same absolute+inset:0 treatment as the <img> removes <picture> from the
grid entirely, leaving .ll-video__ui as the only track. */
.ll-video > picture {
  position: absolute;
  inset: 0;
}

/* Task LAN-5 (ll/zeitleiste): the ported partial renders the marker dot BEFORE the year
(so does the handoff's own components.html -- this is a genuine handoff/Figma divergence,
not a porting bug), but Figma (node 188:4385) puts the dot+line row AFTER the year: within
each 360px-tall column, jahr sits at 0-42, the marker row at 54-74 (its line at row-relative
y=10, its 14px dot centered on that same line), the image at 86-266, the text at 278-326 --
a consistent 12px gap between every pair. grid-template-areas re-sequences the four pieces
by name rather than DOM order, so the Fluid template's own child order stays untouched.
Mobile's areas below just make the ported partial's original 2-column "marker left, content
stacked right" auto-placement explicit -- required once media/text become independently
named grid items, since auto-placement can't skip a spanning cell like that on its own. */
.ll-meilenstein {
  grid-template-areas: "marker jahr" "marker media" "marker text";
}

.ll-meilenstein__jahr {
  grid-area: jahr;
}

.ll-meilenstein__marker {
  grid-area: marker;
}

.ll-meilenstein__media {
  grid-area: media;
}

.ll-meilenstein__text {
  grid-area: text;
}

/* Every other card-style image in the theme resets object-fit for its own <img>
(.ll-card__media, .ll-video, .ll-bild-platzhalter) -- ll-zeitleiste never did, because the
handoff's own demo never puts a real image in this slot (empty placeholder divs only). Once
a real photo renders here it keeps its own cropped pixel size instead of filling the 13:9
frame, leaving a gap -- matches the other components' treatment. */
.ll-meilenstein__media img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

@media (min-width: 768px) {
  .ll-meilenstein {
    grid-template-columns: 1fr;
    grid-template-areas: "jahr" "marker" "media" "text";
    /* This is the actual "moves on resize" bug, not the line's own top (below): .ll-zeitleiste is
    one shared grid row across all N milestones (grid-auto-flow:column), so its row height is
    set by whichever milestone has the most caption text to wrap. Every OTHER milestone's <li>
    then gets stretched to match -- and with no align-content set, CSS Grid's default (normal,
    which behaves as stretch) spreads that leftover height across all four named rows, inflating
    jahr/marker/media/text unevenly per column depending on how much shorter that column's own
    caption is. Different milestones then show their dot at different heights at the very same
    viewport width, which looks like drifting as the browser reflows on resize (measured live:
    -3px/-3px/9px/9px/3px offsets across a 5-milestone page's columns at one fixed width).
    align-content: start pins the leftover space after the last row instead, so every column's
    four rows render at their own natural, un-stretched height regardless of a sibling's caption
    length -- the dot lands at the identical position in every column, at every width. */
    align-content: start;
  }
  .ll-meilenstein__media {
    margin-top: 0;
  }
  /* NOT a fixed 64px: --p3-year is itself a fluid clamp() (24px at narrow desktop widths up
  to 35px at wide ones -- _01-tokens.scss), so the jahr row's real rendered height keeps
  changing as the viewport resizes. A hardcoded top pinned the line to one Figma snapshot
  while the marker row beneath the (shrinking/growing) year drifted away from it -- the dots
  visibly sliding off the line on resize. calc() mirrors the same formula instead of a magic
  number, so the line tracks the year's own height at every width: line-height 1.16 times the
  year's font-size, +12px gap to the marker row, +7px to reach the centre of the 14px dot
  inside it (align-items: start means the dot's own box, not a Figma-frame padding value,
  is what actually sets that row's height in the live DOM -- an earlier +10px borrowed from
  Figma's 20px "Marker" frame instead of this element's real 14px box, landing the line 3px
  below the dot's true centre and the dot 3px "too high" against it). */
  .ll-zeitleiste::before {
    top: calc(var(--p3-year) * 1.16 + 12px + 7px);
  }
}
/* Task LAN-5 (news card): .ll-card__link's own margin-top:auto (_10-card-shell.scss) only
pushes it to the bottom when .ll-card__body itself has grown taller than its own content --
which needs flex-grow, never set here. Without it, cards with a shorter teaser end their body
right after the text, so the "Weiterlesen" line lands at a different height per card instead
of lining up in one row across the grid. Shared by every .ll-card variant, harmless where
nothing stretches the card taller than its content already. */
.ll-card__body {
  flex: 1;
}

/* Whole-card click via a stretched link, not a whole-card <a> -- matches
~/Sites/viceversa/vice-versa-rocks's own ".vv-card h3 a" pattern (Kostas: "see other projects
about fake-link best seo practice"). A card's own title is the one real, crawlable link
(ll-artikel: Item.html; ll-kategorie-card: ll-kategorie-grid/frontend.fluid.html) instead of a
generic "Weiterlesen"/"Ansehen" text, or an anchor wrapping the whole card (image + eyebrow +
title + teaser, ll-kategorie-card's own previous markup) -- an anchor around non-text content
and multiple pieces of text dilutes what the link is actually about, both for SEO and for
anyone tabbing through the page by its links. The ::after covers the full card, so it's
clickable everywhere without a second interactive element.

Generic (.ll-card:not(a), .ll-card__stretched-link) rather than per-component, so any card
built as an <article>/<div> with a real link on just its title gets the same treatment --
already shared by two components, more likely than not to be reused again. A card rendered as
a plain <a> (ll-card-shell's other pattern, _10-card-shell.scss's own "a.ll-card" rules) is
unaffected; the two patterns don't overlap on one card. */
.ll-card:not(a) {
  position: relative;
  z-index: 1;
  transition: box-shadow var(--p3-dur) var(--p3-ease);
}

.ll-card:not(a):hover, .ll-card:not(a):focus-within {
  box-shadow: 0 4px 18px rgba(10, 51, 25, 0.12);
}

.ll-card:not(a):hover .ll-card__link, .ll-card:not(a):focus-within .ll-card__link {
  text-decoration: underline;
}

.ll-card__stretched-link {
  color: inherit;
  text-decoration: none;
}

.ll-card__stretched-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.ll-card__stretched-link:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 3px;
}

/* Image hover/focus zoom, clipped by .ll-card__media's own overflow:hidden. */
.ll-card:not(a) .ll-card__media img {
  transition: transform var(--p3-dur) var(--p3-ease);
}

.ll-card:not(a):hover .ll-card__media img, .ll-card:not(a):focus-within .ll-card__media img {
  transform: scale(1.05);
}

/* LAN-5: ll_form_layout (_25-zertifizierung-lieferung-panel.scss) is a fixed two-up grid — form
plus side panel. Lieferant-werden has no panel (its board has no side content), so left at the
ported default the form would only fill the 1.7fr first track, with dead space beside it instead
of the design's full content width. ll-form-layout--single (set by the Fluid template when the
Panel colPos has no child) collapses it back to one full-width column. */
.ll-form-layout--single {
  grid-template-columns: 1fr;
}

/* LAN-5: optional extra top spacing (ll/form-layout's `abstand_oben` field) -- this container
renders its own .ll-container directly (frontend.fluid.html), so it never carries the
.ll-element class the automatic .ll-element + .ll-element rhythm (_32-element.scss) keys off,
leaving no built-in way to add breathing room above it. Applied to the inner .ll-form-layout
grid, not the outer .ll-container, so it never fights that div's own id-targeted anchor scroll
position. Same 40/64px and 64/100px steps the rest of the site's spacing scale uses. */
.ll-form-layout--abstand-klein {
  margin-top: var(--p3-space-24);
}

@media (min-width: 768px) {
  .ll-form-layout--abstand-klein {
    margin-top: var(--p3-space-40);
  }
}
.ll-form-layout--abstand-gross {
  margin-top: var(--p3-space-64);
}

@media (min-width: 768px) {
  .ll-form-layout--abstand-gross {
    margin-top: var(--p3-space-100);
  }
}
/* LAN-5: the breadcrumb (_26-breadcrumb-platzhalter.scss, a ported partial with no top spacing
of its own) sits directly under the sticky header on every non-root page (Default.html) with
nothing else above it, reading as cramped against the header. */
.ll-breadcrumb {
  margin-top: var(--p3-space-16);
}

@media (min-width: 768px) {
  .ll-breadcrumb {
    margin-top: var(--p3-space-24);
  }
} /* design-diff 4.3 overrides this desktop value to 70px, see _38 */
/* LAN-5 (2026-09-18): the Ansprechpartner card's own aspect-ratio (_13-ansprechpartner-card.scss,
5:4 desktop) never matches the 'portrait' FAL crop variant it renders through (3:4 or 1:1,
sys_file_reference.php) -- object-fit:cover then crops the ALREADY-cropped photo a second time,
by default centered, which reliably eats into a headshot's hairline on top of whatever the FAL
crop itself did. `top` keeps that second crop entirely at the bottom instead, since every one of
these photos frames the head near the top of the frame with room to spare below. */
.ll-ansprechpartner .ll-card__media img {
  -o-object-position: top;
  object-position: top;
}

/* --------------------------------------------------------------------------
31. PROSE — RTE output inside ll/text. Added for TYPO3; the showcase has no
free-text block. Reuses the handoff type helpers so nothing new is designed.
(Numbered 31, not 29: _29-document-reset.scss and _30-integration-overrides.scss
already claimed those numbers by the time this task landed.)

NOTE: the brief's `@extend .ll-h2` / `@extend .ll-h3` / `@extend .ll-bullet`
fail at compile time here with "The target selector was not found." Gulp
compiles every Scss/Base/*.scss file as its own Sass entry point (not only
via theme.scss's @use graph — see gulpfile.js compileScssTheme), so each
partial is compiled in isolation and never sees .ll-h2/.ll-h3/.ll-bullet from
_02-base.scss / _16-step-herkunft-bullet.scss in the same compilation. Per the
brief's own fallback, the declarations are copied here instead of extended.
Keep them in sync with _02-base.scss and _16-step-herkunft-bullet.scss if
those ever change.
-------------------------------------------------------------------------- */
.ll-prose {
  max-width: 900px;
}

/* copied from .ll-h2 in _02-base.scss */
.ll-prose h2 {
  font-family: var(--p3-font-display);
  font-weight: 600;
  font-size: var(--p3-h2);
  line-height: 1.2;
  text-wrap: balance;
  margin: var(--p3-space-40) 0 var(--p3-space-16);
}

/* copied from .ll-h3 in _02-base.scss */
.ll-prose h3 {
  font-family: var(--p3-font-text);
  font-weight: 600;
  font-size: var(--p3-h3);
  line-height: 1.33;
  margin: var(--p3-space-24) 0 var(--p3-space-8);
}

.ll-prose p, .ll-prose li {
  font-size: var(--p3-body);
  line-height: 1.6;
  color: var(--p3-ink);
}

.ll-prose p + p {
  margin-top: var(--p3-space-16);
}

.ll-prose a:not(.ll-btn) {
  color: var(--p3-green-700);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Task 3.5 (axe audit): _07-band.scss sets `.ll-band--green-700`/`--green-900` to
white text and re-whitens `.ll-h2`/`.ll-body`/`.ll-small` at matching specificity
(0,2,0) inside those bands, but a plain `<p>`/`<li>` from an ll/text RTE block has
none of those classes, so it falls through to `.ll-prose p`'s `--p3-ink` above —
which, loaded after _07-band via theme.scss's @use order, wins the cascade even
though it was never meant to apply on a dark band. Result: near-black text on
--p3-green-700/900, a real (axe "serious", not handoff-markup) contrast failure —
caught by the Styleguide's own `01-typografie.yaml` band fixtures. Fixed at 0,3,0
specificity so it wins regardless of cascade order, without touching the
byte-locked _07-band.scss. */
.ll-band--green-700 .ll-prose p, .ll-band--green-700 .ll-prose li,
.ll-band--green-900 .ll-prose p, .ll-band--green-900 .ll-prose li {
  color: var(--p3-white);
}

/* The RTE preset's "Einleitung" / "Kleintext" / "Dachzeile" style definitions
(RTE-theme.yaml — element/class ll-lead / ll-small / ll-eyebrow, named in German in the
editor UI) put those classes directly on a <p>. Without these, the plain ".ll-prose p"
rule above (specificity 0,1,1) beats the shared ".ll-lead" / ".ll-small" / ".ll-eyebrow"
type helpers from _02-base.scss (specificity 0,1,0), silently erasing the very style the
editor picked. Re-declared here at matching specificity (copied from _02-base.scss;
margin left alone so ".ll-prose p + p" spacing still applies to a lead/small/eyebrow
paragraph). */
.ll-prose p.ll-lead {
  font-size: var(--p3-lead);
  line-height: 1.55;
  color: var(--p3-ink-soft);
}

.ll-prose p.ll-small {
  font-size: var(--p3-small);
  line-height: 1.57;
}

.ll-prose p.ll-eyebrow {
  font-size: var(--p3-eyebrow);
  font-weight: 600;
  line-height: 1.43;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--p3-gold-700);
}

/* copied from .ll-bullet / .ll-bullet::before in _16-step-herkunft-bullet.scss */
.ll-prose ul.ll-bullet-list > li {
  display: flex;
  align-items: flex-start;
  gap: var(--p3-space-16);
}

.ll-prose ul.ll-bullet-list > li::before {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  margin-top: 0.5em;
  border-radius: var(--p3-radius-pill);
  background: var(--p3-gold-700);
}

/* Bare <ul>/<ol> — an editor gets these from the toolbar's plain bulleted/numbered list
buttons without picking the "Häkchen-Liste" style, so they need their own rhythm instead
of falling back to browser default bullets/margins. The handoff has no generic list
treatment to port (every list in it — .ll-bullet-list, .ll-zeitleiste, .ll-legende,
.ll-footer__links, the breadcrumb — is purpose-built and sets list-style: none), so this
is new, but it stays consistent with that pattern's spacing and its gold-700 accent
rather than inventing a different look. `:not(.ll-bullet-list)` on the <ul> selectors
keeps this from re-winning against the classed variant just above — the same specificity
trap fixed for ll-lead/ll-small/ll-eyebrow above, in the other direction (a broader
".ll-prose ul" here would otherwise beat the global, unscoped ".ll-bullet-list" rule in
_16-step-herkunft-bullet.scss, since 0,1,1 > 0,1,0). */
.ll-prose ul:not(.ll-bullet-list), .ll-prose ol {
  margin: var(--p3-space-16) 0;
  padding-inline-start: 1.25em;
  display: grid;
  gap: var(--p3-space-8);
}

.ll-prose ul:not(.ll-bullet-list) {
  list-style: disc;
}

.ll-prose ol {
  list-style: decimal;
}

.ll-prose ul:not(.ll-bullet-list) li::marker, .ll-prose ol li::marker {
  color: var(--p3-gold-700);
}

/* --------------------------------------------------------------------------
32. ELEMENT WRAPPER — TYPO3 stacking rhythm. Not in the showcase (which places
components by hand). Tuned against the Phase 3 boards in task 2.28. Numbered 32,
not the 30 the task-2.1 brief names, because tasks 1.9b/1.11 already claimed
_30-integration-overrides.scss and _31-prose.scss after the brief was written.
-------------------------------------------------------------------------- */
.ll-element + .ll-element {
  margin-top: var(--p3-space-40);
}

@media (min-width: 768px) {
  .ll-element + .ll-element {
    margin-top: var(--p3-space-64);
  }
}
.ll-element--ll_cta_band, .ll-element--ll_kennzahlenleiste,
.ll-element + .ll-element--ll_cta_band, .ll-element + .ll-element--ll_kennzahlenleiste {
  margin-top: 0;
}

.ll-element--ll_section_header + .ll-element {
  margin-top: var(--p3-space-40);
} /* design-diff 4.2: was 24px */
/* Task LAN-5: news_pi1 is a classic EXT:news plugin, not a Content Blocks element, so it
renders inside TYPO3's own ".frame" wrapper instead of ".ll-element" -- every rule above this
one only ever matches ".ll-element" siblings, so a section header immediately followed by the
news teaser (Home's "AKTUELLES / Neues von Landlinie.") got no top spacing at all. */
.ll-element--ll_section_header + .frame {
  margin-top: var(--p3-space-40);
} /* design-diff 4.2: was 24px */
/* Same gap again, but below the karussell grid and above its own "Alle Neuigkeiten" button
(rendered inside News/List.html, not spaced by anything above) -- and to give the button
comparable room to what precedes a button elsewhere (.ll-cta-band .ll-btn, .ll-webshop-band
.ll-btn), this one grows at desktop like every other block-level gap on the page does. */
.ll-card-grid--karussell + .ll-btn {
  margin-top: var(--p3-space-24);
}

@media (min-width: 768px) {
  .ll-card-grid--karussell + .ll-btn {
    margin-top: var(--p3-space-40);
  }
}
/* --------------------------------------------------------------------------
33. HERO — page head composition (TYPO3). Figma: board heads, image 878×669
(Home) / 728×420 (subpages). Not in the showcase (which has no dedicated
hero component to port) — `.ll-hero` is a TYPO3 addition per task 2.5's brief.
(Numbered 33, not the 31 the task-2.5 brief names, because task 2.1 already
claimed _31-prose.scss — see that partial's own header for the same
renumbering, done for the same reason.)
-------------------------------------------------------------------------- */
.ll-hero {
  display: grid;
  gap: var(--p3-space-24);
  padding-block: var(--p3-space-40);
}

.ll-hero__text {
  display: grid;
  gap: var(--p3-space-16);
  align-content: center;
  max-width: 640px;
}

.ll-hero__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p3-space-16);
}

/* design-diff 2.2/2.3: the lead is .ll-hero__lead by default (subpage treatment -- Sortiment,
Kunde werden, Lieferanten, Lieferant werden, Service, Aktuelles); Home and Wer sind wir add
--gross via the ll_hero `lead_gross` field to keep the bigger .ll-lead-equivalent size. */
.ll-hero__lead {
  font-size: var(--p3-body);
  line-height: 1.667;
  color: var(--p3-ink-soft);
  margin: 0;
}

.ll-hero__lead--gross {
  font-size: var(--p3-lead);
  line-height: 1.55;
}

/* design-diff 4.6: subpage-with-image default is the 640/728 fixed grid, image 728x420 --
Home (--home) is the exception with its own 4.5 treatment below. */
.ll-hero__media img, .ll-hero__media .ll-bild-platzhalter {
  width: 100%;
  aspect-ratio: 728/420;
  -o-object-fit: cover;
  object-fit: cover;
  border-radius: var(--p3-radius-card);
}

@media (min-width: 768px) {
  .ll-hero {
    grid-template-columns: 640px 728px;
    justify-content: space-between;
    gap: var(--p3-space-64);
    padding-block: var(--p3-space-64);
  }
  /* design-diff 4.3: hero padding-top 36px on subpages (Home's own --home rule below resets it). */
  .ll-hero {
    padding-top: 36px;
  }
}
/* design-diff 4.5: Home's own grid/image shape -- 640px text column, image fills the rest at
878x669, bleeding to the viewport edge once the layout hits its own 1648px board width. */
.ll-hero--home {
  padding-top: var(--p3-space-40);
}

.ll-hero--home .ll-hero__media img, .ll-hero--home .ll-hero__media .ll-bild-platzhalter {
  aspect-ratio: 878/669;
}

@media (min-width: 768px) {
  .ll-hero--home {
    grid-template-columns: 640px minmax(0, 1fr);
    justify-content: normal;
    padding-top: var(--p3-space-64);
  }
}
@media (min-width: 1648px) {
  .ll-hero--home .ll-hero__media {
    margin-right: calc(-1 * var(--p3-gutter));
  }
}
/* Task 5.2 — some boards (P3 "Wer sind wir?", "Service & FAQ") never had a hero
image frame at all. The media slot is genuinely optional: with neither an image
nor a bild_hinweis, the template omits `.ll-hero__media` outright rather than
forcing a "FOTO BENÖTIGT" placeholder that was never asked for, and this
modifier collapses the grid back to a single column so the text does not leave
a gaping empty half at the desktop breakpoint. */
.ll-hero--ohne-medium {
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .ll-hero--ohne-medium {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* --------------------------------------------------------------------------
34. FOCUS-VISIBLE GAPS — handoff CSS omits these four (LAN-5, Task 6.2 QA)
-------------------------------------------------------------------------- */
/* Handoff §7: "Sichtbarer Fokus überall: goldener 3px-Ring (:focus-visible)."
The ported handoff CSS (_01-_28, byte-identical to the design source) opts
the gold ring in per component class and misses these four keyboard-
reachable elements. Confirmed against assets/css/landlinie.css: the gap is
in the delivered design CSS itself, not a porting omission — so it belongs
in a new numbered partial rather than in any locked _01-_28 file. */
.ll-skip-link:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-header__inner > a:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-drawer__close:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

.ll-card-grid--karussell:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
35. DRAWER AT EVERY VIEWPORT  ==  NOT ported handoff CSS.

The horizontal menu never fitted. Measured on the running site: the header needs
1422px (logo 198 + nav 681 + actions 400 + gaps + padding) while .ll-container caps
at 1408px, so it wrapped to three lines at every width below 1700px. The delivered
handoff has the same flaw -- its own components.html measures a 75px shortfall at
1440 and wraps identically -- so this is the design's, not the port's.

Rather than hide links or pick a breakpoint that puts the burger on every laptop
anyway, Kostas chose the drawer at all viewports. That means overriding two things
the ported CSS does at 768px: showing the nav, and hiding the drawer with
!important. Both overrides need !important to win, and this partial loads after
_04 and _05 so it does.
-------------------------------------------------------------------------- */
/* 1. Menu breakpoint. The ported partial swaps burger for nav at 768px, where the nav
immediately wrapped to three lines. With the menu labels shortened (nav_title in the page
fixtures) the full menu fits from 1280px, so that is where it now appears; below it the
drawer is the menu. */
@media (max-width: 1359.98px) {
  .ll-header__nav {
    display: none !important;
  }
  .ll-header__burger {
    display: inline-flex !important;
  }
}
@media (min-width: 1360px) {
  .ll-header__nav {
    display: flex !important;
    flex-wrap: nowrap;
  }
  .ll-header__burger {
    display: none !important;
  }
  /* Each label must stay on ONE line. Without this the nav "fits" while individual links
  wrap their own text -- at 1280 the link height measured 68px against 39px for a single
  line, which is the two-line header Kostas reported. A nav-height check does not catch it,
  because the nav and its links grow together. */
  .ll-header__nav a {
    white-space: nowrap;
  }
}
/* 2. The drawer must be reachable wherever the burger is. _05 hides it above 768 with
!important, which would leave the burger inert between 768 and the menu breakpoint.
Only the OPEN state is forced visible: overriding `.ll-drawer` itself would render the
closed drawer onto every page, since a closed panel carries no transform of its own.
The `[data-open="true"]` selector also outranks _05's `.ll-drawer`, so !important alone
would not have been enough. */
@media (max-width: 1359.98px) {
  .ll-drawer[data-open=true] {
    display: block !important;
  }
}
/* 3. Off-canvas entrance.
The panel slides down from above the viewport and the scrim fades, both as keyframe
animations that run when the drawer is shown.

Deliberately NOT a visibility/opacity transition, which is the obvious way to get an exit
animation too. Expressing the open state through `visibility` makes the panel unfocusable
for two animation frames after it opens, and landlinie.js focuses the close button
immediately -- the browser silently refuses, and the focus trap breaks. That was measured,
not assumed: a synchronous focus lands on <body>, a single requestAnimationFrame does too,
and forcing a layout flush does not help because computed visibility already reads
"visible" while focus is still refused.
It only surfaced under prefers-reduced-motion, i.e. for the users most likely to be
navigating by keyboard. Keeping `display` as the state -- as the ported CSS does -- means
the panel is focusable the instant it exists. An entrance animation without a matching exit
is the price; a working focus trap is not negotiable. */
@keyframes ll-drawer-in {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(0);
  }
}
@keyframes ll-drawer-scrim-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.ll-drawer[data-open=true] .ll-drawer__panel {
  animation: ll-drawer-in 320ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.ll-drawer[data-open=true] .ll-drawer__scrim {
  animation: ll-drawer-scrim-in 280ms ease both;
}

/* 4. Reduced motion: present immediately, no movement (handoff section 7). */
@media (prefers-reduced-motion: reduce) {
  .ll-drawer[data-open=true] .ll-drawer__panel,
  .ll-drawer[data-open=true] .ll-drawer__scrim {
    animation: none;
  }
}
/* --------------------------------------------------------------------------
36. SCROLL REVEAL  ==  NOT ported handoff CSS.

Every content element fades and rises into place the first time it is scrolled to.

Progressive enhancement, and the guard matters: the hidden state applies ONLY under
html.ll-reveal-ready, a class reveal.js sets as it starts. With JavaScript off, or if
the script fails to load, that class never appears and every element renders visibly.
Hiding content in CSS and relying on JS to reveal it is how a script error becomes a
blank page.

Only opacity and transform are animated. Both composite on the GPU and neither
triggers layout, so nothing shifts and the Cumulative Layout Shift score is untouched.

The hero is deliberately excluded: it is the LCP element, and delaying it costs a real
metric to animate something the visitor can already see without scrolling.
-------------------------------------------------------------------------- */
.ll-reveal-ready .ll-element[data-ll-reveal] {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 520ms cubic-bezier(0.22, 0.61, 0.36, 1), transform 520ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--ll-reveal-delay, 0ms);
  will-change: opacity, transform;
}

.ll-reveal-ready .ll-element[data-ll-reveal].is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Children of a grid or row arrive one after another rather than as a block. The delay is
set per child by reveal.js as a custom property, so the count is not hard-coded here. */
.ll-reveal-ready [data-ll-reveal-child] {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 520ms cubic-bezier(0.22, 0.61, 0.36, 1), transform 520ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--ll-reveal-delay, 0ms);
}

.ll-reveal-ready [data-ll-reveal-child].is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* will-change is a rendering hint, not a decoration: drop it once the element has
arrived so the browser stops holding a compositor layer for every element on the page. */
.ll-reveal-ready .ll-element[data-ll-reveal].is-revealed {
  will-change: auto;
}

/* Reduced motion: no movement and no fade at all. Everything is simply present --
the handoff's section 7 asks for the state, not a faster version of the animation. */
@media (prefers-reduced-motion: reduce) {
  .ll-reveal-ready .ll-element[data-ll-reveal],
  .ll-reveal-ready [data-ll-reveal-child] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
/* ==========================================================================
37 — CookieYes consent banner, in Landlinie's colours

CookieYes injects the banner into the document and colours it from its dashboard
settings. It does that by writing INLINE style attributes on nearly every themed
element (background-color: #1863dc on the buttons, #0056a7 on the revisit badge,
#212121 on every piece of text). Inline styles outrank any selector, so the
colour rules below carry !important -- specificity cannot reach them, and a first
attempt without it compiled, deployed and changed nothing but the typeface.

THE CLEANER ROUTE, if it is ever wanted: set the palette in the CookieYes
dashboard instead. It writes the same inline styles, and this file could then
drop every !important. It is not done that way today because the account holds
two sites -- staging and live, separate keys -- and a palette maintained in two
dashboards drifts from the one defined here in tokens.

Rules that CookieYes does NOT write inline (radius, weight, shadow, typeface,
the toggle track, focus rings) need no !important, only enough specificity to
beat its stylesheet -- which it injects inline at runtime, after this file, with
selectors like .cky-btn-accept (0,1,0) and .cky-consent-container
.cky-consent-bar (0,2,0). Hence the doubled class names there.

Selectors are the vendor's, read from the rendered banner rather than from
documentation. Every rule is cosmetic on purpose: a CDN release can rename these
classes, and when it does the banner reverts to CookieYes' own styling and still
works.
========================================================================== */
/* --- Shape and type: not written inline, so specificity is enough ----------- */
/* The widget otherwise inherits Fraunces, a display serif that reads as
decorative in a consent dialogue. Pin it to the text face. */
.cky-consent-container.cky-consent-container,
.cky-preference-center.cky-preference-center,
.cky-btn-revisit-wrapper.cky-btn-revisit-wrapper {
  font-family: var(--p3-font-text);
}

.cky-consent-container.cky-consent-container .cky-consent-bar {
  border-radius: var(--p3-radius-card);
  box-shadow: 0 18px 40px rgba(42, 37, 29, 0.14);
}

.cky-preference-center.cky-preference-center {
  border-radius: var(--p3-radius-card);
}

.cky-btn.cky-btn {
  border-radius: var(--p3-radius-button);
  font-weight: 600;
}

/* Category toggles: on = brand green. The vendor draws the track and the knob as
the element and its ::before, so both need a colour or the track stays blue
behind a green knob. Its own :checked rule is 0,3,0, hence the doubling. */
.cky-switch.cky-switch input[type=checkbox]:checked {
  background: var(--p3-green-500);
}
.cky-switch.cky-switch input[type=checkbox]:checked::before {
  background: var(--p3-white);
}

/* The banner is the vendor's markup, so it never inherits the site's own
focus-visible treatment (_34). Restore it here or keyboard users get whatever
ring the CDN ships that week. */
.cky-btn.cky-btn:focus-visible,
.cky-btn-revisit.cky-btn-revisit:focus-visible,
.cky-btn-close.cky-btn-close:focus-visible,
.cky-accordion-btn.cky-accordion-btn:focus-visible,
.cky-show-desc-btn.cky-show-desc-btn:focus-visible {
  outline: 3px solid var(--p3-gold-500);
  outline-offset: 2px;
}

/* --- Colour: written inline by CookieYes, so !important is the only lever --- */
.cky-consent-bar {
  border-color: var(--p3-sand) !important;
  background-color: var(--p3-white) !important;
}

.cky-title {
  color: var(--p3-green-900) !important;
}

.cky-notice-des,
.cky-preference-content-wrapper,
.cky-accordion-header-des {
  color: var(--p3-ink-soft) !important;
}

/* The actions carry the same weight order as the site's own buttons: accept is
the solid brand green, the secondaries are its outline twins, and customise
stays quiet so it does not compete with either. */
.cky-btn-accept {
  color: var(--p3-white) !important;
  border-color: var(--p3-green-500) !important;
  background-color: var(--p3-green-500) !important;
}

.cky-btn-reject,
.cky-btn-preferences {
  color: var(--p3-green-700) !important;
  border-color: var(--p3-green-500) !important;
  background-color: transparent !important;
}

.cky-btn-customize {
  color: var(--p3-ink-soft) !important;
  border-color: var(--p3-sand) !important;
  background-color: transparent !important;
}

/* The revisit badge sits on every page for the life of the site, so it reads as
part of the furniture rather than as a vendor's blue circle. */
.cky-btn-revisit-wrapper {
  background-color: var(--p3-green-500) !important;
}

.cky-preference-center {
  color: var(--p3-ink) !important;
  border-color: var(--p3-sand) !important;
  background-color: var(--p3-white) !important;
}

.cky-preference-title,
.cky-accordion-btn {
  color: var(--p3-green-900) !important;
}

.cky-show-desc-btn {
  color: var(--p3-green-700) !important;
}

.cky-always-active {
  color: var(--p3-green-700) !important;
}

.cky-audit-table {
  color: var(--p3-ink-soft) !important;
  border-color: var(--p3-sand) !important;
  background-color: var(--p3-paper-deep) !important;
}

/* --------------------------------------------------------------------------
38. DESIGN DIFF — PHASE 3 vs PREVIEW (2026-09-17). Dimi's measured diff between
the Figma Phase 3 boards and the live TYPO3 preview, action-list numbering
kept as section.item (e.g. "4.4") in each comment so it can be cross-checked
against "Design-Diff — Figma Phase 3 vs Preview 2026-09-17_final.md" directly.
Overrides of a ported partial (_01-_28) live here, never in the ported file
itself (see _29-document-reset.scss's own note on that rule); a value that
belongs to a project-owned partial (_29-_37) was changed there in place
instead of duplicated here.
-------------------------------------------------------------------------- */
/* 1. TOKENS */
:root {
  --p3-eyebrow: clamp(0.75rem, 0.7rem + 0.2vw, 0.875rem); /* 1.1 */
}

/* 1.2: the six 18px-text selectors the diff names explicitly -- .ll-body itself
already ships at line-height:1.67 (_02-base.scss) and needs no change. */
.ll-prose p, .ll-prose li,
.ll-bullet-list li,
.ll-kundenstimme__zitat,
.ll-header__link,
.ll-drawer__item,
.ll-accordion-row__summary {
  line-height: 1.667;
}

.ll-meilenstein__jahr {
  line-height: 1.2;
} /* 1.3 */
.ll-root button {
  font: inherit;
} /* 1.4, 5.17 */
.ll-skip-link {
  font-family: var(--p3-font-text);
} /* 1.5 */
.ll-band--green-500 {
  background: var(--p3-green-500);
  color: var(--p3-white);
} /* 1.6 */
.ll-band--green-500 .ll-h2, .ll-band--green-500 .ll-body, .ll-band--green-500 .ll-small {
  color: var(--p3-white);
}

/* 2. TYPE ROLES */
.ll-hero--home .ll-h1 {
  font-size: var(--p3-display);
  line-height: 1.11;
} /* 2.1 */
@media (min-width: 768px) {
  .ll-accordion-row__antwort {
    font-size: var(--p3-body);
    max-width: 1000px;
  } /* 2.4 (mobile keeps Small, untouched) */
}
.ll-zertifizierung__text {
  font-size: var(--p3-body);
} /* 2.5 */
.ll-prose--schmal {
  max-width: 1100px;
} /* 2.6, ll-text's own (until now unwired) `breite` field */
/* 3. COLOUR ROLES (3.1/3.4 also need template edits -- see Kennzahlenleiste/cta-band templates) */
.ll-kennzahl__wert {
  color: var(--p3-gold-100);
} /* 3.2 */
.ll-kennzahl__regel {
  background: var(--p3-gold-100);
}

.ll-usp-chip__icon {
  border-color: var(--p3-green-500);
  color: var(--p3-green-500);
} /* 3.5 */
.ll-herkunft__icon {
  border-color: var(--p3-green-700);
  color: var(--p3-green-700);
} /* 3.6 */
.ll-step__badge {
  background: var(--p3-green-500);
} /* 3.7 */
.ll-video__play {
  background: var(--p3-green-500);
} /* 3.8 */
.ll-btn--login {
  background: transparent;
  border: 1px solid var(--p3-gold-700);
  color: var(--p3-gold-700);
  font-size: var(--p3-label);
  padding-inline: 28px;
} /* 3.9 */
.ll-btn--login:hover {
  background: var(--p3-gold-500);
  color: var(--p3-ink);
  border-color: var(--p3-gold-500);
}

/* 3.9 follow-up: the login button only ever sits on the paper header in production, but the
Styleguide also demos every button style inside each band tone (including the dark ones) --
gold-700/ink (both "light surface" colours, per _01-tokens.scss's own comments) are unreadable
there. Axe caught this as a 1.08:1 contrast failure on styleguide/baender. */
.ll-band--green-700 .ll-btn--login, .ll-band--green-900 .ll-btn--login, .ll-band--green-500 .ll-btn--login {
  color: var(--p3-white);
  border-color: var(--p3-white);
}

.ll-band--green-700 .ll-btn--login:hover, .ll-band--green-900 .ll-btn--login:hover, .ll-band--green-500 .ll-btn--login:hover {
  background: var(--p3-white);
  color: var(--p3-green-900);
}

/* 2.7 follow-up: swapping the CTA/webshop band's second line from .ll-small to .ll-body means the
existing "Rückruf" tel: link (_30-integration-overrides.scss's own ".ll-small a" rule, same reason)
now needs the same "not browser-blue-on-green" fix for .ll-body -- axe caught this as a 1.13:1
color-contrast failure against green-700 (#0000ee on #145a2e) before this rule was added. */
.ll-band--green-700 .ll-body a, .ll-band--green-900 .ll-body a, .ll-band--green-500 .ll-body a {
  color: inherit;
  text-decoration: none;
}

.ll-band--green-700 .ll-body a:hover, .ll-band--green-900 .ll-body a:hover, .ll-band--green-500 .ll-body a:hover {
  text-decoration: underline;
}

/* 4. SPACING / LAYOUT (desktop) */
.ll-section-header {
  max-width: 900px;
} /* 4.10 */
/* 4.17: the button (ll_section_header's own new `buttons` field) sits beside the H2, same
baseline, instead of below the grid it introduces. Named areas (not a wrapper div around
eyebrow/H2/lead) so the button can share the H2's own row regardless of whether eyebrow/lead
are present on a given instance. */
.ll-section-header--mit-button {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "eyebrow eyebrow" "header aktionen" "lead lead";
  -moz-column-gap: var(--p3-space-24);
  column-gap: var(--p3-space-24);
}

.ll-section-header--mit-button .ll-eyebrow {
  grid-area: eyebrow;
}

.ll-section-header--mit-button .ll-h2 {
  grid-area: header;
  align-self: end;
}

.ll-section-header--mit-button .ll-section-header__lead {
  grid-area: lead;
}

.ll-section-header--mit-button .ll-section-header__aktionen {
  grid-area: aktionen;
  align-self: end;
}

@media (max-width: 767.98px) {
  .ll-section-header--mit-button {
    grid-template-columns: 1fr;
    grid-template-areas: "eyebrow" "header" "aktionen" "lead";
    row-gap: var(--p3-space-16);
  }
}
@media (min-width: 768px) {
  .ll-breadcrumb {
    margin-top: 70px;
  } /* 4.3 (mobile 16px stays -- not remeasured) */
  /* 4.4: Kennzahlen self-wraps its own .ll-band (template), USP/Zertifizierung/Lieferbedingungen
  sit inside the ll_band container on a shared `tone` -- distinguished here by the one child
  each band actually contains, so no schema/fixture change was needed for either. Descendant
  (not direct-child) :has(), because LlElement's own wrapper (.ll-element--ll_*) sits between
  .ll-container and the element's own markup. */
  .ll-kennzahlenleiste-band {
    padding-block: 44px;
  }
  .ll-band:has(.ll-usp-band) {
    padding-block: 44px;
  }
  .ll-band:has(.ll-zertifizierung) {
    padding-block: 48px;
  }
  .ll-band:has(.ll-prose--schmal) {
    padding-block: 48px;
  }
  .ll-kategorie-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 40px;
    align-items: start;
  } /* 4.8 */
  .ll-card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  } /* 4.9 */
  .ll-newsletter__form {
    grid-template-columns: minmax(0, 420px) minmax(0, 130px);
    justify-content: space-between;
  } /* 4.11 */
  .ll-newsletter__hinweis {
    max-width: 600px;
  }
  .ll-footer__inner {
    grid-template-columns: 600px repeat(3, 1fr);
  } /* 4.12 */
  .ll-liefergebiet {
    padding: 20px 40px;
  } /* 4.15 */
  .ll-legende {
    gap: 8px;
  }
}
.ll-footer__social {
  gap: 16px;
} /* 4.13 (not breakpoint-scoped in the diff) */
@media (min-width: 768px) {
  /* 4.14, overrides _30's own @768 rule -- loads after it, same media query, same specificity */
  .ll-liefergebiet-layout {
    grid-template-columns: 700px 520px;
    justify-content: space-between;
    gap: var(--p3-space-64);
  }
  .ll-zeitleiste {
    grid-auto-flow: unset;
    grid-template-columns: repeat(auto-fit, 260px);
    justify-content: space-between;
    gap: 27px;
  } /* 4.16 */
}
/* 5. COMPONENTS */
.ll-kategorie-card .ll-card__media {
  aspect-ratio: 322/260;
} /* 5.1 */
.ll-kategorie-card--featured .ll-card__media {
  aspect-ratio: 322/300;
} /* 5.2 */
.ll-artikel .ll-card__media {
  aspect-ratio: 442/240;
} /* 5.3 */
/* 5.4: neutralises the ported small-avatar row layout (_14-lieferant-card.scss) now that the
Lieferanten partner card matches ll-erzeuger-portraits' full portrait-card markup instead. */
.ll-lieferant {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: 0;
}

@media (min-width: 768px) {
  .ll-lieferant {
    padding: 0;
    gap: 0;
  }
}
.ll-card-grid--erzeuger .ll-card__media, .ll-lieferant .ll-card__media {
  width: 100%;
  height: auto;
  flex: none;
  border-radius: 0;
  aspect-ratio: 442/340;
}

@media (min-width: 768px) {
  .ll-lieferant .ll-card__media {
    width: 100%;
    height: auto;
    border-radius: 0;
  }
}
.ll-card-grid--case-studies .ll-card__media {
  aspect-ratio: 442/200;
} /* 5.5 */
.ll-ansprechpartner .ll-card__body {
  padding: 20px;
  gap: 6px;
} /* 5.6 */
.ll-kennzahl {
  gap: 6px;
} /* 5.7 */
.ll-bullet-list {
  gap: 24px;
} /* 5.8 */
@media (min-width: 768px) {
  .ll-accordion-row__summary {
    padding-block: 24px;
  } /* 5.9 */
  .ll-accordion-row__schalter::before {
    width: 20px;
  }
  .ll-accordion-row__schalter::after {
    height: 20px;
  }
  .ll-faq-search {
    min-height: 64px;
    padding: 0 20px;
    gap: 12px;
  } /* 5.10 */
  .ll-faq-kopf__reihe {
    grid-template-columns: 700px 628px;
    -moz-column-gap: 80px;
    column-gap: 80px;
  } /* 5.12 */
}
.ll-faq-search {
  min-height: 56px;
} /* 5.10 mobile */
.ll-suchhilfe {
  padding: 12px 24px;
} /* 5.11 */
.ll-suchhilfe__schritte {
  gap: 4px;
}

.ll-input, .ll-select, .ll-textarea {
  padding: 10px var(--p3-space-16);
  line-height: 30px;
} /* 5.13 */
/* 5.14: inline data-URI replaces a background-image path that 404s from Css/Base/theme.css. */
.ll-select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'><path d='M5 7.5L10 12.5L15 7.5' stroke='%235A5347' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

fieldset.ll-checkbox-group {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
} /* 5.15 */
/* 6.9: no class/aspect-ratio was ever set on the news detail image at all -- it rendered at
its natural crop (1408x1877 on the article that first surfaced this). */
.ll-artikel-detail__bild {
  width: 100%;
  aspect-ratio: 1408/560;
  -o-object-fit: cover;
  object-fit: cover;
  border-radius: var(--p3-radius-card);
}

/* 7.11: badge/eyebrow swap by breakpoint -- both render unconditionally (ll-steps template),
CSS alone decides which one shows. */
.ll-step__nummer {
  display: none;
}

/* 7. MOBILE (<768px) */
@media (max-width: 767.98px) {
  :root {
    --p3-radius-card: 16px;
  } /* 7.3 */
  .ll-hero .ll-btn--inline, .ll-cta-band .ll-btn--inline,
  .ll-webshop-band .ll-btn--inline, .ll-newsletter .ll-btn {
    width: 100%;
  } /* 7.4 */
  .ll-kategorie-card .ll-card__media {
    aspect-ratio: 172/110;
  } /* 7.6 */
  .ll-kennzahlenleiste-band {
    padding: 28px 16px;
  } /* 7.5 */
  .ll-kennzahlenleiste {
    gap: 16px;
  }
  .ll-newsletter {
    margin-inline: calc(-1 * var(--p3-gutter-mobile));
    border-radius: 0; /* 7.8 */
    padding: 32px var(--p3-gutter-mobile);
  }
  .ll-cta-band {
    padding: 32px 16px;
  } /* 7.9 */
  .ll-video__play {
    width: 64px;
    height: 64px;
  } /* 7.13 */
  .ll-video__play svg {
    width: 26px;
    height: 26px;
  }
  .ll-btn--login {
    background: none;
    border: 2px solid var(--p3-gold-500);
    color: var(--p3-ink); /* 7.1 */
    font-size: var(--p3-label);
    height: 44px;
    min-height: 44px;
    padding: 0 16px;
    border-radius: 10px;
  }
  .ll-btn--login__praefix {
    display: none;
  }
  .ll-card-grid--case-studies .ll-card__media {
    aspect-ratio: 358/160;
  } /* 7.12 */
  .ll-step__badge {
    display: none;
  } /* 7.11 */
  .ll-step__nummer {
    display: block;
  }
  .ll-footer__spalte--webshop {
    display: none;
  } /* 7.10 */
  .ll-footer__links--rechtlich {
    display: flex;
    flex-wrap: wrap;
    gap: 0;
  }
  .ll-footer__links--rechtlich li:not(:last-child)::after {
    content: " · ";
  }
}
/*# sourceMappingURL=theme.css.map */
