/* ==========================================================================
   Roadmapped — roadmapped.dev
   Same visual world as the app: monochrome + one blue, tri-layer
   page/card/rule, zero-radius surfaces, system fonts. No dependencies.

   DA (#262–#268, passe v3 #277–#280) :
   - Première partie full-bleed (#277) : hero + démo s'étendent bord à bord ;
     les rails d'antan deviennent une grille de colonnes régulière (--grid-*)
     peinte derrière ces deux sections. Le reste garde le conteneur centré
     (--container-max) et les filets horizontaux entre sections.
   - Trame de points (#278) : halftone fin et régulier (radial-gradient) en
     calque fixe derrière tout le contenu (z-index:-1, jamais au-dessus),
     plus dense en haut de viewport, estompé vers le bas.
   - Doctrine bleu assouplie (#279) : le bleu signale toujours les ÉTATS et
     INTERACTIONS (liens, focus, sélection, in_progress, callout, sigil $),
     et s'autorise désormais quelques accents de DA à faible dose : points
     de la trame teintés bleu, halo diffus derrière le hero, lignes de la
     grille de colonnes, numéros d'étape du stepper. PARCIMONIE. L'orange
     #EA6200 reste la propriété exclusive de l'oiseau.
   - How it works (#280 → #283 → refonte auto-advance) : plus de pin-scroll —
     section de hauteur normale, 4 étapes + piste verticale dont le segment
     accent se remplit (~5,5 s par étape) puis avance, en boucle ; ralenti au
     survol, clic pour sauter. Gate html.js-howplay (posée par le script) ;
     sans elle / en reduced-motion : tout empilé ou piste masquée, clic seul.
     Visuels = pièces isolées de l'UI réelle de l'app (.ui-*), stylées aux
     variables du site.
   - Passe v4 (#283/#284/#286/#287) : reveals généralisés + stagger (#284),
     wordmark en deux lignes bord à bord en mobile (#286), accordéon des
     feature-cards en mobile (#287).
   - Thème : :root = clair ; le sombre vit deux fois (media query pour l'OS,
     [data-theme="dark"] pour le toggle) — GARDER LES DEUX BLOCS EN SYNC.
   ========================================================================== */

/* ---------- Tokens ---------- */

:root {
  color-scheme: light;

  --page:   #fafafa;
  --card:   #ffffff;
  --rule:   #e5e5e5;
  --ink:    #171717;
  --soft:   #525252;  /* secondary body text */
  --muted:  #737373;  /* contrast floor on page/card */
  --accent: #2563eb;
  --tint:   #eef3fd;
  --hover:  #f5f5f5;
  --edge:   #d4d4d4;
  --panel-shadow: -10px 0 24px rgba(0, 0, 0, 0.06);
  --code-bg: #efefef;
  --btn-bg:    #171717;
  --btn-ink:   #ffffff;
  --btn-hover: #404040;

  /* Toggle thème : quelle icône montrer (la destination, pas l'état). */
  --icon-sun:  none;
  --icon-moon: block;

  /* Trame de points (#278) + accents bleus (#279). Le point est un navy-bleu
     très transparent ; le halo et les lignes de grille tirent sur --accent. */
  --dot:  rgba(30, 64, 175, 0.14);
  --halo: rgba(37, 99, 235, 0.08);
  --grid-line: #e2e7f3;   /* --rule légèrement bleui, encore plus discret */
  --grid-step: clamp(7.5rem, 10vw, 10rem);  /* pas des colonnes (#277) */

  /* Gabarit (#263, amendé #277) : la largeur des sections à conteneur
     centré. Hero et démo y échappent désormais (full-bleed). */
  --container-max: 84rem;
  --container-pad: clamp(1.25rem, 4vw, 2rem);

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

/* Sombre via l'OS — ignoré si le toggle a forcé le clair. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --page:   #0a0a0a;
    --card:   #161616;
    --rule:   #2a2a2a;
    --ink:    #ededed;
    --soft:   #b9b9b9;
    --muted:  #a3a3a3;
    --accent: #60a5fa;
    --tint:   #17233c;
    --hover:  #202020;
    --edge:   #3a3a3a;
    --panel-shadow: -10px 0 24px rgba(0, 0, 0, 0.45);
    --code-bg: #262626;
    --btn-bg:    #ededed;
    --btn-ink:   #0a0a0a;
    --btn-hover: #d4d4d4;

    --icon-sun:  block;
    --icon-moon: none;

    --dot:  rgba(147, 197, 253, 0.10);
    --halo: rgba(59, 130, 246, 0.10);
    --grid-line: #232a38;
  }
}

/* Sombre via le toggle (#268) — gagne sur la media query dans les deux sens
   (spécificité (0,2,0) contre le :root clair en (0,1,0)). */
:root[data-theme="dark"] {
  color-scheme: dark;

  --page:   #0a0a0a;
  --card:   #161616;
  --rule:   #2a2a2a;
  --ink:    #ededed;
  --soft:   #b9b9b9;
  --muted:  #a3a3a3;
  --accent: #60a5fa;
  --tint:   #17233c;
  --hover:  #202020;
  --edge:   #3a3a3a;
  --panel-shadow: -10px 0 24px rgba(0, 0, 0, 0.45);
  --code-bg: #262626;
  --btn-bg:    #ededed;
  --btn-ink:   #0a0a0a;
  --btn-hover: #d4d4d4;

  --icon-sun:  block;
  --icon-moon: none;

  --dot:  rgba(147, 197, 253, 0.10);
  --halo: rgba(59, 130, 246, 0.10);
  --grid-line: #232a38;
}

/* ---------- Reset (minimal) ---------- */

*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, p, pre { margin: 0; }

html { -webkit-text-size-adjust: 100%; }

/* Le fond de page vit sur <html> : le calque z-index:-1 (trame de points)
   se glisse ainsi ENTRE le fond et le contenu du <body>. */
html { background: var(--page); }

body {
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* Trame de points (#278, remplace la tuile pixel-art) : halftone fin et
   régulier, fixe, derrière tout, insensible au pointeur. Le masque vertical
   la rend plus présente en haut du viewport (derrière le hero au chargement)
   et l'estompe vers le bas. L'oiseau (canvas z-index énorme) et la
   lisibilité ne la croisent jamais. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: radial-gradient(circle, var(--dot) 1px, transparent 1.6px);
  background-size: 24px 24px;
  -webkit-mask-image: linear-gradient(to bottom,
    rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.55) 45%, rgba(0, 0, 0, 0.28) 100%);
  mask-image: linear-gradient(to bottom,
    rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.55) 45%, rgba(0, 0, 0, 0.28) 100%);
}

::selection { background: var(--tint); color: var(--ink); }

code {
  font-family: var(--mono);
  font-size: 0.875em;
  background: var(--code-bg);
  color: var(--ink);
  padding: 0.1em 0.35em;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--card);
  color: var(--ink);
  padding: 0.5rem 1rem;
  border: 1px solid var(--rule);
  z-index: 10;
}
.skip-link:focus { left: 0.5rem; top: 0.5rem; }

/* ---------- Layout ---------- */

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.section {
  padding-block: clamp(3.5rem, 8vw, 5.5rem);
  /* Filet horizontal pleine largeur : croise les rails, dessine la grille. */
  border-top: 1px solid var(--rule);
}

/* ---------- Nav flottante (#266, ex-header) ----------
   Le header est parti : le hero XXL porte la marque. Survivent le lien
   GitHub et le toggle thème (#268), épinglés en haut à droite. Fond --page
   opaque : lisibles par-dessus tout ce qui scrolle dessous. */

.corner-nav {
  position: fixed;
  top: 0.875rem;
  right: 0.875rem;
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  z-index: 20;
}

.corner-link {
  display: inline-flex;
  align-items: center;
  height: 2rem;
  padding-inline: 0.7rem;
  border: 1px solid var(--edge);
  background: var(--page);
  color: var(--ink);
  font-size: 0.875rem;
  font-weight: 550;
}
.corner-link:hover { background: var(--hover); text-decoration: none; }

/* Toggle thème (#268) : carré, zéro radius, comme le reste des surfaces. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--edge);
  background: var(--page);
  color: var(--ink);
  cursor: pointer;
}
.theme-toggle:hover { background: var(--hover); }
.theme-toggle svg { width: 16px; height: 16px; }
.theme-toggle .icon-sun  { display: var(--icon-sun); }
.theme-toggle .icon-moon { display: var(--icon-moon); }

/* Masqué visuellement, lu par les lecteurs d'écran (le h1 du hero). */
.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;
}

/* ---------- Hero + wordmark XXL (#266) ----------
   « Roadmapped » bord à bord du viewport : un <svg> pleine largeur dont le
   viewBox est recalé en JS sur l'encre exacte du mot (script wordmark dans
   index.html) — hauteur intrinsèque via l'aspect-ratio du viewBox, rendu
   vectoriel net à toute taille. Le perchoir .wordmark-perch, positionné sur
   le haut du glyphe R, est invisible mais garde pointer-events:auto : c'est
   la condition pour rester un perchoir « de confiance » de l'oiseau. */

.hero {
  /* padding-top > ~3.5rem : le R doit rester posable dès le chargement
     (l'oiseau exige ~42px de ciel au-dessus d'un perchoir), et le wordmark
     ne doit pas passer sous la nav flottante. */
  padding-block: clamp(3.75rem, 7vw, 6rem) clamp(2.5rem, 5vw, 4rem);

  /* #277 + #279 : grille de colonnes régulière bord à bord (les rails,
     démultipliés) + halo bleu très diffus derrière le wordmark. Peints sur
     la section elle-même : sous le contenu par construction, et continus
     avec la même grille de .demo (mêmes step/position sur toute la
     largeur du viewport). */
  background-image:
    radial-gradient(58% 42% at 50% 0%, var(--halo), transparent 72%),
    linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px);
  background-size: 100% 100%, var(--grid-step) 100%;
  background-position: 50% 0, 50% 0;
  background-repeat: no-repeat, repeat;
}

/* #277 : le hero s'étend bord à bord — son conteneur perd le cap, la
   lisibilité reste tenue par les max-width en ch du texte. */
.hero .container { max-width: none; }

.wordmark {
  position: relative;
  display: block;
  width: 100%;
  color: var(--ink);
}

.wordmark svg {
  display: block;
  width: 100%;
  height: auto;
}

/* #286 : en mobile, le wordmark casse en deux lignes bord à bord —
   « Road » puis « mapped », chacune remplissant la largeur. Trois <svg>
   par wordmark ; on n'en montre qu'un (desktop) ou deux (mobile).
   Sélecteurs préfixés .wordmark : il faut battre « .wordmark svg »
   ci-dessus (0,1,1) dans les deux sens. */
.wordmark .wordmark-line-two { display: none; }
.wordmark .wordmark-line-two + .wordmark-line-two {
  /* Les viewBox sont recalés au ras de l'encre : sans marge, l'ascendante
     du « d » de mapped toucherait la ligne du dessus. */
  margin-top: clamp(0.375rem, 1.6vw, 0.625rem);
}
@media (max-width: 40rem) {
  .wordmark .wordmark-line-one { display: none; }
  .wordmark .wordmark-line-two { display: block; }
}

.wordmark-text {
  font-family: var(--sans);
  font-weight: 600;      /* #276 : gros mais medium/semibold, plus bold */
  font-size: 100px;      /* = 100 unités user : doit rester égal au FS du script wordmark */
  letter-spacing: 0;     /* surtout pas de tracking : le canvas de mesure n'en tient pas compte */
  fill: currentColor;
}

.wordmark-perch {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;              /* dimensionné par le script wordmark ; 0 = ignoré par l'oiseau */
  height: 18px;          /* ≥ 16px : seuil de hauteur des perchoirs */
  background: transparent;
  pointer-events: auto;  /* requis : un perchoir marqué doit « exister » au pointeur */
}

.hero .container { margin-top: clamp(1.75rem, 4vw, 3rem); }

.hero-tagline {
  max-width: 34ch;
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-wrap: balance;
}

/* #276 : les noms de fichiers de la tagline en monospace, l'accent porté par le
   task.yaml (le vainqueur) via la couleur d'accent. */
.hero-tagline code {
  font-family: var(--mono);
  font-size: 0.82em;
  font-weight: 600;
}
.hero-beat code { color: var(--accent); }

.hero-beat {
  display: block;
  color: var(--muted);
  margin-top: 0.15em;
}

.hero-sub {
  max-width: 58ch;
  margin-top: 1.5rem;
  font-size: clamp(1.0625rem, 1.8vw, 1.1875rem);
  color: var(--soft);
}

.hero-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
  margin-top: 2.25rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border-radius: 6px;
  font-weight: 550;
  font-size: 1rem;
  line-height: 1;
  padding: 0.875rem 1.25rem;
}

.btn-primary {
  background: var(--btn-bg);
  color: var(--btn-ink);
}
.btn-primary:hover {
  background: var(--btn-hover);
  text-decoration: none;
}
.btn-primary code {
  background: color-mix(in srgb, var(--btn-ink) 14%, transparent);
  color: var(--btn-ink);
  padding: 0.2em 0.45em;
  border-radius: 3px;
}

.link-arrow {
  font-weight: 500;
  color: var(--accent);
}

.cta-note {
  margin-top: 1rem;
  font-size: 0.9375rem;
  color: var(--muted);
}

/* ---------- Live demo: two windows (terminal + the real app) ---------- */

.demo {
  padding-block: 0 clamp(3rem, 7vw, 5rem);
  /* #277 : même grille de colonnes que le hero, sans le halo — les deux
     sections étant pleine largeur, les lignes se prolongent sans couture. */
  background-image: linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px);
  background-size: var(--grid-step) 100%;
  background-position: 50% 0;
}

/* #277 : la scène démo est full-bleed elle aussi — seul le padding de
   gabarit la retient aux bords. */
.demo-stage {
  padding-inline: var(--container-pad);
}

/* Two distinct windows with a visible gap: the terminal is one app, the
   dashboard is another. The page background between them is the proof. */
.duo {
  display: grid;
  grid-template-columns: minmax(19rem, 24rem) minmax(0, 1fr);
  gap: clamp(1rem, 2.2vw, 1.75rem);
  align-items: stretch;
}

.window {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--edge);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
}

.window-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.55rem 0.9rem;
  border-bottom: 1px solid var(--rule);
  background: var(--page);
  flex: none;
  min-width: 0;
}

.window-dots {
  display: inline-flex;
  gap: 6px;
  flex: none;
}
.window-dots i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--rule);
  border: 1px solid var(--edge);
}

.window-name {
  font-size: 0.8125rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.window-name-mono {
  font-family: var(--mono);
  font-size: 0.75rem;
}

/* The app window sets the height of the row; the terminal stretches to match. */
.window-app { height: clamp(34rem, 78vh, 52rem); }

.app-frame {
  display: block;
  width: 100%;
  flex: 1;
  min-height: 0;
  border: 0;
  /* The app is light-only for now; its own background, not the site's. */
  background: #fafafa;
}

/* --- Terminal --- */

.term {
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 2.05;
  padding: 1rem 1.1rem;
  flex: 1;
  min-height: 0;
  overflow: auto;
}

.cl   { white-space: pre-wrap; color: var(--soft); }
.cl-p { color: var(--muted); }
.cl[data-kind="you"] .cl-t { color: var(--ink); font-weight: 600; }
.cl[data-kind="cmd"] { color: var(--muted); padding-left: 1.1rem; }
.cl-progress { color: var(--accent); font-weight: 600; }

/* replay states: keep layout, hide content (no layout shift) */
.term-anim .cl:not(.on) { visibility: hidden; }

.term-cursor {
  display: inline-block;
  width: 0.55em;
  height: 1.1em;
  vertical-align: text-bottom;
  background: var(--ink);
}

.demo-caption {
  max-width: 68ch;
  margin-top: 1.75rem;
  font-size: 0.9375rem;
  color: var(--soft);
}

/* ---------- Sections: eyebrows + titles ---------- */

.eyebrow {
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--muted);
  margin-bottom: 0.875rem;
}

/* Le sigil « $ » : seul accent bleu récurrent de la page (#264). */
.eyebrow-ps1 { color: var(--accent); }

.eyebrow-out { color: var(--muted); }

.section-title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  max-width: 30ch;
}

.prose { max-width: 62ch; margin-top: 1.25rem; color: var(--soft); }

/* ---------- Features ---------- */

.feature-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-top: 2rem;
}

.feature-card {
  background: var(--card);
  padding: 1.75rem;
}

/* #287 : l'en-tête complet (fichier + icône + titre) vit dans un <button>
   à l'intérieur du h3. En desktop le bouton est invisible en tant que tel
   (reset complet, cursor par défaut, hors tabulation via JS) : la carte est
   pixel pour pixel celle d'avant. En mobile il devient la tête d'accordéon. */
.feature-toggle {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
}

.feature-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.875rem;
}

.feature-file {
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 400;        /* dans le h3 désormais : ne pas hériter du 650 */
  letter-spacing: normal;
  color: var(--muted);
}

/* Icônes de cartes (#262) : trait fin monochrome, currentColor. */
.feature-icon {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: -1px;
  color: var(--muted);
}

.feature-title {
  font-size: 1.125rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem;
}

.feature-name { display: block; }

.feature-body p {
  font-size: 0.9688rem;
  color: var(--soft);
}

/* Ceinture-bretelles : hidden doit gagner quoi qu'il arrive. */
.feature-body[hidden] { display: none; }

/* ---------- How it works : auto-advance minuté (refonte, ex-stepper) ------
   Plus de pin-scroll : section de hauteur normale. Deux colonnes — les 4
   étapes à gauche (chaque rangée .how-step est un perchoir de l'oiseau),
   les visuels à droite. Le long des étapes, une piste verticale
   (.how-track, 2px sur --rule) : le segment accent (.how-fill, positionné
   par le script how-play sur la rangée active) se remplit sur la durée de
   l'étape (~5,5 s) puis la suivante s'active, en boucle. Survol de la
   colonne des étapes : progression au ralenti (x0.25). Clic : saut direct,
   barre remise à zéro.

   Gate html.js-howplay (posée par le script) :
   - SANS elle (no-JS) : étapes empilées à pleine opacité, les 4 visuels
     empilés séparés d'un filet, piste masquée — tout est lisible.
   - AVEC elle : un seul visuel affiché (l'actif), étapes inactives
     estompées (opacity .5 — jamais ≤ .05 : le test de visibilité de
     l'oiseau tolère la pénombre), piste visible.
   prefers-reduced-motion : piste masquée même avec la gate — le script
   n'auto-avance pas, le clic reste le seul moteur. */

/* align-items: stretch (retour proprio) : la colonne de droite prend
   EXACTEMENT la hauteur du bloc des étapes à gauche — les deux boîtes sont
   à hauteur égale. */
.how-stage {
  margin-top: 1.5rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: stretch;
  width: 100%;
}

/* La piste est une barre inset sur le bord GAUCHE du panneau (absolute,
   hors flux) : le panneau des étapes commence donc PILE au bord gauche du
   conteneur — le callout en dessous s'aligne dessus sans décalage. Même
   vocabulaire que le filet bleu inset du callout. */
.how-lane { position: relative; max-width: 46rem; }

.how-track {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--rule);
  display: none;   /* no-JS : pas de barre morte */
  z-index: 1;
}
html.js-howplay .how-track { display: block; }
.how-fill {
  position: absolute;
  left: 0;
  width: 100%;
  top: 0;
  height: 0;
  background: var(--accent);
}

.how-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--rule);
}

.how-step { padding: 1.25rem clamp(1.25rem, 2.5vw, 1.75rem); }
.how-step + .how-step { border-top: 1px solid var(--rule); }

/* L'estompage « étape inactive » n'a de sens QUE quand le carrousel tourne :
   desktop (≥62rem) ET motion autorisé — exactement la condition du moteur JS
   (engineOn). Hors de là (mobile OU reduced-motion), aucune règle ne s'applique
   ici : les 4 étapes restent à pleine opacité et se lisent comme une liste. */
@media (min-width: 62rem) and (prefers-reduced-motion: no-preference) {
  html.js-howplay .how-step {
    opacity: 0.5;
    transition: opacity 0.3s ease;
    cursor: pointer;
  }
  html.js-howplay .how-step:hover { opacity: 0.8; }
  html.js-howplay .how-step.is-active { opacity: 1; }
}

/* Le titre entier (numéro + intitulé) est le bouton de navigation. Reset
   complet : au repos il ressemble trait pour trait à un titre ordinaire.
   Le focus visible vient du :focus-visible global (outline accent). */
.how-step-btn {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.how-step-num {
  font-family: var(--mono);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--accent);   /* #279 : petit accent bleu de structure */
  margin-right: 0.5rem;
}

.how-step-title {
  font-size: 1.125rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  margin-bottom: 0.375rem;
}

.how-step p {
  font-size: 0.9688rem;
  color: var(--soft);
  max-width: 58ch;
}

/* --- Visuels : pièces isolées de l'UI réelle de l'app (.ui-*), posées
   DANS un fragment de chrome du dashboard (.ui-frame : barre d'onglets +
   rail de sidebar estompé) pour qu'elles lisent « découpées dans le vrai
   outil » et non comme des widgets isolés. La fenêtre bordée = .ui-frame
   lui-même ; avec la gate, il remplit toute la hauteur (= celle des étapes,
   via align-items: stretch). Un visuel actif à la fois ; empilés sans la
   gate (no-JS). */
.how-visuals { position: relative; min-width: 0; }
.how-visual { overflow-x: auto; }
.how-visual + .how-visual { margin-top: 1.25rem; }

html.js-howplay .how-visuals { display: flex; flex-direction: column; min-height: 23rem; }
html.js-howplay .how-visual { display: none; }
html.js-howplay .how-visual + .how-visual { margin-top: 0; }
html.js-howplay .how-visual.is-active {
  display: flex;
  flex-direction: column;
  flex: 1;
  animation: how-visual-in 0.4s ease;
}
@keyframes how-visual-in { from { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  html.js-howplay .how-track { display: none; }
  html.js-howplay .how-visual.is-active { animation: none; }
}

/* --- Chrome de dashboard autour de la pièce (retour proprio #1) ------------
   Fenêtre d'app : barre d'onglets (Backlog/Roadmap/Docs + pastille Activity)
   + rail de sidebar estompé à gauche, la pièce au centre sur fond --page.
   L'onglet actif porte un filet accent (structure) ; la pastille Activity
   s'allume en accent sur le visuel 02. Accent PARCIMONIEUX, tout en vars. */
.ui-frame {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  border: 1px solid var(--rule);
  background: var(--card);
}
.ui-frame-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4375rem 0.625rem;
  border-bottom: 1px solid var(--rule);
}
.ui-frame-tabs { display: flex; gap: 0.875rem; min-width: 0; }
.ui-frame-tab { font-size: 0.75rem; color: var(--muted); padding-bottom: 2px; }
.ui-frame-tab.is-on {
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent);
}
.ui-frame-live {
  flex-shrink: 0;
  font-size: 0.6875rem;
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 0.25rem;
  padding: 0.0625rem 0.375rem;
}
.ui-frame-live.is-on { color: var(--accent); border-color: var(--accent); }
.ui-frame-body { display: flex; flex: 1; min-height: 0; min-width: 0; }
.ui-frame-rail {
  flex-shrink: 0;
  width: 2.5rem;
  border-right: 1px solid var(--rule);
  background: var(--page);
  opacity: 0.6;
  padding: 0.625rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.ui-frame-rail span { display: block; height: 2px; background: var(--rule); }
.ui-frame-rail span:first-child { background: var(--edge); }   /* item « actif » du nav, estompé */
.ui-frame-piece {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0.875rem;
  background: var(--page);
  overflow: hidden;
}

/* --- Vocabulaire des pièces UI — mappé de l'app vers les tokens du site :
   neutral-900→--ink, neutral-500→--muted, neutral-600/700→--soft,
   white→--card, neutral-50→--page/--hover, neutral-200→--rule,
   neutral-300→--edge, accent→--accent, accent-tint→--tint. --- */

.ui-glyph, .ui-icon { flex-shrink: 0; }
.ui-glyph--live { color: var(--accent); }
.ui-icon { color: var(--muted); }
.ui-id {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--muted);
}
.ui-count { font-family: var(--mono); font-size: 0.75rem; color: var(--muted); }
.ui-dim { font-size: 0.6875rem; color: var(--muted); }
.ui-time {
  margin-left: auto;
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.ui-tag { flex-shrink: 0; font-size: 0.6875rem; color: var(--muted); }
.ui-temp {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--muted);
}
.ui-temp svg { flex-shrink: 0; }
.ui-chip {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  border: 1px solid var(--rule);
  background: var(--page);
  padding: 0 0.375rem;
  font-size: 0.6875rem;
  line-height: 1.1rem;
  color: var(--muted);
}
.ui-chip--strong {
  border-color: var(--edge);
  background: var(--hover);
  color: var(--soft);
  font-weight: 500;
}
.ui-chip--mono { font-family: var(--mono); }

/* 01 · Backlog (TaskRow) : rangées sous leur tête de type. */
.ui-pane { border: 1px solid var(--rule); background: var(--card); }
.ui-pane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--rule);
}
.ui-pane-title { font-size: 0.8125rem; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.ui-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--ink);
}
.ui-row + .ui-row { border-top: 1px solid var(--rule); }
.ui-row-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-row.is-done .ui-row-title { color: var(--muted); text-decoration: line-through; }
.ui-row-meta {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-shrink: 0;
}
.ui-row-meta .ui-time { margin-left: 0; }

/* 02 · Activity (LiveActivityMenu) : le popup du header. */
.ui-pop {
  width: 100%;
  max-width: 21rem;
  margin-inline: auto;
  border: 1px solid var(--rule);
  background: var(--card);
}
.ui-pop-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--rule);
}
.ui-pop-title { font-size: 0.75rem; font-weight: 600; color: var(--ink); }
.ui-log { list-style: none; margin: 0; padding: 0; }
.ui-log li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4375rem 0.75rem;
  font-size: 0.75rem;
}
.ui-log li + li { border-top: 1px solid var(--rule); }
.ui-log .is-fresh { background: var(--tint); }
.ui-verb { flex-shrink: 0; font-weight: 500; color: var(--soft); }
.ui-log-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--soft);
}
.ui-pop-foot {
  margin: 0;
  border-top: 1px solid var(--rule);
  padding: 0.4375rem 0.75rem;
  font-size: 0.6875rem;
  color: var(--muted);
}

/* 03 · Panneau d'une tâche done (TaskPanel) : en-tête, titre barré, bloc Log. */
.ui-panel {
  width: 100%;
  max-width: 26rem;
  margin-inline: auto;
  border: 1px solid var(--rule);
  background: var(--card);
  padding: 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.ui-panel-head { display: flex; align-items: center; gap: 0.375rem; }
.ui-status { font-size: 0.75rem; color: var(--soft); }
.ui-panel-title {
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--muted);
  text-decoration: line-through;
}
.ui-logbox {
  border: 1px solid var(--rule);
  background: var(--page);
  padding: 0.625rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.ui-logbox-cap { font-size: 0.6875rem; font-weight: 500; color: var(--muted); }
.ui-dates { font-size: 0.75rem; color: var(--muted); }
.ui-field { display: flex; flex-direction: column; gap: 0.125rem; }
.ui-field-label { font-size: 0.6875rem; color: var(--muted); }
.ui-field-val { font-size: 0.75rem; line-height: 1.45; color: var(--ink); }
.ui-field-val--mono { font-family: var(--mono); }
.ui-panel-foot {
  border-top: 1px solid var(--rule);
  padding-top: 0.5rem;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 04 · Roadmap en colonnes (RoadmapColumns) : têtes, barres fines, cartes. */
.ui-board {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}
.ui-col { min-width: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.ui-col-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}
.ui-col-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.ui-bar {
  height: 4px;
  border-radius: 999px;   /* fidèle à l'app (rounded-full), seule entorse au zéro-radius */
  background: var(--rule);
  overflow: hidden;
}
.ui-bar i { display: block; height: 100%; background: var(--accent); }
.ui-cards { display: flex; flex-direction: column; margin-top: 0.25rem; }
.ui-card {
  display: flex;
  align-items: flex-start;
  gap: 0.375rem;
  border: 1px solid var(--rule);
  background: var(--card);
  padding: 0.5rem 0.625rem;
  font-size: 0.75rem;
  color: var(--ink);
}
.ui-card + .ui-card { margin-top: -1px; }
.ui-card .ui-glyph { margin-top: 0.1875rem; }
.ui-card-body { min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.ui-card-title { color: var(--ink); }
.ui-avail { font-size: 0.6875rem; font-weight: 500; color: var(--soft); }
.ui-card--more { color: var(--muted); font-size: 0.6875rem; }

/* Mobile / tablette : une colonne — étapes d'abord, visuel dessous.
   La piste verticale est masquée (le clic + l'auto-advance suffisent). */
@media (max-width: 62rem) {
  /* Mobile : la section = titre + les 4 étapes en texte. Pas d'exemples
     (auto-advance coupé côté JS), pas de piste, pas de gouttière vide. */
  .how-stage { grid-template-columns: 1fr; }
  .how-lane { max-width: none; }
  html.js-howplay .how-track { display: none; }
  .how-visuals,
  html.js-howplay .how-visuals { display: none; }
}

.callout {
  background: var(--card);
  border: 1px solid var(--rule);
  box-shadow: inset 2px 0 0 var(--accent);
  padding: 1rem 1.25rem;
  color: var(--ink) !important;
  max-width: 58ch;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}

/* ---------- Quickstart ---------- */

.code-block {
  background: var(--card);
  border: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.875rem;
  line-height: 1.9;
  padding: 1.25rem 1.5rem;
  margin-top: 1.75rem;
  max-width: 46rem;
  overflow-x: auto;
}

.code-block code {
  background: none;
  padding: 0;
  font-size: 1em;
}

.code-comment { color: var(--muted); }

/* Quickstart refondu (#300) : trois routes d'installation en blocs distincts
   dans un panneau unique (gaps 1px sur --rule, comme .feature-grid), une
   commande = une rangée .cmd-row copiable individuellement via le .btn-copy
   existant. Le bloc final « After install » reprend le filet bleu inset du
   callout : les trois routes convergent là. Tout en variables : theme-aware. */

.install-stack {
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  max-width: 46rem;
  margin-top: 1.75rem;
}

.install-method {
  background: var(--card);
  padding: 1.25rem 1.5rem 1.375rem;
}

.install-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.75rem;
  row-gap: 0.125rem;
  margin-bottom: 0.875rem;
}

.install-label {
  font-size: 1.0625rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

/* « or » : préfixe mono discret des routes alternatives — les blocs sont des
   options, pas des étapes. */
.install-or {
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--muted);
  margin-right: 0.5rem;
}

.install-note {
  font-size: 0.875rem;
  color: var(--muted);
}

/* Une commande = une rangée : sigil, commande, commentaire, bouton Copy.
   flex-wrap : en mobile le commentaire et le bouton passent à la ligne
   plutôt que de déborder. */
.cmd-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  background: var(--page);
  border: 1px solid var(--rule);
  padding: 0.5rem 0.75rem;
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.6;
}
.cmd-row + .cmd-row { margin-top: 0.5rem; }

/* Même vocabulaire que .eyebrow-ps1 : le $ est bleu, et il est
   décoratif (aria-hidden) — data-copy-text porte la commande nue. */
.cmd-ps1 { flex: none; color: var(--accent); }

.cmd-text {
  background: none;
  padding: 0;
  font-size: inherit;
  color: var(--ink);
  min-width: 0;
  overflow-wrap: anywhere;
}

.cmd-row .btn-copy { margin-left: auto; }

.install-then { box-shadow: inset 2px 0 0 var(--accent); }

.under-block { margin-top: 1.25rem; }

/* ---------- Privacy / Open source pair ---------- */

.pair-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}

.pair-card {
  background: var(--card);
  padding: clamp(1.75rem, 3vw, 2.5rem);
}

.pair-title { font-size: 1.375rem; margin-bottom: 0.75rem; }

.pair-card > p:not(.eyebrow) {
  font-size: 0.9688rem;
  color: var(--soft);
  max-width: 58ch;
}

.pair-links { margin-top: 1.25rem; }
.link-sep { color: var(--muted); margin-inline: 0.5rem; }

/* ---------- Footer (XXL, #266) ----------
   Le wordmark géant referme la page en miroir du hero ; son R est le second
   perchoir de l'oiseau. Pas de padding-bottom : le mot s'assoit sur le bord
   bas de la fenêtre. */

.site-footer {
  border-top: 1px solid var(--rule);
  padding-block: 2.5rem 0;
  font-size: 0.9375rem;
  color: var(--soft);
}

.footer-note { color: var(--muted); margin-top: 0.375rem; }

.wordmark-footer { margin-top: clamp(2rem, 5vw, 3.5rem); }

/* ---------- Reveals au scroll (#267, généralisés #284) ----------
   html.js-reveal n'est posé (dans <head>) que si IntersectionObserver
   existe ET que prefers-reduced-motion ne demande pas le calme : sans JS
   ou en reduced-motion, tout est visible d'emblée. `transform: none` en
   état final — aucun containing block résiduel.
   #284 : fade + rise (14px) sur tous les éléments notables ; le stagger
   entre éléments d'un même lot est un transition-delay inline posé par
   l'IO (script reveals), nettoyé en fin de transition. Les éléments
   perchoirs de l'oiseau qui portent .reveal repassent toujours à
   opacity 1 (l'oiseau ignore opacity ≤ .05 en attendant) ; les deux
   wordmarks, perchoirs de départ, ne sont JAMAIS .reveal. */

html.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
html.js-reveal .reveal.reveal-in {
  opacity: 1;
  transform: none;
}

/* ---------- Responsive ---------- */

/* Grille features : 4 → 2 → 1 colonnes. */
@media (max-width: 76rem) {
  .feature-grid { grid-template-columns: 1fr 1fr; }
}

/* The two windows stack below ~1000px: terminal first, then the app.
   The app window keeps a fixed height and scrolls internally — the page
   itself never scrolls sideways. */
@media (max-width: 62.5rem) {
  .duo { grid-template-columns: 1fr; }

  .term {
    flex: none;
    max-height: 18rem;
  }

  .window-app { height: min(80vh, 38rem); }

  /* The app is a desktop app. Rather than squeeze it into a phone column,
     render it at 2× width and scale it down: the real layout, zoomed out,
     still fully interactive. */
  .window-app { overflow: hidden; }
  .app-frame {
    width: 200%;
    height: 200%;
    flex: none;
    transform: scale(0.5);
    transform-origin: top left;
  }
}

@media (max-width: 760px) {
  .feature-grid,
  .pair-grid { grid-template-columns: 1fr; }

  .feature-card { padding: 1.375rem; }

  /* #287 : sous ce breakpoint les cartes deviennent un accordéon (le JS pose
     aria-expanded + la classe .is-open). La tête devient cliquable ; repliée,
     l'en-tête se resserre un peu. Le repli est ANIMÉ (#290) via grid-rows
     0fr↔1fr — insensible à la hauteur du contenu. Gated par html.js-accordion :
     sans JS, aucune règle de repli -> tout reste déplié (fallback). */
  /* #290 : toute la carte cliquable en mobile, pas seulement la tête. */
  .feature-card { cursor: pointer; }
  .feature-toggle { cursor: pointer; }
  html.js-accordion .feature-toggle[aria-expanded="false"] .feature-head { margin-bottom: 0.625rem; }
  html.js-accordion .feature-body {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.3s ease;
  }
  html.js-accordion .feature-body > * { overflow: hidden; }
  html.js-accordion .feature-card.is-open .feature-body { grid-template-rows: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  html.js-accordion .feature-body { transition: none; }
}

/* Sous ~768px le contenu touche les bords : la grille de colonnes
   n'apporte plus rien (#277) — le hero garde son halo (#279). */
@media (max-width: 48rem) {
  .hero {
    background-image: radial-gradient(58% 42% at 50% 0%, var(--halo), transparent 72%);
    background-size: 100% 100%;
    background-repeat: no-repeat;
  }
  .demo { background-image: none; }
}

/* ---------- Motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    /* #284 : neutralise aussi les délais de stagger posés inline par
       l'IO si la préférence bascule en cours de session. */
    transition-delay: 0ms !important;
  }
}

/* ---------- Prompt-to-copy CTA (hero + final CTA) ---------- */

.prompt-copy {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  flex-wrap: wrap;
  max-width: 100%;
  background: var(--card);
  border: 1px solid var(--rule);
  padding: 0.55rem 0.7rem;
}

.prompt-tag {
  flex: none;
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--muted);
}

.prompt-text {
  font-family: var(--mono);
  font-size: 0.8125rem;
  background: none;
  padding: 0;
  color: var(--soft);
  white-space: normal;
  word-break: break-word;
}

.btn-copy {
  flex: none;
  border: 1px solid var(--edge);
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 550;
  padding: 0.35rem 0.7rem;
  cursor: pointer;
}
.btn-copy:hover { background: var(--hover); }
.btn-copy:disabled { color: var(--muted); cursor: default; }
