/* ============================================================
   Décisions de design propres à cette landing page, déclarées
   UNE fois plutôt que répétées dans les règles.
   ⚠️ L'échelle du thème Snopixis s'arrête à --space-6 (24px) et
   n'expose aucun token de breakpoint : les media queries (640px,
   700px) restent donc en dur, faute de token à référencer.
   ============================================================ */
:root {
    --pf-section-padding: calc(var(--space-6) * 2);   /* 48px — respiration verticale d'une section */
    --pf-content-max: 1080px;                         /* largeur de lecture du contenu */
    --pf-card-width: var(--container-width-sm);       /* 320px — largeur d'une carte du carrousel */
    --pf-aurora-secondary: #8b5cf6;                   /* 2e teinte de l'aurora du hero */
}

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

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background-color: var(--color-bg);
    color: var(--color-text-primary);
}

.blazor-error-boundary {
    background: var(--color-danger);
    padding: 1rem 1rem 1rem 3.7rem;
    color: var(--color-text-inverse);
}

.blazor-error-boundary::after {
    content: "Une erreur est survenue.";
}

/* Détail projet (dialog) : la description est saisie en texte libre dans l'Admin —
   on préserve ses retours à la ligne (règle globale, la classe atterrit sur le <p> de SxText). */
.project-detail__description {
    white-space: pre-line;
}

/* Détail projet — layout côte à côte (image | texte). SxStack ne fait que du 50/50 (flex:1) :
   on pilote le ratio par flex-basis en classe globale (la base .sx-stack ne pose aucun flex d'item,
   donc pas de conflit de spécificité scopé). L'image a une grande base et absorbe l'espace restant
   (flex-grow 1), le texte reste à sa largeur (flex-grow 0). Les min-width font wrapper les deux
   colonnes → empilé quand le dialog est étroit (mobile). */
/* Largeur définie de la modale de détail — lève l'ambiguïté de shrink-to-fit du dialog scroll-container
   (sinon un contenu flex-wrap se réduit à son plus grand item et s'empile). Remplit le XXL (plafond
   1200) sur desktop, 88vw sur mobile (où le contenu wrappe → empilé). */
.project-detail { width: min(88vw, 1120px); max-width: 100%; }
.project-detail__media { flex: 1 1 560px; min-width: 240px; }
.project-detail__text  { flex: 0 1 320px; min-width: 220px; }

/* ============================================================
   Portfolio — animations & polish (piloté par attributs data-*
   posés en JS : robustes aux re-renders Blazor). Tout se coupe
   proprement avec prefers-reduced-motion (voir bloc en bas).
   ============================================================ */

html {
    scroll-behavior: smooth;
}

/* ---- Rythme « une section = un écran » ----
   `mandatory` : le scroll saute vraiment d'un écran à l'autre. C'est sûr parce qu'aucune section
   ne dépasse la hauteur d'écran — les projets passent par un carrousel horizontal, dont la hauteur
   ne dépend plus du nombre de projets. */
html {
    scroll-snap-type: y mandatory;
}
/* ⚠️ Filet de sécurité — piloté par reveal.js, PAS par un seuil de media query deviné :
   le JS mesure les sections et pose `data-overflow` sur <html> dès que l'une dépasse la vue
   (contenu qui s'accumule, fenêtre basse…). L'aimantation repasse alors en souple, sinon le bas
   de cette section deviendrait pénible à atteindre. Se recalcule au redimensionnement et à
   chaque changement de contenu, donc ça s'auto-corrige quand le site se remplit. */
html[data-overflow] {
    scroll-snap-type: y proximity;
}
/* Ciblé par la classe et non par les 5 ids : `.section-band` EST la définition d'une section,
   les ids ne servent qu'aux ancres (SxSectionDots, reveal.js). */
.section-band {
    scroll-snap-align: start;
    min-height: 100svh;           /* svh : hauteur stable malgré les barres mobiles */
    justify-content: center;      /* contenu court → centré, ça se lit comme un choix */
    position: relative;
    overflow: hidden;             /* borne les décors qui débordent */
}

/* ---- Reveal au scroll (fondu de la section) ---- */
[data-reveal] {
    opacity: 0;
    transition: opacity 0.6s ease;
}
[data-reveal][data-revealed] {
    opacity: 1;
}

/* ⚠️ `sx-rise` reste ici, en global, parce qu'il est PARTAGÉ : le hero et les cartes de 3
   sections s'en servent, depuis 4 fichiers scopés différents. Un @keyframes déclaré dans un
   .razor.css est renommé (`sx-rise` → `sx-rise-b-xxx`) et devient invisible pour les autres ;
   un nom externe, lui, est laissé intact par le scoping — c'est ce qui rend ce partage possible.
   Les animations propres à UN composant sont, elles, déclarées chez lui.
   Le reste de l'animation des cartes (opacité initiale, délais en cascade) vit désormais dans
   ProjectsSection / TimelineSection / ContactSection.razor.css. */
@keyframes sx-rise {
    from { opacity: 0; transform: translateY(22px); }
    to   { opacity: 1; transform: none; }
}

/* ============================================================
   Décors de section — un univers par section, en arrière-plan.
   Règle d'or : ça doit se remarquer sans jamais gêner la lecture
   → faible opacité + masque radial qui calme le motif au centre.

   Seul le SOCLE commun aux 5 décors vit ici : il est posé par la page
   (`#accueil > .decor`, `[data-revealed] > .decor`), donc hors de portée
   d'un CSS scopé de composant. Chaque décor définit son propre motif et
   son `--decor-opacity` dans son `.razor.css` (Components/Decor/).
   ============================================================ */
.decor {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 1.4s ease;
    /* Motif riche sur les bords, effacé au centre là où vit le texte */
    -webkit-mask-image: radial-gradient(ellipse 62% 54% at 50% 50%, transparent 18%, rgba(0, 0, 0, 0.5) 52%, #000 82%);
    mask-image: radial-gradient(ellipse 62% 54% at 50% 50%, transparent 18%, rgba(0, 0, 0, 0.5) 52%, #000 82%);
}
#accueil > .decor,
[data-revealed] > .decor {
    opacity: var(--decor-opacity, 0.25);
}

/* ---- Bandes de section : pleine largeur, chaque section = un chapitre ----
   Pas d'arrondi ni de marge extérieure : le décor doit toucher les bords de l'écran, sinon les
   sections se lisent comme des cartes posées sur une page. C'est le CONTENU qui est contraint
   par une largeur max lisible, pas la section.
   Les sections étant des `<section>` brutes, cette règle reprend aussi la mise en page de
   colonne qu'assurait SxStack (`--space-5` = 20px = `GapSize.Lg`). Elle reste globale parce
   qu'elle est commune aux 5 sections — chacune n'emporte dans son .razor.css que ce qui lui
   est propre. */
.section-band {
    display: flex;
    flex-direction: column;
    align-items: stretch;   /* explicite : c'est ce que posait SxStack (AlignItems=Stretch) */
    gap: var(--space-5);
    padding: var(--pf-section-padding) var(--space-6);
}
/* Contenu : largeur de lecture bornée et centrée, et au-dessus du décor et de l'aurora.
   Un seul sélecteur pour les deux effets — il désigne exactement le même ensemble que les
   cinq `#accueil > * …, #projets > * …` qu'il remplace. Les deux exclusions sont les éléments
   positionnés en absolu, qui doivent rester libres de se placer. */
.section-band > *:not(.decor):not(.scroll-cue) {
    width: 100%;
    max-width: var(--pf-content-max);
    margin-inline: auto;
    position: relative;
    z-index: 1;
}

/* ---- Les titres de section ne doivent pas avaler les clics ----
   ⚠️ Un titre occupe toute la largeur de lecture alors que son texte est court (« 02 Parcours »).
   Sa moitié droite, vide et invisible, interceptait pourtant les clics : mesuré, la rose des vents
   du décor n'était atteignable qu'à 20 %. Même remède que pour le hero — le conteneur devient
   traversant, le texte récupère le pointeur et reste donc sélectionnable.
   Règle globale car `SectionHeading` est partagé par les quatre sections. */
.section-heading {
    pointer-events: none;
}
.section-heading .sx-text {
    pointer-events: auto;
}

/* ---- Bouton de thème flottant ---- */
.theme-toggle {
    position: fixed;
    top: var(--space-4);
    right: var(--space-4);
    z-index: 60;
    background-color: color-mix(in srgb, var(--color-bg) 72%, transparent);
    backdrop-filter: blur(8px);
    border-radius: var(--radius-md);
}

/* Les points de navigation latéraux sont le composant `SxSectionDots` du RCL Snopixis.UI :
   il porte son propre CSS scopé, rien à déclarer ici. */

/* ---- Mobile ----
   Ne reste ici que ce qui vaut pour TOUTES les sections ; les replis propres à une section
   (carte de visite compacte, largeur des cartes du carrousel…) sont dans son .razor.css. */
@media (max-width: 640px) {
    /* Padding vertical resserré : avec 24px, la section Contact (formulaire + carte liens
       empilés) dépassait la hauteur d'écran — et en snap `mandatory` son bas devenait
       pénible à atteindre. */
    .section-band {
        padding: var(--space-3) var(--space-4);
    }
}

/* ---- Accessibilité : on coupe tout ----
   ⚠️ Couper les animations ne suffit pas : celles qui PORTENT l'état final (opacité des cartes,
   tracé du filet de titre, centrage de la flèche…) laisseraient leur cible invisible ou décalée.
   Cet état final doit donc être redonné à la main — et il l'est au plus près de chaque élément,
   dans le `.razor.css` du composant concerné. Ne reste ici que ce qui est global. */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
    }
    /* Le fondu d'entrée des sections, piloté par reveal.js */
    [data-reveal] {
        opacity: 1 !important;
    }
}
