/* ============================================================
   Portfolio — Emmanuel Nguyen
   Shared HUD kit: tokens, cursors, nav, buttons, reveal,
   plus the layout for the "À propos" page.
   ============================================================ */

/* ---------- 1. Tokens ---------- */

:root {
  --acc:  #00ffd5;
  --acc2: #ff9a00;

  --bg:       #050607;
  --bg-panel: #04090a;
  --bg-frame: #060809;

  --txt:   #e8ecec;
  --txt-2: #c9d1d3;
  --txt-3: #9aa4a6;
  --txt-4: #8a9294;
  --txt-5: #afb4b6;
  --txt-dim: #2e6e64;

  --line:      rgba(255, 255, 255, .28);
  --line-soft: rgba(255, 255, 255, .12);

  --font-display: 'Chakra Petch', sans-serif;
  --font-mono:    'Share Tech Mono', monospace;
  --font-body:    'Space Grotesk', sans-serif;
}

/* ---------- 2. Base ---------- */

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

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--font-body);
}

a { color: var(--acc); text-decoration: none; }
a:hover { color: #7dffe9; }

img { max-width: 100%; }

/* ---------- 3. Cursors ---------- */

html, body {
  cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28'><g fill='none' stroke='%23064e46' stroke-width='2' transform='translate(2,2)'><path d='M2 9V2h7M19 2h7v7M26 19v7h-7M9 26H2v-7'/></g><g fill='none' stroke='%2300ffd5' stroke-width='2'><path d='M2 9V2h7M19 2h7v7M26 19v7h-7M9 26H2v-7'/></g><rect x='12' y='12' width='4' height='4' fill='%2300ffd5'/></svg>") 14 14, auto;
}

a, a *, .btn-copy, .btn-copy * {
  cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><rect width='32' height='32' fill='%23ffffff' fill-opacity='0.5'/><g fill='none' stroke='%23064e46' stroke-width='2' transform='translate(2,2)'><path d='M2 10V2h8M20 2h8v8M28 20v8h-8M10 28H2v-8'/></g><g fill='none' stroke='%2300ffd5' stroke-width='2'><path d='M2 10V2h8M20 2h8v8M28 20v8h-8M10 28H2v-8'/></g><rect x='11' y='11' width='8' height='8' fill='%2300ffd5'/><rect x='14' y='14' width='2' height='2' fill='%23050607'/></svg>") 16 16, pointer;
}

/* Trailing ghost sprite, spawned by site.js on mousemove. */
.cursor-ghost {
  position: fixed;
  width: 28px;
  height: 28px;
  pointer-events: none;
  z-index: 9998;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28'><g fill='none' stroke='%2300ffd5' stroke-width='2'><path d='M2 9V2h7M19 2h7v7M26 19v7h-7M9 26H2v-7'/></g><rect x='12' y='12' width='4' height='4' fill='%2300ffd5'/></svg>");
  background-size: contain;
  animation: ghostFade .45s ease-out forwards;
}

/* ---------- 4. Keyframes ---------- */

@keyframes glowPulse {
  0%, 100% { text-shadow: 0 0 8px rgba(0, 255, 213, .8), 0 0 24px rgba(0, 255, 213, .35); }
  50%      { text-shadow: 0 0 14px rgba(0, 255, 213, 1), 0 0 40px rgba(0, 255, 213, .55); }
}

@keyframes glowPulseAcc2 {
  0%, 100% { text-shadow: 0 0 8px rgba(255, 154, 0, .8), 0 0 24px rgba(255, 154, 0, .35); }
  50%      { text-shadow: 0 0 14px rgba(255, 154, 0, 1), 0 0 40px rgba(255, 154, 0, .55); }
}

@keyframes dotBlink { 0%, 100% { opacity: 1; } 50% { opacity: .2; } }

@keyframes navBar { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }

@keyframes ghostFade {
  0%   { opacity: .35; filter: blur(0.5px); transform: scale(1); }
  100% { opacity: 0;   filter: blur(4px);   transform: scale(.8); }
}

@keyframes btnSweep { to { left: 130%; } }

/* ---------- 5. Buttons ---------- */

/* Notched outline button. The 1px "border" is the parent background showing
   through around an inset ::before that paints the fill. */
.btn-out,
.btn-out-sm {
  position: relative;
  isolation: isolate;
  background: var(--edge, rgba(255, 255, 255, .25));
}

.btn-out::before,
.btn-out-sm::before {
  content: '';
  position: absolute;
  inset: 1px;
  background: var(--fill, var(--bg));
  z-index: -1;
}

.btn-out:hover,
.btn-out-sm:hover {
  --edge: var(--hover-edge, var(--acc));
  --fill: color-mix(in srgb, var(--acc) 12%, #050607);
  color: var(--acc);
}

.btn-out {
  color: var(--txt);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%);
}
.btn-out::before {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 11px), calc(100% - 11px) 100%, 0 100%);
}

.btn-out-sm {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%);
}
.btn-out-sm::before {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%);
}

/* Solid accent button with a light sweep on hover. */
.btn-bevel-fill {
  position: relative;
  overflow: hidden;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%);
  transition: filter .25s ease, letter-spacing .25s ease;
}

.btn-bevel-fill::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -80%;
  width: 45%;
  background: linear-gradient(105deg, transparent, rgba(255, 255, 255, .75), transparent);
  transform: skewX(-18deg);
  pointer-events: none;
}

.btn-bevel-fill:hover {
  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--acc) 70%, transparent)) brightness(1.12);
  letter-spacing: 3px;
}
.btn-bevel-fill:hover::after { animation: btnSweep .6s ease forwards; }

/* ---------- 6. Scroll reveal ---------- */

.sec-reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .6s ease, transform .6s ease;
}
.sec-reveal.sec-in { opacity: 1; transform: none; }

/* ---------- 7. Nav HUD ---------- */

.hud {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 32px;
  min-height: 84px;
  background: var(--bg);
  clip-path: polygon(
    0 0, 100% 0,
    100% calc(100% - 14px), calc(100% - 14px) 100%,
    calc(50% + 90px) 100%, calc(50% + 78px) calc(100% - 8px),
    calc(50% - 78px) calc(100% - 8px), calc(50% - 90px) 100%,
    14px 100%, 0 calc(100% - 14px)
  );
}

/* The two baseline rules stop short of the centre notch. */
.hud__rule { position: absolute; bottom: 0; height: 1px; background: var(--line); }
.hud__rule--l { left: 14px; right: calc(50% + 89px); }
.hud__rule--r { left: calc(50% + 89px); right: 14px; }

.hud__corner { position: absolute; bottom: 0; width: 15px; height: 15px; pointer-events: none; }
.hud__corner--l { left: 0; }
.hud__corner--r { right: 0; }

.hud__notch {
  position: absolute;
  bottom: 0;
  left: calc(50% - 90px);
  width: 180px;
  height: 9px;
  pointer-events: none;
}

.hud__logo { display: flex; align-items: center; gap: 14px; color: var(--txt); }

.hud__logo-txt {
  display: flex;
  align-items: baseline;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: 1px;
}

.hud__logo .hi { color: var(--txt); }
.hud__logo .lo { color: var(--txt-5); }

.hud__caret {
  display: inline-block;
  width: 9px;
  height: 16px;
  background: #fff;
  transform: translateY(2px);
  animation: dotBlink 1.1s steps(1, end) infinite;
}

.hud__hatch {
  position: absolute;
  left: 210px;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 12px;
  opacity: .55;
  background: repeating-linear-gradient(-55deg, rgba(255, 255, 255, .9) 0 3px, transparent 3px 8px);
}

.hud__pips {
  position: absolute;
  left: 300px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  gap: 5px;
}
.hud__pips span { width: 3px; height: 3px; background: rgba(255, 255, 255, .5); }
.hud__pips span:nth-child(2) { background: rgba(255, 255, 255, .3); }
.hud__pips span:nth-child(3) { background: rgba(255, 255, 255, .9); }

.hud__tabs {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 1px;
}

.hud__tabs a { padding: 8px 18px; color: var(--txt-4); }
.hud__tabs a:hover { color: var(--acc); }
.hud__tabs a[aria-current='page'] { --edge: var(--acc); color: var(--acc); }

.hud__status {
  display: flex;
  gap: 18px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--txt-5);
}

.hud__bars { display: flex; align-items: center; gap: 4px; margin-right: 4px; }
.hud__bars span {
  width: 2px;
  height: 14px;
  background: rgba(255, 255, 255, .35);
  animation: navBar .9s ease-in-out infinite;
}
.hud__bars span:nth-child(2) {
  background: rgba(255, 255, 255, .25);
  animation-duration: 1.2s;
  animation-delay: .2s;
}
.hud__bars span:nth-child(3) {
  background: var(--acc2);
  box-shadow: 0 0 6px rgba(255, 154, 0, .6);
  animation-duration: .75s;
  animation-delay: .1s;
}

.hud__live { color: var(--acc2); text-shadow: 0 0 8px rgba(255, 154, 0, .6); }

/* ---------- 8. Bio + portrait ---------- */

.bio {
  display: grid;
  grid-template-columns: 1fr 520px;
  border-bottom: 1px solid var(--line);
}

.bio__text {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 90px 60px;
  border-right: 1px solid var(--line);
}


.bracket { position: absolute; width: 26px; height: 26px; }
.bracket--tl { top: 20px; left: 20px; border-top: 1px solid var(--acc); border-left: 1px solid var(--acc); }
.bracket--tr { top: 20px; right: 20px; border-top: 1px solid var(--acc); border-right: 1px solid var(--acc); }
.bracket--bl { bottom: 20px; left: 20px; border-bottom: 1px solid var(--acc); border-left: 1px solid var(--acc); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 6px;
  color: var(--acc);
  margin-bottom: 24px;
}

.page-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 76px;
  line-height: .98;
  text-transform: uppercase;
  min-height: 74px;
}

.bio__lead,
.bio__sub {
  max-width: 620px;
  font-size: 19px;
  font-weight: 400;
  line-height: 1.7;
}
.bio__lead { margin: 32px 0 0; color: var(--txt-2); }
.bio__sub  { margin: 20px 0 0; color: var(--txt-3); }

.bio__links {
  display: flex;
  gap: 28px;
  margin-top: 40px;
  font-family: var(--font-mono);
  font-size: 14px;
}

.link-uline { padding-bottom: 3px; border-bottom: 1px solid var(--acc); }
.link-uline--plain { color: var(--txt); border-bottom-color: rgba(255, 255, 255, .4); }
.link-uline--plain:hover { color: var(--acc); border-bottom-color: var(--acc); }

.bio__photo {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 50px;
  background: var(--bg-panel);
}

.cam-tag {
  position: absolute;
  top: 16px;
  left: 16px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--txt-dim);
}

.portrait {
  position: relative;
  padding: 10px;
  background: var(--bg-frame);
  border: 1px solid var(--acc);
  box-shadow: 0 0 30px rgba(0, 255, 213, .25);
}

.portrait img {
  display: block;
  width: 380px;
  height: 420px;
  object-fit: cover;
  background: #0b1113;
  filter: grayscale(35%) contrast(1.05);
}

.portrait__caption {
  position: absolute;
  bottom: 22px;
  left: 22px;
  padding: 6px 12px;
  background: var(--bg);
  border: 1px solid rgba(255, 255, 255, .3);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--acc);
}

/* ---------- 9. Labelled sections ---------- */

.sec {
  display: grid;
  grid-template-columns: 380px 1fr;
  border-bottom: 1px solid var(--line);
}

.sec__label { padding: 60px; border-right: 1px solid var(--line); }

.sec__label h2 {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 3px;
  color: var(--acc);
}

.sec__body { padding: 60px; }

/* Équipement */

.kit { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 40px; }

.kit h3 {
  margin: 0 0 18px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 18px;
}

.kit ul {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--txt-3);
}

.kit .tick { color: var(--acc); }

/* Journal de bord */

.log__heading {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 22px;
}
.log__heading--spaced { margin: 44px 0 8px; }

.log { display: flex; flex-direction: column; max-width: 860px; }

.log__row {
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 24px;
  padding: 26px 8px;
  border-top: 1px solid var(--line);
}
.log__row:last-child { border-bottom: 1px solid var(--line); }

.log__when { font-family: var(--font-mono); font-size: 14px; color: var(--acc); }

.log__what {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
}

.log__desc {
  margin: 8px 0 0;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--txt-3);
}

/* ---------- 9b. Shared content blocks ---------- */

/* Full-width hero band with the dot canvas behind it (Projets, Projet). */
.hero-sec {
  position: relative;
  padding: 90px 60px 70px;
  border-bottom: 1px solid var(--line);
}
.hero-sec--flush { padding: 80px 60px 0; }

.dots-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.hero-sec > *:not(.dots-canvas):not(.bracket) { position: relative; }

.hero-sec .page-title { font-size: 88px; line-height: .96; min-height: 85px; }

.hero-sec__lead {
  max-width: 640px;
  margin: 24px 0 0;
  font-size: 18px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--txt-3);
}

/* Mono chip */
.tag {
  padding: 4px 12px;
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  color: var(--txt-4);
}
.tag--acc { border-color: var(--acc); color: var(--acc); }
.tag--acc2 { border-color: var(--acc2); color: var(--acc2); }
.tag--lg { padding: 8px 16px; font-size: 13px; color: var(--txt-2); }

.tags { display: flex; gap: 8px; }
.tags--wrap { flex-wrap: wrap; gap: 10px; max-width: 780px; margin-top: 22px; }

/* Placeholder visual — stands in until a real image is dropped in. */
.frame {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, #0e1416, #060809);
}
.frame--alt { background: linear-gradient(200deg, #0e1416, #060809); }
.frame--bordered { border: 1px solid var(--line); }

.frame__tag,
.frame__note {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--txt-dim);
}
.frame__tag { top: 14px; left: 16px; }
.frame__note { bottom: 14px; right: 16px; }

.frame__label { font-family: var(--font-mono); font-size: 13px; color: #2e3a3c; }

/* Project row (Projets) */
.prj {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  border-bottom: 1px solid var(--line);
  color: var(--txt);
}
.prj:hover { background: rgba(0, 255, 213, .04); color: var(--txt); }
/* A dossier not written yet: shown, but it leads nowhere and does not react. */
.prj--soon:hover { background: none; }

.prj__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 18px;
  padding: 56px 60px;
}
.prj:not(.prj--flip) .prj__body { border-right: 1px solid var(--line); }
.prj--flip .prj__visual { border-right: 1px solid var(--line); }

.prj__head { display: flex; align-items: center; gap: 18px; }
.prj__num { font-family: var(--font-mono); font-size: 16px; color: var(--acc); }

.prj__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 34px;
  line-height: 1.15;
}

.prj__desc { font-size: 16px; font-weight: 400; line-height: 1.6; color: var(--txt-3); }

.prj__meta {
  display: flex;
  gap: 32px;
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--txt-5);
}
.prj__open { color: var(--acc); }

.prj__visual { height: 460px; }
/* A real visual in place of the placeholder frame: it fills the slot. */
.prj__visual img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Project detail */

.back-link { font-family: var(--font-mono); font-size: 13px; color: var(--txt-4); }
.back-link:hover { color: var(--acc); }

.dossier { display: flex; align-items: center; gap: 14px; margin-top: 34px; }
.dossier__id { font-family: var(--font-mono); font-size: 16px; line-height: 20px; color: var(--acc); }

.prj-title {
  margin: 22px 0 0;
  max-width: 1100px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 66px;
  line-height: 1.02;
  text-transform: uppercase;
}

.meta-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: 50px;
  border: 1px solid var(--line);
  border-bottom: none;
}
.meta-grid > div { padding: 20px 24px; border-right: 1px solid var(--line); }
.meta-grid > div:last-child { border-right: none; }
.meta-grid dt {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--txt-5);
}
.meta-grid dd {
  margin: 8px 0 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 17px;
}

.hero-visual { height: 520px; border: 1px solid var(--line); border-bottom: none; }

/* Hero carousel (Projet) — crossfade slideshow driven by [data-carousel] in
   site.js. The frame follows the screenshots' ratio instead of a fixed height,
   so the mockups are never cropped at any width. */
.hero-visual.carousel { height: auto; display: flex; flex-direction: column; background: var(--bg-frame); border-bottom: 1px solid var(--line); }

.carousel__viewport { position: relative; aspect-ratio: 2400 / 1508; overflow: hidden; touch-action: pan-y; }

.carousel__slide {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  transform: scale(1.03);
  transition: opacity .7s ease, transform 1.2s cubic-bezier(.2, .7, .2, 1);
}
.carousel__slide.is-active { opacity: 1; transform: none; }
.carousel__slide img { display: block; width: 100%; height: 100%; object-fit: cover; }

.carousel__bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 1px;
}
.carousel__caption { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--txt-4); }
.carousel__count { color: var(--acc); }

.carousel__dots { display: flex; gap: 6px; }
/* 20px-tall hit area around a 3px bar. */
.carousel__dot { position: relative; width: 28px; height: 20px; padding: 0; border: 0; background: none; cursor: pointer; }
.carousel__dot::before {
  content: '';
  position: absolute;
  inset: 8.5px 0 auto;
  height: 3px;
  background: rgba(255, 255, 255, .18);
  transition: background .2s;
}
.carousel__dot:hover::before { background: rgba(255, 255, 255, .45); }
.carousel__dot[aria-current="true"]::before { background: var(--acc); }

.carousel__btn {
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  background: none;
  color: var(--txt);
  font-family: var(--font-mono);
  font-size: 14px;
  cursor: pointer;
  transition: border-color .2s, color .2s;
}
.carousel__btn:hover { border-color: var(--acc); color: var(--acc); }

/* Time left before the next slide, drawn along the top edge of the bar. */
.carousel__progress {
  position: absolute;
  top: -1px;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--acc);
  transform: scaleX(0);
  transform-origin: left;
}
.carousel.is-playing .carousel__progress { animation: carouselProgress var(--carousel-delay, 6s) linear forwards; }
@keyframes carouselProgress { to { transform: scaleX(1); } }

/* Without JS only the first slide and its caption show. */
.carousel:not(.is-ready) .carousel__dots,
.carousel:not(.is-ready) .carousel__btn { visibility: hidden; }

@media (max-width: 720px) {
  .carousel__bar { flex-wrap: wrap; gap: 10px 16px; padding: 12px 16px; }
  .carousel__caption { flex-basis: 100%; }
  .carousel__dots { margin-right: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .carousel__slide { transform: none; transition: opacity .01s; }
}

.lead {
  max-width: 760px;
  margin: 0;
  font-size: 20px;
  font-weight: 400;
  line-height: 1.7;
  color: var(--txt-2);
}
.lead em { font-style: normal; color: var(--acc); }

/* Narrow variant of the .log row used for "Décisions clés". */
.log--narrow .log__row { grid-template-columns: 80px 1fr; gap: 20px; }
.log--narrow .log__when { font-size: 15px; }
.log--narrow .log__desc { margin-top: 10px; }

.sol-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 44px; }
.sol-grid .frame { height: 360px; }
/* An odd last frame would sit alone in half a row — let it take the full width. */
.sol-grid .frame:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* ---------- 9 bis. Dossier : sommaire à gauche, lecture à droite ----------
   The rail is driven by [data-case-nav] in site.js. Wide margins on both
   sides keep the reading column near 700px whatever the viewport. */

.cs { display: grid; grid-template-columns: 400px minmax(0, 1fr); }

.cs__nav {
  position: sticky;
  top: 84px;
  align-self: start;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 84px);
  padding: 56px;
  border-right: 1px solid var(--line);
}

.cs__marker { margin-top: 40px; }

/* Outlined numeral: the stroke is the only paint, so it reads as a marker
   rather than a heading competing with the section titles. */
.cs__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 132px;
  line-height: .88;
  color: transparent;
  -webkit-text-stroke: 1px var(--acc2);
}

.cs__big {
  margin-top: 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 1px;
  line-height: 24px;
  text-transform: uppercase;
}

.cs__rail { display: flex; flex-direction: column; gap: 2px; margin: 34px 0 0; padding: 0; list-style: none; }

.cs__row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 9px 0 9px 14px;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
}
.cs__row[aria-current="true"] { background: linear-gradient(90deg, color-mix(in srgb, var(--acc) 9%, transparent), transparent 70%); }

.cs__bar { position: absolute; left: 0; top: 6px; bottom: 6px; width: 2px; background: var(--line-soft); }
.cs__row[aria-current="true"] .cs__bar { background: var(--acc); }

.cs__n { font-family: var(--font-mono); font-size: 12px; color: #6a7375; }
.cs__t { font-family: var(--font-mono); font-size: 13px; letter-spacing: 1.5px; color: var(--txt-4); }
.cs__row:hover .cs__t { color: var(--txt-2); }
.cs__row[aria-current="true"] .cs__n { color: var(--acc); }
.cs__row[aria-current="true"] .cs__t { color: var(--txt); }

.cs__progress { display: flex; flex-direction: column-reverse; gap: 8px; text-align: right; margin-top: auto; font-family: var(--font-mono); font-size: 12px; color: var(--txt-4); }
.cs__track { display: block; width: 100%; height: 2px; background: var(--line-soft); }
.cs__fill { display: block; width: 0; height: 2px; background: var(--acc2); }

.cs__body { padding: 56px; }

/* Generous vertical rhythm: sections are told apart by the space around
   them and by the rail; only the framing sections add a rule (--ruled). */
.cs__sec { max-width: 1200px; padding: 90px 0; scroll-margin-top: 140px; }
/* A clicked section lands 140px from the top. The last one is short, so it
   is given the rest of the viewport (less the body's bottom padding):
   the page can scroll it that far, and the sticky rail is not pushed up by
   the end of the dossier. Side by side only — stacked, the rail scrolls. */
@media (min-width: 1181px) {
  .cs__body > .cs__sec:last-child { min-height: calc(100vh - 192px); }
}
/* The overview stacks four groups — dossier tags, title and tagline, meta,
   carousel — on one 24px rhythm; the title and tagline pair up tighter. */
.cs__sec--hero { display: flex; flex-direction: column; gap: 24px; padding-top: 0; }
.cs__intro { display: flex; flex-direction: column; gap: 16px; }
.cs__sec--hero .lead { max-width: none; }

/* The dossier column is already capped by .cs__sec, so its text runs to
   that width. .log keeps its 860px measure on the other pages. */
.cs__body .log { max-width: none; }
/* The dossier block carried a 34px top margin from the old layout, which
   pushed the right column below the rail. */
.cs__sec--hero .dossier { margin-top: 0; }

.cs__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 60px;
  line-height: 1;
  text-transform: uppercase;
  text-wrap: balance;
}
.cs__title em { font-style: normal; color: var(--acc); }

/* Equal columns, each opened by an --acc2 rule; the 220px basis lets them
   wrap onto new rows before a long value like the stack gets squeezed. */
.cs__meta { display: flex; flex-wrap: wrap; gap: 24px 0; margin: 0; }
.cs__meta > div {
  flex: 1 1 220px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  padding: 0 16px;
  border-left: 2px solid var(--acc2);
}
.cs__meta dt { font-family: var(--font-mono); font-size: 12px; font-weight: 400; letter-spacing: 2px; line-height: 16px; color: var(--txt-4); }
.cs__meta .cs__role { color: var(--acc2); }
.cs__meta dd { margin: 0; font-family: var(--font-body); font-size: 15px; font-weight: 500; line-height: 18px; color: var(--txt); }

.cs__h { margin: 0 0 22px; font-family: var(--font-mono); font-size: 13px; font-weight: 400; letter-spacing: 3px; color: var(--acc); }

.cs__p { margin: 24px 0 0; font-size: 17px; font-weight: 400; line-height: 1.75; color: var(--txt-3); }

/* Section headline in two tones: the claim in --txt, its turn in --acc on its own line. */
.cs__head {
  margin: 0;
  max-width: 900px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 40px;
  line-height: 48px;
  letter-spacing: -.01em;
  color: var(--txt);
}
.cs__head em { display: block; font-style: normal; color: var(--acc); }
.cs__head--warn em { color: var(--acc2); }
.cs__head--plain em { color: inherit; }

/* The framing sections (contexte, problématique) are closed by a soft rule. */
.cs__sec--ruled { border-bottom: 1px solid var(--line-soft); }

/* Shared label: mono caps on a hairline. */
.spec dt,
.pains__h,
.shift__k {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 2px;
  line-height: 16px;
  color: var(--txt-4);
}

/* 01 Contexte: text on the left, spec sheet on the right. */
.ctx { display: flex; align-items: flex-start; gap: 80px; }
.ctx__text { flex: 1; min-width: 0; }
.ctx__text .cs__head + .cs__p { margin-top: 24px; }
.ctx__text .cs__p { line-height: 30px; }

.spec { flex: 0 0 340px; margin: 0; }
.spec > div { display: flex; flex-direction: column; gap: 6px; padding: 16px 0; border-bottom: 1px solid var(--line-soft); }
.spec > div:first-child { padding-top: 0; }
.spec > div:last-child { border-bottom: 0; }
.spec dd { margin: 0; font-size: 16px; line-height: 24px; color: var(--txt-2); }
.spec .spec__acc { color: var(--acc); }

/* 02 Problématique: pain points by audience, then the shift of role. */
.pains { display: flex; gap: 48px; margin-top: 44px; }
.pains__col { flex: 1; min-width: 0; }
.pains__h { margin: 0; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.pains__list { margin: 0; padding: 0; list-style: none; }
.pains__list li {
  position: relative;
  padding: 18px 0 18px 32px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 15px;
  line-height: 23px;
  color: var(--txt-3);
}
.pains__list li::before {
  content: '✕';
  position: absolute;
  top: 18px;
  left: 0;
  font-family: var(--font-mono);
  font-size: 16px;
  line-height: 24px;
  color: var(--acc2);
}
.pains__list li:last-child { border-bottom: 0; }
.pains__list strong { display: block; margin-bottom: 4px; font-size: 16px; font-weight: 500; line-height: 24px; color: var(--txt); }

.shift { display: flex; margin-top: 44px; border: 1px solid var(--line); }
.shift__from,
.shift__to { display: flex; flex: 1; flex-direction: column; gap: 12px; min-width: 0; padding: 28px; }
.shift__v { font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 30px; }
.shift__from .shift__v { color: var(--txt-4); text-decoration-thickness: 1px; }
.shift__to .shift__v { color: var(--acc); }
.shift__arrow {
  display: flex;
  flex: 0 0 100px;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 22px;
  color: var(--acc);
}
.shift__tags { margin-top: 6px; }

/* 03 Objectifs: each row reads problem → objective, on fixed lanes. */
.goals { margin-top: 36px; }
.goals__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 32px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  padding: 30px 0;
  border-bottom: 1px solid var(--line);
}
.goals__row:last-child { border-bottom: 0; }
.goals__pb { position: relative; margin: 0; padding-left: 26px; font-size: 15px; line-height: 28px; color: var(--txt-3); }
.goals__pb::before { content: '✕'; position: absolute; left: 0; font-family: var(--font-mono); color: var(--acc2); }
.goals__to { font-family: var(--font-mono); font-size: 18px; line-height: 28px; color: var(--acc); }
.goals__t { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 28px; color: var(--txt); }
/* The verb carries the accent; the rest of the objective stays in --txt. */
.goals__t em { font-style: normal; color: var(--acc); }
.goals__d { margin: 8px 0 0; font-size: 15px; line-height: 23px; color: var(--txt-3); }

/* 04 Processus: one row per method — outlined numeral, name, finding, key figure. */
.methods { margin: 44px 0 0; padding: 0; list-style: none; }
.methods__row {
  display: grid;
  grid-template-columns: 120px 320px minmax(0, 1fr) 160px;
  gap: 32px;
  align-items: start;
  padding: 32px 0;
  border-bottom: 1px solid var(--line);
}
.methods__row:last-child { border-bottom: 0; }
.methods__n {
  font-family: var(--font-display);
  font-size: 72px;
  font-weight: 700;
  line-height: 64px;
  color: transparent;
  -webkit-text-stroke: 1px var(--acc2);
}
.methods__name { display: flex; flex-direction: column; gap: 8px; }
.methods__t { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 30px; color: var(--txt); }
.methods__k,
.methods__stat span,
.call__k {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  line-height: 16px;
  color: var(--txt-4);
}
.methods__k,
.call__k { letter-spacing: 2px; }
.methods__d { margin: 0; font-size: 17px; line-height: 28px; color: var(--txt-3); }
.methods__stat { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; margin: 0; text-align: right; }
.methods__stat strong { font-family: var(--font-display); font-size: 46px; font-weight: 700; line-height: 46px; color: var(--acc); }
.methods__stat span { letter-spacing: 1px; }

/* 05 Décisions clés: each call reads situation → options → trade-off. */
.calls { display: flex; flex-direction: column; gap: 40px; margin-top: 44px; }
.call { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.call__n { font-family: var(--font-display); font-size: 72px; font-weight: 700; line-height: 64px; color: var(--acc); }
.call__t { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 30px; color: var(--txt); }
.call__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-self: stretch; }
.call__col { display: flex; flex-direction: column; gap: 10px; padding: 24px 28px; }
.call__col + .call__col { border-left: 1px solid var(--line-soft); }
.call__k { margin: 0; }
.call__k--warn { color: var(--acc2); }
.call__p { margin: 0; font-size: 15px; line-height: 23px; color: var(--txt-3); }
.call__opts { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.call__opt { position: relative; padding-left: 24px; font-size: 15px; line-height: 23px; }
.call__opt::before { position: absolute; left: 0; width: 14px; font-family: var(--font-mono); font-size: 14px; }
.call__opt--out { color: var(--txt-4); }
.call__opt--out::before { content: '✕'; }
.call__opt--out s { text-decoration-thickness: 1px; }
.call__opt--in { font-weight: 500; color: var(--txt); }
.call__opt--in::before { content: '✓'; color: var(--acc); }


/* 06 Solution — shared mono label for the tags and captions below. */
.compare__tag,
.compare__k,
.port__k {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 2px;
  line-height: 16px;
  color: var(--txt-4);
}

/* Before / after: two full-page captures in fixed-height panes. site.js
   moves both images by the same fraction of their own overflow, so the
   pages reach their bottom together whatever their length. */
.compare { margin: 50px 0 0; }
.compare__panes { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
.compare__pane {
  position: relative;
  /* The captures are 1920px-wide pages: a 16:9 window shows exactly what a
     1920×1080 screen shows, so the scroll reads like the real page. */
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--line-soft);
  background: var(--bg-panel);
}
.compare__pane--after { border-color: var(--line); }
.compare__pane img { display: block; width: 100%; height: auto; will-change: transform; }
/* Live pane and sticky nav laid over the "after" capture; site.js sizes and
   places them from their data-* coordinates. */
.compare__pane .compare__layer { position: absolute; top: 0; left: 0; will-change: top; }
/* The sticky nav drops in from above once the site header has scrolled out. */
.compare__pane .compare__nav { transform: translateY(-100%); transition: transform .18s ease-out; }
.compare__pane .compare__nav.is-shown { transform: none; }
/* Bottom corner: the top edge belongs to the sticky nav. */
.compare__tag {
  position: absolute;
  bottom: 18px;
  left: 20px;
  z-index: 1;
  padding: 6px 10px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--txt-3);
}
.compare__tag--after { border-color: var(--acc); background: var(--acc); color: var(--bg); }

.compare__bar { display: flex; align-items: center; gap: 14px; margin-top: 18px; }
.compare__play {
  display: flex;
  flex: 0 0 28px;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0;
  border: 1px solid var(--acc);
  background: transparent;
}
.compare__icon { width: 10px; height: 12px; fill: var(--acc); }
.compare__play[aria-pressed="true"] .compare__icon--play,
.compare__play[aria-pressed="false"] .compare__icon--pause { display: none; }

/* The scrubber doubles as the progress bar: a hairline filled up to the thumb. */
.compare__range {
  flex: 1;
  min-width: 0;
  height: 16px;
  margin: 0;
  background: transparent;
  appearance: none;
  -webkit-appearance: none;
  --p: 0%;
}
.compare__range::-webkit-slider-runnable-track {
  height: 2px;
  background: linear-gradient(90deg, var(--acc) var(--p), var(--line-soft) var(--p));
}
.compare__range::-moz-range-track {
  height: 2px;
  background: linear-gradient(90deg, var(--acc) var(--p), var(--line-soft) var(--p));
}
.compare__range::-webkit-slider-thumb {
  width: 10px;
  height: 10px;
  margin-top: -4px;
  border: 0;
  border-radius: 0;
  background: var(--acc);
  -webkit-appearance: none;
}
.compare__range::-moz-range-thumb { width: 10px; height: 10px; border: 0; border-radius: 0; background: var(--acc); }

.compare__cap { display: flex; justify-content: space-between; gap: 40px; margin-top: 18px; }
.compare__cap > span:last-child { flex: 0 1 600px; font-size: 15px; line-height: 23px; color: var(--txt-3); }

/* One loop per feature, alternating sides. */
.feats { display: flex; flex-direction: column; gap: 50px; margin-top: 90px; }
.feat { display: grid; grid-template-columns: minmax(0, 60fr) minmax(0, 40fr); gap: 64px; align-items: center; }
/* Flipped, the columns swap too: the media keeps the wide one. */
.feat--flip { grid-template-columns: minmax(0, 40fr) minmax(0, 60fr); }
.feat--flip .feat__media { order: 2; }
.feat__media {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  background: var(--bg-panel);
}
.feat__media video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Corner brackets, as on the Paper frame. */
.feat__media::before,
.feat__media::after { content: ''; position: absolute; width: 18px; height: 18px; pointer-events: none; }
.feat__media::before { top: -1px; left: -1px; border-top: 2px solid var(--acc); border-left: 2px solid var(--acc); }
.feat__media::after { right: -1px; bottom: -1px; border-right: 2px solid var(--acc); border-bottom: 2px solid var(--acc); }
.feat__text { display: flex; flex-direction: column; gap: 14px; }
.feat__t { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 30px; color: var(--txt); }
.feat__d { margin: 0; font-size: 15px; line-height: 23px; color: var(--txt-3); }

/* S·01 — the live pane builds itself brick by brick, the camera close on each
   new block, then fades from one place to the next over a blurred photo of
   each. The scene is authored on a 900px square stage (the card at its real
   350px width, with the Affluences tokens) that site.js scales to the frame.
   data-sc lists the compositions an element belongs to (the Figma frames S1,
   S2, S4, S5); the .sc<n> class on .lp picks the current one. */
.lp {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  --lp-ease: cubic-bezier(.2, .8, .2, 1);
}
.lp::before,
.lp::after { z-index: 3; }

.lp__bgs { position: absolute; inset: 0; overflow: hidden; }
/* The photos come pre-blurred and graded; a live blur this size is too heavy
   to paint. */
.lp__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s ease;
}

.lp__stage { position: absolute; top: 0; left: 0; width: 900px; height: 900px; transform-origin: 0 0; }
/* The camera: close on the photo, down with each new brick, out to the whole
   card, then it keeps the card centred as its height changes. */
.lp__cam { position: absolute; inset: 0; transform-origin: 0 0; transition: transform .9s cubic-bezier(.65, 0, .35, 1); }
.lp__cam.is-wide { transition-duration: 1.2s; }

/* The card lands with its photo, and fades out and back in to change place. */
.lp__card {
  position: absolute;
  top: 63px;
  left: 275px;
  box-sizing: border-box;
  width: 350px;
  overflow: hidden;
  border: 1px solid #e2ecf1;
  border-radius: 12px;
  background: #fff;
  opacity: 0;
  transform: translateY(-40px);
  box-shadow: 0 34px 44px rgb(0 0 0 / 35%);
  transition: transform .62s cubic-bezier(.34, 1.56, .64, 1), opacity .2s ease, box-shadow .42s ease .26s;
  font-family: 'Nunito', sans-serif;
  color: #13323d;
  text-align: center;
}
.lp__card.is-on { opacity: 1; transform: none; box-shadow: 0 15px 25px rgb(0 0 0 / 15%), 0 5px 10px rgb(0 0 0 / 5%); }
.lp.is-snap .lp__card.is-on { transition: opacity .7s ease; }
.lp__card.is-on.is-dim,
.lp.is-snap .lp__card.is-on.is-dim { opacity: 0; transition: opacity .26s ease; }
/* Between places the blocks switch unseen, without animating. */
.lp.is-snap .lp__cam,
.lp.is-snap .lp__card *,
.lp.is-reset,
.lp.is-reset * { transition: none; }

/* A brick: its row opens and the piece drops in from above, overshoots a
   little and snaps into place. The spacer above it (the auto layout gap)
   opens with it. */
.lp__brick { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .48s var(--lp-ease); }
.lp__slot { min-height: 0; }
.lp__slot::before { content: ''; display: block; height: 24px; }
.lp__piece {
  position: relative;
  opacity: 0;
  transform: translateY(-44px);
  transition: transform .6s cubic-bezier(.34, 1.56, .64, 1) .06s, opacity .18s ease .06s;
}
/* A fold: a part of a block (a row, a link, a button) that comes and goes. */
.lp__fold { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .48s var(--lp-ease), opacity .25s ease; }
.lp__fold > * { min-height: 0; overflow: hidden; }
.lp__fold--row > *::before { content: ''; display: block; margin: 8px 0; border-top: 1px solid #e2ecf1; }
.lp__fold--link > *::before { content: ''; display: block; height: 16px; }
.lp__fold--btn > *::after { content: ''; display: block; height: 24px; }
/* A stack: variants sharing one cell, crossfading. */
.lp__stack { display: grid; }
.lp__stack > * { grid-area: 1 / 1; opacity: 0; transition: opacity .35s ease; }

.lp.sc1 .lp__brick.is-on[data-sc~="1"],
.lp.sc2 .lp__brick.is-on[data-sc~="2"],
.lp.sc4 .lp__brick.is-on[data-sc~="4"],
.lp.sc5 .lp__brick.is-on[data-sc~="5"],
.lp.sc1 .lp__fold[data-sc~="1"],
.lp.sc2 .lp__fold[data-sc~="2"],
.lp.sc4 .lp__fold[data-sc~="4"],
.lp.sc5 .lp__fold[data-sc~="5"] { grid-template-rows: 1fr; }
.lp.sc1 .lp__brick.is-on[data-sc~="1"] > .lp__slot > .lp__piece,
.lp.sc2 .lp__brick.is-on[data-sc~="2"] > .lp__slot > .lp__piece,
.lp.sc4 .lp__brick.is-on[data-sc~="4"] > .lp__slot > .lp__piece,
.lp.sc5 .lp__brick.is-on[data-sc~="5"] > .lp__slot > .lp__piece { opacity: 1; transform: none; }
.lp.sc1 .lp__fold[data-sc~="1"],
.lp.sc2 .lp__fold[data-sc~="2"],
.lp.sc4 .lp__fold[data-sc~="4"],
.lp.sc5 .lp__fold[data-sc~="5"],
.lp.sc1 .lp__stack > [data-sc~="1"],
.lp.sc2 .lp__stack > [data-sc~="2"],
.lp.sc4 .lp__stack > [data-sc~="4"],
.lp.sc5 .lp__stack > [data-sc~="5"],
.lp.sc1 .lp__bg[data-sc~="1"],
.lp.sc2 .lp__bg[data-sc~="2"],
.lp.sc4 .lp__bg[data-sc~="4"],
.lp.sc5 .lp__bg[data-sc~="5"] { opacity: 1; }

/* The card's content, from the Figma frames. */
.lp__card p { margin: 0; }
.lp__card img { display: block; }
.lp__thumb img { width: 100%; height: 197px; object-fit: cover; }
.lp__content { display: flex; flex-direction: column; padding: 0 24px; }

.lp__status p { justify-self: center; font-size: 20px; font-weight: 500; line-height: 24px; white-space: nowrap; color: #49626a; }
.lp__status b { font-weight: 700; }
.lp--ok { color: #00806a; }
.lp--warn { color: #a85d00; }

.lp__head { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 20px; font-weight: 700; line-height: 24px; color: #1d4b5c; }
.lp__head img { width: 24px; height: 24px; }

.lp__visual { margin-top: 16px; }
.lp__visual > div { display: flex; align-items: center; justify-content: center; gap: 24px; padding: 8px 0; }
.lp__chart { position: relative; flex-shrink: 0; width: 72px; height: 60px; }
.lp__data { display: flex; flex-direction: column; align-items: flex-start; white-space: nowrap; }
.lp__data > span { display: flex; align-items: baseline; gap: 4px; }
.lp__big,
.lp__mid,
.lp__grad {
  background: linear-gradient(85deg, #0d6b91 0%, #159fea 85%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.lp__grad { font-size: 16px; font-weight: 700; line-height: 24px; }
/* The product's display face is Museo 700; Nunito 800 stands in. */
.lp__big { font-family: 'Museo', 'Nunito', sans-serif; font-size: 32px; font-weight: 800; line-height: 32px; }
.lp__mid { font-family: 'Museo', 'Nunito', sans-serif; font-size: 20px; font-weight: 800; line-height: 20px; }

/* Waiting-time gauge, assembled from its Figma layers. */
.lp__wait img { position: absolute; }
.lp__w1 { top: 14.44px; left: 20.21px; width: 31.13px; height: 31.13px; }
.lp__w2 { top: 6.77px; left: 12.54px; width: 46.92px; height: 46.92px; }
.lp__w3 { top: 0; left: 36px; width: 30px; height: 60px; }
.lp__w4 { top: 13.09px; left: 19.09px; width: 34.29px; height: 34.29px; }
.lp__w5 { top: 32.2px; left: 31.83px; width: 9.61px; height: 10.94px; transform: rotate(180deg); }

.lp__error {
  padding: 24px 8px;
  border: 1px solid #b5c3c9;
  border-radius: 12px;
  background: #e0f6ff;
  font-size: 16px;
  font-weight: 500;
  line-height: 24px;
  color: #1d4b5c;
}

.lp__zone { margin-top: 16px; padding: 16px; border: 1px solid #e2ecf1; border-radius: 12px; background: #eef8fa; }
.lp__row p { display: flex; align-items: center; gap: 8px; }
.lp__row span { flex: 1; font-size: 16px; font-weight: 600; line-height: 24px; text-align: left; color: #427487; }
.lp__row img { width: 24px; height: 24px; }
.lp__row b { width: 51px; font-size: 16px; font-weight: 700; line-height: 24px; text-align: right; }

.lp__link { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 16px; font-weight: 700; line-height: 24px; color: #0d6b91; }
.lp__link img { width: 24px; height: 24px; }

.lp__btn p {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 52px;
  border-radius: 32px;
  background: linear-gradient(68deg, #0d6b91 0%, #159fea 85%);
  box-shadow: 0 4px 8px rgb(0 0 0 / 15%), 0 2px 4px rgb(0 0 0 / 12%);
  font-size: 16px;
  font-weight: 700;
  line-height: 24px;
  color: #fff;
}
.lp__btn img { width: 24px; height: 24px; }

/* Pause, bottom left: the loop runs on its own, so the button only shows on
   hover or keyboard focus — and stays once paused, so the loop can be
   resumed. Touch screens have no hover: there it always shows. */
.lp__bar { position: absolute; bottom: 18px; left: 20px; z-index: 2; opacity: 0; transition: opacity .2s ease; }
.lp:hover .lp__bar,
.lp:focus-within .lp__bar,
.lp__bar:has([aria-pressed="false"]) { opacity: 1; }
@media (hover: none) {
  .lp__bar { opacity: 1; }
}
/* Over the photo, the icon alone: no frame around it. */
.lp__bar .compare__play { width: 28px; border: 0; }

/* S·02 — the forecasts user flow, after the three 680px square frames of the
   Figma section: S1 the wide shot, S2 the forecasts of the live pane at
   scale 1, a click on « Voir toutes les prévisions », S3 the modal over the
   blurred photo. The camera works in S2's coordinates: the S1 capture is laid
   out 1/0.6634 larger (its live pane is 232px wide, 350px in S2) so both
   live panes line up, and the zoom crossfades from one capture to the other.
   The stage is the 680px frame, scaled to the media by site.js; the cursor
   sits outside the camera so it keeps its size. */
.pv { aspect-ratio: 1 / 1; overflow: hidden; background: #fff; }
.pv::before,
.pv::after { z-index: 3; }
.pv__stage { position: absolute; top: 0; left: 0; width: 680px; height: 680px; overflow: hidden; transform-origin: 0 0; }
.pv__cam { position: absolute; inset: 0; transform-origin: 0 0; transition: transform 1.3s cubic-bezier(.65, 0, .35, 1); }
.pv__s1,
.pv__s2 { position: absolute; display: block; max-width: none; }
.pv__s1 { top: -288.56px; left: -399.01px; width: 1024.98px; height: 1024.98px; }
.pv__s2 { top: 0; left: 0; width: 680px; height: 680px; opacity: 0; transition: opacity .6s ease .45s; }
.pv.is-s2 .pv__s2 { opacity: 1; }
/* The click: a ring spreads from under the pointer. */
.pv__ring {
  position: absolute;
  top: 446px;
  left: 294px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(13, 107, 145, .28);
  opacity: 0;
  pointer-events: none;
}
.pv.is-click .pv__ring { animation: pv-ring .6s ease-out; }
@keyframes pv-ring {
  from { opacity: 1; transform: scale(.2); }
  to { opacity: 0; transform: scale(1.8); }
}
.pv__cursor {
  position: absolute;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .25));
  transition: opacity .3s ease, transform .8s cubic-bezier(.45, 0, .2, 1);
}
.pv__cursor svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform-origin: 21% 12%; transition: transform .12s ease; }
/* The hand is drawn so its fingertip lands where the arrow's tip was. */
.pv__cursor .pv__hand { left: -8.5px; transform-origin: 44% 12%; }
.pv__cursor .pv__hand,
.pv.is-hand .pv__cursor .pv__arrow { display: none; }
.pv.is-hand .pv__cursor .pv__hand { display: block; }
.pv.is-cursor .pv__cursor { opacity: 1; }
.pv.is-press .pv__cursor svg { transform: scale(.86); }
/* S3: the blurred photo (the Figma overlay, pre-rendered), then the modal. */
.pv__s3 { position: absolute; inset: 0; display: block; width: 680px; height: 680px; opacity: 0; transition: opacity .5s ease; }
.pv.is-s3 .pv__s3 { opacity: 1; }
.pv__modal {
  position: absolute;
  top: 120px;
  left: 40px;
  width: 600px;
  height: 440px;
  border-radius: 12px;
  opacity: 0;
  transform: translateY(16px) scale(.97);
  transition: opacity .4s ease, transform .5s cubic-bezier(.2, .8, .2, 1);
}
.pv.is-modal .pv__modal { opacity: 1; transform: none; }
.pv.is-reset .pv__cam,
.pv.is-reset .pv__cam *,
.pv.is-reset .pv__cursor { transition: none; }
.pv__bar { position: absolute; bottom: 18px; left: 20px; z-index: 2; opacity: 0; transition: opacity .2s ease; }
.pv:hover .pv__bar,
.pv:focus-within .pv__bar,
.pv__bar:has([aria-pressed="false"]) { opacity: 1; }
@media (hover: none) {
  .pv__bar { opacity: 1; }
}
.pv__bar .compare__play { width: 28px; border: 0; }

/* S·03 — the sticky navigation, after the Figma frames S1 to S3: the page
   scrolls, the anchor bar drops in once the site header is gone, a click on
   « Infos pratiques » scrolls to that section. The window is a 1078px square
   of the 1920px page (from x 200: the left column and the tabs), shown on the
   680px stage; site.js moves the page, the bar and the cursor frame by frame
   and scales the stage to the media. The cursor sits outside the window so
   it keeps its size. */
.ns { aspect-ratio: 1 / 1; overflow: hidden; background: #fff; }
.ns::before,
.ns::after { z-index: 3; }
.ns__stage { position: absolute; top: 0; left: 0; width: 680px; height: 680px; overflow: hidden; transform-origin: 0 0; }
.ns__win { position: absolute; top: 0; left: 0; width: 1078px; height: 1078px; overflow: hidden; transform: scale(.63080); transform-origin: 0 0; }
.ns__page { position: absolute; top: 0; left: 0; display: block; width: 1078px; height: 2106px; max-width: none; will-change: transform; }
/* The anchor bar drops in once the site header has scrolled away. */
.ns__bar {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 1078px;
  height: 76px;
  max-width: none;
  transform: translateY(-100%);
  transition: transform .28s cubic-bezier(.2, .8, .2, 1);
}
.ns.is-bar .ns__bar { transform: none; }
/* The click: a ring spreads from under the pointer, on « Infos pratiques ». */
.ns__ring {
  position: absolute;
  top: 6.7px;
  left: 348px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(13, 107, 145, .28);
  opacity: 0;
  pointer-events: none;
}
.ns.is-click .ns__ring { animation: ns-ring .6s ease-out; }
@keyframes ns-ring {
  from { opacity: 1; transform: scale(.2); }
  to { opacity: 0; transform: scale(1.8); }
}
.ns__cursor {
  position: absolute;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .25));
}
.ns__cursor svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform-origin: 21% 12%; transition: transform .12s ease; }
/* The hand is drawn so its fingertip lands where the arrow's tip was. */
.ns__cursor .ns__hand { left: -8.5px; transform-origin: 44% 12%; }
.ns__cursor .ns__hand,
.ns.is-hand .ns__cursor .ns__arrow { display: none; }
.ns.is-hand .ns__cursor .ns__hand { display: block; }
.ns.is-press .ns__cursor svg { transform: scale(.86); }
/* White between two passes. */
.ns__veil { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; }
.ns__ctl { position: absolute; bottom: 18px; left: 20px; z-index: 2; opacity: 0; transition: opacity .2s ease; }
.ns:hover .ns__ctl,
.ns:focus-within .ns__ctl,
.ns__ctl:has([aria-pressed="false"]) { opacity: 1; }
@media (hover: none) {
  .ns__ctl { opacity: 1; }
}
.ns__ctl .compare__play { width: 28px; border: 0; }

/* Media zoom (initZoom): one media alone, full window, as on the Paper
   frame — title and close on top, the media as large as it fits below. */
[data-zoom] { cursor: zoom-in; }
.zoom__open {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  color: var(--txt);
}
.zoom__open svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.4; }
.zoom__open:hover { border-color: var(--acc); color: var(--acc); }
/* A click on the media is enough with a pointer: the button only shows when
   it gets keyboard focus, the one way in for keyboard users. */
.zoom__open:not(:focus-visible) {
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
}
.zoom__holder { border: 1px solid var(--line-soft); }
.feat--flip .zoom__holder { order: 2; }

html.is-zoom-open { overflow: hidden; }
.zoom {
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: #010202;
  color: var(--txt);
}
.zoom[open] { display: flex; flex-direction: column; }
.zoom::backdrop { background: #010202; }
.zoom__bar { display: flex; flex: 0 0 auto; align-items: center; gap: 16px; padding: 16px 24px; }
.zoom__t { flex: 1; margin: 0; font-family: var(--font-display); font-size: 16px; font-weight: 600; line-height: 20px; color: var(--txt); }
.zoom__close {
  display: flex;
  flex: 0 0 32px;
  align-items: center;
  justify-content: center;
  height: 32px;
  padding: 0;
  border: 1px solid var(--line);
  background: transparent;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--txt);
}
.zoom__close:hover { border-color: var(--acc); color: var(--acc); }
.zoom__stage {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 0 24px 20px;
  container-type: size;
  cursor: zoom-out;
}
/* The media fills what it can of the stage without cropping. */
.zoom__media { max-width: 100%; max-height: 100%; border: 1px solid var(--line-soft); cursor: default; }
img.zoom__media { width: auto; height: auto; object-fit: contain; }
/* Content zoom (the before/after): the pages at their full length, side by
   side, in a stage that scrolls instead of fitting. */
.zoom__stage--scroll { display: block; overflow-y: auto; container-type: normal; cursor: default; }
.zoom__pages { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; max-width: 1600px; margin: 0 auto; }
.zoom__page { position: relative; border: 1px solid var(--line-soft); }
.zoom__page img { display: block; width: 100%; height: auto; }
.zoom__page .compare__tag { top: 14px; bottom: auto; }
/* The carousel and the before/after carry the zoom button over their media. */
.carousel,
.compare { position: relative; }
.carousel__slide:not(.is-active) { pointer-events: none; }

/* A moved component keeps its own ratio (--zr, set by site.js): as wide as
   the stage allows, unless its height would overflow first. */
.zoom__stage .is-zoomed {
  width: min(100cqw, 100cqh * var(--zr, 1.7778));
  height: auto;
  max-height: none;
  aspect-ratio: var(--zr, 16 / 9);
}
.zoom__stage .feat__media::before,
.zoom__stage .feat__media::after,
.zoom__stage .zoom__open { display: none; }
.zoom__player { display: flex; flex: 0 0 auto; align-items: center; gap: 14px; margin: -20px 24px 20px; padding: 12px 16px; border: 1px solid var(--line-soft); border-top: 0; }
.zoom__player[hidden] { display: none; }
.zoom__time { font-family: var(--font-mono); font-size: 12px; line-height: 16px; color: var(--txt-3); }

/* Web → app: each card pairs a desktop capture with its mobile counterpart. */
.port { display: flex; flex-direction: column; gap: 40px; margin-top: 90px; }
.port__intro { display: flex; justify-content: space-between; align-items: flex-end; gap: 80px; }
.port__intro > div { display: flex; flex-shrink: 0; flex-direction: column; gap: 14px; }
.port__intro .feat__d { flex: 0 1 520px; }
.port__t { margin: 0; font-family: var(--font-display); font-size: 32px; font-weight: 600; line-height: 40px; letter-spacing: -.01em; color: var(--txt); }
.port__cards { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
.port__card { display: flex; flex-direction: column; gap: 28px; margin: 0; padding: 32px; border: 1px solid var(--line-soft); background: var(--bg-panel); }
.port__pair { display: flex; align-items: center; justify-content: center; gap: 16px; }
.port__shot { display: flex; flex: 1 1 0; flex-direction: column; align-items: center; gap: 10px; min-width: 0; }
.port__shot--app { flex: 0 0 38%; max-width: 220px; }
.port__shot img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 4px; }
.port__shot--app img { border-radius: 16px; }
.port__k { white-space: nowrap; }
.port__k--acc { color: var(--acc); }
.port__arrow { flex: 0 0 auto; font-family: var(--font-mono); font-size: 18px; color: var(--acc); }
.port__cap { display: flex; flex-direction: column; gap: 8px; padding-top: 24px; border-top: 1px solid var(--line-soft); }
.port__cap strong { font-family: var(--font-display); font-size: 20px; font-weight: 600; line-height: 26px; color: var(--txt); }
.port__cap span { font-size: 15px; line-height: 23px; color: var(--txt-3); }


/* 07 Résultats: a scorecard — each goal of section 03, its results, and how
   far the measure can be trusted (a three-segment gauge). Fixed 340px lanes
   left and right keep the three rows aligned. */
.score { margin-top: 50px; }
.score__head,
.score__row { display: grid; grid-template-columns: 340px minmax(0, 1fr) 340px; }
.score__head { padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.score__head span,
.score__id,
.score__k {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 2px;
  line-height: 16px;
  color: var(--txt-4);
}
.score__row { align-items: start; padding: 36px 0; border-bottom: 1px solid var(--line-soft); }
.score__row:last-child { border-bottom: 0; }
.score__goal { display: flex; flex-direction: column; gap: 8px; padding-right: 40px; }
.score__t { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 600; line-height: 28px; color: var(--txt); }

.score__kpis { display: flex; flex-wrap: wrap; gap: 24px 48px; }
.score__kpis--tight { column-gap: 32px; }
.score__kpis--list { flex-direction: column; gap: 8px; padding-right: 40px; }
.score__kpi { display: flex; flex-direction: column; gap: 6px; margin: 0; }
.score__kpi strong { font-family: var(--font-display); font-size: 46px; font-weight: 700; line-height: 46px; color: var(--acc); white-space: nowrap; }
.score__kpi span { font-size: 15px; line-height: 22px; color: var(--txt-3); }
.score__checks { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 0; list-style: none; }
.score__checks li { position: relative; padding-left: 24px; font-size: 15px; font-weight: 500; line-height: 23px; color: var(--txt); }
.score__checks li::before { content: '✓'; position: absolute; left: 0; width: 14px; font-family: var(--font-mono); font-size: 14px; color: var(--acc); }
.score__quote { margin: 0; padding-left: 24px; font-size: 15px; line-height: 23px; color: var(--txt-2); }

.score__trust { display: flex; flex-direction: column; gap: 10px; }
.score__meter { display: flex; gap: 4px; }
.score__meter i { width: 28px; height: 6px; border: 1px solid var(--line); }
.score__meter i.is-on { border-color: var(--acc); background: var(--acc); }
.score__trust .score__k { color: var(--acc); }
.score__trust--warn .score__meter i { border-color: var(--acc2); }
.score__trust--warn .score__k { color: var(--acc2); }
.score__d { margin: 0; font-size: 15px; line-height: 23px; color: var(--txt-3); }

/* 08 Retours d'expérience: the title holds still on the left while the
   numbered lessons scroll by on the right. */
.lessons { display: flex; align-items: flex-start; gap: 80px; }
.lessons__aside { flex: 0 0 360px; }
.lessons__list { flex: 1; min-width: 0; margin: 0; padding: 0; list-style: none; }
/* A hairline between lessons only, none above the first or under the last. */
.lessons__row { display: flex; gap: 40px; padding: 36px 0; }
.lessons__row + .lessons__row { border-top: 1px solid var(--line-soft); }
.lessons__n { flex: 0 0 110px; font-family: var(--font-display); font-size: 56px; font-weight: 700; line-height: 56px; color: var(--acc); }
.lessons__body { display: flex; flex: 1; flex-direction: column; gap: 10px; min-width: 0; }
.lessons__t { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 30px; color: var(--txt); }
.lessons__d { margin: 0; font-size: 15px; line-height: 24px; color: var(--txt-3); }

/* Past 1920px the fixed cap leaves a void on the right, so the column takes
   more width rather than detaching from the rail. 1600px keeps the 2400px
   screenshots from being upscaled. */
@media (min-width: 1921px) {
  .cs__sec { max-width: 1600px; }
}

/* Under 1180px the rail turns into a sticky strip above the reading column:
   the numeral and the gauge need width the page no longer has. */
@media (max-width: 1180px) {
  .cs { grid-template-columns: 1fr; }

  .cs__nav {
    min-width: 0; /* grid item: without this it takes its content's width */
    top: 84px;
    z-index: 5;
    flex-direction: row;
    align-items: center;
    gap: 20px;
    height: auto;
    padding: 14px 40px;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: blur(6px);
  }
  .cs__marker, .cs__progress { display: none; }
  .cs__nav .back-link { flex-shrink: 0; }

  /* flex + min-width:0 so the strip scrolls inside itself instead of
     widening the page once a dossier has many sections. */
  .cs__rail { flex: 1; min-width: 0; flex-direction: row; gap: 6px; margin: 0; overflow-x: auto; scrollbar-width: none; }
  .cs__rail::-webkit-scrollbar { height: 0; }
  .cs__row { width: auto; padding: 8px 12px; white-space: nowrap; }
  .cs__bar { top: auto; bottom: 0; left: 12px; right: 12px; width: auto; height: 2px; }

  .cs__body { padding: 0 40px 24px; }
  .cs__sec { padding: 64px 0; scroll-margin-top: 150px; }
  .cs__sec--hero { padding-top: 56px; }
  .cs__title { font-size: 44px; }
  .cs__head { font-size: 34px; line-height: 42px; }
}

/* The spec sheet needs the full 1200px column; below it (≈1500px viewport,
   rail included) it moves under the text. */
@media (max-width: 1500px) {
  .ctx { flex-direction: column; gap: 40px; }
  .spec { flex-basis: auto; width: 100%; }
  /* Four lanes no longer fit: the finding moves under the method name. */
  .methods__row { grid-template-columns: 96px minmax(0, 1fr) 120px; column-gap: 28px; row-gap: 14px; }
  .methods__name { grid-column: 2; }
  .methods__d { grid-column: 2; grid-row: 2; }
  .methods__stat { grid-column: 3; grid-row: 1 / span 2; }
  .methods__n { font-size: 60px; line-height: 56px; }
  /* Side by side, each capture would drop under 200px wide. */
  .port__cards { grid-template-columns: 1fr; }
  /* Two fixed 340px lanes would leave the results too little room: the
     trust lane moves under the results. */
  .score__head { grid-template-columns: 260px minmax(0, 1fr); }
  .score__head span:last-child { display: none; }
  .score__row { grid-template-columns: 260px minmax(0, 1fr); row-gap: 24px; }
  .score__trust { grid-column: 2; }
  /* Beside a 360px title the lessons would drop under 480px: the title
     goes on top, as in the other sections. */
  .lessons { flex-direction: column; gap: 44px; }
  .lessons__aside { flex-basis: auto; }
}

@media (max-width: 1080px) {
  .call__grid { grid-template-columns: 1fr; }
  .call__col { padding: 18px 0; }
  .call__col + .call__col { border-left: 0; border-top: 1px solid var(--line-soft); }

  /* Solution: text goes under each loop, and the web → app cards stack. */
  .feat { grid-template-columns: 1fr; gap: 28px; }
  .feat--flip .feat__media { order: 0; }
  .feat__media:not(.is-zoomed) { justify-self: center; width: 100%; max-width: 560px; }
  .port__intro { flex-direction: column; align-items: flex-start; gap: 16px; }
  .port__intro .feat__d { flex-basis: auto; }

  /* Scorecard: the three lanes stack inside each row; the column heads
     no longer sit over anything, so they go. */
  .score__head { display: none; }
  .score { border-top: 1px solid var(--line); }
  .score__row { grid-template-columns: 1fr; row-gap: 20px; }
  .score__trust { grid-column: auto; }
  .score__goal, .score__kpis { padding-right: 0; }
}

@media (max-width: 720px) {
  .cs__nav { padding: 12px 22px; }
  .cs__body { padding: 0 22px 24px; }
  .cs__sec { padding: 48px 0; }
  .cs__title { font-size: 32px; }
  .cs__head { font-size: 26px; line-height: 32px; }
  .cs__meta { row-gap: 20px; }

  .pains { flex-direction: column; gap: 32px; margin-top: 32px; }
  .shift { flex-direction: column; margin-top: 32px; }
  .shift__from, .shift__to { padding: 22px; }
  .shift__arrow { display: none; }
  .shift__to { border-top: 1px solid var(--line); }
  .shift__v { font-size: 20px; line-height: 26px; }
  .goals__row { grid-template-columns: 1fr; gap: 12px; padding: 24px 0; }
  .goals__to { display: none; }
  .goals__t { font-size: 20px; line-height: 26px; }

  .methods { margin-top: 32px; }
  .methods__row { grid-template-columns: minmax(0, 1fr) auto; row-gap: 12px; padding: 24px 0; }
  .methods__n { grid-column: 1; grid-row: 1; font-size: 48px; line-height: 44px; }
  .methods__stat { grid-column: 2; grid-row: 1; }
  .methods__stat strong { font-size: 34px; line-height: 36px; }
  .methods__name, .methods__d { grid-column: 1 / -1; grid-row: auto; }
  .methods__t, .call__t { font-size: 20px; line-height: 26px; }

  .calls { gap: 32px; margin-top: 32px; }
  .call__n { font-size: 48px; line-height: 44px; }

  .compare__panes { grid-template-columns: 1fr; }
  .compare__cap { flex-direction: column; gap: 10px; }
  .lessons { gap: 32px; }
  .lessons__row { gap: 20px; padding: 28px 0; }
  .lessons__n { flex-basis: 56px; font-size: 40px; line-height: 44px; }
  .lessons__t { font-size: 20px; line-height: 26px; }
  .feats, .port { margin-top: 64px; }
  .feat__t { font-size: 20px; line-height: 26px; }
  .port__t { font-size: 26px; line-height: 32px; }
  .port__card { padding: 20px; }
  .port__k { white-space: normal; text-align: center; }
}

.page-nav { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.page-nav a { padding: 36px 60px; font-family: var(--font-mono); font-size: 14px; }
.page-nav a:hover { color: var(--acc); background: rgba(0, 255, 213, .04); }
.page-nav a:first-child { border-right: 1px solid var(--line); color: var(--txt-4); }
.page-nav a:last-child { text-align: right; color: var(--txt); }
/* A single link (no next mission yet): one full-width row. */
.page-nav:has(> a:only-child) { grid-template-columns: 1fr; }
.page-nav a:only-child { border-right: 0; text-align: left; }

/* ---------- 10. CTA ---------- */

.cta {
  position: relative;
  overflow: hidden;
  padding: 70px 60px;
  text-align: center;
  background-image:
    linear-gradient(rgba(255, 255, 255, .045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .045) 1px, transparent 1px),
    radial-gradient(circle at 50% 120%, rgba(0, 255, 213, .1), transparent 60%);
  background-size: 48px 48px, 48px 48px, 100% 100%;
}
.cta--tight { padding: 60px; }
.cta--tall {
  padding: 90px 60px;
  background-image:
    linear-gradient(rgba(255, 255, 255, .045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .045) 1px, transparent 1px),
    radial-gradient(circle at 50% 120%, rgba(0, 255, 213, .12), transparent 60%);
}

.cta__eyebrow {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 5px;
  color: var(--txt-5);
  margin-bottom: 18px;
}

.cta__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 56px;
  text-transform: uppercase;
}
.cta__title em { font-style: normal; color: var(--acc2); animation: glowPulseAcc2 3s infinite; }

.cta__actions {
  display: flex;
  gap: 28px;
  justify-content: center;
  margin-top: 36px;
  font-family: var(--font-mono);
  font-size: 15px;
}

.btn-copy {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px;
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: 2px;
  border: 0;
  color: var(--txt);
  font-size: 15px;
}

.btn-linkedin {
  padding: 14px 30px;
  background: var(--acc);
  color: var(--bg);
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 2px;
  box-shadow: 0 0 24px color-mix(in srgb, var(--acc) 45%, transparent);
}
.btn-linkedin:hover {
  color: var(--bg);
  box-shadow: 0 0 40px color-mix(in srgb, var(--acc) 80%, transparent);
}

/* Keyboard focus needs to be visible even though the design is cursor-led. */
:focus-visible { outline: 2px solid var(--acc); outline-offset: 3px; }

/* ---------- 11. Responsive ---------- */

@media (max-width: 1200px) {
  .hud__hatch, .hud__pips { display: none; }
}

@media (max-width: 1080px) {
  .bio { grid-template-columns: 1fr; }
  .bio__text { border-right: 0; padding: 70px 40px; }
  .bio__photo { border-top: 1px solid var(--line); padding: 40px; }
  /* Pin the frame so the image percentage resolves against a known width;
     without it the frame falls back to the file’s intrinsic size. */
  .portrait { width: 402px; max-width: 100%; }
  .portrait img { width: 100%; height: auto; aspect-ratio: 380 / 420; }
  .sec { grid-template-columns: 1fr; }
  .sec__label { padding: 40px 40px 0; border-right: 0; }
  .sec__body { padding: 32px 40px 60px; }
  .kit { grid-template-columns: repeat(2, 1fr); gap: 32px; }
  .page-title { font-size: 60px; }
  .cta, .cta--tight, .cta--tall { padding: 60px 40px; }
  .cta__title { font-size: 44px; }

  .hero-sec { padding: 70px 40px 56px; }
  .hero-sec--flush { padding: 70px 40px 0; }
  .hero-sec .page-title { font-size: 60px; min-height: 60px; }
  .prj, .prj--flip { grid-template-columns: 1fr; }
  .prj__body { padding: 40px; border-right: 0 !important; }
  .prj--flip .prj__body { order: -1; }
  .prj--flip .prj__visual { border-right: 0; }
  .prj__visual { height: 280px; border-top: 1px solid var(--line); }
  .prj__meta { flex-wrap: wrap; gap: 16px 24px; }
  .prj-title { font-size: 44px; }
  .meta-grid { grid-template-columns: repeat(2, 1fr); }
  .meta-grid > div:nth-child(2n) { border-right: none; }
  .meta-grid > div:nth-child(-n + 2) { border-bottom: 1px solid var(--line); }
  .hero-visual { height: 360px; }
  .sol-grid { grid-template-columns: 1fr; }
  .page-nav a { padding: 28px 40px; }
}

@media (max-width: 720px) {
  .hud {
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    padding: 14px 20px 20px;
    min-height: 0;
    clip-path: none;
    border-bottom: 1px solid var(--line);
  }
  .hud__rule, .hud__corner, .hud__notch { display: none; }
  .hud__tabs { position: static; transform: none; order: 3; width: 100%; justify-content: center; }
  .hud__tabs a { padding: 8px 12px; }
  .bio__text, .bio__photo { padding: 48px 22px; }
  .sec__label { padding: 36px 22px 0; }
  .sec__body { padding: 24px 22px 48px; }
  .kit { grid-template-columns: 1fr; }
  .log__row { grid-template-columns: 1fr; gap: 10px; }
  .page-title { font-size: 40px; min-height: 40px; }
  .bio__lead, .bio__sub { font-size: 17px; }
  .bio__links { flex-direction: column; align-items: flex-start; gap: 16px; }
  .eyebrow { font-size: 12px; letter-spacing: 4px; }
  .cta, .cta--tight, .cta--tall { padding: 48px 22px; }
  .cta__title { font-size: 32px; }

  .hero-sec { padding: 48px 22px 40px; }
  .hero-sec--flush { padding: 48px 22px 0; }
  .hero-sec .page-title { font-size: 40px; min-height: 40px; }
  .prj__body { padding: 32px 22px; }
  .prj__title { font-size: 26px; }
  .prj-title { font-size: 32px; }
  .meta-grid { grid-template-columns: 1fr; }
  .meta-grid > div { border-right: none; border-bottom: 1px solid var(--line); }
  .meta-grid > div:last-child { border-bottom: none; }
  .hero-visual { height: 240px; }
  .log--narrow .log__row { grid-template-columns: 1fr; gap: 10px; }
  .page-nav { grid-template-columns: 1fr; }
  .page-nav a { padding: 22px; border-right: 0 !important; text-align: left !important; }
  .page-nav a:first-child { border-bottom: 1px solid var(--line); }
  .tags--wrap { gap: 8px; }
  .cta__actions { flex-direction: column; align-items: stretch; gap: 16px; }
  .btn-copy { justify-content: center; }
  .btn-linkedin { text-align: center; }
}

/* Touch pointers get no custom cursor and no ghost trail. */
@media (hover: none) {
  html, body, a, a *, .btn-copy, .btn-copy * { cursor: auto; }
  .cursor-ghost { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .sec-reveal { opacity: 1; transform: none; }
  .cursor-ghost { display: none; }
}
