/* ==========================================================================
   KI Beratung Hessen — stylesheet
   Tokens extracted from the live Elementor kit (.elementor-kit-10).
   See docs/design-system.md for provenance.
   ========================================================================== */

/* --- Tokens ------------------------------------------------------------- */

:root {
  /* Brand */
  --c-primary: #31363f;
  --c-secondary: #eeeeee;
  --c-text: #222831;
  --c-accent: #76abae;

  /* Extended palette */
  --c-white: #ffffff;
  --c-surface: #f8faf9;
  --c-surface-alt: #edf0ef;
  --c-lime: #d6d84f;
  --c-teal-muted: #587274;
  --c-teal-dark: #3c6264;
  --c-teal-deep: #1c3738;
  --c-ink: #0d1d20;

  /* Derived */
  --c-text-muted: #5b636e;
  --c-border: #e2e6e5;
  --c-accent-dark: #5f9295;
  --c-accent-soft: rgba(118, 171, 174, 0.12);

  /*
    Typography — two faces, split the way the live site splits them.

    Running text is Verdana there, and Verdana ships with Windows and macOS,
    so it costs no webfont and raises no licence question. Geneva and DejaVu
    Sans are the nearest stand-ins where it is absent.

    Headings, nav and buttons are Avenir there. Avenir is a licensed Linotype
    face we cannot serve ourselves, so this is Mulish, picked by measuring
    candidates against the real Avenir files rather than by reputation: it
    renders the same headline at 100.2% of Avenir's width and its letterforms
    stay in register across a whole line, where Nunito Sans, Figtree and DM
    Sans all drift apart by the end of it.

    Verdana carries only Regular and Bold, so a 600 lands on synthesised or
    real bold. That is what the live site does too — it asks for 600 in
    Verdana in several places.
  */
  --font-sans: Verdana, Geneva, "DejaVu Sans", sans-serif;
  --font-display: Mulish, -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;

  --fs-eyebrow: 0.75rem;   /* 12 */
  --fs-caption: 0.875rem;  /* 14 */
  --fs-small: 0.9375rem;   /* 15 */
  --fs-body: 1rem;         /* 16 */
  --fs-body-lg: 1.125rem;  /* 18 */
  --fs-lead: 1.25rem;      /* 20 */
  --fs-h4: 1.5rem;         /* 24 */
  --fs-h3: 1.75rem;        /* 28 */
  --fs-h2-sm: 2rem;        /* 32 */
  --fs-h2: 2.375rem;       /* 38 */
  --fs-h1: 3rem;           /* 48 */
  --fs-display: 3.25rem;   /* 52 */
  /* Fluid between the tablet size and 64px. Fixed at 64px, "maßgeschneiderte"
     did not fit the hero's 1.1fr column between 1025px and ~1097px and got
     chopped mid-word. Lower bound matches the <=1024px value so there is no
     jump at that breakpoint. */
  --fs-hero: clamp(3.25rem, 5.4vw, 4rem);
  --fs-numeral: 10.625rem; /* 170 */

  /* Spacing */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 5rem;
  --sp-10: 7rem;

  /* Layout */
  --container: 1140px;
  --container-wide: 1240px;
  --radius: 12px;
  --radius-lg: 20px;
  /* The original runs a 109px bar. Ours sat at 76px, which Willy read as
     cramped, so it went to 104px -- and Hari then read that as too tall.
     92px is where it settled: clearly roomier than the 76 it came from,
     lighter than a full-height copy of the original. The type inside is
     untouched at its measured sizes throughout. Phones keep 76px -- see the
     <=767px block -- because a tall sticky bar there costs screen a visitor
     cannot spare. */
  --header-h: 92px;

  --shadow-sm: 0 1px 3px rgba(34, 40, 49, 0.06),
    0 4px 12px rgba(34, 40, 49, 0.05);
  --shadow-md: 0 4px 16px rgba(34, 40, 49, 0.08),
    0 12px 32px rgba(34, 40, 49, 0.07);

  --transition: 180ms cubic-bezier(0.4, 0, 0.2, 1);

  /*
    Strength of the cursor glow, as one dial. 0.26 reads as a soft teal wash on
    both the light grounds and the dark bands; 0.15 is barely perceptible, 0.35
    starts to read as a spot you can point at rather than a warmth in the page.
  */
  --glow-a: 0.26;
}

/* --- Reset -------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.6;
  color: var(--c-text);
  background: var(--c-white);
  -webkit-font-smoothing: antialiased;
  /*
    Deliberately NOT using `overflow-x: hidden` here. It would paper over
    horizontal overflow instead of fixing it, and it hides the symptom from
    the QA pass in tests/qa.py. Overflow is fixed at the source instead
    (see the min-width:0 rule below).
  */
}

/*
  Grid and flex children default to `min-width: auto`, which refuses to shrink
  below the widest unbreakable word. With long German compounds
  ("maßgeschneiderte") that pushes the track wider than the viewport. Resetting
  to 0 lets overflow-wrap actually do its job.
*/
.grid > *,
.hero__grid > *,
.split > *,
.steps > *,
.team > *,
.chips > *,
.logos > *,
.site-footer__grid > * {
  min-width: 0;
}

img,
picture,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.2;
  color: var(--c-primary);
  /*
    Long German compounds must never punch out of their container, but
    `hyphens: auto` breaks far too eagerly here ("maß-geschneiderte",
    "Erstge-spräch"). break-word alone only splits a word that genuinely
    cannot fit, which is the behaviour we want.
  */
  overflow-wrap: break-word;
  hyphens: manual;
  /*
    Evens out the line lengths instead of filling each line greedily, which is
    what stranded single short words on a heading's last line -- worst on the
    numbered headings of the legal pages at phone widths. Browsers without it
    fall back to normal wrapping.
  */
  text-wrap: balance;
}

/*
  Card titles are the exception. They sit in columns ~250px wide, where single
  German compounds ("Digitalisierungsbeauftragter", "Automatisierungskompetenz")
  are simply wider than the box. Hyphenation is the normal German answer at
  this size and beats break-word chopping the word with no hyphen at all. It
  stays off for display headings, where it broke "maß-geschneiderte".
*/
/*
  `.case h3` stays in this list on purpose. Willy asked for whole words in the
  testimonial cards, and that is done for the attributions below -- they now
  have room to fit. These headings cannot: "Dokumentenverarbeitung" wants
  317px in a 275px column at laptop width. Without hyphenation the browser
  chops it with no hyphen at all ("Dokumentenverarbeitun / g"), which is worse
  than the syllable break. tests/qa.py takes the same view and only reports a
  word as broken when the element is *not* hyphenating.
*/
.card h3,
.case h3,
.step h3,
.tier h3 {
  hyphens: auto;
  /*
    Unconstrained, `auto` hyphenates whenever it packs a line better, not only
    when a word will not fit -- it split "Human-in-the-Loop" into "Hu-man".
    Require a long word and a substantial fragment on each side, so only the
    compounds that genuinely overflow get broken.
  */
  -webkit-hyphenate-limit-before: 5;
  -webkit-hyphenate-limit-after: 4;
  -webkit-hyphenate-limit-lines: 2;
  hyphenate-limit-chars: 10 5 4;
}

p {
  margin: 0;
  overflow-wrap: break-word;
}

/* Same break-word safety net as <p>. Without it a long German compound in a
   testimonial or a bullet punches out of a narrow card at laptop widths. */
blockquote, li, dd {
  overflow-wrap: break-word;
}

/* The UA gives blockquote and figure `margin: 1em 40px`. Nothing here wants
   that: the quote treatments carry their own padding and left border, the 40px
   was squeezing testimonials into a column too narrow for German compounds,
   and on figures it pushed images 24px past their grid column. */
blockquote,
figure {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
}

a {
  color: var(--c-accent-dark);
  text-decoration: none;
  transition: color var(--transition);
}

a:hover {
  color: var(--c-teal-dark);
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

/*
  The ring is --c-accent, which is also the primary button's own background --
  so on that one button the pair measures 1.0:1 and the ring reads only as the
  3px offset gap around it. A two-tone white-and-dark ring was tried and Hari
  turned it down: he would rather the indicator stayed in the palette, and the
  offset gap is enough to see where focus is. Noted, not re-litigated.
*/
:focus-visible {
  outline: 3px solid var(--c-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* --- Utilities ---------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--sp-5);
}

.container--wide { max-width: var(--container-wide); }

.section {
  padding-block: var(--sp-9);
}

.section--tight { padding-block: var(--sp-8); }
.section--surface { background: var(--c-surface); }
.section--alt { background: var(--c-surface-alt); }

/*
  A section that closes on a centred call-to-action needs less room after it
  than one closing on a paragraph. The button already carries `.btn-row`'s own
  top margin, then two section paddings stack under it and the next heading
  adds its leading on top, so the join reads as a hole rather than as a break
  -- 156px and 172px on the homepage before this. Willy flagged two of them;
  matching on the shape catches every section built the same way instead of
  hard-coding the two. E-Rechnung is untouched by design: it uses `.er-section`
  and has to stay 1:1 with the original.
*/
.section:has(> .container > .btn-row:last-child) { padding-bottom: var(--sp-5); }
.section--dark {
  background: var(--c-primary);
  color: var(--c-secondary);
}
.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4 { color: var(--c-white); }
.section--dark p { color: rgba(255, 255, 255, 0.78); }
.section--dark .eyebrow { color: var(--c-accent); }
.section--dark .ticks { color: rgba(255, 255, 255, 0.78); }
.section--dark .ticks li::before { color: var(--c-accent); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: var(--sp-3) var(--sp-5);
  background: var(--c-primary);
  color: var(--c-white);
  border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus {
  left: 0;
  color: var(--c-white);
}

.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;
}

.eyebrow {
  font-family: var(--font-display);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-accent-dark);
}

.section-head {
  max-width: 46rem;
  margin-bottom: var(--sp-7);
}
.section-head--center {
  margin-inline: auto;
  text-align: center;
}
.section-head h2 {
  font-size: var(--fs-h2);
  margin-top: var(--sp-3);
}
.section-head p {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-lg);
  color: var(--c-text-muted);
}
.section--dark .section-head p { color: rgba(255, 255, 255, 0.75); }

/* `pretty` only reflows the last few lines, so long body copy keeps its
   normal wrapping but does not end on a lone word. */
.prose p,
.prose li,
.case-body p,
.lead,
.section-head p {
  text-wrap: pretty;
}

.lead {
  font-size: var(--fs-lead);
  color: var(--c-text-muted);
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
  font-family: var(--font-display);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 0.8125rem 1.625rem;
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
  /*
    One radius for every button on the site. The original renders the homepage
    buttons square-ish and every other page's pill-shaped, so the same
    "Kostenloses Erstgespräch" button in the shared header changed shape as you
    moved between pages. The homepage shape is the one we keep, rounded a hair
    further than the 4px measured there.
  */
  border-radius: 6px;
  border: 2px solid transparent;
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
    border-color var(--transition), transform var(--transition);
}

@media (hover: hover) {
  .btn:hover { transform: translateY(-1px); }
}
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--c-accent);
  border-color: var(--c-accent);
  color: var(--c-white);
}
.btn--primary:hover {
  background: var(--c-accent-dark);
  border-color: var(--c-accent-dark);
  color: var(--c-white);
}

.btn--outline {
  border-color: var(--c-primary);
  color: var(--c-primary);
}
.btn--outline:hover {
  background: var(--c-primary);
  color: var(--c-white);
}

.section--dark .btn--outline {
  border-color: rgba(255, 255, 255, 0.5);
  color: var(--c-white);
}
.section--dark .btn--outline:hover {
  background: var(--c-white);
  border-color: var(--c-white);
  color: var(--c-primary);
}

.btn--ghost {
  font-family: var(--font-sans);
  padding-inline: 0;
  color: var(--c-accent-dark);
}
.btn--ghost:hover {
  color: var(--c-teal-dark);
  transform: none;
}
.btn--ghost::after {
  content: "›";
  font-size: 1.2em;
  line-height: 1;
  transition: transform var(--transition);
}
.btn--ghost:hover::after { transform: translateX(3px); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
}
.btn-row--center { justify-content: center; }

/* --- Header ------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--c-border);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: var(--header-h);
}

/* The taller bar is for the desktop row of links Willy was looking at. A
   phone shows a logo and a hamburger in the same space and cannot spare
   28px of every screen to a sticky bar, so it keeps the old height. */
@media (max-width: 767px) {
  :root { --header-h: 76px; }
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-shrink: 0;
  color: var(--c-primary);
}
.brand:hover { color: var(--c-primary); }

/* Header wordmark, at the original's proportion: it runs 89px in a 109px bar,
   which is 82%. Derived from `--header-h` rather than written as a number, so
   it follows the bar at every breakpoint instead of needing an override per
   height. (The footer and the landscape override set their own heights below
   and still win, being later and more specific.) */
.brand__logo {
  display: block;
  width: auto;
  height: calc(var(--header-h) * 0.82);
}
/* Footer: the wordmark sits above the tagline rather than beside it, and gets
   more room than in the header because no nav is competing for the space. */
.brand--stack {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
}
.site-footer .brand__logo { height: 60px; }

.brand__tag {
  font-size: 0.6875rem;
  color: var(--c-text-muted);
}

/* Navigation */
.nav { display: flex; align-items: center; gap: var(--sp-5); }

.nav__list {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  list-style: none;
}

.nav__link {
  font-family: var(--font-display);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-body);
  /*
    The original asks for 600 in Avenir, which ships 400 and 700 only, so its
    nav renders bold -- the same trick as every heading on the site. Mulish
    has a real 600, so a literal 600 here came out semibold: lighter and, next
    to the 700 headings, visibly greyer. 700 is the match.
  */
  font-weight: 700;
  color: var(--c-primary);
  border-radius: 8px;
  white-space: nowrap;
  transition: background var(--transition), color var(--transition);
}
.nav__link:hover,
.nav__link.is-active {
  background: var(--c-accent-soft);
  color: var(--c-teal-dark);
}

/* Mobile toggle */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 10px;
  border-radius: 8px;
}
.nav-toggle span {
  display: block;
  height: 2px;
  background: var(--c-primary);
  border-radius: 2px;
  transition: transform var(--transition), opacity var(--transition);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* --- Hero --------------------------------------------------------------- */

.hero {
  position: relative;
  padding-block: var(--sp-10) var(--sp-9);
  background:
    radial-gradient(ellipse 70% 60% at 75% 0%, var(--c-accent-soft), transparent 70%),
    var(--c-surface);
  overflow: hidden;
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: var(--sp-8);
  align-items: center;
}

.hero__eyebrow { margin-bottom: var(--sp-4); }

.hero h1 {
  font-size: var(--fs-hero);
  line-height: 1.05;
}

.hero h2 {
  font-size: var(--fs-hero);
  line-height: 1.05;
  color: var(--c-accent-dark);
}

.hero__text {
  margin-top: var(--sp-5);
  font-size: var(--fs-body-lg);
  color: var(--c-text-muted);
  max-width: 34rem;
}

.hero__stat {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-accent);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  box-shadow: var(--shadow-sm);
}
.hero__stat strong { color: var(--c-accent-dark); }

.hero__media {
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}

/* --- Real imagery ------------------------------------------------------- */

/*
  Every one of these replaced a dashed `.ph` box, so each needs the sizing the
  placeholder used to provide. Widths and heights are on the elements
  themselves as well, so the space is reserved before the file arrives and the
  page does not jump.
*/

/* Homepage hero. The original draws the robot straight onto the page -- no
   card, no crop -- and it is a cut-out on transparent, so the rounded box and
   the shadow the placeholder wore would have framed empty air. */
.page-home .hero__media {
  position: relative;
  aspect-ratio: auto;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
}
/*
  The teal panel the robot sits on. The original paints it on the section
  behind the image rather than on the image itself, so the cut-out overhangs
  it: on the live page the panel starts ~9% below the top of the picture and
  stops ~4% above its foot, which is what lets the head and the pedestal
  break out of the rectangle. Percentages rather than pixels so the overhang
  holds as the column resizes. The gradient is the original's, verbatim.
*/
.page-home .hero__media::before {
  content: "";
  position: absolute;
  inset: 9% 0 4% 0;
  border-radius: 4px;
  background: linear-gradient(210deg, rgb(65, 147, 143) 29%, rgb(87, 227, 220) 52%);
}
/* The panel is absolutely positioned and would otherwise paint over the
   static image; this lifts the robot back on top of it. */
.page-home .hero__media img {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
}

/* Client strip. The logos are 300x300 with their own generous white margin,
   so they are contained rather than cropped and share one height, which puts
   the marks on a common baseline however differently they are drawn. */
/*
  Every one of these files is a 300x300 square carrying roughly a quarter of
  its own width as blank margin, so the painted mark is only about 75% of
  whatever box it is given. At the 5.25rem the placeholder used, that left
  ~50px marks in a 150px cell -- too small to read in a "trusted by" strip.
  A 7rem box brings them to ~84px. Scaling the element instead was tried and
  dropped: `transform` grows the box as well as the paint, so the outer logos
  reported as overflowing their container even though nothing was visible
  there.
*/
/*
  Each mark sits on its own grey tile, the way the original lays the strip
  out. All seven files are opaque squares -- none carries an alpha channel --
  so a tile behind them would simply be covered up, and the ground has to be
  blended away instead. `isolation` keeps that blend inside the tile rather
  than letting it reach the page behind.

  `darken` rather than `multiply`: two of the files (Zrakic and J&J) are not
  white-on-white but carry a 247-grey border around a pure-white panel.
  Multiply preserves that 8-level step and turned it into a visible lighter
  rectangle inside the tile. Darken takes the channel minimum, so every tone
  lighter than the tile collapses onto it and the border vanishes, while the
  marks themselves -- all far darker than #edf0ef -- come through untouched.
*/
.logos__tile {
  display: grid;
  place-items: center;
  isolation: isolate;
  width: 100%;
  /* 128px. The tile and the mark inside it shrink together, which is what
     Willy asked for -- the mark is `contain`ed, so it follows the box. */
  max-width: 8rem;
  aspect-ratio: 1;
  background: var(--c-surface-alt);
  border-radius: 4px;
}
.logos__item {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  mix-blend-mode: darken;
}
/*
  The marks are `contain`ed, so a file with 30% empty margin baked into it
  rendered its mark at 70% of the tile -- which is why U2care and Wonderland
  were unreadable. Scaling the <img> was tried and rejected: it pushes the
  image box past the tile, so the mark is either clipped or spills outside the
  grey square. The whitespace is trimmed out of the files themselves instead,
  all seven now filling 92% of their square, so every mark is bigger at the
  same tile size and nothing overflows.
*/

/* Testimonial and case-study avatars. Portraits are not square (Torsten is
   1024x984), so `cover` keeps the face centred instead of squashing it. */
img.case__avatar,
img.case-quote__avatar {
  display: block;
  object-fit: cover;
  border-radius: 999px;
}
img.case__shot,
.case-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.case-figure img { border-radius: var(--radius-lg); aspect-ratio: 1140 / 384; }

/* Certificate and test mark. Both keep their own proportions; the aspect
   ratios on .why__cert/.why__seal already match the files. */
.why__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: rgba(0, 0, 0, 0.1) 3px 0 15px 0;
}

/* Team portraits. The source files are circular cut-outs on white, so a round
   mask lands exactly on the circle rather than cropping into the face. */
.member__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 999px;
}

/*
  Three testimonials on /ergebnisse/ carry a company wordmark rather than a
  portrait or a round client mark. They use the same 57px circle as every
  other card on the page, so the row of attributions stays uniform; the
  wordmarks are simply contained inside it. Entropia's is 2.89:1 and Business
  Elegance's 1.18:1, so they come out small -- deliberately so, on Hari's
  call: the company name is spelled out in full right beside the circle, so
  the mark only has to be recognisable, not readable. BE Renovierung supplied
  no logo, so its circle carries the name as type.
*/
.case__mark {
  /*
    Flex, not grid: an `auto` grid row sizes to its own content, so the image
    height fed back into the row and a percentage cap on it was circular --
    the taller wordmark spilled out of the circle. A flex container with a
    fixed size gives the child a definite box to be capped against.
  */
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  /* Matches `.page-ergebnisse .case__avatar`; these three cards exist only
     on that page. */
  width: 57px;
  height: 57px;
  padding: 6px;
  overflow: hidden;
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: 999px;
}
.case__mark img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* The wordmark closing the E-Rechnung page, on the black band. */
.er-cta__logo {
  display: block;
  width: 171px;
  height: auto;
  margin: 0 auto var(--sp-5);
}

/*
  Client wordmark under the quote on the two Hinnerbäcker case studies, the
  same 92px the original gives it. The file is a JPEG with its own white
  ground, and the original sits it on a light band; our hero is dark, so it
  would otherwise read as a bare white rectangle. Padding and a radius turn
  that white into a deliberate chip -- the original rounds it too (25px).
*/
.case-quote__logo {
  display: block;
  box-sizing: content-box;
  width: 92px;
  height: auto;
  margin-top: var(--sp-4);
  padding: 5px 9px;
  background: var(--c-white);
  border-radius: 10px;
}

/* --- Placeholder (assets pending upload) -------------------------------- */

.ph {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  min-height: 6rem;
  padding: var(--sp-4);
  text-align: center;
  color: var(--c-teal-muted);
  background:
    repeating-linear-gradient(
      45deg,
      var(--c-surface-alt) 0 10px,
      var(--c-surface) 10px 20px
    );
  border: 1px dashed var(--c-accent);
  border-radius: var(--radius);
  font-size: var(--fs-caption);
  font-weight: 600;
}
.ph--round { border-radius: 999px; }
.ph--flat { border-radius: 0; }

/* --- Logo strip --------------------------------------------------------- */

.logos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--sp-5);
  align-items: center;
  justify-items: center;
}
.logos .ph { min-height: 4.5rem; }

/* --- Card grids --------------------------------------------------------- */

.grid {
  display: grid;
  gap: var(--sp-5);
}
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

/* Cap at 3 columns on wide screens so the 9 solution cards land 3×3 rather
   than 4/4/1 with an orphan on the last row. */
@media (min-width: 1100px) {
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* This grid mixes full-width cards in among the normal ones, so the spans
   below only land on flush rows if the column count is known. That is why it
   pins the count rather than leaving it to auto-fit — the three counts are
   the ones auto-fit was already producing at these widths, written down so a
   token change cannot quietly put the spans out of step with the layout. */
.grid--testimonials { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 600px) {
  .grid--testimonials { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 912px) {
  .grid--testimonials { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* One testimonial runs several times longer than the rest. Given the full
   width it reads as its own band, and it stops stretching whatever would
   otherwise have to share its row. */
.case--wide { grid-column: 1 / -1; }

/* At three columns the full-width card above shifts everything after it by
   two slots, which leaves the closing card alone on the last row — so it
   takes the whole row rather than sitting in a third of it. At two columns
   the slots already come out even and it needs no help. */
@media (min-width: 912px) {
  .case--close { grid-column: 1 / -1; }
}

/* Four across, or two — never three. Left to auto-fit, the four "Warum wir?"
   pillars land 3+1 with an orphan, and the three-column tracks are too narrow
   for "Unternehmensprozesse" to fit on a line. */
@media (min-width: 560px) and (max-width: 1099px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1100px) {
  .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  height: 100%;
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition);
}

/*
  Gated on a real pointer. A touch browser applies :hover on tap and, on iOS,
  leaves it applied until the visitor taps somewhere else -- so without this
  the card stays lifted, or recoloured, long after the tap that caused it.
  The effect is decoration, so not running it on touch at all is the right
  answer rather than trying to time it out. The same gate is on every other
  decorative hover in this file.
*/
@media (hover: hover) {
  .card--link:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
  }
}

.card h3 {
  font-size: var(--fs-h4);
}
.card p {
  color: var(--c-text-muted);
  font-size: var(--fs-small);
}

/* push the trailing link to the bottom so cards align regardless of copy length */
.card__foot { margin-top: auto; padding-top: var(--sp-3); }

/* Testimonial / case-study card */
.case {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-6);
  height: 100%;
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition);
}
@media (hover: hover) {
  .case:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
  }
}
.case h3 { font-size: var(--fs-h4); }
.case__result {
  font-size: var(--fs-small);
  color: var(--c-text-muted);
}
.case__quote {
  font-family: var(--font-display);
  padding-left: var(--sp-4);
  border-left: 3px solid var(--c-accent);
  font-size: var(--fs-small);
  font-style: italic;
  color: var(--c-text);
}
.case__author {
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--c-primary);
}
.case__company {
  font-size: var(--fs-caption);
  color: var(--c-text-muted);
}

/* Recommendation variant. Same shell as .case -- only the internals are
   simpler: no result line above the quote and no "Mehr lesen" link below it,
   because these recommendations have no detail page. */
.case--reco { gap: var(--sp-5); }

.case__person {
  /* Pinned to the bottom so avatars line up across a row of cards whose
     quotes differ in length. The slack is taken here and not by the quote
     box: a growing quote drags its accent rule down through the empty space,
     which is very visible next to a rowmate with a much longer testimonial. */
  margin-top: auto;
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: center;
}
/* .ph is built for image slots -- full width, 6rem tall, padded. An avatar
   needs the opposite, so all three are overridden here. */
.case__avatar {
  width: 4rem;
  height: 4rem;
  min-height: 0;
  padding: 0;
}

/* --- Feature list (Warum wir) ------------------------------------------- */

.pillar {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  /* Tighter than the other cards on purpose: these sit four-across, and at
     32px the column got too narrow for "Unternehmensprozesse" to fit. */
  padding: var(--sp-5);
  height: 100%;
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
}
.pillar h3 { font-size: var(--fs-body-lg); }

.ticks {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  list-style: none;
  font-size: var(--fs-small);
  color: var(--c-text-muted);
}
.ticks li {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  /* The label is an anonymous flex item, so it has no box to put min-width:0
     on. Its min-content contribution is the longest word, which overflows a
     narrow .pillar ("Unternehmensprozesse"). `anywhere` (not `break-word`) is
     what shrinks that contribution, so the word wraps inside the card instead
     of punching out of it. `hyphens: auto` was tried instead and rejected: it
     hyphenated every line in the card and still failed on that word. */
  overflow-wrap: anywhere;
}
.ticks li::before {
  content: "✓";
  flex-shrink: 0;
  color: var(--c-accent-dark);
  font-weight: 600;
}

/* --- Team --------------------------------------------------------------- */

.team {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: var(--sp-6);
}

.member {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  padding: var(--sp-6);
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.member__photo { aspect-ratio: 1; }
.member__name { font-size: var(--fs-h4); }
.member__quote {
  margin-top: var(--sp-3);
  font-size: var(--fs-small);
  color: var(--c-text-muted);
}
.member__link { margin-top: var(--sp-4); }

/* --- Process steps ------------------------------------------------------ */

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--sp-5);
  counter-reset: step;
}

.step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  padding-top: var(--sp-7);
  height: 100%;
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
}
.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  top: var(--sp-5);
  right: var(--sp-5);
  font-size: var(--fs-h1);
  font-weight: 600;
  line-height: 1;
  color: var(--c-accent);
  opacity: 0.25;
}
.step h3 {
  font-size: var(--fs-body-lg);
  padding-right: 3rem; /* keep the heading clear of the numeral */
}
.step p {
  font-size: var(--fs-small);
  color: var(--c-text-muted);
}

/* --- Split content section ---------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: var(--sp-8);
  align-items: center;
}

/* --- Homepage teaser band ------------------------------------------------ */

.teaser h2 {
  font-size: var(--fs-h2);
  margin-top: var(--sp-3);
}
.teaser p {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-lg);
}
.teaser .ticks {
  font-size: var(--fs-body);
  gap: var(--sp-4);
}

/* --- Prose (legal + case-study body) ------------------------------------ */

.prose {
  max-width: 46rem;
}
.prose > * + * { margin-top: var(--sp-5); }
.prose h2 {
  font-size: var(--fs-h2-sm);
  margin-top: var(--sp-8);
}
.prose h3 {
  font-size: var(--fs-h4);
  margin-top: var(--sp-7);
}
.prose h4 {
  font-size: var(--fs-body-lg);
  margin-top: var(--sp-6);
}
/* The heading margins above separate one section from the next. On the first
   one there is nothing to separate it from, and stacked on the section's own
   top padding it left a large hole under the page hero. */
.prose > :first-child { margin-top: 0; }
.prose p,
.prose li { color: var(--c-text-muted); }
.prose ul,
.prose ol {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-left: var(--sp-5);
}
.prose li { padding-left: var(--sp-1); }
/* The underline itself is drawn in the micro-interactions block at the foot
   of this file, as a pair of background bars, so that it can wipe in on
   hover and still survive a link that wraps across two lines. */
/*
  A link that is the whole of its paragraph -- the contact address on the
  Impressum -- is a target in its own right rather than a word inside a
  sentence, so it gets the padding that takes it over the 24px minimum. A
  link inside running text deliberately does not: making those inline-block
  would stop a long URL wrapping.
*/
.prose .prose__link-row a {
  display: inline-block;
  padding-block: 0.3125rem;
}
.prose strong { color: var(--c-text); }

.prose__meta {
  padding: var(--sp-5);
  background: var(--c-surface);
  border-radius: var(--radius);
  font-size: var(--fs-small);
}

/* --- Page hero (inner pages) -------------------------------------------- */

.page-hero {
  padding-block: var(--sp-9) var(--sp-8);
  background:
    radial-gradient(ellipse 60% 70% at 85% 10%, var(--c-accent-soft), transparent 70%),
    var(--c-surface);
}
.page-hero h1 {
  font-size: var(--fs-h1);
  max-width: 22ch;
}
.page-hero .lead {
  margin-top: var(--sp-5);
  max-width: 46rem;
}

/* --- Quote block -------------------------------------------------------- */

.quote {
  padding: var(--sp-7);
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.quote p {
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  font-style: italic;
  line-height: 1.6;
  letter-spacing: -0.01em;
}
.quote footer {
  margin-top: var(--sp-4);
  font-size: var(--fs-small);
  font-style: normal;
}
.quote cite {
  display: block;
  font-weight: 600;
  font-style: normal;
  color: var(--c-primary);
}
.quote .quote__company { color: var(--c-text-muted); }

/* --- Motion & icons (shared) -------------------------------------------- */

/* The sprite only carries <symbol> definitions; it must occupy no space but
   stay in the layout tree, so `display: none` is deliberately not used. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.ico {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ico--sm { width: 1rem; height: 1rem; stroke-width: 2; }
.ico--38 { width: 2.375rem; height: 2.375rem; }
.ico--40 { width: 2.5rem; height: 2.5rem; }
.ico--42 { width: 2.625rem; height: 2.625rem; }
.ico--risk { color: #d50000; }

/* --- scroll-in animations (Elementor fadeInUp / fadeInLeft / fadeInRight) -- */

/* Only armed once the observer is running, so the page still renders with JS
   off instead of staying permanently transparent. */
.js-anim [data-anim] {
  opacity: 0;
  transition: opacity 1.2s ease, transform 1.2s ease;
}
.js-anim [data-anim="up"] { transform: translate3d(0, 60px, 0); }
.js-anim [data-anim="left"] { transform: translate3d(-64px, 0, 0); }
.js-anim [data-anim="right"] { transform: translate3d(64px, 0, 0); }
.js-anim [data-anim="fade"] { transform: none; }
.js-anim [data-anim].is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js-anim [data-anim] { opacity: 1; transform: none; transition: none; }
}

/* --- Deep Reading Engine page ------------------------------------------- */

/* The slide-in animations start off-canvas. */
.page-dre main { overflow-x: clip; }
/*
  Same reason as the DRE and E-Rechnung pages: the blocks marked
  `data-anim="right"` sit 64px to the right of where they belong until the
  observer reveals them, and the homepage has nine of them. Without this the
  page loaded with ~40px of horizontal scroll at every viewport under 1300px
  -- "Warum wir?" and the zig-zag process steps were the ones sticking out.
  `clip`, not `hidden`, so no scroll container is created.
*/
.page-home main { overflow-x: clip; }

.dre-hero {
  position: relative;
  /* Was 7rem/5rem, which stood taller than its contents warranted and read
     as a hole above and below the copy. There is no bottom padding at all
     now: the robot is bottom-aligned and finishes on the band's own edge,
     which is what stops a bigger picture from growing the band again. The
     copy carries its own clearance instead -- see .dre-hero__copy. */
  padding-block: var(--sp-7) 0;
  background:
    radial-gradient(ellipse 75% 85% at 78% 108%, rgba(118, 171, 174, 0.42), transparent 62%),
    radial-gradient(ellipse 55% 70% at 6% -12%, rgba(214, 216, 79, 0.13), transparent 60%),
    var(--c-ink);
  color: rgba(255, 255, 255, 0.82);
  overflow: hidden;
}
/* a hairline of the accent bloom, so the band ends on a lit edge */
.dre-hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(118, 171, 174, 0.55), transparent);
}
/*
  The band was one full-width column of text and stood too tall for what it
  says. Splitting it in two keeps the copy inside the left half -- the point
  Willy made was that it must not cross the midline -- and gives the picture
  the space that frees up.
*/
.dre-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: end;
}
/* The section has no bottom padding, so the copy holds itself off the edge. */
.dre-hero__copy {
  max-width: 34rem;
  padding-bottom: var(--sp-8);
}

.dre-hero h1 {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  line-height: 1.12;
  color: var(--c-white);
}
.dre-hero__lead {
  margin-top: var(--sp-5);
  font-size: var(--fs-body-lg);
  color: rgba(255, 255, 255, 0.75);
}

/*
  Willy's robot, cut out of its black ground. It carries no box of its own --
  no card, no border, no radius -- so it reads as sitting in the band rather
  than in a frame, the same way the homepage hero treats its robot.

  Sized by height, not width: it is a portrait subject next to a block of
  copy, and height is what has to stay in step with the text beside it.
  Driving it off the width would let it grow the whole band on a wide screen.
*/
.dre-hero__media {
  justify-self: end;
  display: block;
  width: auto;
  height: clamp(15rem, 32vw, 28.75rem);
  max-width: 100%;
  /*
    The source is cropped at its own bottom edge, straight through the
    forearm, and a hard horizontal cut across a lit band looks like a
    mistake. Fading the last stretch lets it settle into the ground instead.
    The book and both hands sit above the fade, so nothing that carries the
    idea is lost to it.
  */
  -webkit-mask-image: linear-gradient(to bottom, #000 86%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 86%, transparent 100%);
}

@media (max-width: 899px) {
  /* One column, so there is nothing to bottom-align against and the band
     takes its padding back on both sides. */
  .dre-hero { padding-block: var(--sp-7); }
  .dre-hero__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-6);
    align-items: stretch;
  }
  .dre-hero__copy { max-width: none; padding-bottom: 0; }
  .dre-hero__media { justify-self: center; height: 17rem; }
}

.dre-section { padding-block: var(--sp-9); }
.dre-section--arch { background: var(--c-surface); }
.dre-section--cases {
  position: relative;
  background:
    radial-gradient(ellipse 70% 95% at 88% 0%, rgba(118, 171, 174, 0.28), transparent 62%),
    var(--c-teal-deep);
  color: rgba(255, 255, 255, 0.8);
  overflow: hidden;
}

.dre-intro { max-width: 52rem; }
.dre-h2 {
  /*
    Fluid below ~372px. "Anwendungsbeispiele" is 331px at the flat 32px and the
    column is 328 at 360px and 288 at 320, so the browser chopped it and left a
    lone "e" centred on its own line. Hyphenation was the alternative and reads
    worse in a centred display heading -- "Anwendungs-" hanging at the end of a
    line. Shrinking a little on small phones keeps the word whole.
  */
  font-size: clamp(1.55rem, 8.6vw, var(--fs-h2));
  line-height: 1.15;
  color: var(--c-primary);
}
.dre-lede {
  margin-top: var(--sp-5);
  font-size: var(--fs-body-lg);
  color: var(--c-text-muted);
}
.dre-section--cases .dre-h2 { color: var(--c-white); }
.dre-section--cases .dre-lede { color: rgba(255, 255, 255, 0.75); }

/* One heading Willy asked to sit centred. Text-align alone would only centre
   it inside `.dre-intro`, which is a 52rem column pinned to the left of a
   1140px container -- so the column has to be centred as well for the heading
   to land on the page's midline. The lede under it keeps its reading width. */
.dre-section--cases .dre-intro { margin-inline: auto; }
.dre-h2--center { text-align: center; }

/* --- the four architecture points ---------------------------------------- */

.dre-pillars {
  margin-top: var(--sp-8);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-5);
  list-style: none;
}
/* The reveal wrapper and the hovered card are deliberately separate elements.
   `[data-anim].is-in` sets `transform: none` at a higher specificity than a
   component's own `:hover`, so a card that is its own reveal target silently
   loses its hover lift. */
.dre-pillars > li,
.dre-cases > div { display: grid; }
.js-anim .dre-pillars > li:nth-child(2),
.js-anim .dre-cases > div:nth-child(2) { transition-delay: 0.08s; }
.js-anim .dre-pillars > li:nth-child(3),
.js-anim .dre-cases > div:nth-child(3) { transition-delay: 0.16s; }
.js-anim .dre-pillars > li:nth-child(4) { transition-delay: 0.24s; }

.dre-pillar {
  height: 100%;
  display: grid;
  /* Two tracks only: the icon, and one wrapper holding all the text. */
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  padding: var(--sp-6);
  background: var(--c-white);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition);
}
@media (hover: hover) {
  .dre-pillar:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
  }
}
.dre-pillar .ico {
  color: var(--c-accent);
  transition: transform var(--transition);
}
@media (hover: hover) {
  .dre-pillar:hover .ico { transform: scale(1.09); }
}
.dre-pillar p {
  font-size: var(--fs-small);
  color: var(--c-text-muted);
}
/* The lead-in runs into its own sentence, so it stays inline rather than
   becoming a heading -- that would mean moving the colon out of the copy. */
.dre-pillar strong {
  color: var(--c-text);
  font-weight: 600;
}

/* --- the three worked examples ------------------------------------------- */

.dre-cases {
  margin-top: var(--sp-8);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-5);
}
.dre-case {
  position: relative;
  height: 100%;
  padding: var(--sp-6);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform var(--transition), background var(--transition),
    border-color var(--transition);
}
.dre-case::before {
  content: "";
  position: absolute;
  left: var(--sp-6);
  top: 0;
  width: 2.25rem;
  height: 2px;
  background: var(--c-accent);
  transition: width var(--transition);
}
@media (hover: hover) {
  .dre-case:hover {
    transform: translateY(-3px);
    background: rgba(255, 255, 255, 0.09);
    border-color: rgba(118, 171, 174, 0.7);
  }
  .dre-case:hover::before { width: 5rem; }
}
.dre-case h3 {
  font-size: var(--fs-body-lg);
  color: var(--c-white);
}
.dre-case p {
  margin-top: var(--sp-4);
  font-size: var(--fs-small);
  color: rgba(255, 255, 255, 0.75);
}

@media (max-width: 1023px) {
  /* Three across would leave an orphan at two columns, so it drops straight
     to one. */
  .dre-cases { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 767px) {
  .dre-pillars { grid-template-columns: minmax(0, 1fr); }
}


/* --- Homepage ------------------------------------------------------------ */

/*
  Everything below is scoped to .page-home. The homepage was audited element by
  element against the live original and these are the corrections; the same
  values are not necessarily right on the other pages, which the audit did not
  cover, so nothing here leaks out of this page.

  Colours are the original's own computed values, sampled from the live page
  rather than guessed:
    #0D1D20  hero headline and eyebrow      (rgb 13 29 32)
    #000F08  solutions headline and card titles (rgb 0 15 8)  <- the "black" one
    #31363F  other section headlines        (rgb 49 54 63)
    #222831  body copy                      (rgb 34 40 49)
    #587274  hero lead and stat line        (rgb 88 114 116)
*/

/*
  The original asks for weight 600 but only ships Avenir 400 and 700, so every
  heading on it actually resolves to Heavy. Mulish has a real 600, which is
  visibly lighter -- 700 is what matches.
*/
.page-home :is(h1, h2, h3, h4),
.page-home .eyebrow,
.page-home .btn,
.page-home .case__author { font-weight: 700; }

.page-home .section-head h2 { font-size: 3rem; color: #31363f; }

/* The hero eyebrow is a plain bold line on the original, not a small-caps
   label: same size as body copy, no tracking, no uppercase. */
.page-home .hero__eyebrow {
  font-size: var(--fs-body);
  letter-spacing: 0;
  text-transform: none;
  color: #0d1d20;
}
/* Both halves of the headline take one colour. The original sets the second
   line to #0d1d20 against the first line's #31363f, which reads as two
   different blacks rather than as emphasis; Willy asked for the h1's colour
   to win. */
.page-home .hero h1,
.page-home .hero h2 { color: #31363f; }

.page-home .hero__text,
.page-home .hero__stat {
  font-size: var(--fs-body);
  color: #587274;
}
/* The original prints this line plainly -- no card, no rule, no highlight.
   The shared .hero__stat is a bordered callout box, so every part of it has
   to be unset, the shadow and radius included. */
.page-home .hero__stat {
  margin-top: var(--sp-6);
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Body copy sits at full strength on the original, not in a muted grey. */
.page-home .card p,
.page-home .pillar .ticks li,
.page-home .step p,
.page-home .case__result,
.page-home .case__company,
.page-home .member__quote { color: #222831; }

.page-home .section-head h2.solutions__title,
.page-home .card h3 { color: #000f08; }
.page-home .pillar h3,
.page-home .member__name { color: #222831; }
.page-home .step h3 { font-size: var(--fs-h4); color: #31363f; }

/*
  One size for all nine.

  Elementor set these per card -- 24px by default with the two longest titles
  stepped down to 20px and 18px so they would not swamp the box -- and the
  result was six cards in two rows reading as six different components. The
  long titles wrap instead now, which is what the line-height is for.
*/
.page-home .card h3 {
  font-size: var(--fs-h4);
  line-height: 1.2;
  margin-bottom: 15px;
  transition: color 0.4s ease;
}

/* --- solution cards ------------------------------------------------------ */

/*
  Measured off the live JegKit icon box: 25px of padding, a 5px radius, a
  #f0f0f0 hairline and no shadow, with a 60px accent chip above the title.
  Hovering floods the card with the accent, drops the text to #eeeeee and
  inverts the chip to lime -- all over the original's 0.4s.
*/
.page-home .card {
  gap: 0;
  padding: 25px;
  border-color: #f0f0f0;
  border-radius: 5px;
  box-shadow: none;
  transition: background-color 0.4s ease;
}
.page-home .card p {
  font-size: var(--fs-body);
  line-height: 1.6;
  transition: color 0.4s ease;
}

.card__icon {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  margin-bottom: 15px;
  padding: 10px;
  background: #77abae;
  border-radius: 4px;
  color: #f8faf9;
  transition: background-color 0.4s ease, color 0.4s ease;
}
.card__icon .ico,
.step__icon .ico { width: 100%; height: 100%; }

@media (hover: hover) {
  .page-home .card:hover { background: var(--c-accent); }
  .page-home .card:hover h3,
  .page-home .card:hover p { color: #eee; }
  .page-home .card:hover .card__icon {
    background: var(--c-lime);
    color: var(--c-accent);
  }
}

/* --- process steps ------------------------------------------------------- */

/*
  Three panels stacked and staggered -- left, right, left -- joined by a dotted
  curve, on a #f8faf9 ground. Each is 70% of the container, 30px of padding, a
  4px radius and the original's soft one-sided shadow. No numeral: the step is
  identified by an 80px accent glyph instead.
*/
.section--flow { background: #f8faf9; }

.flow {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}
.page-home .flow .step {
  width: 100%;
  gap: var(--sp-4);
  padding: 30px;
  border: 0;
  border-radius: 4px;
  box-shadow: rgba(0, 0, 0, 0.05) 3px 0 12px 0;
}
.page-home .flow .step::before { content: none; }
.page-home .flow .step h3 { padding-right: 0; }
.page-home .flow .step p { font-size: var(--fs-body); line-height: 1.6; }

.step__icon {
  display: block;
  width: 80px;
  height: 80px;
  color: var(--c-accent);
}

/* The dotted curve that runs from one panel down to the next. Its viewBox is
   the container width, so the two ends sit under the panels they join. */
.flow__link {
  display: block;
  height: 98px;
}
.flow__link svg { width: 100%; height: 100%; }
.flow__link path {
  fill: none;
  stroke: var(--c-accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 1 8;
  vector-effect: non-scaling-stroke;
}

@media (min-width: 900px) {
  .page-home .flow .step { width: 70%; }
  .flow__step--right { justify-self: end; }
}
@media (max-width: 899px) {
  .flow { gap: var(--sp-5); }
  .flow__link { display: none; }
}

/* --- the "Mehr" disclosure over the last three solution cards ------------ */

/* With JS off the toggle is pointless, so it hides and every card shows. */
/*
  The solutions band read as oversized next to the rest of the page, so Willy
  asked for it to sit a little tighter. Space only -- 80px of section padding
  down to 64, the gap under the heading from 48 to 36, the gutter between cards
  from 24 to 20 and card padding from 25 to 22. No type is resized, so the
  measured scale from the original stays as it is.
*/
.page-home .section:has(#solutions-grid) { padding-block: var(--sp-8); }
.page-home .section:has(#solutions-grid) .section-head { margin-bottom: 36px; }
.page-home .solutions { gap: 20px; }
.page-home .solutions .card { padding: 22px; }

.solutions__more { display: none; }
.js-anim .solutions__more { display: flex; }
.js-anim .solutions > [data-more] { display: none; }
.js-anim .solutions.is-expanded > [data-more] { display: block; }

/* --- rotating word in the three-step headline --------------------------- */

.rotator {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
}
.rotator__word {
  grid-area: 1 / 1;
  color: var(--c-lime);
  animation: rotator-in 420ms cubic-bezier(0.2, 0, 0.2, 1);
}
@keyframes rotator-in {
  from { opacity: 0; transform: translateY(0.5em) rotateX(-45deg); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .rotator__word { animation: none; }
}

/* --- closing band ------------------------------------------------------- */

/* One line on a light ground, the way the original ends the page. */
.home-cta {
  padding-block: var(--sp-9);
  background: var(--c-white);
  text-align: center;
}
/* The line sits inside a raised panel the width of the container, and the
   whole panel is the link -- not just the middle phrase. */
.home-cta__panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0 0.3em;
  min-height: 90px;
  padding: 10px;
  background: #f2f3f2;
  border-radius: 10px;
  box-shadow: rgba(0, 0, 0, 0.5) 5px 5px 10px 0;
  font-family: var(--font-display);
  font-size: var(--fs-h2-sm);
  font-weight: 700;
  line-height: 1.3;
}
.home-cta__accent { color: var(--c-accent); }
.home-cta__lime {
  color: var(--c-lime);
  transition: color var(--transition);
}
.home-cta__panel:hover .home-cta__lime { color: var(--c-accent); }

@media (max-width: 767px) {
  .page-home .section-head h2 { font-size: var(--fs-h2); }
  .home-cta__panel { font-size: var(--fs-h3); }
}

/* --- homepage section furniture ----------------------------------------- */

/* The original runs its section headings the full width of the container, so
   the solutions heading stays on one line instead of wrapping. */
.page-home .section-head { max-width: none; }

/* The logo strip sits between two buttons here, so it needs its own breathing
   room -- .btn-row only carries a top margin. */
.page-home .logos { margin-block: var(--sp-6); }

/* The chevron replaces the arrow the base button draws after its label. */
.page-home .btn--ghost::after { content: none; }
/* The "Mehr" toggle carries the same chevron as every other link on the page
   rather than a literal ">" character, turned to point down and flipped when
   the extra cards are showing. */
.solutions__toggle .btn__chev {
  transform: rotate(90deg);
  transition: transform var(--transition);
}
.solutions__toggle[aria-expanded="true"] .btn__chev { transform: rotate(-90deg); }

.btn--sm { padding: 0.625rem 1.25rem; }
.btn--block { position: relative; width: 100%; justify-content: center; }
.btn__chev {
  display: inline-flex;
  width: 0.9em;
  flex: none;
}
.btn__chev svg { width: 100%; height: auto; }
.btn--block .btn__chev { position: absolute; right: 1.625rem; }

/* --- hero --------------------------------------------------------------- */

/* The eyebrow sits in a pale panel with a two-bar mark, not as loose text. */
.page-home .hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 20px;
  padding: 10px 14px 10px 8px;
  background: #edf0ef;
  border-radius: 4px;
}
.hero__grip {
  display: inline-flex;
  width: 18px;
  flex: none;
  color: var(--c-accent);
  /*
    Aligned to the top rather than the centre. The label sits on one line at
    desktop width, where centring and top alignment look the same, but it
    wraps to two or three lines on a phone -- and the glyph then floated to
    the middle of the block instead of marking its first line. The offset is
    what centres it against that first line.
  */
  align-self: flex-start;
  margin-top: 0.28em;
}
.hero__grip svg { width: 100%; height: auto; }

/* Hand-drawn lime stroke under the highlighted word, drawn on with the
   reveal the way the original animates it. */
.page-home .hero__mark {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}
.hero__mark-line {
  position: absolute;
  left: 0;
  /* Mulish sits in a tighter content box than the Avenir the original uses,
     so the stroke needs a nudge to clear the descenders the way it does
     there. */
  top: calc(90% + 0.13em);
  width: 100%;
  height: 100%;
  overflow: visible;
}
.hero__mark-line path {
  fill: none;
  stroke: var(--c-lime);
  stroke-width: 9;
  stroke-dasharray: 1500;
  stroke-dashoffset: 1500;
  transition: stroke-dashoffset 1.2s ease 0.35s;
}
.js-anim .page-home [data-anim].is-in .hero__mark-line path,
html:not(.js-anim) .hero__mark-line path { stroke-dashoffset: 0; }

/* --- success stories ---------------------------------------------------- */

/* Quote, avatar and attribution share one tinted panel inside the card. */
.page-home .case__box {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: 20px;
  background: rgba(118, 171, 174, 0.314);
  border-radius: 4px;
}
.page-home .case__quote {
  font-family: var(--font-sans);
  padding-left: 0;
  border-left: 0;
  font-size: var(--fs-body);
  font-style: normal;
  line-height: 1.4;
  color: #222831;
}
.page-home .case__person {
  margin-top: 0;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--sp-3);
}
.page-home .case__avatar { width: 56px; height: 56px; }
.page-home .case__author {
  font-size: var(--fs-body);
  line-height: 1.25;
  color: #222831;
}
.page-home .case__company {
  font-size: var(--fs-small);
  line-height: 1.35;
}
.page-home .case h3 { color: #31363f; }
.page-home .case__result { font-size: var(--fs-body); line-height: 1.4; }
.page-home .case .card__foot {
  margin-top: var(--sp-5);
  padding-top: 0;
  text-align: center;
}
.page-home .case .card__foot .btn { padding-inline: 0; }

/* --- Warum wir? --------------------------------------------------------- */

.why {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-7);
  align-items: start;
}
@media (min-width: 900px) {
  .why { grid-template-columns: minmax(0, 45fr) minmax(0, 55fr); gap: var(--sp-8); }
}

.why__media {
  display: grid;
  gap: var(--sp-4);
}
.why__media .ph {
  border-radius: 4px;
  box-shadow: rgba(0, 0, 0, 0.1) 3px 0 15px 0;
}
.why__cert { aspect-ratio: 487 / 342; }
.why__seal { aspect-ratio: 487 / 180; }

.why__body h2 {
  margin-bottom: var(--sp-6);
  font-size: 3rem;
  color: #31363f;
}

.why__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-5);
}
.why__label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-body-lg);
  font-weight: 700;
  color: #222831;
}
.why__check {
  display: inline-flex;
  width: 20px;
  flex: none;
  color: var(--c-lime);
}
.why__check svg { width: 100%; height: auto; }
.why__list ul {
  margin: var(--sp-2) 0 0;
  padding-left: 1.75rem;
}
.why__list ul li {
  font-size: var(--fs-body);
  line-height: 1.6;
  color: #222831;
}

/* --- team --------------------------------------------------------------- */

/* Portrait above the name on the original, not beside it, and it sits on the
   light ground rather than inside a bordered card. */
.page-home .member {
  display: block;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
/*
  Team block, laid out as the original lays it out: the two members are not
  spread across the full container but sit as a centred pair, each one a 403px
  column with 178px between them. Capping the group and centring it is what
  does that; the columns stay flexible below it so the gap closes before the
  cards have to.
*/
.page-home .team {
  max-width: 61.5rem;   /* 403 + 178 + 403 */
  margin-inline: auto;
  /* 12.4vw reaches the original's 178px at a 1440 viewport, which puts the
     two cards on its 403px; narrower than that the gap closes first and the
     cards keep their width for as long as they can. */
  column-gap: clamp(2rem, 12.4vw, 11.125rem);
}

/*
  The grey plate is 403x300 on the original with a ~250px circle centred in
  it, and the name and quote run left-aligned underneath at the plate's own
  width.

  The circle is sized off the plate's height rather than given `width: 100%;
  height: 100%` like the shared rule does: the plate is wider than it is tall,
  so filling it turns the border-radius into an ellipse. Height plus
  `aspect-ratio: 1` keeps it round whatever the column does.
*/
.page-home .member__photo {
  display: grid;
  place-items: center;
  max-width: none;
  aspect-ratio: 403 / 300;
  padding: 0;
  background: var(--c-surface);
  border-radius: 4px;
}
.page-home .member__photo img {
  width: auto;
  height: 83%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 999px;
}
.page-home .member__photo .ph {
  width: auto;
  max-width: 100%;
  height: 100%;
  aspect-ratio: 1;
}
.member__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
}
.page-home .member__name {
  font-size: var(--fs-h4);
  font-weight: 700;
  color: #222831;
}
.page-home .member__link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: 0;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-accent);
  transition: color var(--transition);
}
.page-home .member__link:hover { color: var(--c-accent-dark); }
.member__in {
  display: inline-flex;
  width: 1.15em;
  flex: none;
}
.member__in svg { width: 100%; height: auto; }
.page-home .member__quote {
  margin-top: var(--sp-3);
  font-size: var(--fs-body);
  line-height: 1.6;
}

/* --- Ergebnisse page ----------------------------------------------------- */

/*
  The cards band sits on the same off-white as the page hero above it, so the
  two read as one continuous ground the way they do on the original, and the
  grid runs at the original's 20px gutter rather than the site default.
*/
/*
  The page hero borrows the Deep Reading Engine hero's treatment: the same ink
  ground with its two accent blooms, the same display size and tight leading,
  the same lit hairline along the bottom edge. The eyebrow takes the accent
  colour the DRE band gives its own label.
*/
.page-ergebnisse .page-hero {
  position: relative;
  padding-block: var(--sp-10) var(--sp-9);
  background:
    radial-gradient(ellipse 75% 85% at 78% 108%, rgba(118, 171, 174, 0.42), transparent 62%),
    radial-gradient(ellipse 55% 70% at 6% -12%, rgba(214, 216, 79, 0.13), transparent 60%),
    var(--c-ink);
  color: rgba(255, 255, 255, 0.82);
  overflow: hidden;
}
.page-ergebnisse .page-hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(118, 171, 174, 0.55), transparent);
}
.page-ergebnisse .page-hero .eyebrow { color: var(--c-accent); }
/* The "ERGEBNISSE" label above this heading is gone at Willy's request and the
   heading centres in the band on its own. `margin-inline: auto` is what
   actually centres it -- the max-width would otherwise hold it against the
   left edge however the text inside is aligned. */
.page-ergebnisse .page-hero h1 {
  /* Wide enough that the sentence lands on three lines rather than five. */
  max-width: 30ch;
  margin-inline: auto;
  font-size: clamp(2.25rem, 4.4vw, 3.5rem);
  line-height: 1.1;
  text-align: center;
  color: var(--c-white);
}
@media (max-width: 767px) {
  .page-ergebnisse .page-hero { padding-block: var(--sp-9) var(--sp-8); }
}

/* The original's grid holds 1140px of *content*, so the container has to be
   that plus its own gutters for the columns to land on the original's 367px
   and the copy to break over the same lines. Scoped to <main>: unscoped it
   also beat `.container--wide` on the header and footer, which then sat 52px
   narrower here than on every other page. */
.page-ergebnisse main .container { max-width: calc(var(--container) + 2 * var(--sp-5)); }

.page-ergebnisse .grid--testimonials { gap: 20px; }

.page-ergebnisse .case {
  gap: 0;
  padding: 20px;
  /*
    Transparent rather than absent, so the hover below can colour it without
    the card changing size. The box is border-box, so the 1px costs nothing
    on the outside.
  */
  border: 1px solid transparent;
  border-radius: 4px;
  box-shadow: rgba(0, 0, 0, 0.15) 3px 0 12px 0;
}
/*
  The same lift the homepage testimonial cards use: identical transform,
  shadow, border colour and timing. It has to be restated rather than left to
  the base `.case:hover` rule, because the page-scoped resting rule above
  (0,2,0) outranks that rule's (0,1,1) and would keep its own shadow and
  transparent border throughout the hover.

  The original WordPress page has no hover state on these at all; this is a
  deliberate departure from it so both sets of testimonial cards behave the
  same way.
*/
@media (hover: hover) {
  .page-ergebnisse .case:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
  }
}

/*
  Same weight story as the homepage: the original asks for 600 in faces that
  ship only 400 and 700, so everything it calls semibold renders bold.

  Title sizes are set per card there so each one still lands on a single
  line; min-height keeps the shorter ones in the original's 38px line box so
  the intro paragraphs below start level across a row.
*/
/*
  The original sizes every card title individually (32/28/27/22px) so each
  one lands on a single line, which reads as six different headings rather
  than one set. They are all one size here instead. 26px is the largest that
  still fits the longest of them, "Rechnungsverarbeitung", on one line.
*/
.page-ergebnisse .case h3 {
  font-size: 1.625rem;
  font-weight: 700;
  line-height: 1.2;
  /*
    Two lines are always reserved. Only one title wraps, and without the
    reserve its intro would sit a line lower than its rowmates' -- the
    ragged look the per-card sizes were there to avoid.
  */
  min-height: 2.4em;
  color: var(--c-primary);
}

.page-ergebnisse .case__result {
  /*
    The panel below is pushed to the foot of the card, so on the card with the
    longest intro the slack ran out and the two ended up touching. 26px is the
    tightest the original ever lets that gap get, so it becomes the floor and
    the auto margin takes whatever is left over.
  */
  margin-bottom: 26px;
  font-size: var(--fs-body);
  line-height: 1.25;
  color: var(--c-text);
}
.page-ergebnisse .case__result strong { font-weight: 700; }

/*
  Quote, avatar and attribution share one tinted panel, pushed to the foot of
  the card so the panels line up across a row whose intros differ in length.
*/
.page-ergebnisse .case__box {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px;
  background: rgba(118, 171, 174, 0.314);
  border-radius: 4px;
}
.page-ergebnisse .case__quote {
  padding-left: 0;
  border-left: 0;
  font-size: var(--fs-body);
  font-style: normal;
  line-height: 1.4;
  color: var(--c-text);
}
.page-ergebnisse .case__person {
  margin-top: 0;
  grid-template-columns: 57px minmax(0, 1fr);
  gap: 20px;
}
.page-ergebnisse .case__avatar { width: 57px; height: 57px; }
.page-ergebnisse .case__author {
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1.25;
  color: var(--c-text);
  /*
    Never split a word. Hyphenation used to run here to squeeze
    "Angebotsvergleich" into the ~160px attribution column between 912 and
    ~1100px, but it rendered "Ge-schäftsführer" on some widths and Willy asked
    for whole words everywhere. The column is `minmax(0, 1fr)`, so a long word
    takes its own line instead.
  */
  hyphens: manual;
}
.page-ergebnisse .case__company {
  font-size: var(--fs-body);
  line-height: 1.25;
  color: var(--c-text);
}

/* One card carries a project photo where its rowmates carry a testimonial. */
.page-ergebnisse .case__shot {
  margin-top: auto;
  min-height: 0;
  aspect-ratio: 327 / 280;
  border-radius: 4px;
}

.page-ergebnisse .card__foot {
  margin-top: 20px;
  padding-top: 0;
  text-align: center;
}
.page-ergebnisse .case__more {
  display: inline-flex;
  align-items: center;
  /* 18px of line box plus 14px of padding clears the 24px touch minimum. The
     underline is positioned against the content box, so it does not move. */
  padding-block: 0.4375rem;
  gap: 0.25em;
  font-size: var(--fs-body-lg);
  font-weight: 700;
  line-height: 1;
  color: var(--c-accent);
  transition: color var(--transition);
}
.page-ergebnisse .case__more:hover { color: var(--c-accent-dark); }

/*
  The recommendations have no intro line above the panel, so the panel is the
  card: it fills the height instead of being pushed to the foot, and the
  attribution sits at its bottom, which keeps the avatars level across a row
  of quotes that differ in length.
*/
.page-ergebnisse .case--reco { gap: 0; }
.page-ergebnisse .case--reco .case__box { margin-top: 0; flex: 1; }
.page-ergebnisse .case--reco .case__person { margin-top: auto; }

/* --- E-Rechnung page ---------------------------------------------------- */

/* Everything below is scoped to this page. It is the one page rebuilt pixel-
   for-pixel against the live WordPress version, which uses its own typeface,
   container width and type scale -- none of which match the rest of the site.
   Values here come from measuring the rendered original, not from the tokens. */

/*
  The live site sets this page in Plus Jakarta Sans -- E-Rechnung and the case
  studies were evidently built later than the rest of it, with a different
  face. The rebuild copied that, then Hari unified the whole site on Verdana +
  Mulish to stop it reading as two sites.

  Willy has since asked for this one page to go back to being strictly 1:1
  with the original, typeface included, so Plus Jakarta Sans returns here and
  only here. The four case-study pages under /ergebnisse/ keep the unified
  pair -- Willy's instruction named E-Rechnung alone.

  The webfont costs nothing on the other eleven pages: Google serves one
  stylesheet for both families, and a browser downloads a font binary only
  when something on the page is actually set in it.
*/
.page-erechnung main :is(h1, h2, h3, h4, h5, h6),
.page-erechnung main .eyebrow,
.page-erechnung main .btn,
.page-erechnung main .case__quote,
.page-erechnung main .quote p {
  font-family: "Plus Jakarta Sans", var(--font-display);
}

/* ==========================================================================
   Case-study pages
   --------------------------------------------------------------------------
   One visual system shared by all four pages under /ergebnisse/: U2care,
   Kommunikation, Potenzial Analyse and Automatische Rechnungsprüfung.

   The live site styles these four completely differently from one another --
   U2care is a Plus Jakarta Sans page on white with teal rules, the other
   three are Avenir on a hexagon-patterned ground. U2care is the one we
   follow, so every value below was measured off
   https://kiberatunghessen.com/index.php/u2care/ and is then applied to all
   four, overriding each page's own original styling. The text still comes
   from each page's own original.

   Measured there: content column 1140, body 18/24, H2 48/600 in the teal with
   a 4px rule 10px under it, cards 367 wide with a 1px teal border and a 20px
   radius, 20px between blocks, 80px above the first one, every block fading
   up on scroll.
   ========================================================================== */

/*
  The original lays these pages out on 1140px of *content*, with the page's own
  20px gutter outside that. Our .container keeps its 24px gutter inside the
  1140, which would leave a 1092 column and reflow every line and card width.
  Widen it by the gutter so the column measures 1140 like the original.
*/
.page-case main .container { max-width: calc(var(--container) + 2 * var(--sp-5)); }

.page-case main {
  font-family: var(--font-sans);
  font-size: var(--fs-body-lg);
  line-height: 1.34;
  color: var(--c-text);
}
.page-case main :is(h1, h2, h3, h4, h5, h6),
.page-case main .btn,
.page-case main .eyebrow {
  font-family: var(--font-display);
}
/* Mulish has a real 600, as Plus Jakarta did before it, so this stays the
   weight the original asks for rather than the 700 the Avenir pages use as a
   stand-in for bold. */
.page-case main :is(h1, h2, h3) { font-weight: 600; }

/* --- hero --------------------------------------------------------------- */

/*
  The original's hero is a photograph with a teal bloom over black, and the
  client quote sits inside it. We have no licence to that photograph, so this
  is the same black + teal-bloom ground the Ergebnisse and Deep Reading Engine
  heroes already use. It reads the same way and costs no asset.
*/
.case-hero {
  position: relative;
  padding-block: var(--sp-9);
  overflow: hidden;
  text-align: center;
  color: rgba(255, 255, 255, 0.86);
  background:
    radial-gradient(ellipse 75% 85% at 78% 108%, rgba(118, 171, 174, 0.42), transparent 62%),
    radial-gradient(ellipse 55% 70% at 6% -12%, rgba(214, 216, 79, 0.13), transparent 60%),
    var(--c-ink);
}
.case-hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(118, 171, 174, 0.55), transparent);
}

/* Lime, sentence case, full size -- the original's "Case study" line is a 24px
   heading, not the small-caps eyebrow used elsewhere on our site. */
.case-hero__eyebrow {
  font-size: var(--fs-h4);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--c-lime);
}

.case-hero h1 {
  max-width: 26ch;
  margin: var(--sp-4) auto 0;
  /*
    64px on the original, whose headline is 60 characters long. Three of the
    four pages carry a headline twice that length, which at 64px fills the
    screen before the reader reaches the quote. 52px is the compromise: same
    scale and weight, still one system across the four pages.
  */
  font-size: clamp(2rem, 3.4vw, 3.25rem);
  line-height: 1.22;
  color: var(--c-white);
}

/* --- hero quote --------------------------------------------------------- */

.case-hero__label {
  margin-top: var(--sp-8);
  font-size: var(--fs-h4);
  font-weight: 400;
  color: var(--c-lime);
}

.case-quote {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: center;
  margin-top: var(--sp-6);
  text-align: left;
}
.case-quote__avatar {
  width: 120px;
  height: 120px;
  min-height: 0;
  font-size: var(--fs-eyebrow);
}
.case-quote__body { position: relative; }
.case-quote blockquote {
  margin: 0;
  padding-inline: var(--sp-7);
  font-size: var(--fs-body-lg);
  font-style: italic;
  line-height: 1.45;
  text-align: center;
  color: var(--c-white);
}
/*
  The original sets its two quotation marks as separate icon widgets, one at
  each end of the text. Generated content does the same job without adding two
  empty elements for a screen reader to walk past.
*/
.case-quote blockquote::before,
.case-quote blockquote::after {
  position: absolute;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 3.25rem;
  font-style: normal;
  line-height: 1;
  color: rgba(255, 255, 255, 0.5);
}
.case-quote blockquote::before { content: "\201C"; left: 0; top: -0.12em; }
.case-quote blockquote::after { content: "\201D"; right: 0; bottom: -0.4em; }

.case-quote__attrib {
  grid-column: 1 / -1;
  margin-top: var(--sp-5);
  font-size: var(--fs-body-lg);
  font-weight: 500;
  line-height: 1.35;
  color: var(--c-white);
}
.case-quote__attrib span {
  display: block;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.72);
}

/* --- body flow ---------------------------------------------------------- */

/*
  One flow container per page rather than a stack of <section>s: the original
  puts every paragraph, heading and card row 20px apart in a single column,
  and only a section heading opens a wider gap.
*/
.case-body { padding-block: var(--sp-8) var(--sp-9); }
.case-body > * { margin: 0; }
.case-body > * + * { margin-top: 20px; }
.case-body > * + .case-h2 { margin-top: 44px; }

.case-h2 {
  padding-bottom: 10px;
  border-bottom: 4px solid var(--c-accent);
  font-size: var(--fs-h1);
  line-height: 1.1;
  color: var(--c-accent);
}
/* A sub-heading inside a section -- "Kernpunkte der Lösung" on U2care. */
.case-h3 {
  font-size: var(--fs-h3);
  line-height: 1.2;
  color: var(--c-text);
}
/*
  The narrative runs at the site's body size rather than the 18px it inherits
  from `.page-case main`.

  18px is the size measured off the original, and at that size a page of
  continuous prose read as one uniform oversized block -- Hari's words were that
  it looked "a little bit like every text is too big". Dropping it to 16px puts
  it on the site's own body size and opens a real step above it for the pull
  quote, which stays at 18px, and below it for the card and list copy at 15px.
*/
.case-body > :is(p, ul, ol) { font-size: var(--fs-body); }
.case-body p { line-height: 1.34; }
.case-body :is(strong, b) { font-weight: 700; }
.case-body a {
  /* Underline drawn in the micro-interactions block at the foot of this file. */
  color: var(--c-accent-dark);
}
.case-body a:hover { color: var(--c-teal-dark); }

.case-figure .ph { aspect-ratio: 1140 / 384; border-radius: var(--radius-lg); }

/* --- cards -------------------------------------------------------------- */

.case-cards {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}
.case-cards--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
@media (min-width: 1100px) {
  .case-cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.case-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 20px;
  border: 1px solid var(--c-accent);
  border-radius: var(--radius-lg);
  /* A step under the narrative, the same relationship the Deep Reading Engine
     page has between its card copy and its section leads. */
  font-size: var(--fs-small);
  line-height: 1.5;
  text-align: center;
}
.case-card > * { margin: 0; }
.case-card__icon {
  width: 50px;
  height: 50px;
  flex: none;
  color: #69727d;
}
.case-card__icon svg { display: block; width: 100%; height: 100%; }
/*
  The three pages that number their steps put the badge where U2care puts its
  icon, so the two occupy the same slot and rows still line up across pages.
*/
.case-card__num {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  margin-bottom: 6px;
  background: var(--c-accent);
  border-radius: 8px;
  font-size: var(--fs-body-lg);
  font-weight: 700;
  line-height: 1;
  color: var(--c-white);
}
.case-card h3 {
  font-size: var(--fs-body-lg);
  font-weight: 700;
  line-height: 1.3;
  color: var(--c-text);
}
.case-card ul {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/*
  Potenzial Analyse's three step cards carry a bullet list. The original
  centres those lines, which leaves the bullets floating at ragged positions
  and is hard to read, so a card holding a list is set left instead.
*/
.case-card--list { text-align: left; align-items: stretch; }
.case-card ul li { position: relative; padding-left: 1.15em; }
.case-card ul li::before {
  content: "";
  position: absolute;
  left: 0.15em;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--c-accent);
}

/* --- panels (the original's feature-box, quote-box and key-stats) -------- */

.case-panel {
  padding: 20px 24px;
  border: 1px solid var(--c-accent);
  border-radius: var(--radius-lg);
}
.case-panel > * { margin: 0; }
.case-panel > * + * { margin-top: 12px; }
.case-panel .ticks {
  padding: 0;
  gap: var(--sp-3);
  /* Supporting copy, sized with the cards. */
  font-size: var(--fs-small);
  color: var(--c-text);
}
/*
  The shared .ticks lays each item out as a flex row, which turns a leading
  <strong> into its own flex item. Combined with the `overflow-wrap: anywhere`
  that list carries, "Handlungsempfehlung" broke across two lines and the
  colon after it was pushed away by the row gap. A hanging indent keeps the
  tick in the margin and leaves the item as one continuous line of text.
*/
.case-panel .ticks li {
  display: block;
  position: relative;
  padding-left: 1.7em;
  overflow-wrap: break-word;
  line-height: 1.4;
}
.case-panel .ticks li::before { position: absolute; left: 0; top: 0; }

.case-callout {
  padding: 20px 24px;
  background: var(--c-surface);
  border-left: 4px solid var(--c-accent);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.case-stats {
  display: grid;
  gap: var(--sp-4) var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  padding: 24px;
  background: var(--c-surface);
  border-radius: var(--radius-lg);
  text-align: center;
}
.case-stats p {
  font-size: var(--fs-h4);
  font-weight: 700;
  line-height: 1.2;
  color: var(--c-accent);
}

@media (max-width: 767px) {
  .case-hero { padding-block: var(--sp-8); }
  .case-quote {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: var(--sp-5);
  }
  .case-quote blockquote { padding-inline: var(--sp-6); }
  .case-quote__attrib { text-align: center; }
  .case-h2 { font-size: var(--fs-h2); }
  .case-body { padding-block: var(--sp-7) var(--sp-8); }
}

.page-erechnung main {
  font-family: "Plus Jakarta Sans", var(--font-display);
  color: var(--c-text);
  /* the slide-in animations start off-canvas */
  overflow-x: clip;
}

/* The original lays this page out on a 1140px content measure, 100px narrower
   than the rest of the site's wide container and with no inner padding at
   desktop widths. Widening the box by the gutter reproduces it exactly. */
.page-erechnung main .container { max-width: 1188px; }

/* --- hero --------------------------------------------------------------- */

.er-hero {
  padding-block: 9.625rem 11rem;
  background: #000 url("/assets/img/erechnung/bg-1.webp") 0 0 / cover no-repeat;
  color: var(--c-white);
  text-align: center;
}
/*
  Opted out of the `text-wrap: balance` the base heading rule applies.

  This heading carries an explicit <br>, so the author has already decided where
  it breaks, and balancing works against that. Below 640px it produced an empty
  trailing line fragment inside `.er-hero__mark` -- and that span's highlight is
  an absolutely positioned ::after, whose containing block for a split inline
  box runs from the first fragment's start to the last one's end. The stroke
  collapsed from 170px to a 27px stub floating in the gap between the two
  headline lines.

  Letting the author's own break stand fixes it at every width. Making the span
  inline-block also fixed the stub, but then the stroke's deliberate 0.35em
  overshoot started registering as overflow inside the span.
*/
.er-hero h1 {
  text-wrap: wrap;
  font-size: 4rem;
  line-height: 1;
  font-weight: 600;
  color: var(--c-white);
}
/* the hand-drawn underline the original parks under the last word */
.er-hero__mark { position: relative; }
.er-hero__mark::after {
  content: "";
  position: absolute;
  left: 0;
  right: -0.35em;
  bottom: -0.05em;
  height: 15px;
  background: url("/assets/img/erechnung/graphic.svg") 50% 50% / 100% 100% no-repeat;
}
.er-hero__lead {
  margin-top: 4rem;
  font-size: 1.25rem;
  line-height: 1.75rem;
  color: rgba(255, 255, 255, 0.75);
}
.er-hero__lead b { color: var(--c-white); font-weight: 700; }
.er-hero__note {
  margin-top: 6rem;
  font-size: 1rem;
  line-height: 1.75rem;
  color: var(--c-white);
}

/* --- shared section furniture ------------------------------------------- */

.er-section { padding-block: 5rem; }

/* Black ground with the neon bloom along the bottom, same artwork as the hero.
   The live site has lost this background on all three of these bands, which is
   why their white type renders on white and the sections read as empty; the
   decorative shape in the questions band is drawn with `plus-lighter`, so it
   only resolves against a dark ground at all. */
.er-section--ask,
.er-section--solutions,
.er-section--cta {
  background: #000 url("/assets/img/erechnung/bg-1.webp") 50% 100% / cover no-repeat;
  color: var(--c-white);
}
.er-section--ask .er-h2,
.er-section--solutions .er-h2,
.er-section--cta .er-cta__title { color: var(--c-white); }
.er-section--risk { padding-block: 5rem 6rem; }
.er-section--detail { padding-block: 0 5rem; }
.er-section--cta { padding-block: 7.5rem; text-align: center; }
/* See the note on .er-card__more: this one button is Avenir on the original. */
.er-section--cta .er-btn { font-family: var(--font-display); }

.er-h2 {
  font-size: 2.75rem;
  line-height: 1.1;
  font-weight: 600;
  text-align: center;
  color: var(--c-primary);
}
.er-h2--lg { font-size: 2.875rem; }
.er-h3 { font-size: 2.375rem; line-height: 1.105; font-weight: 600; color: var(--c-primary); }
.er-h4 { font-size: 1.75rem; line-height: 2.125rem; font-weight: 600; color: var(--c-text); }
.er-body {
  margin-top: 1.5rem;
  font-size: 1.125rem;
  line-height: 1.5rem;
  color: var(--c-text);
}
.er-body b { font-weight: 700; }
.er-accent { color: var(--c-lime); }

.er-btn-row { display: flex; justify-content: center; margin-top: 2.5rem; }
.er-btn-row--start { justify-content: flex-start; }

.er-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 1.125rem 2.25rem;
  border-radius: 999px;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
  /* 0.3s is what the original's buttons use */
  transition: background 0.3s, color 0.3s;
}
.er-btn__arrow { stroke-width: 1.8; }
.er-btn--sm { padding: 0.875rem 1.75rem; font-size: 0.875rem; }
.er-btn--white { background: var(--c-white); color: #000; }
.er-btn--white:hover { background: var(--c-lime); color: #000; }
.er-btn--teal { background: var(--c-accent); color: var(--c-white); }
.er-btn--teal:hover { background: #80b0a4; color: var(--c-white); }
/* the two buttons inside the tab panels go lime on hover, not darker teal */
.er-btn--teal.er-btn--sm:hover { background: var(--c-lime); color: var(--c-text); }

/* --- what happens if you miss the deadline ------------------------------ */

.er-tiles {
  margin-top: 2.25rem;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.25rem;
  list-style: none;
}
.er-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  height: 100%;
  padding: 1.5rem 1.25rem;
  background: #f3f3f3;
  border-radius: 10px;
  text-align: center;
}
.er-tile p {
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--c-text);
}

/* --- the four questions ------------------------------------------------- */

.er-section--ask { position: relative; isolation: isolate; }
/* Decorative shape, bleeding off the left edge exactly as on the original.
   The clipping frame is itself absolutely positioned and inset to the band, so
   the oversized image never enlarges the section's own scroll box. */
.er-blob-wrap {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.er-blob {
  position: absolute;
  left: -288px;
  top: 143px;
  width: 1112px;
  height: 726px;
  max-width: none;
}
.er-section--ask > .container { position: relative; }

.er-asks {
  margin-top: 2.5rem;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.25rem;
  list-style: none;
}
.er-asks li {
  display: grid;
  grid-template-columns: 2.625rem minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
  min-width: 0;
}
.er-asks .ico { color: rgba(255, 255, 255, 0.75); }
/*
  14px on 14px leading, which is what the live page sets here and in the
  feature copy below.

  This value has moved three times. The rebuild copied the original's 14px;
  Hari found it small next to the rest of the site and asked for 16px; he then
  read the result as uniformly oversized and asked for a step down to 15px.
  Willy has now put the page back to strict 1:1, so it returns to the
  original's own figures. The leading really is 1.0 there -- these blocks are
  set as captions, and they wrap to three tight lines on the live page too.
*/
.er-asks p {
  font-size: 0.875rem;
  line-height: 1;
  color: rgba(255, 255, 255, 0.75);
}
.er-asks__close {
  max-width: 52rem;
  margin: 3rem auto 0;
  font-size: 1.125rem;
  font-weight: 500;
  line-height: 1.333;
  text-align: center;
  color: var(--c-white);
}

/* --- image + icon-list rows --------------------------------------------- */

.er-media-split {
  display: grid;
  grid-template-columns: 400px minmax(0, 1fr);
  gap: 2.5rem;
  align-items: center;
}
.er-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 20px;
}

.er-features {
  margin-top: 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  list-style: none;
}
.er-features li {
  display: grid;
  /* Two tracks only: the icon, and one wrapper holding all the text. Siblings
     placed directly in the row would wrap into the narrow icon column. */
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}
.er-features li > div { min-width: 0; }
.er-features .ico { color: var(--c-accent); }
.er-features__title {
  font-size: 1.125rem;
  font-weight: 600;
  /* 18px on 18px, as the original sets it. */
  line-height: 1;
  color: var(--c-text);
}
.er-features__title + p {
  margin-top: 0.5rem;
  /* Sized with `.er-asks p` above -- see the note there. 16/14 leading here,
     not the 1.0 the ask block uses. */
  font-size: 0.875rem;
  line-height: 1.143;
  color: rgba(0, 0, 0, 0.75);
}

/* --- the two solution cards --------------------------------------------- */

.er-cards {
  margin-top: 2.5rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}
.er-card {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  height: 100%;
  padding: 2rem 2.5rem;
  border: 2px solid;
  border-radius: 20px;
}
.er-card h3 {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 2.375rem;
  line-height: 1.2;
  font-weight: 600;
}
.er-card h4 { font-size: 1.1875rem; line-height: 1.3; font-weight: 600; }
/* The original does not give the two cards the same subhead size: the big
   card's runs at 19px and the small card's at 22px. */
.er-card--small h4 { font-size: 1.375rem; }
/* 16px on 22px leading, the original's figures. This block briefly sat at
   --fs-small during the 15px pass; item 9 puts it back. */
.er-card p { margin-top: 1rem; font-size: 1rem; font-weight: 500; line-height: 1.375; }
.er-card__more {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  align-self: center;
  margin-top: auto;
  padding: 1.5rem 0 0;
  background: none;
  border: 0;
  font: inherit;
  /* Two controls on this page escape Plus Jakarta Sans on the original --
     Elementor defaults showing through rather than a decision. 1:1 means
     copying that: this toggle renders in Verdana there, and the closing
     "Termin buchen" in Avenir, for which Mulish is our stand-in. */
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.3s;
}
.er-card__more .ico { transition: transform var(--transition); }
.er-card__more:hover .ico { transform: translateY(2px); }

/* The bloom behind this band runs straight through the right-hand card, so the
   cards get an opaque base under their tint instead of letting it read
   through. Over white on the original the tint alone was already opaque. */
.er-card { background-color: rgba(0, 0, 0, 0.5); }
.er-card--big {
  border-color: var(--c-lime);
  background-image: linear-gradient(rgba(214, 216, 79, 0.25), rgba(214, 216, 79, 0.25));
}
.er-card--big h3,
.er-card--big h4 { color: var(--c-lime); }
/* Low contrast, but this is the original's own treatment for the card copy. */
.er-card--big p { color: rgba(214, 216, 79, 0.6); }
.er-card--big .er-card__more { color: rgba(214, 216, 79, 0.5); }
.er-card--big .er-card__more:hover { color: var(--c-lime); }

.er-card--small {
  border-color: var(--c-accent);
  background-image: linear-gradient(rgba(118, 171, 174, 0.25), rgba(118, 171, 174, 0.25));
}
.er-card--small h3,
.er-card--small h4 { color: var(--c-accent); }
.er-card--small p { color: rgba(118, 171, 174, 0.75); }
.er-card--small .er-card__more { color: rgba(118, 171, 174, 0.75); }
.er-card--small .er-card__more:hover { color: var(--c-accent); }

/* --- detail tabs -------------------------------------------------------- */

.er-tabs__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.er-tabs__btn {
  padding: 15px 35px;
  background: none;
  border: 1px solid var(--c-accent);
  border-radius: 5px;
  font: inherit;
  font-size: 1.1875rem;
  font-weight: 600;
  color: var(--c-accent);
  cursor: pointer;
  transition: background 0.3s, color 0.3s;
}
.er-tabs__btn[aria-selected="true"] { background: var(--c-accent); color: var(--c-white); }
.er-tabs__btn:hover { background: rgba(118, 171, 174, 0.15); }
.er-tabs__btn[aria-selected="true"]:hover { background: var(--c-accent); }

.er-tabs__panel { padding-top: 5rem; }
.er-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.5rem;
  align-items: center;
}
.er-row + .er-row { margin-top: 3.75rem; }

/* --- closing call to action --------------------------------------------- */

.er-cta__title {
  font-size: 2.375rem;
  line-height: 3rem;
  font-weight: 600;
  color: var(--c-primary);
}

/* --- narrow viewports ---------------------------------------------------- */

@media (max-width: 1023px) {
  .er-tiles,
  .er-asks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .er-media-split,
  .er-cards,
  .er-row { grid-template-columns: minmax(0, 1fr); }
  /* stacked, the text should lead even in the flipped rows */
  .er-row--flip .er-shot { order: 2; }
  .er-hero { padding-block: 6rem 7rem; }
  .er-hero h1 { font-size: 3rem; }
  .er-h2 { font-size: 2.25rem; }
  .er-h2--lg { font-size: 2.25rem; }
  .er-h3 { font-size: 2rem; }
  .er-blob { top: 40px; left: -420px; }
}

@media (max-width: 639px) {
  .er-tiles,
  .er-asks { grid-template-columns: minmax(0, 1fr); }
  .er-hero h1 { font-size: 2.25rem; }
  .er-hero__lead { margin-top: 2.5rem; font-size: 1.125rem; }
  .er-hero__note { margin-top: 3rem; }
  .er-h2, .er-h2--lg { font-size: 1.875rem; }
  .er-h3 { font-size: 1.75rem; }
  .er-card { padding: 1.5rem; }
  .er-card h3 { font-size: 1.75rem; }
  .er-tabs__btn { padding: 12px 10px; font-size: 1rem; }
  .er-btn { padding: 1rem 1.5rem; font-size: 0.9375rem; }
}

/* --- Kontakt page -------------------------------------------------------- */

/* Same 1140px content measure the original lays this page out on. */
.page-kontakt main .container { max-width: calc(var(--container) + 2 * var(--sp-5)); }

.kontakt__headline {
  margin-bottom: var(--sp-7);
  /*
    32px, as on the original, but shrinking below ~500px. The rotating phrase
    is held together with non-breaking spaces, so at a fixed 32px it is 409px
    wide and pushes a phone viewport into horizontal scroll -- the original
    does exactly that (scrollWidth 421 at 390px). Fluid here instead.

    The 1.5rem floor was still too high at the narrow end: at 320px it held the
    line at 24px, which is 310px wide in a 288px column, and the page scrolled
    sideways by 6px. 1.3rem clears it with room to spare and binds only below
    ~325px -- at 360 and up the vw term is already the larger of the two, so
    nothing visible changes on a mainstream phone.
  */
  font-size: clamp(1.3rem, 6.4vw, 2rem);
  /* The original asks for 600 in Avenir, which ships 400 and 700 only, so it
     renders bold. Mulish's real 600 is visibly lighter; 700 is the match. */
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  color: var(--c-primary);
}

/*
  The second half of the sentence is typed in letter by letter and cycles
  through three phrases -- the original's animated headline, `animation_type:
  typing`. The caret is its 1px blinking bar.
*/
.typeline {
  display: inline-block;
  white-space: nowrap;
  /* The width of the longest phrase is reserved on this wrapper (see main.js)
     and its contents run left, so the caret trails the last typed letter
     instead of parking at the right edge of the reservation. */
  text-align: left;
  color: var(--c-accent);
}
.typeline__caret {
  display: inline-block;
  width: 1px;
  height: 1.08em;
  margin-left: 0.03em;
  vertical-align: -0.16em;
  background: #0d0d0d;
}
.js-anim .typeline__caret {
  animation: kontakt-caret 1s steps(1, end) infinite;
}
@keyframes kontakt-caret {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .typeline__caret { animation: none; opacity: 0; }
}

/* The tab strip sits under the panel it controls, so the buttons lead in the
   DOM (where a keyboard user wants them) and trail on screen. */
.kontakt__tabs {
  display: flex;
  flex-direction: column-reverse;
}
.kontakt__tablist {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: var(--sp-6);
}
.ktab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 15px 35px;
  background: #cecccc;
  border: 0;
  border-radius: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.6;
  color: var(--c-secondary);
  cursor: pointer;
  transition: background-color 0.3s ease, color 0.3s ease;
}
.ktab__icon {
  display: inline-flex;
  width: 1em;
  flex: none;
}
.ktab__icon svg { width: 100%; height: auto; }
.ktab:hover,
.ktab[aria-selected="true"] {
  background: var(--c-accent);
  color: var(--c-white);
}

/* Form panel chrome, taken from the original's inner section. */
.kform {
  padding: 45px;
  background: #fcfcfc;
  border: 1px solid #dadada;
  border-radius: 4px;
}
.kform__row { position: relative; margin: 0 0 10px; }
.kform__row:last-child { margin-bottom: 0; }
.kform__field {
  display: block;
  width: 100%;
  /*
    Top padding carries the floated label. The field's own text sits below it
    at rest, exactly where the label sits before it floats, so the two swap
    places rather than the text jumping.
  */
  padding: 22px 16px 7px;
  background: var(--c-white);
  border: 1px solid #f0f0f0;
  border-radius: 3px;
  font-family: var(--font-sans);
  /*
    Pinned at 16px rather than following --fs-body. iOS Safari zooms the whole
    page in when a focused field is under 16px, and leaves the visitor at that
    zoom for the rest of the form.
  */
  font-size: 1rem;
  line-height: 1.6;
  color: var(--c-text);
  transition: border-color var(--transition);
}
.kform__field--area {
  resize: vertical;
}

/*
  Floating label. The input keeps a single-space placeholder so
  `:placeholder-shown` can tell an empty field from a filled one -- that is
  what holds the label up after the field loses focus but still has content,
  and it works for autofill too. The label follows the input in the DOM so a
  plain sibling combinator can reach it; `for`/`id` still pair them up.
*/
.kform__label {
  position: absolute;
  top: 22px;
  /* 16px of field padding + the 1px border */
  left: 17px;
  max-width: calc(100% - 34px);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--c-text-muted);
  white-space: nowrap;
  pointer-events: none;
  transform-origin: left top;
  transition: transform var(--transition), color var(--transition);
}
.kform__field:focus + .kform__label,
.kform__field:not(:placeholder-shown) + .kform__label {
  /* 0.75 x 16px = the 12px eyebrow size, reached by scaling so the whole
     move is one composited transform rather than a font-size reflow. */
  transform: translateY(-15px) scale(0.75);
  color: var(--c-accent-dark);
}

/*
  Focus is a flat border-colour change and nothing else -- no outline, no ring,
  no halo. `--c-accent-dark` rather than `--c-accent` because the darker teal
  clears 3:1 against both the white field and the form's own ground, which the
  lighter one does not; the label floating up and turning teal is the second
  half of the indicator.
*/
.kform__field:focus,
.kform__field:focus-visible {
  outline: none;
  border-color: var(--c-accent-dark);
}
.kform__submit {
  width: 100%;
  padding: 16px 32px;
  background: var(--c-accent);
  border: 0;
  border-radius: 4px;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1.4;
  color: var(--c-white);
  cursor: pointer;
  transition: background-color var(--transition);
}
.kform__submit:hover { background: var(--c-accent-dark); }
.kform__submit:disabled { opacity: 0.7; cursor: progress; }

/* Outcome line under the button. Same voice as the rest of the form; the
   colour is the only thing that says which way it went. */
.kform__status {
  margin: 14px 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  text-align: center;
}
.kform__status--ok { color: var(--c-accent-dark); font-weight: 600; }
.kform__status--error { color: #a13d2d; }

/* Under 768px the original puts the strip above the panel and runs the
   buttons full width. */
@media (max-width: 767px) {
  .kontakt__tabs { flex-direction: column; }
  .kontakt__tablist {
    margin-top: 0;
    margin-bottom: var(--sp-6);
  }
  .ktab {
    flex: 1 1 100%;
    justify-content: center;
    padding: 15px 20px;
  }
  .kform { padding: var(--sp-5); }
}

/* --- Calendly booking widget -------------------------------------------- */

/*
  The original shows the widget bare -- no card, no border, unlike the
  contact form on the other tab -- so this wrapper only reserves the space.
  Reserving it matters: the widget arrives async, and without a floor the
  tab strip below would sit up against the headline until the iframe lands,
  then jump 700px down. The height matches Calendly's own inline style.
*/
.calendly {
  min-height: 700px;
}

/* --- CTA band ----------------------------------------------------------- */

.cta {
  padding-block: var(--sp-9);
  background:
    radial-gradient(ellipse 60% 100% at 50% 0%, rgba(118, 171, 174, 0.22), transparent 70%),
    var(--c-primary);
  text-align: center;
}
.cta h2 {
  font-size: var(--fs-h2);
  color: var(--c-white);
  max-width: 20ch;
  margin-inline: auto;
}
/*
  The Deep Reading Engine's closing question is 54 characters and broke over
  three lines in the shared 20ch box. Widened here only, so it breaks after
  "KI" and lands on two. In rem rather than ch because `ch` measures the width
  of "0", which in these faces is far wider than the average letter -- 20ch
  was holding barely 25 real characters.
*/
.page-dre .cta h2 { max-width: 39rem; }
.cta p {
  margin-top: var(--sp-4);
  color: rgba(255, 255, 255, 0.75);
  max-width: 42rem;
  margin-inline: auto;
}

/* --- Footer ------------------------------------------------------------- */

.site-footer {
  padding-block: var(--sp-8) var(--sp-6);
  /* The live footer is #31363F, not the near-black --c-ink. */
  background: var(--c-primary);
  color: var(--c-white);
  font-size: var(--fs-body);
}

.site-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
  gap: var(--sp-7);
}

.site-footer h2 {
  /* Plain bold headings on the live footer -- no small-caps treatment. */
  font-size: var(--fs-body-lg);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--c-white);
  margin-bottom: var(--sp-4);
}

.site-footer ul {
  display: flex;
  flex-direction: column;
  /*
    The gap carried the whole rhythm while each link was only its own 18px
    line box -- under the 24px minimum for a touch target. The padding below
    does that spacing now, so the gap shrinks by the same amount and the list
    keeps its pitch.
  */
  gap: var(--sp-1);
  list-style: none;
}
.site-footer li a {
  display: inline-block;
  padding-block: 0.4rem;
}

.site-footer a { color: var(--c-lime); }
.site-footer a:hover { color: var(--c-accent); }

.site-footer .brand { color: var(--c-white); }
.site-footer .brand__tag { color: var(--c-lime); font-size: var(--fs-body); }

.site-footer__tagline {
  margin-top: var(--sp-4);
  max-width: 24rem;
}

.site-footer__bottom {
  font-family: var(--font-display);
  margin-top: var(--sp-7);
  padding-top: var(--sp-5);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: var(--fs-caption);
  color: var(--c-white);
}

/* --- 404 ---------------------------------------------------------------- */

.notfound {
  display: grid;
  place-items: center;
  min-height: 60vh;
  padding-block: var(--sp-9);
  text-align: center;
}
.notfound__code {
  font-size: var(--fs-numeral);
  font-weight: 600;
  line-height: 1;
  color: var(--c-accent);
  opacity: 0.3;
}
.notfound h1 {
  font-size: var(--fs-h2);
  margin-top: var(--sp-4);
}
.notfound p {
  margin-top: var(--sp-4);
  color: var(--c-text-muted);
  max-width: 34rem;
}

/* ==========================================================================
   Responsive — Elementor's original breakpoints: 1024px / 767px
   ========================================================================== */

@media (max-width: 1024px) {
  :root {
    --fs-hero: 3.25rem;   /* 52 */
    --fs-h1: 2.75rem;     /* 44 */
    --fs-numeral: 8.75rem;/* 140 */
  }

  .hero__grid {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
  .hero__media { max-width: 34rem; }

  .site-footer__grid {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
    gap: var(--sp-6);
  }
}

@media (max-width: 1119px) {
  /*
    Collapse to the mobile drawer before the nav can crowd the logo. Raised
    from 900px when "Deep Reading Engine" became the fifth nav item, then from
    1024px after measuring it: with five bold 16px links plus the CTA the row
    needs 1120px of viewport to sit inside the container's gutter, and it
    genuinely overflowed the viewport on every page between 1025 and 1071px.
    1024px was chosen back then because it is the design system's tablet
    breakpoint, not because the row fitted there.
  */
  .nav-toggle { display: flex; }

  .nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    display: block;
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
    /*
      A closed drawer must not be touchable. `visibility: hidden` below does
      that on its own for anything that inherits it, but opacity alone would
      not -- a fully transparent element still takes taps -- so this is the
      guard that does not depend on inheritance reaching every descendant.
    */
    pointer-events: none;
    padding: var(--sp-5) var(--sp-5) var(--sp-7);
    background: var(--c-white);
    border-bottom: 1px solid var(--c-border);
    box-shadow: var(--shadow-md);
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--transition), transform var(--transition),
      visibility var(--transition);
  }
  .nav[data-open="true"] {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
  }

  .nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-1);
  }
  .nav__link {
    justify-content: space-between;
    padding: var(--sp-4);
    font-size: var(--fs-body);
  }

  .nav > .btn { width: 100%; margin-top: var(--sp-4); }
}

@media (max-width: 767px) {
  :root {
    /*
      16px, not 15. Running text should not get smaller on the screen held
      closest to the face, and 16px is also the threshold below which iOS
      Safari zooms the page in when a form field takes focus.
    */
    --fs-body: 1rem;       /* 16 */
    /*
      Sized so the hero's longest compound always fits the column rather than
      being chopped. "maßgeschneiderte" is about 8.9x the font size wide in
      Mulish 700, and the column is the viewport less the 2rem of gutter, so
      dividing by 9.1 keeps it on one line with a little room to spare. It
      reaches the 40px cap at 390px and steps down from there -- at 360px the
      word was 356px wide in a 328px column and broke mid-word, with no hyphen,
      because `hyphens: manual` is on for display headings.
    */
    --fs-hero: clamp(2rem, calc((100vw - 2rem) / 9.1), 2.5rem);
    --fs-h1: 2.375rem;     /* 38 */
    --fs-display: 2.375rem;/* 38 */
    --fs-h2: 2rem;         /* 32 */
    --fs-h3: 1.5rem;       /* 24 */
    --sp-9: 3.5rem;
    --sp-10: 4rem;
  }

  .container { padding-inline: var(--sp-4); }

  .member {
    grid-template-columns: 1fr;
    gap: var(--sp-4);
  }
  .member__photo { width: 6.5rem; }
  /* The homepage portrait is a full-width block above the name, not the
     small square that sits beside it in the shared card. */
  .page-home .member__photo { width: auto; }
  .page-home .flow .step { padding: 30px; }

  .step::before {
    position: static;
    font-size: var(--fs-h2-sm);
    opacity: 0.4;
  }
  .step { padding-top: var(--sp-6); }
  .step h3 { padding-right: 0; }

  /*
    --sp-9 drops to 3.5rem below this width, so a normal .section becomes
    56px while .section--tight stayed on --sp-8 at 64px -- the tight sections
    ended up looser than the normal ones. Scaled here so the order holds.
  */
  .section--tight { padding-block: var(--sp-7); }

  /*
    The legal pages' numbered headings are long even by German standards
    ("2. Vorabinformationen für die Übermittlung personenbezogener Daten an
    Dritte im Falle einer Fusion/Akquisition"). At 32px in a 328px column that
    ran to seven lines and pushed the section it introduces off the screen. The
    step down to 26px keeps it clearly a heading and clearly above the 24px h3
    below it. Their 64px top margin is desktop spacing in a viewport with a
    fraction of the room, so it scales with them.
  */
  .prose h2 {
    font-size: 1.625rem;
    margin-top: var(--sp-7);
  }
  .prose h3 { margin-top: var(--sp-6); }

  .quote { padding: var(--sp-5); }
  .quote p { font-size: var(--fs-body-lg); }

  .btn { width: 100%; }
  .btn--ghost { width: auto; }
  .btn-row { flex-direction: column; align-items: stretch; }
}

/* --- Short viewports (phone in landscape) -------------------------------- */

/*
  A phone on its side is about 360px tall. A 76px sticky header takes a fifth
  of that and never gives it back, and the drawer it opens is then squeezed
  into what is left. Trimming the header for short viewports gives both the
  page and the drawer that space; nothing else about the layout changes.
*/
@media (orientation: landscape) and (max-height: 500px) {
  :root { --header-h: 56px; }
  .brand__logo { height: 34px; }
  .site-footer .brand__logo { height: 46px; }

  /* Sections carry desktop-height padding into a viewport with almost no
     vertical room, which leaves a landscape phone scrolling through empty
     bands between every block. */
  .section { padding-block: var(--sp-7); }
  .section--tight { padding-block: var(--sp-6); }
  .hero { padding-block: var(--sp-7) var(--sp-6); }
}

/* --- Print -------------------------------------------------------------- */

@media print {
  .site-header, .site-footer, .cta, .nav-toggle { display: none; }
  body { color: #000; }
}

/* ==========================================================================
   Micro-interactions

   Six small behaviours added on top of the finished layout. Every one of them
   reuses an existing colour and the existing `--transition` timing rather than
   introducing its own, so they read as one set. All six degrade cleanly: the
   two that need JS (magnetic CTAs, logo marquee, cursor glow) leave the page
   exactly as it was when it is unavailable, and the global
   `prefers-reduced-motion` block above flattens the CSS-driven ones.
   ========================================================================== */

/* --- 1. Underline that wipes in on hover -------------------------------- */

/*
  Two stacked background bars rather than an ::after, because an absolutely
  positioned pseudo-element only underlines the first line box when a link
  wraps mid-paragraph -- which happens in the legal pages' long German
  sentences. The lower bar is the resting underline and only body-copy links
  carry one; the upper bar is the accent that wipes in from the left.

  `currentColor` on both means each context keeps its own link colour without
  a second set of rules: teal in body copy, lime in the footer.

  Nav links are deliberately not in this list. They already have a distinct
  hover state -- a tinted pill behind the label -- and a second indicator
  underneath it reads as noise rather than polish.
*/
.prose a,
.case-body a,
.site-footer li a,
.case__more,
.er-card__more,
.member__link,
.btn--ghost {
  /* width of the resting bar: 0 for standalone links, 100% for body copy */
  --ul-rest: 0%;
  text-decoration: none;
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  /*
    Positioned against the content box, not the padding box. `.btn--ghost`
    inherits 13px of vertical padding from `.btn`, which parked the bar that
    far below the text and made it read as a rule under the link rather than
    an underline on it. On links with no padding this changes nothing.
  */
  background-origin: content-box;
  background-position: 0 100%, 0 100%;
  background-size: 0% 2px, var(--ul-rest) 1px;
  transition: background-size var(--transition), color var(--transition);
}

/*
  Body-copy links keep a permanent underline so they are still recognisable as
  links inside a block of text. The hover bar wipes across on top of it.
*/
.prose a,
.case-body a {
  --ul-rest: 100%;
}

/*
  Keyboard focus always sweeps the underline in. Hover only does so where
  there is a pointer that can hover: a tap on a touch screen would otherwise
  leave the bar drawn under the link until the visitor tapped elsewhere.
*/
.prose a:focus-visible,
.case-body a:focus-visible,
.site-footer li a:focus-visible,
.case__more:focus-visible,
.er-card__more:focus-visible,
.member__link:focus-visible,
.btn--ghost:focus-visible {
  background-size: 100% 2px, var(--ul-rest) 1px;
}

@media (hover: hover) {
  .prose a:hover,
  .case-body a:hover,
  .site-footer li a:hover,
  .case__more:hover,
  .er-card__more:hover,
  .member__link:hover,
  .btn--ghost:hover {
    background-size: 100% 2px, var(--ul-rest) 1px;
  }
}

/* --- 4. Magnetic booking CTAs ------------------------------------------- */

/*
  JS sets --mag-x / --mag-y; the transform is composed here so the button's
  own 1px hover lift survives instead of being overwritten by an inline
  style. The class is added by JS only on devices with a real cursor, so a
  touch device never sees any of this.

  Specificity note: `.btn.is-magnet` (0,2,0) has to beat `.btn:hover` (0,1,1),
  which is why the lift moves into a custom property here.
*/
.btn.is-magnet,
.er-btn.is-magnet {
  --mag-x: 0px;
  --mag-y: 0px;
  --mag-lift: 0px;
  transform: translate3d(var(--mag-x), calc(var(--mag-y) + var(--mag-lift)), 0);
}
.btn.is-magnet { transition: background var(--transition), color var(--transition),
    border-color var(--transition), transform var(--transition); }
.er-btn.is-magnet { transition: background 0.3s, color 0.3s, transform var(--transition); }

.btn.is-magnet:hover { --mag-lift: -1px; }
.btn.is-magnet:active { --mag-lift: 0px; }

@media (prefers-reduced-motion: reduce) {
  .btn.is-magnet,
  .er-btn.is-magnet { --mag-x: 0px; --mag-y: 0px; }
}

/* --- 5. Client logo strip, scrolling ------------------------------------ */

/*
  Upgraded from the static grid by JS: the seven logos move into a flex track
  which is then duplicated, and the track slides exactly one group's width
  before repeating -- so the seam never shows. Without JS the grid above stays
  as it is.
*/
.logos.is-marquee {
  display: block;
  overflow: hidden;
  /* Softens both ends so logos enter and leave rather than being cut off. */
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.logos__track {
  display: flex;
  width: max-content;
  animation: logos-scroll 30s linear infinite;
}
/*
  Paused by a class the script toggles, not by :hover. On a touch screen
  :hover latches on tap, which froze the strip for good the first time anyone
  touched it. The script hooks pointerenter/leave for a mouse and
  pointerdown/up for a finger, so a press-and-hold pauses it there -- which is
  also the only pause mechanism a touch visitor has (WCAG 2.2.2).
*/
.logos.is-marquee.is-paused .logos__track,
.logos.is-marquee:focus-within .logos__track {
  animation-play-state: paused;
}
.logos__group {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  /* Matches the inter-logo gap, so the join between the two groups keeps the
     same rhythm as the rest of the strip. */
  padding-right: var(--sp-5);
}
.logos.is-marquee .logos__tile {
  width: 8rem;
  flex: none;
}

@keyframes logos-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .logos__track { animation: none; }
}

/* --- 6. Cursor-following background glow -------------------------------- */

/*
  One fixed element, created by JS and parked at the bottom of the stack. The
  negative z-index is what keeps it genuinely behind the page: `body`'s white
  background propagates to the canvas, so this paints above that and below
  every section, card and paragraph. It shows through wherever a section has
  no opaque ground of its own, and is simply hidden where one does -- which is
  the point, it is a ground, not an overlay.

  The teal is `--c-accent`, the same #76abae the testimonial quote panels are
  tinted with, and `--glow-a` in the tokens block is the single dial for how
  strong it is. The stops run all the way to 100% so the falloff uses the whole
  22rem radius -- an earlier 72% cut-off made it a small patch instead of a wash.
*/
.cursor-glow {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1;
  width: 44rem;
  height: 44rem;
  margin: -22rem 0 0 -22rem;
  pointer-events: none;
  background: radial-gradient(
    circle closest-side,
    rgba(118, 171, 174, var(--glow-a)),
    rgba(118, 171, 174, calc(var(--glow-a) * 0.5)) 50%,
    rgba(118, 171, 174, 0) 100%
  );
  opacity: 0;
  transition: opacity 700ms linear;
  will-change: transform;
}
.cursor-glow.is-on { opacity: 1; }

/*
  A section that paints its own opaque ground hides the fixed copy above
  completely. On /ergebnisse/ and /deep-reading-engine/ every section does, so
  the glow never appeared there at all, and on the homepage the hero swallowed
  the whole first screen.

  So each ground-painting section gets its own clipped copy, inserted by JS.
  The section is made a stacking context for the purpose, and the copy sits at
  z-index -1 inside it. Paint order within that context is: the section's own
  background first, then this, then everything the section contains -- so the
  glow lies on the ground and still passes under every card, heading, image and
  paragraph, and takes no pointer events. It is a ground, not an overlay.
*/
.has-glow-ground { isolation: isolate; }
.glow-ground {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.glow-ground > .cursor-glow { position: absolute; }

@media (prefers-reduced-motion: reduce) {
  .cursor-glow { display: none; }
}

/* --- whole words in the attribution line -------------------------------- */
/*
  Willy asked for whole words in the testimonial and recommendation cards. The
  roles are long German compounds and the attribution column is the narrowest
  box on the page once the card grid reaches its three-column state at ~1040px.
  Measured there: the column holds 141px on the Startseite and 158px on
  /ergebnisse/, while "Geschäftsführer" wants 144, "Geschäftsführerin" 161 and
  "Angebotsvergleich" 167.

  Narrowing the gutter beside the avatar is the cheapest room available -- the
  avatar itself keeps the size Willy set, and nothing moves above 1100px, where
  the columns are already wide enough.
*/
@media (max-width: 1099px) {
  .page-home .case__person { gap: 8px; }
  .page-ergebnisse .case__person { gap: 10px; }
  /*
    "Angebotsvergleich" wants 167px and the Startseite card was down to 145 --
    it has 32px of padding where the identical card on /ergebnisse/ has 20.
    Matching that here buys the 24px, and it brings the two copies of Volker's
    card closer together, which is what they are supposed to be.
  */
  .page-home .case { padding: 20px; }
  /*
    Exactly 1024px is the tightest the three-column grid ever gets, and
    "Angebotsvergleich" was still 4px over there. Taking 6px off each side of
    the quote box clears it with room to spare on both pages; the vertical
    padding stays at 20px, so the box keeps its shape.
  */
  .page-home .case__box,
  .page-ergebnisse .case__box { padding: 20px 14px; }
}

/* --- display headings on a small phone ----------------------------------- */
/*
  Long German compounds in the big headings are wider than the column on a
  320-360px phone, and with `hyphens: manual` the browser chops them with no
  hyphen at all -- "Anwendungsbeispiel" then a lone "e" centred on its own
  line. Hyphenation is the other way out and reads worse in a centred display
  heading, so these shrink instead.

  Measured at 320px, needed against available: "Dokumentenmengen" 317/288 and
  312/288, "Umsatzpotenziale" 305/288, "Prozessautomation" 290/288.

  The vw values are picked so each heading meets its flat size exactly at the
  372px breakpoint -- 8.6vw = 32px and 9.7vw = 36px there -- so nothing steps
  as the viewport crosses it. `.dre-h2` carries its own clamp higher up,
  because it also had to cover 360px.
*/
@media (max-width: 372px) {
  .case-hero h1,
  .dre-hero h1,
  .teaser h2 { font-size: 8.6vw; }
  .page-ergebnisse .page-hero h1 { font-size: 9.7vw; }
}

/*
  Below ~340px even the trimmed attribution column cannot hold the longest
  roles: "Angebotsvergleich" wants 167px against 154 and 151, "Geschäftsführerin"
  161 against 151. One step down on the name line closes all three and is the
  smallest change available -- the avatar, the layout and every other size stay
  as they are. Whole words are what Willy asked for.
*/
@media (max-width: 340px) {
  .page-home .case__author,
  .page-ergebnisse .case__author { font-size: var(--fs-caption); }
}

/*
  Three compounds of 19-30 characters are wider than any column a sub-360px
  phone can give them: "Rechnungsverarbeitungsprozess." wants 245px against
  218, "Automatisierungskompetenz" 252 against 224, "Handlungsempfehlung" 242
  against 236. No reasonable type size fits them, so here -- and only here --
  hyphenation is the right answer: this is running prose, where a hyphen is
  ordinary German typesetting, not a centred display heading where it reads as
  a mistake.

  The limits are the conservative ones used elsewhere on the site, so a word
  breaks as "Rechnungsverarbeitungs-prozess" and never as "Ge-schäftsführer",
  which is the break Willy reported.

  Nothing changes at 360px and up, so the strict 1:1 on /e-rechnung/ stands --
  that comparison was made at desktop width, and the live original chops these
  same words on a narrow phone anyway.
*/
@media (max-width: 359px) {
  .case__quote,
  .er-features__title,
  .page-erechnung main h4 {
    hyphens: auto;
    -webkit-hyphenate-limit-before: 5;
    -webkit-hyphenate-limit-after: 4;
    hyphenate-limit-chars: 12 5 4;
  }
}
