/* ==========================================================================
   theme.css — schloss-bernhardt-dresden.de
   GENERIERT von tools/build-theme-css.mjs. Nicht von Hand aendern:
   die Quelle ist style-library/stahl-kupfer/reference.html + tools/theme-harden.css.
   ========================================================================== */
/* ============================================================================
   stahl-kupfer — the SHARED DESIGN LANGUAGE.
   This block is generated into all four pages so their styles cannot drift.
   Tokens: gunmetal steel-blue primary + copper CTA + brushed-metal neutrals.
   Every colour pair below is machine-verified — see design.md "Colour".
   ========================================================================== */
:root{
  /* ============================================================================
     schloss-bernhardt-dresden.de — die Dresdner Themenschicht ueber stahl-kupfer.
     Seed #6B4A18 (Bronze/Umbra, identisch mit der Favicon-Flaeche, Weiss darauf 8.02:1).
     Jedes Paar unten ist GEMESSEN (tools/palette-proof.mjs), nicht geschaetzt.

     Die eine Regel, die dieser Seed erzwingt und die stahl-kupfer nicht kennt:
     --cta liegt NIE auf --primary. Beide sind dunkel; ihre Leuchtdichten trennt nur
     1.36:1, eine Kupferflaeche auf der Ockerflaeche waere als Form nicht erkennbar.
     Deshalb traegt das Ockerpaneel die Rufnummer als .telbig, nie als Button, und die
     CTA-Flaeche sitzt auf --surface, --bg, --alt, --steel oder --dark (>= 3.06:1).
     ============================================================================ */

  /* --- Flaechen: warm getoente Neutrale, nie reines Grau (Dresdner Sandstein) --- */
  --bg:#faf8f4; --surface:#ffffff; --surface-alt:#f2ede4; --steel:#e7dfd1;
  --line:#dcd2c0;          /* dekorative Haarlinie (1.50:1 — nie alleiniges Signal) */
  --line-strong:#7e6c50;   /* 3.83:1 auf dem schlechtesten hellen Grund — tragende Kante */
  --dark:#1b150e; --dark-2:#2a2118; --dark-line:#3d3125; --dark-muted:#cbbba3;

  /* --- Schrift --- */
  --text:#241c11;          /* 16.81:1 auf surface · 12.71:1 auf steel */
  --muted:#544632;         /*  9.14:1 auf surface ·  6.90:1 auf steel */
  --head:#1a130a;

  /* --- Marke --- */
  --primary:#6b4a18;       /* Bronze/Umbra · Weiss darauf 8.02:1 */
  --primary-hover:#553a11;
  --primary-subtle:#f0e7d6;
  --on-primary:#ffffff;

  /* --- der EINE reservierte Akzent: die Telefonaktion --- */
  --cta:#b23c12;           /* Kupferrot · Weiss darauf 5.92:1 · /surface 5.92 · /steel 4.47 · /dark 3.06 */
  --cta-hover:#8f2f0d;
  --cta-light:#f7c29a;     /* Kupfer als TEXT auf dunklem Grund · /dark 11.32 · /dark-2 9.88 · /primary 5.02 */
  --cta-ink:#94320f;       /* Kupfer als TEXT auf hellem Grund · schlechtester Grund 5.83:1 */
  --on-cta:#ffffff;

  --dark-3:#332920;        /* gehobene Flaeche AUF dunklem Band */
  --dark-4:#3d3125;
  --dark-line-2:#57462f;
  --on-dark:#eadcc4;       /* Fliesstext auf jeder dunklen ODER Ocker-Flaeche · /primary 5.93:1 */
  --tint-2:#e9e0cf;
  --cta-tint:#fdf2ec;
  --focus:#12100c;
  --danger:#a32017; --danger-tint:#fbedea;
  --success:#1c5f3a;

  /* --- Persoenlichkeit: kantiger als die Referenz (Beschlag, nicht App) --- */
  --r-xs:2px; --r-sm:3px; --r:7px; --r-lg:12px; --pill:999px;
  --notch:14px;
  --sh-sm:0 1px 2px rgba(27,21,14,.07), 0 2px 6px rgba(27,21,14,.05);
  --sh:0 6px 18px rgba(27,21,14,.09);
  --sh-lg:0 18px 44px rgba(27,21,14,.14);
  --sh-dark:0 18px 44px rgba(0,0,0,.38);

  --c:1180px; --gut:24px;
  --ease:cubic-bezier(.22,.61,.36,1);
  --dur:.22s; --dur-slow:.58s;
  --tap:44px;
  --f:'Segoe UI',system-ui,-apple-system,'Helvetica Neue',Arial,sans-serif;
  --f-num:ui-monospace,'SF Mono','Cascadia Mono','Segoe UI Mono',Menlo,Consolas,monospace;
}

/* ---------------------------------------------------------------- base ---- */
*,*::before,*::after{box-sizing:border-box}
*{margin:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  font-family:var(--f);
  font-size:18px;              /* A10 floor — never drop to 16px */
  line-height:1.7;
  color:var(--text);
  background:var(--bg);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-underline-offset:.18em;
}
img{max-width:100%;height:auto;display:block}
svg{display:block}
a{color:var(--primary);text-decoration-thickness:1px}
/* THE BUG THIS FIXES: a bare `a:hover` is (0,1,1) and beats `.btn{color:var(--btn-fg)}`
   (0,1,0), so on hover every button label turned copper — and on .btn--cta that is
   copper text on a darker-copper wipe, i.e. the label disappears. A link that IS a
   component owns its own colour; only prose links take the copper hover.
   (Same specificity trap as `.section--dark a` further down — attribute/state selectors
   quietly outrank plain class rules.) */
a:not(:where(.btn,.callbtn,.calltab,.chip,.brand,.ftel,.telbig)):hover{
  color:var(--cta-ink)}
/* hyphens:auto on a DISPLAY heading produces mid-word breaks that read as a defect
   ("Schließzylin-" / "der" at 48px). Headings get hyphens:manual with overflow-wrap
   as the safety net for a compound too long for its column; body copy — where German
   hyphenation genuinely helps the ragged edge — keeps hyphens:auto. */
h1,h2,h3,h4{color:var(--head);line-height:1.14;letter-spacing:-.018em;font-weight:800;
  overflow-wrap:break-word;hyphens:manual}
p{max-width:68ch;hyphens:auto}
ul,ol{margin:0;padding:0}
strong{color:var(--head);font-weight:700}
::selection{background:var(--cta);color:#fff}

/* one focus treatment that survives EVERY band: white inner ring + dark outer */
:where(a,button,summary,[tabindex]):focus-visible{
  outline:none;
  box-shadow:0 0 0 3px var(--surface),0 0 0 6px var(--focus);
  border-radius:var(--r-sm);
}.section--dark :where(a,button,summary):focus-visible,.on-dark :where(a,button,summary):focus-visible,footer :where(a,button,summary):focus-visible{
  box-shadow:0 0 0 3px var(--dark),0 0 0 6px var(--cta-light);
}

/* ------------------------------------------------------------ structure --- */
.wrap{max-width:var(--c);margin-inline:auto;padding-inline:var(--gut)}
.wrap--narrow{max-width:860px}
.wrap--wide{max-width:1320px}
.section{padding:clamp(58px,7.2vw,104px) 0;position:relative}
.section--tight{padding:clamp(40px,4.6vw,64px) 0}
.section--alt{background:var(--surface-alt)}
.section--surface{background:var(--surface)}.section--dark{background:var(--dark);color:var(--dark-muted)}.section--dark h1,.on-dark h1,footer h1,.section--dark h2,.on-dark h2,footer h2,.section--dark h3,.on-dark h3,footer h3,.section--dark h4,.on-dark h4,footer h4{color:#fff}
/* ROOT-CAUSE FIX: a bare `.section--dark a` is (0,1,1) and silently beat every
   button's own (0,1,0) colour, so .btn/.callbtn inside a dark band rendered their
   label in --cta-light — copper-on-copper at ~1.4:1 on the CTA fill. A link that is
   a BUTTON carries its own colour; only prose links take the dark-band link colour. */.section--dark a:not(:where(.btn,.callbtn,.calltab,.chip,.brand,.ftel)),.on-dark a:not(:where(.btn,.callbtn,.calltab,.chip,.brand,.ftel)),footer a:not(:where(.btn,.callbtn,.calltab,.chip,.brand,.ftel)){
  color:var(--cta-light)}.section--dark .lead,.on-dark .lead,footer .lead{color:var(--on-dark)}

/* the SIGNATURE band: brushed steel. A material texture (german-design.md §4.3),
   not a decorative gradient — fine vertical hairlines at 2.5% over a flat tint. */
.section--steel{
  background:
    repeating-linear-gradient(90deg,
      rgba(34,65,92,.022) 0 1px, rgba(255,255,255,0) 1px 6px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,.42) 0 1px, rgba(255,255,255,0) 1px 14px),
    var(--steel);
}.section--dark.section--steel{
  background:
    repeating-linear-gradient(90deg,
      rgba(255,255,255,.035) 0 1px, rgba(255,255,255,0) 1px 4px),
    var(--dark);
}

/* --------------------------------------------------------- typography ----- */
.display{
  font-size:clamp(34px,5.6vw,62px);font-weight:800;line-height:1.05;
  letter-spacing:-.026em;color:var(--head);
}
.display .l2{display:block;color:var(--primary)}.section--dark .display,.on-dark .display,footer .display,.hero--dark .display{color:#fff}.section--dark .display .l2,.on-dark .display .l2,footer .display .l2,.hero--dark .display .l2{color:var(--cta-light)}
.display--long{font-size:clamp(30px,4.4vw,48px)}

.stitle{font-size:clamp(27px,3.3vw,42px);font-weight:800;letter-spacing:-.022em}
.h3{font-size:clamp(19px,1.5vw,22px);font-weight:700;letter-spacing:-.012em;line-height:1.28}
.lead{font-size:clamp(18px,1.35vw,20.5px);line-height:1.66;color:var(--muted)}
.small{font-size:16.5px;line-height:1.6}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* section head — the eyebrow + title + optional lead, three rhythms */
.shead{margin-bottom:clamp(30px,3.4vw,50px);max-width:760px}
.shead--center{margin-inline:auto;text-align:center}
.shead--split{display:grid;gap:22px clamp(28px,4vw,64px);align-items:end;max-width:none;
  grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){.shead--split{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr)}}
.shead .stitle+.lead{margin-top:15px}

/* eyebrow — variant A: copper key-bit mark + label */
.eyebrow{display:inline-flex;align-items:center;gap:10px;font-size:13px;font-weight:800;
  letter-spacing:.15em;text-transform:uppercase;color:var(--cta-ink);margin-bottom:15px}.section--dark .eyebrow,.on-dark .eyebrow,footer .eyebrow{color:var(--cta-light)}
/* the key-bitting mark — 4 teeth at 30x12. Measured: a 7-tooth profile at 26x9 renders
   as an illegible smear, so the tooth count is capped at what survives at this size. */
.eyebrow::before{content:"";width:30px;height:12px;flex:none;background:currentColor;
  clip-path:polygon(0 100%,0 42%,20% 42%,20% 8%,40% 8%,40% 58%,60% 58%,60% 22%,80% 22%,80% 70%,100% 70%,100% 100%)}
/* eyebrow — variant B: boxed, for use where a rule would be too quiet */
.eyebrow--box{border:1.5px solid var(--line-strong);color:var(--primary);
  padding:7px 14px;letter-spacing:.13em;font-size:12px}
.eyebrow--box::before{display:none}.section--dark .eyebrow--box,.on-dark .eyebrow--box,footer .eyebrow--box{border-color:var(--dark-line);color:var(--cta-light)}
/* eyebrow — variant C: the pin-tumbler rule. Pins HANG from a shear line rather than
   standing on a baseline — bottom-anchored bars read as signal-strength bars, which is
   the wrong object entirely. Top-anchored under a rule reads as a lock cross-section. */
.pinrule{display:flex;align-items:flex-start;gap:5px;height:24px;margin-bottom:16px;
  padding-top:4px;border-top:2px solid var(--cta);width:45px}
.pinrule i{width:4px;background:var(--cta);display:block;border-radius:0 0 2px 2px}
.pinrule i:nth-child(1){height:13px}.pinrule i:nth-child(2){height:7px}
.pinrule i:nth-child(3){height:17px}.pinrule i:nth-child(4){height:10px}
.pinrule i:nth-child(5){height:15px}.section--dark .pinrule,.on-dark .pinrule,footer .pinrule{border-top-color:var(--cta-light)}.section--dark .pinrule i,.on-dark .pinrule i,footer .pinrule i{background:var(--cta-light)}

/* ------------------------------------------------------------- buttons ---- */
.btn{
  --btn-bg:var(--primary); --btn-fg:var(--on-primary); --btn-bg-h:var(--primary-hover);
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:11px;
  min-height:var(--tap);padding:14px 26px;border:0;border-radius:var(--r-sm);
  background:var(--btn-bg);color:var(--btn-fg);
  font:700 17px/1.2 var(--f);letter-spacing:.005em;text-decoration:none;cursor:pointer;
  transition:background var(--dur) var(--ease),transform var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease);
  overflow:hidden;isolation:isolate;
}
/* The wipe MUST be z-index:-1, not 0. CSS paint order puts a positioned descendant at
   z-index:0 ABOVE the element's own inline content — so a button whose label is a bare
   text node (most of them) had its text painted over by the wipe on hover. `.btn>*`
   cannot rescue it: a text node is not an element and can never be lifted.
   At -1, and with `isolation:isolate` on .btn keeping it inside this stacking context,
   the wipe paints above the button's background and below the label, wrapped or not. */
.btn>*{position:relative;z-index:1}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--btn-bg-h);
  transform:scaleX(0);transform-origin:left;transition:transform .3s var(--ease)}
.btn:hover::before{transform:scaleX(1)}
.btn:hover{box-shadow:var(--sh)}
.btn:active{transform:translateY(1px)}
.btn--cta{--btn-bg:var(--cta);--btn-fg:var(--on-cta);--btn-bg-h:var(--cta-hover)}
.btn--ghost{--btn-bg:transparent;--btn-fg:var(--primary);--btn-bg-h:var(--primary);
  box-shadow:inset 0 0 0 1.5px var(--line-strong)}
.btn--ghost:hover{color:#fff}.section--dark .btn--ghost,.on-dark .btn--ghost,footer .btn--ghost{--btn-fg:#fff;--btn-bg-h:#fff;box-shadow:inset 0 0 0 1.5px var(--dark-line)}.section--dark .btn--ghost:hover,.on-dark .btn--ghost:hover,footer .btn--ghost:hover{color:var(--dark)}
.btn--lg{padding:18px 32px;font-size:18.5px}
.btn--block{display:flex;width:100%}
.btn svg{width:20px;height:20px;flex:none}

/* the call button: label above the number, icon disc at the left.
   Lifted from the Dexon hero treatment, re-coloured to copper. */
.callbtn{
  display:inline-flex;align-items:center;gap:14px;min-height:var(--tap);
  padding:11px 26px 11px 11px;border-radius:var(--pill);
  background:var(--cta);color:#fff;text-decoration:none;
  transition:background var(--dur) var(--ease),transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.callbtn:hover{background:var(--cta-hover);color:#fff;transform:translateY(-2px);box-shadow:var(--sh-lg)}
.callbtn .disc{width:46px;height:46px;flex:none;border-radius:50%;background:rgba(255,255,255,.19);
  display:grid;place-items:center}
.callbtn .disc svg{width:21px;height:21px;stroke:#fff}
/* opacity:.86 white over copper blends to #f5e7df = 4.02:1 — under AA for 12px text.
   Full white is 4.86:1. Never dim text on the accent fill to "soften" it. */
.callbtn .cap{display:block;font-size:12px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;line-height:1}
.callbtn .num{display:block;font-size:21px;font-weight:800;letter-spacing:-.01em;margin-top:3px;
  font-variant-numeric:tabular-nums}
/* Specificity note: `.section--dark a` is (0,1,1) and would otherwise win over a
   plain `.callbtn--dark` (0,1,0), painting this white-ground button in --cta-light
   at ~1.9:1. Doubling the class to (0,2,0) is what keeps it readable on a dark band. */
.callbtn.callbtn--dark{background:var(--surface);color:var(--primary)}
.callbtn.callbtn--dark:hover{background:var(--surface);color:var(--primary)}
.callbtn--dark .disc{background:var(--cta)}
.callbtn--dark .cap{color:var(--muted);opacity:1}

/* ------------------------------------------------------- icon badges ------ */
.ibadge{width:54px;height:54px;flex:none;border-radius:var(--r);display:grid;place-items:center;
  background:var(--primary-subtle);color:var(--primary);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.ibadge svg{width:26px;height:26px;stroke-width:1.7}
.ibadge--cta{background:var(--cta);color:#fff}
.ibadge--dark{background:var(--primary);color:#fff}
.ibadge--outline{background:transparent;box-shadow:inset 0 0 0 1.5px var(--line-strong)}
.ibadge--round{border-radius:50%}
.ibadge--lg{width:70px;height:70px}.ibadge--lg svg{width:32px;height:32px}
.ibadge--sm{width:40px;height:40px;border-radius:var(--r-sm)}.ibadge--sm svg{width:20px;height:20px}.section--dark .ibadge,.on-dark .ibadge,footer .ibadge{background:var(--dark-3);color:var(--cta-light)}

/* --------------------------------------------------------------- cards ---- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:clamp(22px,2.2vw,30px);position:relative;
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease),
             transform var(--dur) var(--ease)}
.card:hover{border-color:var(--line-strong);box-shadow:var(--sh);transform:translateY(-3px)}
.card h3,.card .h3{margin-bottom:9px}
.card p{color:var(--muted);font-size:17px}.section--dark .card,.on-dark .card,footer .card{background:var(--dark-2);border-color:var(--dark-line);color:var(--dark-muted)}.section--dark .card:hover,.on-dark .card:hover,footer .card:hover{border-color:var(--dark-line-2)}.section--dark .card p,.on-dark .card p,footer .card p{color:var(--dark-muted)}

/* the key-bow NOTCH — the style's structural signature: one cut top-right corner.
   NOTE: clip-path also clips border AND box-shadow, so a notched box can never carry
   either. Two forms exist, and both are honest about that:
     .card--notch  — a FILLED notched card (no edge). Only legible on a band that
                     contrasts its fill, so it ships on tint/steel/dark bands.
     .notch/.notch__in — a two-element notched card WITH a hairline edge: the outer
                     box is the line colour, the inner is inset 1px and re-clipped.
   Elevation on a clipped box must use filter:drop-shadow(), which is applied after
   clipping and therefore traces the notch; box-shadow would be cut away. */
.card--notch{
  clip-path:polygon(0 0,calc(100% - var(--notch)) 0,100% var(--notch),100% 100%,0 100%);
  border:0;background:var(--primary-subtle);box-shadow:none;
  transition:background var(--dur) var(--ease),transform var(--dur) var(--ease),filter var(--dur) var(--ease)}
.card--notch:hover{background:var(--tint-2);filter:drop-shadow(0 10px 20px rgba(16,25,35,.13))}.section--dark .card--notch,.on-dark .card--notch,footer .card--notch{background:var(--dark-2)}.section--dark .card--notch:hover,.on-dark .card--notch:hover,footer .card--notch:hover{background:var(--dark-4);filter:none}

.notch{--notch-line:var(--line);
  clip-path:polygon(0 0,calc(100% - var(--notch)) 0,100% var(--notch),100% 100%,0 100%);
  background:var(--notch-line);padding:1px;
  transition:background var(--dur) var(--ease),filter var(--dur) var(--ease)}
.notch:hover{--notch-line:var(--line-strong);filter:drop-shadow(0 10px 20px rgba(16,25,35,.12))}
.notch__in{
  clip-path:polygon(0 0,calc(100% - var(--notch)) 0,100% calc(var(--notch) - 1px),100% 100%,0 100%);
  background:var(--surface);padding:clamp(22px,2.2vw,30px);height:100%}.section--dark .notch,.on-dark .notch,footer .notch{--notch-line:var(--dark-line)}.section--dark .notch:hover,.on-dark .notch:hover,footer .notch:hover{--notch-line:var(--dark-line-2);filter:none}.section--dark .notch__in,.on-dark .notch__in,footer .notch__in{background:var(--dark-2)}

/* the COPPER INLAY — a 3px leading edge marking the emphasis card in a set */
.card--inlay{border-top:3px solid var(--cta)}
.card--lead{background:var(--primary);border-color:var(--primary);color:var(--on-dark)}
.card--lead h3,.card--lead .h3{color:#fff}
.card--lead p{color:var(--on-dark)}

/* -------------------------------------------------------------- grids ----- */
.grid{display:grid;gap:clamp(16px,1.7vw,24px)}
.g2{grid-template-columns:minmax(0,1fr)}
.g3{grid-template-columns:minmax(0,1fr)}
.g4{grid-template-columns:minmax(0,1fr)}
@media(min-width:640px){.g2{grid-template-columns:repeat(2,minmax(0,1fr))}.g3{grid-template-columns:repeat(2,minmax(0,1fr))}.g4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:980px){.g3{grid-template-columns:repeat(3,minmax(0,1fr))}.g4{grid-template-columns:repeat(4,minmax(0,1fr))}}
.split{display:grid;gap:clamp(28px,4vw,60px);align-items:center;grid-template-columns:1fr}
@media(min-width:900px){.split{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .split--wide-l{grid-template-columns:minmax(0,1.22fr) minmax(0,.78fr)}
  .split--wide-r{grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr)}
  .split--flip>*:first-child{order:2}}

/* --------------------------------------------------------------- chips ---- */
.chips{display:flex;flex-wrap:wrap;gap:9px;padding:0;list-style:none}
.chip{display:inline-flex;align-items:center;gap:8px;padding:9px 15px;border-radius:var(--pill);
  background:var(--surface);border:1px solid var(--line);font-size:16px;font-weight:600;color:var(--text);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease)}
.chip:hover{border-color:var(--cta);background:var(--cta-tint)}
.chip--solid{background:var(--primary-subtle);border-color:transparent;color:var(--primary)}.section--dark .chip,.on-dark .chip,footer .chip{background:var(--dark-3);border-color:var(--dark-line);color:var(--on-dark)}

/* ------------------------------------------------------- image slots ------ */
.imgph{position:relative;display:block;width:100%;background:var(--steel);border-radius:var(--r);
  overflow:hidden;color:var(--muted)}
.imgph img{width:100%;height:100%;object-fit:cover}
.imgph--notch{clip-path:polygon(0 0,calc(100% - 22px) 0,100% 22px,100% 100%,0 100%);border-radius:0}
.ratio-16x9{aspect-ratio:16/9}.ratio-4x3{aspect-ratio:4/3}.ratio-1x1{aspect-ratio:1/1}
.ratio-3x4{aspect-ratio:3/4}.ratio-3x2{aspect-ratio:3/2}

/* ------------------------------------------------------------- motion ----- */
.reveal{transform:translateY(18px);transition:transform var(--dur-slow) var(--ease)}
.reveal.in{transform:none}
.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}
.reveal.d3{transition-delay:.24s}.reveal.d4{transition-delay:.32s}
/* one-shot clip reveal for images — fires from the same observer */
.wipe{clip-path:inset(0 0 100% 0);transition:clip-path .8s var(--ease)}
.wipe.in{clip-path:inset(0 0 0 0)}

@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important}
  .reveal{transform:none}
  .wipe{clip-path:none}}

/* ======================================================================== */
/*  SHARED CHROME — identical on every page (navbar, call bar, to-top,      */
/*  footer). Built once here so the four pages cannot drift.                */
/* ======================================================================== */

/* --- topbar: the number is ALWAYS visible, never behind the hamburger --- */
.topbar{background:var(--dark);color:var(--dark-muted);font-size:15.5px}
.topbar .wrap{display:flex;align-items:center;justify-content:space-between;gap:16px;
  min-height:var(--tap);flex-wrap:wrap}
.topbar a{color:#fff;text-decoration:none;display:inline-flex;align-items:center;gap:9px;
  min-height:var(--tap);font-weight:600}
.topbar a:hover{color:var(--cta-light)}
.topbar svg{width:17px;height:17px;stroke:var(--cta-light);flex:none}
.topbar .tb-note{display:none}
@media(min-width:760px){.topbar .tb-note{display:inline-flex;align-items:center;gap:9px}}

/* --- header --- */
header{position:sticky;top:0;z-index:120;background:var(--surface);
  border-bottom:1px solid var(--line);transition:box-shadow var(--dur) var(--ease)}
header.stuck{box-shadow:0 6px 20px rgba(16,25,35,.09)}
.navrow{display:flex;align-items:center;gap:18px;min-height:74px}
.brand{display:inline-flex;align-items:center;gap:11px;text-decoration:none;margin-right:auto}
.brand .bmark{width:40px;height:40px;flex:none;border-radius:var(--r-sm);background:var(--primary);
  display:grid;place-items:center}
.brand .bmark svg{width:23px;height:23px;stroke:var(--cta-light)}
.brand b{font-size:20px;font-weight:800;color:var(--head);letter-spacing:-.02em;line-height:1.1}
@media(max-width:400px){/* the lockup alone was 229px, overflowing a 320px viewport once the burger
     and gutters were counted. */
  .brand b{font-size:16.5px}.brand span{font-size:11px}
  .brand .bmark{width:34px;height:34px}.brand .bmark svg{width:19px;height:19px}
  .navrow{gap:10px}}
.brand span{display:block;font-size:12.5px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.nav{display:none;gap:4px;list-style:none}
.nav a{display:inline-flex;align-items:center;min-height:var(--tap);padding:0 11px;
  font-size:16.2px;font-weight:600;color:var(--text);text-decoration:none;border-radius:var(--r-sm);
  white-space:nowrap;
  transition:color var(--dur) var(--ease),background var(--dur) var(--ease)}
.nav a:hover,.nav a[aria-current="page"]{color:var(--primary);background:var(--primary-subtle)}
.navcall{display:none}
.navcall span{white-space:nowrap}
/* raised from 1040: with four items plus the brand and the call button, the bar
   only genuinely fits from ~1120px. Below that the burger is the honest answer. */
@media(min-width:1120px){.nav{display:flex}.navcall{display:inline-flex}
  .brand b{white-space:nowrap}}
/* flex:none is load-bearing — as a flex item in .navrow the burger shrank to 38px
   wide at tablet widths, i.e. under the 44px floor for the ONE control that opens
   the menu. Width alone does not protect a flex item. */
.burger{display:inline-grid;place-items:center;flex:none;
  width:var(--tap);height:var(--tap);min-width:var(--tap);
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--surface);cursor:pointer}
.burger svg{width:24px;height:24px;stroke:var(--head)}
@media(min-width:1120px){.burger{display:none}}
.mobmenu{display:none;border-top:1px solid var(--line);background:var(--surface)}
.mobmenu.open{display:block}
.mobmenu ul{list-style:none;padding:10px 0 18px}
.mobmenu a{display:flex;align-items:center;min-height:52px;font-size:17.5px;font-weight:600;
  color:var(--text);text-decoration:none;border-bottom:1px solid var(--line)}
.mobmenu a:hover{color:var(--cta-ink)}

/* --- sticky mobile call bar (C2: class matches (call|tel|phone|anruf) + position:fixed) --- */
.callbar{position:fixed;left:0;right:0;bottom:0;z-index:150;display:none;
  background:var(--surface);border-top:1px solid var(--line);
  box-shadow:0 -6px 22px rgba(16,25,35,.15);padding:9px 14px calc(9px + env(safe-area-inset-bottom))}
.callbar a{display:flex;align-items:center;justify-content:center;gap:11px;min-height:52px;
  border-radius:var(--r-sm);background:var(--cta);color:#fff;text-decoration:none;
  font-size:18.5px;font-weight:800;letter-spacing:.01em}
.callbar a svg{width:22px;height:22px;stroke:#fff;flex:none}
@media(max-width:1119px){.callbar{display:block}body{padding-bottom:84px}}

/* --- scroll to top --- */
.totop{position:fixed;right:16px;bottom:96px;z-index:140;width:48px;height:48px;
  display:grid;place-items:center;border:1px solid var(--line);border-radius:50%;
  background:var(--surface);color:var(--primary);cursor:pointer;
  opacity:0;visibility:hidden;transform:translateY(9px);
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease),
             visibility var(--dur) var(--ease),box-shadow var(--dur) var(--ease)}
.totop.show{opacity:1;visibility:visible;transform:none}
.totop:hover{box-shadow:var(--sh);border-color:var(--line-strong)}
.totop svg{width:22px;height:22px;stroke:currentColor}
@media(min-width:1120px){.totop{bottom:24px}}

/* --- footer --- */
footer{background:var(--dark);color:var(--dark-muted);padding-top:clamp(48px,5.4vw,76px)}
footer h3{color:#fff;font-size:17px;letter-spacing:.09em;text-transform:uppercase;margin-bottom:17px}
.fgrid{display:grid;gap:34px clamp(24px,3vw,48px);grid-template-columns:1fr}
@media(min-width:700px){.fgrid{grid-template-columns:repeat(2,1fr)}}
@media(min-width:1020px){.fgrid{grid-template-columns:1.4fr 1fr 1fr 1.1fr}}
footer ul{list-style:none}
/* 44px floor on footer links too: A11 only WARNS on non-call controls, but this
   audience is older and often one-handed on a phone, so the floor is worth the height. */
footer li{margin-bottom:0}
footer a{color:var(--dark-muted);text-decoration:none;
  display:inline-flex;align-items:center;min-height:var(--tap)}
footer a:hover{color:var(--cta-light);text-decoration:underline}
footer .ftel{display:inline-flex;align-items:center;gap:11px;min-height:var(--tap);
  color:#fff;font-size:21px;font-weight:800;font-variant-numeric:tabular-nums}
footer .ftel svg{width:21px;height:21px;stroke:var(--cta-light);flex:none}
.fbase{margin-top:clamp(34px,4vw,52px);border-top:1px solid var(--dark-line);
  padding:22px 0 26px;display:flex;flex-wrap:wrap;gap:10px 22px;
  align-items:center;justify-content:space-between;font-size:15.5px}
.fbase ul{display:flex;flex-wrap:wrap;gap:2px 20px}
.fbase li{margin:0}
.fbase a{min-height:var(--tap)}

/* skip link — visible only on focus, above the sticky header */
.skip{position:absolute;left:0;top:0;z-index:400;background:var(--cta);color:#fff;
  padding:13px 20px;font-weight:700;text-decoration:none;border-radius:0 0 var(--r-sm) 0;
  clip-path:inset(50%);width:1px;height:1px;overflow:hidden;white-space:nowrap}
.skip:focus{clip-path:none;width:auto;height:auto;color:#fff}

/* footer lockup reuses .brand with dark-band colours */
.brand--foot b{color:#fff}
.brand--foot span span{color:var(--dark-muted)}
.brand--foot .bmark{background:var(--dark-2);border:1px solid var(--dark-line)}

/* ======================================================================== */
/*  Two late primitives, both from the hotlock/dexon reads.                 */
/* ======================================================================== */

/* THE KEYPAD GRID — the layout lines ARE the design. One `gap:1px` over a line-
   coloured ground, cells painted in the surface colour, so the rules are drawn by
   the gap rather than by per-cell borders (the source hand-tuned border-width per
   cell at every breakpoint; this needs no arithmetic and reflows for free).
   Reads unmistakably as security hardware — the closest thing this style has to a
   trade-specific structure. Also the mechanism behind the segmented assurance slab:
   three cells at gap:2px read as ONE slab, not three cards. */
.keypad{display:grid;gap:1px;background:var(--line);border:1px solid var(--line)}
.keypad>*{background:var(--surface);padding:clamp(20px,2.2vw,30px);margin:0}
.keypad--tight{gap:2px;background:var(--line-strong);border:0}
.keypad--cta{gap:2px;background:var(--cta-hover);border:0}
.keypad--cta>*{background:var(--cta);color:#fff}
.keypad--cta>* :where(h2,h3,h4,.h3,strong){color:#fff}.section--dark .keypad,.on-dark .keypad,footer .keypad{background:var(--dark-line);border-color:var(--dark-line)}.section--dark .keypad>*,.on-dark .keypad>*,footer .keypad>*{background:var(--dark-2)}
@media(min-width:640px){.keypad--2{grid-template-columns:repeat(2,1fr)}
  .keypad--3{grid-template-columns:repeat(2,1fr)}.keypad--4{grid-template-columns:repeat(2,1fr)}}
@media(min-width:980px){.keypad--3{grid-template-columns:repeat(3,1fr)}
  .keypad--4{grid-template-columns:repeat(4,1fr)}.keypad--6{grid-template-columns:repeat(6,1fr)}}

/* PHONE NUMBER AS DISPLAY TYPE — no button chrome at all. On a page where the call
   IS the only conversion channel, a huge tappable number outranks another square
   button, and it still clears the 44px target by a wide margin. */
.telbig{display:inline-flex;align-items:center;gap:14px;text-decoration:none;
  font-size:clamp(30px,4.4vw,54px);font-weight:800;line-height:1.06;
  letter-spacing:-.025em;font-variant-numeric:tabular-nums;color:var(--head);
  transition:color var(--dur) var(--ease)}
.telbig:hover{color:var(--cta-ink)}
.telbig svg{width:.72em;height:.72em;flex:none;stroke:var(--cta);stroke-width:1.8}.section--dark .telbig,.on-dark .telbig,footer .telbig{color:#fff}.section--dark .telbig:hover,.on-dark .telbig:hover,footer .telbig:hover{color:var(--cta-light)}.section--dark .telbig svg,.on-dark .telbig svg,footer .telbig svg{stroke:var(--cta-light)}

/* THE CALL TAB — a copper block that reads as die-cut out of the image above it:
   one rounded corner, zero top radius, and a negative pull so it bites into the
   photo's bottom edge. From the `blocks` kit, where it is a generic tab; the recon
   flagged it as "the best-shaped button in the corpus and it wants a phone number",
   so here it only ever carries the number. Unlike .btn it has NO hover wipe —
   design-tokens.md §5 forbids animating the CTA; the hover is colour only. */
.calltab{
  display:inline-flex;align-items:center;gap:13px;position:relative;z-index:2;
  margin-top:-34px;padding:20px 30px 20px 26px;
  border-radius:0 var(--r-lg) 0 0;
  background:var(--cta);color:#fff;text-decoration:none;
  font-size:clamp(19px,1.7vw,24px);font-weight:800;letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;min-height:var(--tap);
  transition:background var(--dur) var(--ease)}
.calltab:hover{background:var(--cta-hover);color:#fff}
.calltab svg{width:1.05em;height:1.05em;flex:none;stroke:currentColor;stroke-width:1.9}
.calltab .cap{display:block;font-size:12px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;line-height:1;margin-bottom:4px}

/* TAP-TARGET FLOOR for every click-to-call, whatever a page happens to call it.
   A11 measures the rendered box, so a number styled as pure display type still has
   to clear 44px. min-height only bites on a flex/block box, hence the display switch;
   verified that no tel: link on any page sits inline inside a <p>, so this is safe. */
/* :not(.navcall) is load-bearing: this rule is (0,1,1) and would otherwise beat
   `.navcall{display:none}` (0,1,0) below 1040px, resurrecting the desktop call
   button and pushing the burger off-screen on every phone <=390px. */
a[href^="tel:"]:not(.navcall){display:inline-flex;align-items:center;min-height:var(--tap)}
/* ============================================================================
   stahl-kupfer — SHARED LANGUAGE, PART 2.
   Section + layout primitives and the widget set, all drawn from the recon
   catalogue (`_recon-catalogue.md`). Neutral, composable bricks — never finished
   templates. Every value is a token; nothing here introduces a new theme value.
   ========================================================================== */

/* ------------------------------------------------------------------------- */
/*  A · THE SEAM HELPERS — the overlap grammar, made hard to get wrong.       */
/*  Rule 1 of the style is "every other band has exactly one element crossing  */
/*  its boundary". Two traps make it easy to botch by hand: the crossing       */
/*  element must be the FIRST or LAST child of its band (pulling up a mid-     */
/*  section element just collides with the heading above it), and it needs a   */
/*  z-index or the next band paints over it. These encode both.               */
/* ------------------------------------------------------------------------- */
.seam-up{position:relative;z-index:2;margin-top:calc(-1 * var(--seam,54px))}
.seam-down{position:relative;z-index:2;margin-bottom:calc(-1 * var(--seam,54px))}
.seam-sm{--seam:32px} .seam-lg{--seam:82px}
/* A .seam-down is only half the mechanism and on its own it does NOTHING: the pull is
   smaller than the band's own bottom padding, so the element never reaches the seam.
   It takes THREE classes, and all three are required:
     .section--hang   on the band the element hangs OUT of  (drops its bottom padding)
     .seam-down       on that band's LAST child
     .section--catch  on the following band                 (makes room for the overhang)
   The .seam-up counterpart needs only .seam-up on the next band's FIRST child, plus
   enough bottom padding on the band above for the element to sit in. */
.section--hang{padding-bottom:0}
.section--catch{padding-top:calc(clamp(58px,7.2vw,104px) + var(--seam,54px))}
@media(max-width:699px){/* below 700px the bands are too short for a crossing element to read as
     deliberate — it just looks like a mistake. Collapse them. */
  .seam-up,.seam-down{margin-top:0;margin-bottom:0}
  .section--catch{padding-top:clamp(58px,7.2vw,104px)}}

/* ------------------------------------------------------------------------- */
/*  B · SECTION + LAYOUT PRIMITIVES                                           */
/* ------------------------------------------------------------------------- */

/* B1 · DIPTYCH — zero-gutter two-column band, each half carrying its OWN fill,
   meeting at the exact centreline with no divider. Off-centre text comes from
   asymmetric percentage padding, so it stays optically centred at every width
   with no media query for position. (hotlock: three visually different bands
   from one grid rule.) */
.diptych{display:grid;grid-template-columns:minmax(0,1fr)}
.diptych__half{padding:clamp(38px,5vw,72px) var(--gut)}
@media(min-width:900px){.diptych{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .diptych__half{padding:clamp(52px,6vw,92px) 8% clamp(52px,6vw,92px) 14%}
  .diptych__half+.diptych__half{padding:clamp(52px,6vw,92px) 14% clamp(52px,6vw,92px) 8%}}
.diptych__half--dark{background:var(--dark);color:var(--dark-muted)}
.diptych__half--dark :where(h2,h3,h4){color:#fff}
.diptych__half--steel{background:var(--steel)}
.diptych__half--primary{background:var(--primary);color:var(--on-dark)}
.diptych__half--primary :where(h2,h3,h4){color:#fff}
/* steel ground so a slow or failed image reads as an empty slot, not a black void */
.diptych__half--media{padding:0;position:relative;min-height:320px;background:var(--steel)}
.diptych__half--media img,.diptych__half--media .imgph{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:0}

/* B2 · LEDGER — one hairline frame around rows whose narrow cell is a label tab
   and whose wide cell carries the content. A ruled register reads as a record;
   a card grid reads as marketing. Right for Öffnungszeiten, coverage, liability
   splits, credential lists. (dexon: 20% white label cell / 80% filled cell.) */
.ledger{border:1px solid var(--line);background:var(--surface)}
.ledger__row{display:grid;grid-template-columns:minmax(0,1fr);border-top:1px solid var(--line)}
.ledger__row:first-child{border-top:0}
.ledger__k{padding:16px clamp(16px,2vw,24px);font-weight:700;color:var(--head);
  background:var(--surface-alt);font-size:16.5px;display:flex;align-items:center}
.ledger__v{padding:16px clamp(16px,2vw,24px);color:var(--muted);font-size:16.8px;line-height:1.55}
@media(min-width:700px){.ledger__row{grid-template-columns:minmax(180px,.26fr) 1fr}
  .ledger__k{border-right:1px solid var(--line)}}
.ledger--dark{border-color:var(--dark-line);background:var(--dark-2)}
.ledger--dark .ledger__row{border-top-color:var(--dark-line)}
.ledger--dark .ledger__k{background:var(--dark-3);color:#fff;border-right-color:var(--dark-line)}
.ledger--dark .ledger__v{color:var(--dark-muted)}

/* B3 · SIDE RAIL — a sticky column against a single-file stack. The spine of a
   long service page: the number stays reachable through explanatory copy.
   Single-viewport sticky only — never a multi-viewport scroll sequence. */
.rail{display:grid;gap:clamp(28px,4vw,54px);grid-template-columns:1fr;align-items:start}
@media(min-width:1000px){.rail{grid-template-columns:minmax(0,.4fr) minmax(0,1fr)}
  .rail__side{position:sticky;top:108px}
  .rail--right .rail__side{order:2}}
.rail__main{display:grid;gap:clamp(30px,3.6vw,52px)}

/* B4 · OFFSET GRID — hand-placed masonry rhythm with zero JS and no library.
   Every nth item drops, so the grid reads composed rather than tabulated.
   (ekvator built this with presentational spacer divs; nth-child is cleaner.) */
.offgrid{display:grid;gap:clamp(16px,1.8vw,26px);grid-template-columns:minmax(0,1fr);align-items:start}
@media(min-width:640px){.offgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .offgrid>*:nth-child(2n){margin-top:clamp(20px,3vw,44px)}}
@media(min-width:980px){.offgrid--3{grid-template-columns:repeat(3,minmax(0,1fr))}
  .offgrid--3>*:nth-child(2n){margin-top:0}
  .offgrid--3>*:nth-child(3n-1){margin-top:clamp(24px,3.4vw,52px)}}

/* B5 · PEEK RAIL — user-driven horizontal scroll with the next card bleeding off
   the edge as the affordance. scroll-snap, NOT an auto-carousel: nothing moves
   until the reader moves it, and every card is keyboard-reachable. */
.peek{display:flex;gap:clamp(14px,1.6vw,22px);overflow-x:auto;scroll-snap-type:x mandatory;
  padding-bottom:14px;scrollbar-width:thin}
.peek>*{flex:0 0 clamp(250px,74vw,330px);scroll-snap-align:start}
@media(min-width:760px){.peek>*{flex-basis:330px}}
.peek::-webkit-scrollbar{height:8px}
.peek::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:var(--pill)}
.peek::-webkit-scrollbar-track{background:var(--surface-alt)}

/* B6 · MOSAIC — one tall image beside two stacked halves. An asymmetric 1+2
   composition out of a plain two-column grid. */
.mosaic{display:grid;gap:14px;grid-template-columns:minmax(0,1fr)}
@media(min-width:700px){.mosaic{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr)}}
.mosaic__col{display:grid;gap:14px;grid-template-rows:1fr 1fr}
.mosaic .imgph{height:100%}
.mosaic--flip>*:first-child{order:2}

/* B7 · COMPARE — a static two-up with a shared centre rule. This is the LEGAL
   form of a before/after: the source templates build that with <input
   type="range">, which the validator hard-fails. Nothing here is interactive. */
.compare{display:grid;grid-template-columns:minmax(0,1fr);border:1px solid var(--line);
  background:var(--surface)}
.compare__side{padding:clamp(22px,2.6vw,34px)}
.compare__side+.compare__side{border-top:1px solid var(--line)}
@media(min-width:760px){.compare{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .compare__side+.compare__side{border-top:0;border-left:1px solid var(--line)}}
.compare__tag{display:inline-flex;align-items:center;gap:9px;margin-bottom:13px;
  font-size:12.5px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}
.compare__side--a .compare__tag{color:var(--success)}
.compare__side--b .compare__tag{color:var(--danger)}

/* B8 · TIMELINE — vertical connected steps. Order matters, so a stepper, not a
   grid. The connector is a pseudo-element so no extra markup carries it. */
.timeline{list-style:none;display:grid;gap:clamp(20px,2.4vw,32px);counter-reset:tl}
.timeline>li{position:relative;padding-left:64px;counter-increment:tl}
.timeline>li::before{content:counter(tl,decimal-leading-zero);position:absolute;left:0;top:0;
  width:44px;height:44px;border-radius:50%;display:grid;place-items:center;
  background:var(--surface);color:var(--primary);box-shadow:inset 0 0 0 1.5px var(--line-strong);
  font:800 14px/1 var(--f-num);letter-spacing:.02em}
.timeline>li::after{content:"";position:absolute;left:21.5px;top:52px;bottom:calc(-1 * clamp(20px,2.4vw,32px));
  width:1px;background:var(--line)}
.timeline>li:last-child::after{display:none}.section--dark .timeline>li::before,.on-dark .timeline>li::before,footer .timeline>li::before{background:var(--dark-2);color:var(--cta-light);
  box-shadow:inset 0 0 0 1.5px var(--dark-line)}.section--dark .timeline>li::after,.on-dark .timeline>li::after,footer .timeline>li::after{background:var(--dark-line)}

/* B9 · STEPPER — the horizontal counterpart, for a sibling page that must not
   repeat the timeline's shape. */
.stepper{list-style:none;display:grid;gap:clamp(18px,2vw,26px);grid-template-columns:minmax(0,1fr);
  counter-reset:st}
@media(min-width:820px){.stepper{grid-template-columns:repeat(4,minmax(0,1fr))}}
.stepper>li{counter-increment:st;position:relative;padding-top:56px}
.stepper>li::before{content:counter(st,decimal-leading-zero);position:absolute;left:0;top:0;
  width:42px;height:42px;border-radius:var(--r-sm);display:grid;place-items:center;
  background:var(--primary);color:#fff;font:800 14px/1 var(--f-num)}
.stepper>li::after{content:"";position:absolute;left:52px;top:20px;right:0;height:1px;
  background:var(--line)}
.stepper>li:last-child::after{display:none}
@media(max-width:819px){.stepper>li::after{display:none}}

/* B10 · NOTICE — a real callout, never a paragraph. --danger is the safety
   register (gas, electrical, 110/112); --info carries the copper. */
.notice{border:1px solid var(--danger);border-left-width:5px;background:var(--danger-tint);
  padding:clamp(22px,2.6vw,34px);border-radius:var(--r-sm)}
.notice__head{display:flex;align-items:center;gap:13px;margin-bottom:12px}
.notice__ic{width:40px;height:40px;flex:none;border-radius:50%;display:grid;place-items:center;
  background:var(--danger);color:#fff}
.notice__ic svg{width:22px;height:22px;stroke:currentColor}
.notice h2,.notice h3,.notice .h3{color:var(--danger)}
.notice--info{border-color:var(--cta);background:var(--cta-tint)}
.notice--info .notice__ic{background:var(--cta)}
.notice--info :where(h2,h3,.h3){color:var(--cta-ink)}

/* B11 · STAT RAIL — static figures only. The sources animate these with
   odometers; counters are on the banlist and an invented figure breaks iron
   rule 4, so a figure appears here only if the partner can defend it. */
.stats{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  grid-template-columns:repeat(2,minmax(0,1fr))}
@media(min-width:820px){.stats{grid-template-columns:repeat(4,minmax(0,1fr))}}
.stats>div{background:var(--surface);padding:clamp(20px,2.4vw,30px)}
.stats b{display:block;font-size:clamp(28px,3.4vw,40px);font-weight:800;color:var(--primary);
  letter-spacing:-.025em;font-variant-numeric:tabular-nums;line-height:1.05}
.stats span{display:block;margin-top:7px;font-size:16px;color:var(--muted);line-height:1.4}.section--dark .stats,.on-dark .stats,footer .stats{background:var(--dark-line);border-color:var(--dark-line)}.section--dark .stats>div,.on-dark .stats>div,footer .stats>div{background:var(--dark-2)}.section--dark .stats b,.on-dark .stats b,footer .stats b{color:var(--cta-light)}.section--dark .stats span,.on-dark .stats span,footer .stats span{color:var(--dark-muted)}

/* B12 · INDEX ROWS — the hover-flood service index. Three independent sources
   converged on this shape, and it is the answer to "never a bare <ul>": a list
   that is also a gallery. Four coordinated changes, all pure CSS. */
.rows{list-style:none;border-top:1px solid var(--line)}
.rows>li{position:relative;isolation:isolate;border-bottom:1px solid var(--line);
  transition:border-color var(--dur) var(--ease)}
.rows__flood{position:absolute;inset:auto 0 0 0;height:0;z-index:-1;background:var(--primary);
  transition:height .34s var(--ease)}
.rows>li:hover .rows__flood,.rows>li:focus-within .rows__flood{height:100%}
.rows__link{display:grid;gap:6px 20px;align-items:center;padding:clamp(20px,2.4vw,30px) 0;
  text-decoration:none;color:inherit;min-height:var(--tap)}
.rows__link::after{content:"";position:absolute;inset:0;z-index:1}
.rows>li:hover :where(.rows__t,.rows__d),.rows>li:focus-within :where(.rows__t,.rows__d){color:#fff}
.rows__t{font-size:clamp(19px,1.6vw,23px);font-weight:700;color:var(--head);
  transition:color var(--dur) var(--ease)}
.rows__d{font-size:16.8px;color:var(--muted);line-height:1.55;max-width:62ch;
  transition:color var(--dur) var(--ease)}
.rows__n{font:800 13px/1 var(--f-num);color:var(--muted);letter-spacing:.08em}
.rows__thumb{position:absolute;right:clamp(16px,2.4vw,36px);top:50%;translate:0 -50%;
  width:180px;aspect-ratio:16/11;overflow:hidden;border-radius:var(--r-sm);
  opacity:0;scale:.86;transition:opacity .3s var(--ease),scale .3s var(--ease);
  pointer-events:none;display:none}
@media(min-width:1040px){.rows__thumb{display:block}
  .rows__link{padding-right:230px}
  .rows>li:hover .rows__thumb,.rows>li:focus-within .rows__thumb{opacity:1;scale:1}}

/* B13 · BAND STRIP — a full-bleed accent rule between sections, carrying the
   service vocabulary. The source MARQUEES this; continuous motion is banned, so
   it is static and reads as a hard divider. */
.strip{background:var(--cta);padding:22px 0}
.strip ul{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;
  align-items:center;gap:12px clamp(16px,2vw,26px)}
.strip li{color:#fff;font-size:clamp(15px,1.5vw,19px);font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;display:inline-flex;align-items:center;gap:12px clamp(16px,2vw,26px)}
.strip li:not(:last-child)::after{content:"";width:26px;height:11px;flex:none;background:#fff;
  opacity:.62;
  clip-path:polygon(0 100%,0 42%,20% 42%,20% 8%,40% 8%,40% 58%,60% 58%,60% 22%,80% 22%,80% 70%,100% 70%,100% 100%)}
.strip--dark{background:var(--dark)}
.strip--steel{background:var(--steel)}
.strip--steel li{color:var(--head)}
.strip--steel li:not(:last-child)::after{background:var(--cta);opacity:1}

/* ------------------------------------------------------------------------- */
/*  C · WIDGETS                                                              */
/* ------------------------------------------------------------------------- */

/* C1 · numeral pill — the step marker. Reads better than a bare digit or a
   filled circle, and it is the right shape for a numbered flow. */
.numpill{display:inline-flex;align-items:center;justify-content:center;min-width:44px;
  min-height:30px;padding:5px 14px;border-radius:var(--pill);border:1px solid var(--line);
  background:var(--surface-alt);color:var(--primary);font:800 13.5px/1 var(--f-num);
  letter-spacing:.04em}
.numpill--cta{background:var(--cta);border-color:var(--cta);color:#fff}.section--dark .numpill,.on-dark .numpill,footer .numpill{background:var(--dark-2);border-color:var(--dark-line);color:var(--cta-light)}

/* C2 · seal — a circular CREDENTIAL mark, sized to straddle a band seam.
   Deliberately NOT a rating badge: the sources put "4.5 (1,200 reviews)" in this
   slot, and a rating may only appear if it is real, attributable and evidenced. */
.seal{width:clamp(120px,12vw,148px);height:clamp(120px,12vw,148px);border-radius:50%;
  background:var(--cta);color:#fff;display:grid;place-content:center;justify-items:center;
  gap:3px;text-align:center;padding:12px;border:6px solid var(--surface)}
.seal svg{width:25px;height:25px;stroke:currentColor}
.seal b{font-size:12.5px;font-weight:800;line-height:1.15}
/* opacity:.92 white over copper blends to #f9f1ed = 4.35:1 — under AA for 11px text, and
   axe flags every seal on the page. Same trap the .callbtn .cap comment names: never dim
   text on the accent fill to "soften" it. Full white is 4.86:1. */
.seal i{font-style:normal;font-size:11px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase}
.seal--on-dark{border-color:var(--dark)}
.seal--primary{background:var(--primary)}

/* C3 · caption chip welded to an image corner — one widget, two content types
   (a Stadtteil on a job photo, a date on an article), which is where a gallery
   and a blog grid start reading as one family. */
.capchip{position:absolute;left:0;bottom:0;z-index:2;background:var(--surface);color:var(--head);
  padding:9px 15px;font-size:14px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  border-radius:0 var(--r-sm) 0 0;max-width:calc(100% - 22px)}
.capchip--cta{background:var(--cta);color:#fff}
.capchip--tr{left:auto;right:0;bottom:auto;top:0;border-radius:0 0 0 var(--r-sm)}

/* C4 · avatar cluster ending in a quote mark — the only social-proof widget in
   the whole corpus that carries zero numbers and zero stars, which is why it is
   the one that ports into a German trade site untouched. */
.avatars{display:flex;align-items:center;flex-wrap:wrap}
.avatars img,.avatars .avatars__q{width:56px;height:56px;border-radius:50%;object-fit:cover;
  border:3px solid var(--surface);flex:none}
.avatars>*+*{margin-left:-15px}
.avatars__q{background:var(--cta);color:#fff;display:grid;place-items:center}
.avatars__q svg{width:22px;height:22px}.section--dark .avatars img,.on-dark .avatars img,footer .avatars img,.section--dark .avatars .avatars__q,.on-dark .avatars .avatars__q,footer .avatars .avatars__q{border-color:var(--dark)}

/* C5 · quote card — a speech card with a tail. No stars, no counts, no rating. */
.quote{position:relative;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r);padding:clamp(22px,2.4vw,30px)}
.quote p{font-size:17.2px;line-height:1.62;color:var(--text)}
.quote__by{margin-top:16px;padding-top:14px;border-top:1px solid var(--line);
  font-size:14px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--cta-ink)}.section--dark .quote,.on-dark .quote,footer .quote{background:var(--dark-2);border-color:var(--dark-line)}.section--dark .quote p,.on-dark .quote p,footer .quote p{color:var(--on-dark)}.section--dark .quote__by,.on-dark .quote__by,footer .quote__by{color:var(--cta-light);border-top-color:var(--dark-line)}

/* C6 · flanked hairline — centred text with two rules growing to fill the row.
   Three declarations, and nothing like the usual border-top. */
.hrule{display:flex;align-items:center;gap:18px;font-size:14px;font-weight:800;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.hrule::before,.hrule::after{content:"";flex:1;height:1px;background:var(--line)}
/* the LABEL needs the dark-band colour too, not only the two rules — --muted on --dark
   is 2.49:1. Every widget below that paints text in --muted needs the same partner rule. */.section--dark .hrule,.on-dark .hrule,footer .hrule{color:var(--dark-muted)}.section--dark .hrule::before,.on-dark .hrule::before,footer .hrule::before,.section--dark .hrule::after,.on-dark .hrule::after,footer .hrule::after{background:var(--dark-line)}

/* C7 · colophon chip — a bordered circle holding one letter, beside a name.
   Pure editorial garnish; the right home for a Meister/Innung mark in a hero. */
.colophon{display:inline-flex;align-items:center;gap:10px;font-size:12.5px;font-weight:700;
  letter-spacing:.05em;color:var(--muted)}
.colophon i{font-style:normal;width:22px;height:22px;flex:none;border-radius:50%;
  border:1.6px solid var(--line-strong);display:grid;place-items:center;
  font:800 11px/1 var(--f-num);color:var(--primary)}.section--dark .colophon,.on-dark .colophon,footer .colophon{color:var(--dark-muted)}.section--dark .colophon i,.on-dark .colophon i,footer .colophon i{border-color:var(--dark-line);color:var(--cta-light)}

/* C8 · double-framed card — an outer tinted frame at 10px padding with an inner
   hairline. Two rules, and every card stops looking flat. */
.framed{background:var(--surface-alt);border-radius:var(--r-lg);padding:10px}
.framed__in{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:clamp(20px,2.2vw,28px);height:100%}.section--dark .framed,.on-dark .framed,footer .framed{background:var(--dark-3)}.section--dark .framed__in,.on-dark .framed__in,footer .framed__in{background:var(--dark-2);border-color:var(--dark-line)}

/* C9 · expanding hover pill — an arrow square at rest that grows into a labelled
   button. max-width (not width) so there is no layout shift. */
.hpill{display:inline-flex;align-items:center;gap:0;min-height:var(--tap);
  border-radius:var(--pill);background:var(--primary);color:#fff;text-decoration:none;
  padding:6px;overflow:hidden}
.hpill__ic{width:32px;height:32px;flex:none;display:grid;place-items:center}
.hpill__ic svg{width:18px;height:18px;stroke:currentColor}
.hpill__t{max-width:0;opacity:0;white-space:nowrap;overflow:hidden;font-weight:700;font-size:16px;
  transition:max-width .34s var(--ease),opacity .28s var(--ease),padding .34s var(--ease);padding:0}
.hpill:hover,.hpill:focus-visible{color:#fff;background:var(--cta)}
.hpill:hover .hpill__t,.hpill:focus-visible .hpill__t{max-width:16rem;opacity:1;padding:0 12px 0 4px}

/* C10 · eyebrow variant D — a bordered chip with a solid accent disc flush in
   its left cap. Gives a section a coloured anchor without a coloured band. */
.eyebrow--cap{border:1.5px solid var(--line);border-radius:var(--pill);
  padding:4px 16px 4px 4px;color:var(--primary);letter-spacing:.11em;gap:11px}
.eyebrow--cap::before{width:28px;height:28px;border-radius:50%;background:var(--cta);
  clip-path:none}.section--dark .eyebrow--cap,.on-dark .eyebrow--cap,footer .eyebrow--cap{border-color:var(--dark-line);color:#fff}

/* C11 · crushed numeral — one deliberate break in the type system. A token-driven
   design with no exceptions reads machine-made; exactly one exception reads
   art-directed. Use it ONCE per page, never twice.
   THE NUMERAL IS DECORATION, AND THE MARKUP HAS TO SAY SO. At --line it carries
   1.41:1 (--dark-4 on --dark: 1.33:1) and could never clear AA as text — 3:1 is the
   floor even for display sizes. So the digits are passed in `data-n` and painted by the
   pseudo-element, the same move .timeline already makes for its step counters: a graphic
   in numeral form, not text a reader must decipher. Meaning belongs in the heading
   beside it. Written as <span class="bignum" data-n="01" aria-hidden="true"></span>. */
.bignum{font-size:clamp(56px,8vw,104px);font-weight:800;line-height:.72;letter-spacing:-.04em;
  color:var(--line);font-variant-numeric:tabular-nums;display:block}
.bignum::before{content:attr(data-n)}
.bignum--cta{color:var(--cta)}.section--dark .bignum,.on-dark .bignum,footer .bignum{color:var(--dark-4)}

/* C12 · hours rows — opening times as a real record, not a paragraph. */
.hours{list-style:none;display:grid;gap:0}
.hours li{display:flex;justify-content:space-between;gap:18px;padding:12px 0;
  border-bottom:1px solid var(--line);font-size:16.8px}
.hours li:last-child{border-bottom:0}
.hours b{color:var(--head);font-weight:700}
.hours span{color:var(--muted);text-align:right}.section--dark .hours li,.on-dark .hours li,footer .hours li{border-bottom-color:var(--dark-line)}.section--dark .hours b,.on-dark .hours b,footer .hours b{color:#fff}.section--dark .hours span,.on-dark .hours span,footer .hours span{color:var(--dark-muted)}

/* C13 · breadcrumbs */
.crumbs{list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;font-size:15.5px}
.crumbs li{display:inline-flex;align-items:center;gap:4px;color:var(--muted)}
.crumbs li+li::before{content:"";width:6px;height:6px;flex:none;border-right:1.5px solid var(--line-strong);
  border-top:1.5px solid var(--line-strong);rotate:45deg;margin-right:4px}
.crumbs a{display:inline-flex;align-items:center;min-height:var(--tap);min-width:var(--tap);
  color:var(--muted);text-decoration:none}
.crumbs a:hover{color:var(--cta-ink);text-decoration:underline}
.crumbs [aria-current="page"]{color:var(--head);font-weight:700}

/* C14 · in-page index — the sticky rail's table of contents. */
.toc{list-style:none;display:grid;gap:2px;border-left:2px solid var(--line)}
.toc a{display:flex;align-items:center;min-height:var(--tap);padding:6px 0 6px 16px;
  margin-left:-2px;border-left:2px solid transparent;color:var(--muted);text-decoration:none;
  font-size:16.5px;transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease)}
.toc a:hover,.toc a[aria-current="true"]{color:var(--primary);border-left-color:var(--cta);
  font-weight:700}

/* C15 · tab switcher — buttons with the real roles. The sources build this from
   radio inputs; any <input> is a hard validator fail, and site.js already wires
   [data-switcher] with roving focus. */
.tabs{display:grid;gap:clamp(24px,3vw,44px);grid-template-columns:minmax(0,1fr);align-items:start}
@media(min-width:900px){.tabs{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.tabs__list{display:grid;gap:0;list-style:none}
/* The source dims the inactive tab with opacity:.45. That cannot be rescued: --muted at
   .45 over white is 2.07:1, and even at .9 it is still 4.63:1 on --steel — an opacity
   veil scales the CONTRAST down along with the colour, so no value both dims visibly and
   clears AA on every band this style ships. The inactive state is therefore carried by
   colour and border, the way the rest of the style carries state. */
.tabs__btn{display:block;width:100%;text-align:left;background:none;border:0;cursor:pointer;
  padding:18px 0;border-bottom:1px solid var(--line);color:inherit;font:inherit;
  min-height:var(--tap);transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease)}
.tabs__btn:hover{border-bottom-color:var(--line-strong)}
.tabs__btn[aria-selected="true"]{border-bottom-color:var(--cta);border-bottom-width:2px}
.tabs__btn b{display:block;font-size:clamp(18px,1.5vw,21px);font-weight:700;color:var(--muted);
  margin-bottom:5px;transition:color var(--dur) var(--ease)}
.tabs__btn:hover b,.tabs__btn[aria-selected="true"] b{color:var(--head)}
.tabs__btn span{display:block;font-size:16.4px;color:var(--muted);line-height:1.55}.section--dark .tabs__btn b,.on-dark .tabs__btn b,footer .tabs__btn b,.section--dark .tabs__btn span,.on-dark .tabs__btn span,footer .tabs__btn span{color:var(--dark-muted)}.section--dark .tabs__btn:hover b,.on-dark .tabs__btn:hover b,footer .tabs__btn:hover b,.section--dark .tabs__btn[aria-selected="true"] b,.on-dark .tabs__btn[aria-selected="true"] b,footer .tabs__btn[aria-selected="true"] b{color:#fff}
.tabs__panel[hidden]{display:none}

/* C16 · FAQ accordion — native <details>, so it works with JS off; site.js only
   adds the one-open-at-a-time behaviour. */
.faq{display:grid;gap:12px}
.faq details{border:1px solid var(--line-strong);border-radius:var(--r-sm);
  background:var(--surface);overflow:hidden}
.faq summary{display:flex;align-items:center;gap:14px;justify-content:space-between;
  padding:18px clamp(16px,2vw,24px);min-height:var(--tap);cursor:pointer;list-style:none;
  font-size:clamp(17px,1.4vw,19.5px);font-weight:700;color:var(--head)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"";width:12px;height:12px;flex:none;
  border-right:2px solid var(--cta);border-bottom:2px solid var(--cta);rotate:45deg;
  translate:0 -3px;transition:rotate var(--dur) var(--ease)}
.faq details[open] summary::after{rotate:-135deg;translate:0 3px}
.faq details[open]{border-color:var(--cta)}
.faq__a{padding:0 clamp(16px,2vw,24px) 20px;color:var(--muted);font-size:17px;line-height:1.62}.section--dark .faq details,.on-dark .faq details,footer .faq details{background:var(--dark-2);border-color:var(--dark-line)}.section--dark .faq summary,.on-dark .faq summary,footer .faq summary{color:#fff}.section--dark .faq summary::after,.on-dark .faq summary::after,footer .faq summary::after{border-color:var(--cta-light)}

/* C17 · check / icon list — the default treatment for factors, symptoms and
   benefits. Never a <ul> with the bullets deleted. */
.iclist{list-style:none;display:grid;gap:clamp(14px,1.7vw,22px)}
.iclist--2{grid-template-columns:minmax(0,1fr)}
@media(min-width:700px){.iclist--2{grid-template-columns:repeat(2,minmax(0,1fr))}}
.iclist li{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:start}
.iclist__ic{width:34px;height:34px;flex:none;border-radius:50%;display:grid;place-items:center;
  background:var(--primary-subtle);color:var(--primary)}
.iclist__ic svg{width:18px;height:18px;stroke:currentColor;stroke-width:2.2}
.iclist--cta .iclist__ic{background:var(--cta);color:#fff}
.iclist b{display:block;color:var(--head);font-weight:700;font-size:17.5px;margin-bottom:3px}
.iclist p{font-size:16.6px;color:var(--muted);line-height:1.55}.section--dark .iclist__ic,.on-dark .iclist__ic,footer .iclist__ic{background:var(--dark-3);color:var(--cta-light)}.section--dark .iclist b,.on-dark .iclist b,footer .iclist b{color:#fff}.section--dark .iclist p,.on-dark .iclist p,footer .iclist p{color:var(--dark-muted)}

/* C18 · media frame — an image with the notch, a seam badge slot and a caption
   chip, so a photo is a composed object rather than a rectangle. */
.frame{position:relative}
.frame__seal{position:absolute;left:50%;bottom:0;translate:-50% 50%;z-index:3}
.frame__seal--r{left:auto;right:clamp(16px,4vw,54px);translate:0 50%}


    /* .reveal starts at opacity:0 and only site.js adds .in — without scripting most of
       the page would simply not exist. Progressive enhancement, not decoration. */
    .reveal{opacity:1!important;transform:none!important}
    .wipe{clip-path:none!important}

/* ==========================================================================
   HAERTESCHICHT + DRESDNER ERWEITERUNG
   Wird von tools/build-theme-css.mjs an die uebernommene Designsprache angehaengt.

   Teil 1  Farbige Gruende und ihre Tinte      (die Klasse Fehler, die kein Test sieht)
   Teil 2  Naht-Sicherheit
   Teil 3  Geometrie, Tap-Targets, schmale Viewports
   Teil 4  Chrome-Korrekturen
   Teil 5  Hero-Varianten (die 7 Familien aus dem SECTION-PLAN)
   Teil 6  Behandlungen, die der SECTION-PLAN verlangt und die Referenz nicht kennt
   ========================================================================== */

/* ==========================================================================
   TEIL 1 - FARBIGE GRUENDE UND IHRE TINTE

   Die uebernommene Sprache faerbt innerhalb von `.section--dark` bereits
   gruendlich um. Dieser Build fuehrt weitere farbige Gruende ein, die sie nicht
   kennt. Statt hier eine zweite, parallel zu pflegende Liste zu fuehren, weitet
   der Generator jede `.section--dark <Nachfahre>`-Regel auf `.on-dark` und
   `footer` aus (tools/build-theme-css.mjs, Schritt 5b) - dieselbe, bereits
   durchgemessene Behandlung, an einer Stelle gepflegt.

   Hier bleibt nur, was daraus NICHT folgt.
   ========================================================================== */

/* Die DREI Tintentokens auf jedem dunklen Grund umhaengen.
   Die geerbten Regeln decken alles ab, was die Sprache selbst kennt. Sie decken
   NICHT ab, was dieser Build hinzufuegt: `.timeline > li p{color:var(--muted)}`
   ist (0,1,1) und schlaegt die geerbte Bandfarbe - gemessen 1.98:1 auf vier
   Absaetzen des Signaturbandes. Eine Regel je Primitiv nachzuziehen ist ein
   Wettlauf, den man verliert, sobald ein Primitiv dazukommt.
   Umgehaengt werden nur die TINTEN, nie die Fuellungen: --surface umzuhaengen
   faerbte den weissen Anruf-Button auf dunklem Band mit ein. */
.section--dark, .on-dark, footer {
  --text:  var(--on-dark);
  --muted: var(--dark-muted);
  --head:  #ffffff;
  /* Kupfer als TEXT kippt auf dunklem Grund mit: die helle Form steht dort mit
     2.35:1. Ein Token statt einer Regel je Komponente — sonst faellt jede neue
     Komponente, die var(--cta-ink) benutzt, dieselbe Falle hinunter. */
  --cta-ink: var(--cta-light);
  /* Das `color` MUSS mit. Ein Token umzuhaengen aendert nur, was Regeln AUF oder
     UNTER diesem Element aufloesen - `body{color:var(--text)}` ist laengst berechnet,
     und ein <p> ohne eigene Farbregel erbt diesen fertigen Wert bis nach unten
     durch. Gemessen: 1.08:1 in einem dunklen Telefonblock, dessen Tokens korrekt
     umgehaengt waren. Der Hintergrund bleibt unberuehrt - sonst wuerde das
     Ockerpaneel schwarz. */
  color: var(--text);
}

/* Und die Gegenrichtung: ein Baustein, der seine EIGENE helle Flaeche malt,
   liegt zwar in einem dunklen Band, ist aber kein dunkler Grund. Er holt sich
   die hellen Tinten zurueck, sonst steht sein Text hell auf hell. */
.light-island, .callbtn--dark, .notice, .compare, .phoneblock:not(.phoneblock--dark) {
  --text:    #241c11;
  --muted:   #544632;
  --head:    #1a130a;
  --cta-ink: #94320f;
}

/* Eine helle Insel auf dunklem Grund bekommt ihre Tinte ZURUECK - und zwar als
   Regel, nicht nur als Token. Die geerbte Behandlung setzt `color:#fff` auf jede
   Ueberschrift unter `.on-dark` als LITERALEN Wert; ein umgehaengtes Token kann das
   nicht aufheben. Gemessen: 1:1, weisse Ueberschrift auf weisser Karte.
   `:is()` nimmt die Spezifitaet seines staerksten Arguments - die Kette liegt damit
   ueber der geerbten (0,1,1)-Regel und gewinnt. */
:is(.section--dark, .on-dark, footer)
  :is(.light-island, .notice, .compare, .compare__side, .callbtn--dark, .phoneblock:not(.phoneblock--dark)) {
  color: var(--text);
}
:is(.section--dark, .on-dark, footer)
  :is(.light-island, .notice, .compare, .compare__side, .callbtn--dark, .phoneblock:not(.phoneblock--dark))
  :is(h1, h2, h3, h4, .h3, .stitle, strong, b, dt) { color: var(--head); }
:is(.section--dark, .on-dark, footer)
  :is(.light-island, .notice, .compare, .compare__side, .callbtn--dark, .phoneblock:not(.phoneblock--dark))
  :is(p, li, dd, .lead, .small, figcaption, .ticks li) { color: var(--muted); }
:is(.section--dark, .on-dark, footer)
  :is(.light-island, .notice, .compare, .compare__side, .callbtn--dark, .phoneblock:not(.phoneblock--dark))
  a:not(:where(.btn, .callbtn, .calltab, .chip, .brand, .ftel, .telbig)) { color: var(--cta-ink); }
:is(.section--dark, .on-dark, footer)
  :is(.light-island, .notice, .compare, .compare__side, .callbtn--dark, .phoneblock:not(.phoneblock--dark))
  :is(a, button, summary, [tabindex]):focus-visible {
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 6px var(--focus);
}
/* Die Notiz behaelt ihre Signalfarbe auch dort. */
:is(.section--dark, .on-dark, footer) .notice :is(h2, h3, .h3) { color: var(--danger); }
:is(.section--dark, .on-dark, footer) .notice--info :is(h2, h3, .h3) { color: var(--cta-ink); }

/* Der Bronzegrund ist heller als der fast schwarze. Die Referenz setzt Fliesstext
   auf dunklem Grund als --dark-muted; auf #6b4a18 sind das gemessen 4.27:1 und
   damit unter AA. Auf diesem Grund wird das Token einmal umgehaengt - danach
   stimmt jede geerbte Regel automatisch (5.93:1). Ebenso ruecken die
   Flaechentoene ins Bronze, sonst sitzt eine fast schwarze Karte auf Ocker. */
.on-bronze {
  --dark-muted: #eadcc4;   /* 5.93:1 auf #6b4a18 */
  --dark-2:     #55380f;
  --dark-3:     #5f4113;
  --dark-4:     #6f4f1c;
  --dark-line:  #8a6120;
  --dark-line-2:#a1742c;
  --dark:       #6b4a18;   /* damit .btn--ghost:hover seine Textfarbe vom Grund nimmt */
}

/* Eine bewusst HELLE Insel auf einem farbigen Grund. Die geerbten Dunkelregeln
   reichen sonst in sie hinein: eine weiss gefuellte Karte im Ockerhero behielt
   `a{color:var(--cta-light)}` und stand mit 2.17:1 auf ihrem eigenen Weiss.
   Eine Insel haengt ihre Tokens schlicht zurueck. */
.light-island {
  --dark-muted:  #544632;
  --on-dark:     #241c11;
  --cta-light:   #94320f;
  --dark-2:      #ffffff;
  --dark-3:      #f2ede4;
  --dark-line:   #dcd2c0;
  --dark-line-2: #7e6c50;
  --dark:        #ffffff;
  color: var(--text);
}
.light-island :where(h1, h2, h3, h4, .h3, strong, b, dt) { color: var(--head); }
.light-island :where(p, li, dd, .lead, .small, figcaption) { color: var(--muted); }
.light-island :where(a, button, summary, [tabindex]):focus-visible {
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 6px var(--focus);
}

/* Die Notiz behaelt auf JEDEM Grund ihre eigene Signalfarbe - sie ist eine
   Warnung, keine Bandvariante. */
.notice { color: var(--text); }
.notice :where(p, li) { color: var(--muted); }
.notice :where(h2, h3, .h3) { color: var(--danger); }
.notice--info :where(h2, h3, .h3) { color: var(--cta-ink); }

/* Auf der Akzentflaeche nie ausduennen: Weiss bei opacity .86 ueber Kupfer mischt
   zu #f5e7df = 4.02:1 und faellt unter AA. Die Kappen bleiben volles Weiss. */
.keypad--cta > *, .strip li, .btn--cta { opacity: 1; }
.keypad--cta > * :where(p, li, .small) { color: #fff; }

/* Die Wortmarke traegt ihren Untertitel in einem verschachtelten span; die
   Referenz erwartet dort eine andere Verschachtelung, also hier ausdruecklich. */
.brand b span { color: var(--muted); }
.brand--foot b { color: #fff; }
.brand--foot b span { color: var(--dark-muted); }

/* ==========================================================================
   TEIL 2 · NAHT-SICHERHEIT
   ========================================================================== */

/* Ein `.seam-up` als erstes Kind wird vom eigenen Innenabstand des empfangenden
   Bandes aufgefressen: der Zug ist 54px, `padding-top` bis 104px. Das als Klasse
   zu verlangen heisst, dass ihr Vergessen die Ueberlappung lautlos toetet — also
   greift es automatisch. */
.section:has(> .wrap > .seam-up:first-child),
.section:has(> .seam-up:first-child) { padding-top: 0; }

/* MARGIN COLLAPSE — der Fehler, der zwei Pruefrunden ueberstanden hat. Mit
   padding-top:0 kollabiert der negative margin-top des Kindes DURCH das Elternteil:
   das ganze Band wandert hoch, seine Hintergrundkante (die Naht, die ein Leser
   sieht) reist mit, und nichts kreuzt. Nur dort sah es richtig aus, wo das
   empfangende Band transparent war. Gemessen: -18px -> +64px. */
.section:has(> .wrap > .seam-up:first-child),
.section:has(> .seam-up:first-child),
.section--hang, .section--catch { display: flow-root; }

/* Eine Naht darf nur an einem KOPFLOSEN Objekt kreuzen: das kreuzende Element muss
   erstes Kind sein, ein sichtbarer Abschnittskopf landet dann entweder unter dem
   Block, den er einleitet, oder wird auf den fremden Grund gezogen. Ein
   `.vh`-Titel im kreuzenden Wrapper ist erlaubt — er ist position:absolute, also
   ausserhalb des Flusses. */
.seam-up > .shead:not(.shead--vh), .seam-down > .shead:not(.shead--vh) { outline: 2px dashed var(--danger); }

/* ==========================================================================
   TEIL 3 · GEOMETRIE, TAP-TARGETS, SCHMALE VIEWPORTS
   ========================================================================== */

/* `1fr` und `auto` nehmen ein min-content-Minimum an: ein deutsches Kompositum
   (Zentralschliessanlage, Einbruchschadenreparatur) setzt dann die Mindestbreite
   des Dokuments und die ganze Seite scrollt bei 320px horizontal. */
.grid > *, .split > *, .rail > *, .offgrid > *, .mosaic > *, .compare > *,
.diptych > *, .keypad > *, .stats > *, .ledger__row > * { min-width: 0; }
body { overflow-wrap: break-word; }
p, li, td, th, figcaption, summary, dd, dt { hyphens: auto; }

/* Ein `white-space:nowrap`-Button setzt mit langem Label die Mindest-Layoutbreite
   der Seite: gemessen erzwang das einen Layout-Viewport von 376px auf einem
   320px-Geraet. Der Tell ist `innerWidth !== clientWidth`, nicht scrollWidth. */
@media (max-width: 420px) {
  .btn, .callbtn, .calltab { white-space: normal; padding-inline: 16px; }
  .callbtn span, .calltab span { min-width: 0; }
}

/* Ein `tel:`-Ziel wird gemessen. Die grosse Displaynummer und die Fusszeilennummer
   sind ~30px hoch, wie gross die Ziffern auch aussehen. */
a[href^="tel:"] { min-height: var(--tap); }
.telbig, .ftel { display: inline-flex; align-items: center; min-height: var(--tap); }
/* Attributselektoren sind (0,1,1) und schlagen eine schlichte Klassenregel (0,1,0).
   Ohne die Ausnahme unten hat genau diese Zeile schon einmal `.navcall{display:none}`
   wiederbelebt und den Burger auf jedem Telefon aus dem Bild geschoben. */
a[href^="tel:"]:not(:where(.navcall, .callbar a, .telbig, .ftel, .calltab)) { display: inline-flex; align-items: center; }
@media (max-width: 1119px) { .navcall { display: none; } }

/* Kurze Labels in einer Breadcrumb-nav werden ebenfalls als Tap-Target gemessen —
   min-height allein reicht nicht, "Start" ist 36px breit. */
.crumbs a, .crumbs span { min-height: var(--tap); min-width: 44px; display: inline-flex; align-items: center; }

/* Ein Flex-Kind schrumpft per Default nicht unter min-content. Die Marke hat so
   das Layout auf 383px in einem 360px-Viewport gedrueckt und den Burger mitgenommen. */
.navrow { min-width: 0; }
.brand { min-width: 0; flex: 0 1 auto; }
.brand b, .brand span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.burger, .navcall { flex: 0 0 auto; }

/* Vollflaechige Baender brauchen trotzdem seitlichen Innenabstand. */
.strip { padding-inline: var(--gut); }

/* `height:100%` in einer Box ohne eigene Hoehe kollabiert auf 0 — das Bild ist
   dann schlicht unsichtbar und nichts meldet es. */
.imgph img, .media img { height: auto; }
.imgph { overflow: hidden; }
.imgph.ratio-16x9 img, .imgph.ratio-4x3 img, .imgph.ratio-1x1 img,
.imgph.ratio-3x4 img, .imgph.ratio-3x2 img { height: 100%; }

/* Ein eigener Scroller braucht eine Tastaturaufnahme, sonst faellt axe mit
   `scrollable-region-focusable` (serious). */
.peek { scrollbar-gutter: stable; }

/* ==========================================================================
   TEIL 4 · CHROME-KORREKTUREN
   ========================================================================== */

/* Wenn ein Umschalter auf zwei Wegen gefahren werden kann, gewinnt keiner.
   Das Menue haengt AUSSCHLIESSLICH am `hidden`-Attribut: die Links sind
   geschlossen wirklich ausserhalb der Tab-Reihenfolge, und das Entfernen des
   Attributs oeffnet die Box tatsaechlich, statt nur ein Attribut zu kippen. */
.mobmenu { display: block; }
.mobmenu[hidden] { display: none; }

/* Der Scroll-nach-oben-Knopf schwebt ueber JEDEM Band, also traegt kein einzelner
   Ringfarbwert. Ein Doppelring: was auch darunter liegt, eine Lage kontrastiert. */
.totop:focus-visible { outline: none; box-shadow: 0 0 0 3px #fff, 0 0 0 6px var(--focus); }
.callbar a:focus-visible { outline: none; box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 6px var(--dark); }

/* Die Rufleiste lebt IM footer-Container, damit die Klongrenze sie mit der Chrome
   abschneidet statt sie als geteilten Fliesstext gegen 38 Geschwisterseiten zu zaehlen. */
.callbar { contain: layout; }

/* Untermenue: eine Ausklappung wird allein von aria-expanded gefahren.
   `:focus-within` am Container laesst sich von innen nicht aufheben — Escape gibt
   den Fokus an den Umschalter zurueck, der selbst im Container liegt, also kippt
   aria-expanded auf false und das Panel bleibt sichtbar. */
.nav__has { position: relative; }
.nav__toggle { display: inline-flex; align-items: center; gap: 7px; min-height: var(--tap);
  padding: 0 11px; border: 0; background: none; font: 600 16.5px/1 var(--f); color: var(--text);
  cursor: pointer; border-radius: var(--r-sm); }
.nav__toggle:hover { color: var(--primary); background: var(--primary-subtle); }
.nav__toggle svg { width: 15px; height: 15px; transition: transform var(--dur) var(--ease); }
.nav__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.submenu { position: absolute; top: 100%; left: 0; z-index: 200; min-width: 268px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--sh-lg); padding: 7px; list-style: none; }
.nav__toggle[aria-expanded="false"] + .submenu { display: none; }
.submenu a { display: flex; align-items: center; min-height: var(--tap); padding: 0 13px;
  font-size: 16.5px; font-weight: 600; color: var(--text); text-decoration: none; border-radius: var(--r-sm); }
.submenu a:hover, .submenu a[aria-current="page"] { background: var(--primary-subtle); color: var(--primary); }

/* Eine geschlossene Off-Canvas-Flaeche darf ihre Links nicht fokussierbar lassen —
   `aria-hidden` auf fokussierbaren Kindern ist der axe-SERIOUS `aria-hidden-focus`.
   `visibility:hidden` nimmt sie wirklich aus der Reihenfolge; visibility NIE
   animieren, sonst landet ein Fokus beim Oeffnen auf einem noch versteckten Ziel. */
.mobmenu[hidden] { visibility: hidden; }

/* ==========================================================================
   TEIL 5 · HERO-VARIANTEN
   Sieben Familien, weil der SECTION-PLAN sieben verlangt. Sie unterscheiden sich
   in Grund und Rhythmus, nicht in der Sprache.
   ========================================================================== */
.hero { position: relative; padding-block: clamp(46px, 6vw, 92px); }
.hero .wrap { position: relative; z-index: 2; }
.hero__grid { display: grid; gap: clamp(26px, 3.4vw, 52px); grid-template-columns: minmax(0, 1fr); align-items: center; }
@media (min-width: 960px) { .hero__grid--media { grid-template-columns: minmax(0, 1.06fr) minmax(0, .94fr); } }
.hero__copy > * + * { margin-top: 18px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-top: 26px; }

/* A · dunkles Vollbild-Band mit Zweispalten-Kontrast (home, service/tueroeffnung) */
.hero--dark { background: var(--dark); }
.hero--dark::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 88% at 82% 8%, rgba(178, 60, 18, .17), transparent 62%); }
.duo { display: grid; gap: 1px; background: var(--dark-line); border: 1px solid var(--dark-line); margin-top: clamp(26px, 3vw, 42px); }
@media (min-width: 820px) { .duo { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.duo__side { background: var(--dark-2); padding: clamp(22px, 2.6vw, 34px); }
.duo__tag { display: inline-flex; align-items: center; gap: 9px; font: 800 12.5px/1 var(--f);
  letter-spacing: .14em; text-transform: uppercase; color: var(--cta-light); margin-bottom: 12px; }
.duo__side p { color: var(--dark-muted); font-size: 16.8px; }

/* B · Notfall-Leiste: die Nummer IST die Leiste (notdienst, problem/*) */
.hero--emergency { background: var(--dark); }
.hero--emergency .emgbar { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 26px;
  margin-top: 24px; padding: clamp(18px, 2vw, 26px); background: var(--dark-2);
  border: 1px solid var(--dark-line); border-left: 5px solid var(--cta); }
.hero--emergency .emgbar__note { color: var(--dark-muted); font-size: 16.5px; max-width: 46ch; }
.hero--calm { background: var(--dark-2); }

/* C · dunkle Alarmplatte, dunkler als alles andere (problem/schluessel-steckt-innen,
       service/einbruchschaden-reparatur) */
.hero--situation { background: var(--dark); }
.hero--situation::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(163, 32, 23, .20), transparent 46%); }
.hero--slab { background: var(--dark-2); border-bottom: 5px solid var(--cta); }

/* D · massives Ockerpaneel, kein Foto (preise, faq, glossar, ratgeber-Artikel)
       Auf diesem Grund traegt die Rufnummer als .telbig — nie als CTA-Flaeche. */
.hero--panel { background: var(--primary); }
.hero--panel::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: .5;
  background: repeating-linear-gradient(90deg, rgba(255, 255, 255, .05) 0 1px, transparent 1px 16px); }
.hero--panel .telbig { color: #fff; }
.hero--panel .telbig svg { stroke: var(--cta-light); }
.hero--panel .telbig:hover { color: var(--cta-light); }

/* E · ruhiger Split, textgefuehrt (ueber-uns, ratgeber, service/schliessanlage) */
.hero--split { background: var(--surface); border-bottom: 1px solid var(--line); }
.hero--split .hero__rail { border-left: 3px solid var(--cta); padding-left: clamp(18px, 2vw, 28px); }

/* F · kompakter Hero ueber einer Kartenreihe (leistungen, service/einbruchschutz) */
.hero--compact { background: var(--surface-alt); padding-block: clamp(38px, 4.4vw, 64px); }

/* G · lokaler Kontext — jede Stadtteil- und Kombiseite (12 + 3) */
.hero--local { background: var(--steel); border-bottom: 1px solid var(--line); }
.hero--local .hero__ctx { margin-top: 20px; padding: clamp(16px, 1.8vw, 22px) clamp(18px, 2vw, 26px);
  background: var(--surface); border: 1px solid var(--line); border-left: 4px solid var(--primary); }
.hero--local .hero__ctx p { color: var(--muted); font-size: 17px; margin: 0; }

/* Eine Sprungleiste unter einem Paneel-Hero (faq, glossar) */
.jumps { display: flex; flex-wrap: wrap; gap: 9px; list-style: none; margin-top: 24px; }
.jumps a { display: inline-flex; align-items: center; min-height: var(--tap); padding: 8px 15px;
  border-radius: var(--pill); font-size: 16px; font-weight: 700; text-decoration: none; }

/* ==========================================================================
   TEIL 6 · BEHANDLUNGEN, DIE DER SECTION-PLAN VERLANGT
   ========================================================================== */

/* phone-block — die kostenlose, unverbindliche telefonische Beratung als eigener
   Abschnitt. Kopflos gebaut, also das beste Objekt fuer eine Naht, und das eine,
   das man angetippt haben will. NIE ein Formular. */
.phoneblock { display: grid; gap: clamp(20px, 2.4vw, 34px); align-items: center;
  padding: clamp(24px, 3vw, 40px); background: var(--surface); border: 1px solid var(--line);
  border-top: 4px solid var(--cta); box-shadow: var(--sh); }
@media (min-width: 900px) { .phoneblock { grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr); } }
.phoneblock--dark { background: var(--dark); border-color: var(--dark-line); border-top-color: var(--cta); }
.phoneblock__note { font-size: 16.5px; color: var(--muted); margin-top: 12px; }
.phoneblock--dark .phoneblock__note { color: var(--dark-muted); }
.phoneblock__act { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
@media (min-width: 900px) { .phoneblock__act { align-items: flex-end; text-align: right; } }

/* cta-band — das schliessende Band jeder Seite */
.ctaband { background: var(--dark); padding-block: clamp(44px, 5.4vw, 78px); position: relative; }
.ctaband::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(90% 130% at 12% 100%, rgba(178, 60, 18, .20), transparent 60%); }
.ctaband .wrap { position: relative; z-index: 2; }
.ctaband__grid { display: grid; gap: clamp(22px, 2.6vw, 38px); align-items: center; }
@media (min-width: 900px) { .ctaband__grid { grid-template-columns: minmax(0, 1fr) auto; } }

/* trust-strip — nur Belegbares, nie eine Zahl, nie ein Stern */
.truststrip { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (min-width: 700px) { .truststrip { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.truststrip > li { background: var(--surface); padding: clamp(18px, 2vw, 26px);
  display: flex; gap: 14px; align-items: flex-start; list-style: none; }
.truststrip b { display: block; color: var(--head); font-size: 17.5px; }
.truststrip span { display: block; color: var(--muted); font-size: 16.2px; line-height: 1.5; margin-top: 4px; }
.section--dark .truststrip { background: var(--dark-line); border-color: var(--dark-line); }
.section--dark .truststrip > li { background: var(--dark-2); }

/* usp-panel — die Haltung des Betriebs, als geripptes Kabinett statt als Karten */
.usp { border: 1px solid var(--line-strong); background: var(--surface); }
.usp__row { display: grid; gap: 14px clamp(20px, 2.4vw, 34px); padding: clamp(20px, 2.3vw, 30px);
  border-top: 1px solid var(--line); align-items: start; }
.usp__row:first-child { border-top: 0; }
@media (min-width: 780px) { .usp__row { grid-template-columns: 54px minmax(0, 1fr); } }
.usp__row b { display: block; color: var(--head); font-size: 18.5px; margin-bottom: 6px; }
.usp__row p { color: var(--muted); font-size: 16.8px; margin: 0; }

/* glossar-list — Begriff/Definition, ankerbar, in Gruppen */
.glist { border-top: 1px solid var(--line); }
.glist > div { border-bottom: 1px solid var(--line); padding: clamp(18px, 2.1vw, 26px) 0;
  display: grid; gap: 8px clamp(22px, 3vw, 46px); scroll-margin-top: 120px; }
@media (min-width: 820px) { .glist > div { grid-template-columns: minmax(0, .34fr) minmax(0, .66fr); } }
.glist dt { font-weight: 800; color: var(--head); font-size: 18.5px; }
.glist dd { margin: 0; color: var(--muted); font-size: 16.9px; line-height: 1.6; }
.glist dt small { display: block; font-size: 13.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--cta-ink); margin-top: 5px; }

/* prose-lead — der eine Absatz, der eine Frage sofort beantwortet */
.prose { max-width: 74ch; }
.prose > * + * { margin-top: 18px; }
.prose--lead { font-size: clamp(19px, 1.5vw, 22px); line-height: 1.6; color: var(--text);
  border-left: 4px solid var(--cta); padding-left: clamp(18px, 2vw, 28px); }
.prose--lead p { max-width: none; }

/* chip-cluster — gruppierte Chips mit einer Ueberschrift je Gruppe */
.cluster { display: grid; gap: clamp(20px, 2.4vw, 32px); }
@media (min-width: 760px) { .cluster { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.cluster__t { font: 800 13px/1 var(--f); letter-spacing: .14em; text-transform: uppercase;
  color: var(--cta-ink); margin-bottom: 12px; }

/* Bildunterschrift als sichtbarer Text — sie zaehlt gegen die Klongrenze fuer die
   Seite, ein alt-Attribut nicht (die Grenze liest body.text()). */
.figcap { margin-top: 10px; font-size: 15.6px; color: var(--muted); line-height: 1.5; }

/* Ohne JS ist die Seite vollstaendig; der Reveal ist nur Bewegung. */
.no-js .reveal { transform: none; }

/* ==========================================================================
   TEIL 7 · KLEINTEILE, DIE DIE BAUSTEINE AUSGEBEN
   ========================================================================== */
.split__copy > * + * { margin-top: 18px; }
.split__media { min-width: 0; }
.hero__media { min-width: 0; }
.figure { margin: 0; }

.ticks { list-style: none; display: grid; gap: 9px; margin-top: 14px; }
.ticks li { position: relative; padding-left: 26px; font-size: 16.8px; line-height: 1.55; color: var(--muted); }
.ticks li::before { content: ""; position: absolute; left: 0; top: .48em; width: 13px; height: 7px;
  border-left: 2px solid var(--cta); border-bottom: 2px solid var(--cta); rotate: -45deg; }

.card__go { margin-top: 14px; font-weight: 700; font-size: 16.5px; }
.card__go a { text-decoration: none; display: inline-flex; align-items: center; gap: 8px; min-height: 30px; }
.card__go a::after { content: ""; width: 15px; height: 9px; flex: none; background: currentColor;
  clip-path: polygon(0 38%, 62% 38%, 62% 0, 100% 50%, 62% 100%, 62% 62%, 0 62%);
  transition: translate var(--dur) var(--ease); }
.card__go a:hover::after { translate: 5px 0; }
.card .ibadge { margin-bottom: 15px; }

.chip--plain { cursor: default; color: var(--muted); }
.chip--plain:hover { border-color: var(--line); background: transparent; }

.iclist b { display: block; color: var(--head); font-size: 18px; line-height: 1.3; }
.iclist p { color: var(--muted); font-size: 16.8px; line-height: 1.55; margin-top: 5px; max-width: 56ch; }
.iclist p a { font-weight: 700; }

.duo__side b.h3 { display: block; color: #fff; margin-bottom: 7px; }
.timeline > li > b.h3, .stepper > li > b.h3 { display: block; margin-bottom: 7px; }
.timeline > li p, .stepper > li p { color: var(--muted); font-size: 16.9px; line-height: 1.6; }

.phoneblock h2 { margin-bottom: 10px; }
.phoneblock p { font-size: 17px; }
.ctaband .stitle { max-width: 22ch; }
.ctaband .lead { margin-top: 14px; max-width: 56ch; }

/* Die Sprungleiste liegt auf dem Ockerpaneel: dort ist die :not()-Kette der Basis
   entschaerft, also gewinnt diese Komponentenregel wieder. */
.hero--panel .jumps a { background: rgba(255, 255, 255, .10); border-color: rgba(255, 255, 255, .55); color: #fff; }
.hero--panel .jumps a:hover { background: #fff; color: var(--primary); border-color: #fff; }

/* Der Abschnittskopf im Split-Rhythmus stellt Titel und Lead nebeneinander. */
.shead > div { min-width: 0; }

/* ==========================================================================
   TEIL 8 · CHROME-KLEINTEILE DIESER SITE
   ========================================================================== */
.navbar { background: var(--surface); }
.mobmenu__sub a { padding-left: 22px; font-size: 16.5px; color: var(--muted); }
.mobmenu__sub a::before { content: ""; width: 10px; height: 1.5px; background: var(--cta);
  margin-right: 10px; flex: none; }

.fbrand p { color: var(--dark-muted); font-size: 16.4px; line-height: 1.6; margin: 16px 0 18px; max-width: 42ch; }
.fbrand .fmail { margin-top: 6px; font-size: 16.2px; }
.fbrand .fmail a { color: var(--dark-muted); text-decoration: underline; }
.fgrid--2 { margin-top: clamp(28px, 3vw, 40px); }
@media (min-width: 1020px) { .fgrid--2 { grid-template-columns: 1.4fr 1fr 1fr 1.1fr; } }
footer .h3 { color: #fff; font-size: 17px; letter-spacing: .09em; text-transform: uppercase; margin-bottom: 17px; }

/* Die Rufleiste ueberdeckt sonst den letzten Abschnitt. Der Wert steht als Token,
   weil ihn zwei Regeln brauchen: dieser Abstand und die Hoehe des offenen Menues. */
@media (max-width: 1119px) {
  :root { --callbar-space: 84px; }
  body { padding-bottom: var(--callbar-space); }
}
.section__after { margin-top: clamp(24px, 2.6vw, 34px); font-size: 17px; color: var(--muted); max-width: 62ch; }
.section__after a { font-weight: 700; }

/* Kurze Auszeichnungstexte nie trennen: `hyphens:auto` aus der Basis zerlegt sonst
   LINKSELBISCH in einer Pille und einen Stadtteilnamen in einem Chip. */
.chip, .eyebrow, .duo__tag, .cluster__t, .compare__tag, .capchip, .numpill,
.jumps a, .rows__n, .callbtn .cap, .calltab .cap { hyphens: manual; }
.cluster-wide { margin-top: clamp(28px, 3vw, 42px); padding-top: clamp(24px, 2.6vw, 34px); border-top: 1px solid var(--line); }

/* ==========================================================================
   TEIL 9 · TAP-TARGETS, DIE ERST DIE MESSUNG FINDET
   ========================================================================== */

/* Der geklippte Sprunglink behaelt seinen Innenabstand und misst dadurch 40x26 —
   eine Geisterbox, die jede Geometriepruefung als zu kleines Ziel meldet und dabei
   das Element verdeckt, das wirklich zu klein ist. Geklippt: keine Polsterung. */
.skip { padding: 0; }
.skip:focus { padding: 13px 20px; }

/* Die Wortmarke ist ein Link wie jeder andere: 40px hoch reicht nicht. */
.brand { min-height: var(--tap); }

/* Der Weiterlesen-Link einer Karte war 30px hoch. */
.card__go a { min-height: var(--tap); }

/* Kurze Fusszeilenlabels ("Cotta") sind 43px breit — ein Pixel unter der Schwelle.
   Die Hoehe stimmt laengst; hier fehlt nur die Breite. */
footer a, .fbase a { min-width: var(--tap); }

/* ==========================================================================
   TEIL 10 · EIN KREUZENDES ELEMENT BRAUCHT EIGENEN GRUND
   Eine Naht zieht ihr Element ueber die Bandkante: dessen obere Haelfte liegt
   damit auf dem VORIGEN Grund, die untere auf dem eigenen. Ist das Element
   durchsichtig, steht sein Text auf zwei verschiedenen Farben — auf einer davon
   gemessen 2.35:1, und keine Pruefung, die nur den naechsten deckenden Vorfahren
   sucht, sieht das. Nur ein Renderer, der den sichtbaren Stapel auswertet.

   Deshalb bekommt jede Naht ihren eigenen Grund — ausser das kreuzende Objekt
   malt bereits einen. So kann das Vergessen den Fehler nicht wieder einbauen.
   ========================================================================== */
.seam-up:not(:has(> .phoneblock, > .card, > .keypad, > .truststrip, > .notice,
                  > .ledger, > .compare, > .light-island, > .usp, > .stats, > .framed)) {
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(22px, 2.6vw, 34px);
}
.section--dark .seam-up:not(:has(> .phoneblock, > .card, > .keypad, > .truststrip, > .notice,
                  > .ledger, > .compare, > .light-island, > .usp, > .stats, > .framed)),
.on-dark .seam-up:not(:has(> .phoneblock, > .card, > .keypad, > .truststrip, > .notice,
                  > .ledger, > .compare, > .light-island, > .usp, > .stats, > .framed)) {
  background: var(--dark-2);
  border-color: var(--dark-line);
}

/* ==========================================================================
   TEIL 11 · DAS OFFENE MOBILMENUE MUSS SCROLLEN
   Vierzehn Eintraege sind 757px hoch. Die Kopfleiste ist `position:sticky`,
   also waechst sie beim Oeffnen einfach ueber den Bildschirmrand hinaus: der
   letzte Eintrag ("Kontakt") lag auf einem 390x844-Geraet 13px darunter, auf
   360x640 gleich 217px — und Scrollen half nicht, weil die Kopfleiste klebt.
   Ein Menue, dessen letzte Punkte man nicht erreichen kann, ist kein Menue.

   Die Kopfleiste wird im geoeffneten Zustand zur Spalte mit Bildschirmhoehe;
   das Menue ist das Flex-Kind, das den Rest bekommt und in sich scrollt.
   Damit stimmt es bei jeder Topbar- und Navbar-Hoehe von selbst — keine
   ausgerechnete Zahl, die beim naechsten Handgriff falsch wird.
   ========================================================================== */
@media (max-width: 1119px) {
  header:has(.mobmenu:not([hidden])) {
    display: flex;
    flex-direction: column;
    /* Bildschirmhoehe MINUS Rufleiste. Ohne den Abzug endet das Menue exakt am
       unteren Rand — und die fest stehende Rufleiste (63px) liegt darueber, sodass
       der letzte Punkt zwar gescrollt werden kann, aber verdeckt bleibt. */
    max-height: calc(100vh - var(--callbar-space, 84px));
    max-height: calc(100dvh - var(--callbar-space, 84px));   /* dvh: die Adressleiste zaehlt mit */
  }
  .mobmenu {
    overflow-y: auto;
    overscroll-behavior: contain;   /* kein Weiterscrollen der Seite dahinter */
    -webkit-overflow-scrolling: touch;
    min-height: 0;                  /* sonst schrumpft ein Flex-Kind nie unter min-content */
  }
  /* Etwas Luft unter dem letzten Eintrag, damit er nicht auf der Kante klebt. */
  .mobmenu ul { padding-bottom: 26px; }
}

/* ==========================================================================
   TEIL 12 · ZWEI KLEINTEILE, DIE ERST DIE RECHTSSEITEN GEZEIGT HABEN
   ========================================================================== */

/* Eine Augenbraue ist inline-flex: das Zeichen und der Text sind zwei Flex-Elemente
   auf EINER Zeile, und gesperrter Versalsatz wird schnell breiter als ein 320px-
   Geraet. Gemessen: "ANBIETERKENNZEICHNUNG NACH § 5 DDG" setzte die Mindest-
   Layoutbreite der Seite auf 330px — und zog die fest stehende Rufleiste gleich mit
   hinaus. Umbrechen lassen statt die Seite breiter machen. */
.eyebrow { flex-wrap: wrap; overflow-wrap: break-word; max-width: 100%; }

/* Ein Link in der Datenzeile (Rufnummer, E-Mail) war 22px hoch. Die Zeile ist kein
   Fliesstext, sondern ein Datenfeld — hier gilt dieselbe Zielgroesse wie ueberall. */
.ledger__v a { display: inline-flex; align-items: center; min-height: var(--tap); }
