/* =========================================================================
   motion.css — premier ecran (hero), prechargeur et effets au scroll
   -------------------------------------------------------------------------
   Ce fichier complete css/style.css. Il est pilote par js/motion.js qui :
     - ajoute la classe .is-ready sur <html> quand le rideau du prechargeur se leve,
     - ecrit des variables CSS (--hp, --tl, --sc...) pendant le scroll,
     - ajoute .is-in / .is-active / .lit sur les elements qui apparaissent.
   Regles de conception :
     - on n'anime que transform et opacity (compositeur GPU, fluide sur mobile) ;
     - tout etat "cache avant apparition" est sous .js : sans JavaScript le
       contenu reste visible (et html.js est retiree si motion.js ne demarre pas) ;
     - prefers-reduced-motion : tous les effets sont neutralises en bas de fichier.
   ========================================================================= */

/* ---------- Police d'affichage ----------
   Instance STATIQUE de Sora ExtraBold (graisse 800) dont les contours qui se chevauchent ont ete
   supprimes (fontTools + skia-pathops). Indispensable pour les lettres "creuses" (-webkit-text-stroke) :
   avec la police variable, chaque chevauchement dessine un trait parasite a l'interieur des lettres. */
@font-face {
    font-family: 'Sora Display';
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url('../fonts/sora-800-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- 0. Variables et utilitaires ---------- */
:root {
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);      /* decelere en douceur : "expo out" */
    --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
    --accent-grad: linear-gradient(90deg, #3773d4, #7c4dff);
    --accent-grad-v: linear-gradient(180deg, #3773d4, #7c4dff);
    --nav-h: 88px;                                   /* hauteur reservee a la barre de navigation */
    --font-display: 'Sora Display', 'Sora', system-ui, sans-serif;
    --sheet-bg: linear-gradient(180deg, #0a0d15 0%, #090b12 45%, #06080e 100%);
}

.light-theme {
    --sheet-bg: linear-gradient(180deg, #fbfcff 0%, #f2f5fb 100%);
}

/* Texte lu par les lecteurs d'ecran mais invisible a l'ecran */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Lien d'evitement : cache hors ecran, apparait au focus clavier */
.skip-link {
    position: fixed;
    left: 14px;
    top: -80px;
    z-index: 7000;
    padding: 12px 18px;
    border-radius: 12px;
    background: #fff;
    color: #0a0d15;
    font-weight: 600;
    text-decoration: none;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
    transition: top 0.2s ease;
}

.skip-link:focus {
    top: 14px;
}

/* "clip" (contrairement a "hidden") ne cree pas de conteneur de scroll :
   indispensable pour que position: sticky (hero epingle) fonctionne. */
html,
body {
    overflow-x: clip;
}

/* ---------- 1. Prechargeur de marque ---------- */
.preloader {
    position: fixed;
    inset: 0;
    z-index: 6000;
    display: grid;
    place-items: center;
    color: #fff;
    background:
        radial-gradient(ellipse at 50% 38%, #16204a 0%, transparent 62%),
        #070910;
    transition: transform 0.95s var(--ease-io), visibility 0s linear 0.95s;
    /* Filet de securite : si le JS ne leve pas le rideau, il disparait seul apres 7 s */
    animation: plFailsafe 0.01s linear 7s forwards;
}

.preloader.hide {
    transform: translate3d(0, -100%, 0);
    visibility: hidden;
    pointer-events: none;
}

.preloader-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 22px;
}

.preloader-mark {
    position: relative;
    width: 68px;
    height: 68px;
}

.preloader-logo {
    position: relative;
    z-index: 1;
    display: block;
    border-radius: 18px;
    box-shadow: 0 14px 44px rgba(79, 110, 255, 0.5);
    animation: plPop 0.9s var(--ease-out) both;
}

/* Ondes concentriques qui partent du logo (echo du motif "cible" de la marque) */
.preloader-ripple {
    position: absolute;
    inset: 0;
    border-radius: 22px;
    border: 2px solid rgba(120, 160, 255, 0.55);
    animation: plRipple 1.9s var(--ease-out) infinite;
}

.preloader-ripple:nth-child(2) {
    animation-delay: 0.65s;
}

.preloader-word {
    margin: 0;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.46em;
    padding-left: 0.46em; /* recentre visuellement le dernier espacement de lettre */
    text-transform: uppercase;
    color: #b9c7e6;
    animation: plFade 0.8s var(--ease-out) 0.3s both;
}

.preloader-line {
    position: relative;
    width: 150px;
    height: 2px;
    border-radius: 2px;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.12);
}

.preloader-line i {
    position: absolute;
    inset: 0;
    background: var(--accent-grad);
    transform-origin: 0 50%;
    transform: scaleX(0.06);
    animation: plLoad 2.6s var(--ease-out) forwards;
}

@keyframes plPop {
    from { transform: scale(0.55) rotate(-14deg); opacity: 0; }
    to { transform: none; opacity: 1; }
}

@keyframes plRipple {
    from { transform: scale(1); opacity: 0.75; }
    to { transform: scale(2.7); opacity: 0; }
}

@keyframes plFade {
    from { opacity: 0; transform: translate3d(0, 10px, 0); }
    to { opacity: 1; transform: none; }
}

@keyframes plLoad {
    to { transform: scaleX(0.92); }
}

@keyframes plFailsafe {
    to { visibility: hidden; opacity: 0; }
}

.light-theme .preloader {
    color: #101b2d;
    background:
        radial-gradient(ellipse at 50% 38%, #dfe8ff 0%, transparent 62%),
        #f6f8fc;
}

.light-theme .preloader-word {
    color: #3a4a66;
}

.light-theme .preloader-line {
    background: rgba(16, 27, 45, 0.12);
}

/* ---------- 2. Barre de progression de lecture ---------- */
.scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 5000;
    pointer-events: none;
}

.scroll-progress span {
    display: block;
    height: 100%;
    background: var(--accent-grad);
    box-shadow: 0 0 14px rgba(99, 132, 255, 0.7);
    transform-origin: 0 50%;
    transform: scaleX(0);
    will-change: transform;
}

/* ---------- 3. Hero ---------- */
/* Le hero est epingle en haut (sticky) : la .page-sheet glisse par-dessus comme un rideau. */
.hero {
    position: sticky;
    top: 0;
    z-index: 1;
    height: 100vh;
    height: 100svh;
    min-height: 540px;
    overflow: hidden;
    isolation: isolate;
    color: var(--fg);
    background:
        radial-gradient(120% 70% at 50% 0%, #131c44 0%, transparent 62%),
        linear-gradient(180deg, #0a0d15 0%, #080b14 100%);
}

/* Voile qui assombrit le hero a mesure que la feuille le recouvre */
.hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 6;
    pointer-events: none;
    background: #05070d;
    opacity: calc(var(--hp, 0) * 0.78);
}

.hero-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}

/* Spot lumineux qui suit le curseur (desktop uniquement, voir js/motion.js) */
.hero-spot {
    position: absolute;
    inset: 0;
    background: radial-gradient(560px circle at var(--mx, 68%) var(--my, 42%), rgba(110, 150, 255, 0.16), transparent 62%);
}

.hero-inner {
    position: relative;
    z-index: 2;
    height: 100%;
    max-width: 1240px;
    margin: 0 auto;
    /* haut : barre de navigation ; bas : indicateur de scroll + bandeau d'applications */
    padding:
        calc(var(--nav-h) + env(safe-area-inset-top, 0px)) 22px calc(140px + env(safe-area-inset-bottom, 0px));
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
        'eyebrow'
        'stage'
        'info';
    row-gap: 8px;
    transform-origin: 50% 35%;
    transform: scale(calc(1 - var(--hp, 0) * 0.05));
}

/* Sur mobile le conteneur "copy" disparait : eyebrow et info deviennent
   des elements directs de la grille (haut / bas). Sur desktop il devient la colonne gauche. */
.hero-copy {
    display: contents;
}

.hero-eyebrow {
    grid-area: eyebrow;
    position: relative;
    z-index: 4;
    margin: 0;
    min-height: 1.7em;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    /* dimensionne pour la salutation la plus longue ("Bon après-midi, je suis ...") ;
       js/main.js ajuste encore la taille si un ecran tres etroit la ferait deborder */
    font-size: clamp(9px, 2.72vw, 13px);
    font-weight: 600;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #8fb0ff;
    transform: translate3d(0, calc(var(--hp, 0) * -28px), 0);
    opacity: calc(1 - var(--hp, 0) * 1.6);
}

/* Curseur clignotant pendant la frappe (retire par JS via .typed) ; seulement si JS actif */
.js .hero-eyebrow::after {
    content: '';
    display: inline-block;
    width: 0.12em;
    height: 1em;
    margin-left: 0.3em;
    vertical-align: -0.14em;
    background: currentColor;
    animation: caret 0.9s steps(2) infinite;
}

.js .hero-eyebrow.typed::after {
    display: none;
}

@keyframes caret {
    50% { opacity: 0; }
}

/* --- Scene : halo, anneaux, mot geant, portrait (toutes les tailles en cqw/cqh) --- */
.hero-stage {
    grid-area: stage;
    position: relative;
    min-height: 0;
    --ring: min(62vw, 30vh); /* repli si les container queries ne sont pas supportees */
}

@supports (container-type: size) {
    .hero-stage {
        container-type: size;
        --ring: min(62cqw, 50cqh);
    }
}

/* Halo bleu/violet derriere le buste : il detache le pull sombre du fond */
.hero-stage::before {
    content: '';
    position: absolute;
    z-index: 0;
    left: 50%;
    top: 52%;
    width: calc(var(--ring) * 3.1);
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    background: radial-gradient(closest-side, rgba(84, 116, 255, 0.5), rgba(124, 77, 255, 0.22) 46%, transparent 72%);
    pointer-events: none;
}

/* Anneaux concentriques : rappel du logo "cible" de la marque OSWEL */
.hero-rings {
    position: absolute;
    z-index: 0;
    left: 50%;
    top: 50%;
    width: 0;
    height: 0;
    transform: scale(calc(1 + var(--hp, 0) * 0.4));
    opacity: calc(1 - var(--hp, 0) * 0.85);
}

.hero-ring {
    position: absolute;
    left: 0;
    top: 0;
    border-radius: 50%;
    border: 1px solid rgba(150, 175, 255, 0.2);
    transform: translate(-50%, -50%);
}

.hero-ring--1 { width: var(--ring); height: var(--ring); }
.hero-ring--2 { width: calc(var(--ring) * 1.55); height: calc(var(--ring) * 1.55); border-color: rgba(150, 175, 255, 0.15); }
.hero-ring--3 { width: calc(var(--ring) * 2.2); height: calc(var(--ring) * 2.2); border-color: rgba(150, 175, 255, 0.1); }

/* Petit point lumineux qui orbite sur le 2e anneau */
.hero-orbit {
    position: absolute;
    left: 0;
    top: 0;
    width: calc(var(--ring) * 1.55);
    height: calc(var(--ring) * 1.55);
    transform: translate(-50%, -50%);
    animation: orbit 18s linear infinite;
}

.hero-orbit i {
    position: absolute;
    left: 50%;
    top: 0;
    width: 8px;
    height: 8px;
    margin: -4px 0 0 -4px;
    border-radius: 50%;
    background: #b4c6ff;
    box-shadow: 0 0 14px 4px rgba(120, 160, 255, 0.75);
}

@keyframes orbit {
    from { transform: translate(-50%, -50%) rotate(0deg); }
    to { transform: translate(-50%, -50%) rotate(360deg); }
}

/* Titre : deux mots a des profondeurs differentes. Le <h2> n'a ni z-index ni transform
   (pas de contexte d'empilement) : ses <span> se placent par rapport au portrait. */
.hero-name {
    position: absolute;
    inset: 0;
    margin: 0;
    pointer-events: none;
}

.hero-name-back {
    font-family: var(--font-display);
    position: absolute;
    z-index: 1;
    left: 0;
    right: 0;
    top: 3%;
    text-align: center;
    white-space: nowrap;
    font-size: clamp(74px, 23.5vw, 230px);
    font-weight: 800;
    line-height: 0.85;
    letter-spacing: -0.045em;
    /* lettres "vides" : contour lumineux + leger degrade a l'interieur */
    color: transparent;
    -webkit-text-stroke: 1.5px rgba(160, 186, 255, 0.58);
    background: linear-gradient(180deg, rgba(120, 150, 255, 0.22), rgba(120, 150, 255, 0.02));
    -webkit-background-clip: text;
    background-clip: text;
    transform: translate3d(calc(var(--hp, 0) * -9vw), calc(var(--hp, 0) * -6vh), 0);
}

.hero-name-front {
    font-family: var(--font-display);
    position: absolute;
    z-index: 3;
    left: 0;
    right: 0;
    bottom: 2%;
    text-align: center;
    white-space: nowrap;
    font-size: clamp(32px, 12.4vw, 104px);
    font-weight: 800;
    line-height: 1;
    letter-spacing: 0.02em;
    color: #fff;
    text-shadow: 0 8px 36px rgba(4, 7, 20, 0.7);
    transform: translate3d(calc(var(--hp, 0) * 8vw), calc(var(--hp, 0) * 5vh), 0);
}

.hero-portrait-wrap {
    position: absolute;
    z-index: 2;
    inset: 0;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    pointer-events: none;
}

.hero-portrait {
    display: block;
    height: 100%;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    object-position: 50% 100%;
    transform-origin: 50% 100%;
    transform:
        translate3d(calc((var(--px, 0.5) - 0.5) * -18px), calc(var(--hp, 0) * 7% + (var(--py, 0.5) - 0.5) * -10px), 0)
        scale(calc(1 + var(--hp, 0) * 0.08));
    will-change: transform;
}

/* --- Texte d'accroche et boutons --- */
.hero-info {
    grid-area: info;
    position: relative;
    z-index: 4;
    text-align: center;
    transform: translate3d(0, calc(var(--hp, 0) * -34px), 0);
    opacity: calc(1 - var(--hp, 0) * 1.5);
}

.role-line {
    margin: 0;
    font-size: clamp(15px, 4.3vw, 19px);
    font-weight: 600;
    line-height: 1.35;
    color: #dce9ff;
}

.hero-slogan {
    margin: 5px 0 0;
    font-size: clamp(13px, 3.7vw, 16px);
    font-weight: 500;
    color: #7fa6ff;
}

.hero-info .subtitle {
    display: none; /* redondant avec la section "A propos" sur petit ecran */
    margin: 14px 0 0;
    font-size: 16px;
    line-height: 1.65;
    color: #aebcd9;
}

.hero-buttons {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.hero-buttons .btn {
    flex: 1;
    padding: 14px 8px;
    font-size: 14px;
    line-height: 1.4;
    text-align: center;
    white-space: nowrap;
}

/* --- Indicateur de scroll : un trait avec un point qui coule --- */
.hero-scroll-cue {
    position: absolute;
    z-index: 5;
    left: 50%;
    bottom: calc(60px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin-left: -30px;
    width: 60px;
    color: rgba(199, 211, 232, 0.78);
    text-decoration: none;
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.3em;
    text-indent: 0.3em;
    text-transform: uppercase;
    opacity: calc(1 - var(--hp, 0) * 6);
}

.hero-scroll-line {
    position: relative;
    display: block;
    width: 1px;
    height: 30px;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.2);
}

.hero-scroll-line i {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 14px;
    background: linear-gradient(180deg, transparent, #a9bfff);
    animation: cueDrop 1.9s var(--ease-io) infinite;
}

@keyframes cueDrop {
    from { transform: translateY(-110%); }
    to { transform: translateY(260%); }
}

/* Le bandeau d'applications (defini dans style.css) passe au-dessus des calques */
.hero-marquee {
    z-index: 5;
    padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
}

/* Chaque calque du hero est promu sur sa propre couche GPU : pendant le scroll, seul le
   compositeur deplace/fond ces couches, sans re-dessiner le texte ni les degrades. */
.hero-inner,
.hero-eyebrow,
.hero-info,
.hero-rings,
.hero-name-back,
.hero-name-front,
.hero-portrait-wrap {
    will-change: transform, opacity;
}

.hero::after {
    will-change: opacity;
}

/* Une fois le hero recouvert, on libere ces couches (memoire) */
.hero.is-covered .hero-inner,
.hero.is-covered .hero-eyebrow,
.hero.is-covered .hero-info,
.hero.is-covered .hero-rings,
.hero.is-covered .hero-name-back,
.hero.is-covered .hero-name-front,
.hero.is-covered .hero-portrait-wrap,
.hero.is-covered::after {
    will-change: auto;
}

/* Hero entierement recouvert : on coupe le rendu (economie de batterie) */
.hero.is-covered .hero-inner,
.hero.is-covered .hero-bg,
.hero.is-covered .hero-marquee,
.hero.is-covered .hero-scroll-cue {
    visibility: hidden;
}

/* --- Entree du hero, quand le rideau du prechargeur se leve ---
   Etat de depart cache (sous .js) ; les animations utilisent "backwards" : pendant le delai
   on affiche l'image de depart, puis l'element revient a son style normal (celui qui porte
   aussi les transformations liees au scroll). */
.js:not(.is-ready) .hero-eyebrow,
.js:not(.is-ready) .hero-info,
.js:not(.is-ready) .hero-portrait-wrap,
.js:not(.is-ready) .hero-name-back,
.js:not(.is-ready) .hero-name-front,
.js:not(.is-ready) .hero-rings,
.js:not(.is-ready) .hero-stage::before,
.js:not(.is-ready) .hero-scroll-cue,
.js:not(.is-ready) .hero-marquee {
    opacity: 0;
}

.js.is-ready .hero-portrait-wrap {
    animation: heroRise 1.5s var(--ease-out) 0.05s backwards;
}

.js.is-ready .hero-name-back {
    animation: heroWord 1.4s var(--ease-out) 0.15s backwards;
}

.js.is-ready .hero-name-front {
    animation: heroWordUp 1.2s var(--ease-out) 0.5s backwards;
}

.js.is-ready .hero-rings {
    animation: heroRings 1.8s var(--ease-out) 0.1s backwards;
}

.js.is-ready .hero-stage::before {
    animation: heroGlow 1.8s ease-out backwards;
}

.js.is-ready .hero-eyebrow {
    animation: heroFade 0.9s var(--ease-out) 0.2s backwards;
}

.js.is-ready .hero-info {
    animation: heroFadeUp 1.1s var(--ease-out) 0.7s backwards;
}

.js.is-ready .hero-scroll-cue,
.js.is-ready .hero-marquee {
    animation: heroFade 1.2s ease-out 1.3s backwards;
}

@keyframes heroRise {
    from { opacity: 0; transform: translate3d(0, 9%, 0) scale(0.96); }
}

@keyframes heroWord {
    from { opacity: 0; transform: translate3d(0, 14%, 0) scale(1.08); }
}

@keyframes heroWordUp {
    from { opacity: 0; transform: translate3d(0, 55%, 0); }
}

@keyframes heroRings {
    from { opacity: 0; transform: scale(0.55); }
}

@keyframes heroGlow {
    from { opacity: 0; }
}

@keyframes heroFade {
    from { opacity: 0; }
}

@keyframes heroFadeUp {
    from { opacity: 0; transform: translate3d(0, 26px, 0); }
}

/* Mobile : le hero est un peu plus court que l'ecran, si bien que le haut de la "feuille"
   (le bandeau geant) depasse au bas du premier ecran : une invitation visuelle a scroller. */
@media (max-width: 900px) and (min-height: 600px) {
    .hero {
        height: calc(100vh - 54px);
        height: calc(100svh - 54px);
    }

    .hero-inner {
        padding-bottom: calc(132px + env(safe-area-inset-bottom, 0px));
    }
}

/* --- Desktop : texte a gauche, scene a droite --- */
@media (min-width: 901px) {
    .hero {
        min-height: 620px;
    }

    .hero-inner {
        grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
        grid-template-areas: 'copy stage';
        column-gap: 2vw;
        padding-top: calc(var(--nav-h) + 8px);
        padding-bottom: 104px;
    }

    .hero-copy {
        grid-area: copy;
        position: relative;
        z-index: 4;
        display: flex;
        flex-direction: column;
        justify-content: center;
        gap: 18px;
        padding-right: 1vw;
    }

    .hero-eyebrow {
        grid-area: auto;
        text-align: left;
        font-size: 13px;
        letter-spacing: 0.24em;
    }

    .hero-info {
        grid-area: auto;
        text-align: left;
    }

    .role-line {
        font-size: clamp(20px, 2.1vw, 28px);
        line-height: 1.3;
    }

    .hero-slogan {
        font-size: clamp(16px, 1.5vw, 20px);
        margin-top: 8px;
    }

    .hero-info .subtitle {
        display: block;
        max-width: 540px;
    }

    .hero-buttons {
        gap: 16px;
        margin-top: 28px;
    }

    .hero-buttons .btn {
        flex: 0 0 auto;
        padding: 15px 30px;
        font-size: 15px;
    }

    .hero-name-back {
        font-size: clamp(110px, 13.8vw, 250px);
        top: 2%;
    }

    .hero-name-front {
        font-size: clamp(54px, 7.4vw, 120px);
        bottom: 3%;
    }

    .hero-scroll-cue {
        bottom: 62px;
    }
}

/* Grands ecrans : la scene occupe plus de largeur */
@media (min-width: 1600px) {
    .hero-inner {
        max-width: 1500px;
    }
}

/* Ecrans tres bas (telephone en paysage) : pas de rideau, hero qui suit le flux */
@media (max-height: 560px) {
    .hero {
        position: relative;
        height: auto;
        min-height: 100svh;
    }

    .hero-stage {
        min-height: 300px;
    }
}

/* --- Theme clair : memes calques, couleurs adaptees --- */
.light-theme .hero {
    background:
        radial-gradient(120% 70% at 50% 0%, #e3ebff 0%, transparent 62%),
        linear-gradient(180deg, #f8faff 0%, #eef2fb 100%);
}

.light-theme .hero::after {
    background: #f6f8fc;
}

.light-theme .hero-spot {
    background: radial-gradient(560px circle at var(--mx, 68%) var(--my, 42%), rgba(79, 110, 255, 0.14), transparent 62%);
}

.light-theme .hero-stage::before {
    background: radial-gradient(closest-side, rgba(84, 116, 255, 0.34), rgba(124, 77, 255, 0.14) 46%, transparent 72%);
}

.light-theme .hero-ring {
    border-color: rgba(55, 90, 190, 0.22);
}

.light-theme .hero-name-back {
    -webkit-text-stroke-color: rgba(55, 85, 200, 0.42);
    background-image: linear-gradient(180deg, rgba(79, 110, 255, 0.2), rgba(79, 110, 255, 0.02));
}

.light-theme .hero-name-front {
    color: #0f1a33;
    text-shadow: 0 6px 30px rgba(255, 255, 255, 0.8);
}

.light-theme .hero-eyebrow {
    color: #2f5fc4;
}

.light-theme .role-line {
    color: #15233d;
}

.light-theme .hero-slogan {
    color: #2f5fc4;
}

.light-theme .hero-info .subtitle {
    color: #46566f;
}

.light-theme .hero-scroll-cue {
    color: rgba(30, 45, 80, 0.7);
}

.light-theme .hero-scroll-line {
    background: rgba(16, 27, 45, 0.2);
}

.light-theme .hero-scroll-line i {
    background: linear-gradient(180deg, transparent, #2f5fc4);
}

.light-theme .hero-marquee {
    background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.75));
    border-top-color: rgba(16, 27, 45, 0.08);
}

.light-theme .hero-marquee-item {
    color: #31415f;
}

/* ---------- 4. La "feuille" qui recouvre le hero ---------- */
.page-sheet {
    position: relative;
    z-index: 2;
    background: var(--sheet-bg);
    border-radius: 32px 32px 0 0;
    border-top: 1px solid rgba(150, 175, 255, 0.16);
    box-shadow: 0 -28px 70px rgba(2, 4, 12, 0.6);
}

.light-theme .page-sheet {
    border-top-color: rgba(16, 27, 45, 0.08);
    box-shadow: 0 -28px 70px rgba(33, 59, 112, 0.16);
}

/* ---------- 5. Bandeaux typographiques (scroll-lies) ---------- */
.band {
    overflow: hidden;
    padding: clamp(30px, 6vw, 64px) 0 clamp(14px, 3vw, 36px);
    user-select: none;
    -webkit-user-select: none;
}

.band-row {
    display: flex;
    width: max-content;
    will-change: transform;
}

.band-row + .band-row {
    margin-top: 0.06em;
}

.band-seq {
    font-family: var(--font-display);
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 0.5em;
    padding-right: 0.5em;
    font-size: clamp(34px, 9.6vw, 124px);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -0.03em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--fg);
}

/* Losange decoratif entre les mots (pas de glyphe : identique sur tous les appareils) */
.band-seq b {
    flex: none;
    width: 0.2em;
    height: 0.2em;
    border-radius: 14%;
    background: var(--accent-grad);
    transform: rotate(45deg);
}

.band-row--outline .band-seq {
    color: transparent;
    -webkit-text-stroke: 1.5px rgba(150, 178, 255, 0.42);
}

.band-row--outline .band-seq b {
    background: none;
    border: 2px solid rgba(150, 178, 255, 0.6);
}

.band--cta {
    padding-top: clamp(40px, 7vw, 90px);
    padding-bottom: 0;
}

.band--cta .band-seq {
    font-size: clamp(30px, 7.6vw, 100px);
}

.light-theme .band-row--outline .band-seq {
    -webkit-text-stroke-color: rgba(45, 75, 170, 0.42);
}

.light-theme .band-row--outline .band-seq b {
    border-color: rgba(45, 75, 170, 0.55);
}

/* ---------- 6. Systeme d'apparition (.rv) ---------- */
/* Etat cache avant apparition (uniquement si JS actif) */
.js .rv {
    opacity: 0;
}

/* Quand l'element entre dans l'ecran, js/motion.js ajoute .is-in : l'animation part de
   l'etat decale (--rx/--ry/--rs) et revient au style normal de l'element. Le fill-mode
   "backwards" evite qu'une transformation figee n'ecrase les effets :hover. */
.js .rv.is-in {
    opacity: 1;
    animation: rvIn 0.95s var(--ease-out) var(--d, 0s) backwards;
}

.rv {
    --rx: 0px;
    --ry: 42px;
    --rs: 1;
}

.rv-left { --rx: -52px; --ry: 0px; }
.rv-right { --rx: 52px; --ry: 0px; }
.rv-zoom { --rx: 0px; --ry: 22px; --rs: 0.9; }

@keyframes rvIn {
    from {
        opacity: 0;
        transform: translate3d(var(--rx), var(--ry), 0) scale(var(--rs));
    }
}

/* Titres de section : le texte monte depuis un masque, puis le trait d'accent se dessine */
.js .section-title .tm {
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    padding: 0.1em 0.04em 0.16em;
    margin: -0.1em -0.04em -0.16em;
}

.js .section-title .tm-in {
    display: inline-block;
    transform: translate3d(0, 118%, 0);
}

.js .section-title.is-in .tm-in {
    transform: none;
    transition: transform 1.05s var(--ease-out);
}

.js .section-title::after {
    transform: translateX(-50%) scaleX(0);
    transition: transform 0.9s var(--ease-out) 0.3s;
}

.js .section-title.is-in::after {
    transform: translateX(-50%) scaleX(1);
}

/* "A propos" : les mots s'allument au fil de la lecture (piloté par le scroll) */
.js .lw .w {
    opacity: 0.2;
    transition: opacity 0.12s linear; /* courte : des dizaines de mots changent par seconde de scroll */
}

.js .lw .w.lit {
    opacity: 1;
}

/* ---------- 7. Timeline qui se dessine ---------- */
.timeline::after {
    content: '';
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 19px;
    width: 2px;
    background: var(--accent-grad-v);
    box-shadow: 0 0 12px rgba(99, 132, 255, 0.6);
    transform-origin: 50% 0;
    transform: scaleY(var(--tl, 0));
    will-change: transform;
    pointer-events: none;
}

/* Point lumineux qui descend le long du trait (cree par JS) */
.timeline-head {
    position: absolute;
    z-index: 2;
    left: 13px;
    top: 4px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 4px rgba(99, 132, 255, 0.35), 0 0 22px 6px rgba(99, 132, 255, 0.7);
    transform: translate3d(0, calc(var(--tl, 0) * var(--tl-h, 0px)), 0);
    will-change: transform;
    pointer-events: none;
}

.js .timeline-item {
    opacity: 0.4;
    transition: opacity 0.6s ease;
}

.js .timeline-item.is-active {
    opacity: 1;
}

.timeline-content {
    transition: transform 0.7s var(--ease-out), border-color 0.5s ease, box-shadow 0.5s ease;
}

.js .timeline-item:not(.is-active) .timeline-content {
    transform: translate3d(14px, 0, 0);
}

.timeline-item.is-active .timeline-content {
    border-color: rgba(120, 155, 255, 0.5);
}

.timeline-item.is-active .timeline-dot {
    color: #fff;
    background: var(--accent-grad);
    border-color: rgba(170, 195, 255, 0.9);
    box-shadow: 0 0 26px rgba(99, 132, 255, 0.75);
}

/* ---------- 8. Projets ---------- */
/* Desktop : inclinaison 3D au survol (js/motion.js ajoute .is-tilting et --rx/--ry/--mx/--my) */
@media (hover: hover) and (pointer: fine) {
    .project-card::before {
        content: '';
        position: absolute;
        inset: 0;
        z-index: 3;
        pointer-events: none;
        opacity: 0;
        background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), rgba(255, 255, 255, 0.13), transparent 55%);
        transition: opacity 0.3s ease;
    }

    .project-card.is-tilting {
        transform: perspective(1000px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(-6px);
        transition: transform 0.12s linear, border-color 0.3s ease, box-shadow 0.3s ease;
    }

    .project-card.is-tilting::before {
        opacity: 1;
    }
}

/* Mobile : pile de cartes. Chaque carte s'epingle puis la suivante glisse par-dessus
   (la carte recouverte rapetisse et s'assombrit : variables --sc / --dy / --dim ecrites par JS). */
.projects-grid.is-deck {
    display: block;
}

.projects-grid.is-deck .project-card {
    position: sticky;
    top: calc(var(--nav-h) + 4px);
    margin-bottom: 22px;
    transform-origin: 50% 0;
    transform: translate3d(0, var(--dy, 0px), 0) scale(var(--sc, 1));
    transition: none;
    will-change: transform;
}

.projects-grid.is-deck .project-card:hover {
    transform: translate3d(0, var(--dy, 0px), 0) scale(var(--sc, 1));
}

/* Fond OPAQUE obligatoire : les cartes se recouvrent, un fond translucide laisserait
   voir le texte de la carte du dessous. */
.projects-grid.is-deck .project-card {
    background: linear-gradient(145deg, #141b2e 0%, #0e1424 100%);
}

.light-theme .projects-grid.is-deck .project-card {
    background: linear-gradient(145deg, #ffffff 0%, #f3f6fc 100%);
}

.projects-grid.is-deck .project-card.no-stick {
    position: relative;
    top: auto;
}

/* Voile sombre progressif sur les cartes recouvertes */
.projects-grid.is-deck .project-card::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 4;
    pointer-events: none;
    border-radius: inherit;
    background: #04060c;
    opacity: var(--dim, 0);
}

/* ---------- 9. Barre de navigation : lien actif ---------- */
.nav-links a.is-active {
    color: #fff;
    background: rgba(55, 115, 212, 0.3);
}

.light-theme .nav-links a.is-active {
    color: var(--primary);
    background: rgba(55, 115, 212, 0.13);
}

/* ---------- 10. Mot geant du footer ---------- */
/* Le footer est desormais HORS de la feuille (le <main> s'arrete avant lui) : il porte
   donc lui-meme le fond opaque de la page. */
.footer {
    position: relative;
    z-index: 2;
    overflow: hidden;
    padding-bottom: 0;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.02)),
        var(--sheet-bg);
}

.light-theme .footer {
    background:
        linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)),
        var(--sheet-bg);
}

.footer-wordmark {
    font-family: var(--font-display);
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    column-gap: 0.28em;
    margin-top: 34px;
    margin-bottom: 18px;
    font-size: clamp(40px, 17.5vw, 290px);
    font-weight: 800;
    line-height: 0.96;
    letter-spacing: -0.05em;
    text-transform: uppercase;
    color: transparent;
    -webkit-text-stroke: 1.5px rgba(150, 178, 255, 0.34);
    user-select: none;
    -webkit-user-select: none;
    white-space: nowrap;
}

.footer-wordmark .fw {
    display: inline-flex;
    overflow: hidden;
    padding-bottom: 0.06em;
}

.js .footer-wordmark .fl {
    display: inline-block;
    transform: translate3d(0, 108%, 0);
    transition: transform 1s var(--ease-out);
    transition-delay: calc(var(--i, 0) * 50ms);
}

.js .footer-wordmark.is-in .fl {
    transform: none;
}

.light-theme .footer-wordmark {
    -webkit-text-stroke-color: rgba(45, 75, 170, 0.36);
}

@media (min-width: 901px) {
    .footer-wordmark {
        font-size: clamp(60px, 10vw, 220px);
    }
}

/* ---------- 10b. Mobile : rythme plus serre, competences en 2 colonnes ---------- */
@media (max-width: 768px) {
    .cv-section,
    .about,
    .timeline-section,
    .skills,
    .projects,
    .tools-section,
    .chat-section,
    .reviews-section,
    .contact {
        padding-top: 64px;
        padding-bottom: 64px;
    }

    .skills-note {
        margin-top: -22px;
        margin-bottom: 34px;
    }

    .skills-category {
        margin-bottom: 34px;
    }

    /* Cartes compactes : icone + pourcentage sur la 1re ligne, nom dessous, puis la barre */
    .skills-container {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
    }

    .skills-container > .skill-item:only-child {
        grid-column: 1 / -1;
    }

    .skill-item {
        padding: 14px 14px 16px;
        border-radius: 14px;
    }

    .skill-header {
        flex-wrap: wrap;
        gap: 6px 8px;
        margin-bottom: 4px;
    }

    .skill-header i {
        order: 1;
        font-size: 22px;
        min-width: 0;
    }

    .skill-header .percentage {
        order: 2;
        margin-left: auto;
        font-size: 13px;
    }

    .skill-header h3 {
        order: 3;
        flex: 1 0 100%;
        font-size: 14px;
        line-height: 1.3;
    }

    .progress-bar {
        height: 7px;
        margin-top: 8px;
    }
}

/* ---------- 11. Performance mobile ---------- */
/* Les flous d'arriere-plan (backdrop-filter) sur des dizaines de cartes coutent cher pendant
   le scroll sur telephone. Sur fond sombre uni, leur rendu visuel est quasi identique sans flou. */
@media (max-width: 900px) {
    .skill-item,
    .project-card,
    .stat,
    .cv-card,
    .timeline-content,
    .tool-item,
    .reviews-card,
    .chat-box,
    .btn-secondary,
    .project-badge,
    .project-lightbox {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }

    .navbar {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        background: rgba(10, 12, 20, 0.88);
    }

    .light-theme .navbar {
        background: rgba(255, 255, 255, 0.94);
    }

    .page-sheet {
        border-radius: 26px 26px 0 0;
    }
}

/* Desktop/souris : le spot lumineux n'a de sens qu'avec un curseur */
@media (hover: none) {
    .hero-spot {
        display: none;
    }
}

/* ---------- 12. Accessibilite : mouvement reduit ---------- */
@media (prefers-reduced-motion: reduce) {
    /* pas de rideau : le hero reste en flux normal (meme hauteur, meme mise en page) */
    .hero {
        position: relative;
    }

    .hero::after,
    .scroll-progress {
        display: none;
    }

    .hero-orbit,
    .hero-scroll-line i,
    .hero-eyebrow::after,
    .hero-marquee-track,
    .preloader-ripple {
        animation: none;
    }

    .js .rv,
    .js .timeline-item,
    .js .lw .w {
        opacity: 1;
    }

    .js .section-title .tm-in,
    .js .footer-wordmark .fl,
    .js .timeline-item:not(.is-active) .timeline-content {
        transform: none;
    }

    .js .section-title::after {
        transform: translateX(-50%) scaleX(1);
    }

    .js .rv.is-in,
    .js.is-ready .hero-portrait-wrap,
    .js.is-ready .hero-name-back,
    .js.is-ready .hero-name-front,
    .js.is-ready .hero-rings,
    .js.is-ready .hero-stage::before,
    .js.is-ready .hero-eyebrow,
    .js.is-ready .hero-info,
    .js.is-ready .hero-scroll-cue,
    .js.is-ready .hero-marquee {
        animation: none;
    }

    .preloader {
        transition: opacity 0.4s ease, visibility 0s linear 0.4s;
    }

    .preloader.hide {
        transform: none;
        opacity: 0;
    }
}

/* ---------- Competences : niveaux (remplacent les pourcentages) ---------- */
.skill-level {
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    color: #8fb0ff;
}
.skill-level--advanced { color: #7ee0a8; }
.skill-level--learning { color: #f2b66b; }
.skill-pips { display: flex; gap: 6px; margin-top: 12px; }
.skill-pips i {
    flex: 1;
    height: 6px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.1);
    transition: background 0.6s ease;
}
.js .skill-item.lit .skill-pips i.on { background: var(--accent-grad); }
.skill-item:not(.lit) .skill-pips i.on { background: rgba(255, 255, 255, 0.1); }
.light-theme .skill-pips i { background: rgba(16, 27, 45, 0.12); }
.light-theme .skill-level { color: #2f5fc4; }
.light-theme .skill-level--advanced { color: #14804a; }
.light-theme .skill-level--learning { color: #b36a12; }
.project-badge--client { border-color: rgba(126, 224, 168, 0.55); color: #bff3d6; }
.chip-percentage { white-space: nowrap; }
.project-badge--pack { border-color: rgba(143, 176, 255, 0.55); color: #cfdcff; }
.project-badge--study { border-color: rgba(242, 182, 107, 0.55); color: #ffe0b8; }
.project-badge--game { border-color: rgba(255, 170, 70, 0.6); color: #ffd9a3; }
