/* =========================================================================
   Secrétariat du Lac — single stylesheet
   Visual direction: Letter kit (letter.co), Refero reference
   28523918-c7ef-481b-b818-d69b6151b768
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Tokens
   ------------------------------------------------------------------------- */

:root {
  /* Colors — Letter kit. Do not modify without re-running tests/test_contrast.php */
  --color-midnight: #000000;
  --color-canvas-white: #ffffff;
  --color-carbon: #191b1f;
  --color-ghost-gray: #f6f9f9;
  --color-whisper-gray: #e6ebec;
  --color-stone-whisper: #9fabad;
  --color-deep-teal: #186f64;
  --color-lilac-mist: #e6def0;
  --color-mint-glaze: #eefcef;
  --color-canyon-haze: #fcede1;
  --color-ocean-gaze: #154ea5;
  --color-grape-dusk: #644bc4;
  /* Royal Violet is present to document that it fails AA on white,
     and must never be promoted to an accent role. */
  --color-royal-violet: #536eff;

  /* Semantic roles */
  --color-text: var(--color-carbon);
  --color-text-muted: var(--color-stone-whisper);
  --color-surface: var(--color-canvas-white);
  --color-surface-alt: var(--color-ghost-gray);
  --color-border: var(--color-whisper-gray);
  --color-action: var(--color-deep-teal);
  --color-action-text: var(--color-canyon-haze);

  /* Typography */
  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --text-display: clamp(2.75rem, 6vw, 5rem);      /* 44px -> 80px */
  --text-heading: clamp(2rem, 4vw, 2.875rem);     /* 32px -> 46px */
  --text-heading-sm: clamp(1.375rem, 2.5vw, 1.75rem); /* 22px -> 28px */
  --text-subheading: 1.375rem;                    /* 22px */
  --text-body: 1rem;                              /* 16px */
  --text-caption: 0.8125rem;                      /* 13px */

  --tracking-display: 0.02em;
  --leading-tight: 1.1;
  --leading-heading: 1.2;
  --leading-body: 1.4;
  --leading-caption: 2;

  /* Spacing */
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;   /* standard section gap: 64px */
  --space-24: 6rem;   /* major break: 96px */

  /* Shapes — kit forbids soft radius and any box-shadow */
  --radius-interactive: 2px;
  --content-width: 1200px;
  --border-hairline: 1px solid var(--color-border);

  /* Header's real rendered height: 72px min-height (section 5,
     .site-header__inner) + 1px border-bottom (.site-header). Used by
     section 14 to pull the home page's hero up under the transparent
     header. Keep this in sync with section 5 if either value changes. */
  --header-height: 73px;
}

/* -------------------------------------------------------------------------
   1 bis. Self-hosted fonts
   Substitutes designated by Refero for Albra Sans and Neufile Grotesk Extended.
   No external requests: the files are served by the site itself.
   ------------------------------------------------------------------------- */

@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/playfair-display-v40-latin-600.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/inter-v20-latin-regular.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/inter-v20-latin-500.woff2") format("woff2");
}

/* -------------------------------------------------------------------------
   2. Reset
   ------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background-color: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: 400;
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-heading);
}

p, ul, ol {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Keyboard focus visible on all backgrounds, including Midnight. */
:focus-visible {
  outline: 2px solid var(--color-deep-teal);
  outline-offset: 2px;
}

.section--dark :focus-visible {
  outline-color: var(--color-canvas-white);
}

/* Accessible to screen readers, visually hidden. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* -------------------------------------------------------------------------
   3. Layout
   ------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
  padding-inline: var(--space-6);
}

.section {
  padding-block: var(--space-16);
}

.section--alt {
  background-color: var(--color-surface-alt);
}

.section--dark {
  background-color: var(--color-midnight);
  color: var(--color-canvas-white);
}

.section--dark .section__lead,
.section--dark p {
  color: var(--color-canvas-white);
}

.section__title {
  font-size: var(--text-heading);
  max-width: 22ch;
}

.section__lead {
  margin-top: var(--space-4);
  font-size: 1.125rem;
  max-width: 60ch;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -4rem;
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-carbon);
  color: var(--color-canvas-white);
  text-decoration: none;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: var(--space-4);
}

/* -------------------------------------------------------------------------
   4. Buttons — padding and radius mandated by the Letter kit
   ------------------------------------------------------------------------- */

.button {
  display: inline-block;
  padding: 12px 27.2px;
  border: 1px solid transparent;
  border-radius: var(--radius-interactive);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: 400;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.button--primary {
  background-color: var(--color-deep-teal);
  border-color: var(--color-canyon-haze);
  color: var(--color-canyon-haze);
}

.button--primary:hover {
  background-color: var(--color-carbon);
  border-color: var(--color-carbon);
  color: var(--color-canvas-white);
}

.button--secondary {
  background-color: var(--color-canvas-white);
  border-color: var(--color-carbon);
  color: var(--color-carbon);
}

.button--secondary:hover {
  background-color: var(--color-carbon);
  color: var(--color-canvas-white);
}

.button--on-dark {
  background-color: transparent;
  border-color: var(--color-canvas-white);
  color: var(--color-canvas-white);
}

.button--on-dark:hover {
  background-color: var(--color-canvas-white);
  color: var(--color-carbon);
}

/* -------------------------------------------------------------------------
   5. Header
   ------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background-color: var(--color-canvas-white);
  border-bottom: var(--border-hairline);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  min-height: 72px;
}

.site-header__brand {
  font-family: var(--font-display);
  font-size: var(--text-subheading);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  text-decoration: none;
}

.site-header__toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 1px solid var(--color-carbon);
  border-radius: var(--radius-interactive);
  cursor: pointer;
}

.site-header__toggle-bar,
.site-header__toggle-bar::before,
.site-header__toggle-bar::after {
  display: block;
  width: 18px;
  height: 1px;
  margin-inline: auto;
  background-color: var(--color-carbon);
  content: "";
}

.site-header__toggle-bar::before {
  transform: translateY(-6px);
}

.site-header__toggle-bar::after {
  transform: translateY(5px);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-8);
}

.site-nav__list {
  display: flex;
  gap: var(--space-6);
}

.site-nav__link {
  font-size: var(--text-body);
  text-decoration: none;
  padding-block: var(--space-2);
  border-bottom: 1px solid transparent;
}

.site-nav__link:hover {
  border-bottom-color: var(--color-carbon);
}

.site-nav__link--current {
  color: var(--color-deep-teal);
  border-bottom-color: var(--color-deep-teal);
}

/* -------------------------------------------------------------------------
   6. Footer
   ------------------------------------------------------------------------- */

.site-footer {
  padding-block: var(--space-16) var(--space-8);
  background-color: var(--color-midnight);
  color: var(--color-canvas-white);
}

.site-footer__inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-12);
}

.site-footer__block p,
.site-footer__block li {
  margin-block: var(--space-2);
}

.site-footer__brand {
  font-family: var(--font-display);
  font-size: var(--text-subheading);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
}

.site-footer__label {
  font-size: var(--text-caption);
  line-height: var(--leading-caption);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-whisper-gray);
}

.site-footer__legal {
  margin-top: var(--space-12);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  font-size: var(--text-caption);
  line-height: var(--leading-caption);
  color: var(--color-whisper-gray);
}

/* -------------------------------------------------------------------------
   7. Responsive
   ------------------------------------------------------------------------- */

@media (max-width: 1023px) {
  .site-header__inner {
    flex-wrap: wrap;
  }

  /*
   * No-JS default: the nav stays in normal flow, stacked and fully visible,
   * so every link and the CTA are reachable without main.js running. The
   * collapsing behind the toggle button is added below, scoped to
   * .site-header--enhanced, which main.js applies once it has loaded.
   */
  .site-nav {
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-4);
    padding-top: var(--space-4);
  }

  .site-nav__list {
    flex-direction: column;
    gap: var(--space-4);
  }

  .site-footer__inner {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .site-header--enhanced .site-header__toggle {
    display: block;
  }

  .site-header--enhanced .site-nav {
    display: none;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    flex-basis: auto;
    padding: var(--space-6);
    background-color: var(--color-canvas-white);
    border-bottom: var(--border-hairline);
  }

  .site-header--enhanced .site-nav--open {
    display: flex;
  }
}

@media (max-width: 639px) {
  .section {
    padding-block: var(--space-12);
  }
}

/* -------------------------------------------------------------------------
   8. Utilities
   ------------------------------------------------------------------------- */

/*
 * Standard button-row treatment. The CSP forbids inline style attributes
 * (style-src has no 'unsafe-inline'), so any page that groups a couple of
 * buttons below a paragraph uses this class instead of style="...".
 */
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-8);
}

/* -------------------------------------------------------------------------
   9. Formulaire de contact
   ------------------------------------------------------------------------- */

.contact-layout {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: var(--space-16);
  align-items: start;
}

.field {
  margin-bottom: var(--space-6);
}

.field label {
  display: block;
  margin-bottom: var(--space-2);
  font-weight: 500;
}

.field__required {
  color: var(--color-deep-teal);
}

.field__optional {
  font-weight: 400;
  font-size: var(--text-caption);
  color: var(--color-carbon);
  opacity: 0.7;
}

.field input[type="text"],
.field input[type="email"],
.field input[type="tel"],
.field textarea {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-canvas-white);
  border: 1px solid var(--color-carbon);
  border-radius: var(--radius-interactive);
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--color-carbon);
}

.field textarea {
  resize: vertical;
}

.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-width: 2px;
  border-color: #a8201a;
}

.field__error {
  margin-top: var(--space-2);
  font-size: var(--text-caption);
  line-height: 1.4;
  color: #a8201a;
}

.field--checkbox {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3);
  align-items: start;
}

.field--checkbox input {
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.2rem;
  accent-color: var(--color-deep-teal);
}

.field--checkbox label {
  margin-bottom: 0;
  font-weight: 400;
  font-size: var(--text-caption);
  line-height: 1.6;
}

/* The honeypot must stay in the document flow for bots, but be invisible
   and unreachable by keyboard for humans. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.alert {
  margin-bottom: var(--space-8);
  padding: var(--space-4) var(--space-6);
  border-left: 3px solid;
  font-size: var(--text-body);
}

.alert--success {
  background-color: var(--color-mint-glaze);
  border-left-color: var(--color-deep-teal);
  color: var(--color-carbon);
}

.alert--error {
  background-color: var(--color-canyon-haze);
  border-left-color: #a8201a;
  color: var(--color-carbon);
}

.contact-aside {
  padding: var(--space-8);
  background-color: var(--color-canvas-white);
  border: var(--border-hairline);
}

.contact-aside__title {
  font-size: var(--text-heading-sm);
}

.contact-aside__subtitle {
  margin-top: var(--space-8);
  font-size: var(--text-subheading);
}

.contact-aside__line {
  margin-top: var(--space-3);
  font-size: 1.125rem;
}

.contact-aside p {
  margin-top: var(--space-3);
}

@media (max-width: 1023px) {
  .contact-layout {
    grid-template-columns: 1fr;
    gap: var(--space-12);
  }
}

/* -------------------------------------------------------------------------
   10. Prestations et tarifs
   ------------------------------------------------------------------------- */

.familles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
}

.famille {
  padding: var(--space-8);
  background-color: var(--color-canvas-white);
  border-top: 2px solid var(--color-deep-teal);
}

.famille__titre {
  font-size: var(--text-subheading);
}

.famille__resume {
  margin-top: var(--space-4);
  color: var(--color-carbon);
}

.famille__items {
  margin-top: var(--space-6);
  padding-top: var(--space-6);
  border-top: var(--border-hairline);
}

.famille__items li {
  padding-block: var(--space-2);
  border-bottom: var(--border-hairline);
}

.famille__items li:last-child {
  border-bottom: none;
}

/* Table scrolls inside its own container below 640px; the page itself
   never scrolls horizontally. */
.table-scroll {
  margin-top: var(--space-12);
  overflow-x: auto;
}

.tarifs {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  text-align: left;
}

.tarifs th,
.tarifs td {
  padding: var(--space-4) var(--space-4);
  border-bottom: var(--border-hairline);
  vertical-align: top;
}

.tarifs thead th {
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: 500;
  line-height: var(--leading-caption);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 1px solid var(--color-carbon);
}

.tarifs tbody th {
  font-weight: 400;
}

.tarifs__label {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-subheading);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
}

.tarifs__detail,
.tarifs__note {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--text-caption);
  line-height: 1.5;
}

.tarifs__note {
  color: var(--color-deep-teal);
}

.tarifs td {
  font-size: 1.125rem;
  white-space: nowrap;
}

.conditions {
  margin-top: var(--space-12);
  padding: var(--space-8);
  background-color: var(--color-ghost-gray);
}

.conditions__titre {
  font-size: var(--text-subheading);
}

.conditions__liste {
  margin-top: var(--space-4);
}

.conditions__liste li {
  padding-block: var(--space-2);
  padding-left: var(--space-6);
  position: relative;
}

.conditions__liste li::before {
  position: absolute;
  left: 0;
  color: var(--color-deep-teal);
  content: "—";
}

@media (max-width: 1023px) {
  .familles {
    grid-template-columns: 1fr;
  }
}

/* -------------------------------------------------------------------------
   11. Accueil
   ------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding-block: var(--space-24);
  background-color: var(--color-midnight);
  background-image: url("/assets/img/hero-lac.webp");
  background-size: cover;
  background-position: center;
  color: var(--color-canvas-white);
}

/* Overlay ensuring text stays legible whatever the image looks like. */
.hero::before {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to right,
    rgba(0, 0, 0, 0.85) 0%,
    rgba(0, 0, 0, 0.6) 60%,
    rgba(0, 0, 0, 0.4) 100%
  );
  content: "";
}

.hero__inner {
  position: relative;
}

.hero__title {
  font-size: var(--text-display);
  line-height: var(--leading-heading);
  max-width: 16ch;
}

.hero__lead {
  margin-top: var(--space-6);
  max-width: 52ch;
  font-size: clamp(1.125rem, 2vw, 1.75rem);
  line-height: var(--leading-body);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-12);
}

.constat {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: var(--space-16);
  align-items: start;
}

.constat .section__lead + .section__lead {
  margin-top: var(--space-6);
}

.constat__repere {
  padding: var(--space-8);
  background-color: var(--color-ghost-gray);
  border-top: 2px solid var(--color-deep-teal);
}

.constat__chiffre {
  font-family: var(--font-display);
  font-size: var(--text-heading);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  color: var(--color-deep-teal);
}

.constat__legende {
  margin-top: var(--space-4);
}

.cartes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
  margin-top: var(--space-12);
}

.carte {
  padding: var(--space-8);
  background-color: var(--color-canvas-white);
}

.carte__titre {
  font-size: var(--text-subheading);
}

.carte__resume {
  margin-top: var(--space-4);
}

.carte__items {
  margin-top: var(--space-6);
}

.carte__items li {
  padding-block: var(--space-2);
  border-bottom: var(--border-hairline);
  font-size: var(--text-caption);
  line-height: 1.6;
}

.portrait {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-16);
  align-items: center;
}

.portrait__visuel {
  display: flex;
  align-items: center;
  min-height: 420px;
  padding: var(--space-12);
  background-color: var(--color-ghost-gray);
}

.portrait__citation {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  line-height: 1.35;
}

@media (max-width: 1023px) {
  .constat,
  .cartes,
  .portrait {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .hero {
    padding-block: var(--space-16);
  }

  .portrait__visuel {
    min-height: 0;
    padding: var(--space-8);
  }
}

/* -------------------------------------------------------------------------
   12. Page éditoriale
   ------------------------------------------------------------------------- */

.recit {
  display: grid;
  grid-template-columns: 1fr 1.3fr;
  gap: var(--space-16);
  align-items: start;
}

.recit__visuel {
  display: flex;
  align-items: center;
  min-height: 480px;
  padding: var(--space-12);
  background-color: var(--color-canvas-white);
  border-top: 2px solid var(--color-deep-teal);
  position: sticky;
  top: 96px;
}

.recit__titre {
  margin-top: var(--space-12);
  font-size: var(--text-heading-sm);
}

.recit__titre:first-child {
  margin-top: 0;
}

.recit__texte p {
  margin-top: var(--space-4);
  max-width: 62ch;
  font-size: 1.0625rem;
}

@media (max-width: 1023px) {
  .recit {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .recit__visuel {
    position: static;
    min-height: 0;
    padding: var(--space-8);
  }
}

/* -------------------------------------------------------------------------
   13. Pages de texte long
   ------------------------------------------------------------------------- */

.prose {
  max-width: 68ch;
}

.prose h2 {
  margin-top: var(--space-12);
  font-size: var(--text-heading-sm);
}

.prose p {
  margin-top: var(--space-4);
  font-size: 1.0625rem;
}

.prose code {
  padding: 0.1em 0.35em;
  background-color: var(--color-ghost-gray);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}

/* -------------------------------------------------------------------------
   14. Home page v2 — full-height hero, two-state navigation, audience panels
   ------------------------------------------------------------------------- */

/* `100svh`, not `100vh`: on mobile the address bar retracts on first
   scroll, and `vh` is computed against the retracted viewport, which
   would jump the layout. `svh` stays stable from first paint.
   Coupling: the navigation bar's scroll-driven opacity transition uses
   `animation-range: 0 100svh` against this same distance, so the nav
   finishes turning opaque exactly where the hero ends. If this value
   changes, that range must change with it, or the two will drift apart. */
/* The header is `position: sticky`, so it still occupies its own height in
   normal flow above the hero; without this, the first screen would be
   header height + 100svh, pushing the scroll cue below the fold. Pulling
   the hero up by the header's height puts it back under the now-transparent
   header, so the hero alone spans exactly the first viewport. */
.hero--full {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100svh;
  margin-top: calc(-1 * var(--header-height));
  padding-block: var(--space-24) var(--space-16);
}

/* The cue is positioned rather than laid out in the flex flow: a
   `margin-top: auto` on it would absorb the free space that
   `justify-content: center` needs, pushing the hero content back to the top. */
.hero__scroll-cue {
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-8);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-canvas-white);
  opacity: 0.6;
  /* Decorative and `aria-hidden`, unconditionally: it must never intercept a
     pointer meant for whatever sits under it, at any viewport size — not
     just on the short screens where it currently overlaps the actions row. */
  pointer-events: none;
}

.hero__scroll-label {
  font-size: var(--text-caption);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hero__scroll-line {
  display: block;
  width: 1px;
  height: 40px;
  background-color: currentColor;
  transform-origin: top center;
}

@keyframes scroll-cue-drift {
  0%, 100% { transform: scaleY(0.4); opacity: 0.35; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

.hero__scroll-line {
  animation: scroll-cue-drift 2.4s ease-in-out infinite;
}

/* Below this height the cue's box visually overlaps `.hero__actions`.
   Measured with Playwright across the 300-428px width range (the realistic
   mobile band): the last overlapping height was 730px, at the narrowest
   widths (300-330px); it cleared by 735px everywhere. 740px is that
   measured ceiling plus a small safety margin, not a guess. Below it,
   hiding the cue costs nothing: content already overflows the viewport at
   these heights, so the reader has every cue they need without it. */
@media (max-height: 740px) {
  .hero__scroll-cue {
    display: none;
  }
}

/* `.hero--full` and section 11's mobile `.hero` rule are both single-class
   selectors, so they carry equal specificity; being later in the file,
   `.hero--full` would otherwise outrank the reduced mobile padding at every
   width below 1024px, not just at the narrowest ones. Restoring it here,
   in this section, keeps section 11 untouched. */
/* Top padding matches the header's height, not `--space-3`: the hero is now
   pulled up under the transparent header (see the `margin-top` above), and
   on short small-viewport screens the header's overlay would otherwise sit
   on top of the title. Bottom padding is dropped to 0 rather than kept at
   `--space-3`: the scroll cue is absolutely positioned against the hero's
   own edge, so it does not depend on this padding, and removing it buys
   back room for the title on the shortest phones. Measured at 320x568 and
   360x640 — see task 4 report. At 320x568 this still does not fully close
   the gap: the hero's existing title/lead/actions content is taller than
   the 320x568 viewport minus the header clearance, independent of this
   padding value. Flagged in the report rather than fixed here, because
   closing it needs a content/type-scale change outside this task's scope. */
@media (max-width: 1023px) {
  .hero--full {
    padding-block: var(--header-height) 0;
  }
}

/* Sub-400px devices (iPhone SE class): the 534px content block plus the
   73px header clearance still exceeds the viewport after the fix above.
   Buy the missing space from typography here, in this dedicated
   breakpoint, so nothing at 400px and up is affected — every width from
   360px up already passes all three criteria unmodified. Lowering the
   title's clamp floor from 44px to 36px drops it from four wrapped lines
   to three at this width, which alone closes the gap; the vertical gaps
   (actions margin-top, lead margin-top) were the next lever to try but
   were not needed. */
@media (max-width: 399px) {
  .hero--full .hero__title {
    /* Floor for the hero display type at this width: 36px. Never below
       32px — under that it stops reading as a hero. */
    font-size: 2.25rem;
  }
}

/* Two-state navigation, home page only. Everywhere else the header keeps the
   opaque treatment from section 5, because no other page starts on a dark
   hero and transparent would mean white text on white. */
@supports (animation-timeline: scroll(root)) {
  /* Gated on `.site-header--enhanced`, not `.site-header--over-hero` alone.
     `--enhanced` is what `main.js` adds once it has run, and it is also what
     makes the mobile nav collapse behind a toggle button. Without it the nav
     stays in flow, expanded, at roughly 290px tall, while `.hero--full` only
     moves up by `--header-height` (73px) to sit under the header — so about
     217px of transparent header would sit over the plain white `body`
     background, rendering the brand and links in Canvas White on white.
     Requiring `--enhanced` ties the transparent state to the one guarantee
     that makes it safe: the header really is 73px and really does sit over
     the hero. Without JavaScript, `.site-header--over-hero` alone now keeps
     the ordinary opaque header from section 5 — exactly the safe fallback
     the spec already requires when scroll timelines aren't supported. */
  .site-header--enhanced.site-header--over-hero {
    background-color: transparent;
    border-bottom-color: transparent;
    color: var(--color-canvas-white);
    animation: header-solidify linear both;
    animation-timeline: scroll(root);
    animation-range: 0 100svh;
  }

  .site-header--enhanced.site-header--over-hero .site-header__brand,
  .site-header--enhanced.site-header--over-hero .site-nav__link {
    color: inherit;
  }

  .site-header--enhanced.site-header--over-hero .site-header__toggle {
    border-color: currentColor;
  }

  .site-header--enhanced.site-header--over-hero .site-header__toggle-bar,
  .site-header--enhanced.site-header--over-hero .site-header__toggle-bar::before,
  .site-header--enhanced.site-header--over-hero .site-header__toggle-bar::after {
    background-color: currentColor;
  }

  /* Spec §3: the CTA gets an outlined, transparent-fill treatment over the
     hero and the ordinary filled `.button--primary` look once solid.
     Animated rather than toggled by class, on the same range as the header
     itself, so the two never drift out of sync. */
  .site-header--enhanced.site-header--over-hero .site-nav__cta {
    animation: nav-cta-solidify linear both;
    animation-timeline: scroll(root);
    animation-range: 0 100svh;
  }

  /* `currentColor`, not a fixed white: `color` already flips with the
     animation above (white over the hero, Carbon once solid) for the brand,
     the links and the toggle, so the outline follows it for free in both
     states, with no second value that could drift out of sync. The CTA is
     deliberately excluded: its own `color` is tuned for text-on-fill
     contrast (Canyon Haze on Deep Teal once solid), not for standing out
     against whatever sits behind the button, so reusing it here reproduces
     the same invisible-outline defect this rule exists to prevent. The CTA
     gets its own rule below instead. */
  .site-header--enhanced.site-header--over-hero .site-header__brand:focus-visible,
  .site-header--enhanced.site-header--over-hero .site-nav__link:focus-visible,
  .site-header--enhanced.site-header--over-hero .site-header__toggle:focus-visible {
    outline-color: currentColor;
  }

  /* Confined to the range's last 5%, not a linear crossfade across the
     whole 100svh: interpolating the full distance put the composited
     mid-scroll colour at roughly 1.05:1 for a reader who stops mid-hero —
     sub-AA for half a screen of scrolling. The spec's own table describes
     two states, transparent then opaque, not a gradual blend between them.
     Confining the fade to a short tail keeps that reading while shrinking
     the sub-AA band to a few dozen pixels at realistic viewport heights —
     see the task-8 report for the measured band, before and after. */
  @keyframes header-solidify {
    from,
    95% {
      background-color: transparent;
      border-bottom-color: transparent;
      color: var(--color-canvas-white);
    }
    to {
      background-color: var(--color-canvas-white);
      border-bottom-color: var(--color-border);
      color: var(--color-carbon);
    }
  }

  /* `outline-color` rides the same keyframes as the button's own fill,
     rather than a separate animation on `:focus-visible`: a second
     `animation` shorthand there would replace this one instead of adding to
     it — the CSS `animation` property holds one animation-name per
     selector, so the more specific `:focus-visible` rule would silently
     stop the fill/text transition for as long as the button is focused.
     Folding the ring into this single animation sidesteps that. It has no
     effect while unfocused: `outline-style` stays `none` until
     `:focus-visible` sets it via the base rule in section 2, so an animated
     `outline-color` underneath is simply never painted.
     Deep Teal — the obvious fixed ring colour — doesn't work: once solid
     the button itself is filled Deep Teal, so a same-colour ring reads as a
     smear against the button rather than a ring around it. Canvas White
     over the transparent hero matches the button's own outlined state
     there; Carbon once solid measures 17.25:1 against the Canvas White
     header background, comfortably clear of the button's own Deep Teal
     fill. Measured ratios for both states are in the task-8 report. */
  @keyframes nav-cta-solidify {
    from,
    95% {
      background-color: transparent;
      border-color: var(--color-canvas-white);
      color: var(--color-canvas-white);
      outline-color: var(--color-canvas-white);
    }
    to {
      background-color: var(--color-deep-teal);
      border-color: var(--color-canyon-haze);
      color: var(--color-canyon-haze);
      outline-color: var(--color-carbon);
    }
  }
}

/* The open mobile menu always needs a solid ground to sit on, whatever the
   scroll position. */
.site-header--over-hero .site-nav--open {
  background-color: var(--color-canvas-white);
}

.site-header--over-hero .site-nav--open .site-nav__link {
  color: var(--color-carbon);
}

/* Audience panels — "Cimaise décalée": small tinted blocks inside the
   1200px content width, modelled on Letter's own kit, where a tinted panel
   acts as a gallery wall and the image bleeds to the block's own edge with
   no frame. Row 1 holds two blocks side by side, the second staggered down
   by --space-16 to start a diagonal reading line; row 2 continues that
   diagonal with a single block aligned right. Superseded the earlier
   full-width band layout (0.85x viewport tall) that lived under this same
   selector family. */
.panels-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
}

.panels-row .panel--staggered {
  margin-top: var(--space-16);
}

.panel {
  display: flex;
  min-height: 360px;
  overflow: hidden;
}

.panel--canyon-haze { background-color: var(--color-canyon-haze); }
.panel--mint-glaze  { background-color: var(--color-mint-glaze); }
.panel--lilac-mist  { background-color: var(--color-lilac-mist); }

.panel__content {
  flex: 0 0 52%;
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.panel__content--ocean-gaze { --panel-accent: var(--color-ocean-gaze); }
.panel__content--deep-teal  { --panel-accent: var(--color-deep-teal); }
.panel__content--grape-dusk { --panel-accent: var(--color-grape-dusk); }

.panel__title {
  font-size: var(--text-heading-sm);
  color: var(--panel-accent);
}

.panel__lead {
  margin-top: var(--space-3);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 500;
  color: var(--panel-accent);
}

.panel__text {
  margin-top: var(--space-3);
  color: var(--color-carbon);
}

.panel__cta {
  background-color: var(--panel-accent);
  border-color: var(--panel-accent);
  color: var(--color-canvas-white);
}

.panel__cta:hover {
  background-color: var(--color-carbon);
  border-color: var(--color-carbon);
  color: var(--color-canvas-white);
}

/* Image bleeds to the block's own edge: no frame, no border. The media
   column has no explicit height of its own — `align-items: stretch` (the
   flex default) makes it match whatever height the text column needs, and
   `object-fit: cover` keeps the image filling that height without
   distortion. */
.panel__media {
  flex: 1 1 auto;
  position: relative;
  overflow: hidden;
}

.panel__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Row 2: a single block, aligned right instead of left, continuing the
   diagonal that row 1's stagger starts. */
.panel--wide {
  width: 58%;
  margin-left: auto;
  margin-top: var(--space-16);
}

@media (max-width: 1023px) {
  .panels-row {
    grid-template-columns: 1fr;
  }

  /* The stagger draws a diagonal against the block beside it on desktop;
     stacked in a single column there is no diagonal to draw, and the
     grid's own `gap` (--space-8) already spaces every panel evenly. Zeroing
     this out here, rather than leaving it to compound with that gap, keeps
     all three vertical gaps in the stack equal instead of the first being
     double the other two. */
  .panels-row .panel--staggered {
    margin-top: 0;
  }

  .panel {
    flex-direction: column;
    min-height: 0;
  }

  .panel--wide {
    width: 100%;
    margin-left: 0;
    margin-top: var(--space-8);
  }

  .panel__content {
    flex: none;
  }

  .panel__media {
    min-height: 220px;
  }
}

/* Section reveal. The initial hidden state lives inside the @supports guard
   on purpose: a browser without scroll-driven animation applies none of these
   rules and simply shows the content, instead of leaving it at opacity 0
   forever. */
/* Deliberately testing `view()` here, not `scroll(root)` as the header guard
   above does: each guard keeps its own hidden state inside itself, so a
   browser supporting only one of the two values lands in a merely
   inconsistent-but-visible state, never an invisible one. Do not merge these
   into a single shared guard — that would invert the safety argument. */
@supports (animation-timeline: view()) {
  .reveal {
    opacity: 0;
    translate: 0 24px;
    animation: reveal-in linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }

  @keyframes reveal-in {
    to {
      opacity: 1;
      translate: 0 0;
    }
  }

  /* Panel imagery reveal: a wipe opens the image from bottom to top via
     clip-path while it settles from scale(1.08) to its resting scale(1),
     so the image visibly arrives rather than merely fading in. Replaces
     the earlier, barely-perceptible drift under this same selector. */
  .panel__media img {
    clip-path: inset(100% 0 0 0);
    scale: 1.08;
    animation: media-wipe-reveal linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }

  @keyframes media-wipe-reveal {
    to {
      clip-path: inset(0 0 0 0);
      scale: 1;
    }
  }
}

/* Scroll-driven animations ignore animation-duration, so the global
   reduced-motion rule cannot neutralise them on its own.
   `.site-header--over-hero` alone (specificity 0,1,0) would not be enough to
   neutralise the enhanced state below: the @supports block above styles
   `.site-header--enhanced.site-header--over-hero` at 0,2,0, which outranks
   it regardless of source order. Without the matching selector here, a
   visitor with JavaScript enabled and reduced motion requested would keep
   seeing the transparent, scroll-driven header — motion neutralised in name
   but not in effect. Both selectors are listed below so the rule holds
   whether or not `main.js` has run. Below, `.panel__media img` additionally
   gets its clipping and scaling reset on its own rule: those two properties
   sit directly on the guarded base rule rather than only inside its
   keyframes, so `animation: none` alone would leave the panel imagery stuck
   at its wipe's closed, zoomed-in starting point instead of restoring it. */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .panel__media img,
  .site-header--over-hero,
  .site-header--enhanced.site-header--over-hero,
  .site-header--enhanced.site-header--over-hero .site-nav__cta {
    animation: none;
  }

  .reveal {
    opacity: 1;
    translate: none;
  }

  .panel__media img {
    clip-path: none;
    scale: 1;
  }

  .hero__scroll-line {
    animation: none;
  }

  .site-header--over-hero,
  .site-header--enhanced.site-header--over-hero {
    background-color: var(--color-canvas-white);
    border-bottom-color: var(--color-border);
    color: var(--color-carbon);
  }

  /* Same reasoning as the header itself just above: without the animation
     the CTA would otherwise fall back to the transparent-state values
     declared on it (including the transparent-state ring colour)
     permanently — the one state the spec forbids as a fallback. Force it to
     the always-safe opaque button and ring styling instead matching
     `.button--primary`. */
  .site-header--enhanced.site-header--over-hero .site-nav__cta {
    background-color: var(--color-deep-teal);
    border-color: var(--color-canyon-haze);
    color: var(--color-canyon-haze);
    outline-color: var(--color-carbon);
  }
}

/* -------------------------------------------------------------------------
   15. Logo — inline mark shared by the nav and the home hero
   ------------------------------------------------------------------------- */

/* Layout override for .site-header__brand (declared in section 5): the
   brand now wraps a mark plus the wordmark, so it needs a flex row to
   vertically centre them against each other. Appended here rather than
   edited in section 5, per this stylesheet's append-only convention — same
   equal-specificity, later-wins pattern section 14 already uses against
   section 11. */
.site-header__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  /* Overrides section 5's fixed `var(--text-subheading)` (1.375rem) with a
     size that shrinks with the *viewport* at narrow widths instead of with
     the visitor's root font-size. A fixed-width media-query cutoff was
     tried first (hide the mark below a measured px threshold) and a review
     caught why that breaks: raising the browser's default font size widens
     this rem-sized text in px without moving the query's px boundary, and
     the fallback serif that renders during `font-display: swap` (or if
     Playfair Display fails to load) has different metrics than what any
     single measurement could lock in. A `vw` middle term is immune to
     both — it resizes with the viewport itself, not with the font
     metrics or the root font-size computing `rem`. The floor is `16px`
     (an absolute unit, not `rem`), so it can't be pushed back up by a
     larger root font-size either; only the ceiling stays in `rem`
     (`var(--text-subheading)`), because the desktop-sized ceiling was
     never the width-budget problem this exists to solve. See the
     logo-report's fix section for the measured header heights under both
     adverse conditions (enlarged root font-size, blocked web font) that
     motivated this. */
  font-size: clamp(16px, 4.5vw, var(--text-subheading));
}

.site-header__logo {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  /* No explicit `color`: the mark's strokes are `currentColor`, so it
     follows whatever color .site-header__brand resolves to — Carbon by
     default, and Canvas White fading to Carbon on the home page via the
     scroll-driven animation in section 14 — with nothing to keep in sync. */
}

.hero__logo {
  display: block;
  width: clamp(48px, 12vw, 88px);
  height: clamp(48px, 12vw, 88px);
  margin-bottom: var(--space-6);
}

/* Below 360px width the mark is still hidden, even after the wordmark
   fix above — but the threshold below is now justified by the *worst*
   measured case, not the friendliest one. This is a load-bearing
   distinction: an earlier version of this rule used a plain px cutoff
   (359px) derived from measuring only default conditions, and a review
   caught that this doesn't hold once the wordmark's own width stops being
   the only width-budget variable in play:
     - Chromium's "Very Large" default-font-size accessibility preset
       (root font-size 24px, applied the same way the browser applies it —
       not page zoom) still wraps the header with the mark present, up to
       330px wide, even with the wordmark fix above (which only immunises
       the *wordmark's own* width against root-font-size scaling — the
       surrounding rem-sized padding/gaps in sections 3 and 5 are not
       overridden here and still grow with root font-size, eating the
       width budget independently of the wordmark). Measured live
       (Playwright, setting `document.documentElement.style.fontSize` —
       the same value `rem` resolves against regardless of whether a
       browser's own accessibility preference or an explicit style put it
       there — then reading `.site-header`'s real rendered height): 73px
       at every 5px step from 335px up; wrapped (113px) at 330px and
       below.
     - The Playfair Display fallback (`font-display: swap`, or the font
       failing to load, both tested by blocking the woff2 request so
       Georgia/Times New Roman renders) does not, on its own, move this
       boundary — confirmed at 320px and 360px, both matching their
       default-font-family results exactly.
   359px keeps ~29px of margin over the 330px worst-in-scope-condition
   boundary, comfortably covering 320x568, this task's required
   narrow-viewport check, under either adverse condition alone or
   combined. A further, more extreme 32px root font-size was also tried,
   for rigor beyond an "ordinary" accessibility setting: it wraps as low
   as 300-320px *even with the mark hidden entirely* (wordmark + toggle
   alone) — a pre-existing condition unrelated to the logo, the same class
   of defect as the pre-existing 280-300px default-font-size wrap already
   present before this feature (see the logo-report's fix section),
   out of this task's scope. See the logo-report for the full measurement
   tables. */
@media (max-width: 359px) {
  .site-header__logo {
    display: none;
  }
}

/* Base, resting state: fully drawn. This is deliberately the state a
   browser lands on when no animation runs at all (JS disabled CSS
   animations, or the browser predates them) — the safety pattern this
   stylesheet already uses for scroll-driven reveals (sections 11/14 above):
   the undrawn state must only ever exist transiently, inside a keyframe's
   `from`, never as a base declaration. `.logo__wave` alone is enough to
   cover both wave paths — each also carries `.logo__wave--1` /
   `.logo__wave--2` only to give the hero animation below a per-wave delay
   hook. */
.logo__ring,
.logo__ridge,
.logo__wave {
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
}

/* Hero entrance: the mark draws itself on load, ring first, then the
   ridge, then each wave — ~1.5s total. Every drawable element carries
   `pathLength="100"` (inc/logo.php), so the same dash values work
   regardless of each path's real geometric length.

   `backwards` fill mode, not `forwards`: the keyframes only need to own the
   undrawn state for the delay period before an element starts. Once an
   animation finishes it falls back to the base rule above (already
   `stroke-dashoffset: 0`), so there is nothing left for `forwards` to hold
   — and this project forbids pairing `forwards` with a transition on the
   same property, so this sidesteps that entirely by not using it. */
@keyframes logo-draw {
  from {
    stroke-dashoffset: 100;
  }
  to {
    stroke-dashoffset: 0;
  }
}

.hero__logo .logo__ring {
  animation: logo-draw 0.7s ease-out 0s backwards;
}

.hero__logo .logo__ridge {
  animation: logo-draw 0.6s ease-out 0.5s backwards;
}

.hero__logo .logo__wave--1 {
  animation: logo-draw 0.4s ease-out 0.9s backwards;
}

.hero__logo .logo__wave--2 {
  animation: logo-draw 0.4s ease-out 1.1s backwards;
}

/* Below this width the hero has essentially no vertical slack left: at
   320x568 and 360x640 the title/lead/actions block already fills the
   100svh hero exactly (see the task-4 report in
   .superpowers/sdd/2026-08-16-accueil-v2/), a fit tuned by shrinking the
   title to 36px in the sub-400px query in section 14. Measured live with
   the hero logo present (Playwright + system Chrome against the running
   container): see the logo-report for the numbers behind this threshold.
   Hiding the mark below it costs nothing — it is a decorative flourish,
   and the title and buttons matter more on a short phone. */
@media (max-width: 399px) {
  .hero__logo {
    display: none;
  }
}

/* Reduced motion: skip the draw-in, not just speed it up. The global
   `animation-duration: 0.01ms !important` reset in section 2 would already
   make this near-instant, but `animation: none` is explicit and, combined
   with the always-drawn base state above, leaves the mark visibly drawn
   and static immediately, with nothing timing-dependent to verify. */
@media (prefers-reduced-motion: reduce) {
  .hero__logo .logo__ring,
  .hero__logo .logo__ridge,
  .hero__logo .logo__wave {
    animation: none;
  }
}
