/* ------------------------------------------------------------------
   LXP — page-level styles on top of the design system.
   Tokens, primitives, base reset → css/tokens.css.
   ------------------------------------------------------------------ */

/* ============================ CARD IMAGE HOVER ====================
   DS rule: every <img> inside a `.card` animates the SAME way on hover.
   ONE selector. No per-component overrides. Values live in tokens.css
   as --card-img-hover-scale / --card-img-hover-duration / --card-img-hover-easing.

   To make a new component participate, just add the `.card` class to
   the outer element. Don't add component-specific transition/hover rules
   for the image — they'll diverge from the canon.
   =================================================================== */
.card img {
    transition: transform var(--card-img-hover-duration) var(--card-img-hover-easing);
}
.card:hover img,
.card:focus-within img {
    transform: scale(var(--card-img-hover-scale));
}

/* ============================ CARD LIFT ON HOVER ==================
   DS rule: any card that should lift + cast a softer shadow on hover
   opts in with `.card--liftable`. ONE rule, ONE transition. Used by
   article cards, case-study cards/entries, review cards and the editorial
   destination anchor. Don't add per-component :hover rules for the same
   thing — they drift in duration/easing/shadow and the site loses rhythm.
   =================================================================== */
.card--liftable {
    transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
}
.card--liftable:hover,
.card--liftable:focus-within {
    transform: translateY(-2px);
    box-shadow: var(--shadow-3);
}

/* ============================ PANEL (SET-OFF SURFACE) =============
   DS rule: the ONE way to lift a block of content off the page ground —
   the warm --accent-faint tint, soft --r-lg radius, clamped padding. No
   border, no shadow. This is the sanctioned alternative to running copy;
   it is NOT the general `.card` class (that is deliberately chrome-less,
   a behaviour/typography hook for photo tiles — see tokens.css).

   The recipe lives here ONCE. Opt a new surface in by adding `.panel` to
   its markup. Existing surfaces are grouped in by their own class name so
   there are no markup changes — retune the tint/radius/padding here and
   every panel follows. Don't redeclare these three properties per
   component; that's how the surfaces drift apart.

   Members:
     .reviews__featured              — homepage featured Google review
     .content-element__content.card  — editorial content block (Style: Card)
   Component-specific layout (flex column, line-clamp, author-to-bottom)
   stays on the component's own rules. */
.panel,
.reviews__featured,
.content-element__content.card {
    background: var(--accent-faint);
    border-radius: var(--r-lg);
    padding: clamp(var(--s-6), 4vw, var(--s-8));
}
/* Content sits flush to the panel padding — kill stray outer margins on
   the first/last child (e.g. a leading <h2> or trailing <p> of prose). */
.panel > :first-child,
.reviews__featured > :first-child,
.content-element__content.card > :first-child { margin-top: 0; }
.panel > :last-child,
.reviews__featured > :last-child,
.content-element__content.card > :last-child { margin-bottom: 0; }

/* Footnote content block — opt-in via the CMS "Style variation → Footnote"
   dropdown. Small print that qualifies the section above it: the UN
   disclaimer on /unser-versprechen is the case it was built for. Muted and
   set small so it reads as a legal note rather than as the page's closing
   thought, but still full measure — a footnote nobody can read is worse
   than no footnote. */
.content-element__content.footnote {
    font-size: var(--t-micro);
    line-height: 1.5;
    color: var(--ink-muted);
    margin-top: var(--s-7);
    padding-top: var(--s-5);
    border-top: 1px solid var(--hairline);
}
.content-element__content.footnote > :first-child { margin-top: 0; }
.content-element__content.footnote > :last-child { margin-bottom: 0; }
.content-element__content.footnote p { font-size: inherit; color: inherit; }

:root {
    --measure:   64ch;
    --rail:      1px solid var(--hairline);
    --rail-soft: 1px solid var(--hairline-soft);
}

html {
    /* 103.125% of the 16px browser default = the same 16.5px — but as a
       percentage it still honours a user-raised default font size, which
       a px value silently ignores for every rem on the site. */
    font-size: 103.125%;
    /* Anchor/focus scrolls clear the 71px sticky masthead. */
    scroll-padding-top: 88px;
    line-height: 1.58;
    font-feature-settings: "kern" 1, "liga" 1;
    /* Horizontal-overflow guard for full-bleed (100vw) sections lives in a gated
       rule just below — NOT here on the bare `html`, because overflow on the root
       makes iOS Safari clip position:fixed children (the Lexi bubble + back-to-top
       were getting cut off at the bottom). */
    /* The ROOT background paints the canvas — including iOS Safari's overscroll
       rubber-band past the footer. Match it to the footer's white ground
       (--surface) instead of letting <body>'s bone (--bg) propagate, so an
       over-scroll bounce at the bottom doesn't flash bone below the white footer.
       <body> keeps --bg for the page itself (bone vs white is a hair's
       difference, so the top is visually unchanged). NB: the PERSISTENT bottom
       gap is fixed elsewhere — by the hero using svh, not dvh (see the hero
       stage rule); this rule only tidies the transient over-scroll edge. */
    background: var(--surface);
}

/* Full-bleed (100vw) sections overflow by the vertical-scrollbar gutter (~8–15px)
   on classic-scrollbar browsers, triggering a horizontal scrollbar. `clip` (not
   `hidden`) prevents it without establishing a scroll container, so position:
   sticky keeps working. GATED to NON-touch devices: on iOS/iPadOS Safari, overflow
   on the root element clips position:fixed children (it was cutting off the Lexi
   bubble + back-to-top). Touch browsers use overlay scrollbars (no gutter), so the
   guard isn't needed there anyway — verified there's no horizontal overflow on
   mobile without it. */
@media not all and (any-pointer: coarse) {
    html { overflow-x: clip; }
}

h1, h2, h3, .serif {
    font-feature-settings: "kern" 1, "liga" 1, "onum" 1;
}

/* Structural elements opt out of the body default (Garamond) and use the
   sans stack — nav, breadcrumb, locale switcher, pagination, footer nav.
   Targets the leaf elements (a / li) directly so tokens.css's `p, li`
   serif rule loses to specificity. */
.site-header, .site-header *,
.site-locale__link,
.site-subnav, .site-subnav li, .site-subnav a, .site-subnav h3,
.breadcrumb, .breadcrumb li, .breadcrumb a,
.pagination, .pagination a, .pagination li,
.site-footer, .site-footer li, .site-footer a {
    font-family: var(--sans);
}

/* Brand wordmark stays serif italic (overrides the .site-header * blanket).
   Brand is absolutely positioned within .site-header__inner so its
   espresso plate can hang below the nav row without growing the header.
   The grid template reserves a min-width on column 1 so the nav
   stays viewport-centered (won't slide left under the brand). The
   plate is 1.5× the header height; the wordmark is anchored to its
   bottom edge via flex-end + a small bottom padding. */
.site-header__inner {
    position: relative;
    grid-template-columns: minmax(260px, 1fr) auto 1fr;
}
.site-header__brand {
    position: absolute;
    top: 0;
    left: var(--gutter);
    height: calc(var(--site-header-h, 73px) * 1.5);
    display: block;
    text-decoration: none;
    z-index: 1;
    transition: transform 260ms var(--ease);
    will-change: transform;
}
/* Slide the brand plate up while the visitor is scrolling DOWN past
   the masthead. Scrolling back up restores it to fully visible —
   header-scroll.js toggles .site-header--folded on direction change. */
.site-header--folded .site-header__brand {
    transform: translateY(-30px);
}
.site-header__logo {
    display: block;
    height: 100%;
    width: auto;
}

a {
    color: var(--accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}
a:hover { color: var(--accent-deep); }

/* Headline-in-link: ink color stays, tonal underline wipes L→R on hover/focus.
   Covers both <a><h?> and <h?><a> markup shapes site-wide. */
a :is(h1, h2, h3, h4),
:is(h1, h2, h3, h4):has(a) {
    color: inherit;
    text-decoration: none;
    width: fit-content;
    max-width: 100%;
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 0.08em;
    padding-bottom: 0.15em;
    transition: background-size 420ms cubic-bezier(0.65, 0, 0.35, 1);
}
a:hover :is(h1, h2, h3, h4),
a:focus-visible :is(h1, h2, h3, h4),
:is(h1, h2, h3, h4):has(a:hover),
:is(h1, h2, h3, h4):has(a:focus-visible) {
    background-size: 100% 0.08em;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    padding: var(--s-2) var(--s-4);
    background: var(--accent);
    color: #fff;
}
.skip-link:focus { left: var(--s-4); top: var(--s-4); z-index: 100; }

/* Back-to-top — mobile only. Hidden on desktop entirely; on phones it
   fades in once to-top.js adds .is-visible (past ~0.8 viewport scrolled).
   Espresso disc, design-system rounding + shadow, safe-area aware. */
.to-top { display: none; }
@media (max-width: 720px) {
    .to-top {
        position: fixed;
        /* Bottom-LEFT — the Lexi chat bubble owns the bottom-right corner. */
        left: var(--s-4);
        /* No env(safe-area-inset-bottom) here on purpose: iOS Safari toggles that
           inset 0↔34px as the bottom toolbar collapses/expands on scroll, which
           made the button jump up ~34px (reading as "barely visible") while
           scrolling down. A constant 16px keeps it pinned in every toolbar state. */
        bottom: var(--s-4);
        z-index: 60;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        padding: 0;
        border: none;
        border-radius: var(--r-pill);
        background: var(--accent);
        color: var(--accent-ink, #fff);
        box-shadow: var(--shadow-2);
        cursor: pointer;
        opacity: 0;
        transform: translateY(8px);
        pointer-events: none;
        transition: opacity 200ms var(--ease), transform 200ms var(--ease), background 160ms ease;
    }
    .to-top.is-visible { opacity: 1; transform: none; pointer-events: auto; }
    .to-top:hover, .to-top:focus-visible { background: var(--accent-deep); }
    .to-top:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
}
/* Hidden while the first-visit consent banner covers the bottom of the screen. */
html.cc-banner-open .to-top { display: none !important; }

/* ---------- Site header -------------------------------------------- */

/* Header bar is full-viewport-width (background + border edge-to-edge).
   Content stays max-width via .site-header__inner. The mega-menu
   dropdown anchors to this sticky element so it bleeds full-width too;
   its inner children carry their own max-width + margin: 0 auto. */
.site-header {
    /* Transparent at the top of the page (brand box, CTA + chrome pill
       carry the visual weight as floating elements); takes a solid sand
       skin once scrolled — see `body.is-scrolled .site-header` below. */
    background: transparent;
    border-bottom: 0;
    position: sticky;
    top: 0;
    z-index: 20;
}
/* Three-column grid: brand | nav | utilities. The 1fr / auto / 1fr
   pattern keeps the nav cell exactly in the row's horizontal center
   regardless of brand or utilities width — so when the logo collapses
   to the X mark, the nav doesn't shift. Inner spans full viewport
   width with gutter padding; brand and utilities anchor to the
   viewport edges. Inner is intentionally NOT position: relative so
   the mega-menu dropdown anchors up to the sticky .site-header. */
.site-header__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-4) var(--gutter);
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    column-gap: var(--s-5);
}
.site-header__inner > .site-header__brand   { justify-self: start; }
/* Brand is position: absolute (see top of file), which removes it
   from auto-placement. Pin nav and utilities to their tracks so the
   reserved col 1 stays empty for the brand to overlay. */
.site-header__inner > .site-subnav--inline  {
    grid-column: 2;
    justify-self: center;
}
.site-header__inner > .site-header__utilities {
    grid-column: 3;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: var(--s-5);
}

/* TEST — chrome controls (search + locale + hamburger) clustered into
   a frosted charcoal pill. CTA stays its own button to the left. */
.site-header__controls {
    display: inline-flex;
    align-items: center;
    gap: var(--s-3);
    padding: 0 var(--s-3);
    /* Default ("on paper") state: the pill takes the page's own paper tone
       (--bg bone), so it blends into the page and is defined only by the
       hairline + faint shadow — lighter than a white lozenge, far lighter
       than the old dark blob. Over a fullwidth hero it flips to dark glass
       (override further down): dark glass on imagery, paper on paper. */
    background: var(--bg);
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
    box-shadow: var(--shadow-1);
    color: var(--ink);
    transition: background 220ms var(--ease), color 220ms var(--ease),
                border-color 220ms var(--ease), box-shadow 220ms var(--ease);
}
.site-header__controls .site-search-trigger,
.site-header__controls .site-locale__current,
.site-header__controls .site-contact-trigger,
.site-header__controls .site-menu-trigger {
    color: var(--ink);
}
/* Half-pill CTA inside the controls pill — rounded on the left so its
   curve merges with the outer pill's left edge, flat on the right so
   it sits flush against the search/locale/menu chrome. Reads as one
   continuous shape with the chrome rather than a separate pill. */
.site-header__controls .site-header__cta {
    border-radius: var(--r-pill) 0 0 var(--r-pill);
    font-size: 12px;
    align-self: stretch;
    display: inline-flex;
    align-items: center;
    /* Pull CTA flush to the pill's left edge — its left curve merges
       with the pill's left curve so they read as one shape. */
    margin-left: calc(-1 * var(--s-3));
}
/* a:hover (generic) wins over .btn-primary on specificity — pin
   the CTA text white so it stays legible on the deep espresso hover bg. */
.site-header__controls .site-header__cta,
.site-header__controls .site-header__cta:hover,
.site-header__controls .site-header__cta:focus-visible {
    color: var(--accent-ink);
}
/* 2026-06-09 — primary CTA unified to espresso. The previous orange
   (--feature) variant put white text on #f39200 (2.35:1, fails WCAG AA);
   the CTA now inherits .btn-primary's espresso background (var(--accent),
   white text = 13:1). One primary-action colour sitewide; orange is
   reserved for small non-text accents only (pills, announcement bar). */
.site-header__inner > .site-subnav--inline {
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
}
.site-subnav--inline .site-subnav__links--global {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: var(--s-4);
    white-space: nowrap;
}
/* Hover bridge for the inline nav: the li hit area is extended below
   the visible link by padding-bottom + an equal negative margin-bottom.
   The padding adds invisible hit area; the negative margin keeps the
   margin-box height equal to the link height so flex's align-items:
   center still vertically aligns the link text correctly. */
.site-subnav--inline .site-subnav__links--global > li {
    display: inline-flex;
    align-items: center;
    padding-bottom: 0;
}
.site-subnav--inline .site-subnav__links--global > li.has-dropdown {
    padding-bottom: var(--s-5);
    margin-bottom: calc(var(--s-5) * -1);
}
/* TEST — inline mega-menu nav off; the off-canvas drawer carries navigation
   at all widths (the original "drawer carries all" behaviour). */
.site-header__inner > .site-subnav--inline { display: none; }

.site-locale {
    position: relative;
    font-size: 0.85rem;
}
.site-locale__current {
    appearance: none;
    background: transparent;
    border: 1px solid transparent;
    color: var(--ink);
    cursor: pointer;
    padding: var(--s-1) var(--s-2);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font: inherit;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* Globe affordance so the bare EN/DE/ES reads as a language control.
   Inherits currentColor, matching the search icon's stroke weight. */
.site-locale__globe { flex: 0 0 auto; opacity: 0.85; }
.site-locale__current::after {
    content: "";
    width: 6px;
    height: 6px;
    border-right: 1px solid currentColor;
    border-bottom: 1px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    transition: transform 200ms var(--ease);
}
.site-locale:hover .site-locale__current::after,
.site-locale:focus-within .site-locale__current::after {
    transform: rotate(-135deg) translate(-1px, -1px);
}
.site-locale__panel {
    position: absolute;
    top: 100%;
    right: 0;
    background: #ffffff;
    border: 1px solid var(--hairline);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow-2);
    padding: var(--s-2);
    margin-top: var(--s-2);
    display: flex;
    flex-direction: column;
    min-width: 80px;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-4px);
    transition: opacity 160ms var(--ease), transform 160ms var(--ease);
    z-index: 30;
}
/* Hover bridge: extend the .site-locale hover area down past the
   button so the cursor can travel to the panel without the gap
   killing the hover state. The ::after sits in the same space the
   panel's margin-top occupies — invisible, no layout impact. */
.site-locale::after {
    content: "";
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;
    height: var(--s-2);
}
.site-locale:hover .site-locale__panel,
.site-locale:focus-within .site-locale__panel {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}
.site-locale__link {
    color: var(--ink-soft);
    text-decoration: none;
    padding: var(--s-2);
    border-radius: var(--r-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    transition: background 140ms var(--ease), color 140ms var(--ease);
}
.site-locale__link:hover {
    color: var(--ink);
    background: var(--stone-100);
}
.site-locale__link--current {
    color: var(--ink);
    background: var(--stone-100);
}
.site-locale__link--invalid {
    opacity: 0.35;
    pointer-events: none;
}

/* Header CTA — primary conversion button living next to the locale switcher.
   Uses tokens.css .btn .btn-primary .btn-sm; this rule only handles header-
   specific spacing. The button is hidden <=720px (it moves into the drawer);
   the single hide rule lives in the .site-header__controls 720px block below. */
.site-header__cta { margin-left: var(--s-2); }

/* ---------- Hamburger menu trigger ----------------------------------
   Three-bar icon. Sits at the right edge of the header, opens the
   off-canvas drawer holding the full navigation. */
.site-menu-trigger {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 8px;
    margin-left: var(--s-2);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 36px;
}
/* The visible word beside the icon — NN/g: an unlabelled hamburger is
   the weakest form of the pattern, and with the desktop nav deliberately
   drawer-only this label is the cheapest compensating measure. */
.site-menu-trigger__label {
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: currentColor;
    line-height: 1;
}
.site-menu-trigger__bars {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
}
/* Integer pixel height — 1.5px rendered each bar at a different sub-
   pixel anti-aliasing pattern depending on its y-position, making the
   middle bar look heavier than the outer two on non-retina displays. */
.site-menu-trigger__bar {
    display: block;
    width: 22px;
    height: 1px;
    background: currentColor;
    transition: transform 200ms ease, opacity 200ms ease;
}
.site-menu-trigger[aria-expanded="true"] .site-menu-trigger__bar:nth-child(1) {
    transform: translateY(6.5px) rotate(45deg);
}
.site-menu-trigger[aria-expanded="true"] .site-menu-trigger__bar:nth-child(2) {
    opacity: 0;
}
.site-menu-trigger[aria-expanded="true"] .site-menu-trigger__bar:nth-child(3) {
    transform: translateY(-6.5px) rotate(-45deg);
}
/* TEST — hamburger always visible (drawer is the unified menu now). */
@media (max-width: 720px) {
    .site-header__rails { display: none; }
    /* Mobile chrome is just the hamburger. CTA, search and the language
       selector all move into the drawer (see Header.ss → .site-drawer__cta
       / __search / __locale) so the masthead is logo + hamburger only. */
    .site-header__controls .site-header__cta,
    .site-header__controls .site-search-trigger,
    .site-header__controls .site-locale { display: none; }
    /* With those three gone, the frosted chrome pill wrapped a lone
       hamburger and read as an orphaned lozenge. Strip the pill on mobile
       so the hamburger stands alone as a clean icon on the transparent
       header, inheriting the header ink instead of the pill's forced white
       (dark over content; white over a hero via the not(.is-scrolled)
       rules). */
    .site-header__controls {
        background: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        border: 0;
        box-shadow: none;
        padding: 0;
        color: inherit;
    }
    .site-header__controls .site-menu-trigger { color: inherit; }
    /* Smaller brand plate so the logo doesn't crowd the right-side
       chrome pill on narrow viewports. */
    .site-header__brand { height: calc(var(--site-header-h, 73px) * 1.1); }
    /* Auto-hide the whole masthead on mobile — industry-standard
       "Headroom" pattern. header-scroll.js already toggles
       .site-header--folded on scroll direction (down past the masthead
       hides it, any upward scroll reveals it, always open near the top
       via REVEAL_AT with an ±8px direction deadband to kill jitter), so
       this is purely the CSS payoff: slide the bar up off-screen.
       The masthead moves as ONE rigid unit — brand plate, logo and chrome
       all travel together at the same speed. -120% (not -100%) because the
       brand plate is 1.1× the header height (position:absolute top:0, so it
       hangs ~10% below the bar); the extra 20% clears that overhang — and
       the logo nested inside it — instead of leaving a dark sliver peeking.
       .page-subnav is display:none on mobile, so nothing sticks below the
       header to leave a gap. */
    .site-header { transition: transform 280ms var(--ease); will-change: transform; }
    .site-header--folded { transform: translateY(-120%); }
    .site-header--folded .site-header__brand { transform: none; }
}

/* ---------- Off-canvas drawer ---------------------------------------
   Hosts the full navigation. Right-side panel (max 480px) over a
   translucent dark backdrop; full-bleed below 720px. Closed by ESC,
   backdrop click, or close button. JS adds .is-open / removes hidden. */
.site-drawer {
    position: fixed;
    inset: 0;
    z-index: 100;
}
.site-drawer[hidden] { display: none; }
.site-drawer__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(15, 14, 10, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    transition: opacity 280ms ease;
}
.site-drawer.is-open .site-drawer__backdrop { opacity: 1; }
.site-drawer__panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(480px, 100%);
    background: var(--bg);
    color: var(--ink);
    padding: var(--s-7) var(--s-7) calc(var(--s-9) + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform 320ms cubic-bezier(.22,.61,.36,1);
    box-shadow: var(--shadow-drawer);
}
.site-drawer.is-open .site-drawer__panel { transform: translateX(0); }
.site-drawer__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-5);
    margin-bottom: var(--s-7);
}
.site-drawer__close {
    appearance: none;
    background: transparent;
    border: 0;
    font-size: 32px;
    line-height: 1;
    padding: 4px 10px;
    margin: 0 0 0 -10px;
    color: var(--ink);
    cursor: pointer;
}
.site-drawer__content {
    display: flex;
    flex-direction: column;
    gap: var(--s-8);
}
/* CTA inside the drawer top bar — sits opposite the close button at the
   same vertical position. Orange pill matches the header CTA treatment. */
/* Drawer CTA matches the unified espresso primary (was orange --feature,
   which failed WCAG AA white-on-orange at 2.35:1). */
.site-drawer__cta {
    background: var(--accent);
    color: var(--accent-ink);
    border-radius: var(--r-pill);
    padding: 12px 22px;
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    letter-spacing: 0.02em;
}
.site-drawer__cta:hover,
.site-drawer__cta:focus-visible {
    background: var(--accent-deep);
    color: var(--accent-ink);
}
.site-drawer__nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.site-drawer__nav > ul > li {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    border-top: 1px solid var(--hairline);
}
.site-drawer__nav > ul > li:last-child {
    border-bottom: 1px solid var(--hairline);
}
.site-drawer__nav > ul > li > a {
    display: block;
    padding: var(--s-4) 0;
    font-family: var(--sans);
    font-size: clamp(17px, 2vw, 19px);
    font-weight: 700;
    letter-spacing: -0.005em;
    color: var(--ink);
    text-decoration: none;
    transition: color 150ms ease;
}
.site-drawer__nav > ul > li > a:hover { color: var(--accent); }
.site-drawer__nav > ul > li > a.is-current { color: var(--ink); }
/* Chevron toggle — sits in column 2, only expands the inline children
   list; the parent link still navigates to its overview page. */
.site-drawer__nav-toggle {
    appearance: none;
    background: transparent;
    border: 0;
    padding: var(--s-4) 0 var(--s-4) var(--s-4);
    margin: 0;
    cursor: pointer;
    color: var(--ink-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 150ms ease;
}
.site-drawer__nav-toggle:hover,
/* A color-only change is invisible to many low-vision users — give the
   chevron the same 2px ring every other control uses. */
.site-drawer__nav-toggle:focus-visible {
    color: var(--accent);
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.site-drawer__nav-toggle svg { transition: transform 200ms ease; }
.site-drawer__nav > ul > li.is-expanded .site-drawer__nav-toggle svg {
    transform: rotate(180deg);
}
.site-drawer__nav-children {
    grid-column: 1 / -1;
    list-style: none;
    padding: 0;
    margin: 0;
    display: none;
}
.site-drawer__nav > ul > li.is-expanded > .site-drawer__nav-children {
    display: block;
    margin: 0 0 var(--s-3);
}
.site-drawer__nav-grandchildren {
    list-style: none;
    padding: 0;
    margin: var(--s-1) 0 var(--s-2);
}
.site-drawer__nav-children > li,
.site-drawer__nav-grandchildren > li { margin: 0; }

/* Drawer-only utilities — search field (top of content) + language row
   (bottom). They surface ONLY on mobile, where the header is pared back to
   logo + hamburger; the drawer is also the desktop menu, so they default to
   display:none there (the header still carries search + locale ≥721px). */
.site-drawer__search,
.site-drawer__locale { display: none; }

@media (max-width: 720px) {
    .site-drawer__search { display: block; margin: 0; }
    .site-drawer__search-label {
        display: block;
        font-family: var(--sans);
        font-size: 12px;
        font-weight: 600;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: var(--ink-muted);
        margin-bottom: var(--s-2);
    }
    .site-drawer__search input[type="search"] {
        display: block;
        width: 100%;
        font-family: var(--sans);
        font-size: 1.1rem;
        padding: var(--s-3) 0;
        background: transparent;
        color: var(--ink);
        border: 0;
        border-bottom: 1px solid var(--hairline);
        border-radius: 0;
    }
    .site-drawer__search input[type="search"]::placeholder { color: var(--ink-muted); }
    .site-drawer__search input[type="search"]:focus-visible {
        outline: none;
        border-bottom-color: var(--accent);
    }

    /* Quiet uppercase row — reads as a set-once preference, not nav. The
       generous .site-drawer__content gap above already separates it. */
    .site-drawer__locale { display: flex; gap: var(--s-5); }
    .site-drawer__locale-link {
        font-family: var(--sans);
        font-size: 14px;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--ink-soft);
        text-decoration: none;
        transition: color 150ms ease;
    }
    .site-drawer__locale-link:hover { color: var(--accent); }
    .site-drawer__locale-link--current { color: var(--ink); font-weight: 600; }
    .site-drawer__locale-link--invalid { opacity: 0.4; pointer-events: none; }
}
.site-drawer__nav-children > li > a {
    display: block;
    padding: var(--s-2) 0 var(--s-2) var(--s-4);
    font-family: var(--sans);
    font-size: 16px;
    color: var(--ink-soft);
    text-decoration: none;
    transition: color 150ms ease;
}
.site-drawer__nav-children > li > a:hover,
.site-drawer__nav-children > li > a.is-current { color: var(--accent); }
.site-drawer__nav-grandchildren > li > a {
    display: block;
    padding: var(--s-1) 0 var(--s-1) var(--s-8);
    font-family: var(--sans);
    font-size: 14px;
    color: var(--ink-muted);
    text-decoration: none;
    transition: color 150ms ease;
}
.site-drawer__nav-grandchildren > li > a:hover,
.site-drawer__nav-grandchildren > li > a.is-current { color: var(--accent); }
/* Body scroll lock while drawer is open */
body.is-drawer-open { overflow: hidden; }

/* ---------- Page sub-nav (inline, after hero) -----------------------
   Renders directly under the hero on pages with a section context.
   Sticky on scroll so the page-level nav stays in reach. Distinct from
   the global header sub-nav (which lives in the site-header rails).
   Hidden on mobile — drawer handles it. */
.page-subnav {
    /* Inline sticky sibling-nav. Surfaces the section's peer pages
       (e.g. the Mallorca disciplines: Incentives, Meetings, Team
       Building…) so you can move between them without digging into the
       hamburger drawer. Hidden on mobile (<720px) — the drawer covers
       that case. */
    display: block;
    position: sticky;
    /* Sticks right below the site-header. The actual rendered header
       height is published as --site-header-h by js/header-scroll.js
       (ResizeObserver-tracked), so this stays correct if the header's
       padding/font/border ever changes. Fallback used pre-JS / SSR. */
    top: var(--site-header-h, 73px);
    z-index: 15;
    background: var(--bg);
    border-bottom: 1px solid var(--hairline);
}
.page-subnav__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    /* Left padding clears the brand plate, which hangs into the
       subnav row by ~37px (1.5x header height). gutter (brand left
       offset) + --brand-w (published live by header-scroll.js) +
       small gap keeps the first link past the brand right edge. */
    padding: var(--s-5) var(--gutter) var(--s-3) calc(var(--gutter) + var(--brand-w, 220px) + var(--s-5));
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s-5);
    font-family: var(--sans);
    font-size: 0.9rem;
}
.page-subnav__label {
    font-family: var(--sans);
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--ink);
    letter-spacing: 0.01em;
}
.page-subnav__label::after {
    content: " ·";
    color: var(--ink-muted);
    margin-left: 4px;
}
/* Parent label is a link back UP to the section root (destination
   landing / pillar page). Inherits the label's weight + colour so it
   reads as the section name, not a button. Underline only on hover —
   restrained back affordance, no icon clutter. */
.page-subnav__label a {
    color: inherit;
    text-decoration: none;
    transition: color 120ms ease;
}
.page-subnav__label a:hover,
.page-subnav__label a:focus-visible {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.page-subnav__links {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-5);
}
.page-subnav__links li,
.page-subnav__links a {
    font-family: var(--sans);
}
.page-subnav__links a {
    color: var(--ink-soft);
    text-decoration: none;
    font-size: 0.9rem;
    letter-spacing: 0.03em;
    transition: color 120ms ease;
}
.page-subnav__links a:hover,
.page-subnav__links a.is-current { color: var(--accent); }
.page-subnav__links a.is-current {
    border-bottom: 1px solid var(--accent);
    padding-bottom: 2px;
}
@media (max-width: 720px) {
    .page-subnav { display: none; }
}

/* Inline variant — sits BELOW the hero as a solid sticky bar (vs the
   top-placed bar that floats over the hero). It lives inside the
   maxw-constrained article, so it breaks out to span the viewport while
   __inner re-applies the rail; and it drops the brand-plate offset since
   it's no longer beside the masthead. Solid skin always — the over-hero
   transparent treatment below is scoped to the top bar only. */
.page-subnav--inline {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    /* Always hold a breathing band below the bar so the first section
       never butts against it. The first block can't be relied on for
       this: most carry the universal s-11 section padding, but a
       `.has-section-rule` block zeroes its top padding outright and
       leaves its eyebrow/heading crowding the bar (e.g. "Ibiza in
       Zahlen" on the DMC pages). The margin lives at the bar's flow
       position, so sticky docking is unaffected — content still
       scrolls flush under the stuck bar. */
    margin-bottom: var(--s-6);
    /* Bar is full-bleed (so the background sits under the docked header),
       but the hairline belongs to the content rail — drop the full-width
       border and redraw it inside __inner, gutter-inset, below. */
    border-bottom: 0;
}
.page-subnav--inline .page-subnav__inner {
    padding-left: var(--gutter);
    padding-right: var(--gutter);
    position: relative;
}
/* Hairline matched to the content rail (maxw minus gutters), so it lines
   up with the page body and the subnav links above it — not the viewport. */
.page-subnav--inline .page-subnav__inner::after {
    content: "";
    position: absolute;
    left: var(--gutter);
    right: var(--gutter);
    bottom: 0;
    border-bottom: 1px solid var(--hairline);
}

/* ---------- Sub-nav ------------------------------------------------ */

.site-subnav {
    background: transparent;
    border-bottom: none;
}

/* Mega-menu hover dropdowns on Global nav items.
   Each dropdown spans the full subnav width (anchored to .site-subnav)
   and uses an auto-fill grid so children flow into multiple columns
   when there are more than ~4 items. Pure CSS reveal via hover /
   focus-within. Mobile uses the off-canvas drawer (this whole bar is
   display:none below 720px). */
.site-subnav--combined {
    position: relative;
}
/* Inline variant — dropdown anchors to the sticky .site-header so it
   spans the full row width below the header instead of the narrow
   nav width. */
.site-subnav--inline { position: static; }
/* Hover bridge: each <li> carries the bottom padding that used to live
   on the subnav's __inner. This extends the <li>:hover hit-area down to
   the very bottom of the subnav, eliminating the dead zone between the
   link text and the dropdown. Visually identical (padding has no bg). */
.site-subnav__links--global > li {
    padding-bottom: var(--s-4);
}
.site-subnav__links--global > li.has-dropdown > a::after {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    border-right: 1px solid currentColor;
    border-bottom: 1px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    margin-left: 6px;
    opacity: 0.55;
    transition: transform 200ms ease, opacity 200ms ease;
}
.site-subnav__links--global > li.has-dropdown:hover > a::after,
.site-subnav__links--global > li.has-dropdown:focus-within > a::after {
    transform: translateY(0) rotate(225deg);
    opacity: 1;
}
.site-subnav__dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: #ffffff;
    border-top: 1px solid var(--hairline);
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--shadow-3);
    padding: var(--s-7) var(--gutter) var(--s-8);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity 220ms ease, transform 220ms ease, visibility 0ms 220ms;
    z-index: 30;
}
.site-subnav__links--global > li.has-dropdown:hover > .site-subnav__dropdown,
.site-subnav__links--global > li.has-dropdown:focus-within > .site-subnav__dropdown,
.site-subnav__dropdown:hover {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 220ms ease, transform 220ms ease, visibility 0ms 0ms;
}
.site-subnav__dropdown-eyebrow {
    margin: 0 0 var(--s-5);
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.site-subnav__dropdown-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--s-6) var(--s-5);
}
.site-subnav__dropdown a {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    text-decoration: none;
    color: var(--ink);
    transition: color 150ms ease;
}
/* Thumb: 16:10 frame with FocusFill image inside. Image inherits size
   from the FocusFill output; we just constrain the wrapper aspect. */
.site-subnav__dropdown-thumb {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    background: var(--bg-soft);
    overflow: hidden;
    border-radius: var(--r-sm);
    transition: transform 350ms cubic-bezier(.22,.61,.36,1);
}
.site-subnav__dropdown-thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--card-img-hover-duration) var(--card-img-hover-easing);
}
.site-subnav__dropdown-label {
    font-family: var(--sans);
    font-size: 0.78rem;
    letter-spacing: 0.03em;
}
.site-subnav__dropdown a:hover { color: var(--accent); }
.site-subnav__dropdown a:hover .site-subnav__dropdown-thumb img {
    transform: scale(var(--card-img-hover-scale));
}
.site-subnav__links {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-5);
}
.site-subnav__links a {
    color: var(--ink-soft);
    text-decoration: none;
    font-size: 0.9rem;
    letter-spacing: 0.03em;
}
.site-subnav__links a:hover,
.site-subnav__links a.is-current {
    color: var(--accent);
}
.site-subnav__links a.is-current {
    border-bottom: 1px solid var(--accent);
    padding-bottom: 2px;
}

/* ---------- Breadcrumb -------------------------------------------- */

.breadcrumb {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-5) var(--gutter) 0;
    font-size: 0.8rem;
    color: var(--ink-soft);
}
.breadcrumb ol {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
}
.breadcrumb li + li::before {
    content: "/";
    margin-right: var(--s-2);
    color: var(--hairline);
}
.breadcrumb a {
    color: var(--ink-soft);
    text-decoration: none;
}
.breadcrumb a:hover { color: var(--accent); }
.breadcrumb li[aria-current="page"] span { color: var(--ink); }

/* Full-bleed layouts (Home / DMC) hide the breadcrumb — their heroes
   sit directly below the header rail by design. */
.t-App\\PageType\\HomePage .breadcrumb,
.t-App\\PageType\\DMCPage .breadcrumb { display: none; }

/* ---------- Page layout -------------------------------------------- */

main {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-9) var(--gutter) var(--s-10);
}

.page__head {
    margin-bottom: var(--s-8);
    max-width: var(--measure);
}

.page__title {
    font-size: var(--t-display);
    line-height: 1.05;
    margin: 0 0 var(--s-5);
}

/* ---------- Lead typography (single source of truth) ----------------
   Two tiers, both sans. Contrast vs body is carried by size + weight +
   line-height, not family/style — the serif-italic lede was readable
   but felt like a second voice arguing with the headline above it.

   .lead-editorial — sans 300 (Light), full ink, generous size. Default
   lead voice for page subtitles, ledes, taglines, prose .lead. Sister
   classes (.page__subtitle, .article__tagline, .why-us__lead, etc.)
   compose onto this via the grouped selectors so existing templates
   do not need markup changes. The 300 weight creates the editorial
   triad: bold 700 headline → light 300 lede → regular 400 body.
   Mirrors the <em>-in-headline rule (also 300 against 700). */
.lead-editorial,
.page__subtitle,
.page__lead,
.contact-page__lead,
.contact-direct__lead,
.service__lead,
.why-us__lead,
.sister-brands__lead,
.icon-grid-block__lead,
.newsletter-block__lead,
.product__subtitle,
.product__tagline,
.article__tagline,
.prose .lead,
.prose p.lead,
.prose .copy .lead,
.lead {
    font-family: var(--sans);
    font-weight: 300;
    font-style: normal;
    font-size: clamp(1.2rem, 1.9vw, 1.35rem);
    line-height: 1.4;
    letter-spacing: 0;
    color: var(--ink);
    text-wrap: balance;
    margin: 0 0 var(--s-6);
}

/* .page__subtitle sits directly under the page__head H1 and is the only
   lead surface designed to be pulled tight against the heading above.
   Other lead surfaces (taglines, ledes in body context) keep neutral
   top spacing from the shared rule. */
.page__subtitle {
    margin-top: calc(var(--s-5) * -1);
}

.key-facts {
    list-style: none;
    padding: 0;
    margin: var(--s-6) 0 var(--s-8);
    max-width: var(--measure);
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
}
.key-facts__item {
    display: flex;
    align-items: flex-start;
    gap: var(--s-5);
    font-size: 1.05rem;
    line-height: 1.45;
    color: var(--ink);
}
.key-facts__tick {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    margin-top: 0.2em;
}
.key-facts__tick svg { display: block; }
.key-facts__value {
    flex: 1 1 auto;
}

.page__byline {
    font-size: 0.9rem;
    color: var(--ink-soft);
    margin: var(--s-2) 0 var(--s-5);
}

.page__body,
.prose {
    max-width: var(--measure);
    /* The reading/prose tier. Was inherited silently from body (17px/1.55);
       made explicit so a future body-size change can't move every article. */
    font-size: var(--t-body-lg);
    line-height: var(--lh-body);
}
/* ── Headings in rich text ────────────────────────────────────────────
   BOTH rich-text wrappers, one declaration. `.prose` is editorial copy;
   `.content-element__content` is what the elemental Content block emits.
   They carry the same thing — HTML an editor typed in TinyMCE, where no
   class can be attached to a heading — so they get the same defaults.
   Only `.prose` had them, which left 43 migrated blocks with bare <h2>
   and <h3> falling through to the browser default (found 2026-08-07 by
   the grid-discipline sweep; 25.5px, which sits between the two real
   tiers and therefore looked deliberate).

   EVERYTHING HERE IS :where(), SO THE WHOLE BLOCK SCORES (0,0,0).
   These are DEFAULTS for markup nobody could class, not rules. Any class
   on the heading — `.h--display` above all — must win without !important,
   and `.prose > :first-child` must be able to cancel the top margin.
   That last one is why the margins moved in here too: at (0,1,1) the old
   `.prose h2` beat the (0,1,0) first-child guard below, so a column that
   opened with a heading got an unwanted ~52px indent that the guard was
   written to prevent and never could.

   The whole selector goes inside :where(), not just the tag. `.prose
   :where(h2)` still scores (0,1,0) from the class and merely TIES with
   .h--display — and a tie falls to source order, which app.css wins.
   Zero still beats the UA sheet: author rules outrank it at any
   specificity, so unclassed markup keeps these sizes. */
:where(.prose h2, .content-element__content h2) {
    font-size: var(--t-h2);
    margin-top: var(--s-8);
}
:where(.prose h3, .content-element__content h3) {
    font-size: var(--t-h3);
    margin-top: var(--s-6);
}
:where(.prose h4, .content-element__content h4) {
    font-size: var(--t-h4);
    margin-top: var(--s-6);
}
/* Family is NOT repeated here: tokens.css already sets sans + 700 on
   every h1–h4. It used to be restated when body copy was serif. */
:where(.content-element__content > :first-child) { margin-top: 0; }
.prose p { margin: 0 0 var(--s-5); }
.prose ul, .prose ol { padding-left: var(--s-5); margin: 0 0 var(--s-5); }
.prose li { margin: var(--s-2) 0; }
/* The heading margins above separate a heading from the copy BEFORE it.
   When the heading is the block's first child there is nothing before it,
   so that margin stops being separation and becomes a top indent on the
   whole column — which is how the /unser-versprechen intro ended up with
   its <h2> starting ~64px below the first line of the column beside it.
   ElementTextText already guards its own $Headline field this way
   (.element-textext__headline, ~line 1690); migrated copy carries the <h2>
   inside LeftContent instead, so it never reached that guard. 20 blocks
   are in that shape.

   Same `> :first-child` reset the panel, card and footnote surfaces use. */
.prose > :first-child { margin-top: 0; }
/* Imported rich text can force horizontal scroll on phones two ways:
   a <pre> (e.g. the legal pages' <pre class="AHinweis">) whose default
   white-space:pre never wraps — an ordinary paragraph pasted into one ran
   ~2400px wide — and bare long URLs/words that don't break. Wrap both;
   covers ElementContent and editorial prose. */
.prose,
.content-element__content {
    overflow-wrap: break-word;
}
.prose pre,
.content-element__content pre {
    white-space: pre-wrap;
    overflow-wrap: break-word;
    word-break: break-word;
}

/* Content block as a card — opt-in via the CMS "Style variation → Card"
   dropdown (config: ElementContent.styles in elemental-canvas.yml). The
   block then carries `.card` and reads as a distinct panel rather than
   running copy. Primary use: the "So arbeiten wir" beat on a ServicePage
   ("was wir tun" subpage). The surface treatment is the shared PANEL
   canon at the top of this file — no per-component declarations here. */

/* Legacy SS3 elemental-block wrappers that arrive inside Page.Content.
   The legacy site rendered these as 2-col grids via heavy nested div
   markup (block-colum/block-column with .copy children). lxp6 just lets
   them flow as a single editorial column — `display: contents` makes
   the wrappers transparent to layout so the prose typography reaches
   the inner h2 / p / ul / li directly. */
.prose .element[class*="Block_"],
.prose .block-colum,
.prose .block-column,
.prose .copy,
.prose .copy .Text,
.prose .copy .Ohne {
    display: contents;
}
.prose .no-margin-top { margin-top: 0; }

/* ---------- Elemental blocks (App\Element\*) -----------------------
   ===================================================================
   THE CONTAINER CONTRACT (general site pattern)
   ===================================================================

   Default: <main> owns the rail. It applies `max-width: var(--maxw)`
   and horizontal `padding: var(--gutter)`. Everything inside —
   including .page__elements and every elemental block — lives in
   that bounded content box. Blocks must NOT redeclare maxw or gutter
   themselves; doing so produces a one-gutter double-indent that
   silently breaks alignment with sibling grids on the same page (e.g.
   .team-grid → text block offset right by ~48px at desktop).

   Exception (THREE pages only): HomePage, DMCPage, ContactPage strip
   <main> via `.t-App\PageType\<X> main { max-width: none; padding: 0 }`
   so heroes can run viewport-wide. On those pages — and ONLY those
   pages — each block must self-bound (own maxw + auto margins + own
   gutter padding). Anywhere else, self-bound = double-indent bug.

   Rule of thumb when writing a new block / debugging alignment:
     • Inside .page__elements?  →  Stay BARE by default.
     • Used on a stripped-main page?  →  Restore bounds inside a
       page-scoped selector (`.t-App\PageType\HomePage .my-block { ... }`)
     • Need a 12-col rail for partial-width?  →  Use `.element.is-partial`
       at line ~1118; it already follows this contract.

   Fixed in line with this contract:
     – .element.is-partial   (this file, ~1118)
     – .element-textext      (this file, ~1258)
     – .element-imgtext      (this file, ~1258)

   Known older blocks that still self-bound (work today only because
   they live exclusively on stripped-main pages — homepage chrome).
   If reused on a bounded-main page they'll need the same conversion:
     .home-hero, .home-destinations, .home-section, .why-us, .affiliation,
     .case-rail-wrap, .sister-brands, .editorial-intro, .key-figures,
     .trusted-by-row, .home-rfp-cta, .rfp, .faq, .page-slides,
     .case-study--editorial, .contact-page__head/__body, .article,
     .newsletter-block, .article-holder__head.
   =================================================================== */
.page__elements { /* intentionally bare per the contract above */ }

/* ---- Page-level partial-width blocks ------------------------------
   Activates per-block on any `.element.is-partial` (marker class set
   by ElementPageLayoutExtension when LayoutSpan != 12 or LayoutOffset
   != 0). Sibling full-width blocks are NOT affected — they keep their
   existing internal layout, gutters, and full-bleed behaviour. The
   partial block lives inside a maxw-constrained rail and positions
   its inner content on a 12-column sub-grid via inline custom
   properties (`--layout-span` / `--layout-offset`).

   This deliberately gives up automatic side-by-side pairing of two
   partial siblings — each partial sits on its own row. The trade-off
   buys us total non-interference with existing full-width block
   styling. When real editorial demand surfaces for paired rows,
   revisit with a proper grid container + explicit gutter tracks. */
.element.is-partial {
    box-sizing: border-box;
}
/* Self-bound only on pages that strip <main> (HomePage / DMCPage /
   ContactPage). On every other page <main> already provides maxw +
   gutter, so adding them here would double-indent the inner content
   by one gutter and break alignment with sibling grids (e.g. team-grid). */
.t-App\\PageType\\HomePage .element.is-partial,
.t-HomePage .element.is-partial,
.t-App\\PageType\\DMCPage .element.is-partial,
.t-App\\PageType\\ContactPage .element.is-partial {
    max-width: var(--maxw);
    margin-left: auto;
    margin-right: auto;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
}
.element.is-partial > * {
    /* --col-w wird HIER definiert (nicht auf .is-partial selbst), damit
       100% die Content-Box des Wrappers referenziert — das ist die
       tatsächliche verfügbare Breite. Vorher rechnete die Formel mit
       --maxw (fest 1440px), wodurch bei Viewports < 1440px der Inhalt
       um die Differenz nach rechts aus dem Grid lief.

       DER GUTTER IST BOOTSTRAPS 24px, nicht --gap-m (40px), wie bis
       2026-08-07. Diese zwölf Spalten sind dieselben zwölf Spalten, auf
       denen `.row > .col-*` liegt — sonst meint "Offset 6" hier eine
       andere Linie als "col-7" dort, und ein per Composer nach rechts
       gerückter Block verfehlt den Bootstrap-Block darunter um ~8px.
       Nah genug, um wie Absicht auszusehen. Mit 24px fallen beide
       Systeme exakt aufeinander. */
    --col-w: calc((100% - 11 * 1.5rem) / 12);
    box-sizing: border-box;
    max-width: none;
    padding-left: 0;
    padding-right: 0;
    margin-left: calc(var(--layout-offset, 0) * (var(--col-w) + 1.5rem));
    margin-right: 0;
    width: calc(var(--layout-span, 12) * var(--col-w) + (var(--layout-span, 12) - 1) * 1.5rem);
}
/* Mobile: partial blocks stack full-width — column math on phones
   looks broken regardless of design taste. */
@media (max-width: 800px) {
    .element.is-partial > * {
        width: 100%;
        margin-left: 0;
    }
}

/* ---- Side-by-side pair: Affiliation + Testimonial -----------------
   On the homepage the TOURVEST announcement and the testimonial slider
   sit as one row instead of two beats. Four-column grid: outer 1fr
   spacers absorb extra viewport so the pair caps at `--maxw` centered
   (matching the main-content width), inner cells host the two blocks.
   Other elements span 1 / -1 (full-bleed) and keep their own widths.
   Stacks vertically on narrow viewports. */
@media (min-width: 900px) {
    .page__elements:has(> .app__element__elementaffiliation + .app__element__elementtestimonial) {
        display: grid;
        grid-template-columns:
            1fr
            minmax(0, calc((var(--maxw) - var(--s-6)) / 2))
            minmax(0, calc((var(--maxw) - var(--s-6)) / 2))
            1fr;
        column-gap: var(--s-6);
        align-items: start;
    }
    .page__elements:has(> .app__element__elementaffiliation + .app__element__elementtestimonial) > .element {
        grid-column: 1 / -1;
    }
    /* :has(> A + B) has specificity (0,2,0) because both class-selectors
       inside the compound count — so the half-cell rules need an extra
       class qualifier (`.element.app__...`) to land at (0,4,0), matching
       the full-width rule above. */
    .page__elements > .element.app__element__elementaffiliation:has(+ .app__element__elementtestimonial) {
        grid-column: 2 / 3;
    }
    .page__elements > .element.app__element__elementaffiliation + .element.app__element__elementtestimonial {
        grid-column: 3 / 4;
    }
    /* The paired blocks share a row — drop their full-width centering so
       they fill the half-cell instead. */
    .page__elements > .element.app__element__elementaffiliation:has(+ .app__element__elementtestimonial) .affiliation {
        max-width: none;
    }
}

/* Grid layout container (App\Element\ElementGridList).
   `--cols` and `--gap` come from inline style set by the template;
   defaults match the design-system tokens. Children render as cells
   with `grid-column: span N` (or `1 / -1` when GridSpan is 0). */
.lxp-grid {
    display: grid;
    grid-template-columns: repeat(var(--cols, 12), minmax(0, 1fr));
    gap: var(--gap, var(--gap-l));
    margin: var(--s-9) 0;
}
.lxp-grid__cell { min-width: 0; }
@media (max-width: 720px) {
    /* Collapse to a single column on narrow viewports — declared spans
       become noise on phones. */
    .lxp-grid { grid-template-columns: 1fr; }
    .lxp-grid__cell { grid-column: 1 / -1 !important; }
}

/* Split mode (App\Element\ElementGridList.Split). The container fixes a
   two-column ratio via the inline `--split` custom property (e.g.
   "1fr 2fr"); children auto-flow into the two tracks by source order and
   their own GridSpan is ignored. `align-items: start` keeps a short
   column (e.g. key facts) from stretching beside a tall one (body copy).
   The mobile override is declared AFTER the desktop rule so it wins over
   it on narrow viewports. */
.lxp-grid--split {
    grid-template-columns: var(--split, 1fr 2fr);
    align-items: start;
}
@media (max-width: 720px) {
    .lxp-grid--split { grid-template-columns: 1fr; }
}
/* Key facts in a grid cell sit flush with the top of their column —
   drop the standalone block's top margin (it keeps it below a hero). */
.lxp-grid__cell .key-facts { margin-top: 0; }

/* Icon grid block (App\Element\ElementIconGrid). N-up grid of
   centered icon + title + description cards. Icon is whatever the
   editor uploads (SVG preferred). Auto-collapses to single column
   on phones. */
.icon-grid-block { margin: var(--s-9) 0; }
.icon-grid-block__head { text-align: center; margin: 0 auto var(--s-7); }
.icon-grid-block__title { margin: 0 0 var(--s-3); }
.icon-grid-block__lead { color: var(--ink-2, var(--ink)); margin-left: auto; margin-right: auto; }

.icon-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
    gap: var(--s-9) var(--s-7);
    text-align: center;
}
.icon-grid__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 var(--s-3);
}
/* Icons render as a CSS mask of the SVG so the colour is set via
   `background-color`, not by whatever fill the SVG ships with. The
   block sets `--icon-color` (defaulting to var(--accent)); each card
   sets `--icon-url` inline from the IconCard's Icon URL. */
.icon-grid__icon {
    display: block;
    margin: 0 0 var(--s-4);
    width: 80px;
    height: 80px;
    background-color: var(--icon-color, var(--accent));
    -webkit-mask: var(--icon-url) center / contain no-repeat;
            mask: var(--icon-url) center / contain no-repeat;
}
.icon-grid__title {
    font-family: var(--sans);
    font-size: var(--t-h4);
    font-weight: 600;
    margin: 0 0 var(--s-2);
    /* Inherit body ink — the icon already carries the accent. If you
       want titles tinted to match the icons (legacy LXP behaviour),
       set `color: var(--icon-color, var(--accent));` on this rule. */
}
.icon-grid__desc {
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--ink-2, var(--ink));
    margin: 0;
}
/* Image mode — the asset renders as-is because its colour is part of the
   mark (UN SDG tiles, certification logos). See ElementIconGrid::$IconStyle.

   Everything here is subtraction. The cards carry no `.card` class in this
   mode, no title and no description, so the grid is marks and nothing else:
   the SDG tiles already contain their number and their name, set in the UN's
   own typography, and a caption underneath would say it twice in a second
   language. Tighter row gap than the tinted grid for the same reason — with
   no text between rows the generous --s-9 read as a gap, not a rhythm. */

/* An image-mode grid is almost always a continuation of the paragraph above
   it rather than a section in its own right — on /unser-versprechen the
   intro's closing sentence ("… beeinflussen wir unmittelbar acht der 17
   nachhaltigen Entwicklungsziele") IS this block's caption. So it opts out of
   the global `.element > section { padding-top: var(--s-11) }` beat and sits
   close under the sentence it belongs to. Specificity has to beat
   `.element > section`, hence the compound selector.

   Only the TOP is collapsed. The bottom margin stays: the next block's
   section rule is absolutely positioned at `top: 0` of its own element, so
   with no space below the marks the rule lands flush on the bottom row of
   tiles instead of in the gap it is supposed to mark. */
.element > section.icon-grid-block--image {
    padding-top: 0;
    margin: var(--s-7) 0 var(--s-9);
}

.icon-grid--image {
    /* Fixed track width, packed to the left — NOT `1fr` columns. Stretched
       across the full rail each cell was ~300px holding a 160px mark, so the
       set read as eight scattered stamps instead of one field of evidence.
       Packed left it also starts on the same rail edge as the paragraph above,
       which is what makes it read as that paragraph's illustration. */
    grid-template-columns: repeat(var(--cols, 4), 160px);
    justify-content: start;
    gap: var(--s-5);
    align-items: start;
}
.icon-grid--image .icon-grid__card { padding: 0; }
.icon-grid__mark {
    display: block;
    width: 100%;
    height: auto;
    /* The official tiles are square with the label set inside the artwork,
       so they need real size to stay legible — but capped, or eight of them
       become the loudest thing on a page whose whole argument is restraint. */
    max-width: 160px;
    margin: 0;
}

@media (max-width: 720px) {
    /* 2-up on phones/narrow tablets instead of a single-column stack —
       compact icon+title+desc cards pair cleanly and halve the section
       height on mobile (was 1-col pre-2026-06-05). */
    .icon-grid { grid-template-columns: 1fr 1fr; gap: var(--s-7) var(--s-5); }
    /* Image mode holds its column count one step longer: the marks are
       square and self-contained, so a 2-up of them wastes half the width
       where a 2-up of icon+title+desc cards is exactly right. Tracks go
       fluid here — below the desktop rail there is no spare width to pack
       against, so a fixed 160px would overflow before it grouped anything. */
    .icon-grid--image {
        grid-template-columns: repeat(4, minmax(0, 1fr));
        justify-content: stretch;
        gap: var(--s-4);
    }
    .icon-grid__mark { max-width: 120px; margin: 0 auto; }
    .icon-grid__desc { max-width: none; }
    .icon-grid__icon { width: 56px; height: 56px; }
    /* Defensive overflow guard: flex card child defaults to min-width:auto,
       so a long unbroken title could push the 2-up track past the viewport.
       overflow-wrap breaks any over-long word so it can never out-size the
       track. No visual change at normal content. (2026-06-05) */
    .icon-grid__card { min-width: 0; }
    .icon-grid__title,
    .icon-grid__desc { overflow-wrap: anywhere; }
}
@media (max-width: 560px) {
    /* Image mode steps down before the tinted grid does. The labels are set
       inside the artwork and cannot reflow, so a mark has a hard floor below
       which it stops being readable — narrower than a caption's. */
    .icon-grid--image { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 380px) {
    /* Genuinely tiny screens fall back to a single column so the icon
       cards don't get crushed. */
    .icon-grid { grid-template-columns: 1fr; }
    /* Marks stay 2-up: they are square and wordless-in-layout, so a single
       column here would be eight full-width tiles and a very long scroll. */
    .icon-grid--image { grid-template-columns: 1fr 1fr; }
}

/* Bare inside .page__elements per the contract at line ~1092:
   <main> already applies max-width and gutter. Adding either here
   would double-indent the block relative to siblings (e.g. .team-grid)
   that correctly use main's bounds only. */
.element-textext,
.element-imgtext {
    margin: var(--s-9) 0;
}
/* Wrapping selector adds an extra class to win specificity against
   `.prose h2` (the headline now sits inside the .prose lead column).
   Without this, prose's `margin-top: var(--s-8)` would push the
   headline down — we want it flush at the top of the column.

   SIZE IS NOT SET HERE. Both templates carry `.h--display`, so the size
   comes from --t-section like every other section-opening h2 in the
   codebase. It used to be `--t-h2` (22px), which is the sub-label tier —
   one step too low for a headline that opens a block, and the reason
   these headlines read smaller than the .sustainability / .commitments /
   credential-rail titles they sit beside. Setting font-size or
   line-height here again would out-specify .h--display (0,2,0 vs 0,1,0)
   and silently reintroduce the mismatch. */
.element-textext .element-textext__headline,
.element-imgtext .element-imgtext__headline {
    margin: 0 0 var(--s-5);
    max-width: 28ch;
}
.element-textext__cols {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-6);
    align-items: start;
}
/* Two equal tracks with a 24px gap — arithmetically identical to Bootstrap
   `.row > .col-6 + .col-6`: track 2 starts at 50% + 12px, which is where
   Bootstrap's column 7 starts. That equality is the whole point. This block
   is stacked with 12-col blocks (the credential rail, .sustainability,
   .commitments) whose body copy starts at column 7, and it has to land on
   the same line.

   IT USED TO BE `1fr  minmax(0, calc(var(--measure) + var(--s-8)))` with a
   52px gap — a body track of a fixed ~657px. Because that track was fixed
   and Bootstrap's is proportional, the two only agreed at one viewport
   width (~1430px, where the max-width rail caps out). Below that they came
   apart fast: 77px at 1280, 117px at 1200, ~200px at 1024. Nothing was
   wrong on any one screen, which is why it survived — it was only visible
   when you compared two blocks on one page at a laptop width.

   The `min(100%, 30ch)` floor the old left track carried is gone with it:
   it existed to stop the fixed body track crushing the lead column in the
   820–1100px band. Two proportional tracks cannot crush each other.

   `.prose` still caps the text inside at the 64ch measure, so line length
   is unchanged; only the tracks move. */
/* Scoped with :has() so the second track only exists when a second column
   does. Without the guard, a block with no Headline and no LeftContent —
   the "lead only" shape — renders its single child into track 1 and
   reserves the other half for nothing. Harmless at full width (.prose
   caps the text at the measure anyway), but wrong the moment the block
   is set to a partial column: in a 6-col block the lead would be squeezed
   into 3. */
@media (min-width: 820px) {
    .element-textext__cols:has(.element-textext__left) {
        grid-template-columns: 1fr 1fr;
        gap: 1.5rem;   /* --bs-gutter-x; Bootstrap only sets it on .row */
    }
}
/* Padding only when a column has a background colour. The `--padded`
   class is added by the template when LeftBgColor / BodyBgColor is
   non-empty; without a bg, columns stay flush against the page grid. */
.element-textext__left--padded,
.element-textext__body--padded {
    padding: var(--s-7);
}
@media (min-width: 820px) {
    .element-textext__left--padded,
    .element-textext__body--padded {
        padding: var(--s-8);
    }
}
/* Flip ink when a dark bg token is picked (espresso / Accent). Mirrors
   .section--deep so prose, headlines, and hairlines stay readable. */
.element-textext__left--inverse,
.element-textext__body--inverse {
    --ink:           #f4f1ea;
    --ink-soft:      rgba(244, 241, 234, 0.72);
    --ink-muted:     rgba(244, 241, 234, 0.55);
    --hairline:      rgba(244, 241, 234, 0.18);
    --hairline-soft: rgba(244, 241, 234, 0.08);
    color:           var(--ink);
    font-weight:     400;   /* light-on-dark: stay regular (base sans is 300) */
}

.element-imgtext {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-6);
    align-items: start;
}
@media (min-width: 820px) {
    .element-imgtext { grid-template-columns: 1fr 1fr; gap: var(--s-8); }
}
.element-imgtext__figure { margin: 0; }
.element-imgtext__figure img { width: 100%; height: auto; display: block; }

/* ---------- Team member bio (single page) -------------------------- */

.team-bio__back,
.article__back {
    margin: 0 0 var(--s-6);
    font-family: var(--sans);
    font-size: 0.78rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.team-bio__back a,
.article__back a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color 120ms ease, border-color 120ms ease;
}
.team-bio__back a:hover,
.article__back a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.team-bio__back span,
.article__back span { margin-right: 0.35em; }

/* Editorial 2-track header: name in left rail column, portrait in
   right body column. Shares 2fr/4fr geometry with .team-bio__grid
   below so vertical rhythm runs name→role and photo→body cleanly. */
.team-bio__head-grid {
    display: grid;
    /* minmax(0, …) so an unbreakable long word in the name cannot
       force the rail track to expand past its 2fr share. */
    grid-template-columns: minmax(0, 2fr) minmax(0, 4fr);
    gap: var(--s-9);
    align-items: start;
    margin: 0 0 var(--s-9);
}
@media (max-width: 860px) {
    .team-bio__head-grid {
        grid-template-columns: 1fr;
        gap: var(--s-7);
    }
}

.team-bio__head {
    grid-column: 1;
    margin: 0;
}
.team-bio__name {
    font-size: var(--t-display);
    line-height: 1.05;
    margin: 0;
    overflow-wrap: anywhere;
}

.team-bio__head-grid .team-bio__banner {
    grid-column: 2;
    margin: 0;
}
@media (max-width: 860px) {
    .team-bio__head-grid .team-bio__banner { grid-column: 1; }
}
.team-bio__banner img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* Rail + body share the banner-grid's column geometry (2fr 4fr) so
   the body's leading edge aligns with the photo's leading edge above. */
.team-bio__grid {
    display: grid;
    grid-template-columns: 2fr 4fr;
    gap: var(--s-9);
    align-items: start;
}
@media (max-width: 860px) {
    .team-bio__grid {
        grid-template-columns: 1fr;
        gap: var(--s-7);
    }
}

.team-bio__rail {
    position: sticky;
    top: var(--s-9);
}
@media (max-width: 860px) {
    .team-bio__rail { position: static; }
}

.team-bio__role {
    font-family: var(--serif);
    font-weight: 400;
    font-style: italic;
    font-size: clamp(1.15rem, 1.6vw, 1.4rem);
    line-height: 1.3;
    color: var(--ink-soft);
    margin: var(--s-4) 0 0;
}

.team-bio__contact {
    margin: 0;
    padding-top: var(--s-5);
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--s-3) var(--s-5);
}
.team-bio__contact dt {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-soft);
    align-self: center;
}
.team-bio__contact dd { margin: 0; }
.team-bio__contact a {
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px solid var(--hairline);
    transition: border-color 120ms ease, color 120ms ease;
}
.team-bio__contact a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

.team-bio__body { max-width: var(--measure); }
.team-bio__body .page__elements > * + * { margin-top: var(--s-7); }

/* Prev/next layout via Bootstrap .row + .col-sm-6 on the children.
   Spans full main width (lives outside team-bio__grid). Gutter overridden
   to match editorial spacing; y-gutter kicks in below sm when cols stack. */
.team-bio__nav {
    margin: var(--s-9) 0 0;
    padding-top: var(--s-6);
    border-top: var(--rail-soft);
    --bs-gutter-x: var(--s-6);
    --bs-gutter-y: var(--s-5);
}
.team-bio__nav-link {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    text-decoration: none;
    color: inherit;
}
/* Right-align only when prev/next sit side-by-side (sm and up).
   Below sm they stack and read left-aligned. */
@media (min-width: 576px) {
    .team-bio__nav-link--next { text-align: right; }
}
.team-bio__nav-label {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.team-bio__nav-title {
    font-family: var(--serif);
    font-style: italic;
    font-size: 1.1rem;
    line-height: 1.3;
    color: var(--ink);
}
/* ---------- Product detail — typography + facts -------------------- */

/* Section split: typographic primitives + facts list live here; the
   editorial grid (Bootstrap rail, row rhythm) is owned by the
   "Product detail (editorial layout)" block lower in this file. */

.product__back {
    margin: 0 0 var(--s-5);
    font-size: 0.9rem;
    letter-spacing: 0.02em;
}
.product__back a {
    color: var(--ink-soft);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 2px;
    transition: color 150ms ease, border-color 150ms ease;
}
.product__back a:hover {
    color: var(--ink);
    border-bottom-color: var(--accent);
}
.product__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-hero);
    line-height: 1.05;
    margin: 0 0 var(--s-5);
    letter-spacing: -0.015em;
    max-width: 28ch;
    text-wrap: balance;
}
.product__hero img {
    width: 100%;
    height: auto;
    aspect-ratio: 16/9;
    object-fit: cover;
    display: block;
}

.responsibility {
    list-style: none;
    padding: 0 0 var(--s-6);
    margin: 0 0 var(--s-6);
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--s-5) var(--s-6);
    border-bottom: 1px solid var(--hairline);
}
.responsibility__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--s-2);
}
.responsibility__icon {
    width: 72px;
    height: 72px;
    display: block;
}
.responsibility__label {
    font-size: 0.78rem;
    line-height: 1.25;
    letter-spacing: 0.02em;
    color: var(--ink-soft);
    max-width: 100%;
    margin-top: var(--s-2);
}

.product-facts {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--s-6);
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
    padding-bottom: var(--s-6);
    border-bottom: 1px solid var(--hairline);
}
.product-facts__item {
    display: flex;
    align-items: flex-start;
    gap: var(--s-5);
    font-size: 1rem;
    line-height: 1.4;
    color: var(--ink);
}
.product-facts__icon {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    margin-top: 0.15em;
}
.product-facts__icon svg { display: block; }
.product-facts__value { flex: 1 1 auto; }

.product__location {
    margin: 0;
    padding-top: var(--s-5);
    font-size: 0.9rem;
}
.product__location-label {
    color: var(--ink-soft);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.75rem;
    margin-right: var(--s-2);
}
.product__location-value { color: var(--ink); }

/* ---------- Page-level slideshow ---------------------------------- */

/* Cross-fading hero used on every non-home page via <% include PageSlides %>.
   Matches the homepage hero keyframes (homeHeroCycle) — first slide is
   eager-loaded with priority hint, rest are low-priority so they load
   without blocking LCP but are present before they fade in. Sits inside
   the content column (no full-bleed escape). */
.page-slides {
    max-width: var(--maxw);
    margin: var(--s-6) auto var(--s-8);
    padding: 0 var(--gutter);
}
/* On the generic Page layout (<article class="page">) the surrounding
   <main> already provides max-width + gutter padding — re-applying them
   here would double-indent the hero versus other sections on the page.
   DMCPage / ArticlePage use different wrappers and zero out main's
   gutter, so they keep .page-slides' own constraints. */
article.page > .page-slides {
    max-width: none;
    margin-inline: 0;
    padding-inline: 0;
}
.page-slides__hero { margin: 0; }
.page-slides__hero img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
    border-radius: var(--r-lg);
}
.page-slides__hero figcaption {
    font-size: 1rem;
    color: var(--ink-soft);
    margin-top: var(--s-2);
    font-family: var(--serif);
    font-style: italic;
}

.page-slides__stage {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: 72vh;
    overflow: hidden;
    background: var(--surface);
    border-radius: var(--r-lg);
}
.page-slides__frame {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    animation: homeHeroCycle 60s infinite;
    animation-fill-mode: both;
    animation-timing-function: ease-in-out;
    will-change: opacity, transform;
}
.page-slides__frame:nth-child(1) { animation-delay:  0s; }
.page-slides__frame:nth-child(2) { animation-delay: 12s; }
.page-slides__frame:nth-child(3) { animation-delay: 24s; }
.page-slides__frame:nth-child(4) { animation-delay: 36s; }
.page-slides__frame:nth-child(5) { animation-delay: 48s; }
.page-slides__frame img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ---------- Product detail slideshow ------------------------------ */

/* Gallery layout is owned by the editorial block — .product__gallery
   uses the same Bootstrap .row > col-12 col-sm-6 col-lg-4 grid as
   .article__gallery, with .article-slide__trigger handling the
   image + zoom-in cursor. Caption styles live in the editorial
   block alongside the row rhythm. */

/* ---------- Product grid (listing) --------------------------------- */

.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--s-8) var(--s-6);
    margin-top: var(--s-8);
}

.product-card {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
}

.product-card__image {
    margin: 0 0 var(--s-4);
    aspect-ratio: 8 / 5;
    overflow: hidden;
    background: var(--hairline-soft);
    transition: opacity 200ms ease;
}
.product-card__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.product-card__image--empty {
    background: var(--hairline-soft);
    position: relative;
}
.product-card__image--empty::after {
    content: "";
    position: absolute;
    inset: 40% 45% 40% 45%;
    border: 1px solid var(--hairline);
    border-radius: 50%;
}

/* Mobile density — on phones the catalogue collapses to one full-width
   column; a shorter image ratio + tighter row gap keeps it scannable
   instead of an exhausting single-column scroll. (Sticky filter bar is a
   separate change — it needs to reconcile with the fold-on-scroll header.) */
@media (max-width: 540px) {
    .product-card__image { aspect-ratio: 16 / 9; }
    .product-grid { gap: var(--s-6) var(--s-5); }
}

.product-card__body {
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-1);
    flex: 1;
}
.product-card__summary {
    line-height: 1.45;
    color: var(--ink-soft);
    margin: var(--s-1) 0 0;
    flex: 1;
}

.product-card[hidden] { display: none; }

/* Featured-grid variant — homepage version of the product grid. 4-col
   asymmetric: 1st and 6th cards span 2 cols (diagonal weight, two
   featured slots). Same pattern as the services tiles. */
.product-grid--featured {
    grid-template-columns: repeat(4, 1fr);
}
.product-grid--featured > :first-child,
.product-grid--featured > :nth-child(6) {
    grid-column: span 2;
}
@media (max-width: 900px) {
    .product-grid--featured { grid-template-columns: repeat(2, 1fr); }
    .product-grid--featured > :first-child,
    .product-grid--featured > :nth-child(6) { grid-column: span 2; }
}
@media (max-width: 540px) {
    /* Stay 2-up on phones rather than collapsing to a single column —
       keeps the featured-activities strip compact. The two featured
       slots (1st + 6th) span both columns so they still read as hero
       tiles (was 1-col pre-2026-06-05). */
    .product-grid--featured { grid-template-columns: 1fr 1fr; gap: var(--s-5) var(--s-4); }
    .product-grid--featured > :first-child,
    .product-grid--featured > :nth-child(6) { grid-column: span 2; }
    /* Defensive overflow guard: card child defaults to min-width:auto, so a
       wide product image / long title could push a column past the viewport.
       overflow-wrap breaks any over-long word so the title can never out-size
       the column. No visual change at normal content. (2026-06-05) */
    .product-grid--featured .product-card { min-width: 0; }
    .product-grid--featured .product-card__title,
    .product-grid--featured .product-card__summary { overflow-wrap: anywhere; }
}
/* Defensive overflow guard for the base catalogue grid (auto-fill
   minmax(300px,1fr)). On phones the cards collapse to one column; min-width:0
   stops a wide image / long title from forcing the track past the viewport.
   No visual change at normal content. (2026-06-05) */
@media (max-width: 540px) {
    .product-grid .product-card { min-width: 0; }
    .product-grid .product-card__title,
    .product-grid .product-card__summary { overflow-wrap: anywhere; }
}
.product-grid--featured .product-card__body { padding-top: var(--s-1); }

/* ---------- Catalogue Filter Bar -----------------------------------
   Slim chip row above the product grid. Single-select category chips +
   independent "Sustainable only" toggle. Filtering is client-side
   (filter-catalogue.js) — no form submit, no reload. */

.catalogue-filters {
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-5);
    flex-wrap: wrap;
}
/* When a filter bar is present, the grid's own margin-top provides the
   separation below it — no extra margin needed on the bar itself. */
.catalogue-filters + .product-grid { margin-top: var(--s-6); }

.catalogue-filters__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    align-items: center;
}

.catalogue-filters__sep {
    display: inline-block;
    width: 1px;
    height: 18px;
    background: var(--hairline);
    margin: 0 var(--s-2);
}

.catalogue-filters__count {
    font-family: var(--sans);
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin: 0;
    font-feature-settings: "tnum";
}

/* Sustainable toggle — distinct from category chips:
   accent-coloured when active to read as a modifier, not a category. */
.chip--toggle .chip__icon {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    margin-left: -2px;
}
.chip--toggle[aria-pressed="true"],
.chip--toggle.is-active {
    background: var(--accent-faint);
    color: var(--accent-deep);
    border-color: var(--accent-soft);
}

.product-grid[hidden] { display: none; }

.catalogue-empty {
    padding: var(--s-9) 0;
    text-align: center;
    color: var(--ink-muted);
    font-family: var(--serif);
    font-style: italic;
    font-size: 1.1rem;
}
.catalogue-empty[hidden] { display: none; }

@media (max-width: 600px) {
    .catalogue-filters { gap: var(--s-3); }
    .catalogue-filters__sep { display: none; }
    .catalogue-filters__count { font-size: 11px; }
}

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

.home { padding: 0; }

/* Homepage main doesn't want the container padding from generic pages.
   Hero is the first element and starts at y=0 — the site header floats
   over it transparently (see .t-App\\PageType\\HomePage .site-header
   overrides further down). */
.t-HomePage main,
.t-App\\PageType\\HomePage main {
    padding: 0;
    max-width: none;
}

/* 60s cycle = 5 slides × 12s slot. The 7%/27% keyframes are timed so
   each slide is fully opaque from 7% to 27% — but the next slide's
   fade-in (its 0%→7%) starts at this slide's 20% mark. That 7% overlap
   = ~4s of true crossfade where the incoming slide rises from 0→1 over
   the outgoing slide held at 1, sitting on top in DOM order so it
   gradually replaces it. After 27% the outgoing slide fades out behind
   the incoming one, invisibly. A subtle Ken-Burns scale 1.02 → 1.07
   across the visible window adds gentle motion. */
@keyframes homeHeroCycle {
    0%   { opacity: 0; transform: scale(1.02); }
    7%   { opacity: 1; }
    27%  { opacity: 1; }
    34%  { opacity: 0; transform: scale(1.07); }
    100% { opacity: 0; transform: scale(1.02); }
}

/* ElementHero — reusable hero block. Three layouts:
   - .element-hero--fullwidth → full-bleed image with overlay scrim + text
   - .element-hero--boxed     → image fits within site container with overlay text
   - .element-hero--split     → text col + media col, 50/50 above 820px
   Fullwidth and boxed share the same internal structure (stage + plate);
   only the outer container constraint differs.
   Slide cycling uses elementHeroCycle10 (70s = 10 slides × 7s each).
   Distinct from homeHeroCycle (60s/5 slides) used by .home-hero and
   .page-slides — keeps each system independent so changes here don't
   ripple through the other two. */
.element-hero__stage,
.element-hero__media {
    position: relative;
    overflow: hidden;
    /* Dark espresso fallback (matches --accent-deep / hero plate) so
       any moment a frame is mid-fade or an image hasn't loaded yet,
       the gap reads as part of the hero rather than a flash of
       white. Per-image element overrides on top still work. */
    background: var(--accent-deep);
}
.element-hero__frame {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    animation: elementHeroCycle10 20s infinite;
    animation-fill-mode: both;
}
.element-hero__frame:nth-child(1)  { animation-delay:  0s; }
.element-hero__frame:nth-child(2)  { animation-delay:  2s; }
.element-hero__frame:nth-child(3)  { animation-delay:  4s; }
.element-hero__frame:nth-child(4)  { animation-delay:  6s; }
.element-hero__frame:nth-child(5)  { animation-delay:  8s; }
.element-hero__frame:nth-child(6)  { animation-delay: 10s; }
.element-hero__frame:nth-child(7)  { animation-delay: 12s; }
.element-hero__frame:nth-child(8)  { animation-delay: 14s; }
.element-hero__frame:nth-child(9)  { animation-delay: 16s; }
.element-hero__frame:nth-child(10) { animation-delay: 18s; }

/* 20s cycle = 10 slides × 2s each. Fade in over 1% (~0.2s), hold through
   9% (~1.6s), fade out over 1% (~0.2s), stay hidden until next cycle. */
@keyframes elementHeroCycle10 {
    0%   { opacity: 0; }
    1%   { opacity: 1; }
    9%   { opacity: 1; }
    10%  { opacity: 0; }
    100% { opacity: 0; }
}
.element-hero__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* Single-slide special case — no animation, frame stays visible. */
.element-hero__stage[data-slides="1"] .element-hero__frame,
.element-hero__media[data-slides="1"] .element-hero__frame {
    animation: none;
    opacity: 1;
}

/* Fullwidth — port of legacy .home-hero--image */
.element-hero--fullwidth,
.element-hero--boxed {
    position: relative;
    background: transparent;
}
/* Boxed = same structure as fullwidth, just constrained to site container. */
.element-hero--boxed {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.element-hero--fullwidth .element-hero__stage,
.element-hero--boxed .element-hero__stage {
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: 82vh;
}
.element-hero--boxed .element-hero__stage {
    border-radius: var(--r-md);
}
/* Plate is in the normal flow (not absolute) and is pulled up 100px so it
   overlaps the bottom of the stage. The block's content-driven height
   then naturally hangs below the image — magazine-cover caption that
   straddles the photo edge. The next section starts right after the
   plate's true bottom so there's no overlap with the following block. */
.element-hero--fullwidth .element-hero__plate,
.element-hero--boxed .element-hero__plate {
    /* Plate sits INSIDE the hero, anchored to the bottom-left of the
       stage. Image stays full size; block overlays the lower-left
       corner without overhanging the image edge. */
    position: absolute;
    inset: auto 0 var(--s-7) 0;
    z-index: 2;
    padding: 0 var(--gutter);
    background: transparent;
    color: #fff;
}
.element-hero--boxed .element-hero__plate {
    padding: 0 var(--gutter);
}
.element-hero--fullwidth .element-hero__inner,
.element-hero--boxed .element-hero__inner {
    display: inline-block;
    max-width: min(100%, 64rem);
    padding: var(--s-6) var(--s-7);
    background: var(--accent-deep);
    color: #fff;
    border-radius: 0;
}
.element-hero--fullwidth .element-hero__eyebrow,
.element-hero--fullwidth .element-hero__title,
.element-hero--fullwidth .element-hero__subtitle,
.element-hero--boxed .element-hero__eyebrow,
.element-hero--boxed .element-hero__title,
.element-hero--boxed .element-hero__subtitle {
    color: #fff;
}
.element-hero__subtitle {
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(1.2rem, 1.9vw, 1.35rem);
}
.element-hero--fullwidth .element-hero__title,
.element-hero--boxed .element-hero__title {
    max-width: 22ch;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
/* The subtitle had no measure of its own and ran the full plate width:
   64rem inner minus 2×48px padding is a 928px line box, ~85 characters at
   this size — unreadable in 300 weight, and visually a much wider block
   than the 22ch title stacked above it. Capping it restores the stepped
   silhouette the plate is built around (short headline, slightly narrower
   lead). A ch cap is a deliberate exception to the container-bound body
   text rule: this is hero furniture sitting next to an existing ch cap,
   not prose in a content column. Below 720px the viewport is narrower
   than the cap anyway, so mobile is untouched. */
.element-hero--fullwidth .element-hero__subtitle,
.element-hero--boxed .element-hero__subtitle {
    max-width: 52ch;
    /* Regular, not Light, once the line sits on a photograph. 300 at 21px
       white-on-image has almost no stem left to carry contrast — on a bright
       frame (sunlit water, pale ground) the subtitle read as a watermark on
       every photo hero. The split hero keeps 300: its text sits on a solid
       panel, where Light is doing the job it was chosen for. */
    font-weight: 400;
}
/* Was 0.85. The eyebrow is 11px small-caps on a photograph — dimming it was
   the one thing it could not afford. */
.element-hero--fullwidth .element-hero__eyebrow,
.element-hero--boxed .element-hero__eyebrow { opacity: 1; }

/* Mobile-only in-hero CTA. The header "Request a proposal" button is
   hidden below 720px (it moves into the drawer), leaving the mobile hero
   fold with no visible action. A single white underlined text-link
   restores one clear next step without putting a coloured button on the
   editorial plate. Desktop keeps the header CTA, so this is hidden ≥720px. */
.element-hero__cta { display: none; }
@media (max-width: 720px) {
    .element-hero__cta {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        margin-top: var(--s-4);
        color: #fff;
        font-family: var(--sans);
        font-weight: 500;
        font-size: 15px;
        text-decoration: none;
        border-bottom: 1px solid currentColor;
        padding-bottom: 2px;
    }
    .element-hero__cta .arrow { transition: transform 220ms var(--ease); }
    .element-hero__cta:hover .arrow,
    .element-hero__cta:focus-visible .arrow { transform: translateX(4px); }
}

/* Plate variant — gradient scrim. Drops the solid block; the plate
   becomes a full-width container at the bottom of the hero, and a
   bounded ::before paints a soft dark-to-transparent scrim that's
   roughly the height of the headline (clamped responsive band).
   Text sits above the scrim; eyebrow and the upper part of the
   title may extend above the gradient — text-shadow carries
   readability where the scrim doesn't reach. */
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__plate,
.element-hero--plate-gradient.element-hero--boxed .element-hero__plate {
    inset: auto 0 0 0;
    /* Bottom padding lifts the headline ~60px off the hero edge so
       it doesn't hug the bottom; gradient stays anchored to the
       hero bottom regardless of where the text sits. */
    padding: var(--s-7) 0 var(--s-10);
    background: transparent;
}
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__plate::before,
.element-hero--plate-gradient.element-hero--boxed .element-hero__plate::before {
    content: "";
    position: absolute;
    /* Scrim covers the plate and fades out over one --s-10 above it, so it
       tracks the text block instead of guessing at a height. The plate is the
       containing block here (inset: auto 0 0 0 above), so stretching to its
       top edge and reaching --s-10 further up sizes the band from the copy:
       a two-line desktop subtitle gets a shallow band, a three-line mobile
       subtitle plus the mobile CTA gets a proportionally deeper one.

       Rewritten 2026-08-05, replacing `height: clamp(9rem, 22vh, 18rem)` and
       a 0.65 → 0.30 → 0 ramp. That band was measured from the hero's bottom
       edge while the text sits 96px (--s-10) above it, which landed the
       subtitle around the 0.30 stop — under 3:1 against a bright frame (the
       sunlit water on /unsere-welt, the pale ground on the DMC heroes), so
       the subtitle read as a watermark while the h1 survived on size and
       weight alone. On mobile the taller text block pushed the first subtitle
       line clear out of the band altogether.

       Density is up as well as self-sizing, but the ramp still has four stops
       over the full band so it reads as light falling off toward the bottom
       of the frame, not as a panel laid over the photograph. */
    inset: calc(-1 * var(--s-10)) 0 0 0;
    background: linear-gradient(to top,
        rgba(15, 14, 10, 0.78) 0%,
        rgba(15, 14, 10, 0.58) 30%,
        rgba(15, 14, 10, 0.30) 65%,
        rgba(15, 14, 10, 0)    100%);
    pointer-events: none;
    z-index: 0;
}
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__inner,
.element-hero--plate-gradient.element-hero--boxed .element-hero__inner {
    position: relative;
    z-index: 1;
    display: block;
    background: transparent;
    padding: 0 var(--gutter);
    max-width: var(--maxw);
    margin: 0 auto;
}
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__eyebrow,
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__title,
.element-hero--plate-gradient.element-hero--fullwidth .element-hero__subtitle,
.element-hero--plate-gradient.element-hero--boxed .element-hero__eyebrow,
.element-hero--plate-gradient.element-hero--boxed .element-hero__title,
.element-hero--plate-gradient.element-hero--boxed .element-hero__subtitle {
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}

/* Split — text left, media right; padding only when bg colour is set */
.element-hero--split .element-hero__cols {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
    align-items: stretch;
}
@media (min-width: 820px) {
    .element-hero--split .element-hero__cols {
        grid-template-columns: 1fr 1fr;
    }
}
.element-hero--split .element-hero__text {
    padding: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.element-hero--split .element-hero__text--padded {
    padding: var(--s-7);
    border-radius: var(--radius-m, 4px);
}
@media (min-width: 820px) {
    .element-hero--split .element-hero__text--padded {
        padding: var(--s-8);
    }
}
/* Flip ink when a dark bg token is picked (espresso / Accent) so the
   eyebrow, headline and subtitle stay readable. Mirrors
   .element-textext__left--inverse / .section--deep. */
.element-hero--split .element-hero__text--inverse {
    --ink:           #f4f1ea;
    --ink-soft:      rgba(244, 241, 234, 0.72);
    --ink-muted:     rgba(244, 241, 234, 0.55);
    --hairline:      rgba(244, 241, 234, 0.18);
    --hairline-soft: rgba(244, 241, 234, 0.08);
    color:           var(--ink);
    font-weight:     400;   /* light-on-dark: stay regular (base sans is 300) */
}
.element-hero--split .element-hero__media {
    /* No aspect-ratio on phones. The media's frame is absolutely positioned
       (contributes no height), so a 4/3 ratio plus the 320px min-height
       transferred a 427px minimum *width* onto this grid cell — wider than
       the 335px column, a ~72px horizontal scroll that min-width:0 can't
       undo (the minimum comes from the ratio, not auto). Let min-height
       define the box and the width fill the column. The >=820px rule below
       restores a fluid full-height media in the 2-col layout. */
    min-height: 320px;
}
@media (min-width: 820px) {
    .element-hero--split .element-hero__media {
        aspect-ratio: auto;
        height: 100%;
        min-height: 420px;
    }
}

/* Shared text-plate typography (used by both layouts) */
.element-hero__eyebrow {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin: 0;
}
.element-hero__title {
    font-size: var(--t-hero);
    line-height: 1.1;
    letter-spacing: -0.018em;
    margin: var(--s-3) 0 0;
}
/* ---------- Fullscreen hero + transparent header overlay ----------
   When a page leads with a full-width hero, the hero fills the
   viewport and the masthead floats over it transparently with white
   text. As soon as the visitor scrolls past the masthead, the
   header restores to its solid background + dark ink state. Driven
   by body.is-scrolled (set by js/header-scroll.js at scrollY > 24)
   and CSS :has() so no PHP/template changes are needed.
   ------------------------------------------------------------------ */

/* Hero stage fills the viewport. Use svh (small viewport height), NOT dvh.
   dvh tracks iOS Safari's dynamic bottom toolbar, so a full-height hero at the
   TOP of the page grows/shrinks by ~70px every time the toolbar shows/hides.
   Because the hero drives layout, that reflows the WHOLE document by ~70px —
   and at the bottom of a long page it leaves a ~70px strip of the page ground
   (bone) below the footer: the iOS-only "content doesn't reach the bottom" bug.
   svh is a STATIC value (the toolbar-expanded height): the hero never tracks the
   toolbar, the document height never changes, so there is no bottom gap.
   Trade-off: when the toolbar is retracted, ~70px of the next section peeks
   below the hero — harmless. 100vh is the pre-svh fallback. */
.element-hero--fullwidth .element-hero__stage {
    aspect-ratio: auto;
    height: 100vh;
    height: 100svh;
    max-height: none;
}
/* Pull the hero up under the sticky chrome (header + optional
   page-subnav) so the image starts at the top edge of the viewport.
   Three selectors cover the layouts that route through here:
     1. Elemental-wrapped block (HomePage, generic Page) — hero is
        nested in .page__elements > .element
     2. DMCPage — hero is rendered directly inside <article class="dmc">
        via $forTemplate, no .element wrapper
     3. Generic fallback — any first-child .element-hero--fullwidth
        directly under an article in main
   --site-header-h and --page-subnav-h are published live by
   js/header-scroll.js (subnav var falls back to 0 when absent). */
.page__elements > .element:first-child:has(> .element-hero--fullwidth),
main > article > .element-hero--fullwidth:first-child {
    margin-top: calc(-1 * (var(--site-header-h, 73px) + var(--page-subnav-h, 0px)));
    /* Escape main's max-width + horizontal padding so the hero spans
       the full viewport even on page types where main is constrained
       (HomePage + DMCPage already drop the constraint themselves). */
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
}
/* Drop main's padding-top on pages with a fullwidth hero so the
   negative margin above can pull the hero cleanly to viewport top.
   Horizontal padding stays so the rest of the page keeps its gutter. */
body:has(.element-hero--fullwidth) main {
    padding-top: 0;
}
/* Subtle top scrim on hoisted heroes so the white nav text stays
   readable on bright photos (sky, sand) without darkening the whole
   image. Sits above the photo, below the .element-hero__plate
   (which is z-index: 2). Height covers chrome + ~100px fade tail. */
.page__elements > .element:first-child:has(> .element-hero--fullwidth) .element-hero__stage::before,
main > article > .element-hero--fullwidth:first-child .element-hero__stage::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: calc(var(--site-header-h, 73px) + var(--page-subnav-h, 0px) + 100px);
    z-index: 1;
    background: linear-gradient(to bottom,
        rgba(0, 0, 0, 0.28) 0%,
        rgba(0, 0, 0, 0.14) 55%,
        rgba(0, 0, 0, 0)    100%);
    pointer-events: none;
}
/* Hide the breadcrumb above a fullwidth hero — the masthead already
   floats over the image and a wayfinding strip would clutter the
   top of the frame. (Same pattern as Home / DMC landings.) */
body:has(.element-hero--fullwidth) .breadcrumb { display: none; }

/* Smooth handoff between transparent and solid header states. */
.site-header,
.site-header .site-subnav__links--global a,
.site-header .site-locale__current,
.site-header .site-search-trigger,
.site-header .site-contact-trigger,
.site-header .site-menu-trigger {
    transition: background 220ms var(--ease), color 220ms var(--ease), border-color 220ms var(--ease);
}

/* Transparent header while body has fullwidth hero AND visitor is at
   the top of the page. The :not(.is-scrolled) flips off as soon as
   header-scroll.js detects scroll past 24px, restoring the default
   header skin. */
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header {
    background: transparent;
    border-bottom-color: transparent;
}
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header .site-subnav__links--global a,
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header .site-locale__current,
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header .site-search-trigger,
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header .site-contact-trigger,
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header .site-menu-trigger {
    color: #fff;
}
/* Over the hero (top of a fullwidth-hero page) the controls keep the dark
   frosted glass — it reads on the photo. Once scrolled onto content the
   default white pill takes over (the chrome adapts to its backdrop).
   Desktop only: on mobile the pill is stripped entirely (≤720px block above),
   and this override out-specifies that strip, so it must not reach mobile. */
@media (min-width: 721px) {
    body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header__controls {
        background: rgba(33, 28, 25, 0.7);
        backdrop-filter: blur(24px) saturate(1.4);
        -webkit-backdrop-filter: blur(24px) saturate(1.4);
        border-color: transparent;
        box-shadow: none;
        color: #fff;
    }
}
/* Soft shadow under the white nav text so it stays readable on light
   areas of the hero photo (sky, sand) without needing a scrim. */
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-header__inner {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}

/* Sand skin is reserved for the moment a sticky sub-nav DOCKS beneath the
   header (see the is-subnav-docked rule below) — that's the only time the
   band earns its keep: header + sub-nav merge into one continuous sand band
   with no gap showing through. On plain scroll, and on every page without a
   sub-nav, the header stays transparent the whole way down, letting the
   floating brand plate + chrome carry it. (Previously body.is-scrolled
   turned the header sand on every page once you scrolled past the masthead;
   removed so the sand is tied strictly to docking.) */

/* Pages with an inline sub-nav (bar sits below the hero) solidify the
   header in lockstep with the DOCKING bar, not merely on scroll: the
   header stays ghosted over the hero — transparent + white chrome — no
   matter how far you scroll, until the bar reaches the header (body gets
   .is-subnav-docked from header-scroll.js); then both take sand together.
   These win over the is-scrolled rules above on specificity, so leaving
   the masthead alone no longer flips the header early. The white/over-hero
   treatment is gated on a fullwidth hero so a no-hero inline page (rare —
   base Page without a hero) keeps its normal dark chrome. */
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header {
    background: transparent;
    border-bottom-color: transparent;
}
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header .site-subnav__links--global a,
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header .site-locale__current,
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header .site-search-trigger,
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header .site-contact-trigger,
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header .site-menu-trigger {
    color: #fff;
}
@media (min-width: 721px) {
    body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header__controls {
        background: rgba(33, 28, 25, 0.7);
        backdrop-filter: blur(24px) saturate(1.4);
        -webkit-backdrop-filter: blur(24px) saturate(1.4);
        border-color: transparent;
        box-shadow: none;
        color: #fff;
    }
}
body:has(.element-hero--fullwidth):has(.page-subnav--inline):not(.is-subnav-docked) .site-header__inner {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}
body:has(.page-subnav--inline).is-subnav-docked .site-header {
    background: var(--bg);
}
/* Mobile: the header NEVER takes the sand skin. The floating espresso brand
   plate + frosted chrome pill carry the weight on their own, and the bar
   auto-hides on scroll anyway, so a solid sand band would only add noise.
   Keep it transparent in every scroll/dock state. Placed after the
   is-scrolled / is-subnav-docked sand rules above so it wins the
   same-specificity tie on source order; scoped to ≤720px so desktop keeps
   its solid scrolled band. */
@media (max-width: 720px) {
    .site-header,
    body.is-scrolled .site-header,
    body:has(.page-subnav--inline).is-subnav-docked .site-header {
        background: transparent;
        border-bottom-color: transparent;
    }
}
/* The locale-switcher panel itself stays its normal white card — it
   only opens on hover/focus and shouldn't inherit the white ink. */
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-locale__panel {
    text-shadow: none;
}

/* PageSubNav gets the same transparent-over-hero treatment as the
   header — both pieces of chrome float together over the hero, then
   restore in lockstep when the visitor scrolls. The current-link
   underline switches to white so the active state stays visible. */
.page-subnav,
.page-subnav__label,
.page-subnav__links a {
    transition: background 220ms var(--ease), color 220ms var(--ease), border-color 220ms var(--ease);
}
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav {
    background: transparent;
    border-bottom-color: transparent;
}
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav .page-subnav__label,
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav .page-subnav__label a,
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav .page-subnav__links a {
    color: #fff;
}
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav .page-subnav__links a.is-current {
    border-bottom-color: #fff;
}
body:has(.element-hero--fullwidth):not(.is-scrolled) > .page-subnav .page-subnav__inner {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}

/* Mega-menu dropdown over a fullwidth hero — frosted-glass panel.
   Translucent dark scrim (0.32 alpha) plus a strong backdrop-blur
   so the hero shows through softly while the labels stay legible.
   White link text, muted-white eyebrow, no drop shadow. */
.site-subnav__dropdown,
.site-subnav__dropdown a,
.site-subnav__dropdown-eyebrow,
.site-subnav__dropdown-thumb {
    transition: background 220ms var(--ease), color 220ms var(--ease), border-color 220ms var(--ease), box-shadow 220ms var(--ease), backdrop-filter 220ms var(--ease);
}
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-subnav__dropdown {
    background: rgba(15, 14, 10, 0.32);
    backdrop-filter: blur(24px) saturate(1.2);
    -webkit-backdrop-filter: blur(24px) saturate(1.2);
    border-top-color: rgba(255, 255, 255, 0.12);
    border-bottom-color: rgba(255, 255, 255, 0.12);
    box-shadow: none;
}
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-subnav__dropdown a { color: #fff; }
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-subnav__dropdown-eyebrow {
    color: rgba(255, 255, 255, 0.65);
}
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-subnav__dropdown-thumb {
    background: rgba(255, 255, 255, 0.06);
}
body:has(.element-hero--fullwidth):not(.is-scrolled) .site-subnav__dropdown a:hover {
    color: var(--accent-soft);
}

/* Key figures — own row, full-width band on --bg-elev, hairlines top+bottom.
   The numbers are the "wow" content; mixing them with memberships diluted
   them. Now they get their own breathing room. */
.key-figures {
    background: transparent;
    padding: var(--s-11) 0;
}
.key-figures__head {
    max-width: var(--maxw);
    margin: 0 auto var(--s-7);
    padding: 0 var(--gutter);
}
.key-figures__row {
    list-style: none;
    padding: 0 var(--gutter);
    max-width: var(--maxw);
    margin: 0 auto;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-8) var(--s-6);
}
.key-figures .stat {
    gap: var(--s-3);
    align-items: center;
    text-align: center;
}
.key-figures .t-micro { font-size: 13px; letter-spacing: 0.14em; }
@media (max-width: 720px) {
    .key-figures__row { grid-template-columns: repeat(2, 1fr); }
    .key-figures { padding: var(--s-8) 0; }
}

/* Trusted-by row — own band, sits below memberships with internal hairline. */
.trusted-by-row {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-7) var(--gutter) var(--s-9);
}
.stat {
    display: flex;
    flex-direction: column;
    align-items: baseline;
    gap: 6px;
}
.stat-num {
    font-family: var(--sans);
    font-size: clamp(1.875rem, 4.5vw, 4rem);
    font-weight: 400;
    line-height: 0.95;
    letter-spacing: -0.025em;
    color: var(--feature);
}

.cert-row {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-5) var(--s-7);
    align-items: center;
}

/* Cert chip — two variants:
   - default (logo): bare, no chrome, logo gets room to breathe
   - .cert-chip--text: small pill for memberships without a logo */
.cert-chip {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}
.cert-chip img {
    height: 64px;
    width: auto;
    max-width: 180px;
    object-fit: contain;
    display: block;
}
.cert-chip--text {
    height: 36px;
    padding: 0 14px;
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
    background: var(--surface);
    gap: 8px;
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink);
    letter-spacing: 0.02em;
    white-space: nowrap;
}
.cert-chip--text .badge-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    flex: 0 0 auto;
}

/* Logo strip — endless marquee. Two identical tracks sit side-by-side and
   translate -50% in a loop, so the seam between them is invisible. Edges
   fade out via mask. Pauses on hover. */
.muted { color: var(--ink-muted); }
.logo-strip {
    overflow: hidden;
    display: flex;
    width: 100%;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.logo-strip__track {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex: 0 0 auto;
    animation: logo-strip-scroll 60s linear infinite;
    will-change: transform;
}
.logo-strip:hover .logo-strip__track { animation-play-state: paused; }
@keyframes logo-strip-scroll {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(-100%, 0, 0); }
}
.logo-tile {
    flex: 0 0 auto;
    width: clamp(150px, 18vw, 200px);
    aspect-ratio: 5 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--s-3);
}
.logo-tile img {
    height: clamp(36px, 4.2vw, 52px);
    width: auto;
    max-width: 85%;
    object-fit: contain;
}

/* Destination tiles — photographic squares, typography below the image.
   No overlay text, no hover darken. Minimal Bauhaus treatment: photo as
   photo, label as label. */
.home-destinations {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-11) var(--gutter);
}
.home-destinations__head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-3);
}
.home-destinations__title {
    font-family: var(--sans);
    font-weight: 700;
    /* size owned by .h--display (--t-section); don't set font-size here */
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.destination-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-auto-rows: minmax(0, auto);
    gap: var(--s-5);
}
/* Mallorca anchors the grid at ~2× size — reflects operational reality
   (HQ, longest tenure, most venues). Spans cols 1-2 of the 4-col grid
   so the right two columns share their track positions with the case
   study rail below. */
.destination--anchor {
    grid-row: 1 / span 2;
    grid-column: 1 / span 2;
}
@media (max-width: 820px) {
    .destination-grid { grid-template-columns: 1fr 1fr; }
    .destination--anchor { grid-column: 1 / -1; grid-row: auto; }
}
@media (max-width: 540px) {
    .destination-grid { grid-template-columns: 1fr; }
}
.destination__link {
    display: block;
    text-decoration: none;
    color: inherit;
}
.destination__figure {
    position: relative;
    margin: 0;
    overflow: hidden;
    background: var(--surface);
    aspect-ratio: 8 / 5;
}
.destination__figure img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.destination__figure--empty {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--hairline-soft);
}
/* Gradient mask sits behind the caption to keep the title legible against
   any photo. Bottom 55% of the figure; transparent at top, ink at base. */
.destination__figure::after {
    content: "";
    position: absolute;
    inset: 45% 0 0 0;
    background: linear-gradient(to bottom, rgba(33, 28, 25, 0) 0%, rgba(33, 28, 25, 0.55) 100%);
    pointer-events: none;
}
.destination__title {
    font-family: var(--sans);
    font-weight: 400;
    font-size: var(--t-h2);
    line-height: 1.05;
    letter-spacing: -0.01em;
    color: #fff;
    margin: 0;
}
.destination__body { padding: var(--s-4); }
.destination__pitch {
    color: var(--ink-soft);
    margin: 0;
    max-width: 32em;
}

/* Homepage Destinations strip: 4×2 grid with a 2×2 anchor.
   Layout:
       Mallorca  Mallorca  Ibiza      Formentera
       Mallorca  Mallorca  Menorca    Malta
   Image edges align across the strip: row-1 image-tops at y0,
   row-1 image-bottoms at y(HBild), row-2 image-tops at y(row-1 +
   gap), row-2 image-bottoms at y(2·row + gap). The anchor's
   image stretches from top to row-2 image-bottom by absorbing
   the body-height of row 1 + the inter-row gap via flex-grow on
   the figure. Bodies have fixed height so row alignment can't
   drift with copy length.
   Scoped under .home-destinations so the DestinationsPage index
   (which uses its own .destination-wall overlay layout) stays
   untouched. */
.home-destinations .destination-grid {
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: 1fr 1fr;
}
.home-destinations .destination--anchor {
    grid-column: 1 / span 2;
    grid-row: 1 / span 2;
}
.home-destinations .destination__link {
    display: flex;
    flex-direction: column;
    height: 100%;
}
.home-destinations .destination__figure {
    flex: 1 1 auto;
    min-height: 0;
}
.home-destinations .destination__figure img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.home-destinations .destination__figure::after { display: none; }
.home-destinations .destination__body {
    padding: var(--s-4) 0 0;
    flex: 0 0 auto;
    height: 5.5rem;
    overflow: hidden;
}
.home-destinations .destination__region {
    font-family: var(--sans);
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin: 0 0 var(--s-2);
}
.home-destinations .destination__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(1.2rem, 1.5vw, 1.5rem);
    line-height: 1.15;
    letter-spacing: -0.015em;
    color: var(--ink);
    margin: 0;
    text-wrap: balance;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.home-destinations .destination--anchor .destination__title {
    font-size: clamp(1.6rem, 2.2vw, 2.2rem);
}
.home-destinations .destination__pitch { display: none; }
@media (max-width: 1024px) {
    /* Phones & narrow tablets: Mallorca anchors full-width on top, the
       remaining destinations flow into a 2-up grid below. Stops the strip
       from becoming a long vertical scroll on phones (was a single-column
       stack pre-2026-06-05). The anchor is the first child and spans both
       columns, so it stays first and full-width without markup changes.
       Figures regain a fixed 8:5 aspect since flex-grow no longer has a
       fixed-height row to absorb extra space into. */
    .home-destinations .destination-grid {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto;
        gap: var(--s-5);
    }
    .home-destinations .destination--anchor {
        grid-column: 1 / -1;
        grid-row: auto;
    }
    /* Overflow guard: CSS grid items (and flex children) default to
       min-width:auto, so a long/unbroken title or an intrinsically wide
       figure can blow a 1fr track past the content rail and push the whole
       page wider than the viewport (horizontal scroll on phones). min-width:0
       lets every card — including the 1/-1 anchor — shrink to its track, and
       overflow-wrap breaks any long word instead of forcing extra width. */
    .home-destinations .destination {
        min-width: 0;
    }
    .home-destinations .destination__figure {
        flex: 0 0 auto;
        aspect-ratio: 8 / 5;
        min-width: 0;
    }
    .home-destinations .destination__title {
        overflow-wrap: break-word;
    }
    /* Narrower 2-up tiles need a touch more room for the (now wrapping)
       title; the fixed body height keeps the two columns bottom-aligned. */
    .home-destinations .destination__body {
        height: 4.5rem;
    }
    .home-destinations .destination--anchor .destination__body {
        height: 5.5rem;
    }
    .home-destinations .destination--anchor .destination__title {
        font-size: clamp(1.4rem, 4vw, 1.8rem);
    }
}
/* Very narrow phones (~360px): the 2-up tiles get cramped; let the
   non-anchor destinations breathe with a tighter gap but keep 2 columns
   so the section stays compact rather than reverting to a long stack. */
@media (max-width: 400px) {
    .home-destinations .destination-grid { gap: var(--s-4); }
    .home-destinations .destination__title {
        font-size: clamp(1rem, 4.5vw, 1.2rem);
    }
}

/* ============================================================
   Destinations slideshow — swappable alternative to the 4×2 grid
   above (Includes/HomeDestinationsSlideshow.ss vs
   HomeDestinationsGrid.ss; switch in ElementDestinationStrip.ss).
   Modelled on the aixlesbains-rivieradesalpes.com blog slider:
   full-bleed centered stage, active slide large in the middle
   inside a white passepartout frame, neighbours peeking at both
   edges, poster type on a flat espresso scrim, arrow pair
   below. Driven by js/destination-slideshow.js (vanilla, no
   Swiper): translateX track + one edge clone per side.
   ============================================================ */
.dest-show {
    padding: var(--s-11) 0;
}
.dest-show__head {
    max-width: var(--maxw);
    margin: 0 auto var(--s-8);
    padding: 0 var(--gutter);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-3);
}
.dest-show__kicker { margin: 0; }
.dest-show__title {
    font-family: var(--sans);
    font-weight: 700;
    /* size owned by .h--display (--t-section) */
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.dest-show__stage {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: clamp(520px, 74vh, 800px);
    cursor: grab;
    touch-action: pan-y;
}
.dest-show__stage.is-dragging { cursor: grabbing; }
.dest-show__stage.is-dragging,
.dest-show__stage.is-dragging * { user-select: none; }
.dest-show__track {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    height: 100%;
    transition: transform 600ms var(--ease);
    will-change: transform;
}
/* Overlap layering, straight from the reference: the ACTIVE slide sits
   BELOW its neighbours (z 1 vs 2), and its photo expands beyond the
   slide box to the full viewport width — so the peeking neighbours'
   white frames float ON TOP of the big image. The z-index swap is
   delayed 300ms into the travel (0s transition, 300ms delay) so the
   outgoing and incoming photos don't flicker-fight mid-flight.
   Slide width is a pure viewport ratio (1100/1600 like the reference).
   The active frame expands to 125% (~86vw) — deliberately short of the
   full viewport width, so the print keeps breathing room to the edges
   and its white matte stays visible all around; the neighbours still
   overlap its side edges by ~8.6vw. */
.dest-show__slide {
    flex: 0 0 auto;
    width: 68.75vw;
    height: 100%;
    position: relative;
    z-index: 2;
    transition: z-index 0s linear 300ms;
}
.dest-show__slide.is-active {
    z-index: 1;
    transition: z-index 0s linear 0s;
}
.dest-show__link {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
    text-decoration: none;
    color: inherit;
}
/* White passepartout matte around the photo — a mounted gallery print.
   Absolutely positioned and centered, so the active expansion (width/
   height/padding animate) never reflows anything around it: zero layout
   shift, the photo just grows under the neighbours. Inactive cards are
   smaller (70% height), matching the reference's card-vs-stage rhythm. */
.dest-show__frame {
    margin: 0;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 70%;
    background: #fff;
    padding: clamp(8px, 1.2vw, 20px);
    box-shadow: var(--shadow-3);
    transition: width 600ms var(--ease), height 600ms var(--ease), padding 600ms var(--ease);
}
.dest-show__slide.is-active .dest-show__frame {
    width: 125%;
    height: 100%;
    padding: clamp(12px, 1.8vw, 30px);
}
.dest-show__media {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: var(--stone-200);
}
.dest-show__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* Legibility scrim — center-weighted so the darkness concentrates where
   the copy sits: a flat 0.32 wash measured ~2:1 for the 12px kicker over
   bright sky/sea regions (WCAG floor is 4.5:1). Gradients don't
   interpolate, so the fade runs on opacity, not background. */
.dest-show__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 70% 60% at 50% 50%, rgba(33, 28, 25, 0.55), rgba(33, 28, 25, 0.22) 100%);
    opacity: 0;
    transition: opacity 600ms var(--ease) 120ms;
    pointer-events: none;
}
.dest-show__slide.is-active .dest-show__media::after {
    opacity: 1;
}
.dest-show__media--empty {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--hairline-soft);
}
.dest-show__copy {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--s-3);
    padding: clamp(32px, 6vw, 96px);
    pointer-events: none; /* drags + clicks land on the wrapping anchor */
}
.dest-show__region {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    font-weight: 500;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #fff;
    margin: 0;
}
/* Slide names sit on the section-title tier (--t-section, max ~42px) —
   the type-hierarchy invariant caps everything below the page hero
   (--t-hero, 50px), and hero scale is reserved for the page hero alone.
   background-image/padding-bottom cancel the global a :is(h1..h4)
   hover-underline treatment, which would paint a snapping white bar
   under the name (the copy layer is pointer-events:none, so the anchor
   hovers from everywhere on the slide). */
.dest-show__name {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-section);
    line-height: 1.02;
    letter-spacing: -0.02em;
    color: #fff;
    margin: 0;
    text-wrap: balance;
    background-image: none;
    padding-bottom: 0;
}
/* Garamond italic subline — the sanctioned editorial-accent use. */
.dest-show__pitch {
    font-family: var(--serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.25rem, 1.8vw, 1.65rem);
    line-height: 1.3;
    color: #f4f1ea;
    margin: 0;
    max-width: 34ch;
}
.dest-show__cta {
    margin-top: var(--s-4);
    font-family: var(--sans);
    font-size: var(--t-small);
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #fff;
    border-bottom: 1px solid rgba(255, 255, 255, 0.6);
    padding-bottom: 3px;
    transition: border-color 180ms var(--ease);
}
.dest-show__link:hover .dest-show__cta { border-color: #fff; }
/* Staggered copy entrance on activation — kicker, name, pitch, CTA rise in
   sequence. Gated on html.js: without JS every slide keeps its copy visible. */
html.js .dest-show__copy > * {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 420ms var(--ease), transform 420ms var(--ease);
}
html.js .dest-show__slide.is-active .dest-show__copy > * {
    opacity: 1;
    transform: none;
}
html.js .dest-show__slide.is-active .dest-show__copy > *:nth-child(1) { transition-delay: 240ms; }
html.js .dest-show__slide.is-active .dest-show__copy > *:nth-child(2) { transition-delay: 340ms; }
html.js .dest-show__slide.is-active .dest-show__copy > *:nth-child(3) { transition-delay: 440ms; }
html.js .dest-show__slide.is-active .dest-show__copy > *:nth-child(4) { transition-delay: 540ms; }
/* One-frame transition kill for the loop seam: when the JS swaps a clone
   for its real slide after a wrap, the real slide must snap straight to
   the finished active state (frame at 1, scrim on, copy in place) instead
   of re-running the scale-up and the copy stagger. The *::after leg
   covers the scrim. !important is the point — this must beat every
   transition in the block, including the html.js-gated copy rules. */
.dest-show__slide.is-snap,
.dest-show__slide.is-snap *,
.dest-show__slide.is-snap *::before,
.dest-show__slide.is-snap *::after {
    transition: none !important;
}
/* Single-tile deck: nothing to slide — center the lone slide (works with
   and without JS; the engine bails out below 2 slides) and drop the drag
   affordances. */
.dest-show__slide:only-child { margin: 0 auto; }
/* a lone slide has nothing to overlap — keep its frame inside the box
   (the .is-active leg outweighs the expansion rule's specificity) */
.dest-show__slide:only-child .dest-show__frame,
.dest-show__slide:only-child.is-active .dest-show__frame {
    width: 100%;
    height: 100%;
}
.dest-show__stage:has(.dest-show__slide:only-child) {
    cursor: default;
    touch-action: auto;
}
/* Arrows — the only chrome under the stage: two hairline discs on the sand
   ground, no counter, no dots. The stage edges already step (a peeking
   slide is clickable), so these are the deliberate, quiet duplicate for
   anyone who wants a button. */
.dest-show__nav {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--s-3);
    margin-top: var(--s-6);
    padding: 0 var(--gutter);
}
.dest-show__arrow {
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--hairline-strong);
    border-radius: 50%;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    transition: background-color 220ms var(--ease), border-color 220ms var(--ease), color 220ms var(--ease);
}
.dest-show__arrow svg { display: block; }
.dest-show__arrow:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--surface);
}
.dest-show__arrow:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}
/* No-JS fallback: the stage becomes a plain horizontal scroller — every
   frame full-size, every scrim on (copy is visible via the html.js gate
   above), arrows hidden (they can't navigate anything). */
html:not(.js) .dest-show__stage {
    overflow-x: auto;
    /* pan-y + grab serve the JS drag engine; a real scroller needs native
       horizontal panning and no drag affordance */
    touch-action: auto;
    cursor: default;
}
/* No-JS: a plain scroller has no active/peek layering — every frame fills
   its own slide box (beats the .is-active expansion on specificity). */
html:not(.js) .dest-show__slide .dest-show__frame {
    width: 100%;
    height: 100%;
    padding: clamp(8px, 1.2vw, 20px);
}
html:not(.js) .dest-show__media::after { opacity: 1; }
html:not(.js) .dest-show__nav { display: none; }
@media (max-width: 820px) {
    .dest-show__stage { height: clamp(420px, 62vh, 560px); }
    .dest-show__slide { width: 86vw; }
    /* active ~93vw of the 86vw slide — overlapped, but clear of the edges */
    .dest-show__frame { padding: 6px; height: 78%; }
    .dest-show__slide.is-active .dest-show__frame {
        width: 108%;
        height: 100%;
        padding: 8px;
    }
    .dest-show__copy { padding: 24px; gap: var(--s-2); }
    .dest-show__pitch { font-size: 1.1rem; }
    .dest-show__cta { margin-top: var(--s-3); }
    .dest-show__head { margin-bottom: var(--s-6); }
}
@media (max-width: 400px) {
    .dest-show__nav { gap: var(--s-2); }
}

/* Negative-space rhythm: sections sit on one ground (sand body) and
   are separated by generous vertical breathing room rather than bg
   alternation or hairlines. The space IS the section break. */
.home-section {
    padding: var(--s-11) var(--gutter);
    max-width: var(--maxw);
    margin: 0 auto;
}

/* Full-bleed panel modifier — sand band runs to the viewport edges, but
   the inner content (header, lists, cards) stays inside --maxw so it
   tracks the rest of the page's column. Top + bottom hairlines mark the
   panel's vertical extent. Used for blocks that benefit from a visual
   "section break" without boxing the content into a card (Google Reviews,
   Partner strip). */
/* Panel modifier kept for layout purposes (full-bleed instead of maxw)
   but bg matches the body — negative-space rhythm, no visual bands. */
.home-section--panel {
    background: transparent;
    max-width: none;
    padding: var(--s-11) var(--gutter);
}
.home-section--panel > * {
    /* Match the effective content width of non-panel sections, which sit
       inside .home-section's maxw box AND have gutter padding inside it
       (effective content = maxw − 2·gutter). Without subtracting the
       gutter the panel's children would be 2·gutter wider than the rest
       of the page, making destinations/cases/reviews stand out as wider. */
    max-width: calc(var(--maxw) - 2 * var(--gutter));
    margin-left: auto;
    margin-right: auto;
}

/* Container-contract correction (see the contract at ~1280). .home-section
   self-bounds — maxw + gutter — because every block that carries it was
   written for the three stripped-main page types. Drop one of those blocks
   on any OTHER page and <main> already owns the rail, so the block indents
   by a second gutter and sits ~48px right of its text siblings.

   Neutralise the block's own rail everywhere except the stripped-main pages.
   Only the horizontal box goes; the vertical rhythm (padding-block s-11) is
   untouched, and the ≤900px .service-tiles bleed still lines up because it
   is measured against whichever ancestor carries the gutter.

   First needed by the section directory on /unsere-welt (2026-08-05), where
   an ElementServiceStrip sits under three .element-textext blocks. */
body:not(.t-App\\PageType\\HomePage):not(.t-App\\PageType\\DMCPage):not(.t-App\\PageType\\ContactPage)
    .page__elements .home-section {
    max-width: none;
    margin-inline: 0;
    padding-inline: 0;
}

/* Section rule — thick horizontal anchor pinned to the top-left corner of
   the .element wrapper, which spans the full viewport width regardless of
   the inner section's max-width. That keeps the rule at the viewport's
   left edge for every section type (panel or maxw-constrained) without
   per-section CSS. Rendered from ElementHolder.ss when the editor toggles
   ShowSectionRule on a block. Animates in from the left when scrolled
   into view — driven by .is-in-view set by js/section-rule.js. */
.element { position: relative; }

.section-rule {
    position: absolute;
    top: 0;
    left: 0;
    width: clamp(160px, 28%, 320px);
    max-width: none;
    height: 4px;
    background: var(--accent-a-600);
    border: 0;
    margin: 0;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: transform;
}
.section-rule.is-in-view { transform: scaleX(1); }
.element.has-section-rule { padding-top: 0; }

/* ElementContent rendert ohne inneres <section>, also greift die globale
   .element > section { padding: var(--s-11) ... } Regel (siehe unten)
   nicht. Steht ein ElementContent als eigenständiger Beat zwischen
   anderen Sections (z.B. Homepage-Intro nach dem Hero), kollabiert er
   ohne eigenes Padding auf 0 und wird von den 128px-lauten Nachbarn
   plattgedrückt. 96px (--s-10) gibt ihm einen ruhigeren Beat als die
   Loud Sections — Text soll nicht so schwer wirken wie ein 4-Kachel-
   Grid. Greift nur als direktes Kind von .page__elements, nicht bei
   verschachtelten ElementContent-Blöcken innerhalb anderer Wrapper. */
.page__elements > .element.dnadesign__elemental__models__elementcontent {
    padding-top: var(--s-10);
    padding-bottom: var(--s-10);
    /* Wichtig: KEIN padding-Shorthand. Die is-partial-Regel (oben)
       setzt padding-left/right: var(--gutter) auf stripped-main Pages
       — ein Shorthand hier wischt das mit 0 weg und der Block driftet
       um einen Gutter nach links aus dem Grid. Siehe memory
       css_margin_shorthand_trap (gleicher Mechanismus, padding statt
       margin). */
}

/* Uniform generous top padding across every Elemental section.
   position:relative stays as the containing block for section-scoped
   absolutes (hairlines, decorations). Overrides per-section padding
   variations (s-9 on testimonial-wrap/affiliation/case-rail/
   home-rfp-cta/sister-brands, s-10 on why-us, s-7 on trusted-by-row)
   for one consistent rhythm. */
.element > section { position: relative; padding-top: var(--s-11); }
.element > section.element-hero { padding-top: 0; }

/* Eyebrow sits IN FLOW directly above the section headline — never
   absolutely positioned (the old top-anchored "editorial mark" left it
   ~100px away from its h2). Templates keep the eyebrow as the section's
   direct first child, immediately before the head wrapper.

   margin-block (not the margin shorthand) on purpose: it must not
   touch margin-inline, because `.home-section--panel > *` centers
   panel children via margin-left/right:auto and this higher-specificity
   rule would clobber that (see css_margin_shorthand_trap). */
section > .t-eyebrow {
    margin-block: 0 var(--s-4);
}

/* Full-bleed sections without the panel child-centering rule: mirror
   each section's own head/inner box (maxw, centered, gutter-padded)
   so the in-flow eyebrow's text lines up with the headline below it.
   .newsletter-block carries gutter padding on the section itself, so
   its eyebrow gets no extra padding — __inner has none either. */
.key-figures > .t-eyebrow,
.home-rfp-cta > .t-eyebrow {
    max-width: var(--maxw);
    margin-inline: auto;
    padding-inline: var(--gutter);
}
.newsletter-block > .t-eyebrow {
    max-width: var(--maxw);
    margin-inline: auto;
}

.home-section__head {
    margin-bottom: var(--s-8);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-5);
}
/* Real headline on the section tier — matches case-rail (--t-h1),
   home-services / sister-brands (.h--display) and reviews (--t-section).
   The old eyebrow-scale uppercase treatment predates the in-flow
   eyebrow: with the kicker now sitting directly above, two identical
   micro-lines would stack (eyebrow → eyebrow-styled h2). */
.home-section__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-section);
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.home-section__lead {
    font-family: var(--serif);
    font-size: 1.05rem;
    font-style: italic;
    color: var(--ink-soft);
    margin: 0;
}

/* ---------- Case study rail (homepage) -----------------------------
   Asymmetric two-column layout: title + lede + arrow controls on the
   left, horizontally-scrolling card rail on the right. The rail uses
   scroll-snap for snappy stops at each card. Arrows are wired up via
   js/case-rail.js (data-rail-prev / data-rail-next / data-rail-scroller). */
.case-rail-wrap {
    max-width: var(--maxw);
    margin: 0 auto;
    /* padding-top comes from the universal `.element > section` rule
       (var(--s-11)) for uniform section rhythm — do not set it here. */
    padding: 0 0 var(--s-10);
    /* Let the rail itself bleed past the right gutter into the viewport
       edge so cards visually continue off-screen — strong scroll affordance. */
    overflow: hidden;
}
/* When the case rail is rendered inside a full-bleed sand panel, the
   wrap's own maxw + side padding fight the panel — undo them so the
   panel handles framing and the rail bleeds inside the panel band. */
.case-rail-wrap.home-section--panel {
    max-width: none;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
    padding-bottom: var(--s-8);
}
/* Track layout mirrors .destination-grid (1fr 1fr 1fr 1fr, gap var(--s-5))
   so head sits in col 1 and the three visible cards land exactly on
   cols 2-4 of the destination grid above. */
.case-rail__layout {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    gap: var(--s-5);
    align-items: start;
}
.case-rail__head {
    grid-column: 1;
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
    align-self: start;
    padding-bottom: var(--s-4);
}
.case-rail__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-h1);
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--ink);
    margin: 0;
}
.case-rail__lead {
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink-soft);
    margin: 0;
}
.case-rail__controls {
    display: flex;
    gap: var(--s-2);
    margin-top: var(--s-3);
}
.case-rail__arrow {
    appearance: none;
    background: transparent;
    border: 1px solid var(--hairline);
    border-radius: 999px;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--ink);
    cursor: pointer;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease, transform 150ms ease;
}
.case-rail__arrow:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}
.case-rail__arrow:active { transform: scale(0.95); }
.case-rail__arrow[disabled] {
    opacity: 0.3;
    cursor: not-allowed;
    background: transparent;
    color: var(--ink);
    border-color: var(--hairline);
}

/* The scroller — overflow-x with scroll-snap. No visible scrollbar
   on macOS/iOS; on Windows we leave the native scrollbar. */
.case-rail__scroller {
    grid-column: 2 / -1;
    /* min-width:0 lets the scroller stay within its grid tracks instead
       of expanding to its (much wider) flex-content width. */
    min-width: 0;
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 0;
    -webkit-overflow-scrolling: touch;
    /* Hide scrollbar visually — keyboard / wheel still works */
    scrollbar-width: none;
}
.case-rail__scroller::-webkit-scrollbar { display: none; }

.case-rail {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    gap: var(--s-5);
}
/* Three cards per viewport, sized to one destination-grid 1fr track each
   so they line up with cols 2-4 of .destination-grid. */
.case-rail__item {
    flex: 0 0 calc((100% - 2 * var(--s-5)) / 3);
    scroll-snap-align: start;
}
.case-rail__card {
    display: flex;
    flex-direction: column;
    gap: 0;
    text-decoration: none;
    color: inherit;
    height: 100%;
}
.case-rail__photo {
    margin: 0;
    aspect-ratio: 8 / 5;
    overflow: hidden;
    background: var(--bg-soft);
}
.case-rail__photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.case-rail__body {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    /* Stretch to fill the rest of the card so all cards reach the same
       height (specs sit at the bottom via margin-top: auto below). */
    flex: 1 1 auto;
    /* Top-only: the text block starts flush with the photo's left edge —
       same rhythm as .service-tile__body / .team-card__body. */
    padding: var(--s-4) 0 0;
}
.case-rail__type {
    font-family: var(--sans);
    font-size: 0.95rem;
    line-height: 1.35;
    color: var(--ink-soft);
    margin: 0;
}
.case-rail__specs {
    list-style: none;
    padding: 0;
    /* margin-top: auto keeps cards bottom-aligned across the rail
       even though shorter titles leave more whitespace above. */
    margin: auto 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px var(--s-2);
    font-family: var(--sans);
    font-size: 13px;
    font-style: normal;
    color: var(--ink-muted);
    letter-spacing: 0.02em;
}
.case-rail__specs li { font-family: var(--sans); font-style: normal; }
.case-rail__specs li:not(:last-child)::after {
    content: " · ";
    margin-left: var(--s-2);
    color: var(--ink-muted);
}

/* Mobile: single-column stack — head on top, scroller below full-width. */
@media (max-width: 720px) {
    .case-rail__layout {
        grid-template-columns: 1fr;
        gap: var(--s-5);
    }
    .case-rail__head {
        grid-column: 1 / -1;
        position: static;
        padding-right: var(--gutter);
    }
    .case-rail__scroller {
        grid-column: 1 / -1;
    }
    .case-rail__item {
        flex: 0 0 80%;
    }
}
.case-study-card__specs {
    list-style: none;
    padding: var(--s-3) 0 0;
    margin: auto 0 0;
    border-top: 1px solid var(--hairline);
    display: flex;
    flex-wrap: wrap;
    gap: 6px var(--s-3);
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    font-weight: 500;
    color: var(--ink-muted);
    letter-spacing: 0.18em;
    text-transform: uppercase;
}
.case-study-card__specs li { font-family: var(--sans); font-weight: 500; }
.case-study-card__specs li:not(:last-child)::after {
    content: " · ";
    margin-left: var(--s-3);
    color: var(--hairline);
}

/* ---------- Case study INDEX page (/case-studies) ----------------------
   Hero entry on top (2-col split, image left + copy right), then 5
   smaller entries in 2-up below. Same logic as the homepage deck but
   stretched to fill the index page's content column. */

.case-study-index-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-7) var(--s-5);
}
.case-study-entry { margin: 0; }
.case-study-entry--hero { grid-column: span 2; }
@media (max-width: 900px) {
    .case-study-index-grid { grid-template-columns: 1fr; gap: var(--s-7); }
    .case-study-entry--hero { grid-column: auto; }
}

.case-study-entry__link {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    overflow: hidden;
    transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
    height: 100%;
}
.case-study-entry--hero .case-study-entry__link {
    flex-direction: row;
    align-items: stretch;
}
.case-study-entry--hero .case-study-entry__photo {
    flex: 1 1 50%;
    min-height: 100%;
}
.case-study-entry--hero .case-study-entry__body {
    flex: 1 1 50%;
    padding: var(--s-7);
    gap: var(--s-4);
    justify-content: center;
}
@media (max-width: 900px) {
    .case-study-entry--hero .case-study-entry__link { flex-direction: column; }
    .case-study-entry--hero .case-study-entry__photo { aspect-ratio: 8 / 5; flex: none; min-height: 0; }
}

/* No-photo fallback — imageless case studies degrade to a text-led card
   (eyebrow + title + specs) instead of an empty grey frame, so the index
   reads as an intentional editorial list. Remove once every published
   case study carries a PrimaryImage. */
.case-study-entry--no-photo .case-study-entry__link { flex-direction: column; }
.case-study-entry--no-photo .case-study-entry__body { flex: 1 1 auto; }

.case-study-entry__photo {
    margin: 0;
    background: var(--stone-200);
    overflow: hidden;
}
.case-study-entry__photo[data-ratio="wide"]   { aspect-ratio: 8 / 5; }
.case-study-entry__photo[data-ratio="square"] { aspect-ratio: 8 / 5; }
.case-study-entry__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.case-study-entry__body {
    padding: var(--s-5);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    flex: 1;
}
.case-study-entry__title {
    font-size: var(--t-h2);
    line-height: 1.18;
    margin: 0;
    color: var(--ink);
}
.case-study-entry--hero .case-study-entry__title {
    font-size: var(--t-h1);
    line-height: 1.15;
}
.case-study-entry__summary {
    color: var(--ink-soft);
    margin: 0;
}

/* ---------- Case study DETAIL page (/case-studies/{slug}/{id}) --------- */

.case-study {
    max-width: var(--maxw-text);
    margin: 0 auto;
}
.case-study__head {
    margin-bottom: var(--s-7);
}
.case-study__back {
    margin: 0 0 var(--s-6);
    font-family: var(--sans);
    font-size: 13px;
}
.case-study__back a {
    color: var(--ink-muted);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 1px;
}
.case-study__back a:hover {
    color: var(--ink);
    border-bottom-color: var(--ink);
}
.case-study__eyebrow {
    margin: 0 0 var(--s-3);
}
.case-study__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-display);
    line-height: 1.05;
    letter-spacing: -0.022em;
    margin: 0 0 var(--s-5);
    color: var(--ink);
    text-wrap: balance;
}
.case-study__summary {
    font-family: var(--sans);
    font-size: 1.2rem;
    line-height: 1.5;
    color: var(--ink-soft);
    margin: 0 0 var(--s-7);
}

/* Specs row — small "Destination / Group size / Duration / Programme"
   data block, displayed as a 4-column key/value list with hairline. */
.case-study__specs {
    list-style: none;
    margin: 0 0 var(--s-7);
    padding: var(--s-5) 0;
    border-top: 1px solid var(--hairline);
    border-bottom: 1px solid var(--hairline);
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-5) var(--s-4);
}
@media (max-width: 720px) {
    .case-study__specs { grid-template-columns: repeat(2, 1fr); }
}
.case-study__specs li { display: flex; flex-direction: column; gap: 4px; }
.case-study__spec-label {
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.case-study__spec-value {
    font-family: var(--sans);
    font-size: 15px;
    font-weight: 500;
    color: var(--ink);
}

.case-study__photo {
    margin: 0 0 var(--s-8);
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--stone-200);
    border-radius: var(--r-md);
    /* break out beyond the reading column for visual impact */
    width: calc(100% + 2 * var(--s-9));
    margin-left: calc(-1 * var(--s-9));
}
@media (max-width: 900px) {
    .case-study__photo { width: 100%; margin-left: 0; }
}
.case-study__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.case-study__body {
    margin: 0 0 var(--s-7);
}

/* Pull quote — italic Garamond, indented from a thick accent rule. */
.case-study__quote {
    margin: var(--s-8) 0;
    padding: 0 0 0 var(--s-5);
    border-left: 3px solid var(--accent);
    font-family: var(--serif);
    font-style: italic;
    font-size: clamp(1.15rem, 1.6vw, 1.45rem);
    line-height: 1.45;
    color: var(--ink);
}

.case-study__what-worked {
    margin: var(--s-8) 0 0;
    padding: var(--s-7) 0 0;
    border-top: 1px solid var(--hairline);
}
.case-study__h2 {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 1.5rem;
    letter-spacing: -0.015em;
    margin: 0 0 var(--s-5);
    color: var(--ink);
}

/* Testimonial — design system pattern (components.html). Big serif
   blockquote + 48px avatar circle + name/role/company. Hand-curated
   quotes only; the .review__* widget renders Google Reviews separately. */
.testimonial {
    margin: 0 auto;
    padding: var(--s-6) 0;
    display: grid;
    grid-template-columns: minmax(180px, 240px) minmax(0, 1fr);
    gap: var(--s-8);
    align-items: start;
    text-align: left;
}
.testimonial__meta {
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
    padding-right: var(--s-6);
    border-right: 1px solid var(--hairline);
}
.testimonial__body {
    min-width: 0;
}
.testimonial__quote {
    font-family: var(--serif);
    font-size: clamp(1.25rem, 2vw, 1.75rem);
    line-height: 1.4;
    font-style: italic;
    color: var(--ink);
    margin: 0 0 var(--s-5);
    text-wrap: balance;
}
.testimonial__quote p {
    font-family: inherit;
    font-style: inherit;
    font-size: inherit;
    margin: 0;
    color: inherit;
}
.testimonial__source {
    display: inline-flex;
    align-items: center;
    gap: var(--s-3);
}
.testimonial__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-ink);
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.04em;
    flex: 0 0 auto;
}
.testimonial__cite {
    text-align: left;
    display: flex;
    flex-direction: column;
}
.testimonial__name {
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
}
.testimonial__role {
    font-family: var(--sans);
    font-size: 12px;
    color: var(--ink-muted);
    letter-spacing: 0.02em;
}
.testimonial__logo {
    display: flex;
    align-items: center;
    min-height: 40px;
}
.testimonial__logo img {
    max-height: 48px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    object-position: left center;
    /* Multiply blend drops white logo backgrounds onto the page ground —
       works for SVG (e.g. built-in <rect fill="white">) and raster
       (JPG/PNG with a white card around the mark). */
    mix-blend-mode: multiply;
}
.testimonial__facts {
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
}
.testimonial__fact {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
}
.testimonial__fact-label {
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin: 0;
}
.testimonial__fact-value {
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
    margin: 0;
}
@media (max-width: 720px) {
    .testimonial {
        grid-template-columns: 1fr;
        gap: var(--s-6);
    }
    .testimonial__meta {
        padding-right: 0;
        border-right: 0;
        border-bottom: 1px solid var(--hairline);
        padding-bottom: var(--s-5);
    }
}

/* Testimonial slider — stack of figures, only [is-active] visible.
   Arrows sit beside the quote; on narrow screens they tuck under it. */
.testimonial-wrap {
    overflow: hidden;
    /* Paired with .affiliation in the elements grid — tighter padding
       than the default home-section rhythm so the editorial pair reads
       as one row, not two stadiums of whitespace. */
    padding: var(--s-9) var(--gutter);
}
/* Match the affiliation eyebrow margins so the paired blocks' eyebrows
   line up exactly at the row's baseline (negative-space alignment). */
.testimonial-wrap__eyebrow {
    margin: 0 0 var(--s-4);
}
.testimonial-slider {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--s-3);
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 var(--s-3);
}
.testimonial-slider__stage {
    position: relative;
    display: grid;
}
.testimonial-slider__slide {
    grid-area: 1 / 1;
    opacity: 0;
    visibility: hidden;
    transition: opacity 240ms ease;
    pointer-events: none;
}
.testimonial-slider__slide.is-active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}
.testimonial-slider__arrow {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 1px solid var(--rule);
    color: var(--ink);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex: 0 0 auto;
    transition: border-color 160ms ease, color 160ms ease, background 160ms ease;
}
.testimonial-slider__arrow:hover,
.testimonial-slider__arrow:focus-visible {
    border-color: var(--ink);
    color: var(--ink);
    outline: none;
}
.testimonial-slider__arrow:disabled {
    opacity: 0.35;
    cursor: default;
}
@media (max-width: 720px) {
    .testimonial-slider {
        grid-template-columns: auto auto;
        grid-template-rows: auto auto;
        justify-content: center;
        gap: var(--s-4);
    }
    .testimonial-slider__stage {
        grid-column: 1 / -1;
        grid-row: 1;
    }
    .testimonial-slider__arrow--prev {
        grid-column: 1;
        grid-row: 2;
        justify-self: end;
        margin-right: var(--s-2);
    }
    .testimonial-slider__arrow--next {
        grid-column: 2;
        grid-row: 2;
        justify-self: start;
        margin-left: var(--s-2);
    }
}

/* "Read full testimonial" link — sits below the figcaption inside the
   slide. Sans, small, neutral; the slide that has it (Chargebee)
   visually matches the height of the short quotes around it. */
.testimonial__more-trigger {
    appearance: none;
    -webkit-appearance: none;
    display: block;
    margin: 0 0 var(--s-7);
    background: transparent;
    border: 0;
    padding: 0;
    font-family: var(--sans);
    font-size: var(--t-small);
    color: var(--ink-soft);
    letter-spacing: 0.02em;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 4px;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--rule-band);
    transition: color 160ms ease, text-decoration-color 160ms ease;
}
.testimonial__more-trigger:hover,
.testimonial__more-trigger:focus-visible {
    color: var(--ink);
    text-decoration-color: var(--ink);
    outline: none;
}

/* Modal overlay for the full quote. One per testimonial that has
   QuoteExpanded. [hidden] for initial a11y state; .is-open fades in
   the scrim + card (CSS transition). Body locks scroll while open. */
.testimonial-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--gutter);
    opacity: 0;
    transition: opacity 200ms ease;
}
/* [hidden] must beat display:flex above so the closed modal doesn't
   sit over the page and swallow clicks (scrim is position:absolute
   inset:0 inside it). */
.testimonial-modal[hidden] {
    display: none;
}
.testimonial-modal.is-open {
    opacity: 1;
}
.testimonial-modal__scrim {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    cursor: pointer;
}
.testimonial-modal__card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--rule-band);
    max-width: 720px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
    padding: var(--s-8) var(--s-7);
    transform: translateY(8px);
    transition: transform 200ms ease;
}
.testimonial-modal.is-open .testimonial-modal__card {
    transform: translateY(0);
}
.testimonial-modal__close {
    position: absolute;
    top: var(--s-3);
    right: var(--s-3);
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 0;
    padding: var(--s-2);
    font-family: var(--sans);
    font-size: 24px;
    line-height: 1;
    color: var(--ink-muted);
    cursor: pointer;
    transition: color 160ms ease;
}
.testimonial-modal__close:hover,
.testimonial-modal__close:focus-visible {
    color: var(--ink);
    outline: none;
}
.testimonial-modal__quote {
    margin: 0;
    padding: 0;
    font-family: var(--serif);
    font-size: var(--t-body-lg);
    line-height: 1.55;
    font-style: italic;
    color: var(--ink);
}
.testimonial-modal__quote p {
    font-family: inherit;
    font-style: inherit;
    margin: 0 0 var(--s-4);
}
.testimonial-modal__quote p:last-child {
    margin-bottom: 0;
}
.testimonial-modal__cite {
    margin-top: var(--s-6);
    padding-top: var(--s-4);
    border-top: 1px solid var(--rule-band);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.testimonial-modal__name {
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
}
.testimonial-modal__role {
    font-family: var(--sans);
    font-size: 12px;
    color: var(--ink-muted);
    letter-spacing: 0.02em;
}
body.is-testimonial-modal-open {
    overflow: hidden;
}
@media (max-width: 720px) {
    .testimonial-modal__card {
        padding: var(--s-6) var(--s-5);
    }
}

/* ---------- DMC landing ------------------------------------------- */

.dmc { padding: 0; }

/* DMCPage overrides the generic main padding (same trick as HomePage) */
.t-App\\PageType\\DMCPage main {
    padding: 0 0 var(--s-10);
    max-width: none;
}

/* Process strip — 5-step timeline. Connecting hairline runs through the
   centre of all circles via ::before; circles sit on top with surface
   background to break the line cleanly. First step is active (accent fill). */
.process-strip {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--s-5);
    position: relative;
}
.process-strip::before {
    content: "";
    position: absolute;
    top: 18px;
    left: 6%;
    right: 6%;
    height: 1px;
    background: var(--hairline);
    z-index: 0;
}
@media (max-width: 800px) {
    .process-strip { grid-template-columns: 1fr; gap: var(--s-5); }
    .process-strip::before { display: none; }
}
.process-step {
    position: relative;
    z-index: 1;
    text-align: left;
}
.process-step__circle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--bg);
    border: 1px solid var(--ink);
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
    margin-bottom: var(--s-3);
    font-feature-settings: "tnum";
}
.process-step.is-active .process-step__circle {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-ink);
}
.process-step__title {
    font-size: var(--t-h4);
    color: var(--ink);
    margin: 0 0 4px;
}
.process-step__text {
    font-family: var(--sans);
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink-soft);
    margin: 0;
}

/* ---------- Google Reviews — Featured + supporting ----------------
   Editorial hierarchy, not a row of equal cards: one lead review set
   large in a subtly tinted block, up to two supporting reviews stacked
   beside it. Markup: themes/lxp/templates/Includes/GoogleReviews.ss.
   The eyebrow sits in flow above the head (site-wide `section >
   .t-eyebrow` rule); the head carries the section h2 + the aggregate. */

.reviews__head { flex-wrap: wrap; align-items: baseline; }
.reviews__heading {
    /* section tier — matches other homepage section titles (= --t-h1
       clamp). NOT hero tier (see type-hierarchy invariant). */
    font-size: var(--t-section);
    line-height: 1.1;
    margin: 0;
    /* No measure cap: a 22ch cap was tuned to the English default
       ("What our clients say", 20 chars) and forced longer locales to break
       awkwardly — German "Was unsere Kunden sagen" (23) wrapped a lone "sagen",
       Spanish "Lo que dicen nuestros clientes" (30) is longer still. It's a
       short section title, so let it size to content and stay on one line; the
       flex head (justify-content: space-between) keeps it clear of the summary. */
}

/* Aggregate summary — stars + numeric rating + the Google mark + count.
   The numeric rating (not five painted stars) carries the headline
   trust; the multicolour G names the source. */
.reviews__summary {
    display: flex;
    align-items: baseline;
    gap: var(--s-3);
    margin: 0;
    font-size: 0.95rem;
    color: var(--ink-soft);
    white-space: nowrap;
}
.reviews__stars {
    color: var(--feature-500);
    letter-spacing: 2px;
    font-size: 1rem;
    line-height: 1;
}
.reviews__rating {
    font-family: var(--sans);
    font-weight: 700;
    font-size: 1.6rem;
    letter-spacing: -0.02em;
    line-height: 1;
    color: var(--ink);
}
.reviews__gmark { display: inline-flex; align-self: center; }
.reviews__gmark svg { width: 15px; height: 15px; display: block; }
.reviews__count { letter-spacing: 0.02em; color: var(--ink-muted); }

/* Featured + supporting grid. Lead review ≈ 1.6× the supporting column;
   collapses to a single column on tablet/mobile. */
.reviews__layout {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: var(--s-6);
    align-items: stretch;
}

.reviews__featured {
    /* Surface treatment (tint, radius, padding) comes from the shared
       PANEL canon at the top of this file. Only the lead review's own
       layout lives here: a flex column so __by can be pushed to the
       bottom via margin-top:auto. */
    margin: 0;
    display: flex;
    flex-direction: column;
}
.reviews-featured__stars {
    color: var(--feature-500);
    letter-spacing: 3px;
    font-size: 1.15rem;
    line-height: 1;
    margin-bottom: var(--s-4);
}
.reviews-featured__quote {
    margin: 0;
    /* The lead review reads as a true editorial pull quote — Garamond
       italic, the one sanctioned accent use (set explicitly so it does
       not merely ride the global blockquote rule in tokens.css). */
    font-family: var(--serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.5rem, 2.6vw, 2.1rem);
    line-height: 1.32;
    letter-spacing: -0.005em;
    color: var(--ink);
    /* cap very long reviews so the block keeps a sane height */
    display: -webkit-box;
    -webkit-line-clamp: 8;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.reviews-featured__by {
    margin-top: auto;
    padding-top: var(--s-6);
    font-size: var(--t-body);
    color: var(--ink-soft);
}

.reviews__side {
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
}
.reviews-mini {
    margin: 0;
    border-top: 1px solid var(--hairline);
    padding-top: var(--s-5);
}
.reviews-mini:first-child { border-top: 0; padding-top: 0; }
.reviews-mini__stars {
    color: var(--feature-500);
    letter-spacing: 2px;
    font-size: 0.85rem;
    line-height: 1;
}
/* Per-review stars are honest (★ filled = score, ☆ empty = remainder).
   The filled run inherits the orange; the empty run is a warm grey so the
   filled-vs-empty distinction is carried by COLOUR, not a low-contrast
   glyph outline (≈4.6:1 on bone and on the featured tint). Invisible on
   the common 5-star case — only a sub-5 review shows a grey star. */
.reviews-featured__stars .reviews__stars-off,
.reviews-mini__stars .reviews__stars-off { color: var(--stone-500); }
.reviews-mini__text {
    /* Supporting copy, not a feature pull quote — Helvetica, overriding
       the global blockquote serif/italic (tokens.css). Small italic serif
       reads too soft at this size. */
    font-family: var(--sans);
    font-style: normal;
    margin: var(--s-3) 0;
    font-size: var(--t-body);
    line-height: 1.5;
    color: var(--ink);
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.reviews-mini__by { font-size: var(--t-small); color: var(--ink-muted); }

/* Shared author + time treatment across featured and mini. */
.reviews__author { color: var(--ink); font-weight: 600; }
.reviews__time { color: var(--ink-muted); }
.reviews__time::before { content: " · "; }

/* No rule above the "all reviews on Google" link. It separated a list from
   the action below it, a job the space already does — and the link is
   right-aligned with an accent underline, so it reads as an action either
   way. It also used the same hairline as the .reviews-mini dividers a few
   lines above, where the line means "next item in the list": one mark, two
   meanings. Since the following block now leads with a section rule, the two
   marks ended up stacked a few dozen pixels apart. Spacing kept at the
   former border's optical position (48 + 40 ≈ 72 + 16). */
.reviews__more {
    margin-top: var(--s-9);
    padding-top: var(--s-2);
    font-size: 0.9rem;
    text-align: right;
}
.reviews__more a {
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px solid var(--accent);
    padding-bottom: 2px;
}
.reviews__more a:hover { border-bottom-color: var(--feature-500); }

@media (max-width: 860px) {
    .reviews__layout { grid-template-columns: 1fr; gap: var(--s-5); }
    .reviews-featured__quote { -webkit-line-clamp: 10; }
    .reviews__side { margin-top: var(--s-2); }
}

/* ---------- Article detail (long-read editorial) ------------------ */

/* GRID RHYTHM
   ────────────────────────────────────────────────────────────────
   ONE rail, ONE rhythm. Every block on this page is a Bootstrap
   `.row` direct child of `.article`, using a single page-wide
   gutter override: `--bs-gutter-x: var(--s-8)` (52px). Set once
   on `.article .row` so every row inherits — no per-block overrides.

   `.article` lives inside <main>, which provides the rail via
       max-width: var(--maxw); padding: 0 var(--gutter)
   That rail is identical to the site-header brand-to-controls
   rail (both anchor at var(--gutter) from the viewport edges).

   Because the gutter is uniform across every row, the col-5
   grid line stays consistent: hero LEFT == body LEFT == gallery
   tile-2 LEFT. Bumping the gutter widens the visible gap between
   header↔hero, between gallery tiles, and between prev↔next,
   without breaking that alignment.

   Below lg the editorial row collapses to col-12 (header then hero stack).
   sm-md: gallery + nav split col-sm-6 (50/50 inside rail).
   Below sm: everything stacks col-12. */
.article {
    max-width: var(--maxw);
    margin: 0 auto;
}

/* Page-wide column gutter override. MUST be scoped to the `.row`
   element itself — Bootstrap's `.row` rule sets `--bs-gutter-x: 1.5rem`
   on the row, which shadows any parent declaration. Higher specificity
   here (`.article .row` = 0,2,0 vs Bootstrap's `.row` = 0,1,0) wins.

   Capped to 2× the rail padding: the row's negative outdent is
   gutter/2, and it must never exceed <main>'s --gutter or the row
   spills past the viewport. Below ~650px --gutter hits its 20px floor
   while the fixed s-8 (52px) outdent stayed 26px — a ~6px horizontal
   scroll on phones. min() keeps the full s-8 gutter wherever the rail
   is wide enough (>=650px) and shrinks it to a flush fit below that. */
.article .row {
    --bs-gutter-x: min(var(--s-8), calc(var(--gutter) * 2));
}

/* Vertical rhythm — every row separated by --s-9. Keep the rhythm on
   block-level margin (not row gutter-y) so it composes with main's
   padding box cleanly. */
.article__editorial,
.article__body-row,
.article__gallery {
    margin-bottom: var(--s-9);
}
.article > .row { --bs-gutter-y: 0; }

/* Header + hero share row 1 from md+ (≥768px): header col-md-4
   (cols 1-4), hero col-md-8 (cols 5-12). Below md both stack col-12.
   Editorial split kicks in earlier than the body/gallery/nav offset
   layouts (lg+) so the page reads as a wide editorial header even on
   smaller desktops. */
.article__head { margin: 0; }
.article__hero { margin: 0; }

.article__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-hero);
    line-height: 1.05;
    letter-spacing: -0.015em;
    margin: 0 0 var(--s-5);
    max-width: 28ch;
    text-wrap: balance;
}

.article__byline {
    font-family: var(--sans);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-soft);
    margin: 0;
}

.article__hero img {
    width: 100%;
    height: auto;
    object-fit: cover;
    display: block;
}

.article__external {
    margin-top: var(--s-8);
    padding-top: var(--s-5);
    border-top: var(--rail-soft);
    font-size: 0.95rem;
}
.article__external a { text-decoration: none; border-bottom: 1px solid var(--hairline); }
.article__external a:hover { border-bottom-color: var(--accent); }

/* Gallery: ul.row with li.col tiles. Same Bootstrap default gutter
   as every other row on the page, so tile-2 LEFT edge sits flush
   with body LEFT edge (both at the col-5 grid line at lg+). */
.article-slides {
    list-style: none;
    padding-left: 0;
    margin-block: 0;
    --bs-gutter-y: var(--s-6);
}
.article-slide__trigger {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: zoom-in;
    overflow: hidden;
}
.article-slide__trigger img {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
    transition: transform var(--card-img-hover-duration) var(--card-img-hover-easing);
}
.article-slide__trigger:hover img,
.article-slide__trigger:focus-visible img {
    transform: scale(var(--card-img-hover-scale));
}
.article-slide__trigger:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* ---------- Lightbox -------------------------------------------- */
/* Gallery-wall treatment — sand background (--bg-soft) so photos read
   like prints on a wall, not the usual Instagram black void. Controls
   in dark stone for contrast. The ::backdrop dims the page behind so
   the transition into the lightbox feels like entering a quiet room. */
.lightbox {
    width: 100vw;
    height: 100vh;
    max-width: none;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: var(--bg-soft);
    color: var(--ink);
    overflow: hidden;
}
.lightbox::backdrop {
    background: rgba(15, 14, 10, 0.45);
}
.lightbox[open] {
    display: flex;
    align-items: center;
    justify-content: center;
}
.lightbox__image {
    max-width: min(90vw, 1600px);
    max-height: 86vh;
    object-fit: contain;
    display: block;
    box-shadow: var(--shadow-4);
}
.lightbox__btn {
    position: absolute;
    background: transparent;
    border: 0;
    color: var(--ink-soft);
    cursor: pointer;
    padding: var(--s-3);
    line-height: 0;
    transition: color 0.15s ease, transform 0.15s ease;
}
.lightbox__btn:hover,
.lightbox__btn:focus-visible {
    color: var(--ink);
}
.lightbox__btn:focus-visible {
    outline: 1px solid var(--ink-soft);
    outline-offset: 2px;
}
.lightbox__btn--close {
    top: var(--s-4);
    right: var(--s-4);
}
.lightbox__btn--prev,
.lightbox__btn--next {
    top: 50%;
    transform: translateY(-50%);
}
.lightbox__btn--prev { left: var(--s-4); }
.lightbox__btn--next { right: var(--s-4); }
.lightbox__btn--prev:hover { transform: translateY(-50%) translateX(-3px); }
.lightbox__btn--next:hover { transform: translateY(-50%) translateX(3px); }
.lightbox__counter {
    position: absolute;
    bottom: var(--s-5);
    left: 50%;
    transform: translateX(-50%);
    margin: 0;
    font-family: var(--sans);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--ink-soft);
}

@media (max-width: 560px) {
    .lightbox__btn--prev { left: 0; }
    .lightbox__btn--next { right: 0; }
    .lightbox__image { max-width: 96vw; }
}

/* Nav rides the same single rail. Prev in cols 5-8 (matches body's
   col-lg-8 offset-lg-4 left edge), next in cols 9-12. Below lg falls
   back to col-sm-6 (50/50 side-by-side); below sm fully stacks. Shares
   Bootstrap's default gutter with every other row on the page. */
.article__nav {
    margin-top: var(--s-9);
    padding-top: var(--s-6);
    border-top: var(--rail-soft);
    --bs-gutter-y: var(--s-5);
}

/* When only one direction exists, push it to the right side of the row.
   Margin-left auto in a flex container takes all available space as left
   margin, anchoring the single link at the right edge — keeps "only next"
   visually correct (and "only prev" already sits at offset-lg-4). */
.article__nav-link:only-child {
    margin-left: auto;
}
.article__nav-link {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    text-decoration: none;
    color: inherit;
}
/* Right-align only when prev/next sit side-by-side (Bootstrap sm and up).
   Below sm they stack and read left-aligned. */
@media (min-width: 576px) {
    .article__nav-link--next { text-align: right; }
}
.article__nav-label {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.article__nav-title {
    font-family: var(--serif);
    font-style: italic;
    font-size: 1.1rem;
    line-height: 1.3;
    color: var(--ink);
}

/* News-index intro lede. The intro paragraph is an .element-textext block
   (migrated by `migrate-article-holder-intro`) sitting as the first child
   of .page__elements, directly under the page__head. As an Elemental
   <section> it inherited the universal section rhythm padding — `.element >
   section { padding-top: var(--s-11) }` (128px, ~line 3258) — on top of its
   own s-9 (72px) block margin, opening a ~200px void below the "News"
   headline. That generous rhythm is for sections deep in a page, not the
   lede right under the title. Strip both on the first block so the lede
   reads as the title's subtitle: title → lede → list flows tight, the gap
   below the headline becoming just the page__head's own margin. */
.article-holder .page__head {
    margin-bottom: var(--s-6);
}
/* Same lede-tightening wherever the first block sits directly under the
   inline sub-nav (base Page, ProductGroupPage — the sub-nav is always the
   immediate previous sibling of .page__elements in those layouts): the
   sub-nav already supplies the breathing band, so strip the block's own
   top rhythm (s-11 section padding + collapsed block margin) instead of
   opening a ~200px void below the bar. Pages without a sub-nav keep the
   full rhythm — there the band under the hero/head is wanted. */
.article-holder .page__elements > .element:first-child,
.article-holder .page__elements > .element:first-child > section,
.page-subnav--inline + .page__elements > .element:first-child,
.page-subnav--inline + .page__elements > .element:first-child > section {
    margin-top: 0;
    padding-top: 0;
}

/* ---------- Article list ------------------------------------------ */

/* News index — featured article on top (image left, copy right magazine
   spread), then 2-up grid below with thumbnail + body. Articles' first
   PageSlide image is used as the thumbnail (706 slides exist across 110
   articles in the legacy import). */
.article-holder .article-list {
    margin-top: var(--s-8);
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-7) var(--s-6);
    max-width: none;
}
.article-holder .article-card {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    overflow: hidden;
    background: var(--surface);
    padding: 0;
    transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
}
.article-holder .article-card--featured {
    grid-column: span 2;
    flex-direction: row;
    align-items: stretch;
}
.article-holder .article-card--featured .article-card__photo {
    flex: 1 1 55%;
    margin: 0;
    aspect-ratio: auto;
    min-height: 100%;
}
.article-holder .article-card--featured .article-card__body {
    flex: 1 1 45%;
    padding: var(--s-7);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--s-3);
}
.article-holder .article-card--featured .article-card__title {
    font-size: var(--t-h1);
    line-height: 1.05;
    letter-spacing: -0.02em;
    max-width: 22ch;
}
.article-holder .article-card--featured .article-card__summary {
    font-size: 1.1rem;
    line-height: 1.5;
}

.article-card__photo {
    margin: 0;
    aspect-ratio: 8 / 5;
    overflow: hidden;
    background: var(--stone-200);
}
.article-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.article-holder .article-card__body {
    padding: var(--s-5);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    flex: 1;
}

@media (max-width: 800px) {
    .article-holder .article-list { grid-template-columns: 1fr; gap: var(--s-7); }
    .article-holder .article-card--featured { grid-column: auto; flex-direction: column; }
    .article-holder .article-card--featured .article-card__photo { aspect-ratio: 8 / 5; flex: none; min-height: 0; }
    /* Tighter inner padding on full-width mobile cards (was 24px / 36px featured). */
    .article-holder .article-card__body,
    .article-holder .article-card--featured .article-card__body { padding: var(--s-4); }
}

/* Article-related sidebars (article detail page) keep the simple
   single-column flow — overrides on the holder only. */
.article-list {
    margin-top: var(--s-8);
    display: flex;
    flex-direction: column;
    gap: var(--s-8);
    max-width: var(--measure);
}

.article-card {
    padding-bottom: var(--s-6);
    border-bottom: var(--rail);
}
.article-holder .article-card { border-bottom: none; padding-bottom: 0; }
.article-list .article-card:last-child { border-bottom: none; }

.article-card__date {
    font-family: var(--sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--accent);
}
.article-card__title {
    font-size: var(--t-h2);
    line-height: 1.15;
    margin: var(--s-3) 0 var(--s-3);
    letter-spacing: -0.01em;
    text-wrap: balance;
}
.article-card__title a {
    color: inherit;
    text-decoration: none;
}
.article-card__byline {
    font-size: 0.85rem;
    color: var(--ink-soft);
    margin: 0 0 var(--s-4);
}
.article-card__summary {
    margin: 0;
    color: var(--ink-soft);
}
.article-card__more {
    margin-top: var(--s-4);
    font-size: 0.9rem;
}
.article-card__more a {
    text-decoration: none;
    color: var(--ink);
    border-bottom: 1px solid var(--hairline);
    padding-bottom: 1px;
}
.article-card__more a:hover { border-bottom-color: var(--accent); color: var(--accent); }

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

.team-grid {
    margin-top: var(--s-8);
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--s-6);
}

.team-card {
    grid-column: span 12;
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
}
@media (min-width: 820px) {
    .team-card { grid-column: span 6; }
}
@media (min-width: 1200px) {
    .team-card { grid-column: span 3; }
}
/* DMC team block (ElementLocalTeam, nested in .home-section) becomes a
   horizontal scroll-snap rail on mobile, faithfully matching the
   .service-tiles / .sister-brands rails. Scoped via `.home-section` so the
   standalone team page (TeamMemberHolder.ss — .team-grid sits in .page with
   NO .home-section ancestor) is left as the desktop->single-column stack and
   is NOT turned into a horizontal scroller. The rail bleeds to the section
   edge by cancelling .home-section's own --gutter padding with a negative
   margin-inline; a sliver of the next card hints at scrollability. The
   desktop grid (min-width:820px) is untouched. (2026-06-05) */
@media (max-width: 819px) {
    .home-section .team-grid {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: 64%;
        gap: var(--s-5);
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scroll-padding-left: var(--gutter);
        margin-inline: calc(-1 * var(--gutter));
        padding: 0 var(--gutter) var(--s-4);
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .home-section .team-grid::-webkit-scrollbar { display: none; }
    .home-section .team-card {
        grid-column: auto;
        scroll-snap-align: start;
        min-width: 0;
    }
    .home-section .team-card__photo { min-width: 0; }
    .home-section .team-card__name { overflow-wrap: anywhere; }
}
@media (max-width: 540px) {
    .home-section .team-grid { grid-auto-columns: 82%; gap: var(--s-4); }
}

/* Standalone team page (TeamMemberHolder.ss): .team-grid is a direct child
   of <article class="page"> — NOT inside .home-section — so the rail rules
   above never reach it. It must still collapse to a single column on mobile,
   otherwise the desktop repeat(12,1fr) grid with grid-column:span 12 stacks
   11 column-gaps inside one card and overflows the viewport. This restores
   the pre-2026-06-05 single-column fix, now scoped to .page > .team-grid so
   it cannot touch the DMC rail. (2026-06-05) */
@media (max-width: 819px) {
    .page > .team-grid { grid-template-columns: 1fr; }
    .page > .team-grid .team-card {
        grid-column: auto;
        min-width: 0;
    }
    .page > .team-grid .team-card__photo { min-width: 0; }
    .page > .team-grid .team-card__name { overflow-wrap: break-word; }
}

.team-card__photo {
    margin: 0 0 var(--s-4);
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: var(--hairline-soft);
}
.team-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.team-card__photo--empty {
    width: 100%;
    height: 100%;
    background: var(--hairline-soft);
}

.team-card__body {
    padding: var(--s-4) 0;
}
.team-card__role {
    font-size: 0.85rem;
    color: var(--ink-soft);
    margin: var(--s-1) 0 0;
}

/* ---------- Pagination -------------------------------------------- */

.pagination {
    margin-top: var(--s-8);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-5);
    flex-wrap: wrap;
    font-size: 0.9rem;
}
.pagination__pages {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    gap: var(--s-2);
}
.pagination__page {
    padding: var(--s-2) var(--s-4);
    border: 1px solid transparent;
    color: var(--ink-soft);
}
.pagination__page a {
    color: var(--ink-soft);
    text-decoration: none;
}
.pagination__page a:hover { color: var(--accent); }
.pagination__page--current {
    border-color: var(--accent);
    color: var(--ink);
}
.pagination__page--gap { border: none; padding: 0 var(--s-1); }
.pagination__link {
    color: var(--ink);
    text-decoration: none;
    padding: var(--s-2) var(--s-4);
    border: 1px solid var(--hairline);
}
.pagination__link:hover { border-color: var(--accent); }

.empty {
    margin-top: var(--s-8);
    color: var(--ink-soft);
    text-align: center;
    font-style: italic;
}

/* ---------- FAQ accordion ----------------------------------------- */

/* The FAQ used a 1px hairline rail where every other section leads with the
   animated section rule — one page, two devices for the same job, running
   into each other on the DMC pages (section rule → hairline → section rule).
   The rail is gone; .faq-band carries the same rule every block gets, and
   inherits the top margin so the mark sits exactly where the border did. */
.faq-band {
    position: relative;
    margin-top: var(--s-9);
}

/* The rule exposed a container-contract violation the old rail had been
   hiding: .faq applied its own maxw + gutter unconditionally, so on a
   bounded-main page (everything except the three below) it indented a
   second time — heading at 96px while every other section, and now the
   rule itself, sat at 48px. The rail moved with the box, so the offset
   was invisible until the mark stopped moving with it.

   .faq is bare by default per the container contract (main owns the rail)
   and self-binds only on the three page types that strip <main>'s rail —
   the same list, for the same reason, as .sustainability. */
.faq {
    padding-top: var(--s-6);
    padding-bottom: var(--s-9);
}
.t-App\\PageType\\HomePage .faq,
.t-App\\PageType\\DMCPage .faq,
.t-App\\PageType\\ContactPage .faq {
    max-width: var(--maxw);
    margin-left: auto;
    margin-right: auto;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
}
.faq__cols {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-6);
}
@media (min-width: 820px) {
    .faq__cols {
        grid-template-columns: 1fr 1.4fr;
        gap: var(--s-8);
        align-items: start;
    }
}
.faq__title {
    font-family: var(--sans);
    font-size: var(--t-h2);
    margin: 0;
    letter-spacing: -0.005em;
}
.faq__list {
    display: flex;
    flex-direction: column;
}
.faq__item {
    border-bottom: var(--rail);
}
.faq__question {
    list-style: none;
    padding: var(--s-4) 0;
    cursor: pointer;
    font-family: var(--sans);
    font-weight: 500;
    font-size: 1rem;
    color: var(--ink);
    position: relative;
    padding-right: var(--s-6);
}
.faq__question::-webkit-details-marker { display: none; }
.faq__question:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: var(--r-xs);
}
.faq__question::after {
    content: "+";
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--sans);
    font-size: 1.5rem;
    font-weight: 300;
    color: var(--ink-soft);
    transition: transform 150ms ease;
}
.faq__item[open] > .faq__question::after {
    content: "\2212"; /* minus */
}
.faq__answer {
    padding: 0 0 var(--s-5);
    color: var(--ink-soft);
}
.faq__answer p:last-child { margin-bottom: 0; }

/* Scope the full-bleed section wrapper inside DMCPage so FAQ sits in gutter */
.dmc .home-section .faq { margin-top: 0; padding-top: 0; border-top: 0; }

/* ---------- RFP form (ContactPage dark-surface pattern) -------------
   Per design system patterns.html (Inquiry / RFP form). Full-bleed
   --accent-deep section, two-column inner: copy left + form card
   (white surface) right. The form fields keep their existing
   .contact-form styles inside .rfp__card; only colors & padding
   change to suit the white surface within a dark frame. */

/* Neutralise main on ContactPage so .rfp fills viewport edge-to-edge. */
.t-App\\PageType\\ContactPage main {
    max-width: none;
    padding: 0;
}
.rfp {
    background: var(--accent-deep);
    color: #fff;
    padding: var(--s-9) 0 var(--s-10);
    --ink:       #f4f1ea;
    --ink-soft:  rgba(244, 241, 234, 0.78);
    --ink-muted: rgba(244, 241, 234, 0.55);
    font-weight: 400;   /* light-on-dark: stay regular (base sans is 300) */
}
.rfp__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
    display: grid;
    grid-template-columns: 1fr 1.2fr;
    gap: var(--s-9);
    align-items: start;
}
@media (max-width: 900px) {
    .rfp__inner { grid-template-columns: 1fr; gap: var(--s-7); }
}

/* Own row above the copy/form grid — mirrors .rfp__inner's rail so the
   eyebrow text lines up with the copy column below it. */
.rfp__eyebrow {
    max-width: var(--maxw);
    margin: 0 auto var(--s-4);
    padding: 0 var(--gutter);
}
/* OFF THE SCALE ON PURPOSE. 28–40px is its own step, between --t-h2 (22)
   and --t-section (25–41). Kept because this is the one conversion
   headline on the site: it carries the enquiry form, it sits on a dark
   ground, and its lead runs at 23px — at --t-h2 the headline would render
   smaller than the paragraph under it and the hierarchy would invert
   (checked on screen 2026-08-07, which is how the tier came up at all).
   The template used to carry a `t-h2` class beside it that lost on
   specificity and only made the markup claim a size it never had; that
   is gone. Do not fold this into a tier without looking at the page. */
.rfp__title {
    color: #fff;
    margin: 0 0 var(--s-4);
    max-width: 18ch;
    font-size: clamp(28px, 3.2vw, 40px);
    line-height: 1.1;
    letter-spacing: -0.02em;
}
.rfp__lead {
    font-family: var(--serif);
    font-size: clamp(1.15rem, 2vw, 1.4rem);
    font-style: italic;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.92);
    margin: 0 0 var(--s-5);
    /* Hold the lede to a reading measure so it doesn't run the full copy
       column on desktop. Only bites >~480px-wide columns, so the narrower
       mobile column is unaffected. */
    max-width: 20em;
}
/* Step list — numbered serif, hairline above each step. */
.rfp__steps {
    list-style: none;
    padding: 0;
    margin: var(--s-6) 0 0;
    display: flex;
    flex-direction: column;
    gap: 0;
}
.rfp__step {
    display: grid;
    grid-template-columns: 60px 1fr;
    gap: var(--s-4);
    align-items: baseline;
    padding: var(--s-4) 0;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
}
.rfp__step:last-child { border-bottom: 1px solid rgba(255, 255, 255, 0.18); }
.rfp__step-num {
    font-family: var(--sans);
    font-size: 22px;
    font-feature-settings: "tnum", "lnum";
    color: var(--feature);
}
.rfp__step-text {
    font-size: 14px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.92);
}

/* Trust signal under the step list — small Travelife seal + one-line
   factual context. Hairline above is implied by the .rfp__step:last-child
   bottom border. No background, no card; the logo is a self-contained
   stamp on the dark band. */
/* Google rating — quiet numeric proof on the dark band, above the
   Travelife badge. Star is the one small logo-orange accent. */
.rfp__rating {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: var(--s-6) 0 0;
    font-family: var(--sans);
    font-size: 0.95rem;
    color: rgba(255, 255, 255, 0.82);
}
.rfp__rating-star { color: var(--feature); }
.rfp__rating-value { font-weight: 600; color: #fff; }
.rfp__rating-count { color: rgba(255, 255, 255, 0.6); }

.rfp__trust {
    display: flex;
    align-items: center;
    gap: var(--s-4);
    margin: var(--s-5) 0 0;
    padding: 0;
    text-decoration: none;
    color: inherit;
}
.rfp__trust:hover .rfp__trust-text,
.rfp__trust:focus-visible .rfp__trust-text {
    color: #fff;
}
.rfp__trust-logo {
    flex: 0 0 auto;
    width: 120px;
    height: auto;
    display: block;
}
.rfp__trust-text {
    font-size: 13px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.7);
    transition: color 160ms var(--ease);
}
@media (max-width: 480px) {
    .rfp__trust { gap: var(--s-3); }
    .rfp__trust-logo { width: 96px; }
}

/* Form card — white surface, generous padding, design-system rounding.
   Reset the ink tokens here: the parent .rfp block flips them to cream
   for the dark band, which would render cream-on-white inside this card. */
.rfp__card {
    background: var(--surface);
    --ink:       #211c19;            /* espresso near-black — reset for the white card */
    --ink-soft:  rgba(33, 28, 25, 0.78);
    --ink-muted: rgba(33, 28, 25, 0.55);
    color: var(--ink);
    border-radius: var(--r-lg);
    padding: var(--s-7) var(--s-7);
    box-shadow: var(--shadow-2);
}
@media (max-width: 720px) {
    .rfp__card { padding: var(--s-5) var(--s-4); }
}

/* ---------- Homepage proposal CTA ---------------------------------
   Conversion endpoint at the homepage tail. Teaser variant of the
   .rfp pattern: full-bleed --accent-deep, single-column copy + steps
   + primary CTA → ContactPage. No form (the form lives on the RFP
   page itself). DS reference: homepage.html · formSec section. */
.home-rfp-cta {
    background: var(--bg-deep);
    color: #fff;
    padding: var(--s-9) 0 var(--s-10);
    margin-top: var(--s-8);
    --ink:       #f4f1ea;
    --ink-soft:  rgba(244, 241, 234, 0.78);
    --ink-muted: rgba(244, 241, 234, 0.55);
    font-weight: 400;   /* light-on-dark: stay regular (base sans is 300) */
}
.home-rfp-cta__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.home-rfp-cta__eyebrow {
    margin: 0 0 var(--s-4);
}
.home-rfp-cta__title {
    font-family: var(--sans);
    font-size: var(--t-display);
    line-height: 1.08;
    letter-spacing: -0.018em;
    color: #fff;
    margin: 0 0 var(--s-5);
    max-width: 18ch;
}
.home-rfp-cta__lead {
    font-size: 1.125rem;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.92);
    margin: 0 auto var(--s-7);
    /* Hold the centred lede to a reading measure — it was running the full
       ~1344px band width edge-to-edge. */
    max-width: 42rem;
}
.home-rfp-cta__steps {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--s-7);
    display: flex;
    flex-direction: column;
    gap: 0;
}
.home-rfp-cta__step {
    display: grid;
    grid-template-columns: 60px 1fr;
    gap: var(--s-4);
    align-items: baseline;
    padding: var(--s-4) 0;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
}
.home-rfp-cta__step:last-child { border-bottom: 1px solid rgba(255, 255, 255, 0.18); }
.home-rfp-cta__step-num {
    font-family: var(--sans);
    font-size: 22px;
    font-feature-settings: "tnum", "lnum";
    color: var(--feature);
}
.home-rfp-cta__step-text {
    font-size: 14px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.92);
}
.home-rfp-cta__btn { align-self: start; }
/* Inverted primary — the base .btn-primary is espresso (var(--accent)) on
   this near-black panel (var(--bg-deep)), ~1.2:1 contrast, so the actual
   click target all but vanishes while the headline shouts. Flip it to a
   solid bone fill: the CTA becomes the brightest object on the panel, no
   gradient, no shadow. Scoped to the panel — .btn-primary on light pages
   stays espresso-on-bone. Applies wherever .home-rfp-cta runs (home, DMC,
   service, team). */
.home-rfp-cta .btn-primary {
    /* NB: --ink is redefined to cream inside .home-rfp-cta for light-on-dark
       body copy, so it can't be used for the button label — use the
       un-overridden --accent-deep (#211c19) to get true dark-on-bone. */
    background: var(--bg);
    color: var(--accent-deep);
    border-color: var(--bg);
    font-weight: 600;
}
.home-rfp-cta .btn-primary:hover {
    background: #fff;
    color: var(--accent-deep);
    border-color: #fff;
}
@media (max-width: 720px) {
    .home-rfp-cta { padding: var(--s-7) 0 var(--s-8); }
    .home-rfp-cta__step { grid-template-columns: 44px 1fr; gap: var(--s-3); }
}

/* Centered variant — used at the homepage tail where the band stands
   alone (no left-aligned page rhythm to follow). Title, lede and steps
   align to the center axis; step rows keep the number + text pair but
   collapse to auto columns so the pair centers within its hairline row.
   Button centers via inline-block + text-align on the inner. */
.home-rfp-cta--center { text-align: center; }
.home-rfp-cta--center .home-rfp-cta__title,
.home-rfp-cta--center .home-rfp-cta__lead,
.home-rfp-cta--center .home-rfp-cta__steps { margin-inline: auto; }
.home-rfp-cta--center .home-rfp-cta__title {
    max-width: 24ch;
    line-height: 1.15;
}
.home-rfp-cta--center .home-rfp-cta__step {
    grid-template-columns: auto auto;
    justify-content: center;
    text-align: left;
}

/* ---------- DMC local office (Ibiza / Malta) ---------------------- */
/* Quiet grounding band shown only on DMC pages whose Location carries a
   registered office address. Light, type-driven; sits directly above the
   dark RFP CTA so the page reads office -> brief-us. Self-bound because
   DMC pages run on a stripped (full-bleed) main. */
/* position: relative anchors the hand-written .section-rule in DMCPage.ss —
   the rule is absolutely positioned and normally relies on the .element
   wrapper, which this band does not have. Top padding stays at the band's
   own compact rhythm rather than the 128px the block sections use; this is
   a short address band, not a full section. */
.dmc-office {
    position: relative;
    padding: var(--s-8) 0 0;
}
.dmc-office__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.dmc-office__eyebrow { margin: 0 0 var(--s-3); }
.dmc-office__place {
    font-family: var(--sans);
    font-size: var(--t-h2);
    font-weight: 700;
    line-height: var(--lh-snug);
    letter-spacing: -0.005em;
    color: var(--ink);
    margin: 0 0 var(--s-3);
}
.dmc-office__address {
    font-style: normal;
    font-size: var(--t-body-lg);
    line-height: var(--lh-loose);
    color: var(--ink-soft);
}

/* ---------- Contact page — direct channels ------------------------ */
/* The short path: mail / phone / WhatsApp as hairline rows between the
   hero and the offices list. Carries no H2 on purpose — "Wo Sie uns
   finden" is the page's first heading, and a third H2 tier stacked above
   it plus the RFP title below would read as three section openings in a
   row. Self-bound (__inner) — contact runs on a stripped main. */
.contact-direct {
    padding: var(--s-9) 0;
}
.contact-direct__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.contact-direct__lead {
    margin: 0 0 var(--s-9);
}
.contact-direct__eyebrow { margin: 0 0 var(--s-4); }
.contact-direct__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
/* The --ink rule opens the list, hairlines divide the items, and there is
   no rule under the last one: separators, not a frame. Same reasoning as
   .sustainability__row and .article-list. */
.contact-direct__row { border-top: 1px solid var(--ink); }
.contact-direct__row + .contact-direct__row { border-top: 1px solid var(--hairline); }
/* Whole row is the target — padding lives on the link, not the <li>, so
   the hit area spans the rule-to-rule band rather than just the text. */
.contact-direct__link {
    display: block;
    padding: var(--s-5) 0;
    color: var(--ink);
    text-decoration: none;
}
.contact-direct__link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}
.contact-direct__cols { align-items: baseline; }
.contact-direct__kind { display: inline-block; }
.contact-direct__value {
    display: inline-block;
    text-decoration: underline;
    text-decoration-color: transparent;
    text-underline-offset: 4px;
    transition: text-decoration-color 160ms var(--ease);
}
.contact-direct__link:hover .contact-direct__value {
    text-decoration-color: currentColor;
}
.contact-direct__note {
    font-size: var(--t-body);
    line-height: var(--lh-body);
    color: var(--ink-muted);
}
@media (max-width: 991.98px) {
    /* Stacked: the eyebrow-sized kind needs a gap under it, and the note
       needs one above, or the three lines read as one paragraph. */
    .contact-direct__kind { margin-bottom: var(--s-2); }
    .contact-direct__note { display: inline-block; margin-top: var(--s-2); }
}

/* ---------- Contact page — regional offices list ------------------ */
/* Every Location with a registered address — Palma (HQ), Ibiza, Malta.
   Menorca and Formentera are run from Palma and carry none. Bootstrap
   row > cols. Self-bound — contact runs on a stripped main. */
.contact-offices {
    padding: 0 0 var(--s-9);
}
.contact-offices__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 0 var(--gutter);
}
.contact-offices__eyebrow { margin: 0 0 var(--s-3); }
.contact-offices__title {
    font-family: var(--sans);
    font-size: var(--t-h1);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.015em;
    color: var(--ink);
    margin: 0 0 var(--s-6);
    max-width: 18ch;
}
.contact-offices__grid { row-gap: var(--s-6); }
.contact-offices__place {
    font-family: var(--sans);
    font-size: var(--t-h3);
    font-weight: 700;
    line-height: var(--lh-snug);
    color: var(--ink);
    margin: 0 0 var(--s-2);
}
.contact-offices__address {
    font-style: normal;
    font-size: var(--t-body-lg);
    line-height: var(--lh-loose);
    color: var(--ink-soft);
}

/* ---------- Contact page (head + body wrapper) -------------------- */
/* Page-level editorial frame ABOVE the RfpForm partial. The partial
   carries its own dark band + form card, so this block stays light
   and type-driven — eyebrow / hero-level title / supporting lede /
   breathing room. */
.contact-page__head {
    padding: var(--s-9) 0 var(--s-8);
    margin: 0 auto;
    max-width: var(--maxw);
}
.contact-page__eyebrow {
    margin: 0 0 var(--s-4);
}
.contact-page__title {
    font-family: var(--sans);
    font-size: var(--t-hero);
    font-weight: 700;
    line-height: 1.04;
    letter-spacing: -0.02em;
    color: var(--ink);
    margin: 0 0 var(--s-5);
    max-width: 14ch;
}
.contact-page__body {
    max-width: var(--maxw);
    margin: 0 auto var(--s-8);
}
.contact-page.page--has-hero .contact-page__body { margin-top: var(--s-7); }
@media (max-width: 720px) {
    .contact-page__head { padding: var(--s-7) 0 var(--s-6); }
}

/* ---------- Contact form ------------------------------------------ */

.contact-form { max-width: var(--measure); margin-inline: auto; }
.contact-form form { margin-top: var(--s-6); }

/* SilverStripe wraps the whole form in <fieldset>; browsers give that a
   default border + inset padding. Strip both so the form sits flush
   against the surrounding card. */
.contact-form fieldset {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

/* Hide the honeypot field — legitimate users never see it */
.contact-form #ContactForm_ContactForm_Website_Holder,
#ContactForm_ContactForm input[name="Website"] { position: absolute; left: -9999px; }

.contact-form .field {
    margin-bottom: var(--s-6);
    display: flex;
    flex-direction: column;
}
.contact-form label.left,
.contact-form label {
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-soft);
    margin-bottom: var(--s-2);
}
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form textarea,
.contact-form select {
    font-family: var(--sans);
    font-size: 0.875rem;
    padding: var(--s-4) 0;
    border: none;
    border-bottom: 1px solid var(--hairline-strong);
    background: transparent;
    color: var(--ink);
    width: 100%;
    transition: border-color 150ms ease;
}
.contact-form input:focus,
.contact-form textarea:focus,
.contact-form select:focus {
    outline: none;
    border-bottom-color: var(--ink);
    /* Doubles the underline to 2px without shifting layout — a darker
       1px line alone is too small a delta to read as "focused". */
    box-shadow: 0 1px 0 var(--ink);
}
.contact-form textarea { resize: vertical; min-height: 8rem; }

/* Native <select> — strip browser chrome, replace with editorial caret. */
.contact-form select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%2336302c' stroke-width='1.4' stroke-linecap='round'><path d='M1 1.5l5 5 5-5'/></svg>");
    background-repeat: no-repeat;
    background-position: right 4px center;
    background-size: 12px 8px;
    padding-right: var(--s-6);
    cursor: pointer;
}

/* Two-column field rows — wraps a FieldGroup in PHP. SS6's FieldGroup
   nests its children inside `.middleColumn.fieldgroup`, so the grid
   lives on that inner element, not the outer .field-row wrapper. */
.contact-form .field-row { margin-bottom: var(--s-6); }
.contact-form .field-row > .middleColumn.fieldgroup {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-4) var(--s-6);
}
.contact-form .field-row .fieldgroup-field { margin: 0; }
.contact-form .field-row .fieldholder-small { margin: 0; display: flex; flex-direction: column; }
@media (max-width: 600px) {
    .contact-form .field-row > .middleColumn.fieldgroup { grid-template-columns: 1fr; }
}

/* Chip multi-select — styles each <input type="checkbox"> + <label>
   pair inside a CheckboxSetField as a borderless toggle button. The
   real input is hidden; the label carries the visible state. */
.contact-form .chip-set { margin-bottom: var(--s-6); }
.contact-form .chip-set > label {
    /* The fieldset legend / outer label */
    display: block;
    margin-bottom: var(--s-3);
}
.contact-form .chip-set ul.checkboxset {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-2);
}
@media (max-width: 600px) {
    .contact-form .chip-set ul.checkboxset { grid-template-columns: repeat(2, 1fr); }
}
.contact-form .chip-set ul.checkboxset li { margin: 0; }
.contact-form .chip-set ul.checkboxset input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.contact-form .chip-set ul.checkboxset label {
    display: block;
    text-align: center;
    padding: var(--s-3) var(--s-4);
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink);
    background: #fff;
    border: 1px solid var(--ink);
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
    margin: 0;
}
.contact-form .chip-set ul.checkboxset label:hover {
    background: var(--bg-soft);
}
.contact-form .chip-set ul.checkboxset input[type="checkbox"]:checked + label {
    background: var(--accent);
    color: var(--accent-ink, #fff);
    border-color: var(--accent);
}
.contact-form .chip-set ul.checkboxset input[type="checkbox"]:focus-visible + label {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.contact-form .field.checkbox {
    flex-direction: row;
    gap: var(--s-4);
    align-items: flex-start;
    padding-top: var(--s-4);
}
.contact-form .field.checkbox input { margin-top: 0.3rem; }
.contact-form .field.checkbox label {
    font-family: var(--sans);
    font-size: 0.875rem;
    text-transform: none;
    letter-spacing: 0;
    color: var(--ink-soft);
    /* SS adds .right to checkbox labels (framework CSS sets text-align:
       right); force left so the consent text reads ragged-right, esp.
       when the longer DE string wraps. */
    text-align: left;
}
.contact-form .field.checkbox label a { color: var(--ink); text-underline-offset: 3px; }

/* Privacy-policy link sits below the checkbox as its own field. Plain
   serif size, accent (espresso) link, sits with the same indent as the
   checkbox label so it reads as belonging to the consent block. */
.form-terms-link {
    margin: calc(-1 * var(--s-3)) 0 var(--s-5);
    padding-left: 1.6rem;
    font-family: var(--sans);
    font-size: 0.875rem;
    color: var(--ink-soft);
}
.form-terms-link a {
    color: var(--accent);
    text-decoration: none;
    border-bottom: 1px solid var(--accent-soft);
    padding-bottom: 1px;
}
.form-terms-link a:hover { border-bottom-color: var(--accent); }

.contact-form .message {
    padding: var(--s-4) var(--s-5);
    margin: 0 0 var(--s-5);
    border-left: 2px solid var(--accent-deep);
    background: var(--hairline-soft);
    font-family: var(--sans);
    font-size: 0.875rem;
    color: var(--ink);
}
.contact-form .message.bad { border-left-color: var(--accent); }

/* Zero layout shift on validation. Per-field messages (client- or
   server-side) are pulled out of flow and floated into the gap below
   their field, so showing/hiding an error never reflows the form while
   the user is filling it in. The form-level .message banner is a direct
   child of <form> (not inside a .field), so it keeps its boxed style. */
.contact-form .field,
.contact-form .fieldholder-small { position: relative; }
.contact-form .field .message,
.contact-form .field .error,
.contact-form .field .validation {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin: 3px 0 0;
    padding: 0;
    border: 0;
    background: none;
    font-family: var(--sans);
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--error);
}
/* Invalid field: tint the underline to match its message. .has-error is
   added by contact-validation.js to the field holder. */
.contact-form .has-error input,
.contact-form .has-error textarea,
.contact-form .has-error select { border-bottom-color: var(--error); }

/* ---------- Enquiry modal shell -----------------------------------
   Shared by ALL THREE enquiry dialogs (contact-panel.js initModal):
   #contact-modal (.contact-modal — WhatsApp/Call + quick message), #rfp-modal
   (.rfp-modal — the proposal brief, RfpModal.ss) and #newsletter-modal
   (.newsletter-modal — the signup form, NewsletterModal.ss). All selector
   groups are LOAD-BEARING — do not drop any of them. The contact modal's
   channels live in contact-panel.css. */
.rfp-modal,
.contact-modal,
.newsletter-modal {
    width: min(560px, calc(100vw - var(--s-6)));
    max-height: calc(100dvh - var(--s-8));
    padding: 0;
    border: none;
    border-radius: var(--r-lg);
    background: var(--surface);
    color: var(--ink);
    box-shadow: var(--shadow-4);
    overflow: auto;
    overscroll-behavior: contain;
}
.rfp-modal::backdrop,
.contact-modal::backdrop,
.newsletter-modal::backdrop {
    background: rgba(20, 16, 14, 0.55);
    backdrop-filter: blur(2px);
}
.rfp-modal__panel,
.contact-modal__panel,
.newsletter-modal__panel { position: relative; padding: var(--s-7); }
.rfp-modal__close,
.contact-modal__close,
.newsletter-modal__close {
    position: absolute;
    top: var(--s-4);
    right: var(--s-4);
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: var(--r-pill);
    color: var(--ink-soft);
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease;
}
.rfp-modal__close:hover,
.rfp-modal__close:focus-visible,
.contact-modal__close:hover,
.contact-modal__close:focus-visible,
.newsletter-modal__close:hover,
.newsletter-modal__close:focus-visible { background: var(--bg-elev); color: var(--ink); }
.rfp-modal__close:focus-visible,
.contact-modal__close:focus-visible,
.newsletter-modal__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rfp-modal__title,
.contact-modal__title,
.newsletter-modal__title {
    font-size: clamp(24px, 4vw, 32px);
    line-height: 1.1;
    letter-spacing: -0.02em;
    margin: var(--s-2) var(--s-8) var(--s-3) 0;
}
.rfp-modal__lede,
.contact-modal__lede,
.newsletter-modal__lede { color: var(--ink-soft); margin: 0 0 var(--s-5); max-width: 46ch; }
.rfp-modal .contact-form,
.contact-modal .contact-form,
.newsletter-modal .contact-form { max-width: none; }
.rfp-modal .contact-form form,
.contact-modal .contact-form form,
.newsletter-modal .contact-form form { margin-top: 0; }
.rfp-modal__thanks,
.contact-modal__thanks,
.newsletter-modal__thanks { padding: var(--s-6) 0; }
.rfp-modal__thanks-title,
.contact-modal__thanks-title,
.newsletter-modal__thanks-title { font-size: clamp(22px, 3.5vw, 28px); line-height: 1.15; margin: 0 0 var(--s-3); }
.rfp-modal__thanks-lede,
.contact-modal__thanks-lede { color: var(--ink-soft); margin: 0 0 var(--s-6); max-width: 42ch; }
/* Newsletter thanks-panel: only a title + close button, so give the button
   the spacing the ledes provide in the other two dialogs. */
.newsletter-modal__thanks-title { margin-bottom: var(--s-6); }
@media (max-width: 600px) {
    .rfp-modal,
    .contact-modal,
    .newsletter-modal {
        /* Full-screen sheet. Use 100% (not 100vw): a top-layer <dialog>'s
           containing block IS the viewport, so 100% fills it exactly, while
           100vw counts the scrollbar gutter and spills ~8–15px wider. Because
           the root overflow-x:clip guard is intentionally OFF on touch devices
           (see top of file), that spill has nothing to contain it and the whole
           page scrolls sideways on iOS/Android with the modal open. margin:0
           overrides the UA dialog's centring auto-margins so the sheet stays
           flush at the top-left. */
        width: 100%;
        max-width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        margin: 0;
        border-radius: 0;
    }
    .rfp-modal__panel,
    .contact-modal__panel,
    .newsletter-modal__panel {
        padding: var(--s-8) var(--s-5) var(--s-6);
        /* Full-screen sheet (100dvh) under viewport-fit=cover: keep the submit
           button above the iOS home indicator. */
        padding-bottom: calc(var(--s-6) + env(safe-area-inset-bottom, 0px));
    }
}

.contact-form .Actions { margin-top: var(--s-8); }
.contact-form button,
.contact-form input[type="submit"] {
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    padding: var(--s-4) var(--s-8);
    background: var(--accent);
    color: var(--accent-ink);
    border: none;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background 200ms ease, transform 180ms var(--ease);
}
.contact-form button:hover,
.contact-form input[type="submit"]:hover {
    background: var(--accent-deep);
    transform: translateY(-1px);
}
/* Mirror the prototype's "Send brief →" — append an arrow glyph
   after the action text via a pseudo-element so editors don't have
   to type it into the FormAction title. */
.contact-form .btn-with-arrow::after {
    content: " →";
    display: inline-block;
    margin-left: 0.4em;
    transition: transform 180ms var(--ease);
}
.contact-form .btn-with-arrow:hover::after {
    transform: translateX(2px);
}

/* Field-level validation output from the SS form system */
.contact-form .message.required { content: ""; }
/* Quiet required marker so planners see which fields matter BEFORE they
   submit (it was previously blanked). SS marks required via the input's
   [required] attribute, not a wrapper class, so target the label that
   immediately precedes a required control. Monochrome — info, not colour.
   The textarea/select variants need the `.middleColumn` hop because SS
   wraps those controls (the label is the wrapper's sibling, not the
   control's); the checkbox renders its label AFTER the input. */
.contact-form label:has(~ input[required])::after,
.contact-form label:has(~ textarea[required])::after,
.contact-form label:has(~ select[required])::after,
.contact-form label:has(~ .middleColumn input[required])::after,
.contact-form label:has(~ .middleColumn textarea[required])::after,
.contact-form label:has(~ .middleColumn select[required])::after,
.contact-form input[type="checkbox"][required] ~ label::after {
    content: "*";
    margin-left: 4px;
    color: var(--ink-muted);
    font-weight: 500;
}
/* Per-field error styling (burgundy, AA on the light --surface card) is
   handled by the consolidated zero-shift float rule above, which also
   covers .error / .validation. */

/* Mobile: keep the form compact. The underline fields are airy on a phone,
   so tighten field padding and inter-field spacing without touching the
   desktop rhythm. Placed at the end of the section so these overrides win
   on source order over the equal-specificity base rules above. */
@media (max-width: 720px) {
    .contact-form form { margin-top: var(--s-4); }
    .contact-form .field { margin-bottom: var(--s-5); }
    .contact-form .field-row { margin-bottom: var(--s-5); }
    /* Stacked groups: 24px row-gap leaves room for a floated 1-line error
       under the first field without it touching the next label. */
    .contact-form .field-row > .middleColumn.fieldgroup { gap: var(--s-5); }
    .contact-form label { margin-bottom: var(--s-1); }
    /* ≥16px controls — anything smaller makes iOS Safari zoom-jump the
       whole page the moment a field is focused. */
    .contact-form input[type="text"],
    .contact-form input[type="email"],
    .contact-form textarea,
    .contact-form select { padding: var(--s-3) 0; font-size: 1rem; }
    .contact-form textarea { min-height: 6rem; }
    .contact-form .chip-set { margin-bottom: var(--s-5); }
    .contact-form .Actions { margin-top: var(--s-6); }
}

/* ---------- Search ------------------------------------------------ */

.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0);
    white-space: nowrap; border: 0;
}

/* Header search: icon trigger + full-screen centered <dialog> modal.
   Replaces the old inline input. Native <dialog> handles focus trap +
   ESC; JS in themes/lxp/js/search-modal.js wires the opener + backdrop
   close + focus restoration. */
.site-search-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--ink-soft);
    cursor: pointer;
    transition: color 120ms ease;
}
.site-search-trigger:hover,
.site-search-trigger:focus-visible { color: var(--ink); }
.site-search-trigger:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.site-search-trigger svg { display: block; }

.search-modal {
    margin: auto;
    padding: var(--s-8);
    border: 0;
    background: var(--surface);
    color: var(--ink);
    max-width: 680px;
    width: calc(100vw - var(--s-6));
}
.search-modal[open] { animation: searchModalIn 180ms ease-out both; }
/* Touch users have no ESC key and the backdrop tap is undiscoverable —
   same thin-stroke ✕ as the RFP modal. */
.search-modal__close {
    position: absolute;
    top: var(--s-3);
    right: var(--s-3);
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: var(--r-pill);
    color: var(--ink-soft);
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease;
}
.search-modal__close:hover,
.search-modal__close:focus-visible { background: var(--bg-soft); color: var(--ink); }
.search-modal__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@keyframes searchModalIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.search-modal::backdrop {
    background: rgba(26, 24, 19, 0.35);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.search-modal form { margin: 0; }
.search-modal input[type="search"] {
    width: 100%;
    font-family: var(--sans);
    font-size: 1.4rem;
    line-height: 1.4;
    padding: var(--s-4) 0;
    background: transparent;
    color: var(--ink);
    border: 0;
    border-bottom: 1px solid var(--hairline);
    border-radius: 0;
    -webkit-appearance: none;
    appearance: none;
}
.search-modal input[type="search"]:focus {
    outline: none;
    border-bottom-color: var(--ink);
}
.search-modal input[type="search"]::-webkit-search-cancel-button { display: none; }
.search-modal__hint {
    margin: var(--s-5) 0 0;
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.search-modal__hint kbd {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    color: var(--ink);
    background: transparent;
    border: 1px solid var(--hairline);
    padding: 1px 6px;
    border-radius: 0;
}

.search-form {
    display: flex;
    gap: var(--s-2);
    margin: var(--s-5) 0;
    max-width: var(--measure);
}
.search-form__label { display: none; }
.search-form input[type="search"] {
    flex: 1;
    font-family: var(--sans);
    font-size: 1.25rem;
    padding: var(--s-4) var(--s-5);
    border: 1px solid var(--hairline);
    background: var(--surface);
    color: var(--ink);
}
.search-form input[type="search"]:focus {
    outline: none;
    border-color: var(--accent);
}
.search-form button {
    font-family: var(--sans);
    font-size: 0.85rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0 var(--s-6);
    background: var(--accent);
    color: var(--accent-ink);
    border: none;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background 200ms ease;
}
.search-form button:hover { background: var(--accent-deep); }

.search-section + .search-section {
    margin-top: var(--s-9);
    padding-top: var(--s-8);
    border-top: var(--rail);
}

.search-pages {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-6);
}
.search-pages__item a {
    display: block;
    text-decoration: none;
    color: inherit;
    padding-bottom: var(--s-5);
    border-bottom: var(--rail);
}
.search-pages__item:last-child a { border-bottom: none; }
.search-pages__item h3 {
    font-family: var(--sans);
    font-size: 1.25rem;
    margin: 0 0 var(--s-2);
}
.search-pages__item p {
    color: var(--ink-soft);
    margin: 0 0 var(--s-2);
}
.search-pages__url {
    font-size: 0.75rem;
    color: var(--accent-deep);
    letter-spacing: 0.02em;
}

@media (max-width: 900px) {
    .search-modal {
        padding: var(--s-6);
    }
    .search-modal input[type="search"] {
        font-size: 1.15rem;
    }
}

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

.site-footer {
    border-top: var(--rail-soft);
    background: var(--surface);
    /* Fill the iOS home-indicator safe area with the footer's white ground
       (viewport-fit=cover is set) so no beige canvas shows below the footer.
       __inner keeps its own bottom padding, so footer content still clears it. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
}
.site-footer__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    /* Bottom padding is load-bearing: the legal microline is the last thing
       on the page, and .site-footer only pads out the iOS safe area. Without
       this the © line sits flush on the viewport edge. */
    padding: 0 var(--gutter) var(--s-6);
    font-size: 0.9rem;
}
.site-footer__grid {
    display: grid;
    grid-template-columns: 1.5fr repeat(3, 1fr);
    gap: var(--s-8) var(--s-6);
    padding-bottom: var(--s-8);
    border-bottom: var(--rail-soft);
}
.site-footer__col h3 {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin: 0 0 var(--s-4);
}
.site-footer__col ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.site-footer__col a {
    color: var(--ink);
    text-decoration: none;
}
.site-footer__col a:hover { color: var(--accent); }

.site-footer__brand {
    font-family: var(--serif);
    font-size: 1.35rem;
    font-style: italic;
    margin: 0 0 var(--s-4);
    color: var(--ink);
}
.site-footer__address {
    font-style: normal;
    color: var(--ink-soft);
    line-height: 1.6;
    font-size: 0.9rem;
}
/* Contact links sit directly under the address as one cluster — a small
   top gap separates them, no heading (the brand column carries no heading
   by design). Colours/hover come from .site-footer__col a. */
.site-footer__contact {
    margin-top: var(--s-4);
}
/* FOLLOW column — one channel per row (icon + visible label), never an
   accordion. Rows stack via the base .site-footer__col ul column-flex rule;
   glyphs inherit ink via currentColor and shift to accent together with the
   label on hover (colour/hover come from .site-footer__col a). Focus uses
   the UA default ring like every other footer link. */
.site-footer__social-link {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
}
.site-footer__social-link svg {
    width: 22px;
    height: 22px;
    display: block;
    flex: 0 0 auto;
    border-radius: 2px;
}

/* STATEMENT TIER — pledge left, parent-company mark right. Two tiers
   instead of one because these carry meaning and the row below is
   boilerplate: a 1 %-of-revenue commitment chained to a © notice with
   a `·` reads as legal filler and stops being read. Baseline-aligned so
   the lead-in text sits on the pledge's baseline; the mark is centred
   against that lead-in by its own flex context. */
.site-footer__statement {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-4) var(--s-6);
    justify-content: space-between;
    align-items: baseline;
    padding-top: var(--s-6);
}
/* Reading size, ink — this is a sentence, not a label.
   No width cap: it takes the room the ownership mark leaves, which holds
   it on one line on desktop instead of orphaning the last word. */
.site-footer__pledge {
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink);
}
/* No underline — the sentence reads as a statement first, link second.
   Hover shifts to accent; that is the whole affordance, deliberately quiet. */
.site-footer__pledge a {
    color: inherit;
    text-decoration: none;
    transition: color 160ms var(--ease);
}
.site-footer__pledge a:hover,
.site-footer__pledge a:focus-visible {
    color: var(--accent);
}
/* Ownership: lead-in + mark. The mark carries the parent's name, so the
   text never repeats it (see Footer.ss). Greyscale + 55% keeps the
   parent's orange out of a footer where every other logo is neutral —
   colour returns on hover, same contract as the partner band above. */
.site-footer__ownership {
    display: inline-flex;
    align-items: center;
    gap: var(--s-3);
    flex: 0 0 auto;
    font-size: 0.75rem;
    color: var(--ink-muted);
}
.site-footer__ownership-mark {
    display: inline-flex;
    align-items: center;
    line-height: 0;
}
.site-footer__ownership-mark img {
    height: 38px;
    width: auto;
    display: block;
    filter: grayscale(1);
    opacity: 0.55;
    transition: filter 160ms var(--ease), opacity 160ms var(--ease);
}
.site-footer__ownership-mark:hover img,
.site-footer__ownership-mark:focus-visible img {
    filter: grayscale(0);
    opacity: 1;
}

/* LEGAL MICROLINE — everything here is equal-weight boilerplate, so it
   is one size, one colour, one baseline. Own hairline above it so the
   statement tier reads as content and this as the footnote. */
.site-footer__base {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3) var(--s-5);
    justify-content: space-between;
    align-items: baseline;
    margin-top: var(--s-5);
    padding-top: var(--s-4);
    border-top: var(--rail-soft);
    font-size: 0.75rem;
    color: var(--ink-muted);
}
.site-footer__meta {
    margin: 0;
}
.site-footer__legal {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2) var(--s-5);
}
.site-footer__legal a,
.site-footer__legal .site-footer__legal-btn {
    color: var(--ink-muted);
    text-decoration: none;
}
.site-footer__legal a:hover,
.site-footer__legal .site-footer__legal-btn:hover { color: var(--accent); }

/* Mobile: stack both tiers. The mark drops below the pledge rather than
   shrinking further — at 30px it is already at its floor.
   align-items stays at the default `stretch`: with flex-start the column
   children shrink-wrap to max-content and the pledge sentence and legal
   nav shoot past the viewport instead of wrapping. */
@media (max-width: 720px) {
    .site-footer__statement {
        flex-direction: column;
        gap: var(--s-5);
    }
    .site-footer__pledge {
        font-size: 0.95rem;
    }
    .site-footer__base {
        flex-direction: column;
        gap: var(--s-4);
    }
}

@media (max-width: 900px) {
    .site-footer__grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--s-6);
    }
    .site-footer__col--brand { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
    .site-footer__grid { grid-template-columns: 1fr; }
}

/* ---------- FOOTER LINK COLUMNS — phone accordions -----------------
   Each link column is wrapped in <details class="site-footer__group">
   with the <h3> heading inside <summary>. Desktop must look identical
   to the old plain h3 + ul: summary acts as a transparent passthrough
   (display:contents) so the h3 sits exactly where it did. The <details>
   is authored `open` (see Footer.ss) so the ul shows natively on desktop
   AND with JS off (graceful baseline — every panel expanded, natively
   tappable). The marker triangle is suppressed everywhere; the +/- toggle
   affordance is added on phone only.

   Flash-free collapse: the phone-collapsed state is established by CSS at
   first paint, gated on .js (set render-blocking in Head.ss). Below 720px
   with JS, the ul is display:none by default — which overrides the `open`
   attribute's rendering — and revealed by [data-open] which phone-accordions.js
   toggles. So the page paints collapsed on the first frame; JS only adds
   interactivity, never mutates the painted layout (no expand→collapse CLS). */
.site-footer__group {
    margin: 0;
}
.site-footer__group-summary {
    list-style: none;
    cursor: default;
}
.site-footer__group-summary::-webkit-details-marker { display: none; }
.site-footer__group-summary::marker { content: ""; }
.site-footer__group-summary h3 { margin: 0 0 var(--s-4); }

/* Desktop (>=721px): transparent — column reads as h3 + ul, always open
   (the [open] attribute keeps the ul visible). */
@media (min-width: 721px) {
    .site-footer__group { display: contents; }
    .site-footer__group-summary { display: contents; }
    .site-footer__group > ul { display: flex; }
}

/* Phone (<=720px): collapsible. Summary is a real tappable row with a
   +/- toggle (+ collapsed, - open). */
@media (max-width: 720px) {
    .site-footer__group-summary {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--s-3);
        min-height: 44px;
        cursor: pointer;
        border-top: var(--rail-soft);
        padding: var(--s-2) 0;
    }
    .site-footer__group-summary h3 { margin: 0; }
    .site-footer__group-summary::after {
        content: "+";
        font-size: 1.1em;
        line-height: 1;
        color: var(--ink-soft);
        flex: 0 0 auto;
    }
    .site-footer__group-summary:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
    }
    .site-footer__group > ul { padding: var(--s-2) 0 var(--s-4); }

    /* With JS: collapsed by default (display:none overrides the `open`
       attribute so first paint is collapsed — no flash), revealed by
       [data-open] which the script toggles. The +/- mark tracks [data-open].
       Without JS (.js absent) this rule never matches, so the `open`
       attribute keeps the ul visible — graceful, natively tappable. */
    .js .site-footer__group > ul { display: none; }
    .js .site-footer__group[data-open] > ul { display: flex; }
    .js .site-footer__group[data-open] .site-footer__group-summary::after {
        content: "\2212"; /* − minus */
    }
}

/* Phone: the Follow column is not an accordion, so it has no <summary> row
   to carry the top hairline the collapsible columns get. Add a matching
   divider + tap-friendly spacing so it sits in the same stacked rhythm. */
@media (max-width: 720px) {
    .site-footer__col--follow {
        border-top: var(--rail-soft);
        padding-top: var(--s-3);
    }
    .site-footer__col--follow h3 {
        margin-bottom: var(--s-2);
    }
}

/* ---------- NEWSLETTER ---------------------------------------------
   Both surfaces (footer row + Elemental block) share the contact-form
   visual vocabulary — underlined input, sentence-case label, accent
   submit with arrow — so the signup feels like part of the same site,
   not a bolted-on widget.

   Hide the honeypot reliably — must be position:absolute (not
   display:none) so well-behaved bots still fill it. */
.newsletter-form #Form_NewsletterForm_Website_Holder,
.newsletter-form input[name="Website"] { position: absolute; left: -9999px; }

/* SS6 wraps the whole form in <fieldset> with default UA chrome —
   neutralise it the same way .contact-form does. */
.newsletter-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.newsletter-form .clear { display: none; }

/* Suppress the empty error <p> SS6 always renders unless populated. */
.newsletter-form > .message[style*="display: none"] { display: none !important; }
.newsletter-form .message {
    padding: var(--s-3) var(--s-4);
    margin: 0 0 var(--s-4);
    border-left: 2px solid var(--accent-deep);
    background: var(--hairline-soft);
    font-family: var(--sans);
    font-size: 0.875rem;
    color: var(--ink);
}
.newsletter-form .message.bad { border-left-color: var(--accent); }

/* Shared field treatment — underlined input, sentence-case bold
   label. Matches .contact-form so editors / Daddy never see two form
   languages on the same site. */
.newsletter-form .field {
    margin-bottom: var(--s-5);
    display: flex;
    flex-direction: column;
}
.newsletter-form label.form-label,
.newsletter-form label {
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-soft);
    margin-bottom: var(--s-2);
}
.newsletter-form input[type="email"],
.newsletter-form input[type="text"] {
    font-family: var(--sans);
    font-size: 1rem;
    padding: var(--s-3) 0;
    border: none;
    border-bottom: 1px solid var(--hairline);
    background: transparent;
    color: var(--ink);
    width: 100%;
    border-radius: 0;
    transition: border-color 150ms ease;
}
.newsletter-form input[type="email"]:focus,
.newsletter-form input[type="text"]:focus {
    outline: none;
    border-bottom-color: var(--ink);
}
.newsletter-form input::placeholder { color: var(--ink-muted); }

/* Explicit consent row (inline variant only). Checkbox on the left,
   single-line label on the right, slightly smaller type. */
.newsletter-form .field.checkbox {
    flex-direction: row;
    gap: var(--s-3);
    align-items: flex-start;
    padding-top: var(--s-3);
    margin-bottom: var(--s-5);
}
.newsletter-form .field.checkbox input { margin-top: 0.3rem; accent-color: var(--accent); }
.newsletter-form .field.checkbox label {
    font-family: var(--sans);
    font-size: 0.85rem;
    text-transform: none;
    letter-spacing: 0;
    color: var(--ink-soft);
    margin: 0;
    text-align: left; /* override SS .right on checkbox labels */
}

/* Submit — accent rectangle with arrow glyph, exactly like the RFP
   "Send brief →". Keeps the form actions cohesive site-wide. */
.newsletter-form .Actions,
.newsletter-form .btn-toolbar { margin-top: var(--s-4); }
.newsletter-form button[type="submit"],
.newsletter-form input[type="submit"] {
    font-family: var(--sans);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    padding: var(--s-3) var(--s-7);
    background: var(--accent);
    color: var(--accent-ink);
    border: none;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background 200ms ease, transform 180ms var(--ease);
}
.newsletter-form button[type="submit"]:hover,
.newsletter-form input[type="submit"]:hover {
    background: var(--accent-deep);
    transform: translateY(-1px);
}
.newsletter-form .btn-with-arrow::after {
    content: " →";
    display: inline-block;
    margin-left: 0.4em;
    transition: transform 180ms var(--ease);
}
.newsletter-form .btn-with-arrow:hover::after { transform: translateX(2px); }

/* Field-level validation output from SS */
.newsletter-form .field .error,
.newsletter-form .field .validation {
    font-size: 0.85rem;
    color: var(--accent);
    margin-top: var(--s-2);
}

/* ===== Footer variant — single inline row =========================== */

/* One sand card binding pitch + form into a single cohesive object,
   spanning the standard content width (parent .site-footer__inner is
   already capped at --maxw + gutter padding). Two columns inside:
   pitch on the left, form on the right, both sharing the sand surface
   so they read as one unit rather than two detached islands on
   different surfaces. */

/* Pre-footer trust band — passive credibility, site-wide.
   Three labelled sub-rows: partners, certifications, initiatives.
   Each row gets a small uppercase Helvetica label above a centered
   chip row; hairline separators between rows; whole band closes
   with a hairline before the footer column grid. */
/* Ambient pre-footer trust strip — partner memberships only, no label,
   no row frame. Monochrome + low opacity so the row reads as background
   texture; hover restores colour for the small cohort that knows what
   the logos mean. See Footer.ss + MembershipsFooter.ss for the
   destination strategy decided 2026-05-27. */
.site-footer__trust {
    padding: var(--s-5) 0;
    border-bottom: 1px solid var(--hairline);
    margin-bottom: var(--s-7);
}
.site-footer__trust-row {
    justify-content: center;
    gap: var(--s-5) var(--s-6);
    margin: 0;
    padding: 0;
    list-style: none;
}
.site-footer__trust .cert-chip {
    display: inline-flex;
    align-items: center;
}
.site-footer__trust .cert-chip img {
    height: 40px;
    width: auto;
    max-width: 180px;
    filter: grayscale(1);
    opacity: 0.75;
    transition: filter 200ms var(--ease), opacity 200ms var(--ease);
}
.site-footer__trust .cert-chip:hover img,
.site-footer__trust .cert-chip a:focus-visible img {
    filter: grayscale(0);
    opacity: 1;
}
.site-footer__trust .cert-chip--text {
    font-size: 13px;
    color: var(--ink-muted);
    gap: var(--s-2);
}

/* Newsletter entry — lives in the FOLLOW column as one more channel next
   to the social icons. The trigger is a <button> reset to the column-link
   look (ink, hover accent — mirrors .site-footer__col a); the form lives
   in #newsletter-modal (enquiry modal shell above). id="newsletter" is the
   no-JS redirect anchor; the thanks line replaces the trigger after the
   ?subscribed=1 fallback. */
.site-footer__newsletter {
    /* Matches the s-2 row gap of the social list above so all three
       channel rows share one rhythm. */
    margin-top: var(--s-2);
}
.site-footer__newsletter-link {
    /* Strip every trace of button chrome so it is indistinguishable from
       the .site-footer__col a text links around it — no custom focus ring
       either (the other links use the UA default, so this one does too). */
    appearance: none;
    -webkit-appearance: none;
    padding: 0;
    background: none;
    border: none;
    font: inherit;
    text-align: left;
    color: var(--ink);
    cursor: pointer;
    /* Envelope glyph before the label — inherits currentColor so icon and
       text shift to accent together on hover. */
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
}
.site-footer__newsletter-link svg { display: block; flex: 0 0 auto; }
.site-footer__newsletter-link:hover { color: var(--accent); }
.site-footer__newsletter-thanks {
    margin: 0;
    font-family: var(--serif);
    font-style: italic;
    font-size: 0.95rem;
    color: var(--ink-soft);
}
/* Without JS the dialog can never open — hide the dead trigger. Head.ss
   sets .js on <html> inline before first paint. */
html:not(.js) .site-footer__newsletter-link { display: none; }

@media (max-width: 600px) {
    /* Trust / affiliation logo strip: the base 28px (--s-5) top padding
       reads as too much on phones. Trim the top only — bottom padding and
       the desktop band stay as-is. */
    .site-footer__trust {
        padding-top: var(--s-3);
    }
}

/* ===== Block variant — full surface with pitch + form ============== */

.newsletter-block {
    /* Sand band bleeds to viewport edges even when a maxw parent (main, page)
       would normally constrain it. Inner stays at maxw via __inner. */
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    padding: 0 var(--gutter) var(--s-10);
    background: var(--bg-soft);
    border-bottom: 1px solid var(--rule-band);
}
.newsletter-block__inner {
    max-width: var(--maxw);
    margin: 0 auto;
    /* No padding-top: that s-9 band held flow space under the old
       absolutely-anchored eyebrow; the eyebrow is in flow above now. */
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: var(--s-9);
    align-items: start;
}
.newsletter-block__eyebrow {
    margin: 0 0 var(--s-4);
}
.newsletter-block__title {
    font-family: var(--serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.9rem, 3vw, 2.6rem);
    line-height: 1.15;
    letter-spacing: -0.01em;
    margin: 0 0 var(--s-5);
    color: var(--ink);
}
.newsletter-block__lead {
    color: var(--ink-soft);
    font-size: 1rem;
    line-height: var(--lh-body);
}
.newsletter-block__lead p { margin: 0 0 var(--s-3); }
.newsletter-block__lead p:last-child { margin-bottom: 0; }
.newsletter-block__fineprint {
    margin: var(--s-6) 0 0;
    font-family: var(--sans);
    font-size: 0.85rem;
    color: var(--ink-muted);
    padding-top: var(--s-5);
    border-top: 1px solid var(--hairline);
}
.newsletter-block__fineprint a {
    color: var(--ink-soft);
    text-decoration: none;
    border-bottom: 1px solid var(--hairline);
}
.newsletter-block__fineprint a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* The form surface inside the block — quiet card on bg-elev to lift
   the form off the sand background, no shadow per Daddy's brief
   (clean, minimal, no heavy shadow). Generous interior padding so the
   underlined inputs have room to breathe. */
.newsletter-block__form {
    background: var(--bg-elev);
    border-radius: var(--r-lg);
    padding: var(--s-7);
}
.newsletter-block__thanks-title {
    font-family: var(--serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.4rem, 2vw, 1.7rem);
    line-height: 1.2;
    margin: 0 0 var(--s-3);
    color: var(--ink);
}
.newsletter-block__thanks-lead {
    margin: 0;
    color: var(--ink-soft);
    line-height: var(--lh-body);
    font-size: 0.95rem;
}

@media (max-width: 900px) {
    .newsletter-block { padding: 0 var(--gutter) var(--s-8); }
    .newsletter-block__inner {
        padding-top: var(--s-7);
        grid-template-columns: 1fr;
        gap: var(--s-7);
    }
    .newsletter-block__form { padding: var(--s-6); }
}

/* ---------- Responsive nav (very basic) ---------------------------- */

@media (max-width: 800px) {
    .site-header__inner {
        flex-wrap: wrap;
        gap: var(--s-4);
    }
    .site-locale { justify-content: center; }
}

/* ---------- SERVICES PILLAR (five service-line cards) ---------------- */
/* Editorial photo-led tiles. Same vocabulary as .sister-brands__card:
   no card chrome, photo-driven, sans bold title + serif description,
   small-caps CTA. 3+2 layout (last row left-aligned, trailing cell empty). */

.services-pillar { margin: 0 0 var(--s-10); }
.home-services__head {
    margin: 0 0 var(--s-7);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    align-items: flex-start;
}
.home-services__title {
    font-family: var(--sans);
    font-weight: 700;
    /* size owned by .h--display (--t-section); don't set font-size here */
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.service-tiles {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-6);
    align-items: stretch;
    justify-items: stretch;
}
/* Below 900px the 3-col grid switches to a horizontal scroll-snap rail.
   Bleeds to the viewport edge with negative margins so the first card
   sits flush with the rest of the page's column, and a sliver of the
   next card hints at scrollability. */
@media (max-width: 900px) {
    .service-tiles {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: 64%;
        gap: var(--s-5);
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scroll-padding-left: var(--gutter);
        margin-inline: calc(-1 * var(--gutter));
        padding: 0 var(--gutter) var(--s-4);
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .service-tiles::-webkit-scrollbar { display: none; }
}
@media (max-width: 540px) {
    .service-tiles { grid-auto-columns: 82%; gap: var(--s-4); }
}
.service-tile { margin: 0; display: flex; scroll-snap-align: start; }
.service-tile__link {
    display: flex;
    flex-direction: column;
    width: 100%;
    text-decoration: none;
    color: inherit;
}

.service-tile__photo {
    margin: 0;
    aspect-ratio: 8 / 5;
    overflow: hidden;
    background: var(--bg-soft);
    position: relative;
}
.service-tile__photo-img {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* No-photo fallback (ServicesPage pillar grid) — when a ServicePage has no
   hero image, drop the empty bone frame and render as a text card. Remove
   once every ServicePage carries a hero image. */
.service-tile--no-photo .service-tile__photo { display: none; }
.service-tile--no-photo .service-tile__body { padding-top: 0; }

.service-tile__icon-wrap {
    width: 56px;
    height: 56px;
    border-radius: 999px;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink);
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
.service-tile__icon { display: block; }

/* Title sits below the photo, flush with the image edge — same rhythm as
   .team-card__body. The hover underline wipe on the title comes from the
   site-wide headline-in-link rule (a :is(h1,h2,h3,h4) at the top of this
   file); no per-component hover CSS needed. */
.service-tile__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-2);
    flex: 1 1 auto;
    padding: var(--s-4) 0 0;
}
.service-tile__thesis {
    font-style: normal;
    color: var(--ink-soft);
    margin: 0;
}
/* Small-caps "Read more" line under the thesis — same vocabulary as
   article-card__more / sister-brand link affordances. */
.service-tile__more {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-top: var(--s-3);
    display: inline-block;
    transition: color 200ms var(--ease);
}
.service-tile__link:hover .service-tile__more { color: var(--ink); }

/* ---------- SERVICE SIBLING RAIL (foot of operational service pages) --
   "Services in {Destination}" — reuses the .service-tiles grid above so
   the foot rail reads as the same family as the destination service
   strip. Separated from the page body by a hairline + generous space. */
.service-rail {
    margin-top: var(--s-10);
    padding-top: var(--s-8);
    border-top: 1px solid var(--hairline);
}
.service-rail__head { margin-bottom: var(--s-6); }
.service-rail__title { margin: 0; }
/* The tile for the page you're already on: an accent ring marks "you are
   here", the pointer reverts (it links to self), and the hover lift is
   suppressed so it reads as a static marker, not a destination. */
.service-tile.is-current .service-tile__link { cursor: default; }
.service-tile.is-current .service-tile__photo {
    box-shadow: inset 0 0 0 2px var(--accent);
}

/* Pillar grid wrapper — generous breathing room above the tiles when
   the page chrome above is the editorial page__head fallback. When a
   leading ElementHero precedes the grid, page--has-hero compresses
   that gap so the hero sits cleanly above the inventory. */
.services-pillar__grid { margin-top: var(--s-9); }
.services-pillar.page--has-hero .services-pillar__grid { margin-top: var(--s-8); }

/* ---------- SERVICE PAGE (single service-line root) ------------------ */

.service { margin: 0 0 var(--s-10); }
.service__thesis {
    font-family: var(--serif);
    font-weight: 400;
    font-style: italic;
    font-size: var(--t-h2);
    line-height: 1.15;
    color: var(--ink-soft);
    margin: 0;
    max-width: var(--maxw-text);
}
.service__lead {
    max-width: var(--maxw-text);
    margin: 0 0 var(--s-9);
    font-size: var(--t-body-lg);
}
/* Two-column lead — same 1fr/2fr family as .lxp-grid--split on the
   destination sub-pages: the "So arbeiten wir" card (ExtraClass `card`
   on the second ElementContent block) becomes the left rail, the thesis
   copy runs beside it instead of both stacking in a half-width column.
   Collapses at the same 900px boundary as .lxp-grid. */
@media (min-width: 901px) {
    .service__lead {
        max-width: none;
        display: grid;
        grid-template-columns: 1fr 2fr;
        gap: var(--gap, var(--gap-l));
        align-items: start;
    }
    .service__lead > .card { order: -1; }
}
.service__how, .service__where {
    margin: var(--s-9) 0;
    padding-top: var(--s-7);
    border-top: 1px solid var(--hairline);
}
.service__section-title {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-muted);
    font-weight: 500;
    margin: 0 0 var(--s-5);
}

.service-destinations {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-5);
}
@media (max-width: 900px) { .service-destinations { grid-template-columns: 1fr 1fr; } }
@media (max-width: 540px) { .service-destinations { grid-template-columns: 1fr; } }
.service-destination { margin: 0; }
.service-destination__link {
    display: block;
    padding: var(--s-5) 0;
    border-top: 1px solid var(--ink);
    text-decoration: none;
    color: inherit;
    transition: opacity 200ms var(--ease);
}
.service-destination__link:hover { opacity: 0.75; }
.service-destination__region {
    font-family: var(--sans);
    font-size: 0.7rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin: 0 0 var(--s-2);
    font-weight: 500;
}
.service-destination__title {
    font-family: var(--sans);
    font-weight: 400;
    font-size: var(--t-h2);
    line-height: 1.15;
    margin: 0 0 var(--s-3);
    color: var(--ink);
}
.service-destination__pitch {
    color: var(--ink-soft);
    margin: 0;
}

/* Photo-led variant of the destination card. When DestinationTiles()
   resolved a HeroImage from the linked DMCPage we render the figure
   ABOVE the text block; the photo leads with the body sitting directly
   beneath it (no hairline divider) to match the site's other photo-led
   cards (article, case-study, team). Card stays text-only when no image. */
.service-destination__link:has(.service-destination__photo) {
    padding: 0;
    border-top: 0;
}
.service-destination__photo {
    margin: 0;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--bg-soft);
}
.service-destination__photo-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 400ms var(--ease);
}
.service-destination__link:hover .service-destination__photo-img { transform: scale(1.02); }
.service-destination__link:has(.service-destination__photo) .service-destination__body {
    padding: var(--s-4) 0 0;
}
.service-destination__link:has(.service-destination__photo) .service-destination__title {
    font-size: 1.4rem;
    line-height: 1.18;
}



/* =============================================================
   DESIGN SYSTEM PAGE  ( /design-system/* )
   All rules scoped under .ds-page so this scaffolding cannot
   leak onto regular site pages. Live tokens.css + app.css are
   the source of truth — these are doc-page utilities only.
   ============================================================= */

.ds-page { display: block; }

/* ---------- TOC SUBNAV ---------- */
.ds-toc {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(247, 244, 238, 0.92);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--hairline);
    margin-bottom: var(--s-7);
}
.ds-toc__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-5);
    height: 56px;
}
.ds-toc__brand {
    text-decoration: none;
    color: var(--ink);
    white-space: nowrap;
}
.ds-toc__links {
    display: flex;
    gap: 2px;
    flex-wrap: wrap;
}
.ds-toc__link {
    padding: 8px 12px;
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink-soft);
    text-decoration: none;
    border-radius: var(--r-sm);
    transition: color 140ms var(--ease), background 140ms var(--ease);
}
.ds-toc__link:hover { color: var(--ink); }
.ds-toc__link.is-current {
    color: var(--ink);
    background: var(--stone-100);
}
@media (max-width: 720px) {
    .ds-toc__row { height: auto; padding: var(--s-3) 0; flex-wrap: wrap; }
    .ds-toc__brand { width: 100%; }
}

.ds-page__body {
    padding-bottom: var(--s-10);
}

/* ---------- SHARED LAYOUT HELPERS ---------- */
.ds-page .ds-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-5); }
.ds-page .ds-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); }
@media (max-width: 800px) {
    .ds-page .ds-grid-2,
    .ds-page .ds-grid-3 { grid-template-columns: 1fr; }
}

/* ---------- OVERVIEW HERO (DesignSystemHero) ---------- */
.ds-page .ds-overview-hero {
    padding: var(--s-9) 0 var(--s-8);
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-8);
    align-items: end;
    border-bottom: 1px solid var(--hairline);
}
.ds-page .ds-overview-hero__photos {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-3);
}
.ds-page .ds-overview-hero__photos > *:nth-child(2) {
    margin-top: var(--s-7);
}
@media (max-width: 800px) {
    .ds-page .ds-overview-hero { grid-template-columns: 1fr; }
}

.ds-page .ds-direction-card {
    padding: var(--s-6);
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
}
.ds-page .ds-direction-card__swatches {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.ds-page .ds-direction-card__swatches > div {
    aspect-ratio: 1;
    border-radius: var(--r-sm);
}

.ds-page .ds-principles {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--s-7) var(--s-8);
}
@media (max-width: 720px) {
    .ds-page .ds-principles { grid-template-columns: 1fr; }
}

.ds-page .ds-map {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--s-4);
}
.ds-page .ds-map__card {
    padding: var(--s-6);
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}
.ds-page .ds-map__open { margin-top: auto; }
@media (max-width: 720px) {
    .ds-page .ds-map { grid-template-columns: 1fr; }
}

/* ---------- FOUNDATIONS (DesignSystemFoundations) ---------- */
.ds-page .colorRamp {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    gap: 4px;
}
.ds-page .colorRamp .step {
    aspect-ratio: 1;
    border-radius: 3px;
    position: relative;
}
.ds-page .colorRamp .step span {
    position: absolute;
    bottom: 4px;
    left: 6px;
    font-family: var(--sans);
    font-size: 9px;
    letter-spacing: 0.06em;
    color: rgba(255, 255, 255, 0.85);
}
.ds-page .colorRamp .step.dark span { color: rgba(0, 0, 0, 0.6); }

.ds-page .ds-direction-stack {
    display: flex;
    flex-direction: column;
    gap: var(--s-7);
}

.ds-page .ds-token-swatch {
    width: 28px;
    height: 28px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: 4px;
}

.ds-page .typeRow {
    display: grid;
    grid-template-columns: 180px 1fr 120px;
    align-items: baseline;
    gap: var(--s-5);
    padding: var(--s-4) 0;
    border-bottom: 1px solid var(--hairline);
}
.ds-page .typeRow .meta {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.ds-page .typeRow .num {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    color: var(--ink-muted);
    text-align: right;
}
@media (max-width: 800px) {
    .ds-page .typeRow {
        grid-template-columns: 1fr;
        gap: var(--s-2);
    }
    .ds-page .typeRow .num { text-align: left; }
}

.ds-page .spaceRow {
    display: grid;
    grid-template-columns: 80px 80px 1fr;
    align-items: center;
    gap: var(--s-4);
    padding: 10px 0;
    border-bottom: 1px solid var(--hairline);
    font-family: var(--sans);
    font-size: 13px;
}
.ds-page .spaceRow code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    background: var(--stone-100);
    padding: 2px 6px;
    border-radius: 3px;
}
.ds-page .spaceBar {
    height: 16px;
    background: var(--accent-soft);
    border-radius: 2px;
}

.ds-page .ds-radius-row {
    display: flex;
    gap: var(--s-6);
    align-items: flex-end;
    flex-wrap: wrap;
}
.ds-page .ds-radius-row .t-micro { margin-top: 8px; }
.ds-page .radiusDemo {
    width: 64px;
    height: 64px;
    background: var(--ink);
    display: inline-block;
}

.ds-page .ds-shadow-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-5);
}
.ds-page .shadowDemo {
    width: 100%;
    aspect-ratio: 16 / 9;
    background: var(--surface);
    border-radius: var(--r-md);
    display: grid;
    place-items: center;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    color: var(--ink-muted);
}
.ds-page .ds-shadow-grid .t-micro { margin-top: 8px; }
@media (max-width: 720px) {
    .ds-page .ds-shadow-grid { grid-template-columns: repeat(2, 1fr); }
}

.ds-page .gridCols {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--s-4);
    height: 80px;
}
.ds-page .gridCols > div {
    background: var(--accent-soft);
    border-radius: 2px;
}

/* ---------- COMPONENTS (DesignSystemComponents) ---------- */
.ds-page .compo {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: var(--s-7);
    padding: var(--s-7) 0;
    border-bottom: 1px solid var(--hairline);
}
.ds-page .compo h3 {
    font-family: var(--sans);
    font-size: 24px;
    margin: 0 0 8px;
}
.ds-page .compo .meta {
    font-family: var(--sans);
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.ds-page .compo .desc {
    font-size: 14px;
    color: var(--ink-soft);
    margin-top: 8px;
    line-height: 1.55;
}
@media (max-width: 800px) {
    .ds-page .compo { grid-template-columns: 1fr; }
}

.ds-page .demo {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    padding: var(--s-6);
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
}
.ds-page .demo + .demo { margin-top: var(--s-3); }
.ds-page .demo .row {
    display: flex;
    gap: var(--s-3);
    align-items: center;
    flex-wrap: wrap;
    margin: 0;
}
.ds-page .demo .label {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-bottom: 6px;
}

.ds-page .ds-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-4);
}
@media (max-width: 600px) {
    .ds-page .ds-form-grid { grid-template-columns: 1fr; }
    .ds-page .ds-form-grid > .field[style*="span 2"] { grid-column: auto !important; }
}

.ds-page .ds-radio-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-3);
    width: 100%;
}
.ds-page .ds-radio {
    display: flex;
    gap: 10px;
    align-items: center;
    padding: 14px;
    border: 1px solid var(--hairline);
    border-radius: var(--r-sm);
    cursor: pointer;
    font-family: var(--sans);
    font-size: 14px;
}
.ds-page .ds-radio.is-on {
    border-color: var(--accent);
    background: var(--accent-faint);
}
.ds-page .ds-radio__mark {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--stone-300);
    background: transparent;
    flex-shrink: 0;
}
.ds-page .ds-radio__mark.is-on {
    border: 4px solid var(--accent);
    background: var(--surface);
}
@media (max-width: 600px) {
    .ds-page .ds-radio-row { grid-template-columns: 1fr; }
}

.ds-page .ds-checkbox {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}
.ds-page .ds-checkbox__box {
    width: 18px;
    height: 18px;
    border: 1px solid var(--accent);
    background: var(--accent);
    border-radius: 3px;
    display: grid;
    place-items: center;
    margin-top: 2px;
    flex-shrink: 0;
}

.ds-page .ds-card-service {
    padding: var(--s-6);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}
.ds-page .ds-card-destination {
    display: flex;
    flex-direction: column;
}
.ds-page .ds-card-destination__body { padding: var(--s-5); }
.ds-page .ds-card-activity {
    display: flex;
    overflow: hidden;
}
.ds-page .ds-card-activity__photo {
    width: 96px;
    flex-shrink: 0;
    background: var(--stone-100);
}
.ds-page .ds-card-activity__photo .photo {
    border-radius: 0;
    height: 100%;
}
.ds-page .ds-card-activity__body {
    padding: var(--s-4);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.ds-page .ds-card-activity__title {
    font-family: var(--sans);
    font-size: 17px;
    margin: 0;
}

.ds-page .ds-stat-row { gap: var(--s-7); }
.ds-page .ds-stat {
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.ds-page .ds-stat__num {
    font-family: var(--sans);
    font-size: 44px;
    line-height: 1;
}
.ds-page .ds-stat__plus {
    font-size: 22px;
    vertical-align: top;
}

.ds-page .ds-faq {
    border-bottom: 1px solid var(--hairline);
    padding: var(--s-5) var(--s-6);
}
.ds-page .ds-faq.ds-faq--last { border-bottom: 0; }
.ds-page .ds-faq summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: var(--sans);
    font-size: 22px;
    cursor: pointer;
    list-style: none;
}
.ds-page .ds-faq summary::-webkit-details-marker { display: none; }
.ds-page .ds-faq__sign {
    font-family: var(--sans);
    font-size: 28px;
    font-weight: 300;
    color: var(--ink-muted);
}

.ds-page .ds-testimonial-quote {
    margin: 0;
    font-family: var(--sans);
    font-size: 32px;
    line-height: 1.3;
    letter-spacing: -0.01em;
}
.ds-page .ds-testimonial-source {
    display: flex;
    gap: var(--s-3);
    align-items: center;
    margin-top: var(--s-5);
    font-family: var(--sans);
}
.ds-page .ds-testimonial-source__avatar {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--stone-200);
    border: 1px solid var(--hairline);
}

/* ---------- PATTERNS (DesignSystemPatterns) ---------- */
.ds-page .ds-pattern-section { margin: var(--s-7) 0; }

.ds-page .patternFrame {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    overflow: hidden;
}
.ds-page .patternHead {
    padding: var(--s-5) var(--s-6);
    border-bottom: 1px solid var(--hairline);
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-4);
    flex-wrap: wrap;
}
.ds-page .patternHead h3 {
    font-family: var(--sans);
    font-size: 24px;
    margin: 0;
}
.ds-page .patternHead .meta {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.ds-page .patternBody { padding: 0; }
.ds-page .patternBody.padded { padding: var(--s-7); }
.ds-page .patternNote {
    padding: var(--s-4) var(--s-6);
    background: var(--bg);
    border-top: 1px solid var(--hairline);
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink-soft);
    line-height: 1.55;
}

/* Hero pattern */
.ds-page .ds-hero-pattern {
    position: relative;
    aspect-ratio: 16 / 8;
    overflow: hidden;
}
.ds-page .ds-hero-pattern__bg { position: absolute; inset: 0; }
.ds-page .ds-hero-pattern__bg .photo { border-radius: 0; height: 100%; }
.ds-page .ds-hero-pattern__scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(15,14,10,0.32) 0%, rgba(15,14,10,0) 40%, rgba(15,14,10,0.55) 100%);
}
.ds-page .ds-hero-pattern__content {
    position: relative;
    height: 100%;
    padding: var(--s-7);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    color: #fff;
}
.ds-page .ds-hero-pattern__top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--s-4);
    flex-wrap: wrap;
}
.ds-page .ds-hero-pattern__eyebrow {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    opacity: 0.85;
}
.ds-page .ds-hero-pattern__tag { opacity: 0.85; color: inherit; }
.ds-page .ds-hero-pattern__title {
    font-family: var(--sans);
    font-size: clamp(36px, 5vw, 88px);
    line-height: 1.02;
    letter-spacing: -0.02em;
    margin: 0;
    max-width: 14ch;
    color: #fff;
}
.ds-page .ds-hero-pattern__lead {
    margin-top: var(--s-4);
    font-size: 19px;
    line-height: 1.55;
    opacity: 0.92;
    color: inherit;
}
.ds-page .ds-hero-pattern__cta {
    display: flex;
    gap: var(--s-3);
    margin-top: var(--s-5);
    align-items: center;
    flex-wrap: wrap;
}
.ds-page .ds-hero-pattern__inline {
    color: #fff;
    border-bottom-color: rgba(255, 255, 255, 0.6);
}

/* Trust bar */
.ds-page .ds-trust-row {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: var(--s-7);
    align-items: center;
}
.ds-page .ds-trust-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-5);
}
.ds-page .ds-trust-num {
    font-family: var(--sans);
    font-size: 44px;
    line-height: 1;
    letter-spacing: -0.01em;
}
.ds-page .ds-trust-plus {
    font-size: 22px;
    vertical-align: top;
}
.ds-page .ds-trust-certs {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    align-items: flex-start;
}
.ds-page .certRow {
    display: flex;
    gap: var(--s-2);
    flex-wrap: wrap;
    align-items: center;
}
.ds-page .certChip-bare {
    padding: 6px 12px;
    background: transparent;
    border: 1px solid var(--hairline);
    border-radius: 999px;
    font-family: var(--sans);
    font-size: 12px;
    color: var(--ink-soft);
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}
.ds-page .certChip-bare .badge-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    display: inline-block;
}
@media (max-width: 800px) {
    .ds-page .ds-trust-row { grid-template-columns: 1fr; }
    .ds-page .ds-trust-stats { grid-template-columns: repeat(2, 1fr); }
}

/* Destination grid */
.ds-page .ds-dest-grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    grid-template-rows: auto auto;
    gap: var(--s-4);
}
.ds-page .ds-dest-grid a {
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.ds-page .ds-dest-grid__hero {
    grid-row: span 2;
    gap: var(--s-3) !important;
}
.ds-page .ds-dest-grid__caption {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-4);
    flex-wrap: wrap;
}
.ds-page .ds-dest-grid__title-lg {
    font-family: var(--sans);
    font-size: 32px;
    margin: 4px 0 0;
    letter-spacing: -0.01em;
}
.ds-page .ds-dest-grid__caption-sm {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-3);
}
.ds-page .ds-dest-grid__caption-sm h4 {
    font-family: var(--sans);
    font-size: 22px;
    margin: 0;
}
@media (max-width: 800px) {
    .ds-page .ds-dest-grid {
        grid-template-columns: 1fr;
        grid-template-rows: auto;
    }
    .ds-page .ds-dest-grid__hero { grid-row: auto; }
}

/* Case study */
.ds-page .ds-case-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-4);
    margin-bottom: var(--s-7);
}
.ds-page .ds-case-card { display: flex; flex-direction: column; }
.ds-page .ds-case-card__body {
    padding: var(--s-5);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}
.ds-page .ds-case-card__top {
    display: flex;
    justify-content: space-between;
    gap: var(--s-3);
}
.ds-page .ds-case-card__title {
    font-family: var(--sans);
    font-size: 24px;
    margin: 0;
    line-height: 1.18;
}
.ds-page .ds-case-card__specs {
    display: flex;
    gap: var(--s-3);
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink-soft);
    padding-top: var(--s-3);
    border-top: 1px solid var(--hairline);
    flex-wrap: wrap;
}

.ds-page .ds-case-expanded {
    background: var(--bg-elev);
    border-radius: var(--r-md);
    padding: var(--s-7);
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: var(--s-7);
    align-items: start;
}
.ds-page .ds-case-expanded__title {
    font-family: var(--sans);
    font-size: clamp(28px, 3.4vw, 44px);
    line-height: 1.1;
    letter-spacing: -0.018em;
    margin: var(--s-3) 0 0;
}
.ds-page .ds-case-expanded__stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-5);
    margin-top: var(--s-6);
    padding-top: var(--s-5);
    border-top: 1px solid var(--hairline);
}
.ds-page .ds-case-expanded__num {
    font-family: var(--sans);
    font-size: 32px;
    line-height: 1;
}
@media (max-width: 800px) {
    .ds-page .ds-case-grid { grid-template-columns: 1fr; }
    .ds-page .ds-case-expanded { grid-template-columns: 1fr; }
}

/* RFP form */
.ds-page .ds-rfp {
    background: var(--accent-deep);
    color: #fff;
}
.ds-page .ds-rfp__cols {
    display: grid;
    grid-template-columns: 1fr 1.2fr;
    gap: var(--s-7);
}
.ds-page .ds-rfp__step { color: rgba(255, 255, 255, 0.7); }
.ds-page .ds-rfp__title {
    font-family: var(--sans);
    font-size: clamp(28px, 3.4vw, 44px);
    line-height: 1.08;
    letter-spacing: -0.018em;
    margin: var(--s-3) 0 0;
    color: #fff;
}
.ds-page .ds-rfp__lead {
    margin-top: var(--s-5);
    color: rgba(255, 255, 255, 0.78);
    font-size: 17px;
    line-height: 1.6;
}
.ds-page .ds-rfp__steps {
    margin-top: var(--s-7);
    padding-top: var(--s-5);
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    font-family: var(--sans);
}
.ds-page .ds-rfp__step-row {
    display: flex;
    gap: var(--s-3);
    font-size: 14px;
}
.ds-page .ds-rfp__step-num {
    color: rgba(255, 255, 255, 0.5);
    font-family: var(--sans);
    width: 22px;
}
.ds-page .ds-rfp__form {
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
    background: var(--surface);
    color: var(--ink);
    padding: var(--s-6);
    border-radius: var(--r-md);
}
.ds-page .ds-rfp__form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-3);
}
.ds-page .ds-rfp__chips {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}
@media (max-width: 800px) {
    .ds-page .ds-rfp__cols { grid-template-columns: 1fr; }
    .ds-page .ds-rfp__chips { grid-template-columns: repeat(2, 1fr); }
}

/* Process strip */
.ds-page .ds-process {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--s-4);
    position: relative;
}
.ds-page .ds-process__line {
    position: absolute;
    top: 14px;
    left: 8%;
    right: 8%;
    height: 1px;
    background: var(--hairline);
}
.ds-page .ds-process__step { position: relative; }
.ds-page .ds-process__num {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--ink);
    color: var(--ink);
    display: grid;
    place-items: center;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 500;
    position: relative;
    z-index: 1;
}
.ds-page .ds-process__num.is-current {
    background: var(--accent);
    color: var(--accent-ink);
    border-color: transparent;
}
.ds-page .ds-process__step h4 {
    font-family: var(--sans);
    font-size: 20px;
    margin: var(--s-3) 0 6px;
}
.ds-page .ds-process__step p { margin: 0; }
@media (max-width: 800px) {
    .ds-page .ds-process { grid-template-columns: repeat(2, 1fr); }
    .ds-page .ds-process__line { display: none; }
}

/* ---------- PHOTOGRAPHY (DesignSystemPhotography) ---------- */
.ds-page .ds-subject-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 1fr;
    gap: var(--s-3);
}
@media (max-width: 800px) {
    .ds-page .ds-subject-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    .ds-page .ds-subject-grid { grid-template-columns: 1fr; }
}

.ds-page .ds-ratio-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--s-3);
}
.ds-page .ratioBox {
    aspect-ratio: var(--ratio);
    border: 1px dashed var(--stone-300);
    border-radius: 4px;
    display: grid;
    place-items: center;
    color: var(--ink-muted);
    font-family: var(--sans);
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}
@media (max-width: 800px) {
    .ds-page .ds-ratio-grid { grid-template-columns: repeat(2, 1fr); }
}

.ds-page .doDont {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-5);
}
.ds-page .ddCol {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}
.ds-page .ddCol .head {
    display: flex;
    gap: 10px;
    align-items: center;
    padding-bottom: var(--s-3);
    border-bottom: 1px solid var(--hairline);
}
.ds-page .pill {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 999px;
}
.ds-page .pillDo {
    background: var(--accent-faint);
    color: var(--accent);
    border: 1px solid var(--accent-soft);
}
.ds-page .pillDont {
    background: #f8eeea;
    color: #8b3a26;
    border: 1px solid #f0d4cb;
}
@media (max-width: 720px) {
    .ds-page .doDont { grid-template-columns: 1fr; }
}

/* ---------- TWEAKS PANEL (mounted by ds-init.js) ---------- */
.ds-tweaks {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 100;
    width: 280px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-3);
    font-family: var(--sans);
    font-size: 13px;
    overflow: hidden;
}
.ds-tweaks__head {
    padding: 12px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--hairline);
}
.ds-tweaks__head h4 {
    margin: 0;
    font-family: var(--sans);
    font-size: 18px;
}
.ds-tweaks__close {
    font-size: 20px;
    color: var(--ink-muted);
    line-height: 1;
}
.ds-tweaks__body {
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.ds-tweaks__row {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.ds-tweaks__label {
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.ds-tweaks__seg {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    border: 1px solid var(--hairline);
    border-radius: var(--r-sm);
    overflow: hidden;
}
.ds-tweaks__seg button {
    padding: 8px 6px;
    font-size: 12px;
    color: var(--ink-soft);
    background: var(--surface);
    border-right: 1px solid var(--hairline);
    transition: background 140ms var(--ease), color 140ms var(--ease);
}
.ds-tweaks__seg button:last-child { border-right: 0; }
.ds-tweaks__seg button.is-on {
    background: var(--ink);
    color: var(--bg);
}
.ds-tweaks-toggle {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 100;
    padding: 10px 16px;
    font-family: var(--sans);
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    background: var(--ink);
    color: var(--bg);
    border-radius: var(--r-pill);
    box-shadow: var(--shadow-3);
}

/* ---------- Micro-animations --------------------------------------- */
/* Three subtle motion treatments. JS toggles classes; CSS owns the
   transitions. */

/* 1. Image fade-in on load */
.img-fade { opacity: 0; transition: opacity 250ms ease; }
.img-fade.is-loaded { opacity: 1; }

/* 2. Section reveal on scroll (IntersectionObserver in microanim.js) */
.reveal-on-scroll {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 500ms ease, transform 500ms ease;
}
.reveal-on-scroll.is-revealed {
    opacity: 1;
    transform: none;
}

/* 3. Hero text stagger on first paint — eyebrow → title → subtitle */
@keyframes heroStaggerFade {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}
.element-hero__eyebrow,
.element-hero__title,
.element-hero__subtitle {
    animation: heroStaggerFade 600ms ease both;
}
.element-hero__eyebrow  { animation-delay:   0ms; }
.element-hero__title    { animation-delay:  80ms; }
.element-hero__subtitle { animation-delay: 160ms; }

/* ---------- PAGE CHILD DIRECTORY ------------------------------------
   Auto-rendered cards listing the current page's published in-menu
   children. Used on category-style pages whose children would otherwise
   be hidden from the DMC sub-nav (which only shows direct DMC children).
   See themes/lxp/templates/Includes/PageChildDirectory.ss. */
/* Child-page directory (services umbrella overview etc.). The tiles use
   the shared .service-tiles / .service-tile photo-card grid — identical to
   the foot ServiceSiblingRail — so the wrapper only owns vertical rhythm;
   <main> already provides the maxw + gutter rail (re-applying it here would
   double-pad the grid narrower than the sibling rail on sub-pages). */
.page-children {
    margin: var(--s-8) 0 var(--s-10);
}

/* ---------- Sister brands (homepage / cross-link) ------------------
   3-up teaser row pointing to sibling brands (LuxuryTravelSpain,
   HeliXperiences, YachtXperiences). Each card is a single anchor;
   image hover-zooms, the CTA arrow nudges right. Collapses to one
   column on mobile. */
.sister-brands {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-9) var(--gutter) var(--s-10);
}
.sister-brands__head {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    margin: 0 0 var(--s-7);
}
.sister-brands__title {
    font-family: var(--sans);
    font-weight: 700;
    /* size owned by .h--display (--t-section); don't set font-size here */
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.sister-brands__lead {
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.5;
    /* Body-sized, so it follows the 400 reading voice — the light 300 it
       inherits from the .lead group above is for lead-scale sizes only. */
    font-weight: 400;
    color: var(--ink-soft);
    margin: 0;
}
.sister-brands__grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-6);
}
.sister-brands__item { margin: 0; }
.sister-brands__card {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    height: 100%;
}
.sister-brands__photo {
    margin: 0;
    aspect-ratio: 8 / 5;
    overflow: hidden;
    background: var(--bg-soft);
}
.sister-brands__photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.sister-brands__body {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    flex: 1 1 auto;
    /* Top-only: text starts flush with the photo's left edge — same
       rhythm as .service-tile__body / .case-rail__body / .team-card__body. */
    padding: var(--s-4) 0 0;
}
.sister-brands__summary {
    /* Match the section intro (.sister-brands__lead): 400, 1rem/1.5 — so
       the card copy and the lead read as one consistent voice. */
    font-size: 1rem;
    line-height: 1.5;
    font-weight: 400;
    color: var(--ink-soft);
    margin: 0;
}
/* Below 900px the 3-col grid switches to a horizontal scroll-snap rail —
   identical behaviour to the .service-tiles "six disciplines" strip so the
   homepage reads consistently. Bleeds to the viewport edge with negative
   margins so the first card sits flush with the page column and a sliver of
   the next card hints at scrollability. Replaces the old single-column
   stack (was a long vertical scroll on phones pre-2026-06-05). */
@media (max-width: 900px) {
    .sister-brands__grid {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: 64%;
        gap: var(--s-5);
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scroll-padding-left: var(--gutter);
        margin-inline: calc(-1 * var(--gutter));
        padding: 0 var(--gutter) var(--s-4);
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .sister-brands__grid::-webkit-scrollbar { display: none; }
    /* Defensive overflow guard: keep the scroll-rail items + cards from
       forcing their auto-column wider than 64% on a long localized title
       (grid/flex children default to min-width:auto). overflow-wrap breaks
       any over-long word in the name/summary. The rail's overflow-x:auto
       already clips, so this is belt-and-suspenders. No visual change at
       normal content. (2026-06-05) */
    .sister-brands__item { scroll-snap-align: start; min-width: 0; }
    .sister-brands__card { min-width: 0; }
    .sister-brands__name,
    .sister-brands__summary { overflow-wrap: anywhere; }
}
@media (max-width: 540px) {
    .sister-brands__grid { grid-auto-columns: 82%; gap: var(--s-4); }
}

/* ---------- Why us — strict typographic / Bauhaus -----------------------
   Two distinct modes share the .why-us shell:

   1. STRICT TYPOGRAPHIC (homepage) — when the template renders a
      .why-us__list (reasons exist). Single rigorous hairline grid;
      metrics + reasons share one numeric sequence (00–09). No icons,
      no orange. Index on the left, content on the right.

   2. INTRO-ONLY (DMC pages) — when no reasons exist. Side-by-side
      narrative + stats via the .why-us--intro grid (ExtraClass on the
      outer .element wrapper from ElementHolder.ss, NOT on the .why-us
      section itself — scope from outer wrapper, never inner).
   ---------------------------------------------------------------------- */
.why-us {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-10) var(--gutter) var(--s-9);
}

/* ---- Mode 1: strict typographic (when reasons exist) ---- */
.why-us:has(.why-us__list) .why-us__head {
    padding-bottom: var(--s-6);
    margin-bottom: var(--s-7);
}
.why-us__cluster {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--ink-muted);
    margin: 0 0 var(--s-4);
}
.why-us:has(.why-us__list) .why-us__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-h1);
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--ink);
    margin: 0;
}
.why-us:has(.why-us__list) .why-us__title em {
    font-family: var(--sans);
    font-style: normal;
    font-weight: 300;
    color: var(--ink-muted);
}
.why-us:has(.why-us__list) .why-us__metrics {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 0;
    display: block;
    column-gap: 0;
    row-gap: 0;
    grid-template-columns: none;
}
.why-us:has(.why-us__list) .why-us__metric {
    display: grid;
    grid-template-columns: 1fr 4fr 7fr;
    column-gap: var(--s-7);
    align-items: center;
    padding: var(--s-6) 0;
    border-top: 1px solid var(--hairline);
    border-bottom: 0;
    margin: 0;
    text-align: left;
}
.why-us:has(.why-us__list) .why-us__metric:first-child {
    border-top: 1px solid var(--ink);
}
.why-us__metric-index,
.why-us__row-index {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(2rem, 3vw, 3rem);
    line-height: 0.95;
    letter-spacing: -0.022em;
    color: var(--ink);
    font-feature-settings: "tnum","lnum";
}
.why-us:has(.why-us__list) .why-us__metric-head {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}
.why-us:has(.why-us__list) .why-us__metric-label {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--ink-muted);
    line-height: 1.2;
    margin: 0;
    max-width: none;
}
.why-us:has(.why-us__list) .why-us__metric-num {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(1.25rem, 1.6vw, 1.625rem);
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    font-feature-settings: "tnum","lnum";
}
.why-us__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.why-us__row {
    display: grid;
    grid-template-columns: 1fr 4fr 7fr;
    column-gap: var(--s-7);
    align-items: center;
    padding: var(--s-6) 0;
    border-top: 1px solid var(--hairline);
    margin: 0;
}
.why-us__row-cat {
    font-family: var(--sans);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--ink-muted);
    margin: 0 0 var(--s-3);
}
.why-us__row-body {
    font-family: var(--sans);
    font-size: var(--t-body-lg);
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0;
    max-width: 64ch;
}
@media (max-width: 900px) {
    .why-us:has(.why-us__list) .why-us__metric {
        grid-template-columns: 1fr 4fr;
        row-gap: var(--s-2);
    }
    .why-us:has(.why-us__list) .why-us__metric-label {
        grid-column: 1 / -1;
        padding-top: var(--s-2);
    }
    .why-us__row {
        grid-template-columns: 1fr 11fr;
        row-gap: var(--s-3);
        padding: var(--s-5) 0;
    }
    .why-us__row-body { grid-column: 2 / -1; }
}
@media (max-width: 600px) {
    .why-us { padding: var(--s-9) var(--gutter) var(--s-8); }
}

/* ---- Mode 1 reasons — phone accordion -----------------------------
   Each reason row is wrapped in <details class="why-us__row-fold">; the
   index + head live in <summary>, the body is the collapsible panel.
   The <details> is authored `open` (see ElementWhyUs.ss) so the body
   shows on desktop AND with JS off (graceful baseline). Desktop (>=721px):
   the fold + summary are display:contents so index, head and body re-enter
   the existing .why-us__row grid (1fr 4fr 7fr, then 1fr 11fr <=900) exactly
   as before. The hairline grid look is preserved because .why-us__row still
   owns the grid + border-top.
   Phone (<=720px): summary becomes the visible 2-col row (index + head)
   with a +/- toggle. Flash-free collapse: gated on .js (set render-blocking in
   Head.ss), the body is display:none by default — overriding the `open`
   attribute so the page paints collapsed on the first frame — and revealed
   by [data-open], which phone-accordions.js toggles. JS only adds
   interactivity; it never mutates the painted layout (no expand→collapse
   CLS). Without JS the `open` attribute keeps the body visible. */
.why-us__row-fold { margin: 0; }
.why-us__row-summary { list-style: none; }
.why-us__row-summary::-webkit-details-marker { display: none; }
.why-us__row-summary::marker { content: ""; }

@media (min-width: 721px) {
    .why-us__row-fold,
    .why-us__row-summary { display: contents; }
    .why-us__row-fold > .why-us__row-body { display: block; }
}

@media (max-width: 720px) {
    /* The grid now lives on the summary (the always-visible row); the
       <li>/<details> are transparent so the body can drop below it. */
    .why-us__row { display: block; }
    /* Fixed index column (defined on the fold so both the summary grid and
       the body below it inherit it). A 1fr index column can't shrink below
       the 2-digit number's min-content (~35px at the 2rem index size), so
       the head column started ~10px further right than the body's
       (100%/12)-based indent assumed — the body sat short of the title.
       A known column width makes the title and body indents identical. */
    .why-us__row-fold { display: block; --why-idx-col: 2.5rem; }
    .why-us__row-summary {
        display: grid;
        grid-template-columns: var(--why-idx-col) 1fr;
        column-gap: var(--s-7);
        align-items: center;
        cursor: pointer;
        min-height: 44px;
        position: relative;
    }
    /* The +/- mark sits at the end of the head cell. */
    .why-us__row-summary .why-us__row-head {
        display: flex;
        flex-direction: column;
        gap: var(--s-3);
    }
    .why-us__row-summary::after {
        content: "+";
        position: absolute;
        right: 0;
        top: 50%;
        transform: translateY(-50%);
        font-size: 1.25rem;
        line-height: 1;
        color: var(--ink-soft);
    }
    .why-us__row-summary:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
    }
    /* Keep room for the +/- mark so it never overlaps the title. */
    .why-us__row-name { padding-right: var(--s-5); }
    /* Body drops below, indented to the head column start (index col +
       gap) so its left edge lines up exactly with the title above. */
    .why-us__row-fold > .why-us__row-body {
        margin-top: var(--s-3);
        margin-left: calc(var(--why-idx-col) + var(--s-7));
    }

    /* With JS: collapsed by default (display:none overrides `open` so first
       paint is collapsed — no flash), revealed by [data-open]. The +/- mark tracks
       [data-open]. Without JS the rule never matches, so `open` keeps the body
       visible — graceful, natively tappable. */
    .js .why-us__row-fold > .why-us__row-body { display: none; }
    .js .why-us__row-fold[data-open] > .why-us__row-body { display: block; }
    .js .why-us__row-fold[data-open] .why-us__row-summary::after {
        content: "\2212"; /* − minus */
    }
}

/* ---- Mode 2: intro-only (.why-us--intro) — DMC narrative + stats ---- */
.why-us--intro .why-us__intro {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
        "head    metrics"
        "lead    metrics";
    column-gap: var(--s-9);
    row-gap: var(--s-4);
    align-items: center;
    margin-bottom: 0;
}
/* The two-column grid above assumes a metrics column on the right. With the
   number tiles retired, that track stayed behind and left heading + lead
   rendering at half width with dead space beside them. Scoped with :has() so
   a block that carries tiles keeps the original composition. */
.why-us--intro .why-us__intro:not(:has(.why-us__metrics)) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
        "head"
        "lead";
    column-gap: 0;
}
.why-us--intro .why-us__intro-row { display: contents; }
.why-us--intro .why-us__head { max-width: none; margin: 0; grid-area: head; align-self: end; }
.why-us--intro .why-us__lead { grid-area: lead; align-self: start; max-width: none; margin: 0; }
.why-us--intro .why-us__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-h2);
    line-height: 1.1;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0 0 var(--s-5);
}
.why-us--intro .why-us__metrics {
    grid-area: metrics;
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--s-5);
    row-gap: var(--s-5);
}
/* A 3-metric intro strip stacks as a single column — a 2×2 grid with three
   items leaves an unbalanced empty cell. Count-scoped via :has() so 4-metric
   strips (the other islands) keep their 2×2. The nth-child(-n+2) borders below
   then read as clean dividers between the stacked stats. */
.why-us--intro .why-us__metrics:has(.why-us__metric:nth-child(3):last-child) {
    grid-template-columns: minmax(0, 1fr);
}
/* A 2-metric strip is a single balanced row of two — drop the 2×2 top-row
   divider so the underlines don't dangle with nothing beneath them. */
.why-us--intro .why-us__metrics:has(.why-us__metric:nth-child(2):last-child) .why-us__metric {
    padding-bottom: 0;
    border-bottom: 0;
}
.why-us--intro .why-us__metric {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    gap: var(--s-2);
    padding-bottom: 0;
    border-bottom: 0;
}
.why-us--intro .why-us__metric:nth-child(-n+2) {
    padding-bottom: var(--s-4);
    border-bottom: 1px solid var(--ink);
}
.why-us--intro .why-us__metric-num {
    font-family: var(--sans);
    font-size: clamp(2.75rem, 5vw, 4.25rem);
    font-weight: 700;
    line-height: 0.95;
    letter-spacing: -0.025em;
    color: var(--feature);
}
.why-us--intro .why-us__metric-label { color: var(--ink-soft); }
@media (max-width: 900px) {
    .why-us--intro .why-us__intro {
        grid-template-columns: 1fr;
        grid-template-areas: "head" "lead" "metrics";
        row-gap: var(--s-5);
    }
    .why-us--intro .why-us__head,
    .why-us--intro .why-us__lead { align-self: stretch; }
}
@media (max-width: 560px) {
    .why-us--intro .why-us__metrics { grid-template-columns: 1fr; }
    .why-us--intro .why-us__metric:nth-child(-n+2) { padding-bottom: 0; border-bottom: 0; }
    .why-us--intro .why-us__metric {
        padding-bottom: var(--s-4);
        border-bottom: 1px solid var(--ink);
    }
    .why-us--intro .why-us__metric:last-child { padding-bottom: 0; border-bottom: 0; }
}

/* ---------- Affiliation block (group-membership announcement) ----------
   Single-column editorial section: eyebrow → heading → logo → body
   stacked vertically. Top hairline marks the section boundary; right
   hairline acts as the vertical divider against the paired Testimonial
   block. No bottom border — content flows down into whatever follows.
   Used for the TOURVEST membership announcement. */
.affiliation {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--s-9) var(--gutter);
}
.affiliation__row--media {
    margin-top: var(--s-6);
}
.affiliation__logo {
    margin: 0;
    max-width: 360px;
    width: 100%;
}
.affiliation__eyebrow {
    margin: 0 0 var(--s-4);
}
.affiliation__heading {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(22px, 1.8vw, 30px);
    line-height: 1.15;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
}
.affiliation__logo img {
    display: block;
    width: 100%;
    height: auto;
}
.affiliation__body {
    font-family: var(--sans);
    font-size: 1.0625rem;
    line-height: var(--lh-body);
    color: var(--ink-soft);
}
/* Below lg the cols stack via Bootstrap; tighten the row spacing so
   logo and body don't float too far below the heading. */
@media (max-width: 991px) {
    .affiliation__row--media {
        margin-top: var(--s-5);
    }
    .affiliation__logo {
        margin-bottom: var(--s-4);
    }
}

/* Newsletter unsubscribe page — kept type-only. Confirm button sits
   next to a quiet cancel link so the destructive action has a visible
   escape; nothing reads as a "form" so the page stays calm. */
.page--unsubscribe .unsubscribe-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-5);
    margin-top: var(--s-6);
}
.page--unsubscribe .unsubscribe-form__cancel {
    color: var(--ink-soft);
    text-decoration: underline;
    text-underline-offset: 3px;
    font-family: var(--sans);
    font-size: 0.875rem;
}
.page--unsubscribe .unsubscribe-form__cancel:hover {
    color: var(--ink);
}


/* ================================================================== */
/* Wave 2 — case-study detail, product detail, destinations            */
/* anchor card. Editorial uplift modeled on ArticlePage (the gold      */
/* standard). All new rules are scoped to `--editorial` modifiers so   */
/* the existing rule blocks above keep their current behavior for any  */
/* surface that hasn't moved to the new layout yet.                    */
/* ================================================================== */

/* ---------- Case study detail (editorial layout) ------------------- */

/* Outer wrapper opts out of .case-study's 720px text-cap so the hero +
   specs row can use the full article width. main already owns the
   maxw + gutter rail (see container contract) — do NOT re-apply
   max-width or gutter padding here or the content double-paddings
   and renders narrower than the rest of the site. */
.case-study--editorial {
    max-width: none;
}

.case-study--editorial .case-study__back {
    margin: 0 0 var(--s-5);
}

.case-study--editorial .case-study__hero {
    margin: 0 0 var(--s-7);
}
.case-study--editorial .case-study__hero img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
}

.case-study--editorial .case-study__specs {
    margin: 0 0 var(--s-8);
}

/* The editorial column. Built as a 2-track CSS Grid (1fr left margin
   rail / 2fr editorial column) so children explicitly nominate a track
   via grid-column. Head / body / what-worked / nav all live in column 2.
   Pull-quote opts into column 1 to sit alongside the body's opening. */
.case-study__column {
    display: grid;
    grid-template-columns: 1fr 2fr;
    column-gap: var(--s-6);
    row-gap: 0;
    align-items: start;
}
@media (max-width: 800px) {
    /* Collapse to one column. grid-template-columns:1fr alone is NOT enough:
       the children explicitly nominate tracks (head/body/what-worked/nav →
       grid-column:2, pullquote → grid-column:1), so a single explicit track
       just spawns an implicit second column for the col-2 items and the
       layout stays two-up. Dropping to block flow neutralises every
       grid-column pick so they stack in source order. */
    .case-study__column {
        display: block;
    }
}

.case-study--editorial .case-study__head {
    grid-column: 2;
    margin-bottom: var(--s-6);
}
.case-study--editorial .case-study__title {
    /* Display-tier headline. Bold sans, matching .article__title and the
       site-wide h1-h4 700 default declared in tokens.css. Do NOT lower the
       weight — headlines are bold on lxp6. */
    font-weight: 700;
    font-size: var(--t-display);
    line-height: 1.05;
    letter-spacing: -0.015em;
    margin: 0 0 var(--s-5);
    max-width: 28ch;
    text-wrap: balance;
}
.case-study--editorial .case-study__eyebrow {
    margin: 0 0 var(--s-3);
}
.case-study--editorial .case-study__summary {
    font-family: var(--serif);
    font-style: italic;
    font-size: clamp(1.1rem, 1.8vw, 1.35rem);
    line-height: 1.4;
    color: var(--ink);
    margin: 0 0 var(--s-5);
    max-width: none;
}

/* Pull-quote sits in the LEFT track of the editorial column grid,
   spanning whatever vertical space its content needs. align-self: start
   anchors it to the top so it reads alongside the body's first
   paragraphs rather than centering vertically in the column. */
.case-study__pullquote {
    grid-column: 1;
    align-self: start;
    margin: var(--s-2) 0 var(--s-6);
}
.case-study__pullquote blockquote {
    margin: 0;
    padding: 0 0 0 var(--s-4);
    border-left: 3px solid var(--accent);
    font-family: var(--serif);
    font-style: italic;
    font-size: clamp(1.15rem, 1.8vw, 1.45rem);
    line-height: 1.35;
    color: var(--ink);
    text-wrap: balance;
}
@media (max-width: 800px) {
    .case-study__pullquote {
        grid-column: 1;
        margin: var(--s-6) 0;
    }
}

/* Body in the editorial variant — 64ch reading measure inside the
   2-fr right column. */
.case-study--editorial .case-study__body {
    grid-column: 2;
    max-width: 64ch;
    margin: 0 0 var(--s-7);
}

.case-study--editorial .case-study__what-worked {
    grid-column: 2;
    margin: var(--s-8) 0 0;
    padding: var(--s-7) 0 0;
    border-top: 1px solid var(--hairline);
    max-width: 64ch;
}

/* Prev/next nav inside the editorial column. Mirrors .article__nav. */
.case-study__nav {
    grid-column: 2;
    margin-top: var(--s-9);
    padding-top: var(--s-6);
    border-top: var(--rail-soft);
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-6);
    max-width: 64ch;
}
.case-study__nav-link {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    text-decoration: none;
    color: inherit;
}
.case-study__nav-link--next { text-align: right; }
/* One-direction case. The first case study has only "next", the last only
   "prev". Grid auto-placement drops a lone link into column 1, so "next"
   ends up right-aligned against the MIDDLE of the rail instead of its right
   edge — visibly adrift. .article__nav / .product__nav fix this with
   margin-left:auto, which works because those are Bootstrap flex rows; in a
   grid an auto margin only aligns the item inside its already-half-width
   track, so the link has to change track instead. "prev" alone is already
   correct in column 1. */
.case-study__nav-link--next:only-child { grid-column: 2; }
.case-study__nav-label {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.case-study__nav-title {
    font-family: var(--serif);
    font-style: italic;
    font-size: 1.1rem;
    line-height: 1.3;
    color: var(--ink);
}
@media (max-width: 560px) {
    .case-study__nav { grid-template-columns: 1fr; gap: var(--s-5); }
    .case-study__nav-link--next { text-align: left; }
    /* Reset the only-child track pick. With a single explicit 1fr track a
       leftover grid-column:2 spawns an IMPLICIT second column and the nav
       stays two-up — the same trap documented on .case-study__column. */
    .case-study__nav-link--next:only-child { grid-column: 1; }
}

/* Suppress the older "break-out beyond reading column" trick on the
   editorial variant — full-width hero already does that job. */
.case-study--editorial .case-study__photo {
    width: 100%;
    margin-left: 0;
}

/* ---------- Product detail (editorial layout) ---------------------- */

/* GRID RHYTHM — mirrors .article (see "Article detail" block above).
   ONE rail, ONE rhythm. Every row is a Bootstrap `.row` direct child
   of `.product`, with default 24px gutter. No per-block gutter overrides.

   `.product` lives inside <main>, which provides the rail via
       max-width: var(--maxw); padding: 0 var(--gutter)

   Row map at lg+:
     Row 1 (editorial):  header col-md-4 + hero col-md-8  → md split
     Row 2 (main):       aside col-lg-4 (specs) +
                         .product__body col-lg-8           → body LEFT
                         lines up with hero LEFT at col-5
     Row 3 (gallery):    ul.row > li col-12 col-sm-6 col-lg-4
     Row 4 (nav):        a col-12 col-sm-6 prev + next
*/
.product {
    max-width: var(--maxw);
    margin: 0 auto;
}

/* Page-wide column gutter override — same scoping + 2×-rail cap
   rationale as `.article .row` above (prevents the row outdent from
   overflowing the viewport on phones; keeps full s-8 gutter >=650px). */
.product .row {
    --bs-gutter-x: min(var(--s-8), calc(var(--gutter) * 2));
}

.product__editorial,
.product__main-row,
.product__gallery,
.product__nav {
    margin-bottom: var(--s-9);
}
.product > .row { --bs-gutter-y: 0; }

.product__head { margin: 0; }
.product__hero { margin: 0; }

/* Below md the editorial row stacks (header over hero). The row's
   gutter-y is 0 (vertical rhythm is carried on block margins), so without
   this the title/tagline would sit flush against the hero. Add a breathing
   gap under the head only while stacked; at md+ they're side by side and
   need no top offset. */
@media (max-width: 767.98px) {
    .product__hero { margin-top: var(--s-6); }
}

/* .product__tagline typography is owned by the global lead-cluster
   rule (see .lead group). Keep this layout-only — zero its margin so
   it sits flush under the title in the head column. */
.product__tagline { margin: 0; }

/* Specs rail anchors at cols 1-4 of the main row, with the body
   slot to its right (cols 5-12). The body LEFT edge therefore lines
   up with the hero LEFT edge in Row 1. Inner typography
   (responsibility grid, product-facts list, location) is owned by
   the standalone .responsibility / .product-facts / .product__location
   rules higher up — keep this rule scoped to layout only. */
.product__specs-rail {
    margin: 0;
}
.product__specs-rail .responsibility { margin-bottom: var(--s-5); }
.product__specs-rail .product-facts  { margin: 0 0 var(--s-5); }
.product__specs-rail .product__location { margin: 0; }

/* Subtitle (h2) acts as lede, not section heading — intentional exception
   to the site-wide h1-h4 bold rule (tokens.css). The `.product__subtitle`
   class (0,1,0) beats the element-level tokens `h2 { font-weight: 700 }` by
   specificity. See memory feedback_product_subtitle_is_lead. */
.product__subtitle {
    font-weight: 300;
    line-height: 1.3;
    margin: var(--s-3) 0 0;
    text-wrap: balance;
}
.product__prose { max-width: 64ch; }

/* Gallery — shares .article-slides utility row + .article-slide__trigger
   button/image rules with the article gallery (see "Article detail"
   block above). The .row class on <ul> activates Bootstrap; the
   col-* classes on <li> handle the 3-up grid. */
.product__gallery {
    padding-top: var(--s-6);
    border-top: var(--rail-soft);
}
/* No margin reset here on purpose: the shared .article-slides base already
   zeroes the block-axis margin while keeping Bootstrap's horizontal row
   outdent, so the tiles align to the rail like the hero/body. A blanket
   `margin: 0` here used to clobber the outdent too, insetting every gallery
   image ~one gutter (~20px) inside the rail — narrower than the hero. */

/* Prev/next nav — same anatomy as .article__nav. Prev in cols 1-6 of
   the row (Bootstrap sm+); only-child case anchors to the right via
   margin-left: auto so a single direction sits at the row's right
   edge instead of orphaning at the left. */
.product__nav {
    padding-top: var(--s-6);
    border-top: var(--rail-soft);
    --bs-gutter-y: var(--s-5);
}
.product__nav-link:only-child { margin-left: auto; }
.product__nav-link {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    text-decoration: none;
    color: inherit;
}
@media (min-width: 576px) {
    .product__nav-link--next { text-align: right; }
}
.product__nav-label {
    font-family: var(--sans);
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.product__nav-title {
    font-family: var(--serif);
    font-style: italic;
    font-size: 1.1rem;
    line-height: 1.3;
    color: var(--ink);
}

@media (max-width: 560px) {
    .product__nav { --bs-gutter-y: var(--s-5); }
    .product__nav-link--next { text-align: left; }
}

/* ---------- Destinations index: photographic panels ----------------
   Stacked destination panels down the pillar page. Deliberately
   rail-BOUND, not full-bleed: on this site viewport-wide imagery is
   the vocabulary of single hero moments on the rail-stripped pages
   (Home/DMC/Contact); five stacked panels at hero width would shout.
   Bounded, the stack stays in rhythm with the H1, CTA and FAQs around
   it, and panel proportions hold on very wide monitors. Panels
   separate with the standard tile gap (--s-5): as rail-bound plates,
   the scrim-base of one butting the photo-top of the next read muddy
   — the bone seam keeps each island its own surface (gapless belonged
   to the parked full-bleed wall idea). Captions inset from the panel
   edge like the small overlay tiles. Image hover scale comes from the
   central .card rule — no per-component hover. */
.destination-wall {
    list-style: none;
    padding: 0;
    margin: var(--s-7) 0 0;
    display: grid;
    gap: var(--s-5);
}
.destination-wall__panel { margin: 0; }
.destination-wall__link {
    position: relative;
    display: block;
    height: min(62vh, 580px);
    overflow: hidden;
    text-decoration: none;
    color: #fff;
}
.destination-wall__panel--lead .destination-wall__link {
    height: min(80vh, 760px);
}
.destination-wall__figure {
    position: absolute;
    inset: 0;
    margin: 0;
}
.destination-wall__figure img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.destination-wall__figure--empty {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--accent-a-600);
}
/* Legibility scrim — ink-toned like the tile scrim, but deeper and
   stronger: these panels run bright Mediterranean photography behind
   white display type, so the base needs more weight than the small
   tiles' 0.55. Mid-stop keeps the ramp soft instead of a hard band. */
.destination-wall__link::after {
    content: "";
    position: absolute;
    inset: 30% 0 0 0;
    background: linear-gradient(
        to bottom,
        rgba(33, 28, 25, 0) 0%,
        rgba(33, 28, 25, 0.35) 45%,
        rgba(33, 28, 25, 0.78) 100%
    );
    pointer-events: none;
}
.destination-wall__caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1;
    padding: 0 var(--s-6) var(--s-6);
}
.destination-wall__eyebrow {
    color: rgba(255, 255, 255, 0.85);
    margin: 0 0 var(--s-2);
}
/* Names sit on the site's hero tier (--t-hero), NOT above it: these
   are h2s on an index page, and the h1 hero of the DMC page each panel
   links to uses the same scale — so the click-through reads as a
   seamless handoff, not a step down. */
.destination-wall__name {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-hero);
    line-height: 1.08;
    letter-spacing: -0.018em;
    color: #fff;
    margin: 0;
}
.destination-wall__lede {
    color: rgba(255, 255, 255, 0.92);
    font-family: var(--sans);
    /* 400, not 300: bottoms out at 1rem on mobile, and light on a dark
       photo ground reads too faint at that size. */
    font-weight: 400;
    font-size: clamp(1rem, 1.5vw, 1.2rem);
    line-height: 1.4;
    max-width: 44ch;
    margin: var(--s-3) 0 0;
}
.destination-wall__more {
    display: inline-block;
    margin-top: var(--s-4);
    font-family: var(--sans);
    font-size: 0.9rem;
    color: #fff;
    border-bottom: 1px solid rgba(255, 255, 255, 0.55);
    padding-bottom: 2px;
}
.destination-wall__link:hover .destination-wall__more,
.destination-wall__link:focus-visible .destination-wall__more {
    border-bottom-color: #fff;
}

@media (max-width: 820px) {
    .destination-wall__link { height: min(52vh, 440px); }
    .destination-wall__panel--lead .destination-wall__link { height: min(62vh, 540px); }
    .destination-wall__caption { padding-bottom: var(--s-6); }
    .destination-wall__lede { display: none; }
}

/* ---------- Sustainability credentials block ----------------------
   Definition-list of trust signals: title-left, body-right, one
   credential per row separated by hairlines. Distinct from the
   earlier `.why-us` shell so the type weight, optional logo, and
   Meta sub-label are first-class — not borrowed scaffolding.

   Two styles share the same structure; only the ground changes:

     .sustainability--certifications  bone ground, hairline rows.
                                      Third-party audits — institutional
                                      voice.

     .sustainability--commitments     soft sand band running edge-to-edge.
                                      Self-commitments — quieter register,
                                      visually distinct from the section
                                      above without changing the layout.

   The block stays bare per the container contract (main owns the
   maxw + gutter rail on bounded-main pages like /nachhaltigkeit/).
   ------------------------------------------------------------------ */
.sustainability {
    padding: var(--s-9) 0 var(--s-8);
}

/* Self-bound only on the THREE pages that strip <main>'s rail
   (HomePage / DMCPage / ContactPage — heroes run viewport-wide there).
   Without this the block spans the full viewport on the DMC landing
   pages instead of lining up with its siblings (.why-us, service strip).
   MUST stay page-scoped: on bounded-main pages like /nachhaltigkeit/
   <main> already owns maxw + gutter, so an unscoped rule would
   double-indent. Mirrors .element.is-partial (~line 1205). */
.t-App\\PageType\\HomePage .sustainability,
.t-App\\PageType\\DMCPage .sustainability,
.t-App\\PageType\\ContactPage .sustainability {
    max-width: var(--maxw);
    margin-left: auto;
    margin-right: auto;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
}

.sustainability__intro {
    margin-bottom: var(--s-8);
    align-items: baseline;
}

.sustainability__eyebrow {
    margin: 0 0 var(--s-4);
}

.sustainability__title {
    margin: 0;
    text-wrap: balance;
}

.sustainability__lead {
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(1.1rem, 1.6vw, 1.3rem);
    line-height: 1.45;
    color: var(--ink);
    margin: 0;
    text-wrap: balance;
}

.sustainability__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* The <li> owns the hairline and the vertical padding, and spans the
   full container rail. The Bootstrap .row lives INSIDE it
   (.sustainability__row-cols) so the columns keep their negative
   margins and their content lands ON the rail rather than half a
   gutter inside the rule above. Merging the two onto one element
   forced `margin: 0` here, which is what pushed every row's logo,
   name and body 12px right of the section head. */
.sustainability__row {
    padding: var(--s-6) 0;
    border-top: 1px solid var(--ink);
}
.sustainability__row + .sustainability__row {
    border-top: 1px solid var(--hairline);
}
/* No closing rule under the last row. The rules here are separators, not
   a frame: the --ink rule opens the list against the heading, the
   hairlines divide the items. A line under the last row divides it from
   nothing — the whitespace (and on the commitments variant the sand band
   edge) already ends the list. Same reason .article-list,
   .search-pages__item and .why-us--intro drop theirs. */

.sustainability__row-cols {
    align-items: center;
}

.sustainability__logo {
    display: block;
    /* Logo sits in its own column, name beside it. Logos vary wildly in
       aspect ratio — Carboncero / 2020_C are portrait, the CleanWave
       lockup is a wide wordmark (454×34). Cap by BOTH height and width so
       the wide one fills the column without the portrait ones blowing up:
       height wins for portrait marks, width wins for wordmarks. */
    height: auto;
    max-height: clamp(72px, 8vw, 112px);
    max-width: 100%;
    width: auto;
    margin: 0;
}

/* ── The two naming tiers ─────────────────────────────────────────────
   Every component that puts a NAME on something declares it here, once.
   Ten of them used to carry their own font-size: seven hand-typed
   literals across six values, of which `1.25rem` appeared three separate
   times and one clamp twice, byte-identical. They were never decisions —
   tokens.css had nothing in the 18–26px band to reach for, so each new
   component invented a number. The tokens exist now; see tokens.css.

   Consolidated 2026-08-07 after the grid-discipline sweep found the role
   spread across five rendered sizes on one page. Two changes came with
   it, both deliberate: why-us__row-name capped at 1.5rem like its three
   siblings instead of running on to 1.625rem, and case-rail__name /
   product-card__title moved 18px -> 20px to join the other three cards.

   `color: var(--ink)` rather than a literal: inverse surfaces redefine
   --ink in their own scope, so the name follows the ground it sits on. */
.why-us__row-name,
.sustainability__name,
.certifications__name,
.commitments__name,
.contact-direct__value {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-row-name);
    line-height: 1.2;
    letter-spacing: -0.018em;
    color: var(--ink);
    margin: 0;
    text-wrap: balance;
}

.service-tile__title,
.team-card__name,
.sister-brands__name,
.case-rail__name,
.product-card__title {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-card-title);
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
}

.sustainability__meta {
    margin: var(--s-2) 0 0;
    color: var(--ink-muted);
}

.sustainability__body {
    font-family: var(--sans);
    font-size: var(--t-body-lg);
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0;
}

/* Commitments variant — soft sand band that runs edge-to-edge.
   Uses the same shadow + clip-path trick as .section--soft so the
   block stays bare (main owns the rail) while the colour bleeds.

   Names the semantic token, not the raw stone-100 it used to hardcode:
   this band is the reference the split-hero text columns were matched
   to, and two hand-typed hexes drift the moment one of them is retuned. */
.sustainability--commitments {
    position: relative;
    background: var(--bg-soft);
    box-shadow: 0 0 0 100vmax var(--bg-soft);
    clip-path: inset(0 -100vmax);
    padding: var(--s-10) 0 var(--s-9);
    margin: var(--s-8) 0;
}

@media (max-width: 991px) {
    .sustainability__intro {
        margin-bottom: var(--s-6);
    }
    .sustainability__lead-wrap {
        margin-top: var(--s-4);
    }
    .sustainability__body-col {
        margin-top: var(--s-3);
    }
}

@media (max-width: 600px) {
    .sustainability {
        padding: var(--s-8) 0 var(--s-7);
    }
    .sustainability--commitments {
        padding: var(--s-9) 0 var(--s-8);
    }
    .sustainability__logo {
        max-height: 64px;
    }
    .sustainability__name-col {
        display: flex;
        flex-direction: column;
        justify-content: center;
    }
    .sustainability__body-col {
        flex: 0 0 100%;
        max-width: 100%;
    }
    .sustainability__row {
        padding: var(--s-5) 0;
    }
}

/* ---------- Commitments register (App\Element\ElementCommitments) --
   ------------------------------------------------------------------
   /unsere-welt/nachhaltigkeit/unser-versprechen. Sibling of
   .sustainability above and intentionally close to it — the parent page
   states the credentials in this exact rhythm, so the child page reads as
   the same argument continued. Same 6/6 intro, same hairline rows, same
   column-7 start for the right-hand column.

   The one difference is what the right column holds: a credential is one
   sentence of evidence, a commitment is a list of measures.

   No accordion, no reveal. Replaced a Bootstrap 2 collapse whose JS lxp6
   never loaded, and would not have been kept even if it had: a commitment
   behind a click is a commitment kept out of sight.

   Block stays bare per the container contract (main owns the rail). This
   page is a base Page, so it is never one of the three stripped-main
   layouts and needs no self-bound escape hatch.
   ------------------------------------------------------------------ */
.commitments {
    padding: var(--s-9) 0 var(--s-8);
}

.commitments__eyebrow { margin: 0 0 var(--s-4); }

.commitments__intro {
    margin-bottom: var(--s-8);
    align-items: baseline;
}

.commitments__title {
    margin: 0;
    text-wrap: balance;
}

/* The two clamps in this block (here and on __name) are deliberate copies of
   .sustainability__lead / .sustainability__name, NOT token bypasses waiting
   to be swept. The whole point of the component is that the child page's
   register reads at the same size as the parent page's credentials; replacing
   either one with a token that the other does not use makes them diverge. If
   these ever become tokens, both blocks change together. */
.commitments__lead {
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(1.1rem, 1.6vw, 1.3rem);
    line-height: 1.45;
    color: var(--ink);
    margin: 0;
    text-wrap: balance;
}

.commitments__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Hairline + padding on the <li>, Bootstrap .row nested inside — see the
   identical note on .sustainability__row for why the two jobs cannot share
   an element. --ink opens the list against the heading, --hairline divides
   the items, and nothing closes it: the rules are separators, not a frame. */
.commitments__row {
    padding: var(--s-6) 0;
    border-top: 1px solid var(--ink);
}
.commitments__row + .commitments__row {
    border-top: 1px solid var(--hairline);
}

/* Top-aligned, unlike .sustainability__row-cols. A credential row centres
   because both sides are one line deep; here the left side is one line and
   the right side is up to six, so centring floats the commitment name into
   the middle of its own measures. */
.commitments__row-cols {
    align-items: start;
}

/* .commitments__name is styled with the row-name tier (~line 9588). */

.commitments__body {
    font-family: var(--sans);
    font-size: var(--t-body);
    line-height: 1.55;
    color: var(--ink-soft);
}
.commitments__body > :first-child { margin-top: 0; }
.commitments__body > :last-child { margin-bottom: 0; }

.commitments__body ul {
    list-style: none;
    margin: 0;
    padding: 0;
}
/* En dash rather than a disc, hung outside the measure. A disc at six rows
   × up to six measures reads as ornament; the dash is the mark a printed
   pledge uses, and hanging it keeps every measure's text on one left edge
   including the wrapped lines. */
.commitments__body li {
    position: relative;
    margin: 0 0 var(--s-3);
    padding-left: 1.35em;
}
.commitments__body li:last-child { margin-bottom: 0; }
.commitments__body li::before {
    content: "–";
    position: absolute;
    left: 0;
    top: 0;
    color: var(--ink-muted);
}
/* The migrated copy wraps some measures in a <p> inside the <li>. It is
   inline in the source (a legacy `display: inline !important`), and the
   task strips it where it can — this is the belt-and-braces so a stray one
   never opens a paragraph gap mid-list. */
.commitments__body li > p {
    display: inline;
    margin: 0;
}
/* A lead-in sentence above the measures ("Wichtige Überlegungen … sind:")
   — one commitment has one. Sits at the column edge, no dash. */
.commitments__body > p {
    margin: 0 0 var(--s-3);
}
/* Trailing link out of a row (the code of conduct on the partners
   commitment). Set off from the measures so it does not read as a seventh
   one. */
.commitments__body > p:last-child:not(:first-child) {
    margin: var(--s-4) 0 0;
}

@media (max-width: 991px) {
    .commitments__intro { margin-bottom: var(--s-6); }
    .commitments__lead-wrap { margin-top: var(--s-4); }
    /* Bootstrap's offset only applies from lg up, so below it the body
       column needs its own separation from the name above it. */
    .commitments__body-col { margin-top: var(--s-4); }
}

@media (max-width: 600px) {
    .commitments { padding: var(--s-8) 0 var(--s-7); }
    .commitments__row { padding: var(--s-5) 0; }
}

/* ---------- Sustainability page pull-quote ------------------------
   Sits between the two ElementSustainability blocks via the
   SustainabilityPage layout override. Garamond italic, centered on
   the 12-col grid, narrow measure to keep it as a deliberate pause
   between sections. No quote-mark trash.

   Cancels the Bootstrap .row negative margins inside the block so
   the quote text doesn't leak past the main gutter on mobile. */
.sustainability-quote {
    padding: var(--s-9) 0;
}
.sustainability-quote .row {
    margin-left: 0;
    margin-right: 0;
}
.sustainability-quote .row > [class*="col-"] {
    padding-left: 0;
    padding-right: 0;
}

.sustainability-quote__text {
    font-family: var(--serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.4rem, 2.4vw, 2rem);
    line-height: 1.4;
    letter-spacing: -0.005em;
    color: var(--ink);
    /* Reset UA blockquote margins (default ~1em 40px) — they were
       letting the quote leak past the main gutter on mobile. */
    margin: 0;
    padding: 0;
    text-align: center;
    text-wrap: balance;
}

@media (max-width: 600px) {
    .sustainability-quote {
        padding: var(--s-8) 0;
    }
    .sustainability-quote__text {
        text-align: left;
    }
}

/* ---------- Responsibility key — the four sustainability dimensions -----
   The legend for the icons a visitor meets in a product's specs rail.
   Sibling of `.sustainability` and deliberately NOT identical to it: that
   block is a full-width row list of third-party credentials, this one is a
   2×2 field of definitions.

   The intro does NOT use the 5/7 split its sibling does. Eyebrow, heading
   and lead stack in one half-width column: the lead completes the heading
   rather than answering it, and half width lands the column's right edge on
   the first grid cell's, so the block runs on one rail top to bottom
   instead of stacking a 5/7 rhythm on a 6/6 one.

   Bootstrap .row/.col owns the column math. Each cell is topped by a
   hairline: four horizon lines, no boxes, no cards.

   Block stays bare per the container contract (main owns maxw + gutter);
   this page type is bounded-main, so no self-binding rule is needed.
   ------------------------------------------------------------------ */
.responsibility-key {
    padding: var(--s-9) 0 var(--s-8);
}

.responsibility-key__eyebrow {
    margin: 0 0 var(--s-4);
}

.responsibility-key__intro {
    margin-bottom: var(--s-8);
}

/* The gap below the heading lives HERE, not as a top margin on the lead —
   that is how every stacked title/lead pair in this theme does it
   (.page__title, .article__title, .home-rfp-cta__title, .why-us__title all
   use the same --s-5). A display-scale heading needs the step; --s-4 read
   as one clump with the line under it. */
.responsibility-key__title {
    margin: 0 0 var(--s-5);
    text-wrap: balance;
}

.responsibility-key__lead {
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(1.1rem, 1.6vw, 1.3rem);
    line-height: 1.45;
    color: var(--ink);
    margin: 0;
    text-wrap: balance;
}
/* .prose sets its own paragraph rhythm — the lead is one paragraph, so
   flatten it rather than letting a trailing margin push the grid down. */
.responsibility-key__lead > p {
    font: inherit;
    color: inherit;
    margin: 0;
}

/* Longhand margins only: `margin: 0` would clobber Bootstrap's negative
   row margins and pull every cell in by half a gutter. */
.responsibility-key__list {
    list-style: none;
    padding-left: 0;
    margin-top: 0;
    margin-bottom: 0;
    row-gap: var(--s-8);
}

.responsibility-key__item {
    border-top: 1px solid var(--ink);
    padding-top: var(--s-5);
}

.responsibility-key__icon {
    display: block;
    width: 72px;
    height: 72px;
    margin: 0 0 var(--s-4);
}

.responsibility-key__name {
    font-family: var(--sans);
    font-weight: 700;
    font-size: clamp(1.15rem, 1.4vw, 1.35rem);
    line-height: 1.2;
    letter-spacing: -0.015em;
    color: var(--ink);
    margin: 0 0 var(--s-3);
}

.responsibility-key__body {
    font-family: var(--sans);
    font-size: var(--t-body-lg);
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0;
}

@media (max-width: 991px) {
    .responsibility-key__intro {
        margin-bottom: var(--s-6);
    }
}

@media (max-width: 600px) {
    .responsibility-key {
        padding: var(--s-8) 0 var(--s-7);
    }
    .responsibility-key__list {
        row-gap: var(--s-6);
    }
    .responsibility-key__icon {
        width: 60px;
        height: 60px;
    }
}

/* ---------- Job listing — structured open-position cards ----------------
   Replaces the legacy ad-hoc ElementTextText job ads on /jobs. A two-up
   grid of bordered cards: location + type as small UI labels, role title,
   plain-text intro lede, responsibilities, then a clear two-action footer
   (full flip-book description + apply-by-email). Bootstrap .row/.col owns
   the column math; everything else is token-driven. */
.job-listing {
    padding: var(--s-9) 0 var(--s-10);
}
.job-listing__head {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    margin: 0 0 var(--s-7);
    max-width: var(--maxw-text);
}
.job-listing__title {
    margin: 0;
    color: var(--ink);
}
.job-listing__lead {
    font-size: var(--t-body-lg);
    line-height: var(--lh-loose);
    color: var(--ink-soft);
    margin: 0;
}
.job-listing__grid {
    list-style: none;
    padding: 0;
    /* Reset only the block-axis list margin. The inline-axis margins are
       Bootstrap's `.row` negative outdent (calc(-.5 * --bs-gutter-x)) — a
       blanket `margin: 0` here clobbered them, insetting the card columns
       ~12px inside the page rail so they no longer aligned with the head,
       sub-nav and sibling blocks. Keep the outdent so the cards land on
       the same maxw+gutter rail as the rest of the page body. */
    margin-top: 0;
    margin-bottom: 0;
    row-gap: var(--s-6);
}
.job-listing__item { margin: 0; }

.job-listing__card {
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
    height: 100%;
    padding: var(--s-6);
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    transition: border-color 220ms var(--ease);
}
.job-listing__card:hover { border-color: var(--stone-300); }

.job-listing__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
}
.job-listing__tag {
    display: inline-flex;
    align-items: center;
    font-family: var(--sans);
    font-size: var(--t-micro);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 500;
    color: var(--ink-muted);
    padding: var(--s-1) var(--s-3);
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
}
.job-listing__tag--type {
    color: var(--accent);
    border-color: var(--accent-soft);
}

.job-listing__role {
    font-family: var(--sans);
    font-weight: 700;
    font-size: var(--t-h3);
    line-height: var(--lh-snug);
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
}
.job-listing__intro {
    font-size: var(--t-body-lg);
    line-height: var(--lh-body);
    color: var(--ink-soft);
    margin: 0;
}
.job-listing__body {
    font-size: var(--t-body);
}
.job-listing__body p,
.job-listing__body ul,
.job-listing__body li {
    font-size: var(--t-body);
}

.job-listing__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4);
    margin-top: auto;
    padding-top: var(--s-4);
    border-top: 1px solid var(--hairline-soft);
}
.job-listing__link { font-size: var(--t-small); }

@media (max-width: 800px) {
    .job-listing__card { padding: var(--s-5); }
}

/* ===================================================================
   Credential rail (App\Element\ElementCertifications)

   One row per credential: logo, name, what it covers.

   THE GRID IS THE SUSTAINABILITY SECTION'S, NOT ITS OWN. Head 6/6; rows
   run logo (1-3) · name (4-6) · body (7-12), the same spine
   .sustainability and .commitments use, so the lead starts on the grid
   line its rows' body copy starts on and an ElementTextText intro
   stacked above lands on the same edge. It was 3/9 with the name inside
   the body column until 2026-08-07, which put three different left
   edges on one page.

   THE LOGO CAP IS THE POINT. These marks arrive at wildly different
   intrinsic sizes — the Carbonocero SVG is ~1000px wide and the
   CleanWave lockup is a 454x34 wordmark. Capping BOTH height and width
   lets height win for portrait marks and width win for wordmarks, so
   unrelated logos read as one rail rather than a set of accidents.
   =================================================================== */
.certifications {
    padding: var(--s-9) 0 var(--s-8);
}

.certifications__eyebrow {
    margin: 0 0 var(--s-4);
}

/* Baseline-aligned so the lead sits on the heading's first line, not on
   the top of its box. Same rule as .sustainability__intro. */
.certifications__intro-row {
    margin-bottom: var(--s-8);
    align-items: baseline;
}

.certifications__heading {
    margin: 0;
    text-wrap: balance;
}

.certifications__intro {
    margin: 0;
}
.certifications__intro > :first-child { margin-top: 0; }
.certifications__intro > :last-child  { margin-bottom: 0; }

.certifications__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* The <li> owns the rule and the vertical padding so the line spans the
   full container rail; the Bootstrap .row lives inside it, where its
   negative margins can cancel the columns' gutter padding. Rules are
   separators, not a frame: the --ink rule opens the list against the
   heading, hairlines divide the entries, nothing closes the last one. */
.certifications__item {
    padding: var(--s-7) 0;
    border-top: 1px solid var(--ink);
}
.certifications__item + .certifications__item {
    border-top: 1px solid var(--hairline);
}

.certifications__logo {
    display: block;
    height: auto;
    width: auto;
    max-height: clamp(72px, 8vw, 112px);
    max-width: 100%;
    margin: 0;
    object-fit: contain;
    object-position: left center;
}

/* .certifications__name is styled with .sustainability__name (~line 9593) —
   one declaration for the credential-name tier across both components. */

.certifications__subtitle {
    margin: var(--s-2) 0 0;
    color: var(--ink-muted);
    font-size: var(--t-small);
}

.certifications__body > :first-child { margin-top: 0; }
.certifications__body > :last-child  { margin-bottom: 0; }

.certifications__verify {
    margin: var(--s-4) 0 0;
    font-size: var(--t-small);
}

/* Below lg all three columns stack, one per line. The logo is capped by
   WIDTH here rather than height: at full column width a 454x34 wordmark
   would run the whole screen while a portrait mark would tower over the
   name. 200px lands both in the same optical size class. */
@media (max-width: 991.98px) {
    .certifications__item {
        padding: var(--s-6) 0;
    }
    .certifications__logo {
        max-width: 200px;
        max-height: 64px;
    }
    .certifications__name-col,
    .certifications__body-col {
        margin-top: var(--s-4);
    }
}
