/* Fastpage CMS — frontend. Industrial/blueprint look (steel blue, square,
 * hairline objects, transparent line drawings), built entirely on Open Props —
 * system fonts (system-ui plus the Open Props token --font-industrial for
 * headings), no webfonts, no build. Colours, spacing and shadows come from Open
 * Props tokens. */
:root {
    --ink: var(--gray-9);
    --muted: var(--gray-7);          /* lesbarer Grauton (AA) */
    --accent: var(--blue-8);
    --accent-hover: var(--blue-9);
    --accent-deep: var(--blue-12);   /* volles Feld (Kennzahlen-Band) */
    --bg: var(--gray-1);
    --surface: var(--gray-2);
    --border: var(--gray-4);         /* Haarlinie / Wireframe-Kante */
    --ok-bg: var(--blue-0);  --ok-ink: var(--blue-9);  --ok-border: var(--blue-3);
    --err-bg: var(--red-0);  --err-ink: var(--red-9);  --err-border: var(--red-3);
    --radius: 0;                     /* eckig — Blueprint */
    --pop: var(--shadow-3);
    /* Content width — ONE source for header, body and footer. The three thereby
     * align on the same edges; making the site wider or narrower means changing
     * exactly this value, not four scattered numbers. The gutter is part of it:
     * the width includes the padding (box-sizing: border-box), so the content is
     * 1400px minus two margins. */
    --container: 1400px;
    --gutter: var(--size-4);
    /* Logo size in the header. On mobile the width shrinks (rule in the offcanvas
     * breakpoint) so brand and burger fit side by side. */
    --logo-width: 200px;
    --logo-max-height: 96px;
    /* Two semantic font roles; the branding pairings (.font-<key>) remap both onto
     * other Open Props stacks. `--font-body` rather than `--font-sans` directly, so
     * the Open Props token stays untouched. Default = pure system font in BOTH
     * roles; the condensed industrial heading is the selectable pairing
     * `.font-industrial`. */
    --font-head: var(--font-sans);
    --font-body: var(--font-sans);
}

/* Branding: curated accent palette. The body class `.accent-<key>` remaps the
 * accent tokens onto another Open Props tone — every downstream `var(--accent…)`
 * follows automatically. CSP-safe (a class instead of inline), every colour checked
 * for WCAG AA against white text AND a light background. Default = steel blue (no
 * class). Swatch mirror in the admin: assets/admin/design.css. */
.accent-indigo     { --accent: var(--indigo-9);  --accent-hover: var(--indigo-10); --accent-deep: var(--indigo-12); }
.accent-violett    { --accent: var(--violet-9);  --accent-hover: var(--violet-10); --accent-deep: var(--violet-12); }
.accent-petrol     { --accent: var(--teal-10);   --accent-hover: var(--teal-11);   --accent-deep: var(--teal-12); }
.accent-gruen      { --accent: var(--green-10);  --accent-hover: var(--green-11);  --accent-deep: var(--green-12); }
.accent-rot        { --accent: var(--red-10);    --accent-hover: var(--red-11);    --accent-deep: var(--red-12); }
.accent-terrakotta { --accent: var(--orange-10); --accent-hover: var(--orange-11); --accent-deep: var(--orange-12); }
.accent-graphit    { --accent: var(--gray-9);    --accent-hover: var(--gray-10);   --accent-deep: var(--gray-12); }

/* Branding: curated font pairings. The body class `.font-<key>` remaps the two
 * roles --font-head (headings) and --font-body (body text) onto other Open Props
 * font stacks — every downstream `var(--font-head|body)` follows automatically.
 * All stacks are pure SYSTEM FONTS with a fallback chain: no webfonts, no build,
 * no external request. Default = pure system font (no class, base in :root).
 * Specimen mirror in the admin: assets/admin/design.css — a change here means a
 * change there (SettingsRepositoryTest enforces the parity). */
.font-humanist     { --font-head: var(--font-humanist);   --font-body: var(--font-humanist); }
.font-industrial   { --font-head: var(--font-industrial); --font-body: var(--font-sans); }
.font-redaktionell { --font-head: var(--font-antique);    --font-body: var(--font-transitional); }

/* The industrial headings are condensed and take the tight tracking of the h1–h4
 * base rule; the serif pairing does not — neutralize it there. */
.font-redaktionell h1, .font-redaktionell h2,
.font-redaktionell h3, .font-redaktionell h4 { letter-spacing: 0; }

* { box-sizing: border-box; }
/* A block's jump target (emitted by the BlockRenderer from the «Sprungziel»
   field). Layout-neutral: no box, no height, just a point to jump to — `main` is
   normal block flow, so the element creates no gap there. `scroll-margin-top`
   gives the target air instead of gluing it to the window edge.
   Here and not in `blocks/jumplinks.css`: EVERY block can carry an anchor, even
   when no jumplinks block is on the page (a link from rich text, from a campaign,
   from another page). */
.anchor { display:block; height:0; scroll-margin-top:var(--size-8); }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
body { margin:0; color:var(--ink); background:var(--bg);
    font-family:var(--font-body); font-size:1.0625rem; line-height:1.6;
    display:flex; flex-direction:column; min-height:100vh; }
h1, h2, h3, h4 { font-family:var(--font-head); font-weight:var(--font-weight-7); line-height:1.12; letter-spacing:.01em; }
h1 { font-size:var(--font-size-6); margin:0 0 var(--size-2); }
a { color: var(--accent); text-underline-offset:3px; }
/* Images carry width/height as attributes (the browser reserves the space in
   advance → no layout shift, CLS). For the attributes not to distort the image
   once CSS determines the width, the height must stay free. */
img[width][height] { height:auto; }
a:focus-visible, button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }
.skip { position:absolute; left:-999px; top:0; z-index:60; background:var(--accent); color:#fff; padding:var(--size-2) var(--size-3); }
.skip:focus { left:0; }
.hp { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }
/* Gone for the eye, present for screen readers. Used by the design tab's
 * «Seitentitel anzeigen» switch: the <h1> stays in the document (docs/a11y.md
 * demands exactly one per page) but disappears from view. Deliberately NOT
 * `display:none` or `visibility:hidden` — both would take the text from the
 * screen reader too. `clip-path` instead of the old `clip`, and
 * `white-space:nowrap` so the text does not wrap into single letters in the 1px
 * cell (some screen readers would then spell it out). */
.visually-hidden { position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }
/* GTM-Fallback-iframe unsichtbar halten — CSS-Klasse statt Inline-Style (CSP style-src 'self'). */
.gtm-noscript { display:none; visibility:hidden; }

/* Admin bar top left — visible only to logged-in editors: back to the admin plus
   a jump into the backend editor (both icon-only, name via aria-label), plus a
   draft notice where applicable. It sits above the page and deliberately reserves
   no space: the header should sit the same for editors as for visitors. The
   colours are the backend sidebar's (app.css --sidebar*), as literals here —
   app.css is not loaded in the frontend (ADR-0011). */
.admin-tools { position:fixed; top:0; left:0; z-index:50; display:flex; align-items:stretch; max-width:100vw; }
.admin-return, .admin-edit { display:inline-flex; align-items:center; justify-content:center;
    background:#1c1917; color:#ede9e6; text-decoration:none; border:1px solid #1c1917; padding:.5rem; }
/* A hairline between the two icons, otherwise they merge into one surface. */
.admin-edit { border-left-color:#332e2a; }
.admin-return:hover, .admin-edit:hover { background:#332e2a; border-color:#332e2a; color:#fff; }
.admin-return:focus-visible, .admin-edit:focus-visible { outline:2px solid #2dbca6; outline-offset:2px; }
.admin-return svg, .admin-edit svg { display:block; }

/* Draft preview: a notice bar next to back/edit (a flex child of the admin bar).
   Visible only when logged in — for visitors a draft is a 404. */
.draft-note { margin:0; display:inline-flex; align-items:center; padding:0 .75rem;
    min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    background:var(--yellow-2); color:var(--gray-9); border:1px solid var(--yellow-5); border-left:0;
    font-family:var(--font-head); font-weight:var(--font-weight-6); font-size:13px; letter-spacing:.02em; }

/* ── Blueprint-Primitive (eckig, Haarlinie) ── */
/* The duotone wash was deliberately removed: images in real colours, no accent
   filter. The .duotone wrappers remain as layout containers (crop, image width)
   but carry no colour overlay. */
.blueprint { position:relative; border:1px solid var(--border); border-radius:0; }
.blueprint.duotone { overflow:visible; }
.duotone { position:relative; overflow:hidden; display:block; }
.duotone img { width:100%; display:block; }

/* Button — the primary button is the one filled object */
.btn { display:inline-flex; align-items:center; justify-content:center; gap:6px; cursor:pointer; text-decoration:none;
    font-family:var(--font-head); font-weight:var(--font-weight-6); font-size:15px; line-height:1.2; letter-spacing:.02em;
    color:var(--ink); background:transparent; border:1px solid var(--border); border-radius:0; padding:.6rem 1.1rem; }
.btn-primary { background:var(--accent); color:#fff; border-color:var(--accent); }
.btn-primary:hover { background:var(--accent-hover); }
.btn-primary:active { background:var(--blue-10); }

/* — Kopf / Marke — */
.site-header { border-bottom:1px solid var(--border); position:relative; }
.site-header .bar { max-width:var(--container); margin:0 auto; padding:var(--size-3) var(--gutter);
    display:flex; justify-content:space-between; align-items:center; gap:var(--size-3); }
.brand { display:inline-flex; flex-direction:column; line-height:1.1; text-decoration:none; color:var(--ink); }
.brand-title { font-family:var(--font-head); font-weight:var(--font-weight-7); font-size:1.4rem; letter-spacing:.01em; }
.brand-tagline { font-size:.8rem; font-weight:var(--font-weight-4); color:var(--muted); }
/* Logo: 200px width is the default, not the upper bound of a frame — a landscape
 * tradesperson logo should carry the header. `object-fit:contain` is the guard
 * against a portrait or square logo distorting at that width: it keeps its aspect
 * ratio and is capped by `max-height` instead of being squeezed into the box. */
.brand-logo { display:block; width:var(--logo-width); max-width:100%; height:auto;
    max-height:var(--logo-max-height); object-fit:contain; object-position:left center; }
.header-right { display:flex; align-items:center; gap:var(--size-3); }

/* Sprach-Dropdown */
.lang-dropdown { position:relative; }
.lang-current { display:inline-flex; align-items:center; gap:.35rem; font-weight:var(--font-weight-6); font-size:.85rem;
    color:var(--ink); background:var(--surface); border:1px solid var(--border); border-radius:0; padding:.35rem .6rem; cursor:pointer; }
.lang-current .caret { color:var(--muted); font-size:.75rem; }
.lang-current[aria-expanded="true"] .caret { transform:rotate(180deg); }
.lang-menu { list-style:none; margin:.35rem 0 0; padding:.3rem; position:absolute; top:100%; right:0;
    min-width:150px; background:#fff; border:1px solid var(--border); box-shadow:var(--pop); z-index:25; }
.lang-menu a { display:block; text-decoration:none; color:var(--ink); padding:var(--size-2) .7rem; }
.lang-menu a:hover { background:var(--surface); }
.lang-menu a[aria-current] { font-weight:var(--font-weight-7); color:var(--accent); }

/* — Navigation (Desktop-Leiste + Offcanvas teilen die Listen-Styles) — */
.menu { list-style:none; display:flex; gap:var(--size-1); margin:0; padding:0; align-items:center; }
.main-desktop { display:none; }
.menu-item { position:relative; }
.menu-item > a { text-decoration:none; font-weight:var(--font-weight-6); color:var(--ink); padding:var(--size-2) .6rem; display:inline-block; }
.menu-item > a:hover { color:var(--accent); }
.menu-item > a[aria-current] { color:var(--accent); text-decoration:underline; text-underline-offset:5px; }
.sub-toggle { background:none; border:0; cursor:pointer; font-size:.8rem; color:var(--muted); padding:.4rem .35rem; line-height:1; }
.sub-toggle[aria-expanded="true"] span { display:inline-block; transform:rotate(180deg); }
.submenu { list-style:none; margin:0; padding:.4rem; }
.submenu a { text-decoration:none; color:var(--ink); display:block; padding:var(--size-2) .7rem; white-space:nowrap; }
.submenu a:hover { background:var(--surface); }
@media (min-width:721px) {
    .submenu:not([hidden]) { position:absolute; top:100%; left:0; min-width:200px;
        background:#fff; border:1px solid var(--border); box-shadow:var(--pop); z-index:20; }
    .burger { display:none; }
    .site-menu { display:none; }
    .main-desktop { display:block; border-top:1px solid var(--border); }
    .main-desktop .menu { max-width:var(--container); margin:0 auto; padding:var(--size-1) var(--gutter) var(--size-2); }
}

/* Burger */
.burger { display:none; width:44px; height:44px; background:none; border:1px solid var(--border); cursor:pointer; position:relative; }
.burger-box, .burger-box::before, .burger-box::after { content:""; position:absolute; left:50%; width:22px;
    height:2px; background:var(--ink); transform:translateX(-50%); transition:transform .2s, opacity .2s; }
.burger-box { top:50%; margin-top:-1px; }
.burger-box::before { top:-7px; } .burger-box::after { top:7px; }
.burger[aria-expanded="true"] .burger-box { background:transparent; }
.burger[aria-expanded="true"] .burger-box::before { transform:translateX(-50%) translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] .burger-box::after { transform:translateX(-50%) translateY(-7px) rotate(-45deg); }

/* Mobile: Offcanvas */
@media (max-width:720px) {
    .burger { display:block; }
    /* Brand and burger share a 375px row — a 200px logo no longer fits next to it
     * without crowding. */
    :root { --logo-width: 150px; --logo-max-height: 64px; }
    .offcanvas-backdrop { position:fixed; inset:0; background:color-mix(in srgb, var(--gray-9) 45%, transparent); z-index:30; }
    .site-menu { position:fixed; top:0; right:0; bottom:0; width:min(80vw,320px); background:#fff;
        z-index:40; padding:5rem var(--size-4) var(--size-6); overflow-y:auto; box-shadow:var(--shadow-5);
        transform:translateX(100%); transition:transform .25s ease; visibility:hidden; border-left:1px solid var(--border); }
    body.nav-open .site-menu { transform:translateX(0); visibility:visible; }
    body.nav-open { overflow:hidden; }
    .site-menu .menu { flex-direction:column; align-items:stretch; gap:.15rem; }
    .menu-item { display:flex; flex-wrap:wrap; align-items:center; }
    .menu-item > a { flex:1; padding:var(--size-3) var(--size-2); font-size:1.05rem; }
    .sub-toggle { width:44px; height:44px; font-size:1rem; border:1px solid var(--border); }
    .submenu { flex-basis:100%; padding-left:var(--size-3); }
    .submenu a { padding:.6rem var(--size-2); }
}
@media (prefers-reduced-motion:reduce) {
    .site-menu, .burger-box, .burger-box::before, .burger-box::after { transition:none; }
}

/* — Rumpf — */
main { flex:1; width:100%; max-width:var(--container); margin:0 auto; padding:var(--size-8) var(--gutter); }
.lead { font-size:1.15rem; color:var(--muted); margin:0 0 var(--size-7); }

/* — Breadcrumbs — the visible path belonging to the BreadcrumbList schema (Google
   only shows it in the snippet when it is on the page too). Hairline look like the
   rest of the blueprint theme. */
.breadcrumbs { margin:0 0 var(--size-6); font-size:.875rem; color:var(--muted); }
.breadcrumbs ol { list-style:none; display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--size-2); margin:0; padding:0; }
.breadcrumbs li { display:flex; align-items:center; gap:var(--size-2); }
.breadcrumbs li + li::before { content:"›"; color:var(--border); }
.breadcrumbs a { color:inherit; text-decoration:none; border-bottom:1px solid var(--border); }
.breadcrumbs a:hover, .breadcrumbs a:focus-visible { color:var(--ink); border-bottom-color:var(--accent); }
.breadcrumbs [aria-current="page"] { color:var(--ink); }
.site-footer { border-top:1px solid var(--border); color:var(--muted); font-size:.9rem; }
.site-footer .bar { max-width:var(--container); margin:0 auto; padding:var(--size-6) var(--gutter); }
.footer-nav { margin-bottom:var(--size-3); }
.footer-menu { list-style:none; display:flex; flex-wrap:wrap; gap:var(--size-2) var(--size-6); margin:0; padding:0; }
.footer-menu > li > a { color:var(--ink); text-decoration:none; font-weight:var(--font-weight-6); }
.footer-menu a:hover { color:var(--accent); }
.footer-menu ul { list-style:none; margin:.35rem 0 0; padding:0; display:flex; flex-direction:column; gap:.2rem; }
.footer-menu ul a { color:var(--muted); text-decoration:none; }
.footer-note { display:block; }

/* Bottom row: copyright, legal texts, cookie link. It wraps on narrow screens
   instead of overflowing — the legal texts are the one part whose length the
   business determines itself. */
.footer-bottom { display:flex; flex-wrap:wrap; align-items:baseline;
    gap:var(--size-2) var(--size-5); margin-top:var(--size-3); }
.footer-bottom .footer-note { display:inline; }
.footer-copyright { color:var(--ink); }
/* The list order = the order in the «Rechtstexte» area (top → left). */
.footer-legal ul { list-style:none; display:flex; flex-wrap:wrap;
    gap:var(--size-2) var(--size-4); margin:0; padding:0; }
.footer-legal a { color:var(--muted); text-decoration:none; }
.footer-legal a:hover { color:var(--accent); text-decoration:underline; }

/* Footer contact block from the central company store. */
.footer-contact { margin-bottom:var(--size-3); }
.company-contact { font-style:normal; line-height:1.6; color:var(--muted); }
.company-contact strong { color:var(--ink); font-weight:var(--font-weight-6); }
.company-contact a { color:var(--ink); text-decoration:none; }
.company-contact a:hover { color:var(--accent); }

/* Social channels from the company profile. Deliberately in site.css and not in
   the block CSS: the same row appears in the footer AND in rich text through the
   `%social%` / `%…_link%` placeholders — those have no block whose stylesheet
   could be loaded. blocks/social.css only adds the block's own arrangement. */
.footer-social { margin-bottom:var(--size-3); }
.social-links { list-style:none; display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--size-2) var(--size-3); margin:0; padding:0; }
.social-link { display:inline-flex; align-items:center; gap:.4rem; color:var(--muted);
    text-decoration:none; line-height:1; }
.social-link svg { width:1.35rem; height:1.35rem; flex:none; }
.social-link:hover, .social-link:focus-visible { color:var(--accent); }
.social-link span { font-weight:var(--font-weight-6); }
/* In running text the icon sits on the baseline, not on its own line. */
p .social-link svg { width:1.1em; height:1.1em; }
p .social-links { display:inline-flex; vertical-align:middle; }

/* ── Blocks ── */
/* Shared base only. Block-specific styles are self-contained in the block
   components (blocks/<type>/ → public/assets/blocks/<type>.css) and are loaded by
   the layout only when that block occurs on the page. */
.block { margin: 0 0 var(--size-7); }
.block h2 { font-size:var(--font-size-4); margin:0 0 var(--size-4); }

/* Rich-text output — ONE rule set for every carrier of sanitized HTML: text
   block, page intro (.lead), image+text body and FAQ answer. New rich-text fields
   belong in this list, not in a copy of their own. */
.block-text > :last-child, .lead > :last-child,
.it-body > :last-child, .faq-answer > :last-child { margin-bottom:0; }
.block-text h2, .lead h2, .it-body h2, .faq-answer h2 { font-size:var(--font-size-4); margin:var(--size-5) 0 var(--size-3); }
.block-text h3, .lead h3, .it-body h3, .faq-answer h3 { font-size:var(--font-size-3); margin:var(--size-4) 0 var(--size-2); }
.block-text ul, .block-text ol, .lead ul, .lead ol,
.it-body ul, .it-body ol, .faq-answer ul, .faq-answer ol { margin:0 0 var(--size-3); padding-left:1.5rem; }
.block-text li, .lead li, .it-body li, .faq-answer li { margin:0 0 .35rem; }
.block-text blockquote, .lead blockquote, .it-body blockquote, .faq-answer blockquote {
    margin:0 0 var(--size-3); padding-left:var(--size-4);
    border-left:2px solid var(--accent); color:var(--muted); }

/* Password gate for protected pages (status=protected) */
.page-protected { max-width: 30rem; margin: var(--size-6) auto; }
.pw-form { display: flex; flex-direction: column; gap: var(--size-2); margin-top: var(--size-4); }
.pw-form label { font-weight: var(--font-weight-6); }
.pw-form input[type=password] { padding: .6rem .7rem; font: inherit; border: 1px solid var(--border); background: #fff; border-radius: 0; }
.pw-form button { align-self: flex-start; background: var(--accent); color: #fff; border: 1px solid var(--accent);
    padding: .55rem var(--size-4); font: inherit; font-weight: var(--font-weight-6); cursor: pointer; border-radius: 0; }
.pw-form button:hover { background: var(--blue-9); }
.pw-error { color: var(--red-7); font-weight: var(--font-weight-6); }

/* Kontaktformular (form-Block) — geteilte Formular-Grundstyles inkl. Honeypot. */
.block-form { padding:var(--size-6); }
.block-form h2 { margin:0 0 var(--size-3); }
.form-field { margin-bottom:var(--size-3); }
.block-form label { display:block; font-size:.8rem; margin-bottom:5px; color:var(--gray-7); }
.block-form input[type=text], .block-form input[type=email], .block-form textarea {
    width:100%; min-height:38px; padding:.5rem .7rem; font:inherit; color:var(--ink);
    caret-color:var(--accent); background:var(--surface); border:1px solid var(--border); border-radius:0; }
.block-form textarea { min-height:110px; resize:vertical; }
.block-form input:focus-visible, .block-form textarea:focus-visible { border-color:var(--accent); outline:2px solid var(--accent); outline-offset:0; }
.form-ok { background:var(--ok-bg); color:var(--ok-ink); border:1px solid var(--ok-border); padding:.75rem var(--size-3); margin-bottom:var(--size-3); }
.form-err { background:var(--err-bg); color:var(--err-ink); border:1px solid var(--err-border); padding:.75rem var(--size-3); margin-bottom:var(--size-3); }

/* Card base — services and team share .cards/.card. */
.cards { display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:var(--size-5); }
.card { padding:var(--size-4); }
/* Optional card icon (icon field → Icons::svg): inherits the accent colour
   through currentColor, scales sharply, costs no extra request. */
.card-icon { display:block; width:26px; height:26px; margin-bottom:.5rem; color:var(--accent); }
.card h3 { margin:0 0 .4rem; font-size:1.15rem; }
.card p { margin:0; color:var(--muted); font-size:.95rem; }
/* Bullet list plus read-more link in service cards. */
.card-list { margin:.6rem 0 0; padding:0 0 0 1.1rem; color:var(--muted); font-size:.95rem; }
.card-list li { margin:.2rem 0; }
.card-list li::marker { color:var(--accent); }
.card-link { display:inline-block; margin-top:.7rem; color:var(--accent);
    font-weight:var(--font-weight-6); font-size:.95rem; text-decoration:none; }
.card-link:hover, .card-link:focus-visible { text-decoration:underline; }

/* ── News ── */
/* Einzelbeitrag */
.news-back { margin:0 0 var(--size-3); font-size:.9rem; }
.news-back a { color:var(--muted); text-decoration:none; }
.news-back a:hover { color:var(--accent); }
.news-single-head { margin-bottom:var(--size-6); }
.news-date { color:var(--muted); font-size:.9rem; margin:var(--size-2) 0 0; }

/* Index — post grid */
.news-grid { list-style:none; margin:0; padding:0; display:grid;
    grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:var(--size-6); }
.news-card-link { display:flex; flex-direction:column; height:100%; text-decoration:none; color:inherit;
    border:1px solid var(--border); border-radius:0; background:var(--surface); }
.news-card-link:hover { border-color:var(--accent); }
.news-card-body { display:flex; flex-direction:column; gap:.4rem; padding:var(--size-4); }
.news-card-date { color:var(--muted); font-size:.78rem; text-transform:uppercase; letter-spacing:.05em; }
.news-card-title { font-family:var(--font-head); font-weight:var(--font-weight-7); font-size:1.15rem; line-height:1.2; color:var(--ink); }
.news-card-link:hover .news-card-title { color:var(--accent); }
.news-card-teaser { color:var(--muted); font-size:.92rem; }

/* ── Referenzen ── */
/* Einzelseite */
.ref-back { margin:0 0 var(--size-3); font-size:.9rem; }
.ref-back a { color:var(--muted); text-decoration:none; }
.ref-back a:hover { color:var(--accent); }
.ref-single-head { margin-bottom:var(--size-6); }
.ref-cat { color:var(--accent); font-size:.8rem; text-transform:uppercase; letter-spacing:.06em; font-weight:var(--font-weight-7); margin:0 0 var(--size-1); }
.ref-meta { color:var(--muted); font-size:.9rem; margin:var(--size-2) 0 0; }
.ref-website { margin:var(--size-3) 0 0; }
.ref-website a { color:var(--accent); font-weight:var(--font-weight-6); text-decoration:none; }
.ref-website a:hover, .ref-website a:focus-visible { text-decoration:underline; }
.ref-gallery { display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:var(--size-4); margin-bottom:var(--size-6); }
.ref-gallery img { display:block; width:100%; height:auto; }

/* Index — project tiles */
.ref-grid { list-style:none; margin:0; padding:0; display:grid;
    grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:var(--size-6); }
.ref-card-link { display:flex; flex-direction:column; height:100%; text-decoration:none; color:inherit;
    border:1px solid var(--border); border-radius:0; background:var(--surface); }
.ref-card-link:hover { border-color:var(--accent); }
.ref-card-media { display:block; }
.ref-card-media img { display:block; width:100%; height:auto; aspect-ratio:3/2; object-fit:cover; }
.ref-card-body { display:flex; flex-direction:column; gap:.4rem; padding:var(--size-4); }
.ref-card-cat { color:var(--accent); font-size:.72rem; text-transform:uppercase; letter-spacing:.06em; font-weight:var(--font-weight-7); }
.ref-card-title { font-family:var(--font-head); font-weight:var(--font-weight-7); font-size:1.15rem; line-height:1.2; color:var(--ink); }
.ref-card-link:hover .ref-card-title { color:var(--accent); }
.ref-card-meta { color:var(--muted); font-size:.85rem; }

/* ── Icon size floor against 300×150 ────────────────────────────────────────
   The counterpart to the rule in app.css, for the frontend. `Icons::svg()` (the
   icon field, card icons, block templates) emits only a `viewBox` — a block that
   renders an icon and sets no size in blocks/<type>.css would otherwise get
   300×150 in the middle of the page. Specificity 0 through `:where()` so every
   block rule wins; `:not([width])` leaves SVGs with their own size alone. */
:where(svg:not([width])) { width: 1em; height: auto; }

/* ── `hidden` holds again, whatever else is set ─────────────────────────────
   The counterpart to the rule at the end of app.css, for the frontend. Scattered
   `.foo[hidden] { display: none }` patches exist here too (blocks/form.css five
   times, gallery.css, cookie-banner.css) — each for a place where an own
   `display` rule beat the UA `[hidden]`. `!important`, because block CSS
   (public/assets/blocks/<type>.css) loads conditionally AFTER site.css and an
   equally specific class there would otherwise win by order. */
[hidden] { display: none !important; }
