/* ═══════════════════════════════════════════════════════════
   CŒUR ASTRAL - NUIT ÉDITORIALE BASE
   ═══════════════════════════════════════════════════════════

   Base type, sky, decor helpers and accessibility rules of the redesign.
   Loaded on every page, after tokens.css. Every selector starts with html,
   body.ui-v2, .ui-v2 or a .ca- class, so legacy selectors stay untouched. */

/* ─────────────────────────────────────────────────────────────
   DOCUMENT
   No background here: the sky set on body propagates to the canvas, so
   short pages and overscroll stay sky, never white.
   color-scheme: dark is set on each v2 form control in components.css; the
   page-wide switch waits until legacy native radios are gone (3:1 contrast).
   ───────────────────────────────────────────────────────────── */
html {
  scroll-padding-top: var(--scroll-offset);
}

/* Keyboard focus scrolls clear of the open cookie card at every width
   (WCAG 2.4.11). Scroll padding only works on the root scroller, hence
   html (cookie-consent.js publishes the space). */
html:has(> body.ui-v2 > .ca-cookie-consent--visible) {
  scroll-padding-bottom: calc(var(--ca-cookie-consent-space, 0px) + var(--sp-12));
}

body.ui-v2 {
  background-color: var(--night-900);
  color: var(--ivory-300);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ─────────────────────────────────────────────────────────────
   SKY
   Three static layers with pairwise-coprime tiles (773/547/389 px), so the
   pattern never visibly repeats. Each page may shift it with --sky-pos
   (one position per layer) so two successive screens never share a sky.
   The éclats (773) are drawn by the SPARKLE RULE below; the empty first
   slot keeps each --sky-pos entry on its own layer (éclats, étoiles,
   poussière), so no page changes its value.
   ───────────────────────────────────────────────────────────── */
.ca-sky {
  background-color: var(--night-900);
  background-image:
    none,
    url("../../images/v2/ciel-etoiles-547.svg"),
    url("../../images/v2/ciel-poussiere-389.svg");
  background-size: 773px 773px, 547px 547px, 389px 389px;
  background-repeat: repeat;
  background-position: var(--sky-pos, -500px -300px, 80px 400px, -230px -90px);
}

/* Calm sky for reading and data screens: no bright sparks. Extra
   --sky-pos entries are ignored. */
.ca-sky.ca-sky--calme {
  background-image:
    url("../../images/v2/ciel-etoiles-547.svg"),
    url("../../images/v2/ciel-poussiere-389.svg");
  background-size: 547px 547px, 389px 389px;
}

/* ─────────────────────────────────────────────────────────────
   SPARKLE RULE (ALS-1190)
   The éclats layer is a ::before of the sky. Below 1224px it is at full
   strength, as in the approved mobile mockups: plein keeps its three
   layers and stays distinct from calme, and a page whose content meets a
   spark moves it with its own --sky-pos (match moment, calendar). From
   1224px (the --sky-clear column, the widest v2 content box) the layer is
   masked so text and gauges stay readable: faint (--sky-sparkle-under)
   everywhere by default, and on body at full strength outside the
   central --sky-clear column, ramping over --sky-feather. At 1440 the
   full-strength strips are the outer 60px, the container-wide margins;
   up to 1320px no strip reaches full strength. Étoiles, poussière, halos
   and constellations are untouched. No page overrides this rule.
   An element sky (not body) must be a positioned stacking context. Today
   that is only the match moment .ca-match__content, which .ca-decor-host
   makes relative and isolated.
   ───────────────────────────────────────────────────────────── */

/* Anchors the layer to the whole document; body margin is 0, so the
   layer origin is the canvas origin and the éclats keep their place. */
body.ui-v2.ca-sky:not(.ca-sky--calme) {
  position: relative;
}

/* The extra --sky-pos entries are ignored for one layer, so the éclats
   keep their current offset. */
.ca-sky:not(.ca-sky--calme)::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("../../images/v2/ciel-eclats-773.svg");
  background-size: 773px 773px;
  background-repeat: repeat;
  background-position: var(--sky-pos, -500px -300px);
}

/* Wide screens only: the min-width is the --sky-clear value there
   (container-wide 1320px minus two 48px gutters); media queries cannot
   read custom properties. */
@media (min-width: 1224px) {
  .ca-sky:not(.ca-sky--calme)::before {
    --ca-sky-under: rgb(0 0 0 / var(--sky-sparkle-under));
    --ca-sky-mask: linear-gradient(var(--ca-sky-under), var(--ca-sky-under));
    -webkit-mask-image: var(--ca-sky-mask);
    mask-image: var(--ca-sky-mask);
  }

  /* Body sky: full strength in the margins, faint over the content column. */
  body.ui-v2.ca-sky:not(.ca-sky--calme)::before {
    --ca-sky-edge: calc(50% - var(--sky-clear) / 2);
    --ca-sky-mask: linear-gradient(
      to right,
      rgb(0 0 0) calc(var(--ca-sky-edge) - var(--sky-feather)),
      var(--ca-sky-under) var(--ca-sky-edge),
      var(--ca-sky-under) calc(100% - var(--ca-sky-edge)),
      rgb(0 0 0) calc(100% - var(--ca-sky-edge) + var(--sky-feather))
    );
  }
}

/* ─────────────────────────────────────────────────────────────
   DECOR HOST
   Positioning and stacking context for one halo and one constellation,
   clipped so decor never widens the page.
   ───────────────────────────────────────────────────────────── */
.ca-decor-host {
  position: relative;
  isolation: isolate;
  overflow: clip;
}

/* ─────────────────────────────────────────────────────────────
   HALO - one per screen, centred on its subject
   Usage: <span class="ca-halo" aria-hidden="true"></span> inside a
   .ca-decor-host. Static, never animated, no backdrop-filter above it.
   Defaults follow the spec's logo halo: 480px circle, 320px on mobile.
   ───────────────────────────────────────────────────────────── */
.ca-halo {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  left: var(--halo-x, 50%);
  top: var(--halo-y, 50%);
  width: var(--halo-size, 480px);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: var(--halo-bg, var(--halo-logo));
}

@media (max-width: 599.98px) {
  .ca-halo {
    width: var(--halo-size-mobile, 320px);
  }
}

/* ─────────────────────────────────────────────────────────────
   CONSTELLATION - at most one decorative per screen, cropped by an
   edge, never repeated
   Usage: <img class="ca-constellation" src="…" alt="" aria-hidden="true">.
   The page sets top/right/bottom/left so the drawing crosses an edge of
   its .ca-decor-host; keep opacity 0.22–0.38, rotate −15°..15°, size
   120–460px.
   ───────────────────────────────────────────────────────────── */
.ca-constellation {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  user-select: none;
  width: var(--constellation-size, 320px);
  height: auto;
  opacity: var(--constellation-opacity, 0.3);
  rotate: var(--constellation-rotate, 0deg);
}

/* ─────────────────────────────────────────────────────────────
   DISPLAY TYPOGRAPHY - Cormorant Garamond
   Never under 20px; weight 400 only at 32px and above.
   The two !important (font-family, font-weight) exist only to beat
   materialize-override.css:489-492, which forces h1–h6 to Montserrat 600
   !important; drop them when that file is removed.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-display-xl,
.ui-v2 .ca-display-1,
.ui-v2 .ca-display-2,
.ui-v2 .ca-display-3,
.ui-v2 .ca-display-lede,
.ui-v2 .ca-display-quote,
.ui-v2 .ca-display-numeral {
  margin: 0;
  color: var(--ivory-100);
  font-family: var(--font-display) !important;
  font-variant-numeric: lining-nums;
}

.ui-v2 .ca-display-xl {
  font-size: var(--fs-display-xl);
  line-height: var(--lh-display-xl);
  font-weight: 400 !important;
  letter-spacing: var(--ls-display);
  text-wrap: balance;
}

.ui-v2 .ca-display-1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  font-weight: var(--fw-h1) !important;
  letter-spacing: var(--ls-display);
}

.ui-v2 .ca-display-2 {
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  font-weight: 500 !important;
}

.ui-v2 .ca-display-3 {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: 500 !important;
}

.ui-v2 .ca-display-lede {
  color: var(--ivory-300);
  font-size: var(--fs-lede);
  line-height: var(--lh-lede);
  font-style: italic;
  font-weight: 500 !important;
}

.ui-v2 .ca-display-quote {
  font-size: var(--fs-quote);
  line-height: var(--lh-quote);
  font-weight: 500 !important;
}

.ui-v2 .ca-display-numeral {
  font-size: var(--fs-numeral-xl);
  line-height: var(--lh-numeral-xl);
  font-weight: 400 !important;
}

/* ─────────────────────────────────────────────────────────────
   EYEBROW - small gold uppercase label above a title
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-eyebrow {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--gold-400);
}

/* ─────────────────────────────────────────────────────────────
   LINKS - opt-in, so the legacy chrome keeps its colours
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-link,
.ui-v2 .ca-prose a {
  color: var(--violet-400);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.ui-v2 .ca-link:hover,
.ui-v2 .ca-prose a:hover {
  color: var(--ivory-100);
}

/* ─────────────────────────────────────────────────────────────
   FOCUS & SELECTION
   .ui-v2 :focus-visible outranks Materialize's button:focus { outline: none }.
   ───────────────────────────────────────────────────────────── */
.ui-v2 :focus-visible {
  outline: 2px solid var(--violet-300);
  outline-offset: 2px;
}

body.ui-v2::selection,
.ui-v2 ::selection {
  background-color: var(--violet-600);
  color: var(--ivory-100);
}

/* Visually hidden, still announced by screen readers. */
.ui-v2 .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ─────────────────────────────────────────────────────────────
   ICONS - stroke attributes live on the sprite symbols
   ───────────────────────────────────────────────────────────── */
.ca-icon {
  display: inline-block;
  flex-shrink: 0;
  vertical-align: middle;
}

/* ─────────────────────────────────────────────────────────────
   USER PREFERENCES
   Reduced motion stops animations here. Transitions are not forced: v2
   ones read --dur-*, which tokens.css collapses to 1ms except the 120ms
   --dur-1 fades the spec keeps.
   ───────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ui-v2 *,
  .ui-v2 *::before,
  .ui-v2 *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* High contrast: drop decorative imagery, keep a system focus colour.
   The calme selector matches its own higher specificity. */
@media (forced-colors: active) {
  .ca-sky,
  .ca-sky.ca-sky--calme {
    background-image: none;
  }

  .ca-halo,
  .ca-constellation {
    display: none;
  }

  .ca-sky:not(.ca-sky--calme)::before {
    display: none;
  }

  .ui-v2 :focus-visible {
    outline-color: Highlight;
  }
}
