
:root{
  /* Contrast checked against #fff and against the canvas. --ink3 carries the
     KPI labels, table meta and footnotes, so it has to clear 4.5:1 on both —
     it used to sit at 3.3 and failed.

     The canvas is a hair deeper and carries a trace of the brand's green
     rather than blue. White panels used to sit at 1.10 against it, which is
     barely a separation at all; they now sit at 1.17. Deepening the ground
     moves it toward --ink3, so that grey came down with it (4.31 would have
     failed) and --money with it. Measured, not eyeballed:
       ink 15.53 · ink2 6.15 · ink3 4.79 · brand 6.43 · money 5.17 on canvas,
       and 18.18 / 7.20 / 5.61 / 7.53 / 6.05 on a panel. */
  --ink:#12161A;--ink2:#515861;--ink3:#5F6971;
  --line:#D7DEDA;--line2:#E6EBE8;
  --bg:#EAEEEC;--panel:#fff;
  /* Fainter than --line on purpose: the ground is texture, the border is an
     edge, and they read as one weight when they share a colour. */
  --dot:#DEE4E0;
  --brand:#0F5F55;--brand-ink:#fff;--money:#147053;--acc:#7DD3B2;
  --green:#147053;--red:#B42318;
  --warn:#9A3412;--warn-bg:#FDF4EF;
  --bund:#14415F;--land:#4C3575;--kommune:#6B4409;--eu:#5A6B78;
  /* Two layers: a tight contact shadow so the edge reads, and a wider, softer
     one so the panel lifts. One layer at .04 did neither. */
  --shadow:0 1px 2px rgba(18,32,26,.05),0 2px 6px rgba(18,32,26,.04);
  --r:10px;--gut:24px;
}
:root[data-theme="dark"]{
  /* --ink3 failed AA here too, at 3.8:1 — same small text, same problem. */
  --ink:#E8EDF0;--ink2:#98A2AB;--ink3:#828B93;
  --line:#272F36;--line2:#1A2026;
  --bg:#0E1114;--panel:#171C22;
  /* fainter than --line, as in light */
  --dot:#1E252B;
  --brand:#3FB496;--brand-ink:#08130F;--money:#4FD1A5;--acc:#4FD1A5;
  --green:#4FD1A5;--red:#FF7B72;
  --warn:#F0A177;--warn-bg:#241812;
  --bund:#7FB5D8;--land:#B39DDB;--kommune:#D9A86A;--eu:#9FB2C0;
  --shadow:0 1px 2px rgba(0,0,0,.28);
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;color:var(--ink);font:15px/1.55 -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;
  background-color:var(--bg);
  /* German is a compound language and this is a directory of official
     programme names: "Wohnraummodernisierungsförderung" is one word and it
     is wider than a phone. Without this it does not wrap, it pushes the
     page sideways, and every section inherits a horizontal scrollbar from
     one title. */
  overflow-wrap:break-word}
/* and where it has to break, break it properly — the documents lang
   attribute is set, so the browser hyphenates by German rules */
h1,h2,h3,h4,p,li,dd,summary,.t,.tt,.rn,.job b,.gc b,.step b{hyphens:auto}
/* The dot field the page has always had, moved off the body's own
   background and onto a fixed layer. Fixed is the cheapest parallax there
   is: the content scrolls, the field does not, and the page gains a floor
   to move against. It drifts one cell every two minutes on top of that —
   slow enough that it reads as depth rather than as motion. */
body::before{content:'';position:fixed;inset:-30px;z-index:-2;
  pointer-events:none;
  background-image:radial-gradient(var(--dot) .9px,transparent .9px);
  background-size:22px 22px;background-position:11px 11px;
  animation:dotdrift 120s linear infinite}
@keyframes dotdrift{to{background-position:33px 33px}}
/* and a soft light wandering over it, which warms the dots it passes and
   leaves them again — the only thing on the page with no purpose but to
   make it feel awake */
body::after{content:'';position:fixed;inset:-30px;z-index:-1;
  pointer-events:none;
  background-image:radial-gradient(
    color-mix(in srgb,var(--brand) 55%,transparent) 1px,transparent 1px);
  background-size:22px 22px;background-position:11px 11px;
  -webkit-mask-image:radial-gradient(circle at 50% 50%,#000 0,transparent 62%);
  mask-image:radial-gradient(circle at 50% 50%,#000 0,transparent 62%);
  -webkit-mask-size:780px 780px;mask-size:780px 780px;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  animation:lampwalk 96s ease-in-out infinite}
@keyframes lampwalk{
  0%{-webkit-mask-position:6% 12%;mask-position:6% 12%}
  25%{-webkit-mask-position:74% 4%;mask-position:74% 4%}
  50%{-webkit-mask-position:92% 72%;mask-position:92% 72%}
  75%{-webkit-mask-position:22% 88%;mask-position:22% 88%}
  100%{-webkit-mask-position:6% 12%;mask-position:6% 12%}}
a{color:inherit}
.wrap{max-width:1420px;margin:0 auto;padding:0 var(--gut)}
.wrap.narrow{max-width:860px}
h1,h2,h3{letter-spacing:-.5px;margin:0}

/* ---------- panel: the one surface ---------- */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;box-shadow:var(--shadow)}
.panel>.ph{display:flex;align-items:center;gap:10px;padding:10px 14px;
  border-bottom:1px solid var(--line);font-size:12px;font-weight:700;
  letter-spacing:.6px;text-transform:uppercase;color:var(--ink2)}
.panel>.ph .sp{flex:1}
.panel>.pb{padding:20px}
.panel>.pf{padding:9px 14px;border-top:1px solid var(--line);font-size:11.5px;
  color:var(--ink3)}
.demo-banner{margin:0;padding:9px 24px;text-align:center;font-size:12px;
  font-weight:800;letter-spacing:.3px;color:var(--warn);
  background:var(--warn-bg);border-bottom:1px solid var(--line)}

/* The guide and home page use the same compact FAQ treatment. */
.faq-panel{max-width:760px;margin:36px 0 48px;padding:28px 32px;
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow)}
/* Home and finder are full-width sections; only the guide is prose-width. */
.faq-panel.faq-section,.faq-panel.fsec{max-width:none}
.faq-panel.fsec{padding:28px 32px}
.faq-panel .eyebrow{font-size:11.5px;font-weight:800;letter-spacing:1px;
  text-transform:uppercase;color:var(--brand);margin:0 0 8px}
.faq-panel .faqwrap{margin:14px 0 0;padding:0;background:none;
  border:0;border-radius:0;box-shadow:none}
.faq-panel details{border-bottom:1px solid var(--line2)}
.faq-panel details:last-of-type{border-bottom:0}
.faq-panel details summary{display:flex;align-items:baseline;gap:12px;
  cursor:pointer;list-style:none;padding:15px 0;font-size:16px;font-weight:600}
.faq-panel details summary::marker{content:''}
.faq-panel details summary::-webkit-details-marker{display:none}
.faq-panel details summary::after{content:'+';margin-left:auto;
  color:var(--ink3);font-size:20px;line-height:1}
.faq-panel details[open] summary::after{content:'−'}
.faq-panel details summary:hover{color:var(--brand)}
.faq-panel details summary:focus-visible{outline:2px solid var(--brand);
  outline-offset:4px;border-radius:2px}
.faq-panel details p{margin:0 0 16px;padding:0;max-width:65ch}
.program-changes{margin-top:34px;padding-top:24px;border-top:1px solid var(--line)}
.program-changes h2{margin:0 0 6px;font-size:21px}.program-changes>p{margin:0 0 15px}
.program-changes ol{display:grid;gap:10px;margin:0;padding:0;list-style:none}
.program-changes li{padding:14px 16px;border:1px solid var(--line);border-radius:var(--r);background:var(--panel)}
.program-changes li>div{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.program-changes li b{text-transform:capitalize}.program-changes time{color:var(--ink3);font-size:12px}
.program-changes li p{margin:7px 0;line-height:1.55}.program-changes li a{font-size:12px;font-weight:700;color:var(--brand)}
.faq-panel .faq-more{margin:16px 0 0}
.faq-panel .faq-more a{color:var(--brand);font-weight:700;text-decoration:none}
.faq-panel .faq-more a:hover{text-decoration:underline}
@media(max-width:620px){
  .faq-panel{margin:24px 0 36px;padding:20px}
  .faq-panel.fsec{padding:20px}
  .faq-panel details summary{font-size:15.5px}
}

/* ---------- top bar ---------- */
/* The bar owns a stacking context, so the menu that drops out of it can
   never rise above anything ranked higher than the bar itself — a z-index
   on the dropdown only sorts it *within* here. 70 puts the bar over the
   scroll-progress rule (60) and everything else the pages set. */
/* backdrop-filter makes this element a backdrop root, and a backdrop root
   clips its absolutely positioned descendants to its own box — so the
   dropdowns that hang out of the 56px bar were being cut off by the bar
   itself, whatever z-index they carried. The blur is switched off for as
   long as a menu is open, which is the only time anything needs to escape;
   the bar goes opaque in its place so nothing shows through. */
.top:has(details[open]){backdrop-filter:none;background:var(--bg)}
/* and where :has() is not understood, the blur is not worth a broken menu */
@supports not selector(:has(*)){
  .top{backdrop-filter:none;background:var(--bg)}
}
.top{position:sticky;top:0;z-index:70;background:color-mix(in srgb,var(--bg) 88%,transparent);
  backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.top .wrap{display:flex;align-items:center;gap:10px;height:56px}
/* full-bleed pages (the console) line the bar up with their own content
   instead of the centred column, so the brand and the page title share a
   left edge */
.top.flush .wrap{max-width:none;padding-left:20px;padding-right:20px}
.brand{display:flex;align-items:center;gap:9px;font-weight:650;text-decoration:none}
.nav{margin-left:auto;display:flex;align-items:center;gap:2px}
.nav a.hasai{display:inline-flex;align-items:center;gap:5px}
.nav a.hasai .spark{color:var(--brand)}
.nav a{padding:7px 12px;border-radius:8px;color:var(--ink2);text-decoration:none;
  font-size:14px;font-weight:550}
.nav .btn.sm{display:inline-flex;align-items:center;gap:6px;padding:0 11px}
.nav a.on{color:var(--brand);font-weight:750}
.nav a:hover{color:var(--brand)}
/* the three bar controls share one shape */
.tt,.lang>summary,.nav .btn.sm{height:32px;border:1px solid var(--line);
  border-radius:8px;background:var(--panel);font-size:12.5px;font-weight:700;
  color:var(--ink2);box-sizing:border-box}
.tt{display:inline-flex;align-items:center;padding:3px;margin-left:6px}
.tt button{all:unset;cursor:pointer;width:26px;height:24px;border-radius:6px;
  display:grid;place-items:center;font-size:12.5px;color:var(--ink3)}
.tt button[aria-pressed="true"]{background:color-mix(in srgb,var(--brand) 10%,transparent);
  color:var(--brand)}
.tt button:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.menu{display:none;position:relative;margin-left:6px}

/* ---------- language ---------- */
.lang{position:relative;margin-left:6px}
.lang>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:7px;
  padding:0 10px}
.lang>summary::-webkit-details-marker{display:none}
.lang>summary::after{content:'▾';color:var(--ink3);font-size:11px}
.lang>summary:hover,.nav .btn.sm:hover{border-color:var(--brand);color:var(--brand)}
.lang[open]>summary{border-color:var(--brand);color:var(--brand)}
.lang>summary:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.lang ul{position:absolute;right:0;top:calc(100% + 6px);margin:0;padding:5px;
  list-style:none;background:var(--panel);border:1px solid var(--line);
  border-radius:8px;box-shadow:0 8px 24px color-mix(in srgb,var(--ink) 14%,transparent);
  min-width:168px;z-index:40}
.lang li a{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:6px;
  font-size:13.5px;color:var(--ink);text-decoration:none;white-space:nowrap}
.lang li a:hover{background:color-mix(in srgb,var(--brand) 8%,transparent)}
.lang li a[aria-current]{font-weight:700;color:var(--brand)}
.lang li a .ck{margin-left:auto;font-size:11px}
.lang svg{border-radius:2px;flex:none;box-shadow:0 0 0 1px color-mix(in srgb,var(--ink) 12%,transparent)}

/* ---------- controls ---------- */
.btn{display:inline-flex;align-items:center;gap:7px;padding:9px 15px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink2);
  font:600 13.5px -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;cursor:pointer;text-decoration:none}
.btn:hover{border-color:var(--brand);color:var(--brand)}
.btn.p{background:var(--brand);border-color:var(--brand);color:var(--brand-ink)}
.btn.p:hover{filter:brightness(1.06);color:var(--brand-ink)}
.btn.sm{padding:6px 11px;font-size:12.5px}
input,select{font:14px -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;color:var(--ink);background:var(--panel);
  border:1px solid var(--line);border-radius:8px;padding:9px 12px}
input:focus,select:focus{outline:none;border-color:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 16%,transparent)}
label{font-size:12px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
  color:var(--ink3)}

/* ---------- bits ---------- */
.lv{font-size:10.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase}
.lv.Bund{color:var(--bund)}.lv.Land{color:var(--land)}
.lv.Kommune{color:var(--kommune)}.lv.EU{color:var(--eu)}
.chip{font-size:11px;font-weight:700;border:1px solid var(--line);border-radius:6px;
  padding:2px 8px;color:var(--ink2);white-space:nowrap}
.chip.ok{color:var(--money);border-color:color-mix(in srgb,var(--money) 35%,transparent);
  background:color-mix(in srgb,var(--money) 9%,transparent)}
.muted{color:var(--ink3)}
.warnbox{background:var(--warn-bg);border:1px solid color-mix(in srgb,var(--warn) 30%,transparent);
  border-radius:var(--r);padding:14px 16px;display:flex;gap:12px;font-size:14px}
.warnbox b{color:var(--warn)}
.warnbox>svg,.warnbox>span{flex:none;color:var(--warn)}
/* The one mistake that costs the whole grant. Everywhere else this is a
   note beside the content; on the home page it is the content, so it gets
   the room to be read rather than skimmed. */
.warnbox.loud{padding:22px 24px;gap:16px;align-items:flex-start;
  border-width:2px;border-radius:14px}
.warnbox.loud .wb-t{display:block;font-size:17.5px;letter-spacing:-.3px;
  margin-bottom:5px}
.warnbox.loud p{font-size:15px;line-height:1.6}
.warnbox.loud a{display:inline-block;margin-top:8px}
@media(max-width:560px){.warnbox.loud{padding:18px}}
.warnbox a{color:var(--warn);font-weight:700}

/* ---------- footer ---------- */
footer{border-top:1px solid var(--line);margin-top:48px;background:var(--panel)}
footer .wrap{padding:36px var(--gut) 34px}
.fcols{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:28px;margin-bottom:26px}
.fcol h5{font-size:12px;text-transform:uppercase;letter-spacing:.8px;color:var(--ink3);
  margin:0 0 10px;font-weight:750}
.fcol a{display:block;font-size:13.5px;color:var(--ink2);padding:3px 0;text-decoration:none}
.fcol a:hover{color:var(--brand)}
/* .fcol a is (0,1,1) and .brand is (0,1,0), so the column rule was winning
   over the wordmark: it turned the flex row back into a block, which
   dropped the centring and the gap and left the name sitting on the icon's
   baseline at link size and link colour. */
.fcol a.brand{display:flex;align-items:center;gap:9px;padding:0;
  font-size:15.5px;font-weight:650;color:var(--ink)}
.fcol a.brand:hover{color:var(--brand)}
.fcol p{margin:8px 0 0;font-size:13px;color:var(--ink2);max-width:34ch}
.fbot{border-top:1px solid var(--line);padding-top:16px}
.fbot p{margin:0 0 6px;font-size:12.5px;color:var(--ink2);max-width:96ch}
.fbot .s{font-size:11.5px;color:var(--ink3)}
.flinks{display:flex;flex-wrap:wrap;gap:18px;margin-bottom:12px}
.flinks a{font-size:13px;font-weight:600;color:var(--ink2);text-decoration:none}

@media (max-width:820px){
  :root{--gut:16px}
  .fcols{grid-template-columns:1fr 1fr}
}
/* Below this the bar ran past its own gutter: brand, theme switch, language,
   sign-in and the menu do not fit a phone. Sign-in goes — it is in the footer
   and on its own page — and the language pill drops to the flag alone. */
/* Six links, a theme switch, a language pill and a sign-in button need
   about 955px. An iPad in portrait gives the bar 720, so the row has to
   fold well above a phone. 1060 rather than 980: at 980 an iPad in
   landscape cleared it by 21px, which is not clearance, it is luck with a
   font. The links move into the menu — a real menu now, rather than a ☰
   that was secretly a link to /programs/. */
@media (max-width:1060px){
  /* Direct children only. `.nav a` also matches the links *inside* the
     dropdown — they are nav > details > ul > li > a — so the menu opened
     to a 12px sliver containing nothing but its own padding. */
  .nav>a:not(.btn){display:none}
  .menu{display:block}
}
@media (max-width:560px){
  .nav .btn.sm{display:none}
  .lang>summary span{display:none}
  .lang>summary{padding:0 8px;gap:0}
  .lang ul{min-width:150px}
}

/* ---------- the sign-in dialog ---------- */
.lgd{border:0;padding:0;border-radius:16px;width:min(420px,calc(100vw - 32px));
  background:var(--panel);color:var(--ink);
  box-shadow:0 24px 70px color-mix(in srgb,var(--ink) 30%,transparent)}
.lgd::backdrop{background:color-mix(in srgb,var(--ink) 52%,transparent);
  backdrop-filter:blur(3px)}
.lgform{display:grid;gap:13px;padding:26px 26px 22px}
.lgh{display:grid;gap:7px;margin-bottom:2px}
.lgmark{line-height:0}
.lgh h2{font-size:21px;letter-spacing:-.6px}
.lgh p{margin:0;font-size:13.5px;color:var(--ink2);line-height:1.55}
.lgf{display:grid;gap:6px}
.lgf>span{font-size:12px;font-weight:700;color:var(--ink2)}
.lgf input{font:inherit;font-size:15px;padding:11px 13px;border-radius:10px;
  border:1px solid var(--line);background:var(--bg);color:var(--ink);width:100%;
  transition:border-color .16s,box-shadow .16s}
.lgf input:focus{outline:none;border-color:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 16%,transparent)}
.lgbad{margin:0;font-size:13px;font-weight:650;color:var(--warn);
  background:var(--warn-bg);border-radius:8px;padding:9px 11px}
.lgfoot{display:flex;gap:8px;margin-top:3px}
.lgfoot .btn{flex:1;justify-content:center}
.lgdemo{margin:6px 0 0;padding-top:13px;border-top:1px solid var(--line2);
  font-size:12.5px;color:var(--ink2);display:flex;flex-wrap:wrap;gap:7px;
  align-items:center}
.lgdemo b{font-size:10.5px;font-weight:800;letter-spacing:.7px;
  text-transform:uppercase;color:var(--ink3)}
.lgdemo code{font-size:12px;background:var(--bg);border:1px solid var(--line);
  border-radius:6px;padding:2px 7px}
.lgnote{margin:0;font-size:11.5px;color:var(--ink3);line-height:1.5}
@media (prefers-reduced-motion:no-preference){
  .lgd[open]{animation:lgin .22s cubic-bezier(.2,.8,.3,1)}
}
@keyframes lgin{from{opacity:0;transform:translateY(-8px) scale(.98)}}

/* ---------- the menu behind the burger ----------
   The rule that hides it by default is up with the rest of the bar, on
   purpose. Put it down here and it lands after the 1060 media query that
   shows it, at equal specificity, where the later declaration wins — so
   the burger would be hidden at every width. That is what happened. */
.menu>summary{list-style:none;cursor:pointer;display:flex;
  align-items:center;justify-content:center;box-sizing:border-box;
  width:38px;height:38px;padding:0;margin:0;line-height:0;
  border:1px solid var(--line);border-radius:9px;
  color:var(--ink2);background:var(--panel);-webkit-appearance:none}
.menu>summary svg{display:block}
.menu>summary::marker{content:''}
/* The pages style their FAQ with a bare `details summary::after{content:'+'}`,
   which is every <details> on the page — including this one. The bar was
   drawing a plus inside the burger button and pushing the icon off centre
   with its margin-left:auto. The language picker escapes it by declaring
   its own ::after; this one says there is none. */
.menu>summary::after{content:none;display:none}
.menu>summary::-webkit-details-marker{display:none}
.menu[open]>summary{border-color:var(--brand);color:var(--brand)}
.menu>summary:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.menu ul{position:absolute;right:0;top:calc(100% + 6px);margin:0;padding:5px;
  list-style:none;background:var(--panel);border:1px solid var(--line);
  border-radius:11px;box-shadow:0 10px 30px color-mix(in srgb,var(--ink) 16%,transparent);
  min-width:212px;z-index:2;
  max-height:calc(100dvh - 76px);overflow:auto;overscroll-behavior:contain}
.menu li a{display:flex;align-items:center;gap:9px;padding:10px 12px;
  border-radius:7px;font-size:14.5px;text-decoration:none;color:var(--ink)}
.menu li a:hover{background:color-mix(in srgb,var(--brand) 8%,transparent)}
.menu li a[aria-current]{font-weight:700;color:var(--brand)}

/* ---------- touch ----------
   A mouse can hit a 32px target; a thumb on a moving train cannot. Where
   the pointer is coarse, everything that can be tapped grows to 44px. */
@media (pointer:coarse){
  .btn{min-height:44px}
  .btn.sm{min-height:38px}
  .menu>summary,.lang>summary,.tt button{min-height:40px;min-width:40px}
  .nav a{padding-top:10px;padding-bottom:10px}
  .st,.menu li a,.lang li a{min-height:44px}
  .exchip,.pop{min-height:40px}
  .faqwrap summary,details summary{padding-top:18px;padding-bottom:18px}
  .ctf input,.ctf select,.ctf textarea{font-size:16px}
}

/* ---------- the AI mark ---------- */
.spark{flex:none;vertical-align:-2px}
/* ---------- the bands' own background ----------
   A band paints an opaque panel over the page's dot field, so the hero and
   the finder carry their own. Two soft fields of colour, blurred and
   drifting: the one variant of the thirteen that was chosen by looking at
   them rather than by arguing about them.

   It is masked to nothing well before the headline, and it is the only
   blurred thing left on the site — everything else that moves is drawn. */
.bgband{position:relative;overflow:hidden}
.bgband>.wrap{position:relative;z-index:1}
.bgband::before{content:'';position:absolute;inset:-30px;
  pointer-events:none;z-index:0;
  background:
    radial-gradient(40% 44% at 16% 10%,
      color-mix(in srgb,var(--brand) 26%,transparent),transparent 68%),
    radial-gradient(36% 40% at 84% 88%,
      color-mix(in srgb,var(--acc) 34%,transparent),transparent 66%);
  filter:blur(38px);
  -webkit-mask-image:radial-gradient(135% 115% at 50% 42%,#000 12%,transparent 78%);
  mask-image:radial-gradient(135% 115% at 50% 42%,#000 12%,transparent 78%);
  animation:auroradrift 26s ease-in-out infinite alternate}
@keyframes auroradrift{to{transform:translate3d(5%,-4%,0) scale(1.14)}}

/* ---------- the contact form ---------- */
.contact{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1fr);
  gap:30px;align-items:start;padding:44px 0 56px;
  border-top:1px solid var(--line);margin-top:20px}
.cthead h2{font-size:clamp(22px,2.6vw,30px);letter-spacing:-.9px;margin:0 0 9px}
.ctdirect{margin:18px 0 0;font-size:13.5px;color:var(--ink3)}
.ctdirect a{color:var(--brand);font-weight:650}
.ctform{display:grid;gap:13px;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow);padding:22px 24px}
.ctrow{display:grid;grid-template-columns:1fr 1fr;gap:13px}
.ctf{display:grid;gap:6px}
.ctf>span{font-size:12px;font-weight:700;color:var(--ink2);
  display:flex;align-items:center;gap:7px}
.ctf>span i{font-style:normal;font-size:10px;font-weight:800;
  letter-spacing:.5px;text-transform:uppercase;color:var(--ink3)}
.ctf input,.ctf select,.ctf textarea{font:inherit;font-size:14.5px;
  padding:11px 13px;border:1px solid var(--line);border-radius:10px;
  background:var(--bg);color:var(--ink);width:100%;
  transition:border-color .16s,box-shadow .16s}
.ctf textarea{resize:vertical;min-height:110px;line-height:1.55}
.ctf input:focus,.ctf select:focus,.ctf textarea:focus{outline:none;
  border-color:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 16%,transparent)}
.ctf input::placeholder,.ctf textarea::placeholder{color:var(--ink3)}
.ctf input:user-invalid,.ctf textarea:user-invalid{border-color:var(--warn)}
.ctfoot{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.cthint{margin:0;flex:1;min-width:220px;font-size:12px;color:var(--ink3);
  line-height:1.5}
.ctpriv{margin:0;padding-top:13px;border-top:1px solid var(--line2);
  font-size:12px;color:var(--ink3);line-height:1.55}
.ctpriv a{color:var(--brand)}
@media(max-width:900px){.contact{grid-template-columns:1fr;gap:22px}}
@media(max-width:560px){.ctrow{grid-template-columns:1fr}}
.aibadge{display:inline-flex;align-items:center;gap:5px;font-size:11px;
  font-weight:700;letter-spacing:.6px;text-transform:uppercase;
  color:var(--brand);background:color-mix(in srgb,var(--brand) 12%,transparent);
  border-radius:99px;padding:4px 9px;white-space:nowrap}
/* a slow pulse, so the mark reads as active rather than decorative */
@keyframes sparkpulse{0%,100%{opacity:1}50%{opacity:.55}}
.aibadge .spark{animation:sparkpulse 2.8s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){.aibadge .spark{animation:none}}

/* ---------- motion ---------- */
[data-js] [data-reveal]{opacity:0;transform:translateY(14px);
  transition:opacity .6s cubic-bezier(.2,.7,.3,1),transform .6s cubic-bezier(.2,.7,.3,1);
  transition-delay:calc(var(--i,0) * 70ms)}
[data-js] [data-reveal].in{opacity:1;transform:none}
/* ---------- scroll-linked motion ----------
   Where the browser can drive an animation from the scroll position, the
   reveal stops being a one-shot that fires at a threshold and becomes a
   thing tied to where the page actually is: scroll back up and it goes
   back. Same two properties, so nothing moves that was not already moving,
   and the observer above stays as the fallback everywhere else. */
@supports (animation-timeline:view()){
  [data-js] [data-reveal]{opacity:1;transform:none;transition:none;
    animation:revealin linear both;
    animation-timeline:view();
    animation-range:entry 4% cover 18%}
  @keyframes revealin{
    from{opacity:0;transform:translateY(22px)}
    to{opacity:1;transform:none}}

  /* Parallax is depth, not travel: the three columns of the hero leave at
     slightly different rates as it scrolls away, which is what makes the
     map read as sitting behind the text rather than beside it. Nothing
     moves more than a few per cent of its own height. */
  /* view() with no argument: each column is timed against its own passage
     out of the viewport. `view(.heroband)` is not a thing — and an invalid
     animation-timeline falls back to the document timeline, where a
     duration-less animation completes instantly and leaves the hero sitting
     at its faded end state. */
  .heroband .cpl{animation:parNear linear both;
    animation-timeline:view();animation-range:exit 0% exit 100%}
  .heroband .cpmap{animation:parFar linear both;
    animation-timeline:view();animation-range:exit 0% exit 100%}
  .heroband .cpr{animation:parNearer linear both;
    animation-timeline:view();animation-range:exit 0% exit 100%}
  @keyframes parNear{to{transform:translateY(-14%);opacity:.25}}
  @keyframes parFar{to{transform:translateY(-4%);opacity:.5}}
  @keyframes parNearer{to{transform:translateY(-20%);opacity:.2}}

  /* the band of figures drifts up a little as it comes into view */
  .statband dl{animation:parRise linear both;
    animation-timeline:view();animation-range:entry 0% cover 30%}
  @keyframes parRise{from{transform:translateY(26px)}to{transform:none}}

  /* ---- parallax on the page's blocks ----
     Every card, panel and row keeps moving after it has arrived: in at
     +20px, out at -10px, over its whole passage through the viewport. That
     continuing drift is what separates parallax from a reveal — a reveal
     finishes and the page goes flat again, this never quite settles.

     Two speeds, alternating down a grid, so neighbours are never in step.
     Nothing sticky is in this list: a transform on a sticky element stops
     it sticking. */
  .panel,.job,.tip,.gc,.card,.fcard,.lgi,.how,.srcc,.stwrap,.faqwrap,
  .cta,.example,.spl,.spr,.sbody,.pop,.warnbox,.aicard,.applyp{
    animation:parBlock linear both;
    animation-timeline:view();animation-range:entry 0% exit 100%}
  .jobs>*:nth-child(even),.tips>*:nth-child(even),.glos>*:nth-child(even),
  .cards>*:nth-child(even),.fcards>*:nth-child(even),.pops>*:nth-child(even),
  .legend>*:nth-child(even),.hows>*:nth-child(even){
    animation-name:parBlockSlow}
  @keyframes parBlock{
    from{transform:translateY(20px)}
    to{transform:translateY(-10px)}}
  @keyframes parBlockSlow{
    from{transform:translateY(11px)}
    to{transform:translateY(-5px)}}
  /* Inside a sticky column the view timeline stops advancing while the
     element is stuck, so a panel in there would hold whatever offset it
     had when it stuck. The sidebar keeps the reveal and skips the drift. */
  .pside .panel,.pside .warnbox{animation:none;transform:none}

  /* headings lead their section in by a hair, which is the oldest trick
     in the book and still the one that reads as depth */
  .eyebrow,.sec h2,.fsec h2,section>h2,.slede{
    animation:parHead linear both;
    animation-timeline:view();animation-range:entry 0% cover 35%}
  @keyframes parHead{from{transform:translateY(26px);opacity:0}
    to{transform:none;opacity:1}}

  /* the map is the furthest thing back, so it moves the least */
  .demap,.dsvg{animation:parDeep linear both;
    animation-timeline:view();animation-range:entry 0% exit 100%}
  @keyframes parDeep{from{transform:translateY(8px)}to{transform:translateY(-4px)}}
}

/* On the landing page the scenery stays still; the content enters once as
   it reaches the viewport. Keep scroll-linked parallax on the other pages. */
body.home-page::before,body.home-page::after,
body.home-page .bgband::before{animation:none}
body.home-page .heroband :is(.cpl,.cpmap,.cpr),
body.home-page .statband dl,
body.home-page :is(.panel,.job,.tip,.gc,.card,.fcard,.lgi,.how,.srcc,
  .stwrap,.faqwrap,.cta,.example,.spl,.spr,.sbody,.pop,.warnbox,
  .aicard,.applyp,.eyebrow,.slede,.demap,.dsvg),
body.home-page :is(.sec,.fsec,section)>h2{animation:none}
html[data-js] body.home-page [data-reveal]{
  animation:none;opacity:0;transform:translateY(18px);
  transition:opacity .7s cubic-bezier(.2,.7,.3,1),
    transform .7s cubic-bezier(.2,.7,.3,1);
  transition-delay:calc(var(--i,0) * 75ms)}
html[data-js] body.home-page [data-reveal].in{opacity:1;transform:none}

/* The featured-programme rail and the hero map describe the same server
   records. Hovering or focusing a row previews its geographic scope without
   changing the map's own click selection. */
body.home-page .rail a.map-preview{
  background:color-mix(in srgb,var(--brand) 9%,transparent)}
body.home-page .rail a.map-preview .rn{color:var(--brand)}
body.home-page .rail a.map-preview .fm{
  background:var(--brand);border-color:var(--brand);
  color:var(--brand-ink);transform:translateY(-1px)}
body.home-page .cpmap .demap.has-program-preview path{
  opacity:.32;fill:var(--panel);stroke:var(--line);
  transition:opacity .18s ease,fill .18s ease,stroke .18s ease}
body.home-page .cpmap .demap.has-program-preview.is-federal path,
body.home-page .cpmap .demap.has-program-preview path.programme-match{
  opacity:1;fill:color-mix(in srgb,var(--brand) 58%,var(--panel));
  stroke:var(--line)}

/* ---- things open, rather than appear ---- */
/* A <details> that snaps open is the one place on a page where motion is
   not decoration: without it the text under the summary arrives with no
   indication of where it came from. */
@supports (interpolate-size:allow-keywords){
  :root{interpolate-size:allow-keywords}
  details::details-content{block-size:0;overflow:hidden;
    content-visibility:hidden;
    transition:block-size .32s cubic-bezier(.2,.7,.3,1),
               content-visibility .32s allow-discrete}
  details[open]::details-content{block-size:auto;content-visibility:visible}
}
details summary::after{transition:transform .28s cubic-bezier(.2,.9,.3,1),
  color .2s}
details[open] summary::after{transform:rotate(180deg)}
details summary:hover::after{color:var(--brand)}
/* and the page itself arrives rather than blinking into place */
[data-js] main>:first-child,[data-js] .heroband,
[data-js] .findband{animation:pagein .5s cubic-bezier(.2,.7,.3,1) both}
@keyframes pagein{from{opacity:0;transform:translateY(-6px)}
  to{opacity:1;transform:none}}
.btn{transition:transform .12s ease,background .16s,border-color .16s,
  color .16s}
.btn:active{transform:translateY(1px) scale(.985)}
.lift{transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease}
.lift:hover{transform:translateY(-3px);border-color:var(--brand);
  box-shadow:0 6px 20px color-mix(in srgb,var(--ink) 8%,transparent)}
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  [data-js] [data-reveal]{opacity:1;transform:none}
  html[data-js] body.home-page [data-reveal]{opacity:1;transform:none}
  /* the scroll-driven ones are animations too, so they stop with the rest —
     these put back the state they would have ended on */
  .heroband .cpl,.heroband .cpmap,.heroband .cpr,.statband dl,
  .panel,.job,.tip,.gc,.card,.fcard,.lgi,.how,.srcc,.stwrap,.faqwrap,
  .cta,.example,.spl,.spr,.sbody,.pop,.warnbox,.aicard,.applyp,
  .eyebrow,.sec h2,.fsec h2,section>h2,.slede,.demap,.dsvg{
    opacity:1!important;transform:none!important}
  body::before,body::after,.bgband::before{animation:none!important}
  .lift:hover{transform:none}
}

/* Standalone accent notes should read as cards, not as text on the dotted
   page canvas. The guide's inline .prose .lvl rule is shared by both locales;
   the extra body specificity keeps this one treatment consistent site-wide. */
body .prose .lvl,
body .aicount{
  background:color-mix(in srgb,var(--panel) 95%,var(--c,var(--brand)) 5%);
  border:1px solid var(--line);
  border-left:3px solid var(--c,var(--brand));
  border-radius:var(--r);
  box-shadow:var(--shadow);
  padding:10px 14px;
}

/* ---------- print ----------
   The sheet an applicant takes to the Energieberater. Paper has no theme
   switch, no navigation and no hover, and a link that reads "hier" is
   useless once printed — so the href is set beside it. */
@media print{
  :root,:root[data-theme="dark"]{
    --ink:#000;--ink2:#222;--ink3:#555;--line:#bbb;--line2:#ddd;
    --bg:#fff;--panel:#fff;--dot:transparent;--shadow:none;
    --brand:#000;--money:#000;--warn:#000;--warn-bg:#fff}
  @page{margin:16mm 14mm}
  body{background:#fff!important;font-size:10.5pt;line-height:1.45}
  .nav,footer,.tt,.langsw,.mapwrap,.kpis,.toolbar,.pf,.btn,button,
  .warnbox a,#detail,#cmp,.crumb{display:none!important}
  [data-js] [data-reveal]{opacity:1!important;transform:none!important}
  .wrap{max-width:none;padding:0}
  .panel{border:1px solid var(--line);box-shadow:none;break-inside:avoid}
  body .prose .lvl,body .aicount{background:#fff;box-shadow:none}
  .ph{background:none;border-bottom:1px solid var(--line)}
  h1{font-size:18pt}
  h2{font-size:13pt}
  /* keep a heading with what it introduces */
  h1,h2,h3,.ph{break-after:avoid}
  ul,ol,table,.degbox,.warnbox{break-inside:avoid}
  details{display:block!important}
  details>summary{display:none!important}
  /* the source sentence is the reason the figure can be trusted: print it */
  details.cond blockquote,details.cond ul{display:block!important}
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:8.5pt;
    color:#555;word-break:break-all}
  .prog{display:block}
  .side{position:static;display:block;margin-top:14px}
}
