@import "tokens.css";
@import "components/header.css";
@import "components/footer.css";

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* The real scrollbar shows from the very first paint, always — not a
     reserved-but-invisible "gutter" (scrollbar-gutter: stable), which left
     a blank strip that nothing painted over, showing as a stark black band
     for the whole page-transition animation. Because it's unconditionally
     "scroll" (never toggled to "hidden" — see html.pt-locked in
     page-transition.css, which pins <body> instead), the space it occupies
     never changes, so nothing can ever shift when the overlay lifts either. */
  overflow-y: scroll;
  min-height: 100%;
  /* Root-cause fix for the "black/brown band under a short page" bug
     (FAQ filtered down to one category, very tall viewports, browser
     zoom, overscroll bounce): confirmed directly that <html> itself had
     no background-color at all, so any pixel not covered by <body>'s own
     box — which stops wherever its content ends unless something forces
     it taller — fell through to the browser's own default canvas colour,
     never this site's palette. Matches the body gradient's own darkest
     stop (not the footer's separate violet) so a sliver of exposed root
     canvas blends into the page itself, not just the footer strip. */
  background-color: #010102;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh; /* dynamic viewport unit as a progressive enhancement — see the html min-height comment above for why static 100vh alone wasn't the full fix */
  /* Real sticky footer, not a fixed-height hack: <main> is the only
     normal-flow child that actually grows (both <body>'s [data-page-
     transition] overlay and <header> are position:fixed, so they never
     participate in this flex flow at all — confirmed directly, this
     couldn't just push them around). A short page's <main> stretches to
     fill whatever's left above the footer instead of leaving a gap below
     it; a long page's <main> is already taller than the viewport, so
     `flex: 1 0 auto` changes nothing there. NOTE: while the page-load
     transition overlay is mid-animation, html.pt-locked temporarily forces
     `position: fixed` on this exact element (see page-transition.css) —
     which, being fixed, briefly stops contributing to <html>'s own
     scrollHeight at all (a real, separate, and much shorter-lived
     mechanism than the bug this flex layout fixes — resolves itself the
     instant the transition's own unlock() runs, confirmed directly). */
  display: flex;
  flex-direction: column;
  font-family: var(--font-satoshi);
  color: var(--color-foreground);
  position: relative;
  /* Bande de fond visible SOUS le footer, constatée sur l'accueil : le
     glow décoratif de partials/home/skills.njk (/experience-gradient.svg,
     2448px de haut, absolute) descend 354px sous son conteneur, donc 75px
     sous le bas du footer. Un élément en `absolute` ne fait pas grandir la
     hauteur de <body>, mais il fait grandir le scrollHeight de <html> :
     mesuré 5768px contre 5693px de <body>. Ces 75px ne sont couverts par
     rien et laissent voir le background-color de <html> (#010102) sous le
     violet du footer.

     Devenu visible en retirant le teaser tarif de l'accueil : la section
     compétences est passée en dernière position, et le débordement de son
     glow n'est plus absorbé par une section suivante.

     `overflow: clip` retire ce débordement de la zone défilable en plus de
     ne plus le peindre — c'est ce qui ramène le scrollHeight de <html> à la
     hauteur réelle de <body>. Et surtout : clipper à la boîte de <body>
     n'ampute AUCUN effet voulu, puisque tout le contenu réel y est. Un
     second glow (partials/home/experience.njk) bleed 226px au-dessus de
     .home-legacy — clipper ce conteneur-là l'aurait coupé, clipper <body>
     ne le touche pas.

     `clip` et non `hidden` : `hidden` ferait de <body> un conteneur de
     défilement, avec la seconde barre de défilement que ce projet a déjà
     rencontrée (voir la note sur .home-legacy dans tailwind-home.css).
     `clip` ne crée jamais de conteneur de défilement, et ne devient pas
     bloc conteneur des descendants en position: fixed — l'en-tête et le
     rideau de transition ne sont donc pas rognés. */
  overflow: clip;
  /* Real bug fix, not a colour tweak: position:relative alone (z-index:auto)
     does NOT create a stacking context, so body::before/::after below
     (z-index:-1) were escaping all the way to the document root instead of
     nesting just behind body's own content — landing BEHIND body's own
     background paint too, which silently hid half the nebula (confirmed by
     forcing a stacking context and watching the missing violet/rose glow
     reappear). .page-transition never had this problem: it already sets its
     own explicit z-index (10000). */
  z-index: 0;
  /* Same dark-universe background as the rocket page-transition overlay
     (see css/components/page-transition.css), minus the star field — a
     genuinely dark universe: mostly black/near-black voids, a little deep
     violet, and only the faintest whisper of violet/rose colour. Anchored
     to the viewport (not the full scrollable height) so the nebula reads
     the same regardless of how long the page is. */
  background-color: #010102;
  background-image:
    /* Each patch gets an explicit vmax radius instead of the default
       "farthest-corner" sizing — on a wide/short viewport, farthest-corner
       measures from an off-center point to the *diagonally opposite*
       corner, which balloons on ultra-wide screens and produces a hard,
       flat dark band along one edge instead of a soft localized patch.
       A fixed vmax radius stays proportional to screen size without that
       aspect-ratio blow-up. */
    radial-gradient(circle 40vmax at 12% 82%, rgba(0, 0, 0, 0.65), transparent),
    radial-gradient(circle 42vmax at 88% 12%, rgba(0, 0, 0, 0.6), transparent),
    radial-gradient(circle 36vmax at 65% 92%, rgba(0, 0, 0, 0.55), transparent),
    radial-gradient(circle 34vmax at 6% 22%, rgba(0, 0, 0, 0.5), transparent),
    radial-gradient(circle 42vmax at 20% 15%, rgba(88, 28, 135, 0.14), transparent),
    radial-gradient(circle 44vmax at 84% 20%, rgba(168, 168, 178, 0.16), transparent),
    radial-gradient(circle 48vmax at 74% 84%, rgba(157, 23, 77, 0.09), transparent),
    radial-gradient(circle 58vmax at 50% 48%, rgba(49, 46, 129, 0.08), transparent),
    linear-gradient(180deg, #04040c 0%, #010106 55%, #000000 100%);
  background-attachment: fixed;
}

/* The same two softly blurred colour blobs drifting slowly, reusing the
   pt-nebula-drift-a/b keyframes already defined in page-transition.css
   (loaded on every page right alongside this stylesheet). Fixed + behind
   everything, so it reads as one continuous backdrop while scrolling. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: -25%;
  z-index: -1;
  pointer-events: none;
  filter: blur(70px);
  will-change: translate;
}

body::before {
  background: radial-gradient(circle 65vmax at 28% 32%, rgba(124, 58, 237, 0.22), transparent);
  animation: pt-nebula-drift-a 16s ease-in-out infinite;
}

body::after {
  background: radial-gradient(circle 65vmax at 72% 70%, rgba(219, 39, 119, 0.1), transparent);
  animation: pt-nebula-drift-b 20s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  body::before,
  body::after {
    animation: none;
  }
}

/* Sticky footer, main half: grows to fill any leftover height above the
   footer on a short page (see body's display:flex/flex-direction:column
   above and .site-footer's margin-top:auto in footer.css) — `0 auto`
   keeps its basis at its own natural content height on long pages, so
   this never shrinks a page that's already taller than the viewport. */
main {
  flex: 1 0 auto;
  min-width: 0;
}

img,
video {
  max-width: 100%;
  display: block;
}

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

/* Scroll-reveal: JS adds .is-visible when a [data-reveal] element enters the viewport (see js/reveal.js) */
[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Champ leurre anti-bot (partials/honeypot.njk). Volontairement PAS
   display:none : certains bots sautent les champs masqués ainsi, et le
   piège ne prendrait plus rien. Hors écran, il reste dans le DOM. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
