/*
 * The scrapbook layer — the paper language shared by every page of the site.
 *
 * A page is a sheet of cream paper: photographs are torn out of it, pegged to a
 * washing line or taped on, and the section breaks are ragged tears rather than
 * straight rules. Same tokens as the live design (app.css); the handwriting
 * accent is the only addition.
 *
 * Every class is prefixed `vo3-`. The prefix is a leftover from the design
 * iteration that produced this language; it is kept because renaming it would
 * turn a mechanical extraction into a rewrite of every template.
 *
 * Each page declares its universe on `.vo3-page`, and `--vo3-accent` follows:
 * that single variable is what gives séjour / événement / entreprise their own
 * identity without forking a single component below.
 *
 * Desktop-first, mobile overrides in the single media query at the bottom.
 */

/* The cursor blob is appended to <body>, outside .vo3-page, so these live at
   the root or its handwriting label would fall back to the UI font. */
:root {
    --vo3-script: 'Caveat', 'Playfair Display', cursive;
    --vo3-paper: #FBF7EF;
    --vo3-paper-deep: #F1E9DA;
    --vo3-peg: #C9A87C;
    --vo3-accent: var(--vo-color-sejour);
}

/* The universe is declared as a class on <main>, but the accent has to be resolved
   at the root: the cursor blob is appended to <body>, outside .vo3-page, and would
   otherwise stay terracotta on the plum and slate pages. Matching upwards with
   :has() is what lets one class on <main> colour the whole document. */
:root:has(.vo3-page--evenement) {
    --vo3-accent: var(--vo-color-evenement);
}

:root:has(.vo3-page--entreprise) {
    --vo3-accent: var(--vo-color-entreprise);
}

.vo3-page {
    position: relative;
    background: var(--vo3-paper);
    overflow-x: clip;
}

/* ==========================================================================
   Section entrance vocabulary — four gestures, and no more.

   The pages already carry a lot of motion (the washing line, the highlight
   list, the strips), so arriving on a section always draws from the same small
   set, which turns the scroll into a rhythm rather than a parade of tricks:

     fade   — lifts and fades in (the default for copy and cards)
     rise   — the line lifts out from behind its own edge (titles)
     settle — the photograph eases out of a slight zoom (images)
     hang   — the polaroid swings in on its pegs (the gallery)

   The `is-primed` / `is-in` classes are only ever applied by the enter
   controller: with no JS, or under reduced motion, nothing here applies and
   every section is plainly visible.
   ========================================================================== */

/* --- fade ---------------------------------------------------------------- */

[data-enter="fade"].is-primed {
    opacity: 0;
    transform: translateY(30px);
    transition: none;
}

[data-enter="fade"].is-in {
    opacity: 1;
    transform: none;
    transition: opacity .9s cubic-bezier(.22, .61, .36, 1) var(--enter-delay, 0ms),
                transform .9s cubic-bezier(.22, .61, .36, 1) var(--enter-delay, 0ms);
}

/* --- rise ---------------------------------------------------------------- */

[data-enter="rise"] {
    /* The edge the line hides behind.

       Not `overflow: clip` + `overflow-clip-margin`: Safari ships the former but
       not the latter, so there the clip would land on the box edge and shave the
       accents and descenders (É, ç, j overflow it by 5-9px at these sizes) off
       every title on the page. clip-path takes negative insets — the clip region
       grows past the box to let that ink paint — and, unlike padding, it costs
       the layout nothing, so no title's margins have to be re-tuned around it. */
    clip-path: inset(-.25em -.35em);
}

[data-enter="rise"] > span {
    display: block;
}

/* Far enough down that no ascender pokes back into the widened clip region. */
[data-enter="rise"].is-primed > span {
    transform: translateY(140%);
    transition: none;
}

[data-enter="rise"].is-in > span {
    transform: none;
    transition: transform 1s cubic-bezier(.22, .61, .36, 1) var(--enter-delay, 0ms);
}

/* --- settle -------------------------------------------------------------- */

[data-enter="settle"].is-primed img {
    transform: scale(1.08);
    transition: none;
}

[data-enter="settle"].is-in img {
    transform: none;
    transition: transform 1.5s cubic-bezier(.22, .61, .36, 1) var(--enter-delay, 0ms);
}

/* ==========================================================================
   Shared type
   ========================================================================== */

.vo3-script {
    font-family: var(--vo3-script);
    font-size: clamp(30px, 3.2vw, 42px);
    font-weight: 500;
    line-height: 1;
    color: var(--vo3-accent);
    margin: 0 0 6px;
}

/* On the accent band and over the video, coloured ink would sink into the
   background: the handwriting switches to cream there. */
.vo3-script--cream {
    color: var(--vo-cream);
    opacity: .85;
}

.vo3-display {
    font-family: var(--vo-font-serif);
    font-weight: 500;
    font-size: clamp(34px, 4.6vw, 62px);
    line-height: 1.05;
    letter-spacing: -0.5px;
    margin: 0;
}

.vo3-lead {
    max-width: 620px;
    margin: 26px auto 0;
    font-size: 17px;
    line-height: 1.7;
    color: var(--vo-muted);
}

.vo3-lead--left {
    margin-inline: 0;
}

.vo3-hint {
    font-family: var(--vo3-script);
    font-size: 26px;
    color: var(--vo-muted-light);
}

/* Section header: the title block on the left, the "Faites glisser →" hint on
   the right. Shared by the gallery and the offers. */
.vo3-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 20px;
    margin-bottom: 10px;
}

/* ==========================================================================
   Drag-to-browse strip — the gallery, the offers and the collage are the same
   component, driven by the same drag-carousel controller.
   ========================================================================== */

.vo3-track {
    overflow-x: auto;
    scrollbar-width: none;
    cursor: grab;
}

.vo3-track::-webkit-scrollbar {
    display: none;
}

.vo3-track.is-dragging {
    user-select: none;
}

/* Every openable photograph, wherever it sits. Keyed on [data-openable] and not on
   [data-cursor="Voir"]: that attribute's value is the French label the blob prints,
   and a stylesheet must not break when the wording changes. It cannot be a class
   either — the partial that stamps it is spliced into a tag that already has one. */
[data-openable] {
    cursor: pointer;
}

/* The custom cursor replaces the arrow, but only where the blob actually exists
   (never on touch, never under reduced motion), which the controller settles by
   inserting it or not. Left out, the native arrow would ride alongside the blob. */
body:has(.vo3-cursor) [data-cursor] {
    cursor: none;
}

/* Decorative frond watermark. Its placement is authored per page. */
.vo3-frond {
    position: absolute;
    z-index: 0;
    width: 300px;
    color: var(--vo3-accent);
    opacity: .09;
    pointer-events: none;
}

/* ==========================================================================
   Torn paper edges
   ========================================================================== */

.vo3-tear {
    position: absolute;
    left: -1px;
    right: -1px;
    bottom: -1px;
    z-index: 4;
    width: calc(100% + 2px);
    height: clamp(34px, 4.4vw, 66px);
    pointer-events: none;
    /* The tear casts a hair of shadow on what it covers, so the paper reads as
       lying on top of the photograph instead of being cut out of it. */
    filter: drop-shadow(0 -3px 6px rgba(33, 28, 23, .16));
}

.vo3-tear--flip {
    top: -1px;
    bottom: auto;
    transform: scaleY(-1);
}

.vo3-tear path {
    fill: var(--vo3-paper);
}

/* ==========================================================================
   Hero
   ========================================================================== */

.vo3-hero {
    /* Room for the tear to bite in without eating what sits at the bottom. */
    padding-bottom: clamp(70px, 8vw, 110px);
}

/* The showcase heroes are photographs, not the homepage's video: a full viewport
   of still image is a wall to scroll past, so they open shorter and hand over to
   the paper sooner. */
.vo3-hero--inner {
    min-height: 70vh;
    min-height: 70svh;
}

.vo3-hero__title {
    font-family: var(--vo-font-serif);
    font-weight: 500;
    font-size: clamp(52px, 9vw, 130px);
    line-height: .95;
    margin: 4px 0 0;
    letter-spacing: -1px;
    text-shadow: 0 4px 40px rgba(0, 0, 0, .35);
}

.vo3-hero__title em {
    display: block;
    font-family: var(--vo3-script);
    font-style: normal;
    font-size: 1.05em;
    color: var(--vo-gold);
    margin-top: -.06em;
}

/* ==========================================================================
   Intro
   ========================================================================== */

.vo3-intro {
    position: relative;
    padding-block: clamp(70px, 8vw, 120px) clamp(50px, 6vw, 90px);
}

.vo3-intro__inner {
    position: relative;
    z-index: 1;
    text-align: center;
}

.vo3-counters {
    display: flex;
    justify-content: center;
    gap: clamp(30px, 6vw, 90px);
    margin-top: 58px;
    flex-wrap: wrap;
}

.vo3-counter {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.vo3-counter__value {
    font-family: var(--vo-font-serif);
    font-size: clamp(38px, 4vw, 54px);
    line-height: 1;
}

.vo3-counter__label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    /* --vo-muted-light would be ~3.1:1 on the paper: below AA at this size. */
    color: var(--vo-muted);
}

/* ==========================================================================
   Washing line of polaroids — one sagging rope, horizontally draggable
   ========================================================================== */

.vo3-line {
    padding-block: clamp(40px, 5vw, 70px) clamp(60px, 7vw, 100px);
}

.vo3-line__strip {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: clamp(30px, 4vw, 60px);
    width: max-content;
    min-width: 100%;
    justify-content: center;
    padding: 52px max(var(--vo-gutter), 4vw) 40px;
}

/* The rope: one quadratic curve for the whole strip. Its sag, and every polaroid's
   --drop, are both derived from the `sag` constant in the template, so the pegs
   land on the line at every position. Stretched horizontally by
   preserveAspectRatio="none"; vector-effect keeps the stroke 2px anyway. */
.vo3-line__rope {
    position: absolute;
    /* 37px is what makes the rope land in the jaws of the pegs rather than
       skim over their heads, and it is not free to change:

           rope y(t)   = 37 + 18 + 112·t(1−t)   (SVG offset + path start + sag)
           peg centre  = 52 + 112·t(1−t) − 14 + 17
                       = 55 + 112·t(1−t)        (strip padding + --drop, peg top, half its height)

       The two agree exactly at 37. Move the strip's padding-top, the peg's top,
       or the path, and this has to be re-derived. */
    top: 37px;
    left: 0;
    width: 100%;
    height: 80px;
    pointer-events: none;
}

.vo3-line__rope path {
    fill: none;
    stroke: rgba(33, 28, 23, .42);
    stroke-width: 2px;
    vector-effect: non-scaling-stroke;
}

/* --------------------------------------------------------------------------
   Wooden peg, shared by the polaroid corners and the spare pegs on the rope.
   -------------------------------------------------------------------------- */

.vo3-peg {
    position: absolute;
    width: 11px;
    height: 34px;
    border-radius: 3px;
    background: linear-gradient(100deg, var(--vo3-peg), #E3CBA8 45%, var(--vo3-peg));
    box-shadow: 0 2px 4px rgba(33, 28, 23, .3);
    transform: rotate(var(--peg-rot, 0deg));
}

/* The metal spring, halfway down the peg. */
.vo3-peg::after {
    content: '';
    position: absolute;
    left: 1px;
    right: 1px;
    top: 15px;
    height: 1.5px;
    background: rgba(33, 28, 23, .28);
}

/* --------------------------------------------------------------------------
   Washing-line geometry.

   The rope in the template is `M0,18 Q50,74 100,18` in a 0..80 viewBox drawn
   80px tall — a quadratic whose lowest point is exactly SAG = 28px below its
   ends. Everything hanging off it is placed on that same curve:

       drop(t) = 4 · SAG · t · (1 − t)        → peaks at SAG for t = 0.5

   sampled at each photo's centre, t = (i + 0.5) / 8. The values below are that
   formula evaluated; change the rope's control point (74) and re-evaluate them.

   THE LINE HOLDS EXACTLY EIGHT PHOTOGRAPHS. The count is baked into the sampling
   above and into the three spare pegs below: hang six and the rope misses their
   pegs at the edges, hang ten and the last two float with no geometry at all.
   A page that needs a different number wants the taped collage, not the line.

   It has to live here, not in the template: the site enforces a nonce-based CSP
   with no 'unsafe-inline', so a style="" attribute never reaches the page.
   -------------------------------------------------------------------------- */

.vo3-line__strip > figure:nth-of-type(1) { --rot: -6deg;   --drop: 6.6px; }
.vo3-line__strip > figure:nth-of-type(2) { --rot: 4deg;    --drop: 17.1px; }
.vo3-line__strip > figure:nth-of-type(3) { --rot: -2.5deg; --drop: 24.1px; }
.vo3-line__strip > figure:nth-of-type(4) { --rot: 7deg;    --drop: 27.6px; }
.vo3-line__strip > figure:nth-of-type(5) { --rot: -5deg;   --drop: 27.6px; }
.vo3-line__strip > figure:nth-of-type(6) { --rot: 3deg;    --drop: 24.1px; }
.vo3-line__strip > figure:nth-of-type(7) { --rot: -7.5deg; --drop: 17.1px; }
.vo3-line__strip > figure:nth-of-type(8) { --rot: 5deg;    --drop: 6.6px; }

/* Spare pegs ride the same curve: top = 38px (which centres a 34px peg on the
   rope, see .vo3-line__rope) + the sag at that position, 112·t(1−t). */
.vo3-line__spare {
    z-index: 1;
}

.vo3-line__spare:nth-of-type(1) { left: 13%;   top: 50.7px; --peg-rot: -5deg; }
.vo3-line__spare:nth-of-type(2) { left: 50%;   top: 66px;   --peg-rot: 3deg; }
.vo3-line__spare:nth-of-type(3) { left: 87.5%; top: 50.3px; --peg-rot: -3deg; }

/* --------------------------------------------------------------------------
   Polaroid: the figure swings as one piece (pegs included) around the rope;
   the paper card inside carries the hover so it never touches the animation.
   -------------------------------------------------------------------------- */

.vo3-polaroid {
    position: relative;
    z-index: 2;
    flex: 0 0 auto;
    width: clamp(200px, 22vw, 250px);
    margin: 0;
    transform: translateY(var(--drop, 0)) rotate(var(--rot, 0deg));
    /* Pivot at rope height: that is what makes the swing a pendulum. */
    transform-origin: 50% -6px;
    animation: vo3Sway 6s ease-in-out infinite alternate;
}

/* Pre-hang state, applied by the enter controller only (never here — the line
   must stay fully visible without JS). */
[data-enter="hang"].is-primed {
    opacity: 0;
    animation: none;
}

[data-enter="hang"].is-in {
    animation: vo3Swing 2.3s ease-in-out var(--enter-delay, 0ms) both,
               vo3Sway 6s ease-in-out calc(var(--enter-delay, 0ms) + 2300ms) infinite alternate;
}

/* The idle sway is eight permanently composited layers. Behind the open lightbox
   they would dirty its full-viewport backdrop-filter on every frame, forcing a
   continuous re-blur — so the line holds still while a photo is enlarged. */
.vo3-page:has(.vo3-lightbox[open]) .vo3-polaroid {
    animation-play-state: paused;
}

/* Freeze (not cancel) the swing under the pointer: pausing keeps the current
   frame, so leaving never replays the entrance — that replay was a visible
   blink (the entrance starts at opacity 0). */
.vo3-polaroid:hover {
    animation-play-state: paused;
    z-index: 3;
}

/* The pegs grip the rope; the photo is what hangs crooked from them. Left alone
   they tilt with the figure and a -6° photo swings its left peg ~11px clear of
   the line, gripping nothing — so each peg counter-rotates back to upright and
   is offset by the height its corner gained from the tilt.

   --peg-dx is the horizontal distance from the figure's pivot to the peg, which
   is what turns an angle into a vertical offset: Δy = dx · sin(rot). */
.vo3-polaroid {
    --peg-dx: 105px;
}

.vo3-polaroid__peg--left,
.vo3-polaroid__peg--right {
    z-index: 1;
    transform: rotate(calc(var(--peg-rot, 0deg) - var(--rot, 0deg)));
}

.vo3-polaroid__peg--left {
    top: calc(-14px + var(--peg-dx) * sin(var(--rot, 0deg)));
    left: 14px;
    --peg-rot: -8deg;
}

.vo3-polaroid__peg--right {
    top: calc(-14px - var(--peg-dx) * sin(var(--rot, 0deg)));
    right: 14px;
    --peg-rot: 7deg;
}

.vo3-polaroid__card {
    padding: 12px 12px 0;
    background: #FFFDF8;
    border-radius: 3px;
    box-shadow: 0 18px 32px -18px rgba(33, 28, 23, .55), 0 1px 0 rgba(33, 28, 23, .08);
    transform-origin: 50% 0;
    transition: transform .45s cubic-bezier(.22, .61, .36, 1), box-shadow .45s ease;
}

/* The card straightens most of the way and lifts slightly, as if picked off
   the line — while staying under its pegs. */
.vo3-polaroid:hover .vo3-polaroid__card {
    transform: translateY(-8px) rotate(calc(var(--rot, 0deg) * -.65)) scale(1.04);
    box-shadow: 0 30px 46px -20px rgba(33, 28, 23, .6);
}

/* Press feedback: the paper gives in under the finger before the lightbox opens. */
.vo3-polaroid__card[role="button"]:active {
    transform: translateY(-5px) rotate(calc(var(--rot, 0deg) * -.65)) scale(.97);
    transition-duration: .12s;
}

.vo3-polaroid__card img {
    width: 100%;
    /* The width/height attributes on the <img> (there to reserve the space and
       avoid a layout shift) also act as presentational hints: without this, a
       mismatched intrinsic height would win over the aspect ratio below. */
    height: auto;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    border-radius: 1px;
}

.vo3-polaroid__card figcaption {
    font-family: var(--vo3-script);
    font-size: 27px;
    line-height: 1;
    color: var(--vo3-accent);
    text-align: center;
    padding: 13px 4px 16px;
}

/* Damped pendulum entrance: overshoots around the authored angle and settles.
   All keyframes repeat the same translateY so only the rotation moves. */
@keyframes vo3Swing {
    0% {
        opacity: 0;
        transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) + 13deg));
    }

    14% {
        opacity: 1;
    }

    30% {
        transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) - 7deg));
    }

    54% {
        transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) + 3.5deg));
    }

    76% {
        transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) - 1.5deg));
    }

    100% {
        opacity: 1;
        transform: translateY(var(--drop, 0)) rotate(var(--rot, 0deg));
    }
}

/* Idle pendulum: ±0.55° around the rope, nothing more. */
@keyframes vo3Sway {
    from { transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) - .55deg)); }
    to { transform: translateY(var(--drop, 0)) rotate(calc(var(--rot, 0deg) + .55deg)); }
}

/* --------------------------------------------------------------------------
   Lightbox: the clicked photo re-printed large on the same paper, over a
   blurred page. <dialog> provides Escape, focus trapping and ::backdrop.
   -------------------------------------------------------------------------- */

.vo3-lightbox {
    border: none;
    padding: clamp(14px, 2vw, 22px) clamp(14px, 2vw, 22px) 0;
    background: #FFFDF8;
    border-radius: 4px;
    box-shadow: 0 50px 90px -30px rgba(33, 28, 23, .65);
    max-width: min(880px, 92vw);
}

.vo3-lightbox::backdrop {
    background: rgba(33, 28, 23, .38);
    /* Safari needs the prefix until 18. */
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}

/* A modal <dialog> does not stop the page scrolling underneath it — Chrome and
   Safari both let the wheel/touch chain through to the body. On touch and under
   reduced motion (where the inertial controller is off) this is the only thing
   holding the page still while a photo is enlarged. */
body:has(.vo3-lightbox[open]) {
    overflow: hidden;
}

.vo3-lightbox[open] {
    animation: vo3LightboxIn .5s cubic-bezier(.2, 1.15, .35, 1);
}

.vo3-lightbox[open]::backdrop {
    animation: voFade .4s ease;
}

@keyframes vo3LightboxIn {
    from {
        opacity: 0;
        transform: scale(.88) rotate(-1.5deg);
    }
}

.vo3-lightbox__figure {
    margin: 0;
}

.vo3-lightbox__figure img {
    display: block;
    max-width: 100%;
    max-height: 76vh;
    border-radius: 2px;
}

.vo3-lightbox__figure figcaption {
    font-family: var(--vo3-script);
    font-size: 30px;
    line-height: 1;
    color: var(--vo3-accent);
    text-align: center;
    padding: 16px 4px 18px;
}

.vo3-lightbox__close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 38px;
    height: 38px;
    border: none;
    border-radius: 50%;
    background: rgba(33, 28, 23, .55);
    color: var(--vo-cream);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    transition: background .25s ease, transform .25s ease;
}

.vo3-lightbox__close:hover {
    background: var(--vo-ink);
    transform: rotate(90deg);
}

/* Taped variant: no rope, a strip of masking tape instead. */
.vo3-polaroid--taped {
    width: auto;
    max-width: 320px;
    --rot: -2.5deg;
    transform-origin: center;
    animation: none;
}

.vo3-polaroid__tape {
    position: absolute;
    top: -16px;
    left: 50%;
    width: 108px;
    height: 32px;
    margin-left: -54px;
    background: rgba(224, 165, 103, .42);
    border-left: 1px dashed rgba(255, 255, 255, .5);
    border-right: 1px dashed rgba(255, 255, 255, .5);
    transform: rotate(-4deg);
}

/* ==========================================================================
   Spread — photograph(s) on one side, copy on the other. The host section and the
   séjour's garden are the same composition; only their photos differ.
   ========================================================================== */

.vo3-spread {
    display: flex;
    align-items: center;
    gap: clamp(36px, 5vw, 80px);
}

.vo3-spread__body {
    flex: 1;
}

/* ==========================================================================
   Highlight list — a sticky accordion of rows, each lighting up a photograph
   ========================================================================== */

.vo3-atouts {
    background: var(--vo3-paper-deep);
    padding-block: clamp(70px, 8vw, 110px);
}

.vo3-atouts__grid {
    display: grid;
    grid-template-columns: 1fr .78fr;
    gap: clamp(30px, 4vw, 60px);
    align-items: start;
    margin-top: 48px;
}

.vo3-atouts__list {
    display: flex;
    flex-direction: column;
    border-top: 1px solid rgba(33, 28, 23, .14);
}

.vo3-atout {
    position: relative;
    display: grid;
    grid-template-columns: 44px 1fr 26px;
    grid-template-areas:
        'index title icon'
        '.     text  text';
    align-items: baseline;
    gap: 0 10px;
    width: 100%;
    padding: 22px 26px;
    border: none;
    border-bottom: 1px solid rgba(33, 28, 23, .14);
    background: transparent;
    color: var(--vo-ink);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
    transition: color .35s ease;
}

/* Accordion affordance: without it, nothing says the rows are tappable —
   especially on touch, where there is no hover to discover it by accident. */
.vo3-atout::after {
    content: '+';
    grid-area: icon;
    justify-self: end;
    align-self: center;
    position: relative;
    z-index: 1;
    font-family: var(--vo-font-serif);
    font-size: 26px;
    line-height: 1;
    color: var(--vo-muted-light);
    transition: transform .45s cubic-bezier(.22, .61, .36, 1), color .35s ease;
}

.vo3-atout.is-active::after {
    transform: rotate(45deg);
    color: var(--vo-cream);
}

/* The accent fill sweeps in from the left under the text. */
.vo3-atout::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--vo3-accent);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform .55s cubic-bezier(.22, .61, .36, 1);
}

.vo3-atout.is-active::before {
    transform: scaleX(1);
}

.vo3-atout.is-active {
    color: var(--vo-cream);
}

.vo3-atout__index {
    grid-area: index;
    position: relative;
    z-index: 1;
    font-family: var(--vo-font-serif);
    font-size: 14px;
    opacity: .55;
}

.vo3-atout__title {
    grid-area: title;
    position: relative;
    z-index: 1;
    font-family: var(--vo-font-serif);
    font-size: clamp(21px, 2vw, 27px);
}

.vo3-atout__text {
    grid-area: text;
    position: relative;
    z-index: 1;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    max-height: 0;
    margin-top: 0;
    font-size: 14.5px;
    line-height: 1.6;
    opacity: 0;
    transition: max-height .55s cubic-bezier(.22, .61, .36, 1), opacity .4s ease, margin-top .55s ease;
}

.vo3-atout.is-active .vo3-atout__text,
/* Without JS nothing is ever activated, and the section would read as four bare
   titles over an empty box. While no row is active — which is exactly the no-JS
   case — the first one stands open. The controller activating a row switches
   this off in the same breath. */
.vo3-atouts__list:not(:has(.is-active)) .vo3-atout:first-child .vo3-atout__text {
    max-height: 90px;
    margin-top: 8px;
    opacity: .92;
}

.vo3-atouts__stack {
    position: relative;
    aspect-ratio: 4 / 5;
    border-radius: 4px;
    overflow: hidden;
    box-shadow: 0 26px 50px -26px rgba(33, 28, 23, .55);
}

.vo3-atouts__photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.06);
    transition: opacity .7s ease, transform 1.1s cubic-bezier(.22, .61, .36, 1);
}

.vo3-atouts__photo.is-active,
.vo3-atouts__stack:not(:has(.is-active)) .vo3-atouts__photo:first-child {
    opacity: 1;
    transform: scale(1);
}

/* ==========================================================================
   Offers — drag-to-browse strip of cards
   ========================================================================== */

.vo3-offers {
    position: relative;
    padding-block: clamp(70px, 8vw, 110px);
}

.vo3-offers__head {
    position: relative;
    z-index: 1;
    margin-bottom: 40px;
}

.vo3-offers__track {
    display: flex;
    gap: 28px;
    padding-inline: max(var(--vo-gutter), calc((100vw - var(--vo-container)) / 2 + var(--vo-gutter)));
    padding-block: 10px 24px;
}

.vo3-offer {
    flex: 0 0 clamp(280px, 30vw, 400px);
    display: flex;
    flex-direction: column;
    background: #FFFDF8;
    border-radius: 6px;
    box-shadow: 0 24px 44px -26px rgba(33, 28, 23, .5);
    overflow: hidden;
    transition: transform .5s cubic-bezier(.22, .61, .36, 1), box-shadow .5s ease;
}

.vo3-offer:hover {
    transform: translateY(-6px);
    box-shadow: 0 34px 56px -26px rgba(33, 28, 23, .55);
}

.vo3-offer__media {
    position: relative;
    overflow: hidden;
}

.vo3-offer__media img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    transition: transform 1.1s cubic-bezier(.22, .61, .36, 1);
}

.vo3-offer:hover .vo3-offer__media img {
    transform: scale(1.05);
}

.vo3-offer__tag {
    position: absolute;
    left: 16px;
    bottom: 16px;
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--vo-cream);
    font-family: var(--vo3-script);
    font-size: 20px;
    line-height: 1;
    color: var(--vo3-accent);
}

/* On the homepage the three cards each advertise a different universe, so there
   the tag is coloured per card rather than by the page. */
.vo3-offer--evenement .vo3-offer__tag {
    color: var(--vo-color-evenement);
}

.vo3-offer--entreprise .vo3-offer__tag {
    color: var(--vo-color-entreprise);
}

.vo3-offer__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 24px 24px 26px;
    /* Fill the card so the CTA below can be pushed to its floor. */
    flex: 1;
}

/* Cards whose meta chips wrap to different heights would otherwise leave their
   CTAs on a ragged baseline — which reads as broken, not as organic. */
.vo3-offer__body .vo-btn {
    margin-top: auto;
}

.vo3-offer__title {
    font-size: 30px;
    margin: 0;
}

.vo3-offer__text {
    margin: 0;
    font-size: 14.5px;
    line-height: 1.65;
    color: var(--vo-muted);
}

.vo3-offer__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 4px 0 8px;
    padding: 0;
    list-style: none;
}

.vo3-offer__meta li {
    padding: 5px 11px;
    border: 1px solid rgba(33, 28, 23, .16);
    border-radius: 999px;
    font-size: 12px;
    color: var(--vo-muted);
}

/* ==========================================================================
   Taped note + chips
   ========================================================================== */

.vo3-note-section {
    padding-block: clamp(30px, 4vw, 60px) clamp(70px, 8vw, 110px);
}

.vo3-note {
    position: relative;
    max-width: 860px;
    margin-inline: auto;
    padding: clamp(36px, 4vw, 56px);
    background: var(--vo3-paper-deep);
    border-radius: 4px;
    transform: rotate(-.6deg);
    box-shadow: 0 24px 44px -28px rgba(33, 28, 23, .5);
    text-align: center;
}

.vo3-note__tape {
    position: absolute;
    top: -14px;
    left: 50%;
    width: 130px;
    height: 28px;
    margin-left: -65px;
    background: rgba(224, 165, 103, .45);
    border-left: 1px dashed rgba(255, 255, 255, .55);
    border-right: 1px dashed rgba(255, 255, 255, .55);
    transform: rotate(1.5deg);
}

.vo3-note__title {
    font-family: var(--vo-font-serif);
    font-weight: 500;
    font-size: clamp(28px, 3.4vw, 44px);
    margin: 0 0 30px;
}

.vo3-note__chips {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
}

.vo3-chip {
    padding: 10px 18px;
    border: 1px solid rgba(33, 28, 23, .18);
    border-radius: 999px;
    background: var(--vo3-paper);
    font-size: 14px;
    transition: transform .3s ease, background .3s ease, color .3s ease;
}

.vo3-chip:hover {
    transform: translateY(-3px) rotate(-1.5deg);
}

/* ==========================================================================
   CTA band — the page's accent colour, torn out of the paper above and below
   ========================================================================== */

.vo3-cta {
    position: relative;
    background: var(--vo3-accent);
    color: var(--vo-cream);
    padding-block: clamp(110px, 12vw, 170px);
    text-align: center;
}

.vo3-cta__inner {
    position: relative;
    z-index: 1;
}

.vo3-cta__title {
    font-family: var(--vo-font-serif);
    font-weight: 500;
    font-size: clamp(34px, 5vw, 66px);
    line-height: 1.05;
    margin: 0;
}

.vo3-cta__text {
    max-width: 520px;
    margin: 22px auto 34px;
    font-size: 16.5px;
    line-height: 1.65;
    opacity: .9;
}

.vo3-cta__actions {
    display: flex;
    justify-content: center;
    gap: 14px;
    flex-wrap: wrap;
}

.vo3-btn--cream {
    background: var(--vo-cream);
    color: var(--vo3-accent);
}

.vo3-btn--cream:hover {
    background: #fff;
}

.vo3-btn--outline {
    background: transparent;
    color: var(--vo-cream);
    border: 1px solid rgba(250, 246, 238, .55);
    text-decoration: none;
}

.vo3-btn--outline:hover {
    background: rgba(250, 246, 238, .14);
}

/* ==========================================================================
   Cursor blob (injected on <body> by the cursor-blob controller)
   ========================================================================== */

.vo3-cursor {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 90;
    display: grid;
    place-items: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--vo3-accent);
    pointer-events: none;
    opacity: 0;
    transition: width .35s cubic-bezier(.22, .61, .36, 1), height .35s cubic-bezier(.22, .61, .36, 1), opacity .3s ease, background .3s ease;
    mix-blend-mode: multiply;
}

.vo3-cursor.is-visible {
    opacity: .85;
}

.vo3-cursor.is-active {
    width: 88px;
    height: 88px;
    background: var(--vo-gold);
    opacity: 1;
    mix-blend-mode: normal;
}

.vo3-cursor__label {
    font-family: var(--vo3-script);
    font-size: 24px;
    color: var(--vo-ink);
    opacity: 0;
    transform: scale(.7);
    transition: opacity .3s ease .1s, transform .3s ease .1s;
    white-space: nowrap;
}

.vo3-cursor.is-active .vo3-cursor__label {
    opacity: 1;
    transform: scale(1);
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 900px) {
    .vo3-frond {
        display: none;
    }

    .vo3-polaroid {
        width: 200px;
    }

    .vo3-atouts__grid {
        grid-template-columns: 1fr;
    }

    .vo3-atouts__stack {
        order: -1;
        aspect-ratio: 3 / 2;
    }

    .vo3-head {
        flex-direction: column;
        align-items: flex-start;
    }

    /* The card is barely wider than the label: let the CTA fill it and wrap,
       instead of running out of the card on its nowrap default. */
    .vo3-offer__body {
        align-items: stretch;
    }

    .vo3-offer__body .vo-btn {
        width: 100%;
        justify-content: center;
        text-align: center;
        white-space: normal;
    }

    .vo3-spread {
        flex-direction: column;
        text-align: center;
    }

    .vo3-spread__body .vo3-lead {
        margin-inline: auto;
    }
}
