/* =========================================================================
   GM Concept — design system
   Single hand-written stylesheet. No framework, no build step.
   The brand palette is unchanged from the previous site; everything else
   (layout, type, components, motion) is new.
   ---------------------------------------------------------------------
   1. Tokens          5. Header / nav
   2. Reset & base    6. Sections & components
   3. Layout          7. Forms
   4. Typography      8. Footer & floating actions
   ========================================================================= */

/* -------------------------------------------------------------------------
   Brand typeface — Instrument Sans (SIL OFL 1.1, see fonts/OFL.txt).
   A variable font: each file carries every weight from 400 to 700, so the
   whole weight scale costs one download. Subsets as Google splits them;
   "latin" alone covers French, including œ, « », the narrow no-break space
   and €.
   ------------------------------------------------------------------------- */
@font-face {
    font-family: "Instrument Sans";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/instrument-sans-latin.fa41c43a3d8e.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Instrument Sans";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("../fonts/instrument-sans-latin-ext.1ff13d113ba4.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Stand-in while the webfont loads: Arial, resized and re-spaced to occupy
   exactly the room Instrument Sans will, so the swap does not reflow the
   page. Figures computed with fontTools from both fonts' real metrics
   (average advance over French body copy; hhea ascent/descent). */
@font-face {
    font-family: "Instrument Sans Fallback";
    src: local("Arial"), local("ArialMT");
    size-adjust: 102.85%;
    ascent-override: 94.31%;
    descent-override: 24.31%;
    line-gap-override: 0%;
}

/* =========================================================================
   1. TOKENS
   ========================================================================= */
:root {
    /* --- Brand palette (unchanged) ------------------------------------- */
    --champagne:      #CDB489;   /* primary accent / fills */
    --champagne-dark: #B89A62;   /* fill hover */
    --champagne-ink:  #8C6E2C;   /* accent as TEXT on light backgrounds */
    --on-champagne:   #241C0C;   /* text sitting on a champagne fill */
    --charcoal:       #2b2b2b;   /* body copy */
    --ink:            #20242C;   /* dark surface: header, footer, dark bands */
    --ink-deep:       #1a1d23;   /* deepest surface: subfooter, topbar */
    --sand:           #F2EEE9;   /* soft beige panels */

    /* --- Derived neutrals (same hue family) ---------------------------- */
    --sand-deep:  #E8E0D4;
    --line:       #E7E1D8;   /* hairline on light */
    --line-dark:  rgba(255, 255, 255, .12);
    --muted:      #62666E;   /* secondary text on light */
    --muted-dark: rgba(255, 255, 255, .68);
    --white:      #FFFFFF;
    --canvas:     #FCFBF9;   /* page background — a whisper of the sand */

    /* The accent as raw channels, so alphas and shadows can be derived from it
       rather than hardcoded. Re-theming then needs only the tokens above. */
    --champagne-rgb:      205, 180, 137;
    --champagne-dark-rgb: 184, 154, 98;

    --champagne-a12: rgba(var(--champagne-rgb), .12);
    --champagne-a24: rgba(var(--champagne-rgb), .24);
    --champagne-a40: rgba(var(--champagne-rgb), .40);

    /* Review stars — Google's own review gold, which is what people are
       conditioned to read as a rating. Deliberately its own token rather than
       the accent, so the stars keep this colour whichever accent the site
       ends up with. */
    --star: #FBBC04;

    /* --- Type ---------------------------------------------------------- */
    --font: "Instrument Sans", "Instrument Sans Fallback", -apple-system,
            BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
            Arial, sans-serif;

    --fs-xs:   0.75rem;
    /* One small-caps label style everywhere (eyebrows, card meta, contact
       labels, footer titles): small, open-tracked, never heavy. */
    --label-size:  0.75rem;
    --label-track: .14em;
    --fs-sm:   0.8125rem;
    --fs-md:   0.9375rem;
    --fs-base: clamp(1rem, 0.97rem + 0.14vw, 1.0625rem);
    --fs-lead: clamp(1.0625rem, 1rem + 0.32vw, 1.1875rem);
    --fs-h4:   clamp(1.125rem, 1.06rem + 0.32vw, 1.3125rem);
    --fs-h3:   clamp(1.3125rem, 1.18rem + 0.62vw, 1.625rem);
    --fs-h2:   clamp(1.75rem, 1.42rem + 1.45vw, 2.625rem);
    --fs-h1:   clamp(2.125rem, 1.6rem + 2.3vw, 3.5rem);

    /* --- Space --------------------------------------------------------- */
    --sp-3: .75rem;  --sp-4: 1rem;
    --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-8: 3rem;

    --gutter:  clamp(1.25rem, 4vw, 2.75rem);
    --section: clamp(3.5rem, 7vw, 6.5rem);
    --maxw:    1220px;

    /* --- Radii & elevation --------------------------------------------- */
    --r-xs: 6px;  --r-sm: 10px;  --r: 14px;  --r-lg: 20px;  --r-xl: 28px;
    --r-full: 999px;

    --shadow-sm: 0 1px 2px rgba(35, 28, 12, .05),
                 0 2px 8px rgba(35, 28, 12, .04);
    --shadow:    0 2px 6px rgba(35, 28, 12, .05),
                 0 12px 28px -8px rgba(35, 28, 12, .12);
    --shadow-lg: 0 4px 12px rgba(35, 28, 12, .06),
                 0 28px 60px -16px rgba(35, 28, 12, .22);

    /* --- Chrome heights (JS-independent layout anchors) ----------------- */
    /* Tall enough to carry the logo at a legible size. It is a stacked,
       portrait-format mark (261x320), so height is what makes it readable —
       at 62px it was only ~51px wide and read as an afterthought. */
    --header-h: 104px;
    --topbar-h: 40px;

    --ease: cubic-bezier(.22, .61, .36, 1);
}

@media (max-width: 991px) {
    :root { --header-h: 88px; --topbar-h: 0px; }
}

/* =========================================================================
   2. RESET & BASE
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* Anchor targets clear the sticky header */
    scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
    margin: 0;
    font-family: var(--font);
    font-size: var(--fs-base);
    line-height: 1.65;
    color: var(--charcoal);
    background: var(--canvas);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
}

img, svg, video, iframe { display: block; max-width: 100%; }
img { height: auto; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; }

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

h1, h2, h3, h4, h5, p, figure, blockquote { margin: 0; }
/* No paragraph ends on a lone word (progressive: ignored where unsupported). */
p { text-wrap: pretty; }
/* Phone numbers in tabular figures, so every digit takes the same width. */
a[href^="tel:"] { font-variant-numeric: tabular-nums; }

hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-6) 0; }

::selection { background: var(--champagne-a40); color: var(--on-champagne); }

/* Visible, on-brand focus for keyboard users only */
:focus-visible {
    outline: 3px solid var(--champagne);
    outline-offset: 3px;
    border-radius: var(--r-xs);
}

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

/* Inline SVG icons (sprite in partials/icons.html). Stroke icons by default;
   `.icon--solid` flips to a filled icon (brand marks, stars). */
.icon {
    display: inline-block; width: 20px; height: 20px; flex: none;
    fill: none; stroke: currentColor;
    stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
    vertical-align: middle;
}
.icon--solid { fill: currentColor; stroke: none; }
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Skip link */
.skip-link {
    position: absolute; top: 0; left: 50%; transform: translate(-50%, -110%);
    z-index: 300; background: var(--champagne); color: var(--on-champagne);
    padding: .75rem 1.25rem; border-radius: 0 0 var(--r-sm) var(--r-sm);
    font-weight: 600; font-size: var(--fs-md);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* =========================================================================
   3. LAYOUT
   ========================================================================= */
.wrap {
    width: 100%;
    max-width: var(--maxw);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.section { padding-block: var(--section); }
.section--sand { background: var(--sand); }
.section--dark { background: var(--ink); color: var(--white); }
/* Section headings on a dark band. Scoped to .sec-head so it can't reach into
   light-surfaced children — the review quotes are white cards sitting ON a
   dark section, and their text must stay dark. */
.section--dark .sec-head h2, .on-dark .sec-head h2 { color: var(--white); }

/* Lifts a section's CONTENT over the section above it, while the section's own
   background still starts at the boundary — so the cards read as floating
   between the two surfaces, as in the previous design.

   The light cards are NOT inside a media query: they must look the same at
   every width. They were previously scoped to >=768px, which left them dark
   and heavy on phones. */
.section--dark.section--overlap .card {
    background: var(--white);
    border-color: transparent;
    box-shadow: 0 26px 50px -22px rgba(0, 0, 0, .65);
}
.section--dark.section--overlap .card:hover { background: var(--white); }
.section--dark.section--overlap .card__title { color: var(--ink); }
.section--dark.section--overlap .card__text { color: var(--muted); }
.section--dark.section--overlap .card--icon .card__icon {
    background: var(--champagne-a24);
    color: var(--champagne-ink);
}

/* The lift itself starts at 992px, and NOT a pixel below, because that is
   exactly where #section-hero gains its `min-height: calc(100vh - 300px)`.
   Below it the hero is only as tall as its content, so there is no spare
   photo to ride up into — on an iPad the cards used to land on top of the
   headline and the CTA. The two breakpoints must stay in lock-step. */
@media (min-width: 992px) {
    .section--overlap { padding-top: 0; }
    .section--overlap > .wrap {
        position: relative;
        z-index: 2;
        margin-top: -130px;
    }
}
/* Taller viewport -> taller hero -> more empty photo under the copy, so the
   cards can ride higher. Verified against the measured gap at each step. */
@media (min-width: 992px) and (min-height: 850px) {
    .section--overlap > .wrap { margin-top: -170px; }
}
@media (min-width: 992px) and (min-height: 1000px) {
    .section--overlap > .wrap { margin-top: -210px; }
}

.grid { display: grid; gap: clamp(1.25rem, 2.5vw, 2rem); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 991px) {
    .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
    .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

/* Split layout: main column + sidebar */
.split {
    display: grid;
    gap: clamp(2rem, 4vw, 3.5rem);
    grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
    align-items: start;
}
.split--even { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; }
@media (max-width: 991px) { .split, .split--even { grid-template-columns: 1fr; } }

.stack > * + * { margin-top: var(--sp-4); }
.center { text-align: center; }

/* =========================================================================
   4. TYPOGRAPHY
   ========================================================================= */
h1, h2, h3, h4, .h1, .h2, .h3, .h4 {
    font-weight: 600;
    line-height: 1.14;
    letter-spacing: -0.022em;
    color: var(--ink);
    text-wrap: balance;
}
h1, .h1 { font-size: var(--fs-h1); }
h2, .h2 { font-size: var(--fs-h2); }
h3, .h3 { font-size: var(--fs-h3); line-height: 1.25; letter-spacing: -0.015em; }
h4, .h4 { font-size: var(--fs-h4); line-height: 1.3; letter-spacing: -0.01em; }

.lead {
    font-size: var(--fs-lead);
    line-height: 1.6;
    color: var(--muted);
    text-wrap: pretty;
}
.section--dark .lead, .on-dark .lead { color: var(--muted-dark); }

.eyebrow {
    display: inline-flex; align-items: center; gap: .7em;
    font-size: var(--label-size); font-weight: 600;
    letter-spacing: var(--label-track); text-transform: uppercase;
    color: var(--champagne-ink);
}
/* A hairline rather than a rounded 2px bar. currentColor keeps it in step
   with the label on light and dark sections alike. */
.eyebrow::before {
    content: ""; width: 24px; height: 1px;
    background: currentColor; opacity: .6;
}
.eyebrow--center::before { display: none; }
.on-dark .eyebrow, .section--dark .eyebrow { color: var(--champagne); }

.accent { color: var(--champagne-ink); }
.on-dark .accent, .section--dark .accent { color: var(--champagne); }

.muted { color: var(--muted); }
.on-dark .muted, .section--dark .muted { color: var(--muted-dark); }

.small { font-size: var(--fs-md); }

/* Section header block */
.sec-head { max-width: 680px; margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.sec-head > * + * { margin-top: var(--sp-4); }
/* The eyebrow belongs to its heading: pulled closer than the lead is. */
.sec-head > .eyebrow + * { margin-top: var(--sp-3); }
.sec-head--center { margin-inline: auto; text-align: center; }

/* Header + action on one line */
.sec-head-row {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: var(--sp-5); flex-wrap: wrap;
    margin-bottom: clamp(2rem, 4vw, 3rem);
}
.sec-head-row .sec-head { margin-bottom: 0; }

/* --- Rich text (WordPress-imported service / about copy) --------------- */
.prose { font-size: var(--fs-base); line-height: 1.75; color: #3a3d43; }
.prose > * + * { margin-top: 1.1em; }
.prose h2 { font-size: var(--fs-h3); margin-top: 2em; }
.prose h3 { font-size: var(--fs-h4); margin-top: 1.9em; }
.prose h4 { font-size: var(--fs-base); margin-top: 1.7em; text-transform: uppercase;
            letter-spacing: .08em; color: var(--champagne-ink); }
.prose h2 + *, .prose h3 + *, .prose h4 + * { margin-top: .7em; }
.prose strong { color: var(--ink); font-weight: 600; }
.prose a { color: var(--champagne-ink); font-weight: 600;
           text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--on-champagne); }
.prose ul, .prose ol { padding-left: 0; }
.prose li {
    position: relative; padding-left: 1.85em; margin-top: .55em;
    list-style: none;
}
.prose ul > li::before {
    content: ""; position: absolute; left: .3em; top: .68em;
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--champagne); box-shadow: 0 0 0 4px var(--champagne-a24);
}
.prose ol { counter-reset: p-ol; }
.prose ol > li { counter-increment: p-ol; }
.prose ol > li::before {
    content: counter(p-ol); position: absolute; left: 0; top: .12em;
    width: 1.5em; height: 1.5em; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--champagne-a24); color: var(--champagne-ink);
    font-size: .78em; font-weight: 600;
}
.prose img { border-radius: var(--r); margin-block: 1.5em; }
.prose blockquote {
    border-left: 3px solid var(--champagne);
    padding: .25em 0 .25em 1.4em; color: var(--ink);
    font-size: var(--fs-lead);
}
.prose table { width: 100%; border-collapse: collapse; }
.prose th, .prose td { border: 1px solid var(--line); padding: .6em .8em; text-align: left; }

/* =========================================================================
   5. BUTTONS & PILLS
   ========================================================================= */
.btn {
    --btn-bg: transparent;
    --btn-fg: var(--ink);
    --btn-bd: transparent;
    display: inline-flex; align-items: center; justify-content: center;
    gap: .6em;
    padding: .95rem 1.6rem;
    border: 1.5px solid var(--btn-bd);
    border-radius: var(--r-sm);
    background: var(--btn-bg);
    color: var(--btn-fg);
    font-size: var(--fs-md); font-weight: 600; line-height: 1.2;
    letter-spacing: .005em;
    text-align: center;
    cursor: pointer;
    transition: background .18s var(--ease), border-color .18s var(--ease),
                color .18s var(--ease), transform .18s var(--ease),
                box-shadow .18s var(--ease);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn .icon { width: 1.15em; height: 1.15em; flex: none; }

.btn--primary {
    --btn-bg: var(--champagne); --btn-fg: var(--on-champagne);
    --btn-bd: var(--champagne);
    box-shadow: 0 4px 14px -4px rgba(var(--champagne-rgb), .7);
}
.btn--primary:hover {
    --btn-bg: var(--champagne-dark); --btn-bd: var(--champagne-dark);
    box-shadow: 0 8px 22px -6px rgba(var(--champagne-dark-rgb), .8);
}

.btn--ghost { --btn-fg: var(--ink); --btn-bd: var(--line); --btn-bg: var(--white); }
.btn--ghost:hover {
    --btn-bd: var(--champagne); --btn-fg: var(--champagne-ink);
    box-shadow: var(--shadow-sm);
}

.btn--outline-light {
    --btn-fg: var(--white); --btn-bd: rgba(255, 255, 255, .45);
}
.btn--outline-light:hover {
    --btn-bg: var(--white); --btn-fg: var(--ink); --btn-bd: var(--white);
}

.btn--wa { --btn-bg: #25D366; --btn-fg: #0A2E16; --btn-bd: #25D366; }
.btn--wa:hover { --btn-bg: #1FB855; --btn-bd: #1FB855; }

.btn--lg { padding: 1.15rem 2rem; font-size: var(--fs-base); }
.btn--sm { padding: .65rem 1.1rem; font-size: var(--fs-sm); }
.btn--block { display: flex; width: 100%; }

/* Text link with a sliding arrow */
.arrow-link {
    display: inline-flex; align-items: center; gap: .5em;
    font-weight: 600; font-size: var(--fs-md);
    color: var(--champagne-ink);
}
.arrow-link .icon {
    width: 1.05em; height: 1.05em;
    transition: transform .22s var(--ease);
}
.arrow-link:hover .icon { transform: translateX(4px); }
.on-dark .arrow-link { color: var(--champagne); }

/* Pill filters (projects) */
.filters { display: flex; flex-wrap: wrap; gap: .55rem; justify-content: center; }
.filter {
    padding: .6rem 1.15rem;
    border: 1.5px solid var(--line); border-radius: var(--r-full);
    background: var(--white);
    font-size: var(--fs-md); font-weight: 600; color: var(--muted);
    transition: all .18s var(--ease);
}
.filter:hover { border-color: var(--champagne); color: var(--ink); }
.filter[aria-current="true"] {
    background: var(--ink); border-color: var(--ink); color: var(--white);
}

/* =========================================================================
   6. HEADER / NAVIGATION
   ========================================================================= */
.topbar {
    background: var(--ink-deep);
    color: var(--muted-dark);
    font-size: var(--fs-sm);
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}
.topbar__inner {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-5); height: var(--topbar-h);
}
.topbar__list { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; }
.topbar__item { display: inline-flex; align-items: center; gap: .5em; white-space: nowrap; }
.topbar__item .icon { width: 15px; height: 15px; color: var(--champagne); flex: none; }
.topbar a:hover { color: var(--champagne); }
@media (max-width: 991px) { .topbar { display: none; } }

.site-header {
    position: sticky; top: 0; z-index: 100;
    background: var(--ink);
    transition: box-shadow .25s var(--ease);
}
.site-header.is-scrolled { box-shadow: 0 6px 26px -10px rgba(0, 0, 0, .6); }

/* Nothing about the header resizes on scroll, so the document never reflows.
   It used to hide the topbar and shrink the bar, which made the header
   flicker: the topbar is exactly as tall as the old scroll threshold, so
   removing it shifted the page up, scroll anchoring pulled scrollY back under
   the threshold, the topbar returned — and it oscillated forever. Now the
   topbar is a sibling that simply scrolls away on its own, the bar and the
   logo keep a constant size, and `.is-scrolled` only paints a shadow. */
.nav-bar {
    display: flex; align-items: center; gap: var(--sp-5);
    height: var(--header-h);
}

.brand { display: flex; align-items: center; flex: none; }
/* Deliberately one fixed size: the logo does NOT shrink on scroll. A mark this
   small already needs every pixel, and shrinking it further as you scroll made
   it harder to read exactly when the header is all that's on screen. */
.brand img { height: 78px; width: auto; }
@media (max-width: 991px) {
    .brand img { height: 72px; }
}

.nav { margin-left: auto; }
.nav__list { display: flex; align-items: center; gap: clamp(.5rem, 1.6vw, 1.5rem); }
.nav__link {
    position: relative;
    display: block; padding: .5rem .25rem;
    color: rgba(255, 255, 255, .88);
    font-size: var(--fs-md); font-weight: 600;
    transition: color .18s var(--ease);
}
.nav__link::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
    height: 2px; border-radius: 2px; background: var(--champagne);
    transform: scaleX(0); transform-origin: left;
    transition: transform .22s var(--ease);
}
.nav__link:hover { color: var(--white); }
.nav__link:hover::after { transform: scaleX(1); }
.nav__link[aria-current="page"] { color: var(--champagne); }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }

/* Phone block + primary CTA on the right */
.header-actions { display: flex; align-items: center; gap: var(--sp-4); flex: none; }

.header-phone {
    display: flex; align-items: center; gap: .65rem;
    color: var(--white);
}
.header-phone__icon {
    display: grid; place-items: center; flex: none;
    width: 42px; height: 42px; border-radius: 50%;
    background: var(--champagne-a12);
    border: 1px solid var(--champagne-a40);
    color: var(--champagne);
}
.header-phone__icon .icon { width: 19px; height: 19px; }
.header-phone__text { display: flex; flex-direction: column; line-height: 1.25; }
.header-phone__label {
    font-size: var(--label-size); font-weight: 600; letter-spacing: var(--label-track);
    text-transform: uppercase; color: var(--champagne);
}
.header-phone__num { font-size: var(--fs-md); font-weight: 600; white-space: nowrap; }
.header-phone__num:hover { color: var(--champagne); }

/* WhatsApp, between the phone block and the quote button */
.header-wa {
    display: grid; place-items: center; flex: none;
    width: 46px; height: 46px; border-radius: 50%;
    background: #25D366; color: #0A2E16;
    transition: background .18s var(--ease), transform .18s var(--ease);
}
.header-wa:hover { background: #1FB855; color: #0A2E16; transform: translateY(-1px); }
.header-wa .icon { width: 26px; height: 26px; }

@media (max-width: 1180px) { .header-phone { display: none; } }
@media (max-width: 991px) {
    /* Below the burger breakpoint the drawer and the sticky bottom bar both
       carry WhatsApp, so a third entry point here would just crowd the bar. */
    .nav, .header-actions .btn, .header-wa { display: none; }
}

/* Burger */
.burger {
    display: none;
    margin-left: auto;
    width: 46px; height: 46px; flex: none;
    border: 1px solid var(--line-dark); border-radius: var(--r-sm);
    background: rgba(255, 255, 255, .06);
    cursor: pointer;
    padding: 0;
    place-items: center;
}
.burger__box { display: block; width: 20px; height: 14px; position: relative; }
.burger__box span {
    position: absolute; left: 0; width: 100%; height: 2px; border-radius: 2px;
    background: var(--white);
    transition: transform .25s var(--ease), opacity .2s var(--ease), top .25s var(--ease);
}
.burger__box span:nth-child(1) { top: 0; }
.burger__box span:nth-child(2) { top: 6px; }
.burger__box span:nth-child(3) { top: 12px; }
@media (max-width: 991px) { .burger { display: grid; } }

/* Burger morphs into a close cross while the menu is open. Driven off
   aria-expanded, which the script already maintains — no extra class needed. */
.burger[aria-expanded="true"] { background: var(--champagne-a24); border-color: var(--champagne-a40); }
.burger[aria-expanded="true"] .burger__box span:nth-child(1) { top: 6px; transform: rotate(45deg); }
.burger[aria-expanded="true"] .burger__box span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] .burger__box span:nth-child(3) { top: 6px; transform: rotate(-45deg); }

/* Mobile menu: drops down from under the header rather than sliding in from
   the side. The header itself never moves — no second logo, no second close
   button — so the bar you tapped stays exactly where it was. Sits at z-index
   99, just under the header's 100, so it unrolls behind the bar. */
.drawer {
    position: fixed;
    top: var(--header-h); left: 0; right: 0; bottom: 0;
    z-index: 99;
    background: var(--ink);
    border-top: 1px solid var(--line-dark);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* clip-path reveals downwards; visibility keeps it out of the tab order
       while closed and is delayed so it doesn't cut the animation short. */
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
    transition: clip-path .34s var(--ease), visibility 0s linear .34s;
}
.drawer.is-open {
    clip-path: inset(0 0 0 0);
    visibility: visible;
    transition: clip-path .34s var(--ease), visibility 0s;
}

/* The panel takes focus when the menu opens so the keyboard and screen
   reader land inside it. It is a container, not a control, so it must not
   draw a ring of its own — the links it holds still do. */
.drawer:focus, .drawer:focus-visible { outline: none; }

.drawer__body {
    padding: var(--sp-6) var(--gutter) calc(var(--sp-8) + env(safe-area-inset-bottom));
    display: flex; flex-direction: column; gap: var(--sp-6);
}
.drawer__nav { display: flex; flex-direction: column; }
.drawer__link {
    display: flex; align-items: center; justify-content: space-between;
    padding: 1rem 0;
    border-bottom: 1px solid var(--line-dark);
    color: var(--white); font-size: 1.2rem; font-weight: 600;
}
.drawer__link .icon { width: 18px; height: 18px; color: var(--champagne); }
.drawer__link[aria-current="page"] { color: var(--champagne); }

.drawer__contact { display: flex; flex-direction: column; gap: var(--sp-3); }
.drawer__phone {
    display: flex; align-items: center; gap: .7rem;
    padding: .9rem 1.1rem; border-radius: var(--r-sm);
    background: rgba(255, 255, 255, .06);
    border: 1px solid var(--line-dark);
    color: var(--white); font-weight: 600;
}
.drawer__phone .icon { width: 20px; height: 20px; color: var(--champagne); flex: none; }

body.is-locked { overflow: hidden; }

/* =========================================================================
   8. CARDS
   ========================================================================= */
.card {
    position: relative;
    display: flex; flex-direction: column;
    background: var(--white);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
    transition: transform .28s var(--ease), box-shadow .28s var(--ease),
                border-color .28s var(--ease);
}
.card:hover {
    transform: translateY(-3px);
    border-color: var(--champagne-a40);
    box-shadow: var(--shadow);
}
.card__media { position: relative; overflow: hidden; aspect-ratio: 16 / 10; background: var(--sand); }
.card__media img { width: 100%; height: 100%; object-fit: cover;
                   transition: transform .6s var(--ease); }
.card:hover .card__media img { transform: scale(1.03); }

/* Trade icon floating on the image (service cards) */
.card__chip {
    position: absolute; left: 1rem; bottom: 1rem;
    display: grid; place-items: center;
    width: 46px; height: 46px; border-radius: var(--r-sm);
    background: rgba(255, 255, 255, .94);
    color: var(--champagne-ink);
    box-shadow: var(--shadow-sm);
    backdrop-filter: blur(6px);
}
.card__chip .icon { width: 24px; height: 24px; }

.card__body {
    display: flex; flex-direction: column; flex: 1;
    padding: clamp(1.25rem, 2.4vw, 1.75rem);
    gap: .7rem;
}
.card__title {
    font-size: var(--fs-h4);
    /* Last-resort containment: a word longer than its card breaks instead of
       spilling out. (No hyphens:auto here — combined with the headings'
       text-wrap: balance, browsers hyphenate words that would fit, just to
       even out the lines.) */
    overflow-wrap: break-word;
}
/* Icon cards (why-us, service guarantees) have short titles; greedy wrapping
   suits them better than balance, and it lets the &shy; in "Accompagnement"
   break only where the word truly does not fit — the four-column grid at
   992–1100px, where a title gets ~145px and the word needs 173. */
.card--icon .card__title { text-wrap: wrap; }
.card__text {
    color: var(--muted); font-size: var(--fs-md); line-height: 1.6;
    /* Keep every card's teaser the same length so the grid stays even */
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
}
.card__foot { margin-top: auto; padding-top: .5rem; }

/* Whole-card link: covers the card without nesting interactive elements */
.card__link::after { content: ""; position: absolute; inset: 0; }
.card a:not(.card__link) { position: relative; z-index: 1; }

/* Project card — image-led, caption overlaid.
   Media and body share one grid cell instead of the body being absolutely
   positioned: that keeps `.card` as the containing block, so the stretched
   `.card__link::after` covers the whole card (image included) and not just
   the caption strip. */
.card--project { border: 0; border-radius: var(--r-lg); display: grid;
                 container-type: inline-size; }
.card--project .card__media,
.card--project .card__body { grid-area: 1 / 1; }
.card--project .card__media { aspect-ratio: 4 / 3; }
/* A narrow card (three columns at 992–1100px, ~283px) left the caption
   covering the whole photo, sometimes overflowing it. Below 330px of card
   width the picture goes square to keep room above the caption. Keyed to
   the card's own width, not the viewport, so it holds wherever the card
   is used. (The phone rail sets its own portrait ratio, more specific.) */
@container (max-width: 330px) {
    .card--project .card__media { aspect-ratio: 1 / 1; }
}
.card--project .card__body {
    /* The scrim. It used to fade out across the whole caption, so the eyebrow
       and title sat on a nearly transparent veil: over a bright photo (a white
       facade) they fell to 1.5–2:1. Now the veil stays at 82%+ behind every
       line of text — enough for 4.5:1 even over pure white — and only fades in
       a band ABOVE the text, sized by --scrim-fade, which is also the top
       padding so the two can never drift apart. 76% is the floor for 4.5:1
       with the eyebrow below; see the contrast check in the commit. */
    --scrim: 20, 23, 28;
    --scrim-fade: clamp(1.75rem, 3.5vw, 2.5rem);
    align-self: end; z-index: 1;
    padding: var(--scrim-fade) clamp(1.25rem, 3vw, 1.6rem) clamp(1.25rem, 3vw, 1.6rem);
    background: linear-gradient(to top,
                                rgba(var(--scrim), .9) 0%,
                                rgba(var(--scrim), .76) calc(100% - var(--scrim-fade)),
                                rgba(var(--scrim), 0) 100%);
    color: var(--white);
    gap: .3rem;
}
.card--project .card__title { color: var(--white); font-size: var(--fs-h4); }
/* The summary sits on the dark veil: it needs a light tone, not the grey
   (--muted) that .card__text uses on white cards — that was 1.2:1 here.
   Two lines, not three: it is a teaser under the title, and every extra
   line of text is a line of photo lost under the veil. */
.card--project .card__text { color: rgba(255, 255, 255, .88); -webkit-line-clamp: 2; }
.card--project .card__meta {
    font-size: var(--label-size); font-weight: 600; letter-spacing: var(--label-track);
    /* A lighter tint of the accent on the dark veil: plain --champagne needs
       an 82% veil to reach 4.5:1 over a white photo, this one 76%, so more of
       the picture shows through. Derived, so it follows the accent. */
    text-transform: uppercase; color: color-mix(in srgb, var(--champagne) 60%, #fff);
}

/* Icon card — no image, for "why us" / guarantees */
.card--icon { padding: clamp(1.5rem, 3vw, 2rem); gap: .8rem; }
.card--icon .card__icon {
    display: grid; place-items: center;
    width: 52px; height: 52px; border-radius: var(--r-sm);
    background: var(--champagne-a24); color: var(--champagne-ink);
    margin-bottom: .3rem;
}
.card--icon .card__icon .icon { width: 26px; height: 26px; }
.card--icon .card__text { -webkit-line-clamp: unset; display: block; }

.section--dark .card {
    background: rgba(255, 255, 255, .05);
    border-color: var(--line-dark);
}
.section--dark .card:hover { background: rgba(255, 255, 255, .08); }
.section--dark .card__title { color: var(--white); }
.section--dark .card__text { color: var(--muted-dark); }
.section--dark .card--icon .card__icon {
    background: var(--champagne-a12); color: var(--champagne);
}

/* Sand-surface variant so cards stay visible on a sand section */
.section--sand .card { background: var(--white); }

/* =========================================================================
   9. PROCESS STEPS
   ========================================================================= */
.steps {
    display: grid; grid-template-columns: repeat(4, 1fr);
    gap: clamp(1.5rem, 3vw, 2.25rem);
    counter-reset: step;
}
@media (max-width: 991px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }

.step { position: relative; counter-increment: step; }
.step__num {
    position: relative; z-index: 1;
    display: grid; place-items: center;
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--champagne); color: var(--on-champagne);
    font-size: 1.25rem; font-weight: 600;
    margin-bottom: var(--sp-4);
}
.step__num::before { content: counter(step, decimal-leading-zero); }
/* Connector line between steps */
.step:not(:last-child)::after {
    content: ""; position: absolute; top: 28px; left: 68px; right: -1.5rem;
    height: 2px;
    background: repeating-linear-gradient(to right,
        var(--champagne-a40) 0 8px, transparent 8px 16px);
}
@media (max-width: 991px) {
    .step:nth-child(2n)::after { display: none; }
}
@media (max-width: 560px) { .step::after { display: none; } }
.step__title { font-size: var(--fs-h4); margin-bottom: .5rem; }
.step__text { color: var(--muted); font-size: var(--fs-md); }
.section--dark .step__text { color: var(--muted-dark); }
.section--dark .step__title { color: var(--white); }

/* =========================================================================
   10. TESTIMONIALS
   ========================================================================= */
.quote {
    display: flex; flex-direction: column; gap: var(--sp-4);
    padding: clamp(1.5rem, 3vw, 2.25rem);
    background: var(--white);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    height: 100%;
}
.quote__stars { display: flex; gap: 3px; color: var(--star); }
.quote__stars .icon { width: 18px; height: 18px; }
.quote__text { font-size: var(--fs-base); line-height: 1.7; color: #3a3d43; flex: 1; }
.quote__author { display: flex; align-items: center; gap: .85rem;
                 padding-top: var(--sp-4); border-top: 1px solid var(--line); }
.quote__avatar {
    display: grid; place-items: center; flex: none;
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--champagne-a24); color: var(--champagne-ink);
    font-weight: 600; font-size: var(--fs-md);
}
.quote__name { font-weight: 600; color: var(--ink); line-height: 1.3; }
.quote__meta { font-size: var(--fs-sm); color: var(--muted); }

/* =========================================================================
   11. FAQ (native <details>, no JS)
   ========================================================================= */
.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-4);
    padding: 1.35rem 0;
    font-size: var(--fs-h4); font-weight: 600; color: var(--ink);
    cursor: pointer;
    list-style: none;
    transition: color .18s var(--ease);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--champagne-ink); }
/* The +/- toggle is shared with the services accordion (section 11b). Selectors
   are grouped rather than duplicated; the two differ only in how the open state
   is expressed — [open] on <details>, .is-open on the JS-driven one. */
.faq__sign, .svc__sign {
    position: relative; flex: none;
    width: 32px; height: 32px; border-radius: 50%;
    border: 1.5px solid var(--line);
    transition: background .2s var(--ease), border-color .2s var(--ease),
                transform .25s var(--ease);
}
.faq__sign::before, .faq__sign::after,
.svc__sign::before, .svc__sign::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 12px; height: 2px; border-radius: 2px;
    background: var(--champagne-ink);
    transform: translate(-50%, -50%);
    transition: transform .25s var(--ease), opacity .2s var(--ease);
}
.faq__sign::after, .svc__sign::after { transform: translate(-50%, -50%) rotate(90deg); }

.faq__item[open] .faq__sign,
.svc__item.is-open .svc__sign { background: var(--champagne); border-color: var(--champagne); }
.faq__item[open] .faq__sign::before, .faq__item[open] .faq__sign::after,
.svc__item.is-open .svc__sign::before,
.svc__item.is-open .svc__sign::after { background: var(--on-champagne); }
.faq__item[open] .faq__sign::after,
.svc__item.is-open .svc__sign::after { transform: translate(-50%, -50%) rotate(0); }
.faq__a { padding: 0 0 1.5rem; max-width: 62ch; color: var(--muted); }
.faq__a > * + * { margin-top: .8em; }

/* =========================================================================
   11b. SERVICES ACCORDION (homepage)
   One entry open at a time, paired with a cross-fading image alongside.
   ========================================================================= */
.svc {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 3.5rem);
    align-items: start;
}

.svc__list { border-top: 1px solid var(--line); }
.svc__item { border-bottom: 1px solid var(--line); }
.svc__head { margin: 0; font-size: inherit; }

.svc__btn {
    width: 100%;
    display: flex; align-items: center; gap: .9rem;
    padding: 1.1rem 0;
    background: none; border: 0; cursor: pointer;
    text-align: left; color: var(--ink);
    font-size: var(--fs-h4); font-weight: 600; line-height: 1.3;
    letter-spacing: -0.01em;
    transition: color .18s var(--ease);
}
.svc__btn:hover { color: var(--champagne-ink); }
.svc__title { flex: 1; min-width: 0; }

.svc__icon {
    display: grid; place-items: center; flex: none;
    width: 44px; height: 44px; border-radius: 13px;
    background: var(--champagne-a24); color: var(--champagne-ink);
    transition: background .22s var(--ease), color .22s var(--ease);
}
.svc__icon .icon { width: 23px; height: 23px; }
/* The open entry's icon fills in, so the eye can find it without reading */
.svc__item.is-open .svc__icon { background: var(--champagne); color: var(--on-champagne); }

/* 0fr -> 1fr animates cleanly to the panel's natural height, which a plain
   height transition cannot do without hard-coding a value. */
.svc__panel {
    display: grid; grid-template-rows: 1fr;
    transition: grid-template-rows .34s var(--ease);
}
.js .svc__item:not(.is-open) .svc__panel { grid-template-rows: 0fr; }
.svc__panel-inner { overflow: hidden; }
.svc__text { color: var(--muted); max-width: 58ch; }
.svc__panel-inner > * + * { margin-top: .9rem; }
.svc__panel-inner { padding-bottom: 1.35rem; }
.js .svc__item:not(.is-open) .svc__panel-inner { padding-bottom: 0; }

.svc__media { position: sticky; top: calc(var(--header-h) + 1.5rem); }
.svc__frame {
    position: relative;
    aspect-ratio: 4 / 4.3;
    border-radius: var(--r-xl);
    overflow: hidden;
    background: var(--sand);
    box-shadow: var(--shadow);
}
.svc__img {
    position: absolute; inset: 0;
    width: 100%; height: 100%; object-fit: cover;
    opacity: 0;
    transition: opacity .55s var(--ease);
}
.svc__img.is-active { opacity: 1; }
/* Stand-in for a service that has no photo yet — cross-fades like the images */
.svc__img--blank {
    display: grid; place-items: center;
    background: var(--sand);
    color: var(--champagne-ink);
}
.svc__img--blank .icon { width: 88px; height: 88px; opacity: .5; }

@media (max-width: 899px) {
    .svc { grid-template-columns: 1fr; }
    /* Image first, but NOT pinned. Stacked, the list scrolls up underneath a
       sticky image instead of alongside it, so the pin simply parked a picture
       on top of the text you were trying to read. It scrolls away normally. */
    .svc__media { order: -1; position: static; }
    .svc__frame { aspect-ratio: 16 / 10; }
}
@media (prefers-reduced-motion: reduce) {
    .svc__img { transition: none; }
}

/* =========================================================================
   12. CTA BANDS
   ========================================================================= */
.cta {
    position: relative;
    background:
        radial-gradient(760px 380px at 12% 0%, rgba(var(--champagne-rgb), .22), transparent 66%),
        var(--ink);
    color: var(--white);
    border-radius: var(--r-xl);
    padding: clamp(2rem, 5vw, 3.5rem);
    overflow: hidden;
}
.cta__grid {
    display: grid; grid-template-columns: minmax(0, 1.4fr) auto;
    gap: var(--sp-6); align-items: center;
}
@media (max-width: 860px) { .cta__grid { grid-template-columns: 1fr; } }
.cta__title { color: var(--white); font-size: var(--fs-h2); }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
@media (max-width: 480px) { .cta__actions .btn { width: 100%; } }

/* =========================================================================
   13. PAGE HEAD (interior pages)
   ========================================================================= */
.pagehead {
    background:
        radial-gradient(760px 320px at 85% 0%, var(--champagne-a24), transparent 62%),
        var(--sand);
    padding-block: clamp(2rem, 4vw, 3.25rem) clamp(2.25rem, 4.5vw, 3.5rem);
    border-bottom: 1px solid var(--sand-deep);
}
.pagehead__title { margin-top: var(--sp-3); max-width: 20ch; }
.pagehead__lead { margin-top: var(--sp-4); max-width: 62ch; }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem;
          font-size: var(--fs-md); color: var(--muted); }
.crumbs a:hover { color: var(--champagne-ink); }
.crumbs .icon { width: 14px; height: 14px; opacity: .55; }
.crumbs [aria-current="page"] { color: var(--ink); font-weight: 600; }

/* =========================================================================
   14. FORMS
   ========================================================================= */
.form-grid {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4);
}
.field--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

.field { display: flex; flex-direction: column; gap: .45rem; }
.field__label {
    font-size: var(--fs-md); font-weight: 600; color: var(--ink);
}
.field__label .req { color: #C0392B; }
.field__label .field__optional { font-weight: 400; color: var(--muted); font-size: var(--fs-sm); }
.field__hint { font-size: var(--fs-sm); color: var(--muted); }

.field input[type="text"], .field input[type="email"], .field input[type="tel"],
.field select, .field textarea {
    width: 100%;
    padding: .85rem 1rem;
    font: inherit; font-size: var(--fs-md);
    color: var(--charcoal);
    background: var(--white);
    border: 1.5px solid var(--line);
    border-radius: var(--r-sm);
    transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
    appearance: none;
}
.field textarea { min-height: 150px; resize: vertical; line-height: 1.6; }
.field select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2362666E' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 18px;
    padding-right: 2.75rem;
}
.field :is(input, select, textarea):focus {
    outline: none;
    border-color: var(--champagne);
    box-shadow: 0 0 0 4px var(--champagne-a24);
}
.field ::placeholder { color: #9AA0A8; }

/* Consent / opt-in checkbox */
.field--check { flex-direction: row; align-items: flex-start; gap: .7rem; }
.field--check input[type="checkbox"] {
    width: 20px; height: 20px; flex: none; margin-top: 2px;
    accent-color: var(--champagne-ink); cursor: pointer;
}
.field--check .field__label { font-weight: 500; color: var(--muted); cursor: pointer; }

.field .errorlist { margin-top: .1rem; }
.field .errorlist li { font-size: var(--fs-sm); font-weight: 600; color: #C0392B; }
.field:has(.errorlist) :is(input, select, textarea) { border-color: #E0A9A2; }

/* Contact panel */
.panel {
    background: var(--white);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: clamp(1.5rem, 3vw, 2rem);
}
.panel--sand { background: var(--sand); border-color: var(--sand-deep); }

.contact-list { display: flex; flex-direction: column; gap: var(--sp-4); }
.contact-row { display: flex; align-items: flex-start; gap: .9rem; }
.contact-row__icon {
    display: grid; place-items: center; flex: none;
    width: 42px; height: 42px; border-radius: var(--r-sm);
    background: var(--champagne-a24); color: var(--champagne-ink);
}
.contact-row__icon .icon { width: 20px; height: 20px; }
.contact-row__label {
    display: block;
    font-size: var(--label-size); font-weight: 600; letter-spacing: var(--label-track);
    text-transform: uppercase; color: var(--muted);
}
.contact-row__value { display: block; font-weight: 600; color: var(--ink); line-height: 1.45; }
.contact-row__value a:hover { color: var(--champagne-ink); }

.map-frame {
    border-radius: var(--r); overflow: hidden; border: 1px solid var(--line);
    line-height: 0;
}
.map-frame iframe { width: 100%; height: 100%; border: 0; }

/* Inline CTA inside a panel: text left, buttons right */
.panel-cta {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-5); align-items: center;
}
.panel-cta__actions { display: flex; flex-wrap: wrap; gap: .75rem; }
@media (max-width: 700px) { .panel-cta { grid-template-columns: 1fr; } }

/* Sticky sidebar (service detail, contact) */
.sticky-side { position: sticky; top: calc(var(--header-h) + 1.5rem); }
@media (max-width: 991px) { .sticky-side { position: static; } }

/* =========================================================================
   15. GALLERY & LIGHTBOX
   ========================================================================= */
.gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
@media (max-width: 640px) { .gallery { grid-template-columns: repeat(2, 1fr); } }

.gallery__item {
    position: relative; display: block;
    aspect-ratio: 1; overflow: hidden;
    border-radius: var(--r); background: var(--sand);
    cursor: zoom-in;
}
.gallery__item img { width: 100%; height: 100%; object-fit: cover;
                     transition: transform .5s var(--ease); }
.gallery__item:hover img { transform: scale(1.04); }
.gallery__item::after {
    content: ""; position: absolute; inset: 0;
    background: rgba(32, 36, 44, .3);
    opacity: 0; transition: opacity .25s var(--ease);
}
.gallery__item:hover::after { opacity: 1; }

/* A native <dialog> opened with showModal(): the browser supplies the top
   layer, the focus trap, Escape and the inert page. Only the UA box is reset
   so it fills the viewport; display stays the UA's until [open]. */
.lightbox {
    position: fixed; inset: 0;
    width: 100%; height: 100%; max-width: none; max-height: none;
    margin: 0; border: 0;
    place-items: center;
    padding: clamp(1rem, 4vw, 3rem);
    background: rgba(15, 17, 21, .93);
    backdrop-filter: blur(4px);
}
.lightbox[open] { display: grid; }
body:has(.lightbox[open]) { overflow: hidden; }
.lightbox__img {
    max-width: min(1100px, 100%); max-height: 84vh;
    width: auto; object-fit: contain;
    border-radius: var(--r); box-shadow: var(--shadow-lg);
}
.lightbox__caption {
    margin-top: 1rem; text-align: center;
    color: rgba(255, 255, 255, .8); font-size: var(--fs-md);
}
.lightbox__btn {
    position: absolute;
    display: grid; place-items: center;
    width: 52px; height: 52px; border-radius: 50%;
    background: rgba(255, 255, 255, .12); color: var(--white);
    border: 1px solid rgba(255, 255, 255, .2);
    cursor: pointer; transition: background .18s var(--ease);
}
.lightbox__btn:hover { background: rgba(255, 255, 255, .24); }
.lightbox__btn .icon { width: 24px; height: 24px; }
.lightbox__close { top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem); }
.lightbox__prev { left: clamp(.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: clamp(.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
@media (max-width: 640px) {
    .lightbox__prev { left: .5rem; }
    .lightbox__next { right: .5rem; }
    .lightbox__btn { width: 44px; height: 44px; }
}

/* Horizontal snap rail (project showcase on small screens) */
@media (max-width: 640px) {
    .rail {
        display: grid;
        grid-template-columns: none;   /* beat .grid--3's single-column stack */
        grid-auto-flow: column;
        grid-auto-columns: minmax(78%, 1fr);
        gap: var(--sp-4);
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        /* Bleed to the screen edges so cards peek in from the side */
        margin-inline: calc(var(--gutter) * -1);
        padding-inline: var(--gutter);
        padding-bottom: .5rem;
        scrollbar-width: none;
    }
    .rail::-webkit-scrollbar { display: none; }
    .rail > * { scroll-snap-align: start; }
    /* Rail cards are ~78% of a phone screen: at 4:3 the caption covered all
       but a sliver of the photo. Portrait gives the picture room above it,
       and in a horizontal rail the extra height costs no page length. */
    .rail .card--project .card__media { aspect-ratio: 4 / 5; }
}

/* =========================================================================
   16. SERVICE NAV (sidebar list on service detail)
   ========================================================================= */
.side-nav { display: flex; flex-direction: column; }
.side-nav__link {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3);
    padding: .85rem 0;
    border-bottom: 1px solid var(--line);
    font-weight: 600; color: var(--charcoal);
    transition: color .18s var(--ease), padding-left .18s var(--ease);
}
.side-nav__link .icon { width: 16px; height: 16px; color: var(--champagne);
                        opacity: 0; transition: opacity .18s var(--ease); }
.side-nav__link:hover { color: var(--champagne-ink); padding-left: .35rem; }
.side-nav__link:hover .icon { opacity: 1; }
.side-nav__link[aria-current="page"] {
    color: var(--champagne-ink); font-weight: 600;
}
.side-nav__link[aria-current="page"] .icon { opacity: 1; }

/* Prev / next pager */
.pager {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3); flex-wrap: wrap;
}

/* =========================================================================
   17. FOOTER
   ========================================================================= */
.site-footer { background: var(--ink); color: var(--muted-dark); }
.footer__grid {
    display: grid;
    grid-template-columns: 1.5fr 1fr 1fr 1.2fr;
    gap: clamp(2rem, 4vw, 3rem);
    padding-block: clamp(3rem, 6vw, 4.5rem);
}
@media (max-width: 991px) { .footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .footer__grid { grid-template-columns: 1fr; } }

.footer__logo { height: 78px; width: auto; margin-bottom: var(--sp-4); }
.footer__title {
    color: var(--white); font-size: var(--label-size); font-weight: 600;
    letter-spacing: var(--label-track); text-transform: uppercase;
    margin-bottom: var(--sp-4);
}
.footer__list { display: flex; flex-direction: column; gap: .6rem; }
.footer__list a:hover { color: var(--champagne); }
/* Standalone links, not inline in a sentence, so the 24px minimum target size
   applies at every width — they were 21px on a phone and 23px on desktop.
   These are also the "call us" links, so worth being generous with. */
.footer__list a,
.footer__contact-row a { display: inline-block; padding-block: .3rem; }
.footer__contact { display: flex; flex-direction: column; gap: .8rem; }
.footer__contact-row { display: flex; align-items: flex-start; gap: .65rem; }
.footer__contact-row .icon { width: 17px; height: 17px; color: var(--champagne);
                             flex: none; margin-top: 4px; }
.footer__contact-row a:hover { color: var(--champagne); }

.socials { display: flex; gap: .6rem; margin-top: var(--sp-5); }
.social {
    display: grid; place-items: center;
    width: 40px; height: 40px; border-radius: 50%;
    background: rgba(255, 255, 255, .07);
    border: 1px solid var(--line-dark);
    color: var(--white);
    transition: background .18s var(--ease), color .18s var(--ease),
                transform .18s var(--ease);
}
.social:hover { background: var(--champagne); color: var(--on-champagne);
                border-color: var(--champagne); transform: translateY(-1px); }
.social .icon { width: 18px; height: 18px; }

.subfooter {
    background: var(--ink-deep);
    border-top: 1px solid var(--line-dark);
    font-size: var(--fs-md);
}
.subfooter__inner {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-4); flex-wrap: wrap;
    padding-block: 1.25rem;
}
@media (max-width: 640px) { .subfooter__inner { justify-content: center; text-align: center; } }

/* Areas served — plain text list, good for local SEO */
.area-list { display: flex; flex-wrap: wrap; gap: .5rem; }
.area-list li {
    padding: .35rem .8rem; border-radius: var(--r-full);
    background: var(--champagne-a12); border: 1px solid var(--champagne-a24);
    font-size: var(--fs-md); color: var(--ink);
}
.section--dark .area-list li { color: var(--white); }

/* =========================================================================
   18. FLOATING / STICKY ACTIONS
   ========================================================================= */
.wa-float {
    position: fixed; right: 22px; bottom: 22px; z-index: 90;
    display: grid; place-items: center;
    width: 60px; height: 60px; border-radius: 50%;
    background: #25D366; color: #0A2E16;
    box-shadow: 0 10px 26px -6px rgba(37, 211, 102, .6);
    transition: transform .2s var(--ease), background .2s var(--ease);
}
.wa-float:hover { background: #1FB855; transform: scale(1.04); }
.wa-float .icon { width: 32px; height: 32px; }

/* Sticky call/quote bar — phones only. This is the main mobile conversion path. */
.action-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 95;
    display: none;
    grid-auto-flow: column; grid-auto-columns: 1fr;
    gap: 1px;
    background: var(--line);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
    box-shadow: 0 -6px 24px -10px rgba(0, 0, 0, .3);
}
.action-bar__btn {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .2rem;
    padding: .65rem .35rem;
    background: var(--white);
    font-size: var(--fs-xs); font-weight: 600;
    color: var(--ink);
}
.action-bar__btn .icon { width: 21px; height: 21px; }
.action-bar__btn--call .icon { color: var(--champagne-ink); }
.action-bar__btn--wa .icon { color: #128C7E; }
.action-bar__btn--quote { background: var(--champagne); color: var(--on-champagne); }

@media (max-width: 767px) {
    .action-bar { display: grid; }
    /* Keep the bar from covering the end of the page */
    body { padding-bottom: 66px; }
    .wa-float { display: none; }
}

/* =========================================================================
   18b. MOBILE REFINEMENTS
   ========================================================================= */
@media (max-width: 767px) {
    /* iOS Safari zooms the whole page when a focused field is under 16px.
       On the form that generates the leads, that meant every tap zoomed in and
       left the visitor pinching back out. 16px is the threshold, not a
       preference. */
    .field input[type="text"],
    .field input[type="email"],
    .field input[type="tel"],
    .field select,
    .field textarea { font-size: 16px; }

    /* Small buttons (the project pager) were 38px; give them a full-size
       target now that they are the main way through the gallery on a phone. */
    .btn--sm { padding-top: .85rem; padding-bottom: .85rem; }
}

/* =========================================================================
   19. MOTION
   ========================================================================= */
/* Reveal-on-scroll is opt-in from JS: app.js adds `.js` to <html> before
   anything paints. If the script never loads, nothing is ever hidden. */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }
/* Stagger children of a revealed grid */
.js [data-reveal-group] > * { transition-delay: calc(var(--i, 0) * 70ms); }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
    [data-reveal] { opacity: 1; transform: none; }
}

/* =========================================================================
   20. PRINT
   ========================================================================= */
@media print {
    .site-header, .site-footer, .action-bar, .wa-float, .drawer,
    .cta, .btn { display: none !important; }
    body { padding: 0; background: #fff; color: #000; }
}

/* =========================================================================
   21. LEGACY HERO
   The homepage hero restored from the pre-redesign design (commit e97febb),
   at the explicit request to keep it identical on desktop and mobile.

   The markup in core/home.html is the original, so the theme classes it used
   (.container/.row/.col-lg-*, .de-front, .overlay-bg, .btn-line,
   .spacer-double) had to come back too. Rather than restore Bootstrap
   and the theme sheets for one section, the exact rules that applied to this
   hero were extracted from the old style.css / custom-carpenter.css /
   gmconcept.css and inlined below, every one scoped under #section-hero so
   nothing leaks into the rest of the site. `.lead` in particular is also a
   design-system class; the id scope keeps the two apart.
   ========================================================================= */
#section-hero {
    position: relative;
    padding: 45px 0;
    background: #18191b;
    color: #fff;
    /* Instrument Sans is now the site-wide face (see --font); the hero no
       longer needs to declare it on its own. */

    /* Parallax depth — the single place to tune it. The image is overscanned
       by this much top and bottom, and travels exactly that far as the section
       crosses the viewport. app.js reads this value, so CSS and JS cannot
       drift apart. Bigger = stronger. */
    --parallax-overscan: 35%;
}
#section-hero.gmc-hero {
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}
@media (min-width: 992px) {
    /* The reserve subtracted here is everything that has to share the first
       screen with the hero: the topbar (41px) and header (104px) stacked above
       it, plus ~155px of the following section left showing at the fold so it
       is visibly there on landing. The old design reserved only 200px, which
       put the hero's bottom edge almost exactly on the fold.
       max() keeps a sensible floor on short viewports. */
    #section-hero { min-height: max(520px, calc(100vh - 300px)); }
}

/* --- the parallax image (was jarallax) ------------------------------- */
/* Overscanned top and bottom so app.js can translate it within the section
   without ever exposing an edge. With JS off it simply sits centred. */
#section-hero .jarallax-img {
    position: absolute;
    left: 0; width: 100%;
    top: calc(-1 * var(--parallax-overscan));
    height: calc(100% + 2 * var(--parallax-overscan));
    object-fit: cover;
    z-index: 0;
    will-change: transform;
}

#section-hero .de-front { position: relative; z-index: 5; width: 100%; }

#section-hero .overlay-bg,
#section-hero .overlay-bg.t2 {
    position: absolute; top: 0; left: 0;
    width: 100%; height: 100%;
    z-index: 1;
    background: linear-gradient(100deg,
        rgba(15, 22, 26, .86) 0%,
        rgba(15, 22, 26, .70) 45%,
        rgba(15, 22, 26, .58) 100%);
    opacity: 1;
}

/* --- Bootstrap 5 grid, only what this hero uses ---------------------- */
#section-hero .container {
    width: 100%;
    margin-right: auto; margin-left: auto;
    padding-right: .75rem; padding-left: .75rem;
}
@media (min-width: 576px)  { #section-hero .container { max-width: 540px; } }
@media (min-width: 768px)  { #section-hero .container { max-width: 720px; } }
@media (min-width: 992px)  { #section-hero .container { max-width: 960px; } }
@media (min-width: 1200px) { #section-hero .container { max-width: 1140px; } }
@media (min-width: 1400px) { #section-hero .container { max-width: 1320px; } }

#section-hero .row {                       /* .row.g-4 */
    display: flex; flex-wrap: wrap;
    margin-top: -1.5rem; margin-right: -.75rem; margin-left: -.75rem;
}
#section-hero .row > * {
    flex-shrink: 0; width: 100%; max-width: 100%;
    padding-right: .75rem; padding-left: .75rem;
    margin-top: 1.5rem;
}
#section-hero .justify-content-between { justify-content: space-between; }
#section-hero .align-items-center { align-items: center; }
@media (min-width: 992px) {
    #section-hero .col-lg-6 { flex: 0 0 auto; width: 50%; }
    #section-hero .col-lg-4 { flex: 0 0 auto; width: 33.33333333%; }

    /* The two buttons need ~426px side by side, but the 33% column is only
       380px at a 1200px viewport — so they wrapped, and `ms-2` left the second
       one indented 8px beneath the first. (The original design had this too.)
       Laying the column out as a flex row lets them share a line where there
       is room, and go full width, flush-aligned, where there isn't. */
    #section-hero .col-lg-4 { display: flex; flex-wrap: wrap; align-content: center; gap: 10px; }
    /* The lone button keeps its natural width rather than stretching. */
    #section-hero .col-lg-4 > .btn-line { flex: 0 0 auto; margin-left: 0; }
    /* The rating always takes a line of its own, under the button */
    #section-hero .col-lg-4 > .hero-rating { flex: 0 0 100%; }
}
#section-hero .mb-0 { margin-bottom: 0; }
#section-hero .spacer-double { width: 100%; height: 60px; display: block; clear: both; }

/* --- type ------------------------------------------------------------ */
/* The h1 is the keyword line. It keeps the champagne it had as a strapline and
   simply takes on the heading size; -1px tracking rather than -2px because a
   list of separated terms needs more air than a single phrase. */
#section-hero h1 {
    /* 46, not 52: at 52 the four terms break across three lines and the last
       two sit alone. 46 splits them two and two. */
    font-size: 46px;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -1px;
    text-align: left;
    text-transform: none;
    color: #fff;
}
/* The tagline, demoted to a slogan sitting under the h1 and dropping in as the
   final beat of the same sequence (see heroKeywords in app.js). */
#section-hero .hero-slogan {
    margin-top: 15px;
    font-size: 20px;
    font-weight: 600;
    letter-spacing: .3px;
    color: var(--champagne);
}
/* Each term is wrapped by app.js so Motion can stagger them in. inline-block
   is required — transforms don't apply to inline boxes. The separators keep
   their surrounding spaces, which `white-space: normal` would otherwise
   collapse away once they sit alone inside a span. */
#section-hero .subtitle__part { display: inline-block; }
#section-hero .subtitle__sep { white-space: pre; }
/* Each term and the separator trailing it share one unit that may not break
   internally, so the line can only ever break BETWEEN units — a separator can
   never open a line. Without this, the hidden separator at a wrap kept its box
   and indented the keyword after it by 15px on a phone.
   inline-block, not inline: an inline unit still offered a break between its
   two atomic children and the separator escaped onto the next line anyway.
   An inline-block is atomic to the line that holds it, so it cannot split. */
#section-hero .subtitle__unit { display: inline-block; white-space: nowrap; }
#section-hero h1,
#section-hero .hero-slogan { text-shadow: 0 2px 14px rgba(0, 0, 0, .45); }

/* --- buttons --------------------------------------------------------- */
#section-hero .btn-line {
    display: inline-block;
    font-size: 13px;
    letter-spacing: 2px;
    line-height: 1.5;
    padding: 12px 30px;
    border-radius: 6px;
    border-width: 2px;
    border-style: solid;
    text-align: center;
    text-decoration: none;
    vertical-align: top;
}

/* Solid champagne — an outline button was disappearing into a busy photo.
   This is the same treatment as .btn--primary everywhere else on the site
   (champagne fill, dark text, darker champagne on hover with a 2px lift), so
   the hero CTA and the header CTA now read as the same control. The chevron
   is masked from `currentColor` and follows the text colour on its own. */
#section-hero .btn-line {
    background: var(--champagne);
    border-color: var(--champagne);
    color: var(--on-champagne);
    /* 600, not 700: only 500/600 were ever loaded for the hero, so this
       button always rendered at 600. Pinned so the hero stays identical now
       that the full weight range is available. */
    font-weight: 600;
    text-transform: uppercase;
    box-shadow: 0 4px 14px -4px rgba(var(--champagne-rgb), .7);
    transition: background .18s var(--ease), border-color .18s var(--ease),
                color .18s var(--ease), transform .18s var(--ease),
                box-shadow .18s var(--ease);
}
#section-hero .btn-line:hover {
    background: var(--champagne-dark);
    border-color: var(--champagne-dark);
    color: var(--on-champagne);
    transform: translateY(-2px);
    box-shadow: 0 8px 22px -6px rgba(var(--champagne-dark-rgb), .8);
}
/* The theme drew this chevron with FontAwesome (content "\f054"). That font is
   gone, so the same glyph is masked from an inline SVG and inherits the button
   colour — which is what the old colour overrides were doing by hand. */
#section-hero .btn-line::after {
    content: "";
    display: inline-block;
    width: .6em; height: .6em;
    margin-left: 10px;
    vertical-align: -1px;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512'%3E%3Cpath d='M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z'/%3E%3C/svg%3E") no-repeat center / contain;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512'%3E%3Cpath d='M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z'/%3E%3C/svg%3E") no-repeat center / contain;
    transition: margin-left .2s var(--ease);
}
#section-hero .btn-line:hover::after { margin-left: 20px; }

/* --- Google rating badge --------------------------------------------- */
#section-hero .hero-rating {
    display: inline-flex; align-items: center; flex-wrap: wrap;
    gap: .2rem .55rem;
    margin-top: 1rem;
    color: #fff;
    font-size: 15px;
    /* Rendered at 500 until now (400 was never loaded for the hero). */
    font-weight: 500;
    text-decoration: none;
    text-shadow: 0 2px 14px rgba(0, 0, 0, .45);
}
#section-hero .hero-rating__stars { display: inline-flex; gap: 2px; color: var(--star); }
#section-hero .hero-rating__stars .icon { width: 17px; height: 17px; }
#section-hero .hero-rating__score { font-weight: 600; font-size: 17px; }
#section-hero .hero-rating__meta { color: rgba(255, 255, 255, .78); }
#section-hero a.hero-rating:hover .hero-rating__meta { color: #fff; }

/* --- mobile (identical to the old breakpoints) ----------------------- */
@media (max-width: 991px) {
    #section-hero { padding-top: 32px; padding-bottom: 36px; }
    #section-hero .spacer-double { display: none; }
}
@media (max-width: 767px) {
    #section-hero h1 { font-size: 32px; line-height: 1.2; letter-spacing: -.5px; }
    #section-hero .hero-slogan { font-size: 17px; }
    #section-hero .btn-line {
        display: block;
        width: 100%;
        text-align: center;
        margin: 10px 0 0 0;
    }
}

/* =========================================================================
   22. CONTACT FORM ERROR SUMMARY + TEAM INTRO (kept from PR #4)
   ========================================================================= */
/* One summary above the form, focused on load, each error linking to its
   field: a screen reader hears what went wrong without hunting for it. */
.form-errors { margin-block: 1.25rem; padding: 1rem; border-left: 3px solid #b42318; background: #fff4f2; }
.form-errors ul { margin-top: .5rem; }
.form-errors li + li { margin-top: .35rem; }
.form-errors a { text-decoration: underline; text-underline-offset: 3px; }

/* "Vos interlocuteurs": names, roles and a real photo. Opt-in — renders only
   when the About page fields are filled, never a stock portrait. */
.team-intro { display: grid; gap: 2rem; align-items: center; }
.team-intro > div { max-width: 720px; }
.team-intro h2 { margin-top: .6rem; }
.team-intro__copy { margin-block: 1rem 1.25rem; color: var(--muted); }
.team-intro--with-photo { grid-template-columns: 1fr 1fr; }
.team-intro__photo { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--r-lg); }
@media (max-width: 767px) { .team-intro--with-photo { grid-template-columns: 1fr; } }
