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

    :focus-visible {
        outline-offset: 3px;
    }

    html {
        -webkit-text-size-adjust: none;
        text-size-adjust: none;

        line-height: 1.5;
        scrollbar-gutter: stable;
    }

    body{
        margin: 0;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    h1 {
        font-size: 2em;
        margin-block: 0.67em;
    }

    abbr[title] {
        cursor: help;
        text-decoration-line: underline;
        text-decoration-style: dotted;
    }

    @media (forced-colors: active) {
        mark {
            color: HighlightText;
            background-color: Highlight;
        }
    }

    audio,
    iframe,
    img,
    svg,
    video {
        max-block-size: 100%;
        max-inline-size: 100%;
    }

    fieldset {
        min-inline-size: 0;
    }

    label:has(+ input:not([type="radio"], [type="checkbox"]), select, textarea) {
        display: block;
    }

    textarea:not([rows]) {
        min-block-size: 6em;
    }

    button,
    input,
    select,
    textarea {
        font-family: inherit;
        font-size: inherit;
    }

    [type="search"] {
        -webkit-appearance: textfield;
    }

    @supports (-webkit-touch-callout: none) {
        [type="search"] {
            border: 1px solid -apple-system-secondary-label;
            background-color: canvas;
        }
    }

    input:where([type="tel"], [type="url"], [type="email"], [type="number"]):not(:placeholder-shown) {
        direction: ltr;
    }

    table {
        border-collapse: collapse;
        border: 1px solid;
    }

    th,
    td {
        border: 1px solid;
        padding: 0.25em 0.5em;
        vertical-align: top;
    }

    dialog::backdrop {
        background: oklch(0% 0 0 / 0.3);
    }

    dialog,
    [popover],
    dialog::backdrop {
        opacity: 0;
        transition: opacity 150ms ease-out, display 150ms allow-discrete,
        overlay 150ms allow-discrete;
    }

    dialog[open],
    :popover-open,
    dialog[open]::backdrop {
        opacity: 1;
    }

    @starting-style {
        dialog[open],
        :popover-open,
        dialog[open]::backdrop {
            opacity: 0;
        }
    }

    [hidden]:not([hidden="until-found"]) {
        display: none !important;
    }

    /* Der klebende Header überdeckte sonst das Ziel jedes Sprunglinks — den
       Skip-Link ebenso wie einen Anker aus dem Inhalt. gb.js misst die Höhe. */
    @media (width >= 48rem){
        :root{
            scroll-padding-block-start: calc(var(--header-height, 0px) + 1rem);
        }
    }

    /* Set by gb.js while the mobile navigation overlay is open. */
    body.nav-open{
        overflow: hidden;
    }

    img {
        display: block;
    }

    summary {
        cursor: default;
    }

    iframe {
        border: none;
    }

    @supports(position-area: block-end span-inline-end) {
        [popover] {
            margin: 0;
            position-area: block-end span-inline-end;
        }
    }

    h1, h2, h3, h4, h5, h6{ font-weight: normal; }
    h1, h2, h3, h4, h5, h6, p, ul, ol, dl, dd{  margin: 0; padding: 0; }

    /* Every heading is balanced, rather than the `.balance` utility being
       remembered per template — it had been set on maybe a third of them.
       Browsers cap balancing at a few lines and ignore it beyond that, so long
       headings simply fall back to normal wrapping. */
    h1, h2, h3, h4, h5, h6{
        text-wrap: balance;

        /* Trennung für Überschriften. Deutsche Komposita wie
           „Datenschutzerklärung" sind länger als manche Smartphone-Zeile; ohne
           Trennung ragen sie heraus oder erzwingen eine unschön kurze Zeile
           davor. Getrennt wird nach den Regeln der Sprache aus dem
           lang-Attribut, das im Layout je Site gesetzt ist — es gibt hier also
           nichts einzustellen.

           `overflow-wrap` als Auffangnetz: Fehlt einem Browser das
           Trennwörterbuch, bricht das Wort wenigstens hart um, statt die Seite
           zu verbreitern. */
        hyphens: auto;
        overflow-wrap: break-word;
    }

    /* Body copy gets `pretty` rather than `balance`: it leaves line filling
       alone and only prevents a single word ending up on the last line. Unlike
       `balance` it keeps working on long text. Browsers without support ignore
       it and wrap as before. */
    p{ text-wrap: pretty; }
}

@layer base {
    @font-face {
        font-family: "Valore";
        src: url("/assets/webfonts/valore-pro/ValorePro-Regular.woff2") format("woff2");
        font-weight: normal;
        font-style: normal;
        font-display: swap;
    }
    @font-face {
        font-family: "Valore";
        src: url("/assets/webfonts/valore-pro/ValorePro-Bold.woff2") format("woff2");
        font-weight: 700;
        font-style: normal;
        font-display: swap;
    }

    @font-face {
        font-family: 'SofiaPro';
        src: url('/assets/webfonts/sofia-pro-regular.woff2') format('woff2');
        font-weight: normal;
        font-style: normal;
        font-display: swap;
    }

    @font-face {
        font-family: 'SofiaPro';
        src: url('/assets/webfonts/sofia-pro-bold.woff2') format('woff2');
        font-weight: bold;
        font-style: normal;
        font-display: swap;
    }

    html{
        /* The design is light throughout. Without this, dark-mode browsers paint a
           black canvas and the dark text becomes unreadable. */
        color-scheme: light;

        --color-anthrazit: rgb(42,38,37);
        --color-greige: rgb(217,212,204);
        --color-taupe: rgb(88,80,72);
        --color-mint: rgb(141,189,181);

        /* Nur für Formularfehler. 6.25:1 auf Greige, 9.22:1 auf Weiß. */
        --color-error: rgb(122,48,38);
        --color-button: var( --color-taupe );

        --padding-side: clamp( 1rem, 4vw, 4rem);

        /* Abstand zwischen den Abschnitten einer Seite — eine Quelle statt
           eines margin-block je Abschnitt. */
        --section-gap: clamp( 3rem, 6vw, 5rem );

        /* Lead type: the step between headings (5rem) and body copy (1rem).
           Without it a 16px paragraph sits directly under an 80px line. */
        --font-size-lead: clamp( 1.125rem, 1.4vw, 1.375rem );
        --line-height-lead: 1.55;

        /* Measure. `ch` is font-relative, so it adapts if the typeface changes.
           Mind the number though: 1ch is the width of "0", not of an average
           character — measured in SofiaPro, 12.98px against 9.92px, so 1ch is
           roughly 1.3 characters and the usual "60–75ch" rule would run far
           too wide. 50ch lands at ~65 characters. */
        --measure-lead: 70ch;

        /* Long-form copy (legal pages) may run slightly wider than a lead —
           56ch is ~72 characters here. */
        --measure-body: 56ch;

        /* — Serif heading scale ————————————————————————————————
           Valore's cap height is ~50% of its font size, SofiaPro's ~69%. The eye
           compares letter height, not font size, so every Valore size needs about
           1.4x to look equal — that correction is baked into the values below.
           Comments give the resulting optical size against 16px body copy, whose
           cap height is 11px. */
        --font-serif-1: clamp(2.5rem, 12vw, 5rem);       /* Seitentitel   ~3,6× */
        --font-serif-2: clamp(2.25rem, 3.8vw, 3.3rem);   /* Abschnitt     ~2,4× */
        --font-serif-3: clamp(2rem, 3.2vw, 2.55rem);     /* Thema/Element ~1,85× */
        --font-serif-4: clamp(1.5rem, 2.2vw, 2rem);      /* Karte/Dialog  ~1,45× */

        /* Maximum stage height (slider and single image alike). Capped so the next
           section always peeks in; svh because mobile browser chrome would
           otherwise hide exactly that peek. */
        --hero-max-block: calc(100svh - var(--header-height, 0px) - 5rem);

        /* Stage ratio (slider, overview header, landing-page hero). On a
           portrait screen a 16:9 strip is a sliver of the photo — flip to an
           upright crop there instead. */
        --hero-ratio: 16 / 9;

        @media (orientation: portrait){
            --hero-ratio: 4 / 5;
        }

        /* Flatter on desktop: otherwise the stage fills over 80% of the viewport
           and the next heading lands exactly on the fold. */
        @media (width >= 64rem){
            --hero-max-block: min(62svh, calc(100svh - var(--header-height, 0px) - 5rem));
        }

        --serif-font: 'Valore', sans-serif;
        --sans-serif-font: 'SofiaPro', sans-serif;
    }

    body{
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;

        background-color: #fff;
        color: var( --color-anthrazit );

        font-family: var(--sans-serif-font);
        line-height: 1.3;
    }

    a {
        cursor: pointer;
        text-underline-offset: 0.25em;
        transition: 0.2s ease-out;

        &:link, &:visited, &:hover, &:active{
            color: inherit;
        }
    }

    button{
        font: inherit;
        border: none;
        border-radius: 0;
        background-color: transparent;
        padding: 0;
        cursor: pointer;
    }

    #skip-to-content-link {
        position: fixed;
        top: 0;

        background: var( --color-anthrazit );
        color: white;
        left: 50%;
        padding: 8px;

        transform: translate(-50%, -150%);
        transition: transform 0.3s;
        z-index: 100;

        border-bottom-left-radius: 3px;
        border-bottom-right-radius: 3px;

        &:focus {
            transform: translate(-50%, 0);
        }
    }

    .visually-hidden:not(:focus):not(:active) {
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        height: 1px;
        overflow: hidden;
        position: absolute;
        white-space: nowrap;
        width: 1px;
    }

    figure{
        margin: 0;
    }

    img, video{
        width: 100%;
        height: auto;
    }
}

@layer utilities {
    .text-left{ text-align: left; }
    .text-center{ text-align: center; }
    .text-right{ text-align: right; }

    .serif-font{ font-family: var( --serif-font ); }
    .sans-serif-font{ font-family: var( --sans-serif-font ); }

    .uppercase{text-transform: uppercase;}

    .tracking-120{ letter-spacing: 0.12em; }

    /* Also applied to the apartment intro headline, which comes from a CK field
       and so can't carry the class itself. */
    .font-size-xl,
    .single-apartment .intro__text h2{ font-size: var( --font-serif-1 ); line-height: .8; }

    .balance{ text-wrap: balance; }
    .hyphens{ hyphens: auto; }

    .content-width{
        max-width: 75rem;
        margin-inline: auto;
        padding-inline: var( --padding-side );
    }

    /* Unbulleted lists. Bound to `role="list"` because Safari strips list
       semantics from VoiceOver when `list-style: none` is set — the attribute
       restores them. One rule instead of a reset per list. */
    ul[role="list"],
    ol[role="list"]{
        list-style: none;
        margin: 0;
        padding: 0;
    }

    /* …but not when the list is also the page container: the attribute selector
       above outweighs `.content-width`, so a list carrying both lost its side
       padding and its content sat flush against the viewport edge. On the
       apartment list that pushed the cards' negative bleed off-screen and
       produced a horizontal scrollbar below ~390px.

       `margin` loses to the same rule, so such a list was not centred either:
       it sat flush left while every sibling section was centred, and the
       apartment grid ended a good 30px short of the intro above it. */
    ul[role="list"].content-width,
    ol[role="list"].content-width{
        margin-inline: auto;
        padding-inline: var( --padding-side );
    }

    /* Intro copy: the step between heading and body text. Deliberately a
       utility rather than bound to body classes, so it applies on any new page. */
    .lead{
        max-inline-size: var( --measure-lead );
        font-size: var( --font-size-lead );
        line-height: var( --line-height-lead );
    }

    /* Centred in the measure when the text is centred. */
    .lead.text-center{
        margin-inline: auto;
    }
}

@layer gb{

    /* Vertical rhythm. Every section is a direct child of <main>, so three
       rules replace a margin-block on each one. New sections inherit the
       spacing automatically. */
    main{
        padding-block-end: var( --section-gap );
    }

    main > * + *{
        margin-block-start: var( --section-gap );
    }

    /* The first section clears the header — except full-bleed stages, which
       deliberately sit flush against it. */
    main > :first-child:not(.slider, .hero-video, .overview-header, .lp-hero){
        margin-block-start: var( --section-gap );
    }

    /* Stages stay flush even when a visually-hidden h1 precedes them (home
       page): the sibling rule above would otherwise hand them the full gap. */
    main > :is(.slider, .hero-video, .overview-header, .lp-hero){
        margin-block-start: 0;
    }

    /* Centred message pages — 404, error, booking confirmed and failed. The
       reset strips margins from headings and paragraphs, so headline, lead and
       buttons sat flush against one another; only the button brought spacing of
       its own. Same idea as the rule above, one level down. 2rem matches
       `.lp-button`'s own top margin, so a button as a direct child keeps the
       same rhythm as everything else. */
    .message > * + *{
        margin-block-start: 2rem;
    }

    #main-header{

        padding-block: 2rem;
        background-color: var( --color-greige );
        position: relative;

        /* Own stacking context, above the page. Without it the slider's arrows
           and pagination — positioned with a z-index of their own further down
           the document — painted straight through the mobile nav overlay. */
        z-index: 10;

        /* Ab Tablet klebt der Header oben und weicht beim Runterscrollen nach
           oben weg; gb.js setzt die Klasse. Nur hier oben: Am Telefon ist der
           Header Anker des Overlays und muss stehen bleiben, und ein wegwischender
           Header kostet auf kleinen Displays mehr, als er bringt. */
        @media (width >= 48rem){
            position: sticky;
            inset-block-start: 0;
            transition: transform 0.3s ease;

            &.is-hidden{
                transform: translateY(-100%);
            }

            @media (prefers-reduced-motion: reduce){
                transition-duration: 0s;
            }
        }

        .content-width{
            display: grid;
            grid-template-columns: 1fr auto 1fr;
            align-items: center;
            gap: 2rem;
        }

        /* Spans the full row, but never places anything in the middle track,
           so the logo sits in the gap it leaves. */
        nav {
            grid-area: 1 / 1 / 1 / -1;
            display: grid;
            grid-template-columns: subgrid;
            align-items: center;
        }

        ul {
            grid-row: 1;
            display: flex;
            align-items: center;   /* CTA-Pill vertikal mit den Text-Links ausrichten */
            gap: 2rem;
            list-style: none;
            margin: 0;
            padding: 0;
            justify-content: space-evenly;
        }

        /* Addressed by type index, not :first-child/:last-child: the nav holds
           a third list on top of the two link groups — the language switcher,
           which is itself a <ul> and would otherwise claim the right track and
           push the second group into the middle one, on top of the logo. */
        ul:nth-of-type(1) {
            grid-column: 1;
        }

        ul:nth-of-type(2) {
            grid-column: 3;
        }

        .logo {
            grid-area: 1 / 2;

            /* Paints above <nav>, which overlaps it — without this the nav box
               swallows clicks meant for the logo. */
            z-index: 1;

            img{
                height: 2.8rem;
                width: auto;
            }
        }

        /* The toggle only exists below 48rem; above it the split nav is shown.
           Sized to the 44px minimum tap target, which the bars alone miss. */
        .nav-toggle{
            display: none;
            grid-area: 1 / 3;
            justify-self: end;
            z-index: 1;
            min-inline-size: 2.75rem;
            min-block-size: 2.75rem;
            place-items: center;
        }

        /* Three bars drawn from one element: the middle is the box itself, the
           outer two are its pseudo-elements, offset by transform so they can
           animate. Open, the outer bars glide to the centre and tilt ±45° into
           an X while the middle one fades — no bar turns more than a quarter,
           which keeps the movement quiet. The middle fades via background, not
           opacity: the pseudo-elements would inherit the latter. */
        .nav-toggle__bars,
        .nav-toggle__bars::before,
        .nav-toggle__bars::after{
            display: block;
            inline-size: 1.5rem;
            block-size: 1px;
            background: currentColor;
            transition: transform 0.3s ease, background-color 0.2s ease;
        }

        .nav-toggle__bars{
            position: relative;
        }

        .nav-toggle__bars::before,
        .nav-toggle__bars::after{
            content: "";
            position: absolute;
            inset-inline: 0;
            transform: translateY(-0.5rem);
        }

        .nav-toggle__bars::after{
            transform: translateY(0.5rem);
        }

        .nav-toggle[aria-expanded="true"] .nav-toggle__bars{
            background: transparent;
        }

        .nav-toggle[aria-expanded="true"] .nav-toggle__bars::before{
            transform: rotate(45deg);
        }

        .nav-toggle[aria-expanded="true"] .nav-toggle__bars::after{
            transform: rotate(-45deg);
        }

        /* Keeps the same 1fr auto 1fr grid as on desktop: the logo stays in the
           middle track and is therefore centred, with the toggle in the right
           one. Only the nav moves to its own row. */
        @media (width < 48rem) {
            padding-block: 1rem;

            /* A smaller gap leaves both outer tracks wider than the toggle, so
               they stay equal and the middle track — the logo — is truly
               centred. No row gap: the collapsed nav keeps its grid row and
               would otherwise pad out the header. */
            .content-width{ gap: 0 1rem; }

            .logo img{ height: 2.2rem; }

            .nav-toggle{ display: grid; }

            /* Full-viewport overlay rather than a panel that grows the header.
               Fixed, so the page underneath keeps its position; gb.js locks
               body scrolling while it is open, which also keeps the header —
               and with it the close button — on screen.

               `visibility` carries the discrete step and is delayed by the
               fade on the way out, so the links leave the tab order without
               cutting the transition short. */
            nav{
                position: fixed;
                inset: 0;
                z-index: 1;

                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;

                /* Derselbe Abstand wie innerhalb einer Liste. Die Navigation
                   ist fürs Desktop-Layout in zwei Listen geteilt; im Overlay
                   stehen sie untereinander, und ein größerer Abstand zwischen
                   den Listen ließ die Links ungleichmäßig wirken — 43px an der
                   Nahtstelle gegen 28px sonst. */
                gap: 1.5rem;

                background: var( --color-greige );

                opacity: 0;
                visibility: hidden;
                transition: opacity 0.25s ease, visibility 0s 0.25s;
            }

            nav.is-open{
                opacity: 1;
                visibility: visible;
                transition-delay: 0s;
            }

            nav ul {
                grid-column: auto;
                flex-direction: column;
                align-items: center;
                gap: 1.5rem;
            }

            /* Room to read and to hit: well past the 44px tap target. */
            nav a{
                font-size: 1.375rem;
            }

            /* Toggle and logo stay above the overlay: the header should look
               like it simply stayed put, rather than leaving a lone X. */
            .nav-toggle,
            .logo{
                position: relative;
                z-index: 2;
            }

            /* Only shown inside the overlay — on wider screens the footer
               carries the switcher, and a second one would be a duplicate for
               screen readers as much as for the eye.

               Abgesetzt, weil die Sprachwahl keine Seite ist: Ohne den
               Zwischenraum reihte sie sich als weiterer Menüpunkt ein. */
            .language-switcher{
                flex-direction: row;
                gap: 1.5rem;
                margin-block-start: 1rem;
            }

            @media (prefers-reduced-motion: reduce){
                nav,
                .nav-toggle__bars,
                .nav-toggle__bars::before,
                .nav-toggle__bars::after{
                    transition-duration: 0s;
                }
            }
        }
    }

    /* Language hint — sits between header and main, in the flow. Taupe rather
       than the header's greige so it reads as a separate strip and not as part
       of the header; it is temporary and disappears for good once answered. */
    .language-hint{
        display: flex;
        background-color: var( --color-taupe );
        color: var( --color-greige );
        padding-block: 0.75rem;
        font-size: 0.9375rem;

        .language-hint__inner{
            display: flex;
            flex-wrap: wrap;
            align-items: baseline;
            justify-content: center;
            gap: 0.5rem 1.5rem;
        }

        .language-hint__text{
            margin: 0;
        }

        .language-hint__actions{
            display: flex;
            flex-wrap: wrap;
            align-items: baseline;
            gap: 0.5rem 1.5rem;
        }

        /* Both are actions, so both look like one — the button carries no
           border of its own and would otherwise read as body text. */
        .language-hint__switch,
        .language-hint__dismiss{
            font: inherit;
            color: inherit;
            padding: 0;
            border: 0;
            background: none;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            cursor: pointer;
        }

        .language-hint__dismiss{
            opacity: 0.75;
        }

        .language-hint__switch:hover,
        .language-hint__dismiss:hover{
            text-decoration-thickness: 2px;
            opacity: 1;
        }

        /* Stacked on a phone: side by side the sentence and both actions wrap
           into a ragged block that is harder to scan than three centred rows. */
        @media (width < 48rem){
            text-align: center;

            .language-hint__inner{
                flex-direction: column;

                /* Baseline alignment is for the single row on wide screens; in
                   column direction it governs the horizontal axis instead and
                   would push everything against the left edge. */
                align-items: center;
                gap: 0.5rem;
            }
        }
    }

    .masonry{
        --masonry-gap: 2rem;

        display: grid;
        grid-template-columns: 1fr;
        gap: var( --masonry-gap );
        align-items: start;

        /* Native masonry. Safari 26.4+ ships `grid-lanes`; earlier WebKit builds
           used `masonry`, so declare both and let the valid one win. */
        display: masonry;
        display: grid-lanes;

        @media (width >= 48rem) {
            grid-template-columns: 1fr 1fr;
        }

        .textTile{
            text-wrap: balance;
        }
    }

    /* Set by gb.js only when the browser has neither native value. */
    .masonry.is-polyfilled{
        grid-auto-rows: 1px;
        row-gap: 0;
    }

    .tile{
        figure{
            margin: 0;
        }

        picture{
            display: block;
        }

        img{
            width: 100%;
            height: auto;
        }

        /* Centred until gb.js measures which column the tile landed in; see
           `alignPortraits`. Without JS every portrait stays centred, which is
           the safe reading of the design rather than a broken one. */
        img.portrait{
            width: 80%;
            margin-inline: auto;
        }

        /* Lean towards the middle of the grid. */
        &[data-align="end"] img.portrait{
            margin-inline: auto 0;
        }

        &[data-align="start"] img.portrait{
            margin-inline: 0 auto;
        }

        .headline{
            font-family: "Valore";
        }

        /* Single column below 48rem. Stacked full-width the tiles read as one
           long strip, so images alternate left and right — the shared spine of
           the two-column layout, folded into one. Text stays centred between
           them as the calm counterpoint. */
        @media (width < 48rem){
            img{
                inline-size: 85%;
            }

            img.portrait{
                inline-size: 72%;
            }
        }
    }

    @media (width < 48rem){
        /* Which side a tile leans to is decided in gb.js — a CSS `nth-` cannot
           express it, because the alternation has to count image tiles only and
           skip the text ones between them. */
        .masonry > .tile[data-align="start"] img{
            margin-inline: 0 auto;
        }

        .masonry > .tile[data-align="end"] img{
            margin-inline: auto 0;
        }

        /* The opening image, and any tile the script leaves undecided. */
        .masonry > .tile[data-align="centre"] img{
            margin-inline: auto;
        }

        .masonry > .textTile{
            text-align: center;
        }
    }

    #main-footer{
        color: var( --color-greige );
        background-color: var( --color-taupe );
        padding-block: 3rem;

        img{
            display: block;
            width: 6rem;
            margin-inline: auto;
            margin-block-end: 2rem;
        }

        nav{
            ul{
                display: flex;
                justify-content: center;
                flex-wrap: wrap;

                /* The legal links wrap on narrow screens; without a row gap the
                   wrapped line sat directly under the one above. */
                gap: 0.75em 2em;
                list-style: none;
            }
        }

        .address{
            margin-block-end: 3rem;
        }

        /* "Cookie settings" — reopens the consent dialog. */
        .footer-cookie-settings{
            display: block;
            margin-inline: auto;
            margin-block-start: 2rem;
            padding: 0;
            border: none;
            background: none;
            color: inherit;
            font: inherit;
            font-size: 0.75rem;
            cursor: pointer;
            opacity: 0.85;
        }

        .footer-cookie-settings:hover{
            opacity: 1;
            text-decoration: underline;
        }

        /* Language switcher — centred below the legal nav. */
        .language-switcher{
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 0.5rem;
            margin: 2rem 0 0;
            padding: 0;
            font-size: 0.8rem;

            li{
                display: inline-flex;
                align-items: center;
                gap: 0.5rem;
            }

            li + li::before{
                content: "/";
                opacity: 0.4;
            }

            a{
                text-decoration-color: transparent;
                padding-block: 0.25rem;
            }

            a[aria-current],
            a:hover{
                text-decoration-color: currentColor;
            }
        }
    }

    /* Start-page hero — capped so the content below already peeks in, matching
       the apartment slider / overview header. */


    /* — Apartment entry ——————————————————————————————— */

    /* Video-Bühne der Startseite. Maße wie beim Slider, damit der Wechsel am
       Seitenaufbau nichts ändert. */
    .hero-video{
        position: relative;
        width: 100%;
        aspect-ratio: var( --hero-ratio );
        max-block-size: var( --hero-max-block );

        /* Bis das Video lädt, steht hier dieselbe Fläche wie beim Kartenrahmen
           — kein weißes Loch über der ganzen Bühne. */
        background: var( --color-greige );
    }

    .hero-video__media{
        inline-size: 100%;
        block-size: 100%;
        object-fit: cover;
        display: block;
    }

    /* Gleiche Pille wie beim Slider, damit beide Bühnen sich gleich bedienen. */
    .hero-video__controls{
        position: absolute;
        z-index: 1;
        inset-block-end: 1rem;
        inset-inline-start: 50%;
        transform: translateX(-50%);

        display: flex;
        align-items: center;
        padding: 0.35rem 0.6rem;
        border-radius: 999px;
        background: rgb(0 0 0 / 0.3);
        color: #fff;
    }

    .hero-video__toggle{
        display: flex;
        align-items: center;
        justify-content: center;
        inline-size: 1.5rem;
        block-size: 1.5rem;
        border: 0;
        background: none;
        color: inherit;
        cursor: pointer;

        svg{
            inline-size: 0.85rem;
            block-size: 0.85rem;
        }
    }

    /* Es ist immer genau ein Symbol zu sehen — welches, sagt aria-pressed. */
    .hero-video__toggle .hero-video__play{ display: none; }
    .hero-video__toggle[aria-pressed="true"] .hero-video__pause{ display: none; }
    .hero-video__toggle[aria-pressed="true"] .hero-video__play{ display: block; }

    /* Header slider — used on the homepage and apartment detail pages. */
    .slider{
        /* Full-bleed, sits directly under the header. Capped so the section
           below always peeks in — svh so mobile browser chrome can't hide
           the peek. Pagination/bullet styling is unlayered further down,
           because Swiper's own pagination CSS is unlayered and would
           otherwise win over anything in this layer. */
        width: 100%;
        aspect-ratio: var( --hero-ratio );
        max-block-size: var( --hero-max-block );

        /* Swiper reads these through the cascade fine — nothing competes for
           the custom property itself. White arrows, close to the edge — the
           44px tap target still sits fully inside the stage. */
        --swiper-navigation-color: #fff;
        --swiper-navigation-sides-offset: 1rem;

        .swiper-slide{
            /* Slides are equal height; media crops to fill. */

            figure, picture{
                display: block;
                block-size: 100%;
            }
        }
    }

    .single-apartment{
        .highlights{
            background-color: var( --color-taupe );
            color: var( --color-greige );
            padding-block: 1.5rem;

            dl{
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
                margin: 0 auto;
            }

            /* Native CSS nesting doesn't concatenate like Sass, so `&__item`
               would match nothing — write the class out. */
            .highlights__item{
                padding-block: 0.5rem;
                text-align: center;

                /* Dividers between columns, matching the design. */
                & + &{
                    border-inline-start: 1px solid currentColor;
                }

                dt{ opacity: 0.7; }
                dd{ margin-block-start: 0.35rem; }
            }

            @media (width < 48rem){
                dl{ grid-template-columns: 1fr 1fr; }

                .highlights__item:nth-child(odd){ border-inline-start: none; }
            }
        }

        .intro{

            .intro__text{

                /* The visible hero heading (comes from the description field).
                   Size/line-height come from the shared .font-size-xl rule. */
                h2{
                    font-family: var( --serif-font );
                    margin-block-end: 2rem;
                }

                /* Paragraphs only: the heading lives in the same CK field and
                   keeps its own size. */
                p{
                    max-inline-size: var( --measure-lead );
                    font-size: var( --font-size-lead );
                    line-height: var( --line-height-lead );
                }
            }
        }


        .booking-widget{

            .booking-widget__form{
                display: flex;
                flex-wrap: wrap;
                align-items: end;
                gap: 1.5rem;
                margin-block-start: 2rem;

                label{
                    display: grid;
                    gap: 0.35rem;

                    span{
                        font-size: 0.8rem;
                        opacity: 0.7;
                    }
                }

                input{
                    font: inherit;
                    padding: 0.5rem 0.75rem;
                    border: 1px solid var( --color-taupe );
                    background: transparent;
                }

                button{
                    padding: 0.6rem 1.5rem;
                    border: 1px solid currentColor;
                }
            }

            .booking-widget__result{
                margin-block-start: 1.5rem;
            }

            .booking-widget__status.is-available{ color: var( --color-mint ); }
            .booking-widget__status.is-unavailable{ opacity: 0.7; }

            .booking-widget__price{
                font-size: 1.5rem;
                margin-block-start: 0.5rem;
            }
        }

        .details{
            background-color: var( --color-greige );
            padding-block: 3rem;

            h2{
                padding-block-end: 1rem;
                border-block-end: 1px solid currentColor;
            }

            .details__grid{
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
                gap: 2rem;
                margin-block-start: 2rem;
            }

            .details__item dt{ opacity: 0.7; }
            .details__item dd{ margin-block-start: 0.35rem; }
        }

        .amenities{
            display: flex;
            flex-wrap: wrap;
            gap: 2rem;
            padding: 0;
        }

        .amenity{
            display: flex;
            align-items: center;
            gap: 0.6rem;

            svg{
                width: 1.5rem;
                height: 1.5rem;
                flex: none;
            }
        }
    }

    /* — Apartment overview ————————————————————————————— */

    /* Shared by the apartments overview and the about page. */
    /* Media fill their container. Shared by slider, stage and discover tiles. */
    .slider .swiper-slide :is(img, video),
    .overview-header :is(img, video),
    .discover-tile__media :is(img, video){
        inline-size: 100%;
        block-size: 100%;
        object-fit: cover;
    }

    /* Stage and intro are components, not page quirks. Their class names are
       unique, so binding them to a body class would only stop them applying on
       new pages. */
    .overview-header{
        /* Full-bleed hero, same cap and ratio as the single-apartment slider. */
        position: relative;
        width: 100%;
        aspect-ratio: var( --hero-ratio );
        max-block-size: var( --hero-max-block );

        /* Sicherheitsnetz: nichts kann in den folgenden Text ragen. */
        overflow: hidden;

        /* Fit media by absolute positioning rather than stacked percentage heights.
           Safari does not treat a height derived from `aspect-ratio` as definite,
           so `block-size: 100%` fell back to `auto` and the image rendered at its
           intrinsic ratio. `inset: 0` needs no such resolution. */
        figure,
        picture{
            display: block;
            position: absolute;
            inset: 0;
            margin: 0;
        }

    }

    .overview-intro{
        text-align: center;
    }

    /* Inherits size, leading and measure from the .lead utility and adds only
       the spacing — one source for intro typography. Wrapping is not set here:
       the field renders paragraphs, and those carry `text-wrap: pretty` from
       the reset, which would override anything inherited from this element. */
    .overview-intro__text{
        margin-inline: auto;
        margin-block-start: 1.5rem;
    }

    .apartments-overview,
    .about-page{
        .apartment-list{
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(min(24rem, 100%), 1fr));
            gap: 4rem 2rem;
        }

        .apartment-card{
            img{
                aspect-ratio: 3 / 2;
                object-fit: cover;
            }

            .apartment-card__title{
                font-size: var( --font-serif-4 );
                margin-block: 1rem 0.75rem;

                /* Underline on hover; the accessible name comes from the
                   anchor's aria-label, so this is purely visual. */
                text-decoration: underline;
                text-decoration-color: transparent;
            }

            a{
                display: block;
                text-decoration: none;

                /* Hit area beyond the card without shifting content against the
                   grid (padding equals the negative margin). Kept smaller than the
                   1rem minimum of --padding-side, or the pull would consume that
                   padding exactly and any rounding brings back a scrollbar. */
                margin-block: -1rem;
                padding-block: 1rem;
                margin-inline: -0.75rem;
                padding-inline: 0.75rem;

                &:hover,
                &:focus{
                    background-color: var( --color-taupe );
                    color: var( --color-greige );
                }
            }

            a:hover .apartment-card__title{
                text-decoration-color: currentColor;
            }

            .apartment-card__highlights{
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 0.75rem 1.5rem;

                dt{
                    opacity: 0.7;
                    font-size: 0.8rem;
                }

                dd{
                    margin-block-start: 0.15rem;
                }
            }
        }
    }

    nav{
        a{
            text-decoration-color: transparent;


            &:hover, &:active, &:focus, &[aria-current] {
                text-decoration-color: currentColor;
            }
        }
    }

    /* The header nav carries a language switcher for the mobile overlay. Above
       48rem the footer one is visible, so this copy is removed entirely rather
       than hidden — two switchers would be a duplicate for screen readers. */
    @media (width >= 48rem){
        #main-nav .language-switcher{
            display: none;
        }
    }

    /* — Booking CTA in the nav ————————————————————————— */

    #main-header .nav-cta a{
        display: inline-block;
        padding: 0.55em 1.3em;
        border: 1px solid currentColor;
        border-radius: 999px;
        text-decoration-line: none;
        transition: background-color 0.2s ease-out, color 0.2s ease-out;

        &:hover, &:focus-visible, &[aria-current]{
            background-color: var( --color-button );
            color: var( --color-greige );
        }
    }

    /* Sits right under the stage on the home page. On a phone the full section
       gap pushed it below the fold, and it reads as part of the hero rather
       than as the next section — so it moves up close to the slider. */
    @media (width < 48rem){
        .home-booking{
            margin-block-start: 1.5rem;
        }
    }

    /* — Buchungsformular (hervorgehobene Karte) ————————— */

    .booking-form{
        display: flex;
        flex-wrap: wrap;
        align-items: end;
        gap: 1.25rem 1.5rem;

        background: var( --color-greige );
        padding: clamp(1.25rem, 3vw, 2.25rem);

        /* Schmäler als die Textspalte und zentriert: Über die volle Breite
           zogen sich vor allem Datumsfeld und Absenden-Knopf auseinander,
           ohne dass mehr hineinpasst. */
        max-inline-size: 52rem;
        margin-inline: auto;

        /* Der Bereichswert lautet höchstens „12.10.2026 bis 16.10.2026“.
           Mehr Breite füllt sich nicht, sie zerrt das Feld nur auseinander —
           gilt für das von gb.js erzeugte Feld wie für die beiden nativen
           Datumsfelder, die ohne JavaScript an seiner Stelle stehen. */
        .booking-form__field:has( > .booking-form__range-input ),
        .booking-form__dates .booking-form__field{
            max-inline-size: 22rem;
        }

        /* Die zwei Datumsfelder verhalten sich wie direkte Flex-Items;
           `hidden` (bei aktivem flatpickr) sticht display:contents. */
        .booking-form__dates{
            display: contents;
        }

        .booking-form__range-input{
            cursor: pointer;

            /* Air around the separator ("to" / "bis"). The field value is plain
               text, so single words cannot be targeted — but word-spacing acts on
               its spaces, and those are exactly the two beside the separator. */
            word-spacing: 0.5em;
        }

        /* While only the placeholder shows, keep normal word spacing — otherwise
           "Select dates" would be letterspaced too. */
        .booking-form__range-input:placeholder-shown{
            word-spacing: normal;
        }

        /* Number of nights: positioned below the field so it cannot change the
           field's height, and with it the alignment of the row. */
        .booking-form__field:has(.booking-form__nights){
            position: relative;
        }

        .booking-form__nights{
            position: absolute;
            inset-block-start: calc(100% + 0.3rem);
            inset-inline-start: 0;
            font-size: 0.7rem;
            opacity: 0.7;
            white-space: nowrap;
        }

        /* When the form wraps, the absolutely-positioned nights count sits in
           the row gap, almost touching the next row's label — widen the gap
           only while a count is showing. Single-row layouts have no row gap to
           render, so this changes nothing on desktop. */
        &:has(.booking-form__nights:not(:empty)){
            row-gap: 2.25rem;
        }

        .booking-form__field{
            display: flex;
            flex-direction: column;
            gap: 0.5rem;
            flex: 1 1 9rem;

            label{ font-size: 0.7rem; }

            /* Date fields (direct input children, not the steppers) */
            > input{
                border: 1px solid var( --color-taupe );
                background: #fff;
                padding: 0.7em 0.8em;
                font: inherit;
                color: inherit;
            }
        }

        /* Guest fields: only as wide as their stepper, so no gap opens up.
           Labels stay left-aligned, as on the date field. */
        .booking-form__field:has(.stepper){
            flex: 0 0 auto;
            align-items: start;
        }

        /* Am Telefon dagegen über die volle Breite: Nebeneinander blieben
           rechts 34px ungenutzt, und die Tap-Ziele der Stepper waren kleiner
           als nötig. Zu zweit füllen sie die Zeile exakt aus. */
        @media (width < 48rem){
            .booking-form__field:has(.stepper){
                flex: 1 1 0;
                align-items: stretch;
            }

            .stepper{
                inline-size: 100%;
            }

            .stepper input{
                inline-size: auto;
                flex: 1 1 0;
                min-inline-size: 0;
            }
        }

        .booking-form__submit{
            flex: 1 1 auto;
            align-self: end;

            /* Same vertical box as the fields: identical padding plus a transparent
               border standing in for their 1px one — otherwise the button ends up
               about 3px taller. */
            border: 1px solid transparent;
            padding: 0.7em 1.75em;

            background: var( --color-button );
            color: #fff;
            cursor: pointer;
            letter-spacing: inherit;
            transition: opacity 0.2s ease-out;

            &:hover{ opacity: 0.85; }
        }
    }

    /* — Anfrageformular ————————————————————————————————
       Erbt von .booking-form; ergänzt werden nur die Kontaktfelder und die
       Aufteilung in Abschnitte. */

    .enquiry-form{
        /* Jeder Abschnitt nimmt eine eigene Zeile ein, innerhalb bleibt die
           Feld-Anordnung des Suchformulars unverändert. */
        .enquiry-form__section{
            flex: 1 1 100%;

            display: flex;
            flex-wrap: wrap;
            align-items: end;
            gap: 1.25rem 1.5rem;
        }

        /* Wie beim Suchformular: Die absolut gesetzte Nächte-Angabe säße sonst
           im Zeilenabstand direkt am Label der nächsten Zeile. */
        .enquiry-form__section:has(.booking-form__nights:not(:empty)){
            row-gap: 2.25rem;
        }

        .enquiry-form__field--wide{ flex: 1 1 14rem; }
        .enquiry-form__field--full{ flex: 1 1 100%; }

        textarea{
            border: 1px solid var( --color-taupe );
            background: #fff;
            padding: 0.7em 0.8em;
            font: inherit;
            color: inherit;

            /* `rows` gibt nur die Starthöhe vor — beim Ziehen ließe sich das
               Feld auf eine Zeile zusammenschieben. Untergrenze etwa fünf
               Zeilen, damit eine Nachricht am Stück lesbar bleibt. */
            resize: vertical;
            min-block-size: 8rem;
        }

        /* Honeypot: nicht display:none — das überspringen Bots. Aus dem Bild
           geschoben, aus dem Tabulator genommen (tabindex am Feld) und per
           aria-hidden aus dem Screenreader. */
        .enquiry-form__trap{
            position: absolute;
            inline-size: 1px;
            block-size: 1px;
            overflow: hidden;
            clip-path: inset(50%);
            white-space: nowrap;
        }

        .enquiry-form__error{
            margin: 0;
            font-size: 0.8rem;
            letter-spacing: normal;
            text-transform: none;
            color: var( --color-error );
        }

        :is(input, textarea)[aria-invalid="true"]{
            border-color: var( --color-error );
        }

        /* Zeigt, worauf sich die Anfrage bezieht, wenn sie von einer
           Detailseite kommt. Volle Zeile über den Feldern. */
        .enquiry-form__subject{
            flex: 1 1 100%;
            margin: 0;
            letter-spacing: normal;
            text-transform: none;
        }

        .enquiry-form__note{
            flex: 1 1 100%;
            margin: 0;
            font-size: 0.8rem;
            letter-spacing: normal;
            text-transform: none;
            opacity: 0.8;
        }
    }

    /* Hinweis über dem Formular, solange Anfragen per E-Mail laufen. */
    .booking__hint{
        max-inline-size: var( --measure-lead );
        margin-inline: auto;
        margin-block-end: 1.5rem;
        text-align: center;
    }

    /* Rückmeldung nach dem Absenden. Farbe nur als Akzent am Rand, der Text
       bleibt anthrazit — eine Meldung, die sich allein über die Farbe erklärt,
       kommt bei Farbfehlsichtigkeit nicht an. */
    /* Fokussierbar für die Ansage, aber ohne den Ring eines Bedienelements — es
   ist ein Ziel, kein Knopf. */
.form-messages:focus{
    outline: none;
}

.form-message{
        max-inline-size: var( --measure-lead );
        margin-inline: auto;
        margin-block-end: 2rem;
        padding: 1rem 1.25rem;
        border-inline-start: 3px solid;
        background: var( --color-greige );
    }

    .form-message--success{ border-color: var( --color-mint ); }
    .form-message--error{ border-color: var( --color-error ); }

    /* Personen-Stepper: [−] Wert [+] */
    .stepper{
        display: flex;
        align-items: stretch;
        width: fit-content;
        border: 1px solid var( --color-taupe );
        background: #fff;

        .stepper__btn{
            width: 2.5rem;
            flex: none;
            font-size: 1.2rem;
            line-height: 1;
            color: inherit;
            cursor: pointer;

            &:hover{ background: var( --color-greige ); }
        }

        input{
            width: 3rem;
            border: none;
            border-inline: 1px solid var( --color-taupe );
            background: transparent;
            text-align: center;
            font: inherit;
            color: inherit;
            padding-block: 0.7em;
            -moz-appearance: textfield;
            appearance: textfield;
        }

        input::-webkit-outer-spin-button,
        input::-webkit-inner-spin-button{
            -webkit-appearance: none;
            margin: 0;
        }
    }

    /* — Buchen-Seite ——————————————————————————————————— */

    .booking{

        h1{ margin-block-end: 2rem; }

        /* Keeps the text off the form box. */
        .booking__intro{
            margin-block-end: 3rem;
        }
    }

    .booking-results{
        margin-block-start: 3rem;

        .booking-results__note{
            text-align: center;
            opacity: 0.75;
        }

        .booking-results__list{
            margin: 0;
            padding: 0;
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
            gap: 2rem;
        }
    }

    .booking-card{
        border: 1px solid var( --color-greige );

        &.is-unavailable{ opacity: 0.55; }

        img{ aspect-ratio: 3 / 2; object-fit: cover; }

        .booking-card__body{ padding: 1.25rem; }

        .booking-card__title{ font-size: var( --font-serif-4 ); margin-block-end: 0.5rem; }

        .booking-card__price{ font-size: 1.25rem; margin-block-end: 0.75rem; }

        .booking-card__cta{
            display: inline-block;
            border: 1px solid var( --color-button );
            background: var( --color-button );
            color: var( --color-greige );
            padding: 0.5em 1.25em;
            text-decoration: none;
        }
    }
}

/* Slider pagination — deliberately UNLAYERED.
   Swiper's bundled pagination CSS is unlayered, and unlayered rules beat any
   layered rule regardless of specificity. To override bullet size/colour these
   must sit outside @layer too; here they win on specificity instead.
   `--autoplay-progress` (0 → 1) is set per animation frame by gb.js. */
/* Controls capsule: holds the pause toggle + the pagination bullets. Its own
   background gives the marks constant contrast over any image, so the bullets
   need no borders of their own. */
.slider .slider-controls{
    position: absolute;
    z-index: 1;
    bottom: 1rem;
    left: 50%;
    transform: translateX(-50%);

    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.6rem;
    border-radius: 999px;
    background: rgb(0 0 0 / 0.3);
    color: #fff;
}

/* Pause / play toggle — 1.5rem (24px) target; icon swaps with the .is-paused
   state set by gb.js. */
.slider .slider-toggle{
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    color: inherit;
    cursor: pointer;

    svg{
        width: 0.85rem;
        height: 0.85rem;
    }
}

/* Show pause while playing, play while paused. Kept at matching specificity so
   the generic `svg` rule above can't override the display. */
.slider .slider-toggle__pause{ display: block; }
.slider .slider-toggle__play{ display: none; }
.slider.is-paused .slider-toggle__pause{ display: none; }
.slider.is-paused .slider-toggle__play{ display: block; }

/* Bullets: a static row inside the capsule. */
.slider .swiper-pagination{
    position: static;
    width: auto;
    transform: none;

    display: flex;
    align-items: center;
    /* 1rem gap → dot centres sit 24px apart, so the enlarged hit targets below
       are a full 24px wide without overlapping (WCAG 2.5.8). */
    gap: 1rem;

    --swiper-pagination-color: #fff;
    --swiper-pagination-bullet-inactive-color: #fff;
    --swiper-pagination-bullet-inactive-opacity: 0.45;
    --swiper-pagination-bullet-horizontal-gap: 0;

    /* 0.25rem radius (= half the 0.5rem height) renders the dot as a circle and
       the wide active bullet as a clean stadium; constant across states so only
       the width animates. */
    --swiper-pagination-bullet-width: 0.5rem;
    --swiper-pagination-bullet-height: 0.5rem;
    --swiper-pagination-bullet-border-radius: 0.25rem;
}

.slider .swiper-pagination-bullet{
    position: relative;
    margin: 0;
    /* Smoothly grow/shrink between dot and pill as the active slide changes. */
    transition: width 0.4s ease, opacity 0.4s ease;
}

/* Enlarge the tap/click target to a 24×27px area (WCAG 2.5.8) — well beyond the
   small visual mark. A click on this pseudo-element still registers on the
   bullet itself; with the 1rem gap the areas meet without overlapping. */
.slider .swiper-pagination-bullet::before{
    content: "";
    position: absolute;
    inset: -0.6rem -0.5rem;
}

/* Already-played dots read as full, not faded. */
.slider .swiper-pagination-bullet:has(~ .swiper-pagination-bullet-active){
    --swiper-pagination-bullet-inactive-opacity: 1;
}

/* Active bullet: a wide pill that fills with the autoplay timer. The fill is a
   hard-stop gradient painted onto the pill itself, so it follows the pill's
   border-radius (rounded ends, straight progress front) with no clipping — which
   also keeps the enlarged ::before hit target intact. */
.slider .swiper-pagination-bullet-active{
    width: 3rem;
    height: 0.5rem;
    opacity: 1;
    background: linear-gradient(to right,
        #fff calc(var(--autoplay-progress, 0) * 100%),
        rgb(255 255 255 / 0.3) calc(var(--autoplay-progress, 0) * 100%));
}

/* Arrows as translucent dark discs — a border alone can't outline the thin
   chevron, and a light ring vanishes on bright images; a dark disc keeps the
   white glyph legible over anything. Unlayered so width/height beat Swiper's
   own (unlayered) button sizing. */
.slider .swiper-button-prev,
.slider .swiper-button-next{
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: rgb(0 0 0 / 0.3);
}

.slider .swiper-button-prev::after,
.slider .swiper-button-next::after{
    font-size: 1.1rem;
}

/* Optical centering: the chevron's mass sits to one side, so nudge it outward
   to look centred in the disc. */
.slider .swiper-button-prev::after{
    transform: translateX(-0.1em);
}

.slider .swiper-button-next::after{
    transform: translateX(0.1em);
}

/* — Kontaktseite + Karte ——————————————————————————————— */

/* — Landing pages ————————————————————————————————————
   Blocks are freely combinable, so styles hang off the block classes alone —
   never off a page or body class. */

.lp-hero__media{
    position: relative;
    inline-size: 100%;
    aspect-ratio: var( --hero-ratio );
    max-block-size: var( --hero-max-block );
    overflow: hidden;
    margin-block-end: 3rem;
}

.lp-hero__media :is(figure, picture){
    display: block;
    position: absolute;
    inset: 0;
    margin: 0;
}

.lp-hero__media :is(img, video){
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

.lp-hero__body{
    text-align: center;
}

.lp-hero__body h1{
    font-size: var( --font-serif-2 );
    line-height: 1.05;
    margin-block-end: 1.5rem;
}

.lp-hero__body .lead{
    margin-inline: auto;
}


.lp-content__headline{
    font-size: var( --font-serif-3 );
    line-height: 1.1;
    margin-block-end: 1.5rem;
}

.lp-media{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: 2rem;
    margin-block-start: 2.5rem;
}


.lp-apartments__headline{
    font-size: var( --font-serif-2 );
    margin-block-end: 3rem;
}

.lp-cta{
    padding-block: 4rem;
    background: var( --color-greige );
}

.lp-cta__headline{
    font-size: var( --font-serif-2 );
    line-height: 1.1;
    margin-block-end: 1rem;
}

.lp-button{
    display: inline-block;
    margin-block-start: 2rem;
    padding: 0.85em 2em;
    border: 1px solid var( --color-button );

    /* Dieselbe Pillenform wie der Buchen-Knopf im Header — er ist die
       Handlungsaufforderung der Seite, und die sollte überall gleich
       aussehen. Gefüllt bleibt er trotzdem: Im Header steht der Knopf
       zwischen Textlinks und darf zurückhaltend sein, am Seitenende ist er
       der nächste Schritt. */
    border-radius: 999px;
    background: var( --color-button );
    color: #fff;
    font-size: 0.8rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lp-button:hover{
    background: var( --color-anthrazit );
    border-color: var( --color-anthrazit );
}

/* — Apartments: Kernthemen ————————————————————————— */

.themes__list{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    gap: 4rem 3rem;
    margin: 0;
    padding: 0;
}

.theme__kicker{
    /* 0.7rem ist die Größe für Formularbeschriftungen; der Kicker ist aber
       Inhalt und steht in Versalien, die bei gleicher Größe kleiner wirken als
       Gemischtschreibung. Die Deckkraft steigt mit: 0.65 ergaben 4.77:1 auf
       Weiß — für Text dieser Größe zu knapp, 0.75 bringt 6.62:1. */
    font-size: 0.8125rem;
    margin: 0 0 0.75rem;
    opacity: 0.75;
}

.theme__headline{
    /* See the serif scale above: Valore needs ~1.4x to look equal in size.
       Measured, 28px Valore against 16px SofiaPro came to only 1.29 in cap
       height; these values reach ~1.8. */
    font-size: var( --font-serif-3 );
    line-height: 1.0;
    margin: 0 0 1rem;
}

.theme__text{
    max-inline-size: var( --measure-lead );
    margin: 0;
    line-height: 1.6;
}

/* — About: Opening / Services / Discover & Book ——————————— */
.opening{
    text-align: center;
}

.opening__label{
    font-size: 0.75rem;
    margin: 0;
    opacity: 0.7;
}

.opening__date{
    font-size: var( --font-serif-2 );
    line-height: 1.1;
    margin-block: 0.5rem 0;
}

.opening__note{
    max-inline-size: 34em;
    margin: 1rem auto 0;
    line-height: 1.6;
}


.services__title,
.discover__title{
    font-size: var( --font-serif-2 );
    font-weight: normal;
    margin-block: 0 3rem;
}

.services__list{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 2.5rem 2rem;
    margin: 0;
    padding: 0;
}

.service__icon{
    display: block;
    inline-size: 2rem;
    block-size: 2rem;
    color: var( --color-taupe );
}

.service__icon svg{
    inline-size: 100%;
    block-size: 100%;
}

.service__title{
    font-size: 0.8rem;
    font-weight: normal;
    margin-block: 1rem 0.5rem;
}

.service__text{
    margin: 0;
    line-height: 1.6;
}


.discover__list{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 2.5rem 1rem;
    margin: 0;
    padding: 0;
}

.discover-tile__media{
    aspect-ratio: 3 / 4;
    overflow: hidden;
    margin-block-end: 1rem;
}

.discover-tile__media :is(figure, picture){
    display: block;
    block-size: 100%;
}


.discover-tile__title{
    font-size: 0.8rem;
    font-weight: normal;
    margin-block: 0 0.5rem;
}

.discover-tile__text{
    margin: 0;
    line-height: 1.6;
}

/* — Inhaltsseiten (Datenschutz, Impressum, AGB) ————————————— */

.page-content > h1{
    margin-block-end: 3rem;
}

.prose{
    max-inline-size: var( --measure-body );
    line-height: 1.6;
}

.prose h2{
    font-family: var( --serif-font );
    font-size: var( --font-serif-4 );
    font-weight: normal;
    margin-block: 2.5rem 0.75rem;
}

.prose h3{
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-block: 1.75rem 0.5rem;
}

.prose p,
.prose ul,
.prose ol{
    margin-block: 0 1rem;
}

.prose ul,
.prose ol{
    padding-inline-start: 1.25rem;
}

.prose li{
    margin-block-end: 0.35rem;
}

.prose a{
    color: inherit;
}


.contact__address{
    margin-block-start: 1.5rem;
}

.contact__details{
    margin-block-start: 1.5rem;
    line-height: 1.9;
}

/* Getting here — uses lead type, centred like the address above. */
.contact__arrival{
    margin-block-start: 2.5rem;
    margin-inline: auto;
}

.contact__details a{
    color: inherit;
    text-decoration: none;
    border-block-end: 1px solid var( --color-taupe );
    padding-block-end: 1px;
}

.contact__details a:hover{
    border-block-end-color: currentColor;
}

.contact__social{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
    list-style: none;
    margin: 1.5rem 0 0;
    padding: 0;
}

.contact__social a{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var( --color-taupe );
    border-radius: 50%;
    color: var( --color-anthrazit );
    transition: background-color 0.15s ease, color 0.15s ease;
}

.contact__social a:hover{
    background: var( --color-anthrazit );
    color: var( --color-greige );
}

/* Die Anschrift im Footer ist der Kartenlink. Ohne Unterstreichung bliebe
   unklar, dass sie überhaupt eine ist — die Textfarbe allein reicht als
   einziger Hinweis nicht. */
.address__link{
    color: inherit;
    text-decoration: underline;
    text-decoration-color: transparent;
    text-underline-offset: 0.2em;
    transition: text-decoration-color 0.15s ease;
}

.address__link:hover,
.address__link:focus-visible{
    text-decoration-color: currentColor;
}

/* Karte im Overlay — Apartment-Detailseiten. Natives <dialog>, deshalb kommen
   Fokusfalle, Escape und Hintergrund vom Browser. */
.map-dialog{
    inline-size: min(64rem, 100vw - 2rem);
    max-inline-size: none;
    max-block-size: min(46rem, 100vh - 2rem);
    padding: 0;
    border: 0;
    background: var( --color-greige );
    color: var( --color-anthrazit );
    overflow: hidden;
}

.map-dialog::backdrop{
    background: rgb(42 38 37 / 0.6);
}

/* Im Dialog ist die Höhe vom Viewport begrenzt, nicht vom Seitenverhältnis —
   sonst ragte die Karte auf schmalen, hohen Displays unten heraus. */
.map-dialog .contact-map{
    margin-block-start: 0;
    aspect-ratio: auto;
    block-size: min(36rem, 70vh);
    min-block-size: 0;
    max-block-size: none;
}

.map-dialog .map-links{
    margin: 0;
    padding-block: 1rem;
}

.map-dialog__bar{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 0.75rem 0.75rem 1.25rem;
}

.map-dialog__title{
    margin: 0;
    font-size: var( --font-serif-4 );
}

.map-dialog__close{
    flex: none;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    border: 1px solid transparent;
    border-radius: 50%;
    background: none;
    color: inherit;
    font-size: 1.75rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.map-dialog__close:hover,
.map-dialog__close:focus-visible{
    background: var( --color-taupe );
    color: var( --color-greige );
}

/* Der Dialog blockiert zwar die Bedienung dahinter, das Rad scrollt die Seite
   aber weiter — und mit ihm den Dialog aus dem Blick. */
html:has(dialog[open]){
    overflow: hidden;
}

.map-trigger{
    margin-block: 0;
    text-align: center;
}

/* Grundriss zweispaltig: schmale Textspalte, daneben der Plan. Das Verhältnis
   stammt aus dem Entwurf — der Plan nimmt rund zwei Drittel ein, statt über
   die ganze Breite zu laufen. */
.floorplan{
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr);
    gap: 3rem;

    /* Die Textspalte ist ein paar Zeilen hoch, der Plan gut 500px. Oben
       ausgerichtet hing der Text am Rand einer leeren Fläche; auf gleicher
       Mitte lesen sich beide als ein Block. */
    align-items: center;
}

.floorplan__text{
    margin-block-start: 1.5rem;
}

/* Begrenzt über die Höhe, nicht die Breite: Die vier Pläne haben sehr
   unterschiedliche Seitenverhältnisse — TOP 2 ist fast quadratisch, TOP 11
   querformatig. Bei gleicher Breite wögen sie optisch völlig verschieden
   schwer; bei gleicher Höhe stehen sie sich gleich. */
.floorplan__figure img{
    inline-size: auto;
    max-inline-size: 100%;
    block-size: auto;
    max-block-size: 32rem;

    /* Da die Höhe begrenzt ist, bleibt je nach Seitenverhältnis Platz in der
       Spalte. Mittig verteilt wirkt er beabsichtigt; links angeschlagen sah
       der Plan aus, als fehle rechts etwas. */
    margin-inline: auto;
}

/* Einspaltig, sobald die Textspalte zu schmal für Silben würde. */
@media (width < 60rem){
    .floorplan{
        grid-template-columns: 1fr;
        gap: 1.5rem;
    }

    .floorplan__figure img{
        margin-inline: auto;
        max-block-size: 26rem;
    }
}

.map-heading{
    font-size: var( --font-serif-3 );
    margin-block-end: 1.5rem;
}

/* Der Abstand der Karte ist für die Kontaktseite gedacht, wo sie direkt auf
   den Adressblock folgt. Steht eine Überschrift davor, bringt die ihren
   eigenen mit — beide zusammen rissen die Gruppe auseinander. */
.map-heading + .contact-map{
    margin-block-start: 0;
}

/* Die Links stehen unter der Karte, nicht darin: Innerhalb müssten sie gegen
   Zoom-Buttons und Marker um Platz konkurrieren, und am Telefon lägen sie im
   Bereich, in dem geschoben wird. */
.map-links{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 2rem;
    margin-block-start: 1rem;
    font-size: 0.9rem;
}

.contact-map{
    width: 100%;

    /* Same ratio as the stages: wide in landscape, upright in portrait. On a
       phone the 16/9 strip fell back to the min-height and left barely 200px
       below the marker — too little city to orient by. Reusing --hero-ratio
       keeps that decision in one place. */
    aspect-ratio: var( --hero-ratio );
    min-block-size: 22rem;
    max-block-size: 46rem;
    margin-block-start: 3rem;
    background: #e8e4dd; /* Fallback, solange Tiles laden */
}

/* Der Kompass erscheint erst, wenn die Karte gedreht wurde — gb.js setzt die
   Klasse. Ausgeblendet statt entfernt, damit MapLibre sein eigenes Element
   behält und die Drehung des Symbols weiterhin verwaltet. */
.contact-map .maplibregl-ctrl-compass{
    display: none;
}

.contact-map.is-rotated .maplibregl-ctrl-compass{
    display: block;
}

.contact-map .map-marker{
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: var( --color-anthrazit ) url('/assets/goldenbridge-signet.svg') center / 74% no-repeat;
    box-shadow: 0 2px 6px rgb(0 0 0 / 0.4);
    cursor: pointer;
}

/* MapLibre popup, adapted to the brand. */
.contact-map .maplibregl-popup-content{
    font-family: var( --sans-serif-font );
    background: var( --color-greige );
    color: var( --color-anthrazit );
    border-radius: 0;
    padding: 1rem 1.5rem;
    font-size: 1.05rem;
    line-height: 1.5;
    text-align: center;
    box-shadow: 0 2px 10px rgb(0 0 0 / 0.2);
}

/* Popup tip in the popover colour. Anchor-specific and more specific than
   maplibre's own rules, which would otherwise paint it white. */
.contact-map .maplibregl-popup-anchor-top .maplibregl-popup-tip,
.contact-map .maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.contact-map .maplibregl-popup-anchor-top-right .maplibregl-popup-tip{
    border-bottom-color: var( --color-greige );
}

.contact-map .maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.contact-map .maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.contact-map .maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip{
    border-top-color: var( --color-greige );
}

.contact-map .maplibregl-popup-anchor-left .maplibregl-popup-tip{
    border-right-color: var( --color-greige );
}

.contact-map .maplibregl-popup-anchor-right .maplibregl-popup-tip{
    border-left-color: var( --color-greige );
}

/* — flatpickr theme ————————————————————————————————————————
   flatpickr 4 ships no custom properties of its own — every colour is a fixed
   hex value in its CSS, including the blue #569ff7. This layer introduces the
   --fp-* variables instead; everything below merely wires them up, prefixed
   with `.flatpickr-calendar` to beat flatpickr's own later-loaded rules. */
.flatpickr-calendar{
    /* ——— Stellschrauben ——— */
    --fp-accent: var( --color-button );                                  /* Auswahl */
    --fp-accent-text: var( --color-greige );                             /* Schrift auf Auswahl */
    --fp-range-bg: color-mix(in srgb, var( --fp-accent ) 16%, #fff);     /* Tage dazwischen */
    --fp-hover-bg: var( --color-greige );                                /* Hover */
    --fp-today-border: var( --color-taupe );                             /* heutiger Tag */
}

.flatpickr-calendar .flatpickr-day.selected,
.flatpickr-calendar .flatpickr-day.startRange,
.flatpickr-calendar .flatpickr-day.endRange,
.flatpickr-calendar .flatpickr-day.selected:hover,
.flatpickr-calendar .flatpickr-day.startRange:hover,
.flatpickr-calendar .flatpickr-day.endRange:hover,
.flatpickr-calendar .flatpickr-day.selected.startRange,
.flatpickr-calendar .flatpickr-day.selected.endRange{
    background: var( --fp-accent );
    border-color: var( --fp-accent );
    color: var( --fp-accent-text );
}

.flatpickr-calendar .flatpickr-day.inRange{
    background: var( --fp-range-bg );
    border-color: var( --fp-range-bg );
    box-shadow: -5px 0 0 var( --fp-range-bg ),
                 5px 0 0 var( --fp-range-bg );
}

/* Directly adjacent start/end days: flatpickr bridges the gap with a
   box-shadow (blue by default) rather than a background. */
.flatpickr-calendar .flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
.flatpickr-calendar .flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
.flatpickr-calendar .flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)){
    box-shadow: -10px 0 0 var( --fp-accent );
}

/* flatpickr always paints adjacent-month days at 30% opacity, even when they
   are selectable — at month end those are precisely the bookable ones, which
   made the calendar look empty. Selectable days get full contrast; only truly
   disabled ones stay muted. */
.flatpickr-calendar .flatpickr-day.prevMonthDay:not(.flatpickr-disabled),
.flatpickr-calendar .flatpickr-day.nextMonthDay:not(.flatpickr-disabled){
    color: inherit;
}

.flatpickr-calendar .flatpickr-day.flatpickr-disabled{
    color: color-mix(in srgb, currentColor 28%, transparent);
}

.flatpickr-calendar .flatpickr-day.today{
    border-color: var( --fp-today-border );
}

.flatpickr-calendar .flatpickr-day.today:hover{
    background: var( --fp-today-border );
    color: var( --fp-accent-text );
}

.flatpickr-calendar .flatpickr-day:hover{
    background: var( --fp-hover-bg );
    border-color: var( --fp-hover-bg );
}

/* Gentle fade after selection. gb.js sets `is-closing` while the calendar is
   still open, because a closed one is display:none and could not transition.
   Two classes beat flatpickr's `.flatpickr-calendar.open{opacity:1}`. */
.flatpickr-calendar.open{
    transition: opacity 0.25s ease;
}

.flatpickr-calendar.open.is-closing{
    opacity: 0;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce){
    .flatpickr-calendar.open{
        transition: none;
    }
}

/* Two months side by side do not fit on a phone, so they are stacked instead.
   flatpickr groups its DOM by kind — both month labels, then both weekday
   rows, then both day grids — so the three wrappers are dissolved with
   `display: contents` and the six parts are laid out in one column. Everything
   belonging to the second month is pulled behind the first with a single
   `order`; the arrows are absolutely positioned and stay out of the flow. */
@media (width < 48rem){
    /* `.open` is in the selector purely for weight: flatpickr's own
       `.flatpickr-calendar.open{display:inline-block}` loads later and would
       otherwise win the tie. */
    .flatpickr-calendar.open.multiMonth{
        display: grid;

        /* Two full months are taller than a phone screen, so the calendar is
           capped at half of it and scrolls internally. flatpickr can no longer
           decide for itself whether the calendar fits: it measures by summing
           the offsetHeight of its direct children, and those are exactly the
           wrappers dissolved above, which now measure 0. gb.js therefore
           scrolls the calendar into view after opening. */
        max-block-size: 50dvh;
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .flatpickr-calendar.multiMonth :is(.flatpickr-months, .flatpickr-innerContainer,
    .flatpickr-rContainer, .flatpickr-weekdays, .flatpickr-days){
        display: contents;
    }

    .flatpickr-calendar.multiMonth :is(.flatpickr-month, .flatpickr-weekdaycontainer,
    .dayContainer):nth-of-type(2){
        order: 1;
    }

    /* Both took their width from `flex: 1` in the row they no longer sit in:
       the month label is absolutely positioned and would collapse to nothing,
       the weekday row would end up narrower than the grid below it. */
    .flatpickr-calendar.multiMonth :is(.flatpickr-month, .flatpickr-weekdaycontainer){
        inline-size: 100%;
    }
}

/* — Consent-Banner (craft-cmp, Marken-Override) ————————————————— */
.cc-banner{
    position: fixed;
    inset-inline: 1rem;
    inset-block-end: 1rem;
    z-index: 9999;
    max-width: 34rem;
    margin-inline: auto;
    padding: 1.5rem;
    background: var( --color-greige );
    color: var( --color-anthrazit );
    box-shadow: 0 8px 40px rgb(0 0 0 / 0.25);
}

.cc-banner__head{
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-block-end: 0.75rem;
}

.cc-banner__title{
    font-size: 1.25rem;
}

.cc-banner .language-switcher{
    display: flex;
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    font-size: 0.8rem;
}

.cc-banner .language-switcher a{
    color: inherit;
    text-decoration: none;
    opacity: 0.6;
}

.cc-banner .language-switcher a[aria-current="true"]{
    opacity: 1;
    text-decoration: underline;
}

.cc-banner__text{
    font-size: 0.9rem;
    line-height: 1.55;
}

.cc-banner__links{
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 0.75rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.8rem;
}

.cc-banner__links a{ color: inherit; }

.cc-banner__actions{
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-block-start: 1.25rem;
}

/* Accept and reject must look equivalent. A highlighted accept beside a
   subdued reject steers the choice, and the consent no longer counts as freely
   given. Both share this single class; there is deliberately no "primary". */
.cc-btn{
    /* Basis 0: accept and reject share the space exactly, or word length alone
       would make one button larger. */
    flex: 1 1 0;
    padding: 0.65rem 1rem;
    border: 1px solid var( --color-button );
    background: var( --color-button );
    color: #fff;
    font: inherit;
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.cc-btn:hover{
    background: var( --color-anthrazit );
    border-color: var( --color-anthrazit );
}

/* Subordinate: "settings" and "cancel". This does not touch the
   accept/reject pair — both decisions stay equally prominent, one click away. */
.cc-btn--quiet{
    flex: 0 1 auto;
    background: transparent;
    border-color: transparent;
    color: var( --color-taupe );
    text-decoration: underline;
}

.cc-btn--quiet:hover{
    background: transparent;
    border-color: transparent;
    color: var( --color-anthrazit );
}

/* Am Telefon reichte der Platz für drei Knöpfe nebeneinander nicht: „Ablehnen"
   teilte sich die Zeile mit „Einstellungen" und war 112px breit, „Akzeptieren"
   sprang in die nächste Zeile und maß 310px. Damit war die Zustimmung fast
   dreimal so groß wie die Ablehnung — genau das Ungleichgewicht, das eine
   Einwilligung angreifbar macht.

   Als Raster statt Flex-Umbruch: Die beiden Entscheidungen teilen sich eine
   eigene Zeile zu exakt gleichen Teilen, „Einstellungen" steht darüber. */
@media (width < 48rem){
    .cc-banner__actions{
        display: grid;
        grid-template-columns: 1fr 1fr;
    }

    .cc-btn--quiet{
        grid-column: 1 / -1;
    }
}

.cc-modal{
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgb(0 0 0 / 0.5);
}

.cc-modal__box{
    width: 100%;
    max-width: 32rem;
    max-height: 90vh;
    overflow-y: auto;
    padding: 1.75rem;
    background: var( --color-greige );
    color: var( --color-anthrazit );
}

.cc-modal__title{
    font-size: 1.25rem;
}

.cc-modal__list{
    list-style: none;
    margin: 1.25rem 0;
    padding: 0;
}

.cc-modal__row{
    display: flex;
    gap: 1rem;
    align-items: flex-start;
    justify-content: space-between;
    padding-block: 1rem;
    border-block-start: 1px solid var( --color-taupe );
}

.cc-modal__label{
    margin: 0;
    font-weight: 600;
}

.cc-modal__desc{
    margin: 0.25rem 0 0;
    font-size: 0.85rem;
    line-height: 1.45;
    opacity: 0.8;
}

/* Toggle switch for the categories */
.cc-switch{
    position: relative;
    flex: none;
    inline-size: 2.75rem;
    block-size: 1.5rem;
}

.cc-switch input{
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.cc-switch__track{
    position: absolute;
    inset: 0;
    border-radius: 1rem;
    background: color-mix(in srgb, var( --color-taupe ) 35%, #fff);
    transition: background-color 0.15s ease;
}

.cc-switch__track::before{
    content: "";
    position: absolute;
    inset-block-start: 0.2rem;
    inset-inline-start: 0.2rem;
    inline-size: 1.1rem;
    block-size: 1.1rem;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.15s ease;
}

.cc-switch input:checked + .cc-switch__track{
    background: var( --color-button );
}

.cc-switch input:checked + .cc-switch__track::before{
    transform: translateX(1.25rem);
}

.cc-switch input:disabled + .cc-switch__track{
    opacity: 0.55;
    cursor: not-allowed;
}

.cc-switch input:focus-visible + .cc-switch__track{
    outline: 2px solid var( --color-anthrazit );
    outline-offset: 2px;
}

/* — Page transitions: gentle cross-fade (View Transitions API) ————
   Applies to cross-document navigation. Browsers without support simply
   navigate without a transition. */
@view-transition {
    navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root){
    animation-duration: 0.35s;
    animation-timing-function: ease;
}

@media (prefers-reduced-motion: reduce){
    ::view-transition-old(root),
    ::view-transition-new(root){
        animation: none;
    }
}