/* ==========================================================================
   Pandaren (PANDAREN TRADING LIMITED) — pandarentrading.com

   Direction: agency-grade portfolio. Design system generated with
   ui-ux-pro-max: Portfolio Grid pattern, Motion-Driven style,
   monochrome zinc palette with a single electric-blue accent,
   Archivo (display) / Space Grotesk (mono-ish grotesk) — self-hosted.
   Motion: IntersectionObserver reveals + 200-300ms hovers, all gated
   behind prefers-reduced-motion.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Fonts (self-hosted, variable, latin subset — OFL licence)
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-var.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("/assets/fonts/space-grotesk-var.woff2") format("woff2");
  font-weight: 300 700;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  --bg: #fafafa;
  --fg: #09090b;
  --primary: #18181b;
  --secondary: #3f3f46;
  --muted-fg: #71717a;
  --surface: #ffffff;
  --muted: #f1f3f5;
  --border: #e4e4e7;
  --accent: #2563eb;
  --accent-ink: #1d4ed8;
  --on-accent: #ffffff;

  --font-display: "Archivo", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-body: "Archivo", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-grotesk: "Space Grotesk", ui-monospace, "SF Mono", Menlo, monospace;

  --shell: 1200px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --radius: 2px;

  --dur-1: 200ms;
  --dur-2: 320ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #09090b;
    --fg: #fafafa;
    --primary: #f4f4f5;
    --secondary: #d4d4d8;
    --muted-fg: #a1a1aa;
    --surface: #111113;
    --muted: #17171a;
    --border: #27272a;
    --accent: #3b82f6;
    --accent-ink: #60a5fa;
    --on-accent: #09090b;
  }
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 5.5rem;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.06rem);
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

h1, h2, h3, h4 {
  font-family: var(--font-display);
  margin: 0;
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

p { margin: 0 0 1.05em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-1) var(--ease-out);
}
a:hover { color: var(--accent); }

button { cursor: pointer; }

::selection { background: var(--accent); color: var(--on-accent); }

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

.skip-link {
  position: absolute; left: 1rem; top: -100%; z-index: 99;
  background: var(--fg); color: var(--bg); padding: 0.65rem 1rem;
  font-family: var(--font-grotesk); font-size: 0.78rem;
}
.skip-link:focus { top: 0.75rem; }

.sheet {
  width: min(100% - var(--gutter) * 2, var(--shell));
  margin-inline: auto;
}

/* Shared metadata typography */
.label, .eyebrow, .numeral {
  font-family: var(--font-grotesk);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-fg);
}
.eyebrow { display: block; margin-bottom: 1.1rem; color: var(--accent); }
.numeral { color: var(--accent); }

hr.rule { border: 0; border-top: 1px solid var(--border); margin: 0; }

/* --------------------------------------------------------------------------
   3. Reveal system (JS adds .in when visible; reduced-motion opts out)
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-2) var(--ease-out), transform 0.55s var(--ease-out);
  transition-delay: var(--d, 0ms);
  will-change: opacity, transform;
}
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after { animation: none !important; transition-duration: 0.01ms !important; }
}

/* --------------------------------------------------------------------------
   4. Masthead
   -------------------------------------------------------------------------- */
.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-1) var(--ease-out);
}
.masthead[data-stuck="true"] { border-bottom-color: var(--border); }
.masthead .sheet {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: 68px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  flex: 0 0 auto;
}
.brand img { width: 30px; height: 30px; }
.brand strong {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}
.brand span {
  font-family: var(--font-grotesk);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-fg);
  border-left: 1px solid var(--border);
  padding-left: 0.65rem;
}
@media (max-width: 640px) { .brand span { display: none; } }

.nav { margin-left: auto; display: flex; align-items: center; gap: clamp(1rem, 2.4vw, 2rem); }
.nav a {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--secondary);
  position: relative;
  padding: 0.35rem 0;
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-1) var(--ease-out);
}
.nav a:hover { color: var(--fg); }
.nav a:hover::after { transform: scaleX(1); }

.nav a.is-seal, .nav .btn-nav {
  background: var(--primary);
  color: var(--bg);
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  font-size: 0.85rem;
  transition: background var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.nav a.is-seal::after { display: none; }
.nav a.is-seal:hover { background: var(--accent); color: var(--on-accent); transform: translateY(-1px); }

.nav-toggle {
  margin-left: auto;
  display: none;
  background: none;
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  font-family: var(--font-grotesk);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  min-height: 44px;
}
@media (max-width: 800px) {
  .nav-toggle { display: block; }
  .nav {
    position: absolute;
    inset: 68px 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    padding: 0.5rem var(--gutter) 1.25rem;
    display: none;
  }
  .nav[data-open="true"] { display: flex; }
  .nav a { padding: 0.9rem 0; border-bottom: 1px solid var(--border); font-size: 1rem; min-height: 44px; }
  .nav a::after { display: none; }
  .nav a.is-seal { margin-top: 0.9rem; text-align: center; border-bottom: 0; }
}

/* --------------------------------------------------------------------------
   5. Hero
   -------------------------------------------------------------------------- */
.hero { padding-block: clamp(4rem, 10vw, 8rem) clamp(3rem, 7vw, 5.5rem); }

.hero-kicker {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.75rem;
}
.hero-kicker .dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.hero h1 {
  font-size: clamp(2.9rem, 9vw, 6.8rem);
  font-weight: 640;
  letter-spacing: -0.045em;
  max-width: 13ch;
  margin-bottom: 2rem;
}
.hero h1 .accent { color: var(--accent); }

.hero-lede {
  font-size: clamp(1.08rem, 1rem + 0.5vw, 1.35rem);
  line-height: 1.55;
  color: var(--secondary);
  max-width: 36rem;
  margin-bottom: 2.5rem;
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 0.9rem; align-items: center; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 48px;
  padding: 0.8rem 1.6rem;
  border-radius: 999px;
  background: var(--primary);
  color: var(--bg);
  font-weight: 600;
  font-size: 0.95rem;
  border: 1px solid transparent;
  transition: background var(--dur-1) var(--ease-out),
              transform var(--dur-1) var(--ease-out),
              box-shadow var(--dur-1) var(--ease-out);
}
.btn:hover {
  background: var(--accent);
  color: var(--on-accent);
  transform: translateY(-2px);
  box-shadow: 0 12px 28px -14px color-mix(in srgb, var(--accent) 55%, transparent);
}
.btn svg { width: 16px; height: 16px; transition: transform var(--dur-1) var(--ease-out); }
.btn:hover svg { transform: translateX(3px); }

.btn--ghost, .btn--seal {
  background: transparent;
  color: var(--fg);
  border-color: var(--border);
}
.btn--ghost:hover, .btn--seal:hover {
  background: var(--muted);
  color: var(--fg);
  border-color: var(--fg);
  box-shadow: none;
}

.hero-meta {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
}
.hero-meta span {
  font-family: var(--font-grotesk);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--muted-fg);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.hero-meta svg { width: 14px; height: 14px; color: var(--accent); flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   6. Section scaffolding
   -------------------------------------------------------------------------- */
.section { padding-block: clamp(3.5rem, 8vw, 6.5rem); }
.section + .section { border-top: 1px solid var(--border); }

.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
.section-head h2 {
  font-size: clamp(1.9rem, 1.3rem + 2.8vw, 3.4rem);
  max-width: 22ch;
}
.section-head .count {
  font-family: var(--font-grotesk);
  font-size: 0.78rem;
  color: var(--muted-fg);
  white-space: nowrap;
  padding-bottom: 0.5rem;
}
.section-intro { color: var(--secondary); font-size: 1.1rem; max-width: 42rem; margin-bottom: clamp(2rem, 4vw, 3rem); }

/* --------------------------------------------------------------------------
   7. Work grid (Portfolio Grid pattern)
   -------------------------------------------------------------------------- */
.work-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

.work-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  overflow: hidden;
  transition: transform var(--dur-2) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.work-card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  box-shadow: 0 20px 44px -24px rgba(0, 0, 0, 0.25);
}

.work-visual {
  aspect-ratio: 16 / 9;
  display: grid;
  place-items: center;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--accent) 7%, var(--muted)), var(--muted));
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.work-visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-2) var(--ease-out);
}
.work-card:hover .work-visual img { transform: scale(1.03); }
.work-visual--pixel img { image-rendering: pixelated; }
.work-visual .mono {
  font-family: var(--font-grotesk);
  font-size: clamp(1.4rem, 4vw, 2rem);
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--secondary);
  transition: transform var(--dur-2) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.work-card:hover .mono { transform: scale(1.05); color: var(--accent); }

.work-body { padding: 1.25rem 1.35rem 1.45rem; display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.work-body h3 { font-size: 1.22rem; font-weight: 600; letter-spacing: -0.015em; }
.work-body p { color: var(--secondary); font-size: 0.94rem; line-height: 1.55; }

.work-foot {
  margin-top: auto;
  padding-top: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.chip {
  font-family: var(--font-grotesk);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.32rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted-fg);
}
.chip--live { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.work-ref { font-family: var(--font-grotesk); font-size: 0.68rem; color: var(--muted-fg); letter-spacing: 0.1em; }

/* --------------------------------------------------------------------------
   8. Capabilities (two disciplines)

   v10 — récrit en « fiche technique », adapté de 21st.dev #5541
   (« Feature Section » par ruixen.ui) : un récit d'un côté, un panneau
   de lignes tramées de l'autre, chaque ligne portant un index, un
   intitulé et son descriptif. La boucle défilante et le fondu du
   composant d'origine sont écartés — quatre lignes tiennent à l'écran,
   et un carrousel infini se heurterait à prefers-reduced-motion.
   -------------------------------------------------------------------------- */
.caps { display: grid; grid-template-columns: 1fr; }

/* Chaque discipline occupe une bande pleine largeur, séparée par un filet. */
.cap {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: center;
  padding-block: clamp(1.75rem, 4vw, 3rem);
}
.cap + .cap { border-top: 1px solid var(--border); }
/* Rythme éditorial : la seconde discipline inverse récit et panneau — les
   largeurs suivent le déplacement, le panneau reste toujours le plus large. */
.cap:nth-of-type(even) { grid-template-columns: minmax(0, 1.14fr) minmax(0, 0.86fr); }
.cap:nth-of-type(even) .cap-copy { order: 2; }

.cap-head { display: flex; align-items: center; gap: 0.85rem; margin-bottom: 1.1rem; }
.cap-icon {
  width: 44px; height: 44px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--accent) 10%, var(--muted));
  color: var(--accent);
  flex: 0 0 auto;
}
.cap-icon svg { width: 22px; height: 22px; }
.cap-id {
  font-family: var(--font-grotesk);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--secondary);
}

.cap h3 { font-size: clamp(1.6rem, 1.25rem + 1.3vw, 2.15rem); margin-bottom: 0.85rem; }

/* Chapô bicolore : la clause d'attaque en pleine encre, la suite en retrait. */
.cap-lede {
  color: var(--secondary);
  font-size: clamp(1rem, 0.96rem + 0.28vw, 1.15rem);
  line-height: 1.6;
  max-width: 34rem;
}
.cap-lede strong { color: var(--fg); font-weight: 600; }

/* Le panneau : lignes tramées, index à gauche, coche à droite. */
.cap-spec {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  overflow: hidden;
}
.cap-spec li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.95rem;
  min-height: 66px;
  padding: 0.85rem clamp(0.9rem, 2vw, 1.25rem);
  border-top: 1px solid var(--border);
  transition: background var(--dur-1) var(--ease-out);
}
.cap-spec li:first-child { border-top: 0; }
.cap-spec li:hover { background: var(--muted); }

.spec-n {
  width: 38px; height: 38px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--muted);
  display: grid;
  place-items: center;
  font-family: var(--font-grotesk);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--secondary);
  transition: border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.cap-spec li:hover .spec-n { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); color: var(--accent-ink); }

.spec-t { min-width: 0; }
.spec-t b {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--fg);
  line-height: 1.25;
}
.spec-t span {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--secondary);
}
.spec-k { width: 16px; height: 16px; color: var(--accent); flex: 0 0 auto; }

.cap-tags { margin-top: 1.4rem; display: flex; flex-wrap: wrap; gap: 0.45rem; }
/* Les puces reposent désormais sur la bande teintée, plus sur une carte
   blanche : on leur rend un fond de surface, sans quoi le gris `--muted-fg`
   tombe à 4,34:1 en mode clair. */
.cap-tags .chip { background: var(--surface); }

@media (max-width: 900px) {
  .cap, .cap:nth-of-type(even) { grid-template-columns: 1fr; }
  .cap { gap: 1.5rem; align-items: start; }
  .cap:nth-of-type(even) .cap-copy { order: 0; }
  .cap-lede { max-width: none; }
}

/* --------------------------------------------------------------------------
   9. Principles strip
   -------------------------------------------------------------------------- */
.principles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  counter-reset: pr;
}
.principle { border-top: 2px solid var(--fg); padding-top: 1.2rem; }
.principle .numeral { display: block; margin-bottom: 0.8rem; }
.principle h3 { font-size: 1.2rem; margin-bottom: 0.5rem; }
.principle p { color: var(--secondary); font-size: 0.95rem; }

/* --------------------------------------------------------------------------
   10. Standards + imprint

   v11 — les quatre engagements ne sont plus quatre cartes détourées : au
   shell de 1200 px, `auto-fit` en alignait trois puis en laissait une
   orpheline sur la rangée suivante. Ils forment maintenant un registre
   continu de deux colonnes, tramé par des filets, adapté de 21st.dev #1521
   (« Feature Section with hover effects » par manuarora700) : barre d'accent
   posée sur le filet à hauteur du titre, titre qui glisse, lavis discret.
   -------------------------------------------------------------------------- */
.standards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.standard {
  position: relative;
  overflow: hidden;
  padding: clamp(1.6rem, 3vw, 2.2rem) clamp(1.4rem, 2.6vw, 2rem);
}
/* Filets internes seulement : la grille reste ouverte sur ses côtés, comme
   les bandes de la section Capabilities. */
.standard:nth-child(odd) { border-right: 1px solid var(--border); }
.standard:nth-child(n + 3) { border-top: 1px solid var(--border); }

/* Lavis au survol : il monte depuis le bas sur la première rangée, descend
   depuis le haut sur la seconde — le dégradé pointe toujours vers le filet
   médian. Purement décoratif, donc sous le texte et sans capter le pointeur. */
.standard::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to top, var(--muted), transparent);
  transition: opacity var(--dur-1) var(--ease-out);
}
.standard:nth-child(n + 3)::after {
  background: linear-gradient(to bottom, var(--muted), transparent);
}
.standard:hover::after { opacity: 1; }

.standard-icon {
  display: block;
  position: relative;
  z-index: 1;
  margin-bottom: 0.9rem;
  color: var(--secondary);
  transition: color var(--dur-1) var(--ease-out);
}
.standard-icon svg { width: 22px; height: 22px; }
.standard:hover .standard-icon { color: var(--accent); }

.standard h3 {
  position: relative;
  z-index: 1;
  font-size: 1.12rem;
  margin-bottom: 0.55rem;
}
/* La barre naît du filet lui-même : callée sur le bord gauche de la cellule,
   elle grandit et prend l'accent au survol pendant que le titre s'écarte. */
.standard h3::before {
  content: "";
  position: absolute;
  left: calc(-1 * clamp(1.4rem, 2.6vw, 2rem));
  top: 50%;
  translate: 0 -50%;
  width: 3px;
  height: 1.1rem;
  border-radius: 0 3px 3px 0;
  background: var(--border);
  transition: height var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out);
}
.standard h3 span {
  display: inline-block;
  transition: transform var(--dur-1) var(--ease-out);
}
.standard:hover h3::before { height: 1.75rem; background: var(--accent); }
.standard:hover h3 span { transform: translateX(6px); }

.standard p { position: relative; z-index: 1; color: var(--secondary); font-size: 0.93rem; }
.standard a { color: var(--accent-ink); font-weight: 500; }
.standard a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Une seule colonne dès que deux cellules côte à côte serrent la mesure. */
@media (max-width: 760px) {
  .standards { grid-template-columns: 1fr; }
  .standard:nth-child(odd) { border-right: 0; }
  .standard + .standard { border-top: 1px solid var(--border); }
  .standard:nth-child(n + 3)::after { background: linear-gradient(to top, var(--muted), transparent); }
}

.imprint {
  margin-top: clamp(2rem, 4vw, 3rem);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--muted);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
}
.imprint dl { margin: 0; }
.imprint dt { margin-bottom: 0.35rem; }
.imprint dd { margin: 0 0 1.1rem; font-size: 0.97rem; line-height: 1.55; }
.imprint dd:last-child { margin-bottom: 0; }
.imprint address { font-style: normal; }
.imprint a { color: var(--accent-ink); font-weight: 500; }
.imprint a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* --------------------------------------------------------------------------
   11. Contact band — deux registres séparés par un filet.

       v12 : adapté à la main en CSS vanilla de 21st.dev « Newsletter Band »
       (@7ovr, demo 21497). L'original pose l'identité à gauche (label,
       titre, sous-titre) et tout l'appareil d'action à droite d'une bande
       pleine largeur, la note de bas de bloc glissée sous l'action. La
       liste de réassurance qui remplace ici le champ e-mail reprend l'idée
       de « Cta 4 » (@shadcnblockscom, demo 2205) : colonne de droite en
       items cochés, pas en formulaire. Aucun champ n'est posé ici — le
       formulaire vit sur /contact et /api/contact n'est pas touché.
   -------------------------------------------------------------------------- */
.contact-band {
  margin-block: clamp(3rem, 7vw, 5.5rem);
  border-radius: 16px;
  background: var(--primary);
  color: var(--bg);
  padding: clamp(2.5rem, 5vw, 4rem) clamp(1.5rem, 4vw, 3.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 23rem);
  gap: clamp(2rem, 4vw, 4rem);
  align-items: stretch;
  text-align: left;
}
/* `stretch` plutôt que `center` : c'est ce qui donne au filet vertical toute
   la hauteur de la bande. Chaque colonne recentre ensuite son propre contenu,
   sinon le filet ne mesurerait que la hauteur du bouton — un tiret posé au
   milieu de nulle part. */
.contact-lead {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.contact-band .eyebrow { color: color-mix(in srgb, var(--bg) 62%, transparent); }
.contact-band h2 {
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 3.1rem);
  max-width: 15ch;
  margin: 0 0 1.1rem;
}
.contact-band p { color: color-mix(in srgb, var(--bg) 74%, transparent); max-width: 36rem; margin: 0; }

/* Colonne d'action : le filet vertical la détache du récit, comme les
   filets de la section Standards détachent les cellules du registre. */
.contact-act {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1.5rem;
  padding-left: clamp(1.75rem, 3.5vw, 3.25rem);
  border-left: 1px solid color-mix(in srgb, var(--bg) 20%, transparent);
}
.contact-band .btn {
  margin-top: 0;
  background: var(--bg);
  color: var(--fg);
}
.contact-band .btn:hover { background: var(--accent); color: var(--on-accent); }

/* Les conditions d'échange, mot pour mot celles de l'ancienne ligne `.sub`,
   simplement dépliées en deux items sous le bouton. */
.contact-terms {
  display: grid;
  gap: 0.7rem;
  margin: 0;
  max-width: none;
  font-family: var(--font-grotesk);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  line-height: 1.45;
  color: color-mix(in srgb, var(--bg) 70%, transparent);
}
.contact-terms span { display: flex; align-items: flex-start; gap: 0.75rem; }
/* Le point médian n'existe que pour la feuille précédente : un visiteur qui
   reçoit ce markup avec `style.11.css` en cache retrouve mot pour mot la
   ligne d'aujourd'hui — « … deux business days · English & Français ». Sous
   la feuille courante les deux conditions sont empilées, il disparaît. */
.contact-terms .sep { display: none; }
/* La coche est dessinée en CSS (deux bords d'une boîte tournée) plutôt
   qu'en SVG dans le markup : un visiteur qui reçoit ce markup avec
   `style.11.css` encore en cache n'hérite d'aucune règle pour ces items,
   et une coche en SVG s'y détacherait de son texte, orpheline à gauche du
   bloc centré. En `::before`, elle disparaît simplement — il ne reste que
   les deux lignes de texte, lisibles. */
.contact-terms span::before {
  content: "";
  flex: none;
  width: 0.4rem;
  height: 0.7rem;
  margin-top: 0.18em;
  border: 0 solid color-mix(in srgb, var(--bg) 58%, transparent);
  border-right-width: 1.5px;
  border-bottom-width: 1.5px;
  transform: rotate(42deg);
}

/* Sous 900 px la bande se replie : le filet passe de la gauche au-dessus. */
@media (max-width: 900px) {
  .contact-band { grid-template-columns: 1fr; gap: 1.9rem; }
  .contact-band h2 { max-width: 18ch; }
  .contact-act {
    align-self: stretch;
    padding-left: 0;
    padding-top: 1.75rem;
    border-left: 0;
    border-top: 1px solid color-mix(in srgb, var(--bg) 20%, transparent);
  }
}

/* --------------------------------------------------------------------------
   12. Footer — outlined wordmark cresting a fluted plate.
       Adapted by hand to vanilla CSS from 21st.dev "Footer Section 5"
       (@solaceui, demo 19358): the React original stacks an oversized
       -webkit-text-stroke wordmark over a shader-lit panel. Here the shader
       is a repeating-linear-gradient and the palette stays zinc, not blue.
   -------------------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--border); padding-block: clamp(2.5rem, 5vw, 3.5rem) 2rem; }

/* Pages that carry the full four-column footer opt into the plate treatment;
   the slim 404 footer keeps the plain hairline above. */
.site-footer--plate {
  position: relative;
  overflow: hidden;
  border-top: 0;
  padding-block: clamp(1rem, 2.5vw, 1.75rem) 2rem;
}

/* Decorative only. The text lives in CSS `content` on purpose: while a stale
   stylesheet is still cached at the edge, the empty div renders as nothing
   instead of an unstyled slab of giant text. */
.footer-wordmark {
  position: relative;
  z-index: 0;
  line-height: 0.74;
  margin-bottom: -0.19em;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
.footer-wordmark::before {
  content: "Pandaren";
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: min(20vw, 18rem);
  letter-spacing: -0.035em;
  white-space: nowrap;
  color: color-mix(in srgb, var(--muted-fg) 22%, transparent);
}
@supports (-webkit-text-stroke: 1px currentColor) {
  .footer-wordmark::before {
    color: transparent;
    -webkit-text-stroke: 1px color-mix(in srgb, var(--muted-fg) 52%, transparent);
  }
}

.footer-plate {
  position: relative;
  z-index: 1;
  isolation: isolate;
  border: 1px solid var(--border);
  border-radius: 16px;
  /* --surface, not --muted: the small uppercase column headings need a light
     enough backdrop to clear 4.5:1, and it matches the cards elsewhere. */
  background: var(--surface);
  padding: clamp(1.75rem, 4vw, 2.75rem) clamp(1.25rem, 3.5vw, 2.5rem) clamp(1.25rem, 3vw, 1.75rem);
}
/* Fluted glass, the cheap way: hairline rules fading out toward the base. */
.footer-plate::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--fg) 6%, transparent) 0 1px,
    transparent 1px 5rem
  );
  opacity: 0.55;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
  mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
  pointer-events: none;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: 2rem;
  margin-bottom: 2.25rem;
}
.footer-grid h4 {
  font-family: var(--font-grotesk);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-fg);
  margin-bottom: 0.9rem;
}
.footer-grid ul { list-style: none; margin: 0; padding: 0; }
.footer-grid li { padding-block: 0.36rem; font-size: 0.94rem; color: var(--secondary); }
/* Padding + matching negative margin: the hit area covers the whole row
   without changing the vertical rhythm. */
.footer-grid a { color: var(--secondary); transition: color var(--dur-1) var(--ease-out); }
.footer-grid li a {
  display: inline-block;
  padding-block: 0.36rem;
  margin-block: -0.36rem;
}
.footer-grid a:hover { color: var(--accent); }
.footer-grid address { font-style: normal; font-size: 0.94rem; line-height: 1.6; color: var(--secondary); }

/* The brand column carries the postal address; give it the extra room so
   "…Kiu Yin Commercial Building" stops breaking across two lines. */
@media (min-width: 900px) {
  .footer-plate .footer-grid { grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); }
}

/* Comfortable thumb targets once the columns stack. */
@media (max-width: 760px) {
  .footer-grid { gap: 1.75rem; }
  .footer-grid li { padding-block: 0.66rem; }
  .footer-grid li a { padding-block: 0.66rem; margin-block: -0.66rem; }
}

.footer-base {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 2rem;
  justify-content: space-between;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-family: var(--font-grotesk);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: var(--muted-fg);
}
.footer-base a { color: inherit; }
.footer-base a:hover { color: var(--accent); }

/* --------------------------------------------------------------------------
   13. Legal / document pages
   -------------------------------------------------------------------------- */
.doc-hero {
  padding-block: clamp(3rem, 7vw, 5rem) clamp(1.75rem, 3.5vw, 2.5rem);
  border-bottom: 1px solid var(--border);
}
.doc-hero h1 { font-size: clamp(2.1rem, 1.5rem + 2.8vw, 3.6rem); margin-bottom: 1rem; max-width: 22ch; }
.doc-hero p { max-width: 44rem; color: var(--secondary); }

/* Document facts — the old single grey line, unfolded into a register of
   labelled cells separated by rules (the vocabulary already used by the
   Standards section). The text nodes are untouched: the middots and the
   colons are `.sep` spans, so a visitor still served an older sheet reads
   the very same sentence, word for word. */
.doc-meta {
  font-family: var(--font-grotesk);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--muted-fg);
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem 1.6rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--border);
  max-width: 44rem;
}
.doc-meta .sep { display: none; }
/* `.sep` is still a DOM sibling, so `.doc-fact + .doc-fact` would never
   match — the rule hangs off the separator itself. */
.doc-meta .sep + .doc-fact { border-left: 1px solid var(--border); padding-left: 1.6rem; }
.doc-fact-k {
  display: block;
  font-size: 0.63rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-fg);
  margin-bottom: 0.3rem;
}
.doc-fact-v { font-size: 0.86rem; letter-spacing: 0.02em; color: var(--secondary); }
@media (max-width: 520px) {
  .doc-meta { gap: 0.9rem 1.1rem; }
  .doc-meta .sep + .doc-fact { padding-left: 1.1rem; }
}

.doc {
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding-block: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
/* Une piste de grille vaut `min-width: auto` par défaut : la table de
   `.doc-body` (min-width 32rem) élargissait donc la colonne à 512 px sur
   mobile, et toute la page débordait de 145 px — mesuré à 390 px de
   viewport, sur l'ancienne feuille comme sur la nouvelle. Avec `min-width:
   0`, c'est `.table-wrap` qui reprend son rôle et fait défiler la table. */
.doc > * { min-width: 0; }
@media (max-width: 880px) { .doc { grid-template-columns: 1fr; } }

/* Table of contents — a rail the reader's position rides along, after
   « Table of Contents » by @hirael (21st.dev, id 18113). Two departures from
   the original: the marker is the accent rule rather than a foreground bar,
   and the numbering already in the system is kept. */
.toc { position: sticky; top: 5.5rem; }
@media (max-width: 880px) { .toc { position: static; border-bottom: 1px solid var(--border); padding-bottom: 1.25rem; } }

.toc h2 {
  font-family: var(--font-grotesk);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-fg);
  margin-bottom: 0.9rem;
}
/* Le repli mobile est entièrement construit en JS (voir main.7.js) : le
   markup de la table des matières est resté celui de la production, donc un
   visiteur encore servi par une ancienne feuille voit exactement la page
   d'hier — pas un contrôle non stylé. Le bouton n'existe que si CETTE
   feuille est bien appliquée. */
.toc[data-foldable] h2 { margin-bottom: 0; }
.toc-fold {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  text-align: left;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
/* 1,05 rem de part et d'autre d'une ligne de 0,68 rem : 44 px de cible. */
.toc[data-foldable="true"] .toc-fold { cursor: pointer; padding-block: 1.05rem; }
.toc[data-foldable="true"] .toc-fold[aria-expanded="true"] { color: var(--fg); }
/* Chevron dessiné en CSS plutôt que livré en SVG dans le markup. */
.toc-fold::after {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-1) var(--ease-out);
}
.toc[data-foldable="false"] .toc-fold::after { display: none; }
.toc[data-foldable="true"] .toc-fold[aria-expanded="true"]::after { transform: translateY(1px) rotate(-135deg); }

.toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: toc;
  border-left: 1px solid var(--border);
}
.toc li { padding-block: 0; }
.toc a {
  display: block;
  font-size: 0.9rem;
  color: var(--secondary);
  border-left: 1px solid transparent;
  margin-left: -1px;
  padding: 0.42rem 0.4rem 0.42rem 0.85rem;
  transition: color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out);
}
.toc a::before {
  counter-increment: toc;
  content: counter(toc, decimal-leading-zero);
  font-family: var(--font-grotesk);
  font-size: 0.66rem;
  color: var(--accent);
  margin-right: 0.55rem;
}
.toc a:hover, .toc a:focus-visible { color: var(--accent); }
/* The marker. `aria-current` is set by the scroll spy, so the styling and
   what assistive technology is told can never drift apart. */
.toc a[aria-current="true"] {
  color: var(--fg);
  font-weight: 500;
  border-left-color: var(--accent);
}

@media (max-width: 880px) {
  /* ≥ 44 px targets once the rail is the only way to move around. */
  .toc a { padding-block: 0.72rem; }
  .toc li + li { border-top: 1px solid var(--border); }
}

.doc-body { max-width: 44rem; }
.doc-body section { padding-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.doc-body h2 { font-size: clamp(1.4rem, 1.2rem + 0.9vw, 1.9rem); margin-bottom: 0.85rem; }
.doc-body h3 { font-size: 1.14rem; margin: 1.5rem 0 0.55rem; }
.doc-body p, .doc-body li { color: var(--secondary); }
.doc-body ul, .doc-body ol { padding-left: 1.2rem; margin: 0 0 1.05em; }
.doc-body li { padding-block: 0.2rem; }
.doc-body li::marker { color: var(--accent); }
.doc-body a { color: var(--accent-ink); font-weight: 500; }
.doc-body a:hover { text-decoration: underline; text-underline-offset: 3px; }
.doc-body strong { color: var(--fg); font-weight: 600; }

.callout {
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  border-radius: 0 8px 8px 0;
  padding: 1rem 1.2rem;
  margin: 0 0 1.35rem;
  font-size: 0.95rem;
}

.table-wrap { overflow-x: auto; margin: 0 0 1.35rem; border: 1px solid var(--border); border-radius: 10px; }
table { border-collapse: collapse; width: 100%; min-width: 32rem; font-size: 0.93rem; }
th, td { text-align: left; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th {
  font-family: var(--font-grotesk);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-fg);
  background: var(--muted);
}
td { color: var(--secondary); }
tr:last-child td, tr:last-child th { border-bottom: 0; }

/* --------------------------------------------------------------------------
   14. 404
   -------------------------------------------------------------------------- */
.notfound { padding-block: clamp(4rem, 12vw, 8rem); }
.notfound-body { max-width: 42rem; }
.notfound img { width: 72px; height: auto; image-rendering: pixelated; margin-bottom: 1.6rem; }
.notfound h1 { font-size: clamp(2.1rem, 1.45rem + 2.9vw, 3.4rem); margin-bottom: 1rem; }
.notfound p { color: var(--secondary); margin-bottom: 1.75rem; }
/* `.notfound p` (0,2,0) outranks `.eyebrow`/`.label` (0,1,0): without these two
   the metadata lines lose their own colour and read as body copy. */
.notfound .eyebrow { color: var(--accent); }
.notfound .label { color: var(--muted-fg); }
.notfound-lede { max-width: 33rem; }

.notfound-actions { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-bottom: 0; }
.notfound .btn + .btn { margin-left: 0; }

/* Suggested routes — a register of live paths, in the same rule vocabulary
   as the Standards section. */
.notfound-routes {
  margin-top: clamp(2.5rem, 6vw, 3.5rem);
  border-top: 1px solid var(--border);
  padding-top: 1.4rem;
}
.notfound-routes .label { margin: 0 0 0.35rem; }
.routes { list-style: none; margin: 0; padding: 0; }
.routes li + li { border-top: 1px solid var(--border); }
.routes a {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 1.15rem;
  padding: 0.95rem 2.4rem 0.95rem 0.7rem;
  transition: background var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.routes a:hover, .routes a:focus-visible { background: var(--muted); }
.routes-path {
  font-family: var(--font-grotesk);
  font-size: 0.9rem;
  font-weight: 500;
  color: inherit;
}
.routes-desc { font-size: 0.9rem; color: var(--secondary); }
/* Chevron drawn in CSS, not SVG: under an older cached sheet it simply is
   not painted, instead of hanging unstyled beside the text. */
.routes a::after {
  content: "";
  position: absolute;
  right: 1rem;
  top: 50%;
  width: 7px;
  height: 7px;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  opacity: 0;
  transform: translate(-5px, -50%) rotate(45deg);
  transition: opacity var(--dur-1) var(--ease-out),
              transform var(--dur-1) var(--ease-out);
}
.routes a:hover::after, .routes a:focus-visible::after {
  opacity: 1;
  transform: translate(0, -50%) rotate(45deg);
}

@media (max-width: 520px) {
  .routes a { padding-right: 1.9rem; }
  .routes-desc { flex-basis: 100%; }
}

/* --------------------------------------------------------------------------
   15. Utilities kept for legal pages
   -------------------------------------------------------------------------- */
.u-mt { margin-top: 1.5rem; }
.u-mb { margin-bottom: 1rem; }

@media print {
  .masthead, .nav, .btn, .toc { display: none !important; }
  body { background: #fff; color: #111; }
  .doc { grid-template-columns: 1fr; }
  a { color: #111; text-decoration: underline; }
}


/* --------------------------------------------------------------------------
   16. Hero backdrop — quiet dot grid, agency texture without noise
   -------------------------------------------------------------------------- */
.hero { position: relative; }
.hero::before {
  content: "";
  position: absolute;
  inset: 0 0 18%;
  z-index: -1;
  background-image: radial-gradient(color-mix(in srgb, var(--fg) 9%, transparent) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 75% 90% at 28% 18%, #000 0%, transparent 68%);
  mask-image: radial-gradient(ellipse 75% 90% at 28% 18%, #000 0%, transparent 68%);
}

/* Live chip: a quiet pulse */
.chip--live { display: inline-flex; align-items: center; gap: 0.4rem; }
.chip--live::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* --------------------------------------------------------------------------
   17. Contact form
   -------------------------------------------------------------------------- */
.form-wrap { max-width: 44rem; padding-block: clamp(2rem, 5vw, 3.5rem); }
.form-wrap--wide { max-width: 66rem; }

.form-banner {
  border-radius: 10px;
  padding: 1rem 1.2rem;
  margin-bottom: 1.5rem;
  font-size: 0.97rem;
  border: 1px solid var(--border);
}
.form-banner--ok {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
}
.form-banner--err {
  border-color: color-mix(in srgb, #dc2626 45%, var(--border));
  background: color-mix(in srgb, #dc2626 7%, var(--surface));
}

.contact-form { display: grid; gap: 1.25rem; }
.field-row { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.field { display: grid; gap: 0.45rem; }
.field label { font-weight: 600; font-size: 0.94rem; }
.field label span { color: var(--accent); }
.field input,
.field select,
.field textarea {
  font: inherit;
  color: var(--fg);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.8rem 0.95rem;
  min-height: 48px;
  width: 100%;
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.field textarea { resize: vertical; min-height: 10rem; }
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.field-help { font-size: 0.85rem; color: var(--muted-fg); margin: 0; }
.contact-form .btn { justify-self: start; }

/* Pot de miel : hors écran pour les humains, visible pour les robots. */
.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   17b. Contact form — sections à intitulés latéraux
   D'après « Form Layout / Form Sections with Side Labels » (@ephraimduncan,
   id 4348), réécrit en CSS grid vanilla. Le formulaire est découpé en trois
   bandes séparées par des filets ; chaque bande annonce à gauche ce qu'elle
   demande et pourquoi, les champs occupent la colonne de droite.

   Les classes historiques (.contact-form, .field-row, .field, .field-help)
   sont conservées telles quelles : si un nœud Cloudflare sert encore
   style.8.css avec ce nouveau markup, les bandes se dépilent simplement en
   une colonne et le formulaire reste utilisable.
   -------------------------------------------------------------------------- */
.contact-form--sectioned { gap: 0; }

.form-section {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding-block: clamp(1.75rem, 4vw, 2.75rem);
  border-top: 1px solid var(--border);
  align-items: start;
}
.form-section:first-of-type { border-top: 0; padding-top: 0; }
@media (max-width: 880px) {
  .form-section { grid-template-columns: 1fr; gap: 1.25rem; }
}

.form-section-head h2 {
  font-size: 1.02rem;
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem;
}
.form-section-head p {
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--muted-fg);
  margin: 0;
  max-width: 34ch;
}
.form-section-index {
  display: block;
  font-family: var(--font-grotesk);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-fg);
  margin-bottom: 0.55rem;
}

.form-fields { display: grid; gap: 1.25rem; }

/* Sans cela, la ligne d'aide sous « Email » étire les rangées de la grille
   voisine et le champ « Votre nom » descend de quelques pixels. */
.contact-form--sectioned .field-row { align-items: start; }
.contact-form--sectioned .field { align-content: start; }

/* Une liste de quatre entrées n'a pas besoin de toute la colonne. */
.contact-form--sectioned select { max-width: 24rem; }

/* Ligne de bas de champ : aide à gauche, compteur à droite.
   D'après « Floating Label » (@ddoemonn, id 23566) — on n'en garde que la
   mécanique (ligne d'aide reliée en aria-describedby, compteur de caractères,
   état invalide), pas l'étiquette flottante ni son rouge saturé. */
.field-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.field-foot .field-help { flex: 1 1 auto; }
.field-counter {
  flex: 0 0 auto;
  font-family: var(--font-grotesk);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted-fg);
  transition: color var(--dur-1) var(--ease-out);
}
.field-counter[data-state="near"] { color: var(--secondary); }
.field-counter[data-state="full"] { color: var(--accent-ink); font-weight: 600; }

/* État invalide — seulement après une vraie saisie de l'internaute
   (:user-invalid), jamais sur un champ vide encore jamais touché. */
.field input:user-invalid,
.field textarea:user-invalid,
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: color-mix(in srgb, #dc2626 55%, var(--border));
}
.field input:user-invalid:focus-visible,
.field textarea:user-invalid:focus-visible,
.field input[aria-invalid="true"]:focus-visible,
.field textarea[aria-invalid="true"]:focus-visible {
  border-color: #dc2626;
  box-shadow: 0 0 0 3px color-mix(in srgb, #dc2626 20%, transparent);
}

/* Pied de formulaire : bouton + rappel de délai, alignés sur la colonne
   des champs pour que l'action reste sous ce qu'elle envoie. */
.form-submit { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; }
.form-submit .btn { justify-self: start; }
.form-note {
  font-size: 0.85rem;
  color: var(--muted-fg);
  margin: 0;
  max-width: 32ch;
}


/* --------------------------------------------------------------------------
   18. Polish v5 — browser chrome, tinted band, textured contact
   -------------------------------------------------------------------------- */

/* Web screenshots framed as a minimal browser window. */
.work-visual--browser { position: relative; padding-top: 30px; }
.work-visual--browser::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 30px;
  background: var(--muted);
  border-bottom: 1px solid var(--border);
  z-index: 1;
}
.work-visual--browser::after {
  content: "";
  position: absolute;
  top: 11px; left: 14px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--border);
  box-shadow: 14px 0 0 var(--border), 28px 0 0 var(--border);
  z-index: 2;
}

/* Tinted band to break the page rhythm. */
.section--tint { background: var(--muted); }
/* v10 : la bande est teintée, seul le panneau de spécifications reste blanc.
   Ses lignes survolées reprennent donc la teinte de la bande, pas l'inverse. */
.section--tint .cap-spec { background: var(--surface); }
.section--tint .cap-spec li:hover { background: color-mix(in srgb, var(--muted) 70%, var(--surface)); }
.section--tint .spec-n { background: color-mix(in srgb, var(--muted) 70%, var(--surface)); }

/* Contact band: same quiet dot texture as the hero.
   v12 : la trame visait le quart haut-droit, qui est désormais occupé par
   le bouton. Elle est réorientée vers le bas-gauche — sous la queue du
   paragraphe — c'est-à-dire la seule zone que les deux colonnes laissent
   vide. Le `::before` reste `position: absolute`, donc hors flux : il ne
   crée pas de piste dans la grille du conteneur. */
.contact-band { position: relative; overflow: hidden; }
.contact-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(color-mix(in srgb, var(--bg) 16%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(ellipse 62% 85% at 16% 88%, #000, transparent 70%);
  mask-image: radial-gradient(ellipse 62% 85% at 16% 88%, #000, transparent 70%);
  pointer-events: none;
}
.contact-band > * { position: relative; }


/* --------------------------------------------------------------------------
   19. v6 — hero « display » et mosaïque (adapté de 21st.dev #9724 & #7826)
   -------------------------------------------------------------------------- */

/* Hero display : capitales massives, seconde ligne en contour. */
.hero .sheet { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 21rem); gap: clamp(2rem, 4vw, 3.5rem); align-items: center; }
@media (max-width: 960px) { .hero .sheet { grid-template-columns: 1fr; } }

.hero h1 {
  font-size: clamp(3rem, 10.5vw, 8.2rem);
  font-weight: 750;
  text-transform: uppercase;
  letter-spacing: -0.035em;
  line-height: 0.92;
  max-width: none;
}
.hero h1 .outline {
  color: transparent;
  -webkit-text-stroke: 2px var(--fg);
  text-stroke: 2px var(--fg);
}
.hero h1 .accent { color: var(--accent); }

/* Entrée : blur-in du bloc principal (CSS pur, annulé par reduced-motion). */
@keyframes blur-in {
  from { filter: blur(22px); opacity: 0; transform: scale(1.015); }
  to   { filter: blur(0);    opacity: 1; transform: none; }
}
.hero-main { animation: blur-in 1.1s var(--ease-out) both; }

/* Pastille « live » du kicker. */
.hero-kicker .dot { position: relative; }
.hero-kicker .dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0.5;
  animation: ping 2.4s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@keyframes ping { 75%, 100% { transform: scale(2.1); opacity: 0; } }

/* CTA circulaire fléché, façon studio. */
.cta-orbit {
  display: inline-flex;
  align-items: center;
  gap: 1.1rem;
  text-decoration: none;
}
.cta-orbit .ring {
  width: 58px; height: 58px;
  border-radius: 50%;
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
  transition: background var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}
.cta-orbit .ring svg { width: 20px; height: 20px; transition: transform var(--dur-2) var(--ease-out); }
.cta-orbit .lbl {
  font-family: var(--font-grotesk);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.cta-orbit:hover { color: var(--fg); }
.cta-orbit:hover .ring { background: var(--accent); border-color: var(--accent); transform: scale(1.06); }
.cta-orbit:hover .ring svg { stroke: var(--on-accent); transform: translate(2px, -2px); }

/* Cellules méta à droite (command cells) : entrée décalée depuis la droite. */
/* `cell-in` démarre à translateX(42px) : pendant les ~1,2 s d'entrée, les
   trois cellules dépassaient à droite et la page se laissait faire défiler
   latéralement de 22 px sur mobile (412 px pour 390 — le défaut noté au
   journal du 2 août, attribué à tort à la largeur des cellules : elles font
   bien 350 px, elles étaient seulement décalées). On clippe au conteneur :
   les cellules glissent depuis son bord au lieu de pousser la page.
   `clip` plutôt que `hidden` — pas de conteneur de défilement créé, donc
   aucun effet sur les `position: sticky` d'autres pages ; et là où il n'est
   pas connu, on retombe simplement sur le comportement actuel. */
.cells { display: flex; flex-direction: column; gap: 0.9rem; overflow-x: clip; }
@media (max-width: 960px) { .cells { flex-direction: row; flex-wrap: wrap; } .cells .cell { flex: 1 1 14rem; } }
.cell {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 1.15rem 1.25rem;
  animation: cell-in 0.9s var(--ease-out) both;
}
.cell:nth-child(2) { animation-delay: 140ms; }
.cell:nth-child(3) { animation-delay: 280ms; }
@keyframes cell-in {
  from { opacity: 0; transform: translateX(42px); }
  to   { opacity: 1; transform: none; }
}
.cell .cell-id {
  font-family: var(--font-grotesk);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted-fg);
  display: block;
  margin-bottom: 0.55rem;
}
.cell .cell-val {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}
.cell .bar {
  height: 2px; width: 72px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
  align-self: center;
}
.cell .bar i {
  display: block; height: 100%; width: 60%;
  background: var(--accent);
  animation: bar-slide 2.6s var(--ease-out) infinite alternate;
}
@keyframes bar-slide { from { transform: translateX(-30%); } to { transform: translateX(70%); } }
.cell .cell-rows { display: grid; gap: 0.45rem; margin-top: 0.2rem; }
.cell .cell-rows div {
  display: flex; justify-content: space-between;
  font-family: var(--font-grotesk);
  font-size: 0.68rem;
  color: var(--muted-fg);
  border-top: 1px solid var(--border);
  padding-top: 0.45rem;
}
.cell .cell-rows div:first-child { border-top: 0; padding-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .hero-main, .cell { animation: none; }
  .hero-kicker .dot::after, .cell .bar i { animation: none; }
}

/* Catalogue : quatre entrées, quatre blocs identiques.
   La mosaïque précédente (vedette 2×2 + satellites + bande pleine largeur)
   donnait des hauteurs dictées les unes par les autres : la vedette prenait
   la hauteur des deux satellites empilés et ouvrait un grand vide sous son
   texte, et la bande finale ne ressemblait à aucune autre carte. Ici la
   grille fait deux colonnes, `grid-auto-rows: 1fr` égalise les rangées, et
   chaque visuel garde le même 16/9 — les blocs sont homogènes par
   construction, quelle que soit la longueur des textes.

   Les classes `--feature` et `--wide` restent dans le HTML sans effet : le
   markup n'a pas bougé, donc un visiteur encore servi par `style.14.css`
   retrouve exactement la mosaïque d'avant plutôt qu'une mise en page à
   moitié appliquée. */
@media (min-width: 861px) {
  .work-grid {
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: 1fr;
  }
}


/* --------------------------------------------------------------------------
   20. v7 — page produit CardRadar (/cardradar)
   Panneaux recréés depuis les visuels App Store du studio.
   -------------------------------------------------------------------------- */
.pp-hero { padding-block: clamp(3rem, 7vw, 5rem) clamp(2rem, 4vw, 3rem); border-bottom: 1px solid var(--border); }
.pp-hero .kicker { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.pp-hero .app-badge { width: 64px; height: 64px; border-radius: 15px; }
.pp-hero h1 { font-size: clamp(2.4rem, 1.6rem + 3.6vw, 4.4rem); letter-spacing: -0.04em; }
.pp-hero .tagline { font-size: clamp(1.1rem, 1rem + 0.6vw, 1.4rem); color: var(--secondary); margin-top: 0.9rem; max-width: 38rem; }

.pp-feature {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: center;
  padding-block: clamp(2.5rem, 6vw, 4.5rem);
}
.pp-feature + .pp-feature { border-top: 1px solid var(--border); }
.pp-feature:nth-child(even) .pp-copy { order: 2; }
@media (max-width: 880px) {
  .pp-feature { grid-template-columns: 1fr; }
  .pp-feature:nth-child(even) .pp-copy { order: 0; }
}
.pp-copy h2 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem); margin-bottom: 0.9rem; }
.pp-copy p { color: var(--secondary); max-width: 30rem; }

/* Le panneau : fond marketing bleu nuit, carte blanche arrondie. */
.pp-panel {
  border-radius: 20px;
  background: linear-gradient(165deg, #071427, #0a1f3d 55%, #10345f);
  padding: clamp(1.5rem, 3.5vw, 2.75rem);
  box-shadow: 0 30px 70px -35px rgba(7, 20, 39, 0.55);
}
.pp-card {
  background: #fff;
  color: #111;
  border-radius: 20px;
  padding: clamp(1.1rem, 2.2vw, 1.5rem);
  box-shadow: 0 24px 60px -24px rgba(0,0,0,.5);
  font-size: 0.92rem;
}
.pp-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.8rem; }
.pp-chip {
  font-size: 0.8rem; font-weight: 600;
  padding: 0.42rem 0.95rem; border-radius: 999px;
  background: #f0f1f3; color: #1c1c1e;
}
.pp-chip.on { background: #0a84ff; color: #fff; }
.pp-lbl { font-size: 0.78rem; color: #6b7280; font-weight: 600; margin: 0.35rem 0 0.45rem; }

.pp-markets { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 0.6rem; }
@media (max-width: 480px) { .pp-markets { grid-template-columns: 1fr; } }
.pp-m { background: #f4f5f7; border-radius: 14px; padding: 0.95rem; }
.pp-m .h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 0.45rem; }
.pp-m .n { font-weight: 700; font-size: 0.98rem; }
.pp-m .c { font-size: 0.75rem; color: #6b7280; font-weight: 600; }
.pp-m .k { font-size: 0.74rem; color: #6b7280; margin-top: 0.45rem; }
.pp-m .v { font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; }
.pp-m .v2 { font-size: 1.05rem; font-weight: 700; }
.pp-m .note { font-size: 0.68rem; color: #8a919c; line-height: 1.35; margin-top: 0.15rem; }
.pp-m .ok { font-size: 0.72rem; font-weight: 700; color: #1d9a52; margin-top: 0.5rem; line-height: 1.3; }

.pp-price-big { font-size: 2.1rem; font-weight: 800; letter-spacing: -0.02em; }
.pp-verdict { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.pp-verdict .word { font-size: 1.5rem; font-weight: 700; color: #6b7280; }
.pp-score { font-size: 0.8rem; font-weight: 700; }
.pp-scorebar { height: 6px; border-radius: 3px; background: #e8e9ec; overflow: hidden; margin-top: 0.3rem; width: 110px; }
.pp-scorebar i { display: block; height: 100%; width: 20%; background: #6b7280; border-radius: 3px; }
.pp-bullets { margin: 0.6rem 0 0; padding: 0; list-style: none; font-size: 0.85rem; font-weight: 600; }
.pp-bullets li { padding: 0.15rem 0; }
.pp-meta { font-size: 0.76rem; color: #8a919c; margin-top: 0.7rem; line-height: 1.5; }
.pp-block { background: #f4f5f7; border-radius: 14px; padding: 0.95rem; }
.pp-block + .pp-block { margin-top: 0.75rem; }

.pp-total { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; }
.pp-total .lab { font-size: 0.85rem; color: #6b7280; }
.pp-cta-chip { background: #0a84ff; color: #fff; font-size: 0.8rem; font-weight: 700; padding: 0.45rem 1rem; border-radius: 999px; }
.pp-gain { color: #1d9a52; font-weight: 700; font-size: 0.85rem; margin-top: 0.2rem; }
.pp-row { display: flex; align-items: center; gap: 0.7rem; padding: 0.55rem 0; border-top: 1px solid #eceef1; }
.pp-thumb { width: 34px; height: 47px; border-radius: 4px; background: linear-gradient(150deg, #cdd6e2, #9fb0c5); flex: 0 0 auto; }
.pp-row .rn { font-weight: 700; font-size: 0.85rem; }
.pp-row .rm { font-size: 0.74rem; color: #6b7280; }
.pp-row .rv { margin-left: auto; font-weight: 700; font-size: 0.85rem; white-space: nowrap; }

.pp-banner { background: #f4f5f7; border-radius: 12px; padding: 0.8rem 0.95rem; font-size: 0.82rem; }
.pp-banner .mut { color: #8a919c; display: block; margin-bottom: 0.2rem; }
.pp-list-h { font-size: 0.8rem; font-weight: 700; color: #6b7280; margin: 0.8rem 0 0.2rem; }
.pp-opp { display: flex; justify-content: space-between; gap: 0.8rem; padding: 0.45rem 0; border-bottom: 1px solid #eceef1; font-size: 0.85rem; }
.pp-opp b { display: block; }
.pp-opp .why { font-size: 0.76rem; color: #6b7280; font-weight: 400; }
.pp-opp .sc { font-weight: 700; }

.pp-search { background: #f0f1f3; border-radius: 10px; padding: 0.65rem 0.9rem; font-size: 0.95rem; color: #111; margin-bottom: 0.7rem; }
.pp-note {
  font-family: var(--font-grotesk);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  color: var(--muted-fg);
  margin-top: 0.9rem;
}
.pp-cta-band { text-align: center; padding-block: clamp(2.5rem, 6vw, 4rem); border-top: 1px solid var(--border); }

.pp-panel .pp-note { color: rgba(255,255,255,0.55); }

/* Logo pixel 12x10 : ne pas l'ecraser en carre */
.brand img { width: 30px; height: 24px; }
