/*
Theme Name: Alice Gerfault
Theme URI: https://alice-gerfault.com
Author: Alice Gerfault
Description: Thème bloc pour alice-gerfault.com — patrons jacquard modernes.
Version: 1.6.21
Requires at least: 6.6
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: alice-gerfault
Tags: full-site-editing, block-themes, e-commerce
*/

@layer tokens, base, components, wp-overrides, utilities;

@layer tokens {
  /* =============================================
   DESIGN TOKENS — mapped from --wp--preset--*
   ============================================= */

  :root {
    --ag-ink: var(--wp--preset--color--ink, #142033);
    --ag-ink-soft: var(--wp--preset--color--ink-soft, #4b5563);
    --ag-accent: var(--wp--preset--color--accent, #d0008b);
    --ag-paper: var(--wp--preset--color--paper, #fff);
    --ag-deep-navy: var(--wp--preset--color--deep-navy, #101a2a);
    --ag-mint: var(--wp--preset--color--mint, #ddeee8);
    --ag-blue-ice: var(--wp--preset--color--blue-ice, #e5f0f2);
    --ag-rose: var(--wp--preset--color--rose, #f8dbef);
    --ag-rule: var(--wp--preset--color--rule, #d8dedc);
    --ag-secondary: var(--wp--preset--color--secondary, #1d4a3a);
    --ag-on-dark: var(--wp--preset--color--on-dark, #b8c0c7);
    --ag-paper-deep: color-mix(in srgb, var(--ag-ink) 3%, var(--ag-paper));
    --ag-rule-strong: color-mix(in srgb, var(--ag-ink) 24%, var(--ag-paper));
    --ag-accent-deep: #a8006f; /* darkened accent for hover/active states */
    --ag-rule-dark: #465365; /* hairline rules/borders on dark sections */
    --ag-cream: #f4eee0; /* warm off-white text on dark sections */
    --ag-font-display: var(
      --wp--preset--font-family--instrument-serif,
      "Instrument Serif",
      Georgia,
      serif
    );
    --ag-font-body: var(
      --wp--preset--font-family--manrope,
      "Manrope",
      system-ui,
      sans-serif
    );

    /* System mono on purpose: the bundled JetBrains Mono woff2 was Google's
       latin-ext subset — no digits, no lowercase — so every eyebrow, label and
       price already fell back to the system face. Dropped the face rather than
       shipping a second one, which keeps the rendering identical. */
    --ag-font-mono: ui-monospace, "Cascadia Code", monospace;
    --ag-font-brand: var(
      --wp--preset--font-family--prata,
      "Prata",
      "Cormorant Garamond",
      Georgia,
      serif
    );

    /* --- Type scale: sizes (mirror theme.json fontSizes presets) --- */
    --ag-text-xxs: var(--wp--preset--font-size--xxs, 10.5px);
    --ag-text-xs: var(--wp--preset--font-size--eyebrow, 11.5px);
    --ag-text-cap: var(--wp--preset--font-size--cap, 12.5px);
    --ag-text-sm: var(--wp--preset--font-size--small, 14px);
    --ag-text-base: var(--wp--preset--font-size--body, 16px);
    --ag-text-md: var(--wp--preset--font-size--md, 18px);
    --ag-text-lg: var(--wp--preset--font-size--lg, 20px);
    --ag-text-xl: var(--wp--preset--font-size--xl, 24px);
    --ag-text-xxl: var(--wp--preset--font-size--xxl, 28px);
    --ag-text-xxxl: var(--wp--preset--font-size--xxxl, 32px);
    --ag-text-huge: var(--wp--preset--font-size--huge, 40px);
    --ag-text-lede: var(
      --wp--preset--font-size--lede,
      clamp(18px, 1.5vw, 22px)
    );
    --ag-text-display-s: var(
      --wp--preset--font-size--display-s,
      clamp(28px, 2.6vw, 40px)
    );
    --ag-text-display-m: var(
      --wp--preset--font-size--display-m,
      clamp(36px, 4.2vw, 64px)
    );
    --ag-text-display-l: var(
      --wp--preset--font-size--display-l,
      clamp(44px, 5.8vw, 88px)
    );
    --ag-text-display-xl: var(
      --wp--preset--font-size--display-xl,
      clamp(56px, 7.6vw, 124px)
    );

    /* Named display outliers — deliberate one-offs kept off the snap scale */
    --ag-text-marquee: 44px;
    --ag-text-hero-stat: 84px;
    --ag-text-shop-hero: clamp(52px, 8.4vw, 142px);
    --ag-text-shop-tech-tile: clamp(40px, 3.6vw, 58px);

    /* Brand lockup (Prata "Alice / Gerfault"): three size stops tuned per
       placement — nav header, mobile drawer, footer. Off-snap because the
       glyphs are proprietary display type, not the utility scale. */
    --ag-text-brand-nav: 29px;
    --ag-text-brand-nav-sm: 21px;
    --ag-text-brand-drawer: 26px;
    --ag-text-brand-footer: 21px;

    /* --- Type scale: weights --- */
    --ag-weight-normal: 400;
    --ag-weight-medium: 500;
    --ag-weight-semibold: 600;
    --ag-weight-bold: 700;

    /* --- Type scale: tracking (letter-spacing) --- */
    --ag-tracking-tight: -0.02em;
    --ag-tracking-snug: -0.01em;
    --ag-tracking-brand: 0.01em;
    --ag-tracking-normal: 0;
    --ag-tracking-wide: 0.02em;
    --ag-tracking-label: 0.1em;
    --ag-tracking-eyebrow: 0.16em;
    --ag-tracking-eyebrow-lg: 0.18em;

    /* --- Type scale: leading (line-height) --- */
    --ag-leading-none: 1;
    --ag-leading-brand: 1.05;
    --ag-leading-hero: 0.9;
    --ag-leading-display: 0.98;
    --ag-leading-tight: 1.1;
    --ag-leading-snug: 1.15;
    --ag-leading-base: 1.55;
    --ag-leading-relaxed: 1.6;

    /* Hors échelle nommé, comme --ag-text-marquee côté tailles : l'exergue de
       la page À propos tombe entre le serré des titres (1,15) et l'aéré du
       corps (1,55), et aucun cran existant ne rend ce registre. */
    --ag-leading-exergue: 1.4;

    /* --- Spacing scale ---
     Fine numeric scale for component micro-spacing (gaps/padding/margin).
     The three section-level steps mirror theme.json's editor presets
     (md 56 / lg 80 / section 120) and alias the generated --wp--preset--spacing--*
     so the two scales cannot drift; the finer steps are CSS-only literals
     theme.json's coarse preset list cannot express. See KTD-1. */
    --ag-space-3xs: 4px;
    --ag-space-2xs: 8px;
    --ag-space-xs: 12px;
    --ag-space-sm: 16px;
    --ag-space-md: 20px;
    --ag-space-lg: 24px;
    --ag-space-xl: 32px;
    --ag-space-2xl: 40px;
    --ag-space-3xl: 48px;
    --ag-space-4xl: 56px;
    --ag-space-5xl: 80px;
    --ag-space-tight: 46px;
    --ag-space-section: 30px;

    /* Measured height of the sticky site header on desktop: .nav-inner's 20px
       block padding x 2 + the 62px brand mark + .ag-nav's 1px border-bottom is
       only 103px -- what actually sets the height is .nav-links, whose 37.7px
       row plus 16px block margins outgrows the brand mark (110.7px total,
       rounded up). Not expressible as a calc() since the row is font-metric
       sized. Anything that must clear the header (sticky rails, scroll-margin
       on anchor targets) offsets from this rather than guessing with a spacing
       step. Under 900px the nav links collapse and the real header is 95px, so
       this overshoots there -- harmless extra breathing room. */
    --ag-header-h: 112px;

    /* --- Radius --- */
    --ag-radius-sm: 2px;
    --ag-radius-md: 4px;
    --ag-radius-pill: 999px;

    /* --- Z-index scale --- */
    --ag-z-raised: 2;
    --ag-z-sticky: 50;
    --ag-z-overlay: 9000;
    --ag-z-max: 9999;

    /* --- Elevation (shadow) --- */
    --ag-shadow-md: 0 14px 32px rgb(0 0 0 / 12%);
    --ag-shadow-lg:
      0 40px 80px -20px rgb(20 32 51 / 25%), 0 0 0 1px rgb(20 32 51 / 6%);

    /* --- Motion (duration / easing) --- */
    --ag-dur-fast: 0.15s;
    --ag-dur-base: 0.2s;
    --ag-dur-slow: 0.35s;
    --ag-ease: cubic-bezier(0.2, 0.6, 0.2, 1);
  }
}

@layer base {
  /* =============================================
   BASE RESET
   ============================================= */

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

  body {
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink);
    text-rendering: optimizelegibility;

    background: var(--ag-paper);

    -webkit-font-smoothing: antialiased;
  }

  a {
    color: inherit;
    text-decoration: none;
  }

  button {
    cursor: pointer;
    font: inherit;
  }

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

@layer components {
  /* =============================================
   LAYOUT
   ============================================= */

  .ag-wrap {
    max-width: 1480px;
    margin-right: auto;
    margin-left: auto;
    padding-right: var(--ag-space-2xl);
    padding-left: var(--ag-space-2xl);
  }

  .section {
    padding-top: var(--ag-space-section);
    padding-bottom: var(--ag-space-section);
  }

  .section-tight {
    padding-top: var(--ag-space-tight);
    padding-bottom: var(--ag-space-tight);
  }

  /* ---------------------------------------------------------------------------
   Auto grid primitive — responsive multi-column grid that collapses
   3 -> 2 -> 1 at 900 / 720. Column count via --cols (default 3), gap via
   --grid-gap (default xl). Shared by the editorial 3-col grids. The 4-col
   product grids (.reco-row / .commu-cards / .ressource-grid) use a distinct
   4 -> 2 -> 1 collapse at 900 / 560 and are kept as their own group below.
   Container queries are the eventual fit here (deferred — see plan U6).
   --------------------------------------------------------------------------- */
  .grid-auto,
  .patrons-grid,
  .preuves-grid,
  .journal-grid,
  .reco-row,
  .commu-cards,
  .ressource-grid {
    display: grid;
    grid-template-columns: repeat(var(--cols, 3), 1fr);
    gap: var(--grid-gap, var(--ag-space-xl));
  }

  /* =============================================
   TYPOGRAPHY
   ============================================= */

  /*
 * Canonical type classes. Authors compose THESE in markup; the --ag-text-*,
 * --ag-weight-*, --ag-tracking-*, --ag-leading-* tokens are the layer these
 * classes consume. Do not reintroduce raw px / weight / em literals here.
 */

  /* Eyebrow — mono uppercase kicker */
  .eyebrow {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  .eyebrow-ink {
    color: var(--ag-ink);
  }

  .eyebrow-accent {
    color: var(--ag-accent);
  }

  /* Label — mono uppercase tracked label (tags, hints, switches) */
  .label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .label-sm {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  /* Body copy */
  .body {
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
  }

  .body-sm {
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
  }

  .caption {
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-cap);
    line-height: var(--ag-leading-base);
  }

  .lede {
    max-width: 56ch;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-lede);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .display {
    font-family: var(--ag-font-display);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-display);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .display-xl {
    font-size: var(--ag-text-display-xl);
  }

  .display-l {
    font-size: var(--ag-text-display-l);
  }

  .display-m {
    font-size: var(--ag-text-display-m);
  }

  .display-s {
    font-size: var(--ag-text-display-s);
  }

  .serif-it {
    font-family: var(--ag-font-display);
    font-style: italic;
  }

  .price-tag {
    font-family: var(--ag-font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--ag-tracking-snug);
  }

  .muted {
    color: var(--ag-ink-soft);
  }

  .note-hand {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-base);
    font-style: italic;
    color: var(--ag-accent);
  }

  .scroll-hint {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: center;

    margin-top: var(--ag-space-4xl);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .scroll-hint::before {
    content: "";

    display: inline-block;
    flex-shrink: 0;

    width: 24px;
    height: 1px;

    background: currentcolor;
  }

  /* =============================================
   BUTTONS
   ============================================= */

  /* ---------------------------------------------------------------------------
   Button system — single source of truth.
   Appearance is driven by --btn-* custom properties so all three entry points
   share ONE recipe: standalone .btn, the core block button
   (.wp-block-button.btn .wp-block-button__link, see BLOCK BUTTON GLOBAL), and
   the nav Panier pill (.ag-nav .btn). Variant classes only flip the --btn-*
   values; because custom properties inherit, setting them on the
   .wp-block-button WRAPPER (which always also carries .btn) propagates to the
   inner .wp-block-button__link. The colour/size literals therefore live here
   once, not in three recipes.
   --------------------------------------------------------------------------- */

  /* Default (primary) values — set on the standalone element and the block wrapper */
  .btn,
  .wp-block-button.btn {
    --btn-bg: var(--ag-ink);
    --btn-fg: var(--ag-paper);
    --btn-border: var(--ag-ink);
    --btn-bg-hover: var(--ag-accent);
    --btn-fg-hover: var(--ag-paper);
    --btn-border-hover: var(--ag-accent);
    --btn-pad: var(--ag-space-sm) var(--ag-space-lg);
    --btn-gap: var(--ag-space-xs);
    --btn-font-size: var(--ag-text-sm);
  }

  /* Ghost variant */
  .btn-ghost,
  .wp-block-button.btn-ghost {
    --btn-bg: transparent;
    --btn-fg: var(--ag-ink);
    --btn-border: var(--ag-ink);
    --btn-bg-hover: var(--ag-ink);
    --btn-fg-hover: var(--ag-paper);
    --btn-border-hover: var(--ag-ink);
  }

  /* Accent variant */
  .btn-accent,
  .wp-block-button.btn-accent {
    --btn-bg: var(--ag-accent);
    --btn-fg: var(--ag-paper);
    --btn-border: var(--ag-accent);
    --btn-bg-hover: var(--ag-accent-deep);
    --btn-border-hover: var(--ag-accent-deep);
  }

  /* Small variant */
  .btn-sm,
  .wp-block-button.btn-sm {
    --btn-pad: var(--ag-space-xs) var(--ag-space-sm);
    --btn-font-size: var(--ag-text-cap);
  }

  /* Ghost variant on dark bands — value-flips inherit to both standalone and block */
  .band-dark .btn-ghost,
  .band-dark .wp-block-button.btn-ghost {
    --btn-border: rgb(255 255 255 / 40%);
    --btn-fg: var(--ag-paper);
    --btn-bg-hover: var(--ag-paper);
    --btn-fg-hover: var(--ag-deep-navy);
    --btn-border-hover: var(--ag-paper);
  }

  /* Standalone button appearance — reads the --btn-* values above */
  .btn {
    cursor: pointer;

    display: inline-flex;
    gap: var(--btn-gap);
    align-items: center;

    padding: var(--btn-pad);
    border: 1px solid var(--btn-border);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--btn-font-size);
    font-weight: var(--ag-weight-medium);
    color: var(--btn-fg);
    text-decoration: none;
    letter-spacing: var(--ag-tracking-wide);

    background: var(--btn-bg);

    transition:
      transform var(--ag-dur-base) ease,
      background var(--ag-dur-base) ease,
      border-color var(--ag-dur-base) ease,
      color var(--ag-dur-base) ease;
  }

  .btn:hover {
    transform: translateY(-1px);
    border-color: var(--btn-border-hover);
    color: var(--btn-fg-hover);
    background: var(--btn-bg-hover);
  }

  .btn-arrow {
    display: inline-block;
    transition: transform var(--ag-dur-base) ease;
  }

  .btn:hover .btn-arrow {
    transform: translateX(4px);
  }

  /* =============================================
   CHIPS
   ============================================= */

  .chip {
    cursor: pointer;

    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    padding: var(--ag-space-2xs) var(--ag-space-xs);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);

    background: transparent;

    transition: all var(--ag-dur-base) ease;
  }

  .chip:hover,
  .chip-active {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(--ag-ink);
  }

  .chip-soft {
    border-color: rgb(208 0 139 / 35%);
    color: var(--ag-accent);
    background: var(--ag-blue-ice);
  }

  .chip-sage {
    border-color: rgb(29 74 58 / 25%);
    color: var(--ag-secondary);
    background: var(--ag-mint);
  }

  /* =============================================
   IMAGE SLOT
   ============================================= */

  .slot {
    position: relative;

    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;

    border-radius: var(--ag-radius-sm);

    background:
      repeating-linear-gradient(
        135deg,
        rgb(43 37 32 / 4%) 0,
        rgb(43 37 32 / 4%) 1px,
        transparent 1px,
        transparent 14px
      ),
      var(--ag-paper);
  }

  .slot img {
    position: absolute;
    inset: 0;

    width: 100%;

    /* WooCommerce ships an unlayered `.woocommerce img { height: auto }`
       (woocommerce-layout.css) that outranks any @layer rule, collapsing the
       image to its intrinsic ratio and exposing the hatch below a non-square
       slot. !important is the documented escape hatch (see DESIGN.md). */
    height: 100% !important;

    object-fit: cover;
  }

  /* ---------------------------------------------------------------------------
   Overlay label primitive — mono-uppercase pill on imagery (tags, counts,
   timestamps). The shared recipe lives once here; each use adds only its
   position offsets and, for light-on-image variants, its colour/background.
   .u-overlay-label is the canonical name for new markup; the existing
   component classes compose the same recipe to avoid pattern churn (KTD-3).
   --------------------------------------------------------------------------- */
  .u-overlay-label,
  .slot-tag,
  .gallery-label,
  .preuve-num {
    position: absolute;

    padding: var(--ag-space-3xs) var(--ag-space-2xs);
    border-radius: var(--ag-radius-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);

    background: rgb(0 0 0 / 45%);
  }

  /* Slot tag — light pill, bottom-left */
  .slot-tag {
    bottom: 12px;
    left: 14px;

    color: var(--ag-ink-soft);

    background: rgb(255 255 255 / 90%);
    backdrop-filter: blur(4px);
  }

  /* =============================================
   CARD LINK
   ============================================= */

  .card-link {
    display: block;
    color: inherit;
    text-decoration: none;
    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .card-link:hover {
    transform: translateY(-4px);
  }

  .card-link .slot {
    transition: filter var(--ag-dur-slow) ease;
  }

  .card-link:hover .slot {
    filter: brightness(0.96) contrast(1.02);
  }

  .card-link:hover .journal-post-title,
  .card-link:hover .journal-post-title a {
    color: var(--ag-accent);
  }

  /* =============================================
   BANDS (full-width color sections)
   ============================================= */

  .band {
    width: 100%;
    padding-top: var(--ag-space-section);
    padding-bottom: var(--ag-space-section);
  }

  .band-dark {
    color: var(--ag-paper);
    background-color: var(--ag-deep-navy);
  }

  .band-dark .eyebrow {
    color: var(--ag-on-dark);
  }

  .band-dark .eyebrow-accent {
    color: var(--ag-accent);
  }

  .band-dark .lede {
    color: var(--ag-on-dark);
  }

  .band-dark .display {
    color: var(--ag-paper);
  }

  .band-dark h1,
  .band-dark h2,
  .band-dark h3,
  .band-dark h4 {
    color: var(--ag-paper);
  }

  .band-dark .chip {
    border-color: var(--ag-rule-dark);
    color: var(--ag-on-dark);
  }

  .band-dark .chip:hover,
  .band-dark .chip-active {
    border-color: var(--ag-paper);
    color: var(--ag-deep-navy);
    background: var(--ag-paper);
  }

  .band-dark .btn-ghost {
    border-color: rgb(255 255 255 / 40%);
    color: var(--ag-paper);
  }

  .band-dark .btn-ghost:hover {
    border-color: var(--ag-paper);
    color: var(--ag-deep-navy);
    background: var(--ag-paper);
  }

  /* Solid button on a dark band — value-flips the --btn-* contract rather than
     adding a variant class, as .band-dark .btn-ghost already does. No dark band
     carried a solid button before the home vedette block; cream-on-ink keeps it
     readable, and the accent hover matches the light-background behaviour.

     The :not() exclusions are load-bearing: every variant also carries .btn, so
     an unscoped `.band-dark .btn` (0,2,0) would outrank `.btn-ghost` (0,1,0) and
     fill the seven ghost buttons on the home — and two more on /jacquard-moderne/
     — with cream. */
  .band-dark .btn:not(.btn-ghost, .btn-accent),
  .band-dark .wp-block-button.btn:not(.btn-ghost, .btn-accent) {
    --btn-bg: var(--ag-cream);
    --btn-fg: var(--ag-ink);
    --btn-border: var(--ag-cream);
    --btn-bg-hover: var(--ag-accent);
    --btn-fg-hover: var(--ag-paper);
    --btn-border-hover: var(--ag-accent);
  }

  /* Vedette block on a dark band. The block is shared verbatim with /boutique/,
     so only the colours that assume a paper background are re-pointed here —
     --ag-ink-soft is unreadable on deep navy. Values transcribed from the
     mockup's .on-ink block; its --text-on-dark-secondary is #B8C0C7, i.e. this
     theme's --ag-on-dark. The cream tints stay literal rather than introducing
     an --ag-cream-rgb token (KTD6), as .marquee-dot already does. */
  .band-dark .shop-icon-badge {
    color: var(--ag-accent);
  }

  .band-dark .shop-icon-title {
    color: var(--ag-cream);
  }

  .band-dark .shop-icon-text {
    color: var(--ag-on-dark);
  }

  .band-dark .shop-icon-others-label,
  .band-dark .shop-icon-other-reason {
    color: rgb(244 238 224 / 60%);
  }

  .band-dark .shop-icon-other-arrow {
    color: rgb(244 238 224 / 50%);
  }

  .band-dark .shop-icon-other-item {
    border-bottom-color: rgb(244 238 224 / 16%);
    color: var(--ag-cream);
  }

  .band-dark .shop-icon-other-item:first-child {
    border-top-color: rgb(244 238 224 / 16%);
  }

  /* :focus-visible doubles :hover throughout the theme (.hub-porte, .hub-frise-item)
     so keyboard users get the same affordance the mockup only gave the mouse. */
  .band-dark .shop-icon-other-item:hover,
  .band-dark .shop-icon-other-item:focus-visible {
    color: var(--ag-accent);
  }

  .band-dark .shop-icon-other-item:hover .shop-icon-other-arrow,
  .band-dark .shop-icon-other-item:focus-visible .shop-icon-other-arrow {
    color: var(--ag-accent);
  }

  .band-dark a {
    color: var(--ag-paper);
  }

  .band-mint {
    background-color: var(--ag-mint);
  }

  /* =============================================
   NAVIGATION
   ============================================= */

  /* The header template part renders as <header class="wp-block-template-part">.
   Sticky must live on that wrapper — if it lives on .ag-nav, the nav's
   containing block is exactly its own height, leaving no room to stick.
   Target the <header> tag directly (only the header part uses it) rather than
   :has(.ag-nav), so stickiness doesn't depend on :has() support on mobile. */
  header.wp-block-template-part {
    position: sticky;

    /* Must outrank .patron-catalog__filterbar (also z-sticky): both are
       sticky siblings at the same stacking level, so without this the
       mega-menu panel — which overflows below the header — would be
       painted under the later-in-DOM filter bar. */
    z-index: var(--ag-z-overlay);
    top: 0;
  }

  .ag-nav {
    position: relative;

    width: 100%;
    border-bottom: 1px solid var(--ag-rule);

    background: color-mix(in srgb, var(--ag-paper) 86%, transparent);
    backdrop-filter: blur(14px);
  }

  .ag-nav .nav-inner {
    display: flex;
    gap: var(--ag-space-lg);
    align-items: center;
    justify-content: space-between;

    max-width: 1480px;
    margin: 0 auto;
    padding: var(--ag-space-md) var(--ag-space-2xl);
  }

  /* Brand lockup: [SVG mark] | [Alice / Gerfault stacked in Prata] */
  .nav-brand,
  .footer-brand {
    display: inline-flex;
    flex-shrink: 0;
    gap: 18px;
    align-items: center;

    color: var(--ag-ink);
    text-decoration: none;
  }

  .nav-brand .nav-brand-mark,
  .footer-brand .nav-brand-mark {
    display: block;
    width: 62px;
    height: 62px;
  }

  /* Thin pink separator drawn in CSS — stays razor-crisp at any size. */
  .nav-brand .nav-brand-sep,
  .footer-brand .nav-brand-sep {
    flex: none;
    width: 2px;
    height: 57px;
    background: var(--ag-accent);
  }

  .nav-brand .nav-brand-text,
  .footer-brand .nav-brand-text {
    display: inline-flex;
    flex-direction: column;
    gap: 0;

    font-family: var(--ag-font-brand);
    font-size: var(--ag-text-brand-nav);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-brand);
    letter-spacing: var(--ag-tracking-brand);
  }

  /* Nav links */
  .nav-links {
    display: flex;
    gap: var(--ag-space-xl);
    align-items: center;
  }

  .nav-item {
    display: flex;
    align-items: center;
  }

  .nav-item .nav-link {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;
  }

  .nav-link {
    position: relative;

    padding: var(--ag-space-2xs) 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-ink);
    text-decoration: none;
  }

  .nav-link::after {
    content: "";

    position: absolute;
    bottom: 0;
    left: 0;

    width: 0;
    height: 1px;

    background: var(--ag-ink);

    transition: width var(--ag-dur-base) ease;
  }

  .nav-link:hover::after,
  .nav-link.active::after {
    width: 100%;
  }

  .nav-link.nav-icon::after {
    display: none;
  }

  .nav-icon {
    display: inline-flex;
    align-items: center;
  }

  .nav-caret {
    transform: rotate(45deg) translateY(-2px);

    display: inline-block;

    width: 8px;
    height: 8px;
    border-right: 1.4px solid currentcolor;
    border-bottom: 1.4px solid currentcolor;

    transition: transform var(--ag-dur-base) ease;
  }

  .nav-item:hover .nav-caret {
    transform: rotate(225deg) translateY(-1px);
  }

  /* Right cluster */
  .nav-cta {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: center;
  }

  /* Account icon — logged-in dot + dropdown. The icon itself is a plain
     .nav-icon; .nav-account only owns the positioning context and the two
     states assets/js/nav.js toggles after hydration (the server markup is
     identical for every visitor — see inc/account-state.php). */
  .nav-account {
    position: relative;
  }

  .ag-account-dot {
    position: absolute;
    top: 6px;
    right: 6px;
    transform: scale(0.6);

    width: 7px;
    height: 7px;
    border: 1.5px solid var(--ag-paper);
    border-radius: 50%;

    opacity: 0;
    background: var(--ag-accent);

    transition:
      opacity var(--ag-dur-base) var(--ag-ease),
      transform var(--ag-dur-base) var(--ag-ease);
  }

  .nav-account.is-logged .ag-account-dot {
    transform: scale(1);
    opacity: 1;
  }

  .ag-account-dropdown {
    position: absolute;
    z-index: var(--ag-z-sticky);
    top: calc(100% + var(--ag-space-sm));
    right: 0;

    width: 220px;
    padding: var(--ag-space-2xs);
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
    box-shadow: var(--ag-shadow-md);
  }

  .ag-account-hello {
    margin: 0 0 var(--ag-space-3xs);
    padding: var(--ag-space-2xs) var(--ag-space-xs) var(--ag-space-3xs);
    border-bottom: 1px solid var(--ag-rule);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  .ag-account-dropdown a {
    display: flex;
    align-items: center;

    min-height: 44px;
    padding: 0 var(--ag-space-xs);
    border-radius: var(--ag-radius-sm);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink);
    text-decoration: none;

    transition: background var(--ag-dur-fast) ease;
  }

  .ag-account-dropdown a:hover {
    background: var(--ag-paper-deep);
  }

  .ag-account-dropdown a.ag-account-logout {
    margin-top: var(--ag-space-3xs);
    padding-top: var(--ag-space-3xs);
    border-top: 1px solid var(--ag-rule);

    font-weight: var(--ag-weight-medium);
    color: var(--ag-accent-deep);
  }

  /* Header search: icon-sized at rest, expanding into a real field. `:focus-within`
     carries the keyboard path on its own, so the field stays reachable without JS;
     nav.js adds `.is-open` for the pointer path. It replaced a link to `/?s=`,
     which is a search for the empty string and returns no results. */
  .nav-search {
    display: flex;
    align-items: center;

    border: 1px solid transparent;
    border-radius: var(--ag-radius-pill);

    transition:
      border-color var(--ag-dur-base) var(--ag-ease),
      background-color var(--ag-dur-base) var(--ag-ease);
  }

  .nav-search:focus-within,
  .nav-search.is-open {
    border-color: var(--ag-rule-strong);
    background: var(--ag-paper);
  }

  .nav-search-input {
    width: 0;
    min-width: 0;
    padding: 0;
    border: 0;
    border-radius: 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink);

    appearance: none;
    opacity: 0;
    background: transparent;

    transition:
      width var(--ag-dur-base) var(--ag-ease),
      padding var(--ag-dur-base) var(--ag-ease),
      opacity var(--ag-dur-base) var(--ag-ease);
  }

  .nav-search-input::-webkit-search-decoration,
  .nav-search-input::-webkit-search-cancel-button,
  .nav-search-input::-webkit-search-results-button,
  .nav-search-input::-webkit-search-results-decoration {
    appearance: none;
  }

  .nav-search:focus-within .nav-search-input,
  .nav-search.is-open .nav-search-input {
    width: 200px;
    padding: var(--ag-space-3xs) 0 var(--ag-space-3xs) var(--ag-space-sm);
    opacity: 1;
    background: var(--ag-paper);
  }

  .nav-search-input:focus {
    background: var(--ag-paper);
    outline: none;
    box-shadow: none;
  }

  .nav-search-input::placeholder {
    color: var(--ag-ink-soft);
  }

  .nav-search-btn {
    cursor: pointer;

    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;

    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;

    color: var(--ag-ink);

    background: transparent;
  }

  .lang-switch {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    padding: var(--ag-space-3xs) var(--ag-space-xs);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lang-switch button,
  .lang-switch a {
    cursor: pointer;

    padding: var(--ag-space-3xs) 0;
    border: 0;

    font: inherit;
    color: var(--ag-ink-soft);
    text-decoration: none;
    letter-spacing: inherit;

    background: none;

    transition: color var(--ag-dur-fast) ease;
  }

  .lang-switch button.on,
  .lang-switch a.on {
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  .lang-switch button:hover,
  .lang-switch a:hover {
    color: var(--ag-ink);
  }

  .lang-sep {
    color: var(--ag-ink-soft);
  }

  /* Panier pill — nav delta only: tighter gap. Full recipe + ghost/sm variants
   inherit from the .btn system above (.btn-sm / .btn-ghost set their own --btn-*). */
  .ag-nav .btn {
    --btn-gap: var(--ag-space-2xs);
  }

  /* =============================================
   PRIMARY NAV — mega-menu (desktop) + drawer (mobile)
   ============================================= */

  /* Mega parent stays static so the panel spans the whole nav width; the
     positioning context is .ag-nav (position: relative, set above). */
  .nav-item.has-mega {
    position: static;
  }

  .nav-mega {
    pointer-events: none;

    position: absolute;
    z-index: var(--ag-z-sticky);
    top: 100%;
    right: 0;
    left: 0;
    transform: translateY(-6px);

    border-top: 1px solid var(--ag-rule);
    border-bottom: 1px solid var(--ag-rule);

    opacity: 0;
    background: var(--ag-paper);
    box-shadow: var(--ag-shadow-md);

    transition:
      opacity var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  /* Invisible hover bridge: fills the vertical gap between the trigger and the
     panel so the cursor never leaves the hover region on its way down. Only
     active while the panel is open (it inherits the panel's pointer-events). */
  .nav-item.has-mega .nav-mega::before {
    content: "";

    position: absolute;
    right: 0;
    bottom: 100%;
    left: 0;

    height: var(--ag-space-2xl);
  }

  .nav-item.has-mega:hover .nav-mega,
  .nav-item.has-mega:focus-within .nav-mega {
    pointer-events: auto;
    transform: none;
    opacity: 1;
  }

  /* Columns grid and promo feature sit side-by-side inside the wrap so their
     widths and heights stay decoupled: the feature has a fixed width and its
     height comes from the columns' natural height (align-items: stretch),
     not the other way around. */
  .nav-mega-wrap {
    display: flex;
    gap: var(--ag-space-2xl);
    align-items: stretch;

    /* Enough vertical room that a promo image + text feels substantial and the
       columns' link lists breathe. Panel height auto-grows if content is taller. */
    min-height: 340px;
  }

  .nav-mega-inner {
    display: grid;
    grid-auto-columns: 1fr;
    grid-auto-flow: column;
    flex: 1 1 auto;
    gap: var(--ag-space-2xl);

    padding: var(--ag-space-lg) 0 var(--ag-space-xl);
  }

  .nav-mega-col h6 {
    margin: 0 0 var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .nav-mega-links {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .nav-mega-links li {
    border-bottom: 1px solid var(--ag-rule);
  }

  .nav-mega-links li:last-child {
    border-bottom: none;
  }

  .nav-mega-links a {
    display: block;

    padding: var(--ag-space-2xs) 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink);
    text-decoration: none;

    transition:
      padding var(--ag-dur-fast) ease,
      color var(--ag-dur-fast) ease;
  }

  .nav-mega-links a:hover {
    padding-left: var(--ag-space-xs);
    color: var(--ag-accent-deep);
  }

  .nav-mega-feature {
    /* Sibling of .nav-mega-inner via flex on the wrap: fixed width, stretched
       to the columns' height. The negative right margin bleeds the promo
       past the wrap's right padding to the panel edge. */
    position: relative;

    overflow: hidden;
    flex: 0 0 340px;

    margin-right: calc(var(--ag-space-2xl) * -1);

    color: inherit;
    text-decoration: none;

    background: var(--ag-paper-deep);
  }

  a.nav-mega-feature {
    cursor: pointer;
    display: block;
  }

  a.nav-mega-feature:hover .nav-mega-feature-img {
    transform: scale(1.03);
  }

  a.nav-mega-feature:hover .feat-cta {
    border-bottom-color: var(--ag-accent);
    color: var(--ag-accent);
  }

  a.nav-mega-feature:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: -2px;
  }

  .nav-mega-feature-img {
    position: absolute;
    inset: 0;

    display: block;

    width: 100%;
    height: 100%;

    object-fit: cover;

    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .nav-mega-feature-scrim {
    /* Cream-toned book covers leave the mockup's soft scrim too weak at the
       text band. Deepen the gradient so the bottom third reaches near-solid
       ink well before the title sits on it, guaranteeing contrast on any image. */
    pointer-events: none;
    position: absolute;
    inset: 0;
    background: linear-gradient(
      180deg,
      transparent 40%,
      rgb(20 32 51 / 55%) 62%,
      rgb(20 32 51 / 92%) 82%,
      rgb(20 32 51 / 96%) 100%
    );
  }

  .nav-mega-feature-content {
    position: absolute;
    right: 0;
    bottom: var(--ag-space-md);
    left: 0;

    display: flex;
    flex-direction: column;
    gap: var(--ag-space-3xs);

    padding: 0 var(--ag-space-lg);

    color: var(--ag-cream);
  }

  .nav-mega-feature .feat-eyebrow {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-cream);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);

    opacity: 0.9;
  }

  .nav-mega-feature .feat-title {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-cream);
  }

  /* Description is not part of the overlay in the desktop mockup — kept in
     markup so the mobile drawer can still render it. */
  .nav-mega-feature > .nav-mega-feature-content > p {
    display: none;
  }

  .nav-mega-feature .feat-cta {
    align-self: flex-start;

    margin-top: var(--ag-space-2xs);
    padding-bottom: var(--ag-space-3xs);
    border-bottom: 1px solid var(--ag-cream);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-cream);
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* Plain dropdown — a top item with children not flagged as a mega. */
  .nav-item.has-dropdown {
    position: relative;
  }

  .nav-item.has-dropdown .sub-menu {
    pointer-events: none;

    position: absolute;
    z-index: var(--ag-z-sticky);
    top: 100%;
    left: 0;
    transform: translateY(-6px);

    min-width: 220px;
    margin: 0;
    padding: var(--ag-space-2xs) 0;
    border: 1px solid var(--ag-rule);

    list-style: none;

    opacity: 0;
    background: var(--ag-paper);
    box-shadow: var(--ag-shadow-md);

    transition:
      opacity var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  .nav-item.has-dropdown .sub-menu::before {
    content: "";

    position: absolute;
    right: 0;
    bottom: 100%;
    left: 0;

    height: var(--ag-space-2xl);
  }

  .nav-item.has-dropdown:hover .sub-menu,
  .nav-item.has-dropdown:focus-within .sub-menu {
    pointer-events: auto;
    transform: none;
    opacity: 1;
  }

  .nav-item.has-dropdown .sub-menu a {
    display: block;

    padding: var(--ag-space-2xs) var(--ag-space-md);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink);
    text-decoration: none;
  }

  .nav-item.has-dropdown .sub-menu a:hover {
    color: var(--ag-accent-deep);
  }

  /* Active page indicator on the desktop bar. */
  .nav-inner > .nav-links .current-menu-item > .nav-link::after,
  .nav-inner > .nav-links .current-menu-ancestor > .nav-link::after {
    width: 100%;
    background: var(--ag-accent);
  }

  /* Hamburger — hidden while the desktop bar is shown. */
  .nav-burger {
    cursor: pointer;

    position: relative;

    display: none;

    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;

    background: none;
  }

  .nav-burger span {
    position: absolute;
    right: 3px;
    left: 3px;

    height: 1.6px;

    background: var(--ag-ink);

    transition:
      transform var(--ag-dur-base) var(--ag-ease),
      opacity var(--ag-dur-base) ease;
  }

  .nav-burger span:nth-child(1) {
    top: 9px;
  }

  .nav-burger span:nth-child(2) {
    top: 14px;
  }

  .nav-burger span:nth-child(3) {
    top: 19px;
  }

  /* =============================================
   MOBILE DRAWER (full-screen accordion)
   ============================================= */

  body.ag-nav-lock {
    overflow: hidden;
  }

  .nav-drawer {
    position: fixed;
    z-index: var(--ag-z-overlay);
    inset: 0;

    display: flex;
    flex-direction: column;

    color: var(--ag-cream);

    visibility: hidden;
    opacity: 0;
    background: var(--ag-deep-navy);

    transition: opacity var(--ag-dur-base) ease;
  }

  .nav-drawer.is-open {
    visibility: visible;
    opacity: 1;
  }

  .nav-drawer-head {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: space-between;

    padding: var(--ag-space-sm) var(--ag-space-lg);
    border-bottom: 1px solid var(--ag-rule-dark);
  }

  .nav-drawer-head .nav-brand {
    color: var(--ag-cream);
  }

  .nav-drawer-head .nav-brand-mark {
    width: 57px !important;
    height: 57px !important;
  }

  .nav-drawer-head .nav-brand-sep {
    height: 52px !important;
  }

  .nav-drawer-head .nav-brand-text {
    font-size: var(--ag-text-brand-drawer) !important;
  }

  .nav-drawer-close {
    cursor: pointer;

    position: relative;

    width: 44px;
    height: 44px;
    border: 0;

    background: none;
  }

  .nav-drawer-close::before,
  .nav-drawer-close::after {
    content: "";

    position: absolute;
    top: 21px;
    right: 10px;
    left: 10px;

    height: 1.6px;

    background: var(--ag-cream);
  }

  .nav-drawer-close::before {
    transform: rotate(45deg);
  }

  .nav-drawer-close::after {
    transform: rotate(-45deg);
  }

  .nav-drawer-search {
    flex: 0 0 auto;
    padding: var(--ag-space-sm) var(--ag-space-lg);
  }

  .nav-drawer-search input {
    width: 100%;
    min-height: 44px;
    padding: var(--ag-space-xs) var(--ag-space-sm);
    border: 1px solid var(--ag-rule-dark);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-base);
    color: var(--ag-cream);

    background: rgb(255 255 255 / 6%);
  }

  .nav-drawer-body {
    overflow-y: auto;
    flex: 1 1 auto;
  }

  /* The drawer reuses the mega markup, presented as an inline accordion. */
  .nav-drawer .nav-links {
    display: flex;
    flex-direction: column;

    /* Override the desktop bar's align-items:center, which would otherwise
       centre and shrink the stacked items instead of filling the width. */
    align-items: stretch;

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .nav-drawer .nav-item {
    display: block;
    border-bottom: 1px solid var(--ag-rule-dark);
  }

  .nav-drawer .nav-item .nav-link {
    display: flex;
    align-items: center;
    justify-content: space-between;

    min-height: 44px;
    padding: var(--ag-space-sm) var(--ag-space-lg);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    color: var(--ag-cream);
  }

  /* A parent row is a link plus a disclosure button, so the label can lead to the
     section's own page while the caret opens the accordion. */
  .nav-drawer-row {
    display: flex;
    align-items: stretch;
  }

  .nav-drawer-row .nav-link {
    flex: 1 1 auto;
    justify-content: flex-start;
  }

  .nav-drawer-toggle {
    cursor: pointer;

    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;

    width: 56px;
    padding: 0;
    border: 0;
    border-left: 1px solid var(--ag-rule-dark);

    color: var(--ag-on-dark);

    background: none;
  }

  .nav-drawer .nav-caret {
    border-color: var(--ag-on-dark);
  }

  .nav-drawer .nav-item.is-open > .nav-drawer-row .nav-caret,
  .nav-drawer .nav-item.is-open > .nav-link .nav-caret {
    transform: rotate(225deg) translateY(-1px);
    border-color: var(--ag-accent);
  }

  /* Mega panel becomes a collapsed accordion inside the drawer. */
  .nav-drawer .nav-mega {
    pointer-events: auto;

    position: static;
    transform: none;

    overflow: hidden;

    max-height: 0;
    border: 0;

    opacity: 1;
    background: rgb(0 0 0 / 14%);
    box-shadow: none;

    transition: max-height var(--ag-dur-slow) ease;
  }

  .nav-drawer .nav-item.is-open .nav-mega {
    max-height: 1600px;
  }

  /* The desktop hover bridge is meaningless in the accordion drawer. */
  .nav-drawer .nav-mega::before,
  .nav-drawer .sub-menu::before {
    content: none;
  }

  /* Plain dropdown inside the drawer: same collapse/expand as the mega. */
  .nav-drawer .sub-menu {
    pointer-events: auto;

    position: static;
    transform: none;

    overflow: hidden;

    max-height: 0;
    margin: 0;
    padding: 0;
    border: 0;

    list-style: none;

    opacity: 1;
    background: rgb(0 0 0 / 14%);
    box-shadow: none;

    transition: max-height var(--ag-dur-slow) ease;
  }

  .nav-drawer .nav-item.is-open > .sub-menu {
    max-height: 800px;
  }

  .nav-drawer .sub-menu a {
    display: block;

    min-height: 44px;
    padding: var(--ag-space-xs) var(--ag-space-lg);

    font-size: var(--ag-text-base);
    color: var(--ag-cream);
    text-decoration: none;
  }

  /* Accordion, not a hover panel: no flex row to lay a promo column beside,
     and no 340px floor reserved for a promo image the drawer never shows. */
  .nav-drawer .nav-mega-wrap {
    display: block;
    min-height: 0;
  }

  .nav-drawer .nav-mega-inner {
    display: block;
    padding: 0 var(--ag-space-lg) var(--ag-space-md);
  }

  .nav-drawer .nav-mega-col {
    padding: var(--ag-space-sm) 0;
    border-bottom: 1px solid var(--ag-rule-dark);
  }

  .nav-drawer .nav-mega-col:last-child {
    border-bottom: none;
  }

  .nav-drawer .nav-mega-col h6 {
    color: var(--ag-on-dark);
  }

  .nav-drawer .nav-mega-links li {
    border-bottom: none;
  }

  .nav-drawer .nav-mega-links a {
    min-height: 44px;
    font-size: var(--ag-text-base);
    color: var(--ag-cream);
  }

  .nav-drawer .nav-mega-links a:hover {
    color: var(--ag-cream);
  }

  /* No promo block in the drawer: on a phone it buried the link columns under
     a full-width image card. The desktop hover panel keeps it. Hiding the
     container also stops the lazy image being fetched — it has no box to
     intersect — so the drawer costs nothing extra on mobile. */
  .nav-drawer .nav-mega-feature {
    display: none;
  }

  .nav-drawer-foot {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: space-between;

    padding: var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule-dark);
  }

  /* =============================================
   HERO
   ============================================= */

  .hero-image-col {
    position: relative;
  }

  /* Le visuel héro est un lien vers sa fiche produit. `.slot img` est en
     position absolue dans le `.slot`, donc l'ancre — statique et inline —
     n'aurait aucune surface cliquable : on l'étire sur tout le slot. */
  .hero-image-col .slot > a {
    position: absolute;
    inset: 0;
    display: block;
  }

  .hero {
    padding-top: var(--ag-space-4xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .hero-title {
    letter-spacing: var(--ag-tracking-tight);
  }

  .hero-trust {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-md);

    margin: var(--ag-space-xl) 0 0;
    padding: 0;

    list-style: none;
  }

  .hero-trust li {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: center;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
  }

  .hero-trust-mark {
    display: flex;
    align-items: center;
  }

  .hero-trust-flag {
    overflow: hidden;
    display: inline-flex;

    width: 22px;
    height: 15px;
    border-radius: var(--ag-radius-sm);
  }

  .hero-trust-flag span {
    flex: 1;
  }

  .sticky-note {
    pointer-events: none;

    position: absolute;
    z-index: var(--ag-z-raised);
    transform: rotate(-2.5deg);

    padding: var(--ag-space-xs) var(--ag-space-md);
    border: 1px solid rgb(208 0 139 / 25%);
    border-radius: var(--ag-radius-md);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-style: italic;
    color: var(--ag-ink);

    background: var(--ag-paper);
    box-shadow: var(--ag-shadow-md);
  }

  .sticky-note .sn-eyebrow {
    display: block;

    margin-bottom: var(--ag-space-3xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    font-style: normal;
    color: var(--ag-accent);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* =============================================
   MARQUEE STRIP
   ============================================= */

  .float-marquee {
    overflow: hidden;
    display: flex;
    gap: var(--ag-space-4xl);
    align-items: center;

    width: 100%;
    padding: var(--ag-space-sm) 0;

    color: var(--ag-cream);

    background-color: var(--ag-secondary);
  }

  .marquee-track {
    display: flex;
    gap: var(--ag-space-4xl);
    align-items: center;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-style: italic;
    white-space: nowrap;

    animation: marquee 38s linear infinite;
  }

  .marquee-track span {
    display: inline-flex;
    flex-shrink: 0;
    gap: var(--ag-space-xl);
    align-items: center;
  }

  .marquee-dot {
    flex-shrink: 0;

    width: 6px;
    height: 6px;
    border-radius: 50%;

    background: rgb(244 238 224 / 50%);
  }

  /* =============================================
   COLLECTIONS — PORTES D'ENTRÉE
   ============================================= */

  /* Five full-bleed doors: photo, title, sentence, and an "Explorer →" that
     surfaces on interaction. A fourth "door or photo card" family alongside
     .hub-porte*, .shop-collection-card and .hub-frise-* — none of which carries
     a full-bleed image under a title *and* a sentence. The naming deliberately
     echoes them (.door-go after .hub-porte-go, .door-photo::after after
     .hub-frise-overlay) so a new family does not also mean a new convention.

     Cream tints stay literal rather than adding an --ag-cream-rgb token (KTD6),
     matching .marquee-dot just above. */
  .doors {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--ag-space-xs);
  }

  .door {
    position: relative;

    overflow: hidden;
    display: flex;
    align-items: flex-end;

    aspect-ratio: 2/3.2;
    border-radius: var(--ag-radius-sm);

    color: var(--ag-cream);
    text-decoration: none;
  }

  .door img {
    position: absolute;
    inset: 0;

    width: 100%;
    height: 100%;

    object-fit: cover;

    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  /* :focus-visible doubles :hover — the mockup only reveals the zoom and the
     "Explorer →" on hover, which leaves keyboard and touch visitors with no
     affordance at all. .hub-porte and .hub-frise-item already pair the two. */
  .door:hover img,
  .door:focus-visible img {
    transform: scale(1.04);
  }

  .door-photo::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgb(16 26 42 / 88%), rgb(16 26 42 / 0%) 58%);
  }

  .door-cap {
    position: relative;
    z-index: var(--ag-z-raised);
    padding: var(--ag-space-lg);
  }

  /* The mockup's 25px/1.08 and 13.5px/1.45 are off the theme's snap scale, which
     Stylelint enforces. Snapped to the nearest stops — xl (24px)/tight (1.1) and
     sm (14px)/base (1.55). Sub-pixel differences; the token scale is the
     authority the project asks the mockup to be confronted with. */
  .door-cap h3 {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-cream);
  }

  .door-cap p {
    max-width: 24ch;
    margin: var(--ag-space-2xs) 0 0;

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: rgb(244 238 224 / 72%);
  }

  .door-go {
    transform: translateY(6px);

    display: inline-block;

    margin-top: var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-cream);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);

    opacity: 0;

    transition:
      opacity var(--ag-dur-base) var(--ag-ease),
      transform var(--ag-dur-base) var(--ag-ease);
  }

  .door:hover .door-go,
  .door:focus-visible .door-go {
    transform: none;
    opacity: 1;
  }

  /* =============================================
   PATRONS / PRODUCTS GRID
   ============================================= */

  /* Patrons grid — .grid-auto (3->2->1) + bottom spacing */
  .patrons-grid {
    margin-bottom: var(--ag-space-4xl);
  }

  .filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
    align-items: center;

    margin-bottom: var(--ag-space-2xl);
    padding-bottom: var(--ag-space-lg);
    border-bottom: 1px solid var(--ag-rule-dark);
  }

  .patron-card-meta {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: var(--ag-space-sm);
    align-items: end;

    margin-top: var(--ag-space-lg);
  }

  .patron-card-title {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    line-height: var(--ag-leading-none);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-wide);
  }

  /* Cream-on-dark was this rule's only color, written for the .band-dark
     carousel (patrons-selection.php) content-product.php first shipped in.
     The same card also renders on the light catalogue/hub grids, where that
     cream at 60% opacity on paper was near-illegible (anomalie Alice du
     2026-08-16, point 9); .band-dark below restores it for the dark band. */
  .patron-card-type {
    margin-top: var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-sm);
    font-style: italic;
    color: var(--ag-ink-soft);
  }

  .band-dark .patron-card-type {
    color: rgb(244 238 224 / 60%);
  }

  .patron-card-price {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-lg);
    color: var(--ag-ink-soft);
    white-space: nowrap;
  }

  .patron-card-chips {
    display: flex;
    gap: var(--ag-space-2xs);
    margin-top: var(--ag-space-sm);
  }

  /* Dark-band price keeps the white text; light-bg catalog card (below) uses
     the default --ag-ink-soft set on .patron-card-price above. */
  .band-dark .patron-card-price {
    color: var(--ag-paper);
  }

  /* Sur une landing, le fil d'Ariane ouvre la page et pose déjà l'espace du
     haut : le header n'a plus à le poser une seconde fois. Même geste que la
     fiche patron, où .fiche-hero se resserre sous le fil d'Ariane. */
  .patron-landing-page .patron-catalog__header {
    padding-top: var(--ag-space-lg);
  }

  /* The count-and-reset aside that answered the title from the other column is
     gone, and so is the eyebrow above it: the title now runs alone. */
  .patron-catalog__header-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
  }

  /* La maquette pose 132px (styles.css:2367), dessinés pour « Patrons de
     tricot » — trois mots. Le titre réel monte à 45 caractères sur une landing
     («  Patrons de bonnets et petits projets au tricot »), que ce corps casse en
     quatre ou cinq lignes avant même la grille. Ramené sur l'échelle du thème :
     display-l ici, display-m sur les landings, dont les H1 sont les plus longs
     du site parce qu'ils portent la requête. */
  .patron-catalog__title {
    margin: 0;
    font-size: var(--ag-text-display-l);
    line-height: var(--ag-leading-none);
    letter-spacing: var(--ag-tracking-tight);
  }

  .patron-landing-page .patron-catalog__title {
    font-size: var(--ag-text-display-m);
  }

  /* Le mot distinctif du titre — « tricot » sur le hub, la facette sur une
     landing. Seul emploi de l'accent dans cette vue, cf. DESIGN.md. */
  .patron-catalog__title em {
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-snug);
  }

  /* Le texte passe sous la grille et court sur toute la largeur du contenu : il
     prolonge le titre au lieu de lui répondre depuis l'autre bord. Le `56ch` de
     `.lede` est donc levé ici — c'est la seule position du site où la mesure est
     volontairement large. */
  .patron-catalog__lede {
    max-width: none;
    margin-top: var(--ag-space-lg);
  }

  /* Le texte SEO d'une landing fait deux paragraphes là où le catalogue tient
     en une phrase : au corps `lede` (jusqu'à 22px) il pèse autant que le titre.
     Il redescend au corps de lecture. */
  .patron-landing-page .patron-catalog__lede {
    font-size: var(--ag-text-base);
  }

  .patron-catalog__lede p + p {
    margin-top: var(--ag-space-sm);
  }

  /* --- Sticky filter bar --- */
  .patron-catalog__filterbar {
    position: sticky;
    z-index: var(--ag-z-sticky);
    top: 110px; /* sits under the fixed nav — intentional one-off */

    padding: var(--ag-space-lg) 0;
    border-top: 1px solid var(--ag-rule);
    border-bottom: 1px solid var(--ag-rule);

    background: color-mix(in srgb, var(--ag-paper-deep) 35%, var(--ag-paper));
    backdrop-filter: blur(10px);
  }

  /* Two main columns: Niveau + Technique on the left, Type de vêtement +
     Public on the right. Columns size to their content and spread apart so the
     chip rows are not artificially squeezed into a 50% track. */
  .patron-catalog__filters {
    display: grid;
    grid-template-columns: auto auto;
    gap: var(--ag-space-sm) var(--ag-space-2xl);
    justify-content: space-between;
  }

  /* Each main column is its own label|chips sub-grid; the filter rows use
     display:contents so their label and chips align across the two rows. The
     chips track prefers one line (max-content) but may shrink and wrap when the
     viewport is tight. */
  .patron-catalog__filter-col {
    display: grid;
    grid-template-columns: max-content minmax(0, max-content);
    gap: var(--ag-space-sm) var(--ag-space-md);
    align-content: start;
    align-items: center;
  }

  .patron-catalog__filter-row {
    display: contents;
  }

  .patron-catalog__filter-label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .patron-catalog__filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
  }

  /* --- Desktop facet pastilles + band ---
     One pill per axis; opening one drops a full-width band under the row of
     pills rather than a floating menu. Nothing overlays the grid, so there is
     no shadow to dose, no z-index to lose and no menu running off the bottom
     of the viewport — and it repeats the gesture of the header's mega-menu.

     Unlike the mobile sheet below, this layout hangs on no JS flag: keying it
     on a class patron-filters.js adds meant the expanded grid painted first and
     then visibly collapsed into pastilles, since that file is deferred. Plain
     CSS is the only presentation that costs nothing at first paint. The
     deferred script is left with the opening and closing alone. */
  .patron-catalog__filter-toggle {
    display: none; /* the sheet carries the labels under 900px */
  }

  /* The wrapper is the band; under 900px it must not exist as a box, or it
     would nest the sheet's label and chips one level deeper than its own
     layout expects. */
  .patron-catalog__filter-drawer {
    display: contents;
  }

  /* The sheet already ends on « Tout effacer » — a second reset inside it would
     be the same link twice. */
  .patron-catalog__filter-reset {
    display: none;
  }

  /* --- Compact filter bar + bottom sheet ---
     Every control below belongs to the mobile presentation and stays out of the
     flow until the `scripting: enabled` regime claims them: with no script the
     panel is the expanded grid itself, and a « Filtrer » button would open
     nothing. Laid out under `width <= 900px` further down. */
  .patron-catalog__filterbar-compact,
  .patron-catalog__filter-actives,
  .patron-catalog__filter-scrim,
  .patron-catalog__filter-panel-head,
  .patron-catalog__filter-panel-foot {
    display: none;
  }

  body.ag-filter-lock {
    overflow: hidden;
  }

  /* --- Footer note --- */
  .patron-catalog__footer {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-sm);
    align-items: center;
    justify-content: space-between;

    margin-top: var(--ag-space-4xl);
    padding: var(--ag-space-2xl) 0;
    border-top: 1px solid var(--ag-rule);
  }

  /* --- Grid: symmetric top spacing below the filter bar --- */
  .patron-catalog__grid {
    margin-top: var(--ag-space-2xl);
  }

  /* --- Filter chip (pill selector) ---
     Distinct from .chip: body-weight, sentence-case, larger hit area.
     Reusable wherever a pill-style filter control is needed. */
  .filter-chip {
    cursor: pointer;

    padding: 9px 18px; /* generous hit area — pill control */
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);

    background: transparent;

    transition:
      color var(--ag-dur-base) ease,
      border-color var(--ag-dur-base) ease,
      background var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  .filter-chip:hover {
    transform: translateY(-1px);
    border-color: var(--ag-ink);
  }

  .filter-chip--active {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(--ag-ink);
  }

  /* --- Catalog product card (light bg) ---
     New BEM elements on the existing .patron-card block. The dark-band card
     in patrons-selection.php uses the older .patron-card-* element classes. */
  .patron-card__photo {
    position: relative;
    margin-bottom: var(--ag-space-lg);
  }

  /* Square slot: patron photos are uploaded 1:1 (1000x1000). A 4/5 slot with
     object-fit: cover silently cropped ~20% off the top and bottom of every
     card. Keep this in sync with the source aspect ratio. */
  .patron-card__photo .slot {
    aspect-ratio: 1/1;
    width: 100%;
  }

  .patron-card__num {
    position: absolute;
    right: 16px; /* image-corner offsets — mockup */
    bottom: 14px;

    padding: var(--ag-space-3xs) 9px; /* 9px corner-pill inline padding — intentional one-off */
    border-radius: var(--ag-radius-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-paper);
    letter-spacing: var(--ag-tracking-eyebrow);

    background: color-mix(in srgb, var(--ag-deep-navy) 60%, transparent);
    backdrop-filter: blur(6px);
  }

  .patron-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
  }

  .patron-card__row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--ag-space-sm);
    align-items: baseline;
  }

  .patron-card__name {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-none);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-snug);
  }

  /* =============================================
   YOUTUBE SECTION
   ============================================= */

  .yt-card {
    position: relative;

    overflow: hidden;
    display: block;

    border-radius: var(--ag-radius-sm);

    background: #0f1015;
  }

  .yt-card .slot {
    aspect-ratio: 16/9;
    width: 100%;
  }

  /* Le ratio vit sur la carte et pas seulement sur son .slot : l'iframe posée
     par video-facade.js est en position absolue, elle ne participe donc pas au
     dimensionnement. Sans cette règle la carte s'effondrerait si le .slot venait
     à manquer.
     Ciblé sur [data-video-embed] : toute carte du site est aujourd'hui rendue
     par ag_youtube_facade(), le sélecteur laisse la porte ouverte à une
     vignette purement décorative qui garderait son .slot. */
  .yt-card[data-video-embed] {
    aspect-ratio: 16/9;
  }

  .yt-card[data-video-embed] iframe {
    position: absolute;
    inset: 0;

    width: 100%;
    height: 100%;
    border: 0;
  }

  /* Le lecteur se superpose à la vignette et n'apparaît qu'une fois chargé.
     Posé visible d'emblée, il montrait le fond #0f1015 de la carte pendant la
     seconde ou deux que YouTube met à peindre son poster — un rectangle noir en
     plein article. La vignette reste dessous et tient la place jusque-là. */
  .yt-card__player {
    opacity: 0;
    transition: opacity var(--ag-dur-slow) var(--ag-ease);
  }

  .yt-card.is-player-ready .yt-card__player {
    opacity: 1;
  }

  /* Le lecteur chargé recouvre la façade, mais recouvrir n'est pas retirer : le
     bouton et le lien restaient atteignables au clavier alors qu'ils ne font
     plus rien — une tabulation dans le vide. Le lecteur de YouTube apporte les
     siens. Le titre et la chaîne, eux, ne sont pas focusables et restent en
     place : c'est le texte qui entoure le lecteur dans le DOM.
     Le sélecteur du CTA doit rester aussi armé que celui qui le met en
     inline-flex plus haut (`.yt-card[data-video-embed] a.yt-card-cta`) : à
     spécificité moindre, `display: none` était simplement ignoré et le lien
     restait dans l'ordre de tabulation. */
  .yt-card.is-player-ready .yt-card-play,
  .yt-card[data-video-embed].is-player-ready a.yt-card-cta {
    display: none;
  }

  @media (prefers-reduced-motion: reduce) {
    .yt-card__player {
      transition: none;
    }
  }

  /* R3 : le contrôle de lecture est un vrai bouton, il lui faut un focus
     visible — l'habillage existant ne stylise que :hover. */
  .yt-card-play:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: 2px;
  }

  /* Play button primitive — centered circular play control over video imagery.
   Size and background are per-use deltas. */
  .u-play-button {
    cursor: pointer;

    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    display: flex;
    align-items: center;
    justify-content: center;

    /* Le reset global ne pose que cursor et font sur `button` : sans cette
       remise à zéro, une façade rendue par ag_youtube_facade() hérite de la
       bordure et du padding par défaut du navigateur sur son contrôle. */
    padding: 0;
    border: 0;
    border-radius: 50%;

    color: var(--ag-ink);

    background: var(--ag-paper);

    transition:
      background var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  /* YouTube badge play — la marque rouge officielle rend le contrôle
     reconnaissable comme lecteur YouTube. Le lecteur intégré de YouTube pose
     la même vignette (viewBox 67×60, fond #f00, flèche blanche) au cœur d'un
     carré de 72 px : reproduire ces mêmes constantes évite qu'un visiteur
     habitué au vrai lecteur hésite sur ce qu'il regarde. */
  .yt-card-play {
    --yt-brand-red: #f00;
    --yt-brand-red-pressed: #c00;
    --yt-brand-arrow: #fff;

    cursor: pointer;

    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    display: block;

    width: 72px;
    height: 72px;
    padding: 0;
    border: 0;

    background: transparent;

    transition: transform var(--ag-dur-base) ease;
  }

  .yt-card-play svg {
    display: block;
    width: 100%;
    height: 100%;
  }

  .yt-card-play__bg {
    fill: var(--yt-brand-red);
    transition: fill var(--ag-dur-base) ease;
  }

  .yt-card-play__arrow {
    fill: var(--yt-brand-arrow);
  }

  .yt-card:hover .yt-card-play {
    transform: translate(-50%, -50%) scale(1.08);
  }

  .yt-card:hover .yt-card-play__bg {
    fill: var(--yt-brand-red-pressed);
  }

  .yt-card-play.yt-card-play-sm {
    width: 56px;
    height: 56px;
  }

  /* Top overlay et CTA « Regarder sur YouTube » — l'habillage du vrai lecteur.
     Rendus derrière le bouton central (z-index) mais devant l'aperçu, et
     `pointer-events: none` sur l'entête pour que le clic sur la zone du titre
     retombe sur la carte et lance la lecture — sauf sur l'ancre YouTube
     elle-même, qui reste cliquable (voir video-facade.js). */

  /*
   * `.yt-card-header` reste en block (pas flex) : un enfant flex voit son
   * `display: -webkit-box` "blockifié" par le moteur, qui le remplace par
   * `flow-root`. Sans `-webkit-box`, `-webkit-line-clamp` n'a plus d'effet
   * et le titre restait à la première ligne écrasée en une seule.
   */
  .yt-card-header {
    pointer-events: none;

    position: absolute;
    top: 0;
    right: 0;
    left: 0;

    padding: 12px 16px 24px;

    color: var(--ag-paper);

    background: linear-gradient(
      to bottom,
      rgb(0 0 0 / 60%) 0%,
      rgb(0 0 0 / 36%) 50%,
      rgb(0 0 0 / 0%) 100%
    );
  }

  .yt-card-header__title {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;

    /* Standard property not yet Baseline in Aug 2026, but pairing it with the
       -webkit- form keeps the IDE's vendorPrefix diagnostic quiet and future-
       proofs the rule the day it lands. */
    /* stylelint-disable-next-line plugin/use-baseline */
    line-clamp: 2;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-md);
    font-weight: var(--ag-weight-semibold, 600);
    line-height: var(--ag-leading-snug);
    text-shadow: 0 1px 4px rgb(0 0 0 / 60%);
  }

  .yt-card-header__channel {
    margin-top: 2px;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: rgb(255 255 255 / 85%);
    text-shadow: 0 1px 4px rgb(0 0 0 / 60%);
  }

  /*
   * Le CTA vit dans le flux de l'article, donc sous la règle prose qui teinte
   * toute ancre en `--ag-accent-deep` avec un liseré rose. Gagner en
   * spécificité ne suffit pas : la règle prose porte `:not(…, .btn)`, ce qui
   * la remonte elle aussi à (0,3,1) — à égalité, l'ordre source la fait
   * gagner, et le CTA relisait en rose souligné. `.yt-card-cta` est donc
   * exclu du `:not()` de la règle prose (comme `.btn`) : c'est un bouton
   * posé sur la vignette, pas un lien de texte.
   */
  .yt-card[data-video-embed] a.yt-card-cta {
    position: absolute;
    right: 12px;
    bottom: 12px;

    display: inline-flex;
    gap: 8px;
    align-items: center;

    padding: 8px 14px;
    border: 0;
    border-radius: 999px;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper);
    text-decoration: none;
    text-shadow: 0 1px 4px rgb(0 0 0 / 60%);

    background: rgb(0 0 0 / 60%);
    backdrop-filter: blur(6px);

    transition: background var(--ag-dur-base) ease;
  }

  .yt-card[data-video-embed] a.yt-card-cta:hover,
  .yt-card[data-video-embed] a.yt-card-cta:focus-visible {
    color: var(--ag-paper);
    background: rgb(0 0 0 / 80%);
  }

  .yt-card-cta__brand {
    display: inline-flex;
    gap: 4px;
    align-items: center;
    font-weight: var(--ag-weight-bold, 700);
  }

  .yt-card-cta__brand-mark {
    display: block;
    width: 32px;
    height: auto;
    filter: drop-shadow(0 1px 2px rgb(0 0 0 / 40%));
  }

  .yt-card-cta__brand-bg {
    fill: var(--ag-paper);
  }

  .yt-card-cta__brand-word {
    letter-spacing: var(--ag-tracking-snug, -0.01em);
  }

  /* Habillage lecteur sur une vignette secondaire (~440×248 sur l'accueil) :
     aux tailles pleines, entête et CTA mangeaient la moitié de l'aperçu et se
     rejoignaient au milieu. Le titre tombe à une ligne — deux lignes de 18 px
     plus la signature couvraient le tiers haut de la vignette. */
  .yt-card-compact .yt-card-header {
    padding: 8px 12px 20px;
  }

  .yt-card-compact .yt-card-header__title {
    -webkit-line-clamp: 1;

    /* stylelint-disable-next-line plugin/use-baseline */
    line-clamp: 1;
    font-size: var(--ag-text-sm);
  }

  .yt-card-compact .yt-card-header__channel {
    font-size: var(--ag-text-xs);
  }

  .yt-card[data-video-embed].yt-card-compact a.yt-card-cta {
    right: 8px;
    bottom: 8px;
    padding: 5px 10px;
    font-size: var(--ag-text-xs);
  }

  .yt-card-compact .yt-card-cta__brand-mark {
    width: 24px;
  }

  .yt-grid {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: var(--ag-space-md);
  }

  .yt-col-right {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-md);
  }

  /* =============================================
   LIVRE / BOOK
   ============================================= */

  .livre-stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-3xl);
    align-items: baseline;

    padding-top: var(--ag-space-xl);
    border-top: 1px solid var(--ag-rule);
  }

  .livre-stat-number {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    line-height: var(--ag-leading-none);
    color: var(--ag-ink);
  }

  .livre-cover-wrap {
    position: relative;
  }

  .livre-cover-accent {
    position: absolute;
    z-index: 0;
    inset: 8% -6% 8% 14%;

    border-radius: var(--ag-radius-sm);

    background: var(--ag-blue-ice);
  }

  .livre-cover-wrap img {
    position: relative;
    z-index: var(--ag-z-raised);

    width: 100%;
    height: auto;
    border-radius: var(--ag-radius-sm);

    box-shadow: var(--ag-shadow-lg);
  }

  .blue-ice-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-md);

    height: 100%;
    padding: clamp(32px, 3.6vw, 56px);
    border-radius: var(--ag-radius-md);

    background: var(--ag-blue-ice);
  }

  /* =============================================
   PREUVES SOCIALES / TESTIMONIALS
   ============================================= */

  /* Preuves grid — .grid-auto (3->2->1) + bottom spacing */
  .preuves-grid {
    margin-bottom: var(--ag-space-2xl);
  }

  .preuve-card {
    margin: 0;
  }

  .preuve-photo {
    position: relative;
  }

  /* Preuve number — dark pill (primitive default), top-right */
  .preuve-num {
    top: 14px;
    right: 14px;
  }

  .preuve-quote {
    margin: var(--ag-space-md) 0 var(--ag-space-xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-style: italic;
    line-height: var(--ag-leading-base);
    color: var(--ag-ink);
  }

  .preuve-credit {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-3xs);
  }

  .preuve-name {
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  .preuve-meta {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .preuves-strip {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: var(--ag-space-2xs);
    margin-top: 0;
  }

  .preuves-strip .slot {
    aspect-ratio: 1/1;
    border-radius: var(--ag-radius-sm);
  }

  .preuves-more {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
    align-items: center;
    justify-content: center;

    border-radius: var(--ag-radius-sm);

    color: var(--ag-ink);
    text-decoration: none;

    background: var(--ag-blue-ice);

    transition: background var(--ag-dur-base);
  }

  .preuves-more:hover {
    background: var(--ag-mint);
  }

  .preuves-more-num {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    line-height: var(--ag-leading-none);
  }

  .preuves-more-label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-align: center;
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* =============================================
   JOURNAL / QUERY LOOP POSTS
   ============================================= */

  /* Journal grid — .grid-auto with a wider gap */
  .journal-grid {
    --grid-gap: var(--ag-space-2xl);
  }

  .journal-post-image .slot {
    aspect-ratio: 16/9;
  }

  .journal-post-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
    align-items: center;
  }

  .journal-post-title {
    margin: var(--ag-space-xs) 0 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);

    transition: color var(--ag-dur-base) var(--ag-ease);
  }

  /* =============================================
   FOOTER
   ============================================= */

  .ag-footer {
    padding: 96px 0 var(--ag-space-2xl); /* 96px top: intentional footer offset, off the snap scale */
    color: var(--ag-cream);
    background: var(--ag-deep-navy);
  }

  /* --- Newsletter block ------------------------------------------------ */

  /*
   * !important on the block-rhythm margins below is required for the same
   * reason as the button section (KTD-2): the footer's top-level rows are
   * direct children of flow-layout group blocks, and WordPress emits
   * `:where(.is-layout-flow) > * { margin-block-start: <blockGap>;
   * margin-block-end: 0 }` UNLAYERED — which outranks any @layer rule
   * whatever its specificity. Without it every row collapses to the generic
   * 24px block gap and the footer loses its vertical composition.
   */
  .footer-news {
    margin-block: 0 var(--ag-space-4xl) !important;
  }

  /* L'écran mot de passe oublié/réinitialisation n'a rien à voir avec la
     newsletter, et l'inscription y détourne l'attention d'un geste déjà
     technique (anomalie Alice du 2026-08-14, point 8). */
  .compte-page--no-newsletter .footer-news {
    display: none;
  }

  /* 7fr/5fr rather than a symmetric split: the left column carries a display
     heading that needs the extra measure, the right one a single form row. */
  .footer-news-top {
    display: grid;
    grid-template-columns: 7fr 5fr;
    gap: var(--ag-space-4xl);
    align-items: start;

    margin-bottom: var(--ag-space-3xl);
  }

  .footer-news-eyebrow {
    margin: 0 0 var(--ag-space-md);
  }

  .footer-news-title {
    max-width: 15ch;
    margin: 0 0 var(--ag-space-xs);
    color: var(--ag-cream);
  }

  .footer-news-subhead {
    max-width: 34ch;
    margin: 0;

    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-cream);
  }

  .footer-news-form-col {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .footer-news-announce {
    margin: 0 0 var(--ag-space-2xs);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-cream);
  }

  .footer-news-proof {
    max-width: 34ch;
    margin: 0 0 var(--ag-space-sm);
    font-size: var(--ag-text-sm);
    color: color-mix(in srgb, var(--ag-cream) 72%, transparent);
  }

  /* In-article newsletter encart (articles 502 and 519, where a native
     MailPoet block used to sit). Unlike the footer and the Livre page, this
     surface has no mockup: the reference is what production renders today, so
     every value below is transcribed from that page — MailPoet's own inline
     styles for the card and the field, the theme's `.btn.btn-accent` for the
     button (production already carried those classes on the submit
     paragraph). Off-scale lengths (33px, 5px, 42px, 44px) are kept raw and
     named as transcriptions rather than rounded to a token.

     Two knowing departures, both because production's value comes from
     MailPoet's own machinery rather than from this site: the title's Cormorant
     — a Google font MailPoet injected, which leaves with it — becomes the
     theme's display serif, and its 42px snaps to `--ag-text-huge` (40px)
     because the linter refuses raw font sizes. */
  .ag-inline-news {
    margin: var(--ag-space-lg) 0 0;
    padding: 33px; /* transcribed */
    border-radius: 5px; /* transcribed */

    color: var(--ag-paper);

    background: var(--ag-deep-navy);
  }

  /* Accent on deep-navy, same pairing as the footer's eyebrow. The title's own
     top margin below supplies the gap, so this one only cancels the default. */
  .ag-inline-news-eyebrow {
    margin: 0;
  }

  /* `.display` is deliberately NOT used in the markup: it would also impose
     its 0.98 leading and negative tracking, where production's title rides a
     1.4 leading. Only the family is borrowed. */
  .ag-inline-news-title {
    margin: 42px 0; /* transcribed */

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    line-height: var(--ag-leading-exergue);
    color: var(--ag-paper);
  }

  .ag-inline-news-title em {
    font-style: italic;
  }

  .ag-inline-news-lede {
    margin: var(--ag-space-sm) 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-paper);
  }

  .ag-inline-news-mention {
    margin: 13px 0; /* transcribed */

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-cap);
    line-height: var(--ag-leading-exergue);
    color: var(--ag-paper);
  }

  /* Same shrink-to-fit trap as the footer: the plugin's three wrapper divs
     carry no width of their own. */
  .ag-inline-news > [id^="mailerlite-form_"],
  .ag-inline-news .mailerlite-form,
  .ag-inline-news .mailerlite-form form {
    width: 100%;
  }

  /* The plugin nests the submit button INSIDE `.mailerlite-form-inputs`, so
     the 20px production leaves between the field and the button belongs to the
     field, and the one before the legal mention to the button. Hanging it on
     the wrapper instead stacks both gaps after the button. */
  .ag-inline-news .mailerlite-form-inputs {
    margin-bottom: 0;
  }

  .ag-inline-news .mailerlite-form-field {
    margin-bottom: var(--ag-space-md);
  }

  .ag-inline-news .mailerlite-form-field input {
    box-sizing: border-box;
    width: 100%;
    height: 44px; /* transcribed */
    padding: 10px; /* transcribed */
    border: 1px solid var(--ag-on-dark);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-paper);

    background: transparent;
  }

  .ag-inline-news .mailerlite-form-field input::placeholder {
    color: var(--ag-paper);
    opacity: 1;
  }

  .ag-inline-news .mailerlite-form-field input:focus-visible {
    border-color: var(--ag-paper);
    outline: none;
  }

  /* Hidden until the plugin's script reveals them inline — the plugin
     stylesheet that used to do this is dequeued. */
  .ag-inline-news .mailerlite-form-loader,
  .ag-inline-news .mailerlite-form-response {
    display: none;
  }

  /* The label is the field's accessible name; production shows none. */
  .ag-inline-news .mailerlite-form-field label {
    position: absolute;

    overflow: hidden;

    width: 1px;
    height: 1px;

    white-space: nowrap;

    clip-path: inset(50%);
  }

  .ag-inline-news .mailerlite-form-description:empty {
    display: none;
  }

  /* Mirrors `.btn.btn-accent` — the plugin's button markup can't carry those
     classes, so the same tokens are read here rather than re-invented. */
  .ag-inline-news .mailerlite-subscribe-submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    height: 44px; /* transcribed */
    margin-bottom: var(--ag-space-md);
    padding: 0 var(--ag-space-lg);
    border: 1px solid var(--ag-accent);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper);
    letter-spacing: var(--ag-tracking-wide);

    background: var(--ag-accent);
    cursor: pointer;

    transition:
      background var(--ag-dur-base) ease,
      border-color var(--ag-dur-base) ease;
  }

  .ag-inline-news .mailerlite-subscribe-submit:hover {
    border-color: var(--ag-accent-deep);

    background: var(--ag-accent-deep);
  }

  .ag-inline-news .mailerlite-form-response h4 {
    margin: 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-base);
    color: var(--ag-paper);
  }

  .ag-inline-news .mailerlite-form-error {
    margin-top: var(--ag-space-3xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
  }

  /* Below 500px production flattens EVERY paragraph of the encart to 16px —
     MailPoet's own mobile stylesheet — so the title comes out the same size as
     the body copy and reads as a stray line rather than a heading. That is a
     defect of the plugin being replaced, not a design decision, so it is not
     reproduced: the title steps down the type scale instead, and only
     production's full-width button is kept. Flagged for Alice. */
  @media (width <= 560px) {
    .ag-inline-news {
      padding: var(--ag-space-lg);
    }

    .ag-inline-news-title {
      margin: var(--ag-space-lg) 0;
      font-size: var(--ag-text-xxl);
    }

    .ag-inline-news .mailerlite-subscribe-button-container,
    .ag-inline-news .mailerlite-subscribe-submit {
      width: 100%;
    }

    .ag-inline-news .mailerlite-subscribe-submit {
      justify-content: center;
    }
  }

  /* The plugin wraps its form in three unstyled divs. `.footer-news-form-col`
     is a column flex container with `align-items: flex-start`, so each of them
     shrinks to fit its content and the pill's `max-width` below never gets a
     chance to apply — the field came out 86px narrower than the design. The
     old theme markup put the form directly in the column, which is why this
     rule had no reason to exist before. */
  .footer-news-form-col > [id^="mailerlite-form_"],
  .footer-news-form-col .mailerlite-form,
  .footer-news-form-col .mailerlite-form form {
    width: 100%;
  }

  /* Pill-in-pill: the submit button nests inside the field's own border, so
     the padding here is the visual gap between the two radii.

     The markup is the MailerLite plugin's, not the theme's — hence the
     `.mailerlite-*` hooks. Its own stylesheet only sets margins and a centred
     button, all overridden here; the rules live in the theme's sheet so a
     plugin update can't wipe them. */
  .footer-news-form-col .mailerlite-form-inputs {
    display: flex;
    align-items: stretch;

    width: 100%;
    max-width: 420px;
    margin-bottom: var(--ag-space-xs);
    padding: var(--ag-space-3xs);
    border: 1px solid var(--ag-rule-dark);
    border-radius: var(--ag-radius-pill);
  }

  .footer-news-form-col .mailerlite-form-field input {
    flex: 1;
    width: 100%;
    min-width: 0;
    padding: var(--ag-space-xs) var(--ag-space-md);
    border: none;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-cream);

    background: transparent;
    outline: none;
  }

  .footer-news-form-col .mailerlite-form-field input::placeholder {
    color: var(--ag-on-dark);
  }

  .footer-news-form-col .mailerlite-subscribe-submit {
    padding: var(--ag-space-xs) 18px;
    border: none;
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper);
    white-space: nowrap;

    background: var(--ag-accent);

    transition:
      color var(--ag-dur-base) var(--ag-ease),
      background var(--ag-dur-base) var(--ag-ease);
  }

  .footer-news-form-col .mailerlite-subscribe-submit:hover {
    color: var(--ag-deep-navy);
    background: var(--ag-paper);
  }

  /* The plugin renders a visible <label> and an always-present description
     wrapper; the theme's design has neither. Hidden rather than removed —
     the label is the field's accessible name, and the markup is not ours to
     filter. */
  .footer-news-form-col .mailerlite-form-field label {
    position: absolute;

    overflow: hidden;

    width: 1px;
    height: 1px;

    white-space: nowrap;

    clip-path: inset(50%);
  }

  .footer-news-form-col .mailerlite-form-description:empty {
    display: none;
  }

  .footer-news-form-col .mailerlite-form-field {
    display: flex;
    flex: 1;

    min-width: 0;
    margin-bottom: 0;
  }

  /* Hidden until the plugin's own script fades them in with an inline style.
     The plugin's stylesheet used to supply this; it is dequeued
     (inc/newsletter-subscribe.php), so the theme owns the initial state. */
  .footer-news-form-col .mailerlite-form-loader,
  .footer-news-form-col .mailerlite-form-response {
    display: none;
  }

  /* Sits inside the pill while the request is in flight. */
  .footer-news-form-col .mailerlite-form-loader {
    margin: 0;
    padding: var(--ag-space-xs) var(--ag-space-md);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-on-dark);
  }

  .footer-news-form-col .mailerlite-form-response h4 {
    margin: 0 0 var(--ag-space-xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-base);
    color: var(--ag-cream);
  }

  .footer-news-form-col .mailerlite-form-error {
    margin-top: var(--ag-space-3xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
  }

  .footer-news-mention {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: color-mix(in srgb, var(--ag-cream) 40%, transparent);
    letter-spacing: var(--ag-tracking-wide);
  }

  .footer-news-benefits {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-xl);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .footer-news-benefits li {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: center;
    margin: 0;
  }

  .footer-news-benefit-icon {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;

    width: 52px;
    height: 52px;
    border: 1px solid var(--ag-accent);
    border-radius: 50%;

    color: var(--ag-accent);
  }

  .footer-news-benefit-icon svg {
    width: 22px;
    height: 22px;
  }

  .footer-news-benefit-text {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-3xs);
  }


  .footer-news-benefit-text strong {
    font-size: var(--ag-text-base);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-cream);
  }

  .footer-news-benefit-text span {
    font-size: var(--ag-text-sm);
    color: color-mix(in srgb, var(--ag-cream) 60%, transparent);
  }

  /* --- Link columns ---------------------------------------------------- */

  .footer-cols {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--ag-space-lg);
    margin-block: 0 var(--ag-space-4xl) !important;
  }

  .footer-col {
    grid-column: span 2;
  }

  .footer-col-brand {
    grid-column: span 4;
  }

  /* Footer variant of the brand lockup — small mark, cream text on deep-navy. */
  .footer-brand {
    gap: var(--ag-space-xs);
    align-items: center;
    color: var(--ag-cream);
  }

  .footer-brand .nav-brand-mark {
    width: 44px;
    height: 44px;
  }

  .footer-brand .nav-brand-sep {
    width: 1px;
    height: 38px;
  }

  .footer-brand .nav-brand-text {
    /* Optical centering: Prata's x-height sits high in its em-box, so the
       two stacked lines look bottom-heavy against the mark unless nudged up. */
    transform: translateY(-1px);
    font-size: var(--ag-text-brand-footer);
    line-height: var(--ag-leading-brand);
  }

  .footer-brand-baseline {
    max-width: 28ch;
    margin: 18px 0 0;
    color: color-mix(in srgb, var(--ag-cream) 60%, transparent);
  }

  .footer-links {
    display: grid;
    gap: 10px;

    margin-block: 0 !important;
    padding: 0;

    list-style: none;
  }

  .footer-links li {
    margin: 0;
  }

  .footer-links a {
    color: var(--ag-on-dark);
    text-decoration: none;
    transition: color var(--ag-dur-fast) var(--ag-ease);
  }

  .footer-links a:hover {
    color: var(--ag-paper);
  }

  .footer-rule {
    margin-block: 0 var(--ag-space-4xl) !important;
    border: none;
    border-top: 1px solid color-mix(in srgb, var(--ag-cream) 15%, transparent);
  }

  .footer-bottom {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: center;
    justify-content: space-between;
  }

  .footer-legal {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: color-mix(in srgb, var(--ag-cream) 45%, transparent);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-wide);
  }

  .footer-legal a {
    color: inherit;
    text-decoration: none;
    transition: color var(--ag-dur-fast) var(--ag-ease);
  }

  .footer-legal a:hover {
    color: var(--ag-paper);
  }

  @media (width >= 901px) {
    /* One flat flex line: every pill is an item, and so is every band, which
       claims a full row of its own via `flex-basis: 100%`. The row and column
       wrappers stay in the markup for the sheet, so here they step aside. */
    .patron-catalog__filters {
      display: flex;
      flex-wrap: wrap;
      gap: var(--ag-space-2xs);
      justify-content: flex-start;
    }

    .patron-catalog__filter-col,
    .patron-catalog__filter-row {
      display: contents;
    }

    .patron-catalog__filter-toggle {
      cursor: pointer;

      display: inline-flex;
      gap: var(--ag-space-3xs);
      align-items: center;

      padding: 9px 18px;
      border: 1px solid var(--ag-rule-strong);
      border-radius: var(--ag-radius-pill);

      font-family: var(--ag-font-body);
      font-size: var(--ag-text-sm);
      font-weight: var(--ag-weight-medium);
      line-height: var(--ag-leading-snug);
      color: var(--ag-ink);
      white-space: nowrap;

      background: var(--ag-paper);

      transition:
        color var(--ag-dur-base) ease,
        border-color var(--ag-dur-base) ease,
        background var(--ag-dur-base) ease;
    }

    .patron-catalog__filter-toggle:hover,
    .patron-catalog__filter-toggle[aria-expanded="true"] {
      border-color: var(--ag-ink);
    }

    .patron-catalog__filter-toggle--active {
      border-color: var(--ag-ink);
      color: var(--ag-paper);
      background: var(--ag-ink);
    }

    /* `margin-left: auto` eats the free space of the pill line, so the link
       lands on the far right facing the facets it clears. It keeps the default
       order, and the bands take `order: 1`, so it never falls below them. */
    .patron-catalog__filter-reset {
      display: inline-flex;

      /* Without this the item stretches to the pill height and the underline
         detaches from the text it belongs to. */
      align-self: center;

      margin-left: auto;
      border-bottom: 1px solid currentcolor;

      font-family: var(--ag-font-mono);
      font-size: var(--ag-text-xxs);
      color: var(--ag-accent);
      text-transform: uppercase;
      letter-spacing: var(--ag-tracking-eyebrow);
      white-space: nowrap;

      transition: color var(--ag-dur-base) ease;
    }

    .patron-catalog__filter-reset:hover {
      color: var(--ag-ink);
    }

    .patron-catalog__filter-caret {
      flex: none;
      transition: transform var(--ag-dur-base) var(--ag-ease);
    }

    .patron-catalog__filter-toggle[aria-expanded="true"]
      .patron-catalog__filter-caret {
      transform: rotate(180deg);
    }

    /* `order: 1` puts every band after every pill whatever the source order,
       so the axes stay on one line and the open band sits under all of them —
       not in the middle of the row. */
    .patron-catalog__filter-drawer {
      display: none;
      flex-basis: 100%;
      gap: var(--ag-space-sm);
      align-items: baseline;
      order: 1;

      margin-top: var(--ag-space-3xs);
      padding-top: var(--ag-space-sm);
    }

    .patron-catalog__filter-row.is-open .patron-catalog__filter-drawer {
      display: flex;
    }

    /* Fallback where the script will never run. Focus alone opens the band, so
       the pastilles are never decorative. It stays out of the scripted regime,
       where `.is-open` rules and a pastille left focused after its own click
       would refuse to close. */
    /* stylelint-disable-next-line plugin/use-baseline -- `scripting` ships in
       every engine since December 2023 (FF 113, Safari 17, Chrome 120); only
       Baseline's 30-month "widely available" label lagged, to June 2026, and
       the plugin's frozen snapshot predates that flip. */
    @media (scripting: none) {
      .patron-catalog__filter-row:focus-within .patron-catalog__filter-drawer {
        display: flex;
      }
    }

    .patron-catalog__filter-drawer .patron-catalog__filter-label {
      flex: none;
      padding-top: 10px; /* optical: aligns the cap-height to the chip text */
    }

    /* The band's own selected chip stays lighter than the sheet's ink fill —
       the pastille above already carries the choice in full contrast, and two
       ink blocks one under the other read as two separate selections. */
    .patron-catalog__filter-drawer .filter-chip--active {
      border-color: transparent;
      color: var(--ag-ink);
      background: var(--ag-mint);
    }
  }

  @media (width <= 900px) {
    .footer-news-top,
    .footer-news-benefits {
      grid-template-columns: 1fr;
    }

    .footer-news-top {
      gap: var(--ag-space-lg);
    }

    .footer-news-benefits {
      gap: 14px;
    }

    /* Halve the 12-track grid so the brand block and each link column keep
       their relative widths while pairing up two per row. */
    .footer-cols {
      grid-template-columns: repeat(6, 1fr);
    }
  }

  @media (width <= 560px) {
    .footer-cols {
      grid-template-columns: repeat(4, 1fr);
      gap: var(--ag-space-xl) var(--ag-space-lg);
    }

    .footer-col-brand {
      grid-column: span 4;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .nav-mega,
    .nav-drawer,
    .nav-drawer .nav-mega,
    .nav-burger span {
      transition: none;
    }
  }

  /* Hide the desktop bar (not the drawer's copy) and reveal the hamburger:
     on narrow viewports and on touch/coarse pointers (which can't open a hover mega). */
  @media (width <= 900px), (hover: none) {
    .nav-inner > .nav-links {
      display: none;
    }

    .nav-burger {
      display: block;
    }

    /* The drawer opens on its own search field, so the header one would be a
       second, cramped entry point to the same query. */
    .nav-search {
      display: none;
    }
  }

  @media (width <= 720px) {
    .ag-wrap {
      padding-right: var(--ag-space-lg);
      padding-left: var(--ag-space-lg);
    }

    /* Sur mobile le fil d'Ariane d'une landing passe à deux lignes et le
       `blockGap` de 24px le suit : ces 40px de plus ouvraient ~87px entre lui et
       l'exergue. C'est le geste que le commentaire posé sur la règle de bureau
       décrit déjà — il ne tenait simplement pas sous 720px. */
    .patron-landing-page .patron-catalog__header {
      padding-top: 0;
    }
  }

  @media (width <= 900px) {
    .grid-auto,
    .patrons-grid,
    .preuves-grid,
    .journal-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .grid-auto,
    .patrons-grid,
    .preuves-grid,
    .journal-grid {
      grid-template-columns: 1fr;
    }
  }

  @media (width <= 900px) {
    .patron-catalog__filterbar {
      position: static;
    }

    /* Stack the two main filter columns. */
    .patron-catalog__filters {
      grid-template-columns: 1fr;
      gap: var(--ag-space-md);
    }
  }

  /* The bottom sheet is the whole mobile presentation of the bar, and it only
     makes sense where its « Filtrer » button can actually open something.
     `scripting: enabled` is what says so at parse time — the flag used to come
     from patron-filters.js, which meant every phone painted the five axes
     stacked in full and then watched them fold away: a layout shift the whole
     height of the panel, on every catalogue page. A browser too old for the
     media feature simply keeps the expanded grid, which is the same thing a
     visitor without JS gets. */
  /* stylelint-disable-next-line plugin/use-baseline -- `scripting` ships in
     every engine since December 2023 (FF 113, Safari 17, Chrome 120); only
     Baseline's 30-month "widely available" label lagged, to June 2026, and the
     plugin's frozen snapshot predates that flip. */
  @media (width <= 900px) and (scripting: enabled) {
    /* =============================================
       FILTER BAR — COMPACT + BOTTOM SHEET
       ============================================= */

    /* Stacked in full, the five axes are 19 chips over nine lines: the first
       patron started below the fold and the bar had to give up its stickiness
       to fit. Folded behind one button, the catalogue starts under the header
       and the bar can stick again. */
    .patron-catalog__filterbar {
      position: sticky;
      top: var(--ag-filterbar-top, 68px);

      padding: 0;
      border: 0;

      /* The blur moves down to the compact bar. A backdrop-filter here would
         make this block the containing block of its `position: fixed`
         descendants, and the sheet would anchor to the bar's own bottom edge
         instead of the viewport's. */
      background: none;
      backdrop-filter: none;
    }

    .patron-catalog__filterbar > .ag-wrap {
      padding: 0;
    }

    .patron-catalog__filterbar .patron-catalog__filterbar-compact {
      display: flex;
      gap: var(--ag-space-sm);
      align-items: center;
      justify-content: space-between;

      padding: var(--ag-space-xs) var(--ag-space-lg);
      border-top: 1px solid var(--ag-rule);
      border-bottom: 1px solid var(--ag-rule);

      background: color-mix(in srgb, var(--ag-paper) 92%, transparent);
      backdrop-filter: blur(10px);
    }

    .patron-catalog__filter-open {
      cursor: pointer;

      display: inline-flex;
      gap: var(--ag-space-2xs);
      align-items: center;

      padding: 10px 20px;
      border: 1px solid var(--ag-ink);
      border-radius: var(--ag-radius-pill);

      font-family: var(--ag-font-body);
      font-size: var(--ag-text-sm);
      font-weight: var(--ag-weight-semibold);
      line-height: var(--ag-leading-snug);
      color: var(--ag-paper);

      background: var(--ag-ink);
    }

    .patron-catalog__filter-badge {
      display: inline-grid;
      place-items: center;

      min-width: 18px;
      height: 18px;
      padding: 0 5px;
      border-radius: var(--ag-radius-pill);

      font-family: var(--ag-font-mono);
      font-size: var(--ag-text-xxs);
      color: var(--ag-paper);

      background: var(--ag-accent);
    }

    .patron-catalog__filter-total {
      font-family: var(--ag-font-mono);
      font-size: var(--ag-text-xxs);
      color: var(--ag-ink-soft);
      text-transform: uppercase;
      letter-spacing: var(--ag-tracking-eyebrow);
    }

    /* Active filters stay legible without opening the sheet — and each pill is
       the link that drops its own axis. */
    .patron-catalog__filterbar .patron-catalog__filter-actives {
      overflow-x: auto;
      display: flex;
      gap: var(--ag-space-3xs);

      padding: var(--ag-space-2xs) var(--ag-space-lg);
      border-bottom: 1px solid var(--ag-rule);

      background: var(--ag-paper);
    }

    /* Même parti que .angles-thumbs : la rangée doit se lire comme une suite de
       pastilles, pas comme un conteneur défilant. Firefox garde sa barre
       native — `scrollbar-width` n'est pas Baseline. */
    .patron-catalog__filter-actives::-webkit-scrollbar {
      display: none;
    }

    .patron-catalog__filter-pill {
      display: inline-flex;
      flex: none;
      gap: var(--ag-space-3xs);
      align-items: center;

      padding: 6px 12px;
      border-radius: var(--ag-radius-pill);

      font-size: var(--ag-text-xs);
      font-weight: var(--ag-weight-semibold);
      color: var(--ag-secondary);
      text-decoration: none;

      background: var(--ag-mint);
    }

    .patron-catalog__filterbar .patron-catalog__filter-scrim {
      position: fixed;
      z-index: var(--ag-z-overlay);
      inset: 0;

      display: block;

      visibility: hidden;
      opacity: 0;
      background: rgb(20 32 51 / 45%);

      transition:
        opacity var(--ag-dur-slow) var(--ag-ease),
        visibility var(--ag-dur-slow);
    }

    .patron-catalog__filterbar.is-open
      .patron-catalog__filter-scrim {
      visibility: visible;
      opacity: 1;
    }

    .patron-catalog__filterbar .patron-catalog__filter-panel {
      position: fixed;
      z-index: var(--ag-z-overlay);
      right: 0;
      bottom: 0;
      left: 0;
      transform: translateY(100%);

      display: flex;
      flex-direction: column;

      max-height: 85dvh;
      border-radius: var(--ag-radius-md) var(--ag-radius-md) 0 0;

      visibility: hidden;
      background: var(--ag-paper);
      box-shadow: var(--ag-shadow-md);

      transition:
        transform var(--ag-dur-slow) var(--ag-ease),
        visibility var(--ag-dur-slow);
    }

    .patron-catalog__filterbar
      .patron-catalog__filter-panel.is-open {
      transform: translateY(0);
      visibility: visible;
    }

    .patron-catalog__filterbar .patron-catalog__filter-panel-head {
      display: flex;
      flex: none;
      align-items: center;
      justify-content: space-between;

      padding: var(--ag-space-sm) var(--ag-space-lg) var(--ag-space-xs);
      border-bottom: 1px solid var(--ag-rule);
    }

    .patron-catalog__filter-panel-head .display {
      font-size: var(--ag-text-xl);
    }

    .patron-catalog__filter-close {
      cursor: pointer;

      display: grid;
      place-items: center;

      width: 32px;
      height: 32px;
      border: 0;
      border-radius: var(--ag-radius-pill);

      font-size: var(--ag-text-md);
      line-height: var(--ag-leading-none);
      color: var(--ag-ink);

      background: var(--ag-paper-deep);
    }

    /* The label column was the desktop's; inside the sheet the chips get the
       whole width instead of wrapping around a 52px gutter. */
    .patron-catalog__filterbar .patron-catalog__filters {
      overflow-y: auto;
      flex: 1;
      gap: var(--ag-space-md);
      padding: var(--ag-space-xs) var(--ag-space-lg) var(--ag-space-md);
    }

    .patron-catalog__filterbar .patron-catalog__filter-col,
    .patron-catalog__filterbar .patron-catalog__filter-row {
      display: flex;
      flex-direction: column;
      gap: var(--ag-space-2xs);
    }

    .patron-catalog__filterbar .patron-catalog__filter-col {
      gap: var(--ag-space-md);

      /* The grid's `align-items: center` becomes horizontal centring once the
         column turns into a flex column: each axis shrank to its widest chip
         line and floated to the middle, staggering the five labels. */
      align-items: stretch;
    }

    .patron-catalog__filterbar .patron-catalog__filter-panel-foot {
      display: flex;
      flex: none;
      gap: var(--ag-space-sm);
      align-items: center;

      padding: var(--ag-space-sm) var(--ag-space-lg);
      padding-bottom: max(var(--ag-space-sm), env(safe-area-inset-bottom));
      border-top: 1px solid var(--ag-rule);
    }

    .patron-catalog__filter-clear {
      font-size: var(--ag-text-xs);
      font-weight: var(--ag-weight-semibold);
      color: var(--ag-ink-soft);
      text-underline-offset: 3px;
    }

    .patron-catalog__filter-done {
      cursor: pointer;

      flex: 1;

      padding: 13px var(--ag-space-sm);
      border: 0;
      border-radius: var(--ag-radius-pill);

      font-family: var(--ag-font-body);
      font-size: var(--ag-text-sm);
      font-weight: var(--ag-weight-semibold);
      color: var(--ag-paper);

      background: var(--ag-accent);
    }
  }

  @media (width <= 720px) {
    .filter-chip {
      padding: 8px 14px; /* tighter pill on mobile */
      font-size: var(--ag-text-xs);
    }

    .patron-card__name {
      font-size: var(--ag-text-xl);
    }
  }

  @media (width <= 720px) {
    .ag-nav .nav-inner {
      gap: var(--ag-space-xs);
      padding: var(--ag-space-sm) var(--ag-space-lg);
    }

    /* The desktop lockup is 218px wide, which on a 390px screen (iPhone 12)
       pushed the 28px hamburger past the right gutter: clipped off-screen, and
       the page scrolled sideways. .nav-brand is flex-shrink: 0, so nothing
       absorbed the overflow on its own. */
    .nav-brand {
      gap: 10px;
    }

    .nav-brand .nav-brand-mark {
      width: 44px;
      height: 44px;
    }

    .nav-brand .nav-brand-sep {
      height: 40px;
    }

    .nav-brand .nav-brand-text {
      font-size: var(--ag-text-brand-nav-sm);
    }
  }

  /* The doors keep the mockup's own stops (1100px, 560px) rather than the
     theme's 900/720: five portrait cells get too narrow to read well before
     900px, and the single-column fallback only makes sense once two no longer
     fit. Transcribed from mockup_refv2/styles.css. */
  @media (width <= 1100px) {
    .doors {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 560px) {
    .doors {
      grid-template-columns: 1fr;
    }
  }

  @media (width <= 720px) {
    .yt-grid {
      grid-template-columns: 1fr;
    }

    /* La colonne unique rend les trois cartes égales : le rétrécissement
       « vignette secondaire » n'a plus de raison d'être, et laissé en place il
       donnait deux tailles d'habillage sur des cartes de même largeur. */
    .yt-grid .yt-card-compact .yt-card-header {
      padding: 12px 16px 24px;
    }

    .yt-grid .yt-card-compact .yt-card-header__title {
      -webkit-line-clamp: 2;

      /* stylelint-disable-next-line plugin/use-baseline */
      line-clamp: 2;
      font-size: var(--ag-text-md);
    }

    .yt-grid .yt-card-compact .yt-card-header__channel {
      font-size: var(--ag-text-sm);
    }

    .yt-card[data-video-embed].yt-card-compact a.yt-card-cta {
      right: 12px;
      bottom: 12px;
      padding: 8px 14px;
      font-size: var(--ag-text-sm);
    }

    .yt-grid .yt-card-compact .yt-card-cta__brand-mark {
      width: 32px;
    }
  }

  @media (width <= 720px) {
    .preuves-strip {
      grid-template-columns: repeat(3, 1fr);
    }
  }

  /* =============================================
   RESPONSIVE — GLOBAL
   ============================================= */

  @media (width <= 900px) {
    .band {
      padding-top: var(--ag-space-5xl);
      padding-bottom: var(--ag-space-5xl);
    }

    .section {
      padding-top: var(--ag-space-5xl);
      padding-bottom: var(--ag-space-5xl);
    }

    .section-tight {
      padding-top: var(--ag-space-3xl);
      padding-bottom: var(--ag-space-3xl);
    }
  }

  @media (width <= 720px) {
    .band {
      padding-top: var(--ag-space-4xl);
      padding-bottom: var(--ag-space-4xl);
    }

    .section {
      padding-top: var(--ag-space-4xl);
      padding-bottom: var(--ag-space-4xl);
    }

    .section-tight {
      padding-top: var(--ag-space-xl);
      padding-bottom: var(--ag-space-xl);
    }

    .hero {
      padding-top: var(--ag-space-2xl);
      padding-bottom: var(--ag-space-3xl);
    }

    .sticky-note {
      display: none;
    }

    .hero-trust {
      gap: var(--ag-space-sm);
    }

    .livre-stats {
      gap: var(--ag-space-lg);
    }
  }

  @keyframes marquee {
    from {
      transform: translateX(0);
    }

    to {
      transform: translateX(-50%);
    }
  }
}

@layer wp-overrides {
  /* =============================================
   GUTENBERG BLOCK OVERRIDES
   ============================================= */

  /* Remove default margin from wp-block-group in bands */
  .band > .wp-block-group {
    margin: 0;
  }

  /* Ensure wide/full blocks escape constrained container */
  .wp-site-blocks {
    padding-right: 0 !important;
    padding-left: 0 !important;
  }

  /* Query loop: remove default list styles */
  .wp-block-post-template {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* Heading blocks in Instrument Serif */
  .wp-block-heading {
    font-family: var(--ag-font-display);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-display);
    letter-spacing: var(--ag-tracking-snug);
  }

  /* Site title in nav */
  .wp-block-site-title a {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-style: italic;
    color: var(--ag-ink);
    text-decoration: none;
  }

  /* =============================================
   BUTTONS LAYOUT — wp-block-buttons wrapper
   ============================================= */

  /* By default wp-block-buttons is block; make it inline-flex so buttons sit side by side */
  .wp-block-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    align-items: center;
  }

  .wp-block-button {
    flex: none;

    /* Reset block-level display from editor */
    width: auto !important;
  }

  /* =============================================
   NAV BUTTON OVERRIDES
   ============================================= */

  /* Undo the default block button wrapper display */
  .ag-nav .wp-block-buttons {
    display: flex;
    align-items: center;
  }

  .ag-nav .wp-block-button {
    display: inline-flex;
  }

  .ag-nav .wp-block-button__link {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    padding: var(--ag-space-2xs) var(--ag-space-sm);
    border: 1px solid var(--ag-ink);
    border-radius: var(--ag-radius-pill) !important;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-cap) !important;
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper) !important;
    text-decoration: none;
    letter-spacing: var(--ag-tracking-wide);
    white-space: nowrap;

    background-color: var(--ag-ink) !important;
  }

  .ag-nav .wp-block-button__link:hover {
    border-color: var(--ag-accent);
    background-color: var(--ag-accent) !important;
  }

  /* WooCommerce nav icons — keep compact */
  .ag-nav .wc-block-mini-cart__button,
  .ag-nav .woocommerce-account-icon {
    display: flex;
    align-items: center;
    justify-content: center;

    width: 36px;
    height: 36px;
  }

  /* =============================================
   BLOCK BUTTON GLOBAL
   ============================================= */

  /*
 * !important throughout this section is REQUIRED, not reactive (KTD-2):
 * theme.json styles core/button (background: ink, text: paper, radius: 999px)
 * as UNLAYERED global styles (`:root :where(.wp-block-button__link)`), and
 * unlayered CSS outranks every @layer regardless of specificity. So every
 * button variant that must differ from — or reassert — that default
 * (ghost = transparent, accent = pink, all hover states, nav/sm sizing)
 * needs !important to win. Cascade layers fixed our internal ordering;
 * they cannot beat WordPress's unlayered output. Verified empirically:
 * removing these reverts ghost/accent buttons to the theme.json ink default.
 */

  /*
 * WordPress generates an inset box-shadow matching the border color
 * whenever a border color is set on a button block. Combined with the
 * actual border this creates a visible double-ring on ghost buttons.
 * Suppress it globally and drive ALL button appearance from CSS classes.
 */
  .wp-block-button__link,
  .wp-element-button {
    box-shadow: none !important;
  }

  /*
 * The bare .btn / .btn-* classes (see "BUTTONS" section) are meant for
 * standalone <button>/<a> elements (footer form, nav Panier). On a core
 * button block the class lands on the .wp-block-button WRAPPER, so the
 * wrapper renders as a pill AROUND the already-styled link — a button
 * inside a button. Neutralise the wrapper; the inner link is styled below.
 */
  .wp-block-button.btn,
  .wp-block-button.btn-ghost,
  .wp-block-button.btn-accent,
  .wp-block-button.btn-sm {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  /* Block button appearance — same recipe as .btn, reading the shared --btn-*
   values that inherit from the .wp-block-button wrapper's variant classes
   (.btn / .btn-ghost / .btn-accent / .btn-sm / .band-dark, all defined once in
   the BUTTONS section). !important only on the theme.json-contested properties. */
  .wp-block-button.btn .wp-block-button__link {
    display: inline-flex;
    gap: var(--btn-gap);
    align-items: center;

    padding: var(--btn-pad);
    border: 1px solid var(--btn-border) !important;
    border-radius: var(--ag-radius-pill) !important;

    font-family: var(--ag-font-body);
    font-size: var(--btn-font-size) !important;
    font-weight: var(--ag-weight-medium);
    color: var(--btn-fg) !important;
    text-decoration: none;
    letter-spacing: var(--ag-tracking-wide);

    background: var(--btn-bg) !important;

    transition:
      background var(--ag-dur-base) ease,
      border-color var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  .wp-block-button.btn .wp-block-button__link:hover {
    transform: translateY(-1px);
    border-color: var(--btn-border-hover) !important;
    color: var(--btn-fg-hover) !important;
    background: var(--btn-bg-hover) !important;
  }

  /* btn-sm block padding must beat WP core's unlayered em-based default padding.
   Other sizes intentionally inherit core's padding (matches prior baseline);
   theme.json doesn't set button padding, but WP core does — unlayered. */
  .wp-block-button.btn-sm .wp-block-button__link {
    padding: var(--btn-pad) !important;
  }

  /* Focus ring */
  .wp-block-button__link:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: 2px;
  }

  /* =============================================
   MOBILE RESPONSIVE — PATTERNS
   ============================================= */

  @media (width <= 720px) {
    /* Hero columns: stack */
    .hero .wp-block-columns {
      flex-direction: column;
    }

    .hero .wp-block-column {
      flex-basis: 100% !important;
      width: 100% !important;
    }

    /* YouTube grid: stack */
    .yt-grid {
      grid-template-columns: 1fr;
    }

    /* Livre: stack columns */
    .band .wp-block-columns {
      flex-direction: column;
    }

    .band .wp-block-column {
      flex-basis: 100% !important;
      width: 100% !important;
    }

    /* Blue ice card full width */
    .blue-ice-card {
      margin-top: var(--ag-space-lg);
    }
  }
}

@layer components {
  /* =================================================================
   PRODUCT PAGE — Fiche Patron (single-product)
   All styles scoped under .ag-fiche-patron, using --ag-* tokens.
   ================================================================= */

  .ag-fiche-patron {
    display: block;
  }

  .ag-fiche-patron [hidden] {
    display: none !important;
  }

  /* Visible focus for all interactive product-page elements */
  .ag-fiche-patron a:focus-visible,
  .ag-fiche-patron button:focus-visible,
  .ag-fiche-patron [role="tab"]:focus-visible,
  .ag-lightbox button:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: 2px;
  }

  /* --- Breadcrumb (vertical padding only — keep .ag-wrap's gutter so the crumb aligns with the hero) --- */
  .ag-breadcrumb {
    padding-top: var(--ag-space-lg);
    padding-bottom: var(--ag-space-2xs);
  }

  .ag-breadcrumb .ag-crumb-sep {
    padding: 0 var(--ag-space-xs);
    color: var(--ag-rule);
  }

  .ag-breadcrumb a {
    border-bottom: 1px solid transparent;
  }

  .ag-breadcrumb a:hover {
    border-bottom-color: currentcolor;
  }

  .ag-breadcrumb .ag-crumb-current {
    color: var(--ag-ink);
  }

  /* --- S1 Hero --- */
  .fiche-hero {
    padding-top: var(--ag-space-sm);
  }

  .fiche-hero-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: start;
  }

  .fiche-photo {
    position: relative;
  }

  .fiche-photo-main {
    position: relative;
  }

  .fiche-photo-main .slot {
    aspect-ratio: 9/10;
  }

  .fiche-photo-main-btn {
    cursor: zoom-in;

    display: block;

    width: 100%;
    padding: 0;
    border: 0;

    background: none;
  }

  .fiche-hero-badges {
    position: absolute;
    z-index: var(--ag-z-raised);
    top: 16px;
    left: 16px;

    display: flex;
    gap: var(--ag-space-2xs);
  }

  /* The badges sit on an arbitrary product photograph, so the base .chip
     (transparent background, ink text) has no contrast anyone can guarantee —
     measured 1.04:1 against the darkest pixel behind it, 2.72:1 against the
     lightest, both below the 4.5:1 of WCAG 1.4.3 at this 11.5px size. A 92%
     paper wash on the plain variant holds the worst case above 13:1 whatever
     the image; .chip-soft is left alone, its blue-ice fill is already opaque.
     These are static labels, not controls, so the interactive affordances
     .chip carries are cancelled too. */
  .fiche-hero-badges .chip {
    pointer-events: none;
    cursor: default;
  }

  .fiche-hero-badges .chip:not(.chip-soft) {
    border-color: var(--ag-rule-strong);
    background: color-mix(in srgb, var(--ag-paper) 92%, transparent);
  }

  .fiche-photo-side {
    position: absolute;
    top: 16%;
    right: -16px;
    bottom: 22%;

    display: flex;
    flex-direction: column;
    gap: var(--ag-space-xs);

    width: 22%;
    margin: 0;
  }

  .fiche-thumb {
    cursor: pointer;

    position: relative;

    flex: 1;

    padding: 0;
    border: 2px solid transparent;

    background: none;
  }

  .fiche-thumb .slot {
    width: 100%;
    height: 100%;
  }

  .fiche-thumb.is-active {
    border-color: var(--ag-ink);
  }

  /* The strip hangs off the photo's right edge, geometry that only works while
     the hero is two columns. Once .fiche-hero-grid stacks the photo goes full
     width and the overlay covers a fifth of the product shot, so the strip
     reflows into a row underneath. The mockup drops it outright at this size
     (styles.css, `.fiche-photo-side { display: none }`); keeping it is a
     deliberate divergence — swapping photos is the point of the strip, and
     hiding it leaves phone visitors with a single photo they cannot change. */
  @media (width <= 980px) {
    .fiche-photo-side {
      position: static;
      flex-direction: row;

      width: auto;
      margin-top: var(--ag-space-2xs);
    }

    .fiche-thumb {
      aspect-ratio: 1 / 1;
    }
  }

  .fiche-info {
    padding-top: var(--ag-space-2xs);
  }

  .fiche-product-title {
    margin: 0 0 var(--ag-space-2xs);
  }

  .fiche-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    align-items: center;

    margin-bottom: var(--ag-space-md);
  }

  .fiche-rating {
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-label);
  }

  .level-strip {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;

    margin: var(--ag-space-lg) 0;
    padding: var(--ag-space-sm) 0;
    border-top: 1px solid var(--ag-rule);
    border-bottom: 1px solid var(--ag-rule);
  }

  .level-strip-val {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
  }

  .add-panel {
    position: relative;

    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    padding: var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper-deep);
  }

  .add-panel-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
  }

  .fiche-price {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    line-height: var(--ag-leading-none);
  }

  .fiche-price del {
    margin-right: var(--ag-space-xs);
    /* stylelint-disable-next-line scale-unlimited/declaration-strict-value -- intentional relative size: strikethrough price scales with the parent price */
    font-size: 0.6em;
    color: var(--ag-ink-soft);
  }

  /* Le CTA appartient au panneau d'achat, pas à une famille de produit : les
     trois héros (patron, papeterie, accessoire) partagent `.add-panel`, comme
     la règle du panneau lui-même plus haut. Scopée à `.ag-fiche-patron`, cette
     règle laissait les fiches papeterie et accessoire avec le bouton
     WooCommerce brut au lieu de la pilule rose de la maquette. */
  .add-panel .button,
  .add-panel .single_add_to_cart_button {
    justify-content: center;

    width: 100%;
    padding: var(--ag-space-sm);
    border-color: var(--ag-accent);
    border-radius: var(--ag-radius-pill);

    color: var(--ag-paper);
    text-align: center;

    /* !important: beats WooCommerce's UNLAYERED default button background,
     which outranks any @layer (KTD-2). The only WP/Woo-contested prop here. */
    background: var(--ag-accent) !important;
  }

  .add-panel .button:hover,
  .add-panel .single_add_to_cart_button:hover {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(
      --ag-ink
    ) !important; /* see above — beats Woo unlayered hover */
  }

  /* Choix de variante (cf. woocommerce/single-product/add-to-cart/variable.php).
     Le radio réel porte le choix et reste focusable ; seul son rendu natif est
     masqué, d'où `opacity: 0` plutôt que `display: none`, qui le sortirait de
     l'ordre de tabulation. */
  .ag-variation {
    margin: 0 0 var(--ag-space-md);
    padding: 0;
    border: 0;
  }

  .ag-variation-legend {
    margin-bottom: var(--ag-space-2xs);
    padding: 0;
  }

  .ag-variation-choices {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
  }

  .ag-variation-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
  }

  .ag-variation-chip {
    cursor: pointer;
    transition:
      border-color var(--ag-dur-base) var(--ag-ease),
      color var(--ag-dur-base) var(--ag-ease);
  }

  .ag-variation-radio:checked + .ag-variation-chip {
    border-color: var(--ag-accent);
    color: var(--ag-accent);
  }

  .ag-variation-radio:focus-visible + .ag-variation-chip {
    outline: 2px solid var(--ag-accent);
    outline-offset: 2px;
  }

  .ag-variation-radio:disabled + .ag-variation-chip {
    cursor: not-allowed;
    text-decoration: line-through;
    opacity: 0.4;
  }

  /* Quantité + CTA sur une seule ligne (cf. woocommerce/single-product/
     add-to-cart/simple.php). `stretch` fait porter la hauteur par le bouton :
     le stepper s'aligne dessus sans hauteur codée en dur. */
  .ag-qty-row {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: stretch;
  }

  .ag-qty-row .single_add_to_cart_button {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
  }

  /* Même composant visuel que le stepper du drawer (.ag-cart-drawer-qty) et de
     la page panier (.qty-mini) : cadre discret, boutons sur --paper, valeur sur
     --paper-deep en mono tabulaire. Seule l'échelle change — la fiche produit
     le pose à côté d'un CTA de ~50px, où des segments de 26px seraient une
     cible tactile hors norme. */
  .ag-qty {
    overflow: hidden;
    display: flex;
    flex: 0 0 auto;
    align-items: stretch;

    border: 1px solid var(--ag-rule-strong);
    border-radius: 6px;

    background: var(--ag-paper);
  }

  .ag-qty-btn {
    cursor: pointer;

    display: flex;
    align-items: center;
    justify-content: center;

    width: 40px;
    padding: 0;
    border: 0;

    font-family: inherit;
    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-none);
    color: var(--ag-ink-soft);

    background: var(--ag-paper);

    transition:
      background var(--ag-dur-fast) var(--ag-ease),
      color var(--ag-dur-fast) var(--ag-ease);
  }

  .ag-qty-btn:hover:not(:disabled) {
    color: var(--ag-ink);
    background: var(--ag-paper-deep);
  }

  .ag-qty-btn:disabled {
    cursor: not-allowed;
    opacity: 0.4;
  }

  /* Le conteneur .quantity de WooCommerce arrive `float: left` avec des marges,
     posés par le CSS non-layered du plugin — d'où les !important, sans quoi le
     champ sort de la ligne flex. */
  .ag-qty .quantity {
    float: none !important;
    margin: 0 !important;
  }

  .ag-qty input.qty {
    width: 44px;
    height: 100%;
    padding: 0;
    border: 0;
    border-right: 1px solid var(--ag-rule-strong);
    border-left: 1px solid var(--ag-rule-strong);
    border-radius: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--ag-ink);
    text-align: center;

    appearance: textfield;
    background: var(--ag-paper-deep);
  }

  /* Les flèches natives doublonneraient les boutons − / +. */
  .ag-qty input.qty::-webkit-outer-spin-button,
  .ag-qty input.qty::-webkit-inner-spin-button {
    margin: 0;
    appearance: none;
  }

  .fiche-short {
    max-width: 46ch;
    margin-bottom: var(--ag-space-lg);

    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .fiche-short p {
    margin: 0;
  }

  .add-panel-secure {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-align: center;
    letter-spacing: var(--ag-tracking-label);
  }

  .hero-reassure {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs) var(--ag-space-md);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .hero-reassure li {
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
  }

  .reassure-tick {
    font-weight: var(--ag-weight-bold);
    color: var(--ag-accent);
  }

  /* --- S2 Ce que vous recevez --- */
  .value-grid {
    display: grid;
    grid-template-columns: 0.92fr 1.08fr;
    gap: 64px;
    align-items: start; /* 64px: intentional wide hero-grid gap, off the snap scale */
  }

  .value-list,
  .value-learn {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .value-receive {
    padding: var(--ag-space-2xl);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);
    background: var(--ag-paper-deep);
  }

  .value-list li {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;

    padding: var(--ag-space-sm) 0;
    border-bottom: 1px solid var(--ag-rule);

    font-size: var(--ag-text-base);
  }

  .value-list li:last-child {
    padding-bottom: 0;
    border-bottom: none;
  }

  .value-num {
    flex-shrink: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-label);
  }

  .value-highlight {
    padding-top: var(--ag-space-2xs);
  }

  .value-learn li {
    position: relative;

    margin-bottom: var(--ag-space-md);
    padding: 0 0 var(--ag-space-md) var(--ag-space-xl);
    border-bottom: 1px solid var(--ag-rule);

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .value-learn li:last-child {
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: none;
  }

  .value-learn li::before {
    content: "→";

    position: absolute;
    top: 0;
    left: 0;

    font-family: var(--ag-font-mono);
    color: var(--ag-accent);
  }

  /* --- S3 Vidéo --- */
  .video-grid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: var(--ag-space-3xl);
    align-items: start;
  }

  .video-in-list {
    display: grid;
    gap: var(--ag-space-xs);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .video-in-list li {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: center;

    font-size: var(--ag-text-base);
    color: var(--ag-ink);
  }

  .video-in-head {
    margin-top: var(--ag-space-xl);
    padding-top: var(--ag-space-md);
    border-top: 1px solid var(--ag-rule);
  }

  /* --- S4 Histoire --- */
  .story-grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: var(--ag-space-2xl);
    align-items: start;
  }

  .story-quote-col {
    position: sticky;
    top: 100px;
  }

  .story-quote-mark {
    display: block;
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-hero-stat);
    line-height: var(--ag-leading-none);
  }

  .story-body p {
    margin: 0 0 var(--ag-space-md);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  /*
   * The long description carries `.ag-prose` so its lists, bold runs and
   * links match the articles. Only the type scale differs: an article runs
   * at 18px across a ~790px measure, this sits in the 2fr middle column of
   * `.story-grid` (~550px), so it stays on the 16px `.story-body` scale.
   *
   * Set once on the container, not per element: `.story-body p` already
   * forced 16px on paragraphs but reached nothing else, so list items came
   * out 18px next to 16px paragraphs in the same column.
   */
  .story-prose {
    --ag-prose-size: var(--ag-text-base);
  }

  .story-title {
    margin: 0 0 var(--ag-space-xl);
    line-height: var(--ag-leading-snug);
  }

  .story-origin {
    margin-top: var(--ag-space-xl);
    padding: var(--ag-space-lg) 0 0;
    border-top: 1px solid var(--ag-rule);
  }

  .story-origin-body {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-style: italic;
    line-height: var(--ag-leading-base);
    color: var(--ag-ink);
  }

  .story-proto .slot {
    aspect-ratio: 3 / 4;
  }

  .story-proto figcaption {
    margin-top: var(--ag-space-sm);
  }

  /* --- S5 Informations essentielles --- */
  .essential-card {
    overflow: hidden;
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);
    background: var(--ag-paper);
  }

  .essential-head {
    padding: var(--ag-space-xl) var(--ag-space-2xl) var(--ag-space-3xs);
  }

  .essential-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    margin: 0;
    padding: var(--ag-space-lg) 0 0;
  }

  .essential-cell {
    padding: var(--ag-space-lg) var(--ag-space-2xl) var(--ag-space-xl);
    border-top: 1px solid var(--ag-rule);
    border-right: 1px solid var(--ag-rule);
  }

  .essential-cell:last-child {
    border-right: none;
  }

  .essential-cell dt {
    margin-bottom: var(--ag-space-xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .essential-cell dd {
    margin: 0;
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-snug);
  }

  .essential-attrs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-sm);
    align-items: center;

    padding: var(--ag-space-lg) var(--ag-space-2xl) var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule);

    background: var(--ag-paper-deep);
  }

  .attr-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
  }

  .attr-tag {
    display: inline-flex;
    align-items: center;

    padding: var(--ag-space-2xs) var(--ag-space-xs);
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-cap);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-ink);

    background: var(--ag-paper);

    transition: all var(--ag-dur-base) ease;
  }

  .attr-tag:hover {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(--ag-ink);
  }

  /* Tabs (desktop) → accordion (mobile, ≤900px).
   Triggers and panels are interleaved in the DOM; on desktop the grid pulls every
   .ag-tab onto row 1 and stacks the panels into the shared row 2 area, so it reads
   as a classic tab bar. Below 900px the grid drops to a stacked accordion. */
  .ag-info {
    display: grid;
    grid-template-columns: repeat(4, max-content) 1fr;
    column-gap: var(--ag-space-3xs);
    border-bottom: 1px solid var(--ag-rule);
  }

  .ag-tab {
    cursor: pointer;

    display: inline-flex;
    grid-row: 1;
    align-items: center;

    margin-bottom: -1px;
    padding: var(--ag-space-sm) var(--ag-space-md);
    border: 0;
    border-bottom: 2px solid transparent;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
    white-space: nowrap;

    background: none;
  }

  .ag-tab[aria-selected="true"] {
    border-bottom-color: var(--ag-accent);
    color: var(--ag-ink);
  }

  .ag-tab-chevron {
    display: none;
  }

  .ag-tabpanel {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-top: var(--ag-space-2xl);
  }

  .ag-tabpanel[hidden] {
    display: none;
  }

  .tech-grid {
    overflow: hidden;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px; /* 1px: hairline rule between cells, intentional */

    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-rule);
  }

  .tech-block {
    padding: var(--ag-space-xl) var(--ag-space-2xl);
    background: var(--ag-paper);
  }

  .tech-block .tech-num {
    display: block;

    margin-bottom: var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .tech-block h4 {
    margin: 0 0 var(--ag-space-xs);
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
  }

  .tech-block p {
    margin: 0;
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .tech-block--cta {
    display: flex;
    flex-direction: column;

    text-decoration: none;

    background: var(--ag-ink);

    transition: background var(--ag-dur-base) ease;
  }

  .tech-block--cta:hover {
    background: color-mix(in srgb, var(--ag-accent) 80%, #000);
  }

  .tech-block--cta h4 {
    color: var(--ag-paper);
  }

  .tech-block--cta p {
    color: rgb(255 255 255 / 72%);
  }

  .tech-cta-eyebrow {
    display: block;

    margin-bottom: var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: rgb(255 255 255 / 55%);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .tech-cta-link {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    margin-top: auto;
    padding-top: var(--ag-space-lg);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .matos-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: start;
  }

  .yarn-list,
  .accessory-list {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .yarn-list li,
  .accessory-list li {
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: baseline;

    padding: var(--ag-space-2xs) 0;

    color: var(--ag-ink-soft);
  }

  .yarn-list li::before {
    content: "✓";
    font-weight: var(--ag-weight-bold);
    color: var(--ag-accent);
  }

  .measures-table {
    border-collapse: collapse;
    width: 100%;
  }

  .measures-table th,
  .measures-table td {
    padding: var(--ag-space-xs) var(--ag-space-sm);
    border-bottom: 1px solid var(--ag-rule);
    font-size: var(--ag-text-base);
    text-align: center;
  }

  .measures-table th:first-child,
  .measures-table td:first-child {
    text-align: left;
  }

  /* Tableaux de mensurations issus des PDF patrons : jusqu'à 14 colonnes de
     tailles, donc défilement horizontal avec la colonne de libellés figée. */
  .measures-table + .measures-caption {
    margin-top: var(--ag-space-2xl);
  }

  .measures-caption {
    margin: 0 0 var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .measures-note {
    margin: var(--ag-space-xs) 0 0;
    font-size: var(--ag-text-cap);
    font-style: italic;
    color: var(--ag-ink-soft);
  }

  .measures-table thead th {
    border-bottom: 1px solid var(--ag-rule-strong);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    font-weight: var(--ag-weight-medium);
    white-space: nowrap;

    background: var(--ag-paper);
  }

  .measures-table tbody td {
    font-family: var(--ag-font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .measures-table tbody tr:nth-child(odd) td {
    background: var(--ag-paper-deep);
  }

  .measures-table tbody tr:last-child td {
    border-bottom: 0;
  }

  /* Colonne de libellés figée à gauche pendant le défilement horizontal. */
  .measures-table thead th:first-child,
  .measures-table .measures-rowlabel {
    position: sticky;
    z-index: var(--ag-z-raised);
    left: 0;

    min-width: 16ch;
    border-right: 1px solid var(--ag-rule-strong);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    text-align: left;
    white-space: normal;

    background: var(--ag-paper);
  }

  .measures-table tbody tr:nth-child(odd) .measures-rowlabel {
    background: color-mix(in srgb, var(--ag-ink) 3%, var(--ag-paper));
  }

  .ressource-grid {
    --cols: 4;
    --grid-gap: var(--ag-space-lg);
  }

  /* --- Visionneuse partagée (.angles-*) -----------------------------------
     One viewer — main image + prev/next + « Agrandir » + counter + thumb
     strip — rendered by template-parts/angles-viewer.php for the fiche
     Patron (S6), the fiche Ressource (R6) and the page Livre (L7). Head and
     viewer live together so the whole component has one source of truth. */
  .angles-head {
    display: grid;
    grid-template-columns: 7fr 5fr;
    gap: var(--ag-space-lg);
    align-items: end;

    margin-bottom: var(--ag-space-2xl);
  }

  .angles-head-lede {
    margin: 0;
  }

  /* S6 sits its title flush; R6 and L7 pass .res-section-title instead. */
  .angles-head-title {
    margin: 0;
  }

  /* Gallery label — light pill, bottom-left, wider padding */
  .gallery-label {
    z-index: var(--ag-z-raised);
    bottom: 12px;
    left: 14px;

    padding: var(--ag-space-3xs) var(--ag-space-xs);

    color: var(--ag-ink);

    background: color-mix(in srgb, var(--ag-paper) 90%, transparent);
    backdrop-filter: blur(4px);
  }

  /* S6 visionneuse */
  .angles-viewer {
    max-width: 980px;
    margin: 0 auto;
  }

  .angles-main {
    position: relative;
  }

  .angles-main .slot {
    aspect-ratio: 4 / 3;
    border-radius: var(--ag-radius-md);
  }

  .angles-nav {
    cursor: pointer;

    position: absolute;
    z-index: var(--ag-z-raised);
    top: 50%;
    transform: translateY(-50%);

    display: flex;
    align-items: center;
    justify-content: center;

    width: 50px;
    height: 50px;
    padding: 0;
    border: 0;
    border-radius: 50%;

    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-none);
    color: var(--ag-ink);

    background: color-mix(in srgb, var(--ag-paper) 92%, transparent);

    transition:
      background var(--ag-dur-base) var(--ag-ease),
      color var(--ag-dur-base) var(--ag-ease);
  }

  .angles-nav:hover,
  .angles-nav:focus-visible {
    color: var(--ag-paper);
    background: var(--ag-accent);
  }

  .angles-nav.prev {
    left: 20px;
  }

  .angles-nav.next {
    right: 20px;
  }

  .angles-zoom {
    cursor: zoom-in;

    position: absolute;
    z-index: var(--ag-z-raised);
    top: 18px;
    right: 18px;

    padding: 8px 14px;
    border: 0;
    border-radius: 999px;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
    letter-spacing: var(--ag-tracking-label);

    background: color-mix(in srgb, var(--ag-ink) 75%, transparent);
  }

  .angles-counter {
    position: absolute;
    z-index: var(--ag-z-raised);
    bottom: 18px;
    left: 18px;

    padding: 6px 12px;
    border-radius: var(--ag-radius-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
    letter-spacing: var(--ag-tracking-label);

    background: color-mix(in srgb, var(--ag-ink) 75%, transparent);
  }

  /* Hidden pool — one element per gallery image, wired into the shared
     lightbox so its arrow navigation cycles through every viewer image. */
  .angles-pool {
    display: none;
  }

  .angles-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;

    margin-top: 18px;
  }

  .angles-thumb {
    cursor: pointer;

    overflow: hidden;
    flex: 0 0 84px;

    width: 84px;
    padding: 0;
    border: 2px solid transparent;
    border-radius: var(--ag-radius-sm);

    opacity: 0.55;
    background: none;

    transition:
      opacity var(--ag-dur-base) var(--ag-ease),
      border-color var(--ag-dur-base) var(--ag-ease);
  }

  .angles-thumb .slot {
    aspect-ratio: 3 / 4;
    border-radius: 2px;
  }

  .angles-thumb:hover,
  .angles-thumb:focus-visible {
    opacity: 1;
  }

  .angles-thumb.is-active {
    border-color: var(--ag-ink);
    opacity: 1;
  }

  /* --- S7 Galerie communautaire --- */
  .commu-cards {
    --cols: 4;
    --grid-gap: var(--ag-space-md);
  }

  .commu-card {
    display: block;

    padding: 0;
    border: 0;

    text-align: left;

    background: none;
  }

  .commu-card .slot {
    aspect-ratio: 4 / 5;
  }

  .commu-card-meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-top: var(--ag-space-xs);
  }

  .commu-handle {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
  }

  /* --- S8 FAQ --- */
  .faq-grid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: var(--ag-space-3xl);
    align-items: start;
  }

  .faq-sublabel {
    margin: 0 0 var(--ag-space-2xs);
  }

  .faq-sublabel + .faq-sublabel,
  .faq-item + .faq-sublabel {
    margin-top: var(--ag-space-2xl);
  }

  .faq-item {
    border-bottom: 1px solid var(--ag-rule);
  }

  .faq-trigger {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: center;
    justify-content: space-between;

    width: 100%;
    padding: var(--ag-space-md) 0;
    border: 0;

    text-align: left;

    background: none;
  }

  .faq-trigger h4 {
    margin: 0;
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
  }

  .faq-toggle {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;

    width: 26px;
    height: 26px;
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);
  }

  .faq-toggle::before {
    content: "+";
  }

  .faq-trigger[aria-expanded="true"] .faq-toggle::before {
    content: "×";
  }

  .faq-panel {
    max-width: 60ch;
    padding: 0 0 var(--ag-space-lg);

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  /* --- S9 CTA Jacquard --- */
  .fiche-pedago {
    padding: var(--ag-space-2xl) 0;
  }

  .pedago-inner {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: var(--ag-space-xl);
    align-items: center;

    padding: clamp(36px, 4vw, 56px);
    border-radius: var(--ag-radius-md);

    color: var(--ag-paper);

    background: var(--ag-secondary);
  }

  .pedago-inner .eyebrow {
    color: var(--ag-on-dark);
  }

  .pedago-inner h2 {
    margin: 0;
    color: var(--ag-paper);
  }

  .pblock-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    margin-top: var(--ag-space-lg);
  }

  .pblock-badge {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    padding: var(--ag-space-2xs) var(--ag-space-sm);
    border: 1px solid rgb(255 255 255 / 32%);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .pblock-badge span {
    font-weight: var(--ag-weight-bold);
    color: var(--ag-accent);
  }

  .pedago-cta {
    text-align: right;
  }

  /* --- S10 Vous aimerez aussi --- */
  .reco-row {
    --cols: 4;
    --grid-gap: var(--ag-space-xl);
  }

  .reco-card-meta {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: var(--ag-space-sm);
    align-items: end;

    margin-top: var(--ag-space-sm);
  }

  /* --- Shared lightbox --- */
  .ag-lightbox {
    position: fixed;
    z-index: var(--ag-z-overlay);
    inset: 0;

    display: flex;
    align-items: center;
    justify-content: center;

    background: rgb(20 32 51 / 92%);
  }

  .ag-lightbox[hidden] {
    display: none !important;
  }

  .ag-lightbox-figure {
    max-width: 86vw;
    max-height: 86vh;
    margin: 0;
    text-align: center;
  }

  .ag-lightbox-figure img {
    max-width: 86vw;
    max-height: 78vh;
    margin: 0 auto;
  }

  .ag-lightbox-figure figcaption {
    display: flex;
    gap: var(--ag-space-lg);
    justify-content: space-between;

    margin-top: var(--ag-space-xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: var(--ag-paper);
    letter-spacing: var(--ag-tracking-label);
  }

  .ag-lightbox-close {
    position: absolute;
    top: 22px;
    right: 26px;

    border: 0;

    font-size: var(--ag-text-xxl);
    line-height: var(--ag-leading-none);
    color: var(--ag-paper);

    background: none;
  }

  .ag-lightbox-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);

    padding: 0 var(--ag-space-md);
    border: 0;

    font-size: var(--ag-text-marquee);
    line-height: var(--ag-leading-none);
    color: var(--ag-paper);

    background: none;
  }

  .ag-lightbox-nav.prev {
    left: 12px;
  }

  .ag-lightbox-nav.next {
    right: 12px;
  }

  /* Le `blockGap` de WordPress pose déjà 24px avant le fil d'Ariane et 24px
     après : sur mobile, ce padding portait le total à ~104px d'air autour d'une
     ligne de 17px. Il se contente ici de décoller la ligne du bandeau. */
  @media (width <= 720px) {
    .ag-breadcrumb {
      padding-top: var(--ag-space-2xs);
    }
  }

  @media (width <= 720px) {
    .measures-table thead th:first-child,
    .measures-table .measures-rowlabel {
      min-width: 12ch;
      font-size: var(--ag-text-xs);
    }

    .measures-table tbody td,
    .measures-table thead th {
      font-size: var(--ag-text-xs);
    }
  }

  @media (width <= 900px) {
    .ag-info {
      display: block;
      border-bottom: 0;
    }

    .ag-tab {
      display: flex;
      gap: var(--ag-space-sm);
      align-items: center;
      justify-content: space-between;

      width: 100%;
      margin-bottom: 0;
      padding: var(--ag-space-sm) var(--ag-space-3xs);
      border-bottom: 1px solid var(--ag-rule);

      text-align: left;
      white-space: normal;
    }

    /* Neutralise the desktop accent underline; the row rule is the divider here. */
    .ag-tab[aria-selected="true"],
    .ag-tab[aria-expanded="true"] {
      border-bottom-color: var(--ag-rule);
      color: var(--ag-ink);
    }

    .ag-tab-label {
      flex: 1 1 auto;
    }

    .ag-tab-chevron {
      transform: rotate(-45deg);

      display: block;
      flex: none;

      width: 8px;
      height: 8px;
      border-right: 2px solid currentcolor;
      border-bottom: 2px solid currentcolor;

      transition: transform var(--ag-dur-base) ease;
    }

    .ag-tab[aria-expanded="true"] .ag-tab-chevron {
      transform: rotate(45deg);
    }

    .ag-tabpanel {
      margin-top: 0;
      padding: var(--ag-space-3xs) var(--ag-space-3xs) var(--ag-space-xl);
    }
  }

  /* --- Responsive collapse --- */
  @media (width <= 980px) {
    .fiche-hero-grid,
    .value-grid,
    .video-grid,
    .matos-grid,
    .faq-grid,
    .pedago-inner {
      grid-template-columns: 1fr;
      gap: var(--ag-space-xl);
    }

    .story-grid {
      grid-template-columns: 1fr;
    }

    .story-quote-col {
      position: static;
    }

    .essential-grid {
      grid-template-columns: repeat(2, 1fr);
    }

    .essential-cell:nth-child(2n) {
      border-right: none;
    }

    .tech-grid {
      grid-template-columns: 1fr;
    }

    .ressource-grid,
    .reco-row,
    .commu-cards {
      grid-template-columns: repeat(2, 1fr);
    }

    .angles-head {
      grid-template-columns: 1fr;
      gap: var(--ag-space-sm);
    }

    .angles-nav {
      width: 42px;
      height: 42px;
      font-size: var(--ag-text-lg);
    }

    .angles-nav.prev {
      left: 10px;
    }

    .angles-nav.next {
      right: 10px;
    }

    .angles-zoom {
      top: 12px;
      right: 12px;
    }

    .angles-counter {
      bottom: 12px;
      left: 12px;
    }

    /* Mobile: single-row horizontal scroll strip. Wrapping onto multiple
       centred rows leaves the last row half-empty and reads as disorganised
       once the gallery holds more than a handful of images; a scroll strip
       stays legible with 3 or 15 thumbs. `safe center` keeps small sets
       centred and falls back to `start` the moment the strip overflows,
       so the first thumb is never pushed off-screen. */
    .angles-thumbs {
      scroll-snap-type: x mandatory;

      overflow-x: auto;
      flex-wrap: nowrap;
      justify-content: safe center;

      padding-block: 2px;
      padding-inline: 4px;

      -webkit-overflow-scrolling: touch;
    }

    /* Hide the scrollbar on WebKit/Blink so the strip reads as a photo
       row, not a scroll container. Firefox falls back to the native
       scrollbar (scrollbar-width is not yet Baseline). */
    .angles-thumbs::-webkit-scrollbar {
      display: none;
    }

    .angles-thumb {
      scroll-snap-align: center;
      flex: 0 0 64px;
      width: 64px;
    }

    .pedago-cta {
      text-align: left;
    }
  }

  @media (width <= 560px) {
    .ressource-grid,
    .reco-row,
    .commu-cards,
    .essential-grid {
      grid-template-columns: 1fr;
    }

    .essential-cell {
      border-right: none;
    }

    .fiche-price {
      font-size: var(--ag-text-xxxl);
    }
  }
}

@layer utilities {
  /* =============================================
   ACCESSIBILITY UTILITIES
   ============================================= */

  /* Visually hidden but accessible to screen readers */
  .sr-only {
    position: absolute;

    overflow: hidden;

    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;

    white-space: nowrap;

    clip-path: inset(50%);
  }

  /* Skip-to-content link — hidden until focused */
  .skip-to-content {
    position: absolute;
    z-index: var(--ag-z-max);
    top: auto;
    left: -9999px;

    overflow: hidden;

    width: 1px;
    height: 1px;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
  }

  .skip-to-content:focus-visible {
    position: fixed;
    top: 1rem;
    left: 1rem;

    overflow: visible;

    width: auto;
    height: auto;
    padding: 0.5rem 1.25rem;
    border-radius: var(--ag-radius-pill);

    color: var(--ag-paper);

    background: var(--ag-ink);
    outline: 2px solid var(--ag-accent);
    outline-offset: 2px;
  }

  /* Focus ring for nav links (keyboard users) */
  .nav-link:focus-visible {
    border-radius: var(--ag-radius-sm);
    outline: 2px solid var(--ag-accent);
    outline-offset: 3px;
  }

  /* The newsletter input is borderless inside the form's pill, so the focus
     ring goes on the pill — an outline on the input alone would draw a second
     rectangle inside the rounded field. */
  .footer-news-form-col .mailerlite-form-inputs:focus-within {
    border-color: rgb(255 255 255 / 40%);
    outline: 2px solid rgb(255 255 255 / 75%);
    outline-offset: 2px;
  }

  /* =============================================
   FOOTER HEADING — column labels above footer link lists
   ============================================= */

  /* Rendered as a <p>, not a heading — these are visual mono labels, not
     document headings, so they don't belong in the h1–h6 outline. */
  .footer-heading {
    margin-block: 0 var(--ag-space-md) !important;

    font-family: var(--ag-font-mono) !important;
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow) !important;
  }

  /* =============================================
   SLOT ASPECT-RATIO MODIFIERS
   ============================================= */

  .slot--4-5 {
    aspect-ratio: 4 / 5;
  }

  .slot--square {
    aspect-ratio: 1 / 1;
  }

  .slot--3-4 {
    aspect-ratio: 3 / 4;
  }

  .slot--3-2 {
    aspect-ratio: 3 / 2;
  }

  .slot--16-9 {
    aspect-ratio: 16 / 9;
  }

  /* =============================================
   REDUCED MOTION
   ============================================= */

  @media (prefers-reduced-motion: reduce) {
    /* Freeze the marquee — it is aria-hidden, so stopping is safe */
    .marquee-track {
      animation: none;
    }

    /* Collapse all transitions to imperceptible durations */
    *,
    *::before,
    *::after {
      scroll-behavior: auto !important;
      transition-duration: 0.01ms !important;
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
    }
  }
}

/* ==========================================================================
   Blog — page /blog et archives de catégorie
   ========================================================================== */

.blog-hero {
  padding-top: var(--ag-space-2xs);
}

.blog-hero-title {
  margin: 0 0 var(--ag-space-xl);
}

.blog-hero-sub {
  display: block;
  margin-top: var(--ag-space-md);
}

.blog-hero-tools {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ag-space-lg);
  align-items: center;
}

.blog-search {
  display: flex;
  gap: var(--ag-space-2xs);
  align-items: center;

  width: 100%;
  max-width: 440px;
  padding: 4px 6px 4px 20px;
  border: 1px solid var(--ag-ink);
  border-radius: 999px;

  background: var(--ag-paper);
}

.blog-search input {
  flex: 1;

  min-width: 0;
  border: 0;

  font: inherit;
  font-size: var(--ag-text-sm);
  color: var(--ag-ink);

  background: transparent;
}

.blog-search input:focus {
  outline: none;
}

.blog-search input::placeholder {
  color: var(--ag-ink-soft);
}

.blog-search-btn {
  cursor: pointer;

  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;

  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;

  color: var(--ag-paper);

  background: var(--ag-ink);
}

/* --- À la une --- */

.blog-feature {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--ag-space-3xl);
  align-items: center;

  color: var(--ag-ink);
}

.blog-feature .slot {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
  object-fit: cover;
}

.blog-feature-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ag-space-sm);
  align-items: center;

  margin-bottom: var(--ag-space-md);
}

.blog-feature-title {
  margin: 0 0 var(--ag-space-md);
  font-size: clamp(30px, 3.4vw, 46px);
  line-height: var(--ag-leading-tight);
}

.blog-feature-excerpt {
  max-width: 46ch;
  margin: 0 0 var(--ag-space-lg);
  line-height: var(--ag-leading-relaxed);
  color: var(--ag-ink-soft);
}

/* --- Explorer par thème --- */

.blog-themes-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--ag-space-xl);
}

.blog-theme-card {
  display: block;
  padding-top: var(--ag-space-lg);
  border-top: 1px solid var(--ag-rule);
  color: var(--ag-ink);
}

.blog-theme-title {
  margin: 0 0 var(--ag-space-2xs);
  font-size: var(--ag-text-xl);
  font-weight: 400;
  line-height: var(--ag-leading-tight);
}

.blog-theme-desc {
  margin: 0;
  font-size: var(--ag-text-sm);
  line-height: var(--ag-leading-base);
  color: var(--ag-ink-soft);
}

.blog-theme-link {
  display: inline-block;
  margin-top: var(--ag-space-lg);
}

/* --- Archives de catégorie --- */

.blog-archive-title {
  margin: 0 0 var(--ag-space-md);
}

/* --- Tous les articles --- */

.blog-tous-head .filters {
  margin: 0;
  padding: 0;
  border: 0;
}

.journal-grid {
  align-items: start;
}

.blog-tous-empty {
  padding: var(--ag-space-3xl) 0;
  color: var(--ag-ink-soft);
  text-align: center;
}

/* ==========================================================================
   Recherche — les deux zones de résultats (boutique puis blog)
   ========================================================================== */

.search-zone__head {
  margin-bottom: var(--ag-space-xl);
}

.search-zone__eyebrow {
  margin-bottom: var(--ag-space-xs);
}

.search-zone__title {
  margin: 0;
}

.search-zone__count {
  margin: var(--ag-space-2xs) 0 0;
  font-family: var(--ag-font-mono);
  font-size: var(--ag-text-cap);
  color: var(--ag-ink-soft);
}

/* Hairline between the zones: the two grids share a card rhythm, so section
   padding alone doesn't read as a boundary. */
.search-zone--blog {
  border-top: 1px solid var(--ag-rule);
}

/* The grid already carries the head's spacing; its own catalog margin would
   double it. */
.search-zone--boutique .patron-catalog__grid {
  margin-top: 0;
}

/* Collapsed boutique grid: three full rows, the rest behind the reveal button.
   `.is-collapsed` is applied by search-page.js, never by the server — without JS
   the grid stays whole and the button stays hidden.

   The 10 below is AG_SEARCH_BOUTIQUE_VISIBLE + 1 (inc/search-results.php). It is
   duplicated here because nth-child takes no custom property; change both. */
.search-zone__grid.is-collapsed > :nth-child(n + 10) {
  display: none;
}

.search-zone__more {
  margin-top: var(--ag-space-2xl);
  text-align: center;
}

/* `.btn` sets display: inline-flex, which outranks the UA stylesheet's
   `[hidden] { display: none }` — without this the button renders anyway, and a
   visitor without JS gets a reveal control that reveals nothing. */
.search-zone__more-btn[hidden] {
  display: none;
}

/* --- Pagination --- */

.blog-pagination {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ag-space-sm);
  align-items: center;
  justify-content: center;

  margin-top: var(--ag-space-3xl);
}

.blog-pagination .wp-block-query-pagination-numbers {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ag-space-sm);
  align-items: center;
}

.blog-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;

  width: 40px;
  height: 40px;
  border: 1px solid var(--ag-rule-strong);
  border-radius: 50%;

  font-family: var(--ag-font-mono);
  font-size: var(--ag-text-xs);
  color: var(--ag-ink);
  text-decoration: none;

  transition:
    color var(--ag-dur-base) var(--ag-ease),
    background-color var(--ag-dur-base) var(--ag-ease),
    border-color var(--ag-dur-base) var(--ag-ease);
}

.blog-pagination a.page-numbers:hover {
  border-color: var(--ag-ink);
  color: var(--ag-paper);
  background: var(--ag-ink);
}

.blog-pagination .page-numbers.current {
  border-color: var(--ag-ink);
  color: var(--ag-paper);
  background: var(--ag-ink);
}

.blog-pagination .wp-block-query-pagination-previous,
.blog-pagination .wp-block-query-pagination-next {
  font-family: var(--ag-font-mono);
  font-size: var(--ag-text-xs);
  color: var(--ag-ink);
  text-decoration: none;
}

@media (width <= 900px) {
  .blog-feature {
    grid-template-columns: 1fr;
    gap: var(--ag-space-lg);
  }

  .blog-themes-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (width <= 560px) {
  .blog-themes-grid {
    grid-template-columns: 1fr;
  }
}

@layer components {
  /* =============================================
   ARTICLE — gabarit single.html
   ============================================= */

  /* --- Fil d'Ariane + méta (ligne unique) --- */
  .article-eyebrow-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-md);
    align-items: baseline;
    justify-content: space-between;
  }

  .article-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    align-items: center;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .article-eyebrow-meta {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /*
   * `wp:html`'s raw markup emits five sibling nodes directly (no wrapper),
   * so core's unlayered `.is-layout-flow > * + *` block-gap rule applies its
   * margin-block-start to every crumb but the first. On a flex item that
   * margin isn't collapsed away like it would be in normal inline flow — it
   * pushes "Tricot" etc. down a few pixels relative to "Accueil", visibly off
   * the same baseline. `!important` because the offending rule is unlayered
   * and outranks anything in `@layer components` regardless of specificity —
   * see docs/solutions/theme-quality/cascade-layers-cannot-override-wordpress-theme-json.md.
   */
  .article-breadcrumb > * {
    margin-block: 0 !important;
  }

  .article-breadcrumb a {
    color: var(--ag-ink-soft);
  }

  .article-breadcrumb a:hover,
  .article-breadcrumb a:focus-visible {
    color: var(--ag-ink);
  }

  .article-breadcrumb .bc-sep {
    opacity: 0.5;
  }

  .article-breadcrumb .bc-axis {
    color: var(--ag-accent-deep);
  }

  /* --- Hero --- */
  .article-hero {
    padding-top: var(--ag-space-3xl);
    padding-bottom: var(--ag-space-4xl);
  }

  /*
   * The mockup's 22ch is sized for its display-l title (up to 96px); this
   * template uses the smaller display-m (up to 64px), so the same character
   * cap reads narrow at this size. Scaled by the size ratio (96/64) to keep
   * a comparable pixel measure.
   */
  .article-title {
    max-width: 34ch;
    margin: 0;

    font-size: var(--ag-text-display-m);
    line-height: var(--ag-leading-none);
    letter-spacing: var(--ag-tracking-tight);
  }

  .article-title .article-subtitle {
    font-style: italic;
    color: var(--ag-accent);
  }

  .article-hero-photo-wrap {
    margin-top: var(--ag-space-3xl);
  }

  .article-hero-figure {
    margin: 0;
  }

  /*
   * No `width: 100%`: that forced every hero image to fill the container even
   * when its own upload was narrower, upscaling it past its intrinsic size.
   * `max-width: 100%` alone still shrinks it to fit a narrow viewport, but
   * lets a wide container respect the image's native resolution instead.
   *
   * No `margin-inline: auto` either: a narrower-than-container image should
   * align with the title's left edge, not float centered in the `.ag-wrap`.
   */
  .article-hero-figure img {
    display: block;

    aspect-ratio: 16 / 9;
    max-width: 100%;
    height: auto;
    border-radius: var(--ag-radius-sm);

    object-fit: cover;
  }

  /*
   * `.article-prose` is the front-end className `single.html` gives
   * `wp:post-content`. The classic post editor doesn't render inside that
   * template — its canvas root only ever carries `.editor-styles-wrapper`
   * (on `<body>`) and `.wp-block-post-content`, never `.article-prose` — so
   * every rule below that only matched `.article-prose` rendered on the
   * published page and never previewed while Alice was actually writing.
   * `:is()` matches either ancestor without duplicating each rule.
   *
   * `.ag-prose` is the third member of that group: the portable hook for any
   * other rich-text field Alice authors in the same editor and expects to
   * look the same — today the WooCommerce long description in S4 Histoire,
   * which was rendering browser-default disc bullets next to the articles'
   * pink arrows. Two rules stay article-only and say so at their own site
   * (the prose measure and the drop cap).
   */
  .article-hero-figure figcaption,
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    :is(.wp-block-embed, .wp-block-image, .wp-block-gallery)
    figcaption {
    display: flex;
    gap: var(--ag-space-md);

    padding-top: var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /*
   * Corps : rail de sommaire + prose.
   *
   * Pas de padding-top ici : `.article-hero` porte déjà un padding-bottom du
   * même ordre juste au-dessus. Les deux cumulés doublaient l'espace blanc
   * entre la photo du hero et le sommaire/la prose.
   */
  .article-body {
    padding-bottom: var(--ag-space-5xl);
  }

  /* ---------------------------------------------
   PAGES LÉGALES — CGV, mentions légales

   These render through the generic `page.html`, which drops post-content
   straight into the 1480px `.ag-wrap`: an unreadable measure for continuous
   legal prose, and no `<h1>` since the template renders no post title. Both
   are fixed in the page content itself (a `.ag-legal` wrapper carrying the
   title), so no per-page template is needed — the body reuses `.ag-prose`.
   --------------------------------------------- */

  .ag-legal {
    max-width: 49.5rem; /* same measure as .article-prose */
    margin-inline: auto;
  }

  .ag-legal__title {
    margin-block: 0 var(--ag-space-2xl);
  }

  .article-layout {
    display: grid;
    grid-template-columns: 250px 1fr;
    gap: var(--ag-space-5xl);
    align-items: start;
  }

  /*
   * Prose measure for legacy content. Imported articles carry neither
   * .is-layout-constrained nor any block class, so the width is given to the
   * direct children of the prose container instead.
   *
   * A fixed `rem`, not `72ch`: `ch` is relative to each element's own font,
   * so the same "72ch" measured wider on the quote (display font, larger
   * size) than on a plain paragraph — visibly inconsistent column widths.
   * `rem` stays constant regardless of which child's font it's applied to.
   * 49.5rem matches what 72ch was already resolving to for body text.
   *
   * Article-only, hence no `.ag-prose`: the measure is tuned to the article
   * column. Prose reused inside an already-narrow grid column (the product
   * story) gets its width from that column instead.
   */
  :is(.article-prose, .editor-styles-wrapper .wp-block-post-content) > * {
    max-width: 49.5rem;
  }

  /*
   * Below the sommaire threshold, `.article-toc` never renders and `.article-prose`
   * is the grid's only child — auto-placement drops it into the 250px sommaire
   * column instead of spanning the row. Span explicitly, then hand the second
   * column back to the prose once a sommaire sibling is actually present.
   *
   * Grid placement only ever matters on the front end — the editor has no
   * `.article-layout` grid at all — so this one keeps the plain `.article-prose`
   * selector rather than the `:is()` pair used everywhere else here.
   */
  .article-prose {
    grid-column: 1 / -1;
  }

  /*
   * `--ag-prose-size` rather than a plain `font-size`, so a reuse site can
   * retune the scale to its column: the product story sits in a ~550px grid
   * column where the article's 18px reads oversized.
   *
   * It has to be a custom property and not an override rule. `:is()` takes
   * the specificity of its *most* specific argument, and
   * `.editor-styles-wrapper .wp-block-post-content` makes this selector
   * (0,2,0) — so even `.ag-prose.story-prose` ties and loses on source
   * order. A property declared only at the reuse site has nothing to tie
   * with.
   */
  :is(
    .article-prose,
    .ag-prose,
    .editor-styles-wrapper .wp-block-post-content
  ) {
    min-width: 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-prose-size, var(--ag-text-md));
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .article-layout:has(.article-toc) .article-prose {
    grid-column: 2;
  }

  /*
   * `!important` throughout this section's `margin-block`/`margin-top`/
   * `margin-bottom` declarations: core's unlayered `.is-layout-flow`
   * block-gap CSS sets `margin-block: 0` on every direct child and adds its
   * own gap only as `margin-block-start` between siblings, and unlayered
   * styles always beat `@layer components` regardless of specificity — see
   * docs/solutions/theme-quality/cascade-layers-cannot-override-wordpress-theme-json.md.
   * Every element below is a direct child of `.article-prose` /
   * `.wp-block-post-content`, so every one of them was affected.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    > p {
    margin-block: 0 var(--ag-space-lg) !important;
  }

  /*
   * Drop cap applied without an authored class: Alice will not add one.
   * Article-only, hence no `.ag-prose` — an editorial opener gesture, not
   * something a product description or any other reused prose block wants.
   */
  :is(.article-prose, .editor-styles-wrapper .wp-block-post-content)
    > p:first-of-type::first-letter {
    float: left;

    margin-inline-end: var(--ag-space-sm);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-hero-stat);
    font-style: italic;
    line-height: var(--ag-leading-none);
    color: var(--ag-accent);
  }

  /* ---------------------------------------------
   TRAITEMENT INLINE — liens et gras

   `.ag-rich` joins the group here and only here. The rules above and below
   are block-level scaffolding (measure, paragraph rhythm, list markers,
   heading scale) that a full prose block wants and a short authored blurb
   does not. Links and bold are different: they are properties of the *text*,
   so every surface where Alice writes needs them identically, whatever the
   block styling around it. `.ag-rich` is the hook for those surfaces — today
   the product short description in the hero, whose links were rendering with
   the base reset's `color: inherit; text-decoration: none` and so were not
   just off-palette but indistinguishable from body text.
   --------------------------------------------- */

  /*
   * `b` alongside `strong`: content imported from the legacy site (product
   * descriptions above all) was authored in the classic editor and carries
   * plain `<b>` tags, which the block editor never emits. Without it, the
   * same bold run reads semibold-ink in an article and UA-default in a
   * product description.
   */
  :is(
      .article-prose,
      .ag-prose,
      .ag-rich,
      .editor-styles-wrapper .wp-block-post-content
    )
    :is(strong, b) {
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  /*
   * `:not(.btn)`: a `.btn` anchor (e.g. the legacy `[button]` shortcode's
   * rendered CTA, inc/legacy-button-shortcode.php) sits directly in prose but
   * is a button, not an inline text link — without the exclusion this rule's
   * (0,3,1) specificity beat `.btn`'s (0,2,0) `color: var(--btn-fg)`, painting
   * `--ag-accent-deep` text on the `.btn-accent` pink background (near-
   * unreadable) plus a stray underline-like border under the pill.
   */
  :is(
      .article-prose,
      .ag-prose,
      .ag-rich,
      .editor-styles-wrapper .wp-block-post-content
    )
    a:not(:has(img), .btn, .yt-card-cta) {
    padding-bottom: 1px;
    border-bottom: 1px solid var(--ag-accent-deep);
    color: var(--ag-accent-deep);
  }

  /*
   * A bold run inside a link is the common shape for an emphasised CTA
   * ("pense au <a><strong>Pack Horizon</strong></a>"). The `strong` rule
   * above sets `color` on the element itself, which beats the link colour
   * inherited from the ancestor `a` — so the link tinted its underline pink
   * and left the words ink, reading as bold body text with a stray rule
   * under it. Hand the colour back to whichever link state is active.
   */
  :is(
      .article-prose,
      .ag-prose,
      .ag-rich,
      .editor-styles-wrapper .wp-block-post-content
    )
    a
    :is(strong, b) {
    color: inherit;
  }

  :is(
      .article-prose,
      .ag-prose,
      .ag-rich,
      .editor-styles-wrapper .wp-block-post-content
    )
    a:not(.btn, .yt-card-cta):hover,
  :is(
      .article-prose,
      .ag-prose,
      .ag-rich,
      .editor-styles-wrapper .wp-block-post-content
    )
    a:not(.btn, .yt-card-cta):focus-visible {
    border-bottom-color: var(--ag-ink);
    color: var(--ag-ink);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    h2 {
    margin-block: var(--ag-space-5xl) var(--ag-space-lg) !important;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-display-s);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    h3 {
    margin-block: var(--ag-space-2xl) var(--ag-space-md) !important;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ul,
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ol {
    margin-block: 0 var(--ag-space-lg) !important;
    padding-inline-start: 0;
    list-style: none;
  }

  /*
   * A nested list is a continuation of its parent item, not a new block: the
   * `--ag-space-lg` trailing gap above belongs after the *outer* list only.
   * Left in place it opened a 24px hole between a sub-list and the next
   * top-level bullet — visible on any product description with a nested
   * "laine recommandée" sub-list.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    li
    > :is(ul, ol) {
    margin-block: var(--ag-space-2xs) 0 !important;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    li {
    position: relative;
    margin-bottom: var(--ag-space-2xs);
    padding-inline-start: var(--ag-space-lg);
  }

  /*
   * The classic editor wraps every list item's text in its own `<p>`. The
   * `> p` rule above only reaches direct children of the prose root, so those
   * inner paragraphs kept the UA's 1em block margins and blew each bullet
   * apart. Collapse them; a genuine second paragraph inside one item still
   * gets a gap from the sibling rule.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    li
    > p {
    margin-block: 0 !important;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    li
    > p
    + p {
    margin-block-start: var(--ag-space-2xs) !important;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ul
    > li::before {
    content: "→";

    position: absolute;
    inset-inline-start: 0;

    font-family: var(--ag-font-mono);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-accent);
  }

  /*
   * Sub-levels drop back to a quiet dash. A nested list multiplies the arrow
   * across a block of items that are already subordinate, and accent is a
   * signal used once per viewport — a column of pink arrows under another
   * column of pink arrows reads as noise and flattens the hierarchy the
   * nesting is there to express.
   *
   * `li ul`, not `li > ul`: this has to hold at every depth below the first,
   * not just the second level.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    li
    ul
    > li::before {
    content: "–";
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink-soft);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ol {
    counter-reset: ag-ol;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ol
    > li {
    counter-increment: ag-ol;
    padding-inline-start: var(--ag-space-2xl);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    ol
    > li::before {
    content: counter(ag-ol, decimal-leading-zero);

    position: absolute;
    inset-inline-start: 0;
    top: 0.2em;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    img {
    max-width: 100%;
    height: auto;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    figcaption {
    padding-top: var(--ag-space-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* ---------------------------------------------
   BLOCS EDITORIAUX — traitement des blocs natifs

   L'aspect editorial est celui du bloc *nu* : les contenus importes ne portent
   aucune classe de style, donc ils en heritent sans edition. Les variations
   nommees sont reservees aux ecarts.
   --------------------------------------------- */

  /*
   * `margin-block` needs `!important`: core's unlayered `.is-layout-flow`
   * block-gap rule sets `margin-block: 0` plus a `margin-block-start` gap
   * between siblings only, and unlayered styles beat anything in
   * `@layer components` regardless of specificity — see
   * docs/solutions/theme-quality/cascade-layers-cannot-override-wordpress-theme-json.md.
   * Without it the quote measured 24px top / 0px bottom instead of the 40px
   * each side specified here, in both the editor and the front end.
   *
   * `margin-inline: 0` on top of that: the browser's UA stylesheet gives
   * every `<blockquote>` a ~40px inline margin. Nothing here overrode it, so
   * fixing the block-gap conflict just exposed it — the quote sat 40px
   * indented from where the surrounding paragraphs start.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote {
    position: relative;

    margin-block: var(--ag-space-2xl) !important;
    margin-inline: 0 !important;
    padding-left: var(--ag-space-xl);
    padding-block: var(--ag-space-lg);
    border-left: 3px solid var(--ag-accent);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-style: italic;
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote
    p {
    margin-block: 0 var(--ag-space-xs);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote
    p:first-child::before {
    content: "\201C";

    transform: translateY(0.3em);

    display: inline-block;

    margin-right: var(--ag-space-3xs);

    font-size: calc(var(--ag-text-xxl) * 2.3);
    line-height: calc(var(--ag-leading-none) * 0);
    color: var(--ag-accent);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote
    cite {
    display: block;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-style: normal;
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* Ecart nomme : bandeau pleine largeur sur fond sombre. */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote.is-style-bandeau-sombre {
    padding: var(--ag-space-3xl);
    border-left: 0;
    border-radius: var(--ag-radius-md);

    color: var(--ag-cream);
    text-align: center;

    background-color: var(--ag-deep-navy);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote.is-style-bandeau-sombre
    cite {
    color: var(--ag-accent);
  }

  /*
   * The generic `strong` rule below hard-codes `--ag-ink` (near-black) for
   * the light background the rest of the prose sits on. Left as-is, any
   * bold word inside this dark card would inherit that instead of the
   * card's own cream text — dark-on-dark, effectively invisible.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-quote.is-style-bandeau-sombre
    strong {
    color: inherit;
  }

  /*
   * Closing note before "Continuer le parcours" — a teaser to a future or
   * related article, set off from the surrounding prose. A style variation,
   * not the bare-element default: unlike the quote's editorial citation, most
   * paragraphs in an article are not a closing note, so this one is opt-in.
   */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-paragraph.is-style-note-cloture {
    margin-block: var(--ag-space-3xl) !important;
    padding-inline-start: var(--ag-space-lg);
    border-inline-start: 2px solid var(--ag-accent);

    font-style: italic;
    color: var(--ag-ink-soft);
  }

  /* Same UA-default inline margin as blockquote: `<figure>` ships ~40px too. */
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    :is(.wp-block-image, .wp-block-embed, .wp-block-gallery) {
    margin-block: var(--ag-space-2xl) !important;
    margin-inline: 0 !important;
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    :is(.wp-block-image, .wp-block-embed)
    img,
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-embed
    iframe {
    border-radius: var(--ag-radius-sm);
  }

  .article-hero-figure figcaption::before,
  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    :is(.wp-block-embed, .wp-block-image, .wp-block-gallery)
    figcaption::before {
    content: "—";
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-accent-deep);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    mark {
    padding-inline: var(--ag-space-3xs);
    color: var(--ag-ink);
    background-color: var(--ag-mint);
  }

  :is(.article-prose, .ag-prose, .editor-styles-wrapper .wp-block-post-content)
    .wp-block-separator {
    margin-block: var(--ag-space-3xl) !important;
    border: 0;
    border-top: 1px solid var(--ag-rule);
  }

  /* ---------------------------------------------
   BLOCS EDITORIAUX ACF
   --------------------------------------------- */

  .ag-editorial {
    margin-block: var(--ag-space-2xl);
  }

  /* Placeholder d'editeur : un bloc vide ne doit jamais etre invisible. */
  .ag-editorial--vide {
    padding: var(--ag-space-lg);
    border: 1px dashed var(--ag-rule-strong);
    border-radius: var(--ag-radius-md);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-align: center;
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  /* --- Astuce d'Alice --- */
  .ag-astuce {
    overflow: hidden;
    display: grid;
    grid-template-columns: 96px 1fr;

    border-radius: var(--ag-radius-md);

    background-color: var(--ag-mint);
  }

  .ag-astuce__mark {
    display: flex;
    align-items: center;
    justify-content: center;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxxl);
    font-style: italic;
    color: var(--ag-accent);

    background-color: var(--ag-deep-navy);
  }

  .ag-astuce__body {
    padding: var(--ag-space-xl);
  }

  .ag-astuce__title,
  .ag-erreur__title,
  .ag-patron__title,
  .ag-faq__title {
    margin-block: var(--ag-space-2xs) var(--ag-space-md);
  }

  .ag-astuce__text p:last-child,
  .ag-erreur__text p:last-child {
    margin-bottom: 0;
  }

  .ag-astuce__sig {
    margin-block: var(--ag-space-md) 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-base);
    font-style: italic;
    color: var(--ag-accent-deep);
  }

  /* --- Erreur frequente --- */
  .ag-erreur {
    padding: var(--ag-space-xl);
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-md);
  }

  .ag-erreur__cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-xl);
    margin-top: var(--ag-space-md);
  }

  .ag-erreur__col {
    padding-top: var(--ag-space-md);
    border-top: 2px solid var(--ag-rule);
  }

  .ag-erreur__col--wrong {
    border-top-color: var(--ag-accent);
  }

  .ag-erreur__col--right {
    border-top-color: var(--ag-secondary);
  }

  /* --- Patron recommande --- */
  .ag-patron {
    overflow: hidden;
    display: grid;
    grid-template-columns: 280px 1fr;

    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-md);
  }

  .ag-patron__img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .ag-patron__body {
    padding: var(--ag-space-xl);
  }

  .ag-patron__desc {
    margin-block: 0 var(--ag-space-md);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .ag-patron__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-md);
    align-items: baseline;

    margin-block: 0 var(--ag-space-md);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .ag-patron__cta {
    border-bottom: 1px solid var(--ag-accent);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .ag-patron__cta:hover,
  .ag-patron__cta:focus-visible {
    border-bottom-color: var(--ag-ink);
    color: var(--ag-ink);
  }

  /* --- FAQ d'article : reprend les styles d'item de la fiche patron --- */
  .ag-faq__items {
    margin-top: var(--ag-space-md);
  }

  /* --- Continuer le parcours --- */
  .article-continuer__lede {
    max-width: 56ch;
    margin-block: var(--ag-space-2xs) var(--ag-space-xl);
    font-size: var(--ag-text-base);
  }

  .article-continuer__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-xl) var(--ag-space-3xl);
  }

  .article-continuer__grid[data-count="1"] {
    grid-template-columns: minmax(0, 34rem);
  }

  .article-continuer__grid[data-count="2"] {
    grid-template-columns: repeat(2, 1fr);
  }

  /* A compact row — thumbnail and text side by side — not a photo card. */
  .article-continuer__item {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    padding-top: var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule);
  }

  /*
   * `aspect-ratio` lives on this plain wrapper, not on the `<img>` itself:
   * on a replaced element the CSS ratio can lose to the `width`/`height`
   * HTML attributes WordPress always renders, so the box collapsed to the
   * image's own intrinsic height instead of the 16:9 slot. A wrapper with
   * no intrinsic size has nothing to conflict with.
   */
  .article-continuer__thumb {
    overflow: hidden;
    aspect-ratio: 16 / 9;
    width: 100%;
    border-radius: var(--ag-radius-sm);
  }

  .article-continuer__img,
  .article-continuer__thumb .slot {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .article-continuer__body {
    display: block;
    min-width: 0;
  }

  .article-continuer__cat {
    display: block;
    margin-bottom: var(--ag-space-3xs);
  }

  .article-continuer__card-title {
    display: block;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  .article-continuer__desc {
    display: block;

    margin-top: var(--ag-space-3xs);

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .article-continuer__item:hover .article-continuer__card-title,
  .article-continuer__item:focus-visible .article-continuer__card-title {
    color: var(--ag-accent);
  }

  /* --- Sommaire --- */

  /* Offsets from --ag-header-h, not a bare spacing step: the sticky header is
     opaque, so a smaller top parked the sommaire title and item 01 underneath
     it. max-height subtracts the same offset plus a bottom gutter, otherwise
     the rail runs past the viewport and its own scrollbar hides the last
     items. */
  .article-toc {
    position: sticky;
    z-index: var(--ag-z-raised);
    top: calc(var(--ag-header-h) + var(--ag-space-lg));

    overflow-y: auto;
    align-self: start;

    max-height: calc(100vh - var(--ag-header-h) - var(--ag-space-2xl) - var(--ag-space-lg));
  }

  .article-toc-title {
    margin-block: 0 var(--ag-space-md);
  }

  .article-toc-list {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .article-toc-item {
    position: relative;
    padding-left: var(--ag-space-md);
    border-left: 1px solid var(--ag-rule);
    transition: border-color var(--ag-dur-base) var(--ag-ease);
  }

  .article-toc-item.is-active {
    border-left-color: var(--ag-accent);
  }

  .article-toc-item.is-active::before {
    content: "";

    position: absolute;
    top: 14px;
    left: -3px;

    width: 5px;
    height: 5px;
    border-radius: var(--ag-radius-pill);

    background-color: var(--ag-accent);
  }

  .article-toc-item a {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--ag-space-xs);

    padding-block: var(--ag-space-2xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink-soft);
  }

  .article-toc-item.is-active a,
  .article-toc-item a:hover,
  .article-toc-item a:focus-visible {
    color: var(--ag-ink);
  }

  /*
   * `--accent-deep` on every number, not just the active one: the mockup's
   * `.toc-num` (styles.css:1658) is unconditionally accent-deep. That's the
   * muted pressed-state pink, not the bright `--accent` DESIGN.md caps at one
   * element per viewport — the two tokens carry different budgets.
   */
  .article-toc-item .toc-num {
    padding-top: 2px;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-accent-deep);
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .article-toc-progress {
    margin-top: var(--ag-space-xl);
    padding-top: var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule);
  }

  .article-progress {
    overflow: hidden;
    height: 4px;
    border-radius: var(--ag-radius-pill);
    background-color: var(--ag-rule);
  }

  .article-progress-fill {
    display: block;

    width: 0;
    height: 100%;
    border-radius: var(--ag-radius-pill);

    background-color: var(--ag-accent);

    transition: width var(--ag-dur-fast) linear;
  }

  /* Headings clear the sticky site header when reached from the sommaire, plus
     breathing room above the heading. --ag-space-4xl alone (56px) left headings
     half-hidden under it. */
  .article-prose :is(h2, h3) {
    scroll-margin-top: calc(var(--ag-header-h) + var(--ag-space-lg));
  }

  @media (prefers-reduced-motion: reduce) {
    .article-progress-fill {
      transition: none;
    }
  }

  @media (width <= 900px) {
    .article-layout {
      grid-template-columns: 1fr;
      gap: var(--ag-space-xl);
    }

    /*
     * `.article-layout:has(.article-toc) .article-prose { grid-column: 2; }`
     * applies at every width, and its specificity (two classes plus a
     * pseudo-class) beats a plain `.article-prose` reset regardless of
     * source order. Matching the same selector here is what lets this rule
     * actually win under the breakpoint.
     */
    .article-layout:has(.article-toc) .article-prose {
      grid-column: 1;
    }

    /*
     * Below the breakpoint the sommaire is a full-width card above the prose, not
     * a rail. Sticky is dropped, and so is the progress bar: sitting in a static
     * box at the top of the page it would scroll out of view immediately and could
     * never report progress.
     */
    .article-toc {
      position: static;

      overflow-y: visible;

      max-height: none;
      padding: var(--ag-space-lg);
      border-radius: var(--ag-radius-md);

      background-color: var(--ag-paper-deep);
    }

    .article-toc-progress {
      display: none;
    }
  }

  @media (width <= 900px) {
    .ag-erreur__cols,
    .ag-patron {
      grid-template-columns: 1fr;
    }

    .article-continuer__grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .ag-astuce {
      grid-template-columns: 1fr;
    }

    .ag-astuce__mark {
      padding-block: var(--ag-space-md);
    }

    .article-continuer__grid {
      grid-template-columns: 1fr;
    }
  }
}

@layer components {
  /* ============================================================
     Hub « Oser le jacquard »
     ============================================================ */

  /* --- Hero + frise (U2) --------------------------------------- */
  .hub-hero {
    padding-top: var(--ag-space-5xl);
    padding-bottom: var(--ag-space-4xl);
  }

  .hub-hero-title {
    margin: 0 0 var(--ag-space-2xl);
  }

  .hub-hero-title .serif-it {
    color: var(--ag-accent);
  }

  .hub-hero-lead {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: end;

    margin-bottom: var(--ag-space-3xl);
  }

  .hub-promise {
    margin: 0;
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
  }

  .hub-hero-lead-body .lede {
    margin: 0 0 var(--ag-space-lg);
  }

  .hub-hero-cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
  }

  .hub-frise {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0;
  }

  .hub-frise-item {
    display: block;
  }

  .hub-frise-item:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: -3px;
  }

  .hub-frise-photo {
    position: relative;
    overflow: hidden;
    display: block;
    aspect-ratio: 4 / 5;
  }

  .hub-frise-photo .slot,
  .hub-frise-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .hub-frise-item:hover .hub-frise-photo img {
    transform: scale(1.05);
  }

  .hub-frise-overlay {
    position: absolute;
    inset: 0;

    display: flex;
    align-items: flex-end;
    justify-content: center;

    padding-bottom: var(--ag-space-sm);

    opacity: 0;
    background: linear-gradient(to top, rgb(20 32 51 / 45%), transparent 55%);

    transition: opacity var(--ag-dur-base) var(--ag-ease);
  }

  .hub-frise-item:hover .hub-frise-overlay,
  .hub-frise-item:focus-visible .hub-frise-overlay {
    opacity: 1;
  }

  .hub-frise-name {
    font-size: var(--ag-text-xs);
    font-weight: 600;
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-wide);
  }

  @media (width <= 900px) {
    .hub-frise {
      grid-template-columns: repeat(3, 1fr);
    }
  }

  @media (width <= 720px) {
    .hub-hero-lead {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }

    .hub-frise {
      scroll-padding-left: var(--ag-space-lg);
      scroll-snap-type: x mandatory;

      overflow-x: auto;
      display: flex;
      gap: var(--ag-space-xs);
    }

    .hub-frise-item {
      scroll-snap-align: start;
      flex: 0 0 46%;
    }
  }
}

@layer components {
  /* --- Portes « Par où commencer ? » (U3) ---------------------- */
  .hub-portes-block {
    padding-top: var(--ag-space-4xl);
    padding-bottom: var(--ag-space-4xl);
  }

  .hub-portes-label {
    display: block;
    margin-bottom: var(--ag-space-lg);
  }

  .hub-portes {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ag-space-sm);
  }

  .hub-porte {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    padding: var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    color: var(--ag-ink);
    text-decoration: none;

    background: var(--ag-paper);

    transition:
      border-color var(--ag-dur-base) var(--ag-ease),
      transform var(--ag-dur-base) var(--ag-ease);
  }

  .hub-porte:hover {
    transform: translateY(-2px);
    border-color: var(--ag-ink);
  }

  .hub-porte:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: 3px;
  }

  .hub-porte-idx {
    font-family: var(--ag-font-mono, monospace);
    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
  }

  .hub-porte-q {
    font-size: var(--ag-text-md);
    font-weight: 600;
    line-height: var(--ag-leading-snug);
  }

  .hub-porte-go {
    margin-top: auto;
    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
  }

  @media (width <= 900px) {
    .hub-portes {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .hub-portes {
      grid-template-columns: 1fr;
    }
  }
}

@layer components {
  /* --- À la une (U4) ------------------------------------------- */
  .hub-une {
    padding-top: var(--ag-space-4xl);
    padding-bottom: var(--ag-space-4xl);
  }

  .hub-une-head {
    margin-bottom: var(--ag-space-2xl);
  }

  .hub-une-heading {
    margin: var(--ag-space-2xs) 0 0;
  }

  .hub-une-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: start;
  }

  .hub-une-feature {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);
  }

  .hub-une-photo {
    overflow: hidden;
    display: block;
    aspect-ratio: 16 / 9;
    border-radius: var(--ag-radius-sm);
  }

  .hub-une-photo .slot,
  .hub-une-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .hub-une-feature-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-sm);
    align-items: center;
  }

  .hub-une-title {
    font-size: var(--ag-text-xxl);
    line-height: var(--ag-leading-snug);
  }

  .hub-une-excerpt {
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .hub-une-readmore {
    align-self: flex-start;

    margin-top: var(--ag-space-2xs);

    font-size: var(--ag-text-sm);
    font-weight: 600;
    color: var(--ag-accent);
  }

  .hub-une-feature:hover .hub-une-readmore .btn-arrow {
    transform: translateX(3px);
  }

  .hub-une-side {
    padding-top: var(--ag-space-2xs);
  }

  .hub-une-list {
    display: flex;
    flex-direction: column;
    margin-top: var(--ag-space-sm);
  }

  /* Grille 110px + reste, comme `.hubv5-une-item` de la maquette (hub.jsx) :
     en flex avec une vignette de 72px les trois lignes ne s'alignaient pas et
     la colonne de texte flottait. */
  .hub-une-item {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: var(--ag-space-md);
    align-items: center;

    padding: var(--ag-space-xs) 0;
    border-top: 1px solid var(--ag-rule);

    color: var(--ag-ink);
    text-decoration: none;

    transition: padding-left var(--ag-dur-base) var(--ag-ease);
  }

  .hub-une-item:hover {
    padding-left: var(--ag-space-2xs);
  }

  /* Ratio d'origine de la photo, pas celui de la maquette : ces vignettes sont
     des miniatures 16/9 avec le titre incrusté dans l'image, qu'un recadrage en
     4/3 coupait sur les côtés jusqu'à rendre le texte illisible. */
  .hub-une-item-thumb {
    overflow: hidden;
    border-radius: var(--ag-radius-sm);
  }

  .hub-une-item-thumb img {
    display: block;
    width: 100%;
    height: auto;
  }

  /* Article sans image : le motif hachuré tient la place de la vignette. */
  .hub-une-item-thumb > span.slot {
    display: block;
    aspect-ratio: 4 / 3;
    width: 100%;
  }

  .hub-une-item-body {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
    min-width: 0;
  }

  .hub-une-item:hover .hub-une-item-title {
    color: var(--ag-accent-deep);
  }

  .hub-une-item:focus-visible {
    outline: 2px solid var(--ag-accent);
    outline-offset: 3px;
  }

  /* `.display` porte la famille et la graisse ; ici seule la taille descend
     sous l'échelle display, trop grosse pour une liste latérale. */
  .hub-une-item-title {
    font-size: var(--ag-text-lg);
    transition: color var(--ag-dur-base) var(--ag-ease);
  }

  @media (width <= 900px) {
    .hub-une-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }
  }
}

@layer components {
  /* --- Sommaire de référence (U5, section sombre) -------------- */
  .hub-sommaire {
    padding-top: var(--ag-space-5xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .hub-sommaire-head {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: end;

    margin-bottom: var(--ag-space-3xl);
  }

  .hub-sommaire-heading {
    margin: var(--ag-space-2xs) 0 0;
  }

  .hub-sommaire-intro {
    max-width: 40ch;
    margin: 0;
    color: var(--ag-on-dark);
  }

  .hub-sommaire-cols {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-2xl);
  }

  .hub-sommaire-col-title {
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: baseline;

    margin: 0 0 var(--ag-space-sm);

    font-size: var(--ag-text-lg);
    color: var(--ag-cream);
  }

  .hub-sommaire-num {
    color: var(--ag-accent);
  }

  .hub-sommaire-desc {
    margin: 0 0 var(--ag-space-sm);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-on-dark);
  }

  .hub-sommaire-links {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .hub-sommaire-link {
    padding: var(--ag-space-sm) 0;
    border-top: 1px solid var(--ag-rule-dark);
    font-size: var(--ag-text-sm);
  }

  .hub-sommaire-link a {
    color: var(--ag-cream);
    text-decoration: none;
    transition: color var(--ag-dur-base) var(--ag-ease);
  }

  .hub-sommaire-link a:hover {
    color: var(--ag-accent);
  }

  .hub-sommaire-link.is-upcoming {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
    align-items: center;

    color: var(--ag-on-dark);
  }

  .hub-sommaire-tag {
    padding: 2px var(--ag-space-2xs);
    border: 1px solid var(--ag-rule-dark);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-on-dark);
    text-transform: uppercase;
  }

  .hub-sommaire-more {
    display: inline-block;

    margin-top: var(--ag-space-md);

    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
    text-decoration: none;
  }

  @media (width <= 900px) {
    .hub-sommaire-head {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }

    .hub-sommaire-cols {
      grid-template-columns: 1fr;
    }
  }
}

@layer components {
  /* --- Tricoter pour apprendre (U7) --------------------------- */
  .hub-patrons {
    padding-top: var(--ag-space-4xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .hub-patrons-head {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-3xl);
    align-items: end;

    margin-bottom: var(--ag-space-2xl);
  }

  .hub-patrons-heading {
    margin: var(--ag-space-2xs) 0 0;
  }

  .hub-patrons-intro {
    max-width: 44ch;
    margin: 0;
    color: var(--ag-ink-soft);
  }

  .hub-patron-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
  }

  .hub-patron-photo {
    overflow: hidden;
    display: block;

    aspect-ratio: 4 / 5;
    margin-bottom: var(--ag-space-2xs);
    border-radius: var(--ag-radius-sm);
  }

  .hub-patron-photo .slot,
  .hub-patron-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Même police, alignement et couleur de prix que .patron-card (carte
     boutique) — la carte du hub avait sa propre recette au lieu de reprendre
     celle-ci, d'où une divergence visuelle (anomalie Alice du 2026-08-16,
     point 6). */
  .hub-patron-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--ag-space-sm);
    align-items: baseline;
  }

  .hub-patron-title {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-none);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-snug);
  }

  .hub-patron-title a {
    color: var(--ag-ink);
    text-decoration: none;
  }

  .hub-patron-price {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-lg);
    color: var(--ag-ink-soft);
    white-space: nowrap;
  }

  .hub-patrons-foot {
    display: flex;
    justify-content: center;
    margin-top: var(--ag-space-3xl);
  }

  @media (width <= 900px) {
    .hub-patrons-head {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }
  }
}

@layer wp-overrides {
  /* WordPress émet du CSS de layout non-layered qui remet à 0 les marges auto
     de .ag-wrap aux grands viewports : le conteneur cesse alors d'être centré.
     On rétablit le centrage avec !important (le non-layered normal perd face à
     un !important layered). Voir docs/solutions/theme-quality/. */
  .ag-wrap {
    margin-right: auto !important;
    margin-left: auto !important;
  }

  /* Le block-gap global de WordPress (:where(.is-layout-flow) > * =>
     margin-block-start: 24px) crée une bande blanche entre deux sections
     pleine largeur colorées adjacentes. On colle les bandes colorées entre
     elles, comme la maquette. Le hub Jacquard intercale `.livre-book`
     (elle-même `.band`) dans un wrapper `.livre-book-tone-mint` pour la
     teinter en vert — ce wrapper, pas `.livre-book`, est le frère direct de
     `.hub-sommaire` dans le flux, donc `.band + .band` ne le voit pas
     (anomalie Alice du 2026-08-16, point 7). */
  .band + .band,
  .hub-sommaire + .livre-book-tone-mint {
    margin-block-start: 0 !important;
  }
}

@layer components {
  /* --- Le livre « Oser le Jacquard en Rond » (fond mint, partagé home/hub) -- */
  .band-mint {
    background-color: var(--ag-mint);
  }

  .band-mint .eyebrow,
  .band-mint .eyebrow-accent {
    color: var(--ag-accent-deep);
  }

  /* Le fond appartient à la page, pas au bloc. La maquette pose le livre en
     blanc sur l'accueil et la boutique, en vert sur le Hub Oser le Jacquard —
     d'où un défaut blanc et une teinte que le hub porte lui-même. */
  .livre-book {
    background: var(--ag-paper);
  }

  .livre-book-tone-mint .livre-book {
    background: var(--ag-mint);
  }

  .livre-book-tone-mint .livre-book .eyebrow,
  .livre-book-tone-mint .livre-book .eyebrow-accent {
    color: var(--ag-accent-deep);
  }

  .livre-book-grid {
    display: grid;
    grid-template-columns: 0.85fr 1.15fr;
    gap: var(--ag-space-5xl);
    align-items: center;
  }

  .livre-book-cover-wrap {
    display: flex;
    justify-content: center;
  }

  .livre-book-cover-frame {
    position: relative;
    width: 100%;
    max-width: 360px;
  }

  .livre-book-cover-panel {
    position: absolute;
    z-index: 0;
    inset: 7% -6% 7% 14%;

    border-radius: var(--ag-radius-sm);

    background: color-mix(in srgb, var(--ag-mint) 82%, var(--ag-ink));
  }

  .livre-book-cover-img {
    position: relative;
    z-index: 1;

    display: block;

    width: 100%;
    height: auto;
    border-radius: var(--ag-radius-sm);

    box-shadow: var(--ag-shadow-lg);
  }

  .livre-book-title {
    margin: var(--ag-space-sm) 0 0;
  }

  .livre-book-lede {
    max-width: 46ch;
    margin: var(--ag-space-lg) 0;
  }

  .livre-book-features {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-xs) var(--ag-space-xl);

    margin: 0 0 var(--ag-space-lg);
    padding: 0;

    list-style: none;
  }

  .livre-book-features li {
    position: relative;
    padding-left: var(--ag-space-md);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink);
  }

  .livre-book-features li::before {
    content: "";

    position: absolute;
    top: 8px;
    left: 0;
    transform: rotate(45deg);

    width: 7px;
    height: 7px;

    background: var(--ag-accent);
  }

  .livre-book-btns {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    margin-top: var(--ag-space-lg);
  }

  @media (width <= 900px) {
    .livre-book-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .livre-book-cover-wrap {
      justify-content: flex-start;
    }
  }

  @media (width <= 720px) {
    .livre-book-features {
      grid-template-columns: 1fr;
    }
  }
}

/* ==========================================================================
   FICHE RESSOURCE — famille papeterie PDF
   Porté depuis mockup_refv2/ressource.css. Chaque grande section porte sa
   propre identité de fond, ce qui rythme une page nettement plus longue que
   la fiche patron. Le slider de galerie de la maquette n'est pas repris :
   l'aperçu réutilise la mosaïque de s6-angles (KTD10 du plan).
   ========================================================================== */

@layer components {
  .band-ice {
    background: var(--ag-blue-ice);
  }

  .res-section-eyebrow {
    margin-bottom: var(--ag-space-xs);
  }

  .res-section-title {
    margin: 0 0 var(--ag-space-xl);
  }

  .res-centered-eyebrow {
    margin-bottom: var(--ag-space-xs);
    text-align: center;
  }

  .res-centered-title {
    margin: 0 0 var(--ag-space-3xl);
    text-align: center;
  }

  /* ===== Hero ===== */
  .res-hero {
    padding-top: var(--ag-space-2xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .res-hero-grid {
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: var(--ag-space-5xl);
    align-items: center;
  }

  .res-hero-title {
    margin: 0 0 var(--ag-space-md);
  }

  .res-hero-tagline {
    max-width: 42ch;
    margin: 0 0 var(--ag-space-lg);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-style: italic;
    color: var(--ag-ink-soft);
  }

  .res-hero-intro {
    max-width: 48ch;
    margin: 0 0 var(--ag-space-md);

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .res-benefit-list {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-xs);

    margin: 0 0 var(--ag-space-xl);
    padding: 0;

    list-style: none;
  }

  .res-benefit-list li {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: flex-start;

    font-size: var(--ag-text-base);
    color: var(--ag-ink);
  }

  .res-benefit-tick {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;

    width: var(--ag-space-md);
    height: var(--ag-space-md);
    border-radius: 50%;

    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-bold);
    color: var(--ag-secondary);

    background: var(--ag-mint);
  }

  .res-add-panel {
    max-width: 420px;
  }

  .res-add-panel-head {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;
    justify-content: space-between;
  }

  .res-cta-secure {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-align: center;
    letter-spacing: var(--ag-tracking-label);
  }

  .res-hero-photo {
    position: relative;
  }

  .res-hero-photo > .slot {
    aspect-ratio: 4 / 5;
    border-radius: var(--ag-radius-md);
  }

  .res-hero-side {
    position: absolute;
    right: calc(var(--ag-space-xl) * -1);
    bottom: calc(var(--ag-space-lg) * -1);
    display: flex;
  }

  .res-hero-side-item {
    overflow: hidden;

    width: 108px;
    border: var(--ag-space-3xs) solid var(--ag-paper);
    border-radius: var(--ag-radius-md);

    box-shadow: var(--ag-shadow-md);
  }

  .res-hero-side-item:nth-child(1) {
    z-index: var(--ag-z-raised);
    transform: rotate(-6deg) translateY(-8px);
    margin-right: calc(var(--ag-space-lg) * -1);
  }

  .res-hero-side-item:nth-child(2) {
    z-index: var(--ag-z-raised);
    transform: rotate(3deg);
  }

  .res-hero-side-item:nth-child(3) {
    z-index: var(--ag-z-raised);
    transform: rotate(10deg) translateY(6px);
    margin-left: calc(var(--ag-space-lg) * -1);
  }

  .res-hero-side-item .slot {
    aspect-ratio: 3 / 4;
    border-radius: 0;
  }

  /* ===== Problème ===== */
  .res-problem {
    color: var(--ag-cream);
    background: var(--ag-ink);
  }

  .res-problem-inner {
    max-width: 640px;
  }

  .res-problem-title {
    margin: 0 0 var(--ag-space-lg);
    font-size: var(--ag-text-display-s);
    color: var(--ag-cream);
  }

  .res-problem-list {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-xs);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .res-problem-list li {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: baseline;

    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-snug);
    color: var(--ag-cream);
  }

  .res-problem-tick {
    flex-shrink: 0;
    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
  }

  /* ===== Solution ===== */
  .res-solution-band {
    background: var(--ag-blue-ice);
  }

  .res-solution-pad {
    padding: var(--ag-space-4xl) 0;
  }

  /* Le visuel est optionnel : sans lui la colonne de texte occupe la bande
     entière, plutôt que de laisser un vide à droite. */
  .res-solution-grid {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    gap: var(--ag-space-3xl);
    align-items: center;
  }

  .res-solution-grid:not(:has(.res-solution-visual)) {
    grid-template-columns: 1fr;
  }

  .res-solution-title {
    margin: 0 0 var(--ag-space-md);
    color: var(--ag-ink-soft);
  }

  .res-solution-promise {
    margin: 0 0 var(--ag-space-lg);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-display-s);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .res-solution-body {
    max-width: 44ch;
    margin: 0;

    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  /* Cadrage paysage : en portrait (4/5) la bande devenait plus haute que son
     texte et poussait le reste de la fiche vers le bas. */
  .res-solution-visual .slot {
    aspect-ratio: 5 / 4;
    border-radius: var(--ag-radius-md);
    box-shadow: var(--ag-shadow-md);
  }

  /* ===== Contenu ===== */
  .res-contents-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--ag-space-md);
  }

  .res-content-card {
    display: grid;
    grid-template-columns: 96px 1fr;
    gap: var(--ag-space-md);
    align-items: center;

    padding: var(--ag-space-md);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
  }

  .res-content-card .slot {
    aspect-ratio: 3 / 4;
    border-radius: var(--ag-radius-sm);
  }

  .res-content-num {
    display: block;

    margin-bottom: var(--ag-space-3xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-accent-deep);
    letter-spacing: var(--ag-tracking-label);
  }

  .res-content-card h3 {
    margin: 0 0 var(--ag-space-3xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-snug);
  }

  .res-content-card p {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  /* ===== Ce que ça change ===== */
  .res-perks-band {
    background: var(--ag-mint);
  }

  .res-perks-grid {
    display: grid;
    grid-template-columns: 0.9fr 1.1fr;
    gap: var(--ag-space-4xl);
    align-items: start;
  }

  .res-perks-title {
    margin: 0;
    color: var(--ag-secondary);
  }

  .res-perks-list {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .res-perks-list li {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;

    padding: var(--ag-space-md) 0;
    border-bottom: 1px solid var(--ag-rule);
  }

  .res-perks-list li:last-child {
    padding-bottom: 0;
    border-bottom: none;
  }

  .res-perks-num {
    flex-shrink: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-secondary);
    letter-spacing: var(--ag-tracking-label);
  }

  .res-perks-list h3 {
    margin: 0 0 var(--ag-space-3xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-secondary);
  }

  .res-perks-list p {
    margin: 0;
    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
  }

  /* ===== Comment ça marche ===== */
  .res-timeline {
    display: grid;
    grid-template-columns: repeat(var(--res-steps, 4), 1fr);
    align-items: start;
  }

  .res-timeline-step {
    position: relative;
    padding: 0 var(--ag-space-lg);
    text-align: center;
  }

  .res-timeline-step:first-child {
    padding-left: 0;
  }

  .res-timeline-step:last-child {
    padding-right: 0;
  }

  .res-timeline-num {
    display: flex;
    align-items: center;
    justify-content: center;

    width: var(--ag-space-tight);
    height: var(--ag-space-tight);
    margin: 0 auto var(--ag-space-md);
    border-radius: 50%;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-style: italic;
    color: var(--ag-cream);

    background: var(--ag-ink);
  }

  .res-timeline-arrow {
    position: absolute;
    top: var(--ag-space-lg);
    right: 0;

    font-family: var(--ag-font-mono);
    color: var(--ag-rule-strong);
  }

  .res-timeline-step:last-child .res-timeline-arrow {
    display: none;
  }

  .res-timeline-text {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  /* ===== Audience ===== */
  .res-audience-grid {
    overflow: hidden;
    display: grid;
    grid-template-columns: 1fr 1fr;

    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);
  }

  .res-audience-col {
    padding: var(--ag-space-2xl);
  }

  .res-audience-col.yes {
    border-right: 1px solid var(--ag-rule);
    background: var(--ag-paper);
  }

  .res-audience-col.no {
    background: var(--ag-paper-deep);
  }

  .res-audience-head {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: center;
    margin-bottom: var(--ag-space-lg);
  }

  .res-audience-mark {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;

    width: var(--ag-space-xl);
    height: var(--ag-space-xl);
    border-radius: 50%;

    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-bold);
  }

  .res-audience-col.yes .res-audience-mark {
    color: var(--ag-secondary);
    background: var(--ag-mint);
  }

  .res-audience-col.no .res-audience-mark {
    color: var(--ag-ink-soft);
    background: var(--ag-rule-strong);
  }

  .res-audience-col h3 {
    margin: 0;
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
  }

  .res-audience-col ul {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .res-audience-col li {
    position: relative;

    padding-left: var(--ag-space-md);

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .res-audience-col.yes li::before {
    content: "+";

    position: absolute;
    left: 0;

    font-weight: var(--ag-weight-bold);
    color: var(--ag-secondary);
  }

  .res-audience-col.no li::before {
    content: "–";

    position: absolute;
    left: 0;

    font-weight: var(--ag-weight-bold);
    color: var(--ag-ink-soft);
  }

  /* ===== Signature ===== */
  .res-signature {
    color: var(--ag-cream);
    background: var(--ag-secondary);
  }

  .res-signature-grid {
    display: grid;
    grid-template-columns: 0.5fr 1.5fr;
    gap: var(--ag-space-2xl);
    align-items: center;
  }

  .res-signature-photo {
    max-width: 240px;
  }

  .res-signature-photo .slot {
    aspect-ratio: 4 / 5;
    border-radius: var(--ag-radius-md);
  }

  .res-signature-mark {
    display: block;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    font-style: italic;
    line-height: var(--ag-leading-none);
    color: var(--ag-on-dark);
  }

  .res-signature-text {
    margin: 0 0 var(--ag-space-md);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    line-height: var(--ag-leading-snug);
    color: var(--ag-cream);
  }

  .res-signature-bio {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: center;

    padding-top: var(--ag-space-md);
    border-top: 1px solid var(--ag-rule-dark);
  }

  .res-signature-avatar {
    overflow: hidden;
    flex-shrink: 0;

    width: var(--ag-space-2xl);
    height: var(--ag-space-2xl);
    border-radius: 50%;
  }

  .res-signature-avatar .slot {
    aspect-ratio: 1 / 1;
    border-radius: 50%;
  }

  .res-signature-bio p {
    max-width: 52ch;
    margin: 0;

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-on-dark);
  }

  .res-signature-bio strong {
    display: block;

    margin-bottom: var(--ag-space-3xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-base);
    font-style: italic;
    color: var(--ag-cream);
  }

  /* ===== Vidéo ===== */
  .res-video-grid {
    display: grid;
    grid-template-columns: 1fr 1.3fr;
    gap: var(--ag-space-4xl);
    align-items: center;
  }

  .res-video-duration {
    margin: var(--ag-space-xs) 0 0;
    text-align: right;
  }

  .res-video-title {
    margin: 0 0 var(--ag-space-md);
  }

  .res-video-intro {
    max-width: 42ch;
    margin: 0;

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  /* ===== Conseils ===== */
  .res-tips-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-lg);
  }

  .res-tip.sticky-note {
    position: static;
    width: calc(25% - var(--ag-space-md));
    min-width: 220px;
    padding: var(--ag-space-lg);
  }

  .res-tip:nth-child(1) {
    transform: rotate(-2.5deg);
  }

  .res-tip:nth-child(2) {
    transform: rotate(1.5deg);
  }

  .res-tip:nth-child(3) {
    transform: rotate(-1.5deg);
  }

  .res-tip:nth-child(4) {
    transform: rotate(2deg);
  }

  .res-tip p {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-style: italic;
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  /* ===== Avis ===== */
  .res-testi-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-lg);
  }

  .res-testi-card {
    padding: var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);
    background: var(--ag-paper-deep);
  }

  .res-testi-quote {
    margin: 0 0 var(--ag-space-md);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-style: italic;
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  .res-testi-name {
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  /* ===== Suggestions ===== */
  .res-related-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ag-space-lg);
  }

  .res-related-card {
    display: block;
  }

  .res-related-card .slot {
    aspect-ratio: 4 / 3;
    border-radius: var(--ag-radius-md);
  }

  .res-related-card h4 {
    margin: var(--ag-space-xs) 0 var(--ag-space-3xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-snug);
  }

  .res-related-benefit {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  /* ===== Appel intermédiaire ===== */
  .res-cta-mid-band {
    background: var(--ag-deep-navy);
  }

  .res-cta-mid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xl);
    align-items: center;
    justify-content: space-between;
  }

  .res-cta-mid-title {
    margin: 0 0 var(--ag-space-2xs);
    color: var(--ag-cream);
  }

  .res-cta-mid p {
    margin: 0;
    color: var(--ag-on-dark);
  }

  .res-cta-mid-actions {
    display: flex;
    gap: var(--ag-space-lg);
    align-items: center;
  }

  .res-cta-mid-actions .price-tag {
    font-size: var(--ag-text-xl);
    color: var(--ag-cream);
  }

  /* Le <form class="cart"> n'est là que pour que cart.js intercepte le bouton :
     il ne doit rien peser dans l'alignement de la bande. `!important` parce que
     `.woocommerce div.product form.cart { margin-bottom: 2em }` est non calquée
     et bat n'importe quelle règle d'@layer : ces 32px fantômes sous le form
     entraient dans le calcul du centrage et remontaient le bouton de 16px,
     contre le prix à sa gauche et contre le texte de la bande. */
  .res-cta-mid-form {
    display: flex;
    margin: 0 !important;
  }

  /* ===== Responsive ===== */
  @media (width <= 1024px) {
    .res-hero-grid,
    .res-solution-grid,
    .res-perks-grid,
    .res-signature-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .res-signature-grid {
      text-align: center;
    }

    .res-signature-photo {
      width: 240px;
      margin: 0 auto;
    }

    .res-audience-grid {
      grid-template-columns: 1fr;
    }

    .res-audience-col.yes {
      border-right: none;
      border-bottom: 1px solid var(--ag-rule);
    }

    .res-related-grid {
      grid-template-columns: repeat(2, 1fr);
    }

    .res-timeline {
      grid-template-columns: 1fr 1fr;
      gap: var(--ag-space-xl) 0;
    }

    .res-timeline-arrow {
      display: none;
    }
  }

  @media (width <= 900px) {
    .res-video-grid,
    .res-testi-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }
  }

  @media (width <= 720px) {
    .res-contents-grid,
    .res-timeline,
    .res-related-grid {
      grid-template-columns: 1fr;
    }

    .res-hero-side {
      position: static;
      justify-content: center;
      margin-top: var(--ag-space-lg);
    }

    .res-tips-grid {
      flex-direction: column;
    }

    .res-tip.sticky-note {
      transform: none;
      width: 100%;
    }

    .res-cta-mid {
      flex-direction: column;
      align-items: flex-start;
    }
  }
}

@layer components {
  /* ===== FICHE ACCESSOIRE — famille produit physique =====
     Le gros du hero réutilise le namespace `fiche-*` de la fiche patron.
     Seul ce qui lui est propre est déclaré ici. */
  .acc-breadcrumb {
    padding-top: var(--ag-space-lg);
    padding-bottom: var(--ag-space-2xs);
  }

  .acc-breadcrumb a {
    color: inherit;
  }

  .acc-breadcrumb-sep {
    padding: 0 var(--ag-space-2xs);
  }

  .acc-breadcrumb-current {
    color: var(--ag-ink);
  }

  .acc-hero {
    padding-top: var(--ag-space-lg);
    padding-bottom: var(--ag-space-2xl);
  }

  .acc-photo {
    position: relative;
  }

  /* Square photo, where the fiche patron uses 9/10: an accessoire is shot on a
     flat-lay, not worn. */
  .acc-photo .fiche-photo-main .slot {
    aspect-ratio: 1 / 1;
  }

  .acc-photo-badge {
    position: absolute;
    z-index: var(--ag-z-raised);
    top: var(--ag-space-sm);
    left: var(--ag-space-sm);

    border-color: transparent;

    background: var(--ag-paper);
  }

  .acc-meta-sep {
    color: var(--ag-rule-strong);
  }

  .acc-title {
    margin: 0 0 var(--ag-space-3xs);
  }

  .acc-tagline {
    margin-bottom: var(--ag-space-lg);
  }

  .acc-short {
    max-width: 46ch;
    margin-bottom: var(--ag-space-lg);

    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .acc-add-panel-head {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;
    justify-content: space-between;
  }

  .acc-stock-dot {
    display: inline-block;

    width: var(--ag-space-3xs);
    height: var(--ag-space-3xs);
    margin-right: var(--ag-space-2xs);
    border-radius: 50%;

    background: var(--ag-secondary);
  }

  .acc-details-grid {
    display: grid;
    grid-template-columns: 1.2fr 0.8fr;
    gap: var(--ag-space-4xl);
  }

  .acc-details-text {
    margin: 0;
    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .acc-details-note {
    margin: var(--ag-space-sm) 0 0;
    font-size: var(--ag-text-sm);
    font-style: italic;
    color: var(--ag-ink-soft);
  }

  .acc-contents {
    padding: var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);
    background: var(--ag-paper-deep);
  }

  .acc-contents-title {
    margin: 0 0 var(--ag-space-xs);
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
  }

  .acc-contents-list {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .acc-contents-list li {
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: flex-start;

    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
  }

  .acc-contents-tick {
    font-weight: var(--ag-weight-bold);
    color: var(--ag-secondary);
  }

  .acc-linked-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--ag-space-lg);
    max-width: 720px;
  }

  .acc-linked-card {
    display: grid;
    grid-template-columns: 88px 1fr;
    gap: var(--ag-space-sm);
    align-items: center;

    padding: var(--ag-space-xs);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
  }

  .acc-linked-card .slot {
    aspect-ratio: 1 / 1;
    border-radius: var(--ag-radius-sm);
  }

  .acc-linked-body h3 {
    margin: 0 0 var(--ag-space-3xs);
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-weight: var(--ag-weight-normal);
  }

  .acc-linked-price {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
  }

  @media (width <= 900px) {
    .acc-details-grid,
    .acc-linked-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }
  }
}

@layer components {
  /* Pastilles de carte — empilées plutôt que superposées : un produit peut
     être à la fois nouveau et gratuit, et l'ancien positionnement absolu
     unique les aurait fait se recouvrir au même point. */
  .patron-card__flags {
    position: absolute;
    z-index: var(--ag-z-raised);
    top: var(--ag-space-xs);
    left: var(--ag-space-sm);

    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
  }
}

@layer components {
  /* =============================================
   PAGE LIVRE — HERO ET BLOC CONVERSION
   Port de mockup_refv2/livre.css (sélecteurs .lv-*) pour
   docs/plans/2026-07-26-002-feat-page-livre-plan.md, U3. Cette passe ne porte
   que ce que l1-hero.php / l2-inscription.php / l3-conversion.php
   consomment ; les unités suivantes (U4-U7) complètent au fil de l'eau.
   ============================================= */

  /* ---- 1 · Hero (« Couverture » — seul style livré, KD5) ---- */
  .lv-hero {
    padding-top: var(--ag-space-2xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .lv-hero-grid {
    display: grid;
    grid-template-columns: 1fr 0.92fr;
    gap: var(--ag-space-5xl);
    align-items: center;
  }

  .lv-hero-title {
    margin: 0;
  }

  .lv-status-badge {
    display: inline-block;

    margin-bottom: var(--ag-space-lg);
    padding: var(--ag-space-2xs) var(--ag-space-sm);
    border: 1px solid color-mix(in srgb, var(--ag-accent) 32%, transparent);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent-deep);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);

    background: color-mix(in srgb, var(--ag-accent) 9%, transparent);
  }

  .lv-hero-sub {
    display: block;

    max-width: 40ch;
    margin: var(--ag-space-xl) 0 0;

    font-size: var(--ag-text-lede);
    color: var(--ag-ink-soft);
  }

  .lv-hero-sub em {
    font-family: var(--ag-font-display);
    font-style: italic;
    color: var(--ag-ink);
  }

  .lv-hero-promise {
    max-width: 34ch;
    margin: var(--ag-space-lg) 0 0;
    padding-top: var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    color: var(--ag-ink);
  }

  .lv-hero-promise strong {
    font-weight: var(--ag-weight-normal);
    color: var(--ag-accent-deep);
  }

  .lv-hero-promise em {
    font-style: italic;
  }

  .lv-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xs);
    align-items: center;

    margin-top: var(--ag-space-2xl);
  }

  .lv-cover-wrap {
    position: relative;
  }

  .lv-cover-plinth {
    position: absolute;
    z-index: 0;
    inset: 7% -5% 7% 16%;

    border-radius: var(--ag-radius-sm);

    background: var(--ag-blue-ice);
  }

  .lv-cover-img {
    position: relative;
    z-index: var(--ag-z-raised);

    display: block;

    width: 100%;
    height: auto;
    border-radius: var(--ag-radius-sm);

    box-shadow: var(--ag-shadow-lg);
  }

  /* ---- Section helpers communs (repris tels quels de livre.css) ---- */
  .lv-sec-head {
    margin-bottom: var(--ag-space-3xl);
  }

  .lv-num {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  /* ---- 2 · Inscription prioritaire (état 1) ---- */
  .lv-inscription {
    position: relative;

    overflow: hidden;
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: var(--ag-space-5xl);
    align-items: center;

    padding: clamp(2.5rem, 5vw, 4.75rem);
    border-radius: var(--ag-radius-md);

    color: var(--ag-cream);

    background: var(--ag-ink);
  }

  .lv-inscription h2 {
    margin: var(--ag-space-sm) 0 0;
    color: var(--ag-cream);
  }

  .lv-inscription-lede {
    max-width: 38ch;
    margin: var(--ag-space-sm) 0 0;
    font-size: var(--ag-text-base);
    color: color-mix(in srgb, var(--ag-cream) 78%, transparent);
  }

  .lv-inscription .lv-num {
    color: color-mix(in srgb, var(--ag-cream) 55%, transparent);
  }

  .lv-inscription-list {
    display: grid;
    gap: 0;

    margin: var(--ag-space-xl) 0 0;
    padding: 0;

    list-style: none;
  }

  .lv-inscription-list li {
    display: flex;
    gap: var(--ag-space-sm);
    align-items: baseline;

    padding: var(--ag-space-sm) 0;
    border-top: 1px solid color-mix(in srgb, var(--ag-cream) 16%, transparent);

    color: color-mix(in srgb, var(--ag-cream) 90%, transparent);
  }

  .lv-inscription-list li:last-child {
    border-bottom: 1px solid
      color-mix(in srgb, var(--ag-cream) 16%, transparent);
  }

  .lv-inscription-list .k {
    flex-shrink: 0;

    width: 26px;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent);
    letter-spacing: var(--ag-tracking-label);
  }

  .lv-form-card {
    padding: var(--ag-space-xl);
    border: 1px solid color-mix(in srgb, var(--ag-cream) 18%, transparent);
    border-radius: var(--ag-radius-md);
    background: color-mix(in srgb, var(--ag-cream) 5%, transparent);
  }

  .lv-form-card .eyebrow {
    color: var(--ag-accent);
  }

  .lv-form-title {
    margin: var(--ag-space-xs) 0 var(--ag-space-lg);
    color: var(--ag-cream);
  }

  /* Same pill as before the MailerLite migration, retargeted onto the
     plugin's markup — the theme no longer emits `.lv-form`. Declarations are
     moved, not rewritten, so the two cannot drift apart. */
  .lv-form-card .mailerlite-form-inputs {
    display: flex;
    align-items: stretch;

    width: 100%;
    padding: 5px;
    border: 1px solid color-mix(in srgb, var(--ag-cream) 32%, transparent);
    border-radius: var(--ag-radius-pill);

    background: rgb(0 0 0 / 18%);
  }

  .lv-form-card .mailerlite-form-field input {
    flex: 1;
    width: 100%;
    min-width: 0;
    padding: var(--ag-space-sm) var(--ag-space-md);
    border: none;

    font: inherit;
    color: var(--ag-cream);

    background: transparent;
    outline: none;
  }

  .lv-form-card .mailerlite-form-field input::placeholder {
    color: color-mix(in srgb, var(--ag-cream) 50%, transparent);
  }

  /* The plugin wraps its button in a container div, and that div — not the
     button — is the flex item the pill row stretches. Without this the button
     came out 3px shorter than the field it sits beside. */
  .lv-form-card .mailerlite-subscribe-button-container {
    display: flex;
  }

  .lv-form-card .mailerlite-subscribe-submit {
    display: flex;
    align-items: center;
    justify-content: center;

    padding: var(--ag-space-sm) var(--ag-space-lg);
    border: none;
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-paper);
    white-space: nowrap;

    background: var(--ag-accent);

    transition:
      background var(--ag-dur-base) ease,
      transform var(--ag-dur-base) ease;
  }

  .lv-form-card .mailerlite-subscribe-submit:hover {
    transform: translateY(-1px);
    color: var(--ag-ink);
    background: var(--ag-paper);
  }

  /* The plugin wraps its form in three unstyled divs; without this they
     shrink-to-fit and the pill never fills the card. Same cause as the
     footer. */
  .lv-form-card > [id^="mailerlite-form_"],
  .lv-form-card .mailerlite-form,
  .lv-form-card .mailerlite-form form {
    width: 100%;
  }

  .lv-form-card .mailerlite-form-field {
    display: flex;
    flex: 1;

    min-width: 0;
    margin-bottom: 0;
  }

  /* The plugin renders a visible label and an always-present description
     wrapper; this design has neither. */
  .lv-form-card .mailerlite-form-field label {
    position: absolute;

    overflow: hidden;

    width: 1px;
    height: 1px;

    white-space: nowrap;

    clip-path: inset(50%);
  }

  .lv-form-card .mailerlite-form-description:empty {
    display: none;
  }

  /* Hidden until the plugin's script reveals them inline — its stylesheet,
     which used to supply this, is dequeued. */
  .lv-form-card .mailerlite-form-loader,
  .lv-form-card .mailerlite-form-response {
    display: none;
  }

  .lv-form-card .mailerlite-form-loader {
    margin: 0;
    padding: var(--ag-space-sm) var(--ag-space-md);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: color-mix(in srgb, var(--ag-cream) 50%, transparent);
  }

  .lv-form-card .mailerlite-form-response h4 {
    margin: 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-base);
    color: var(--ag-cream);
  }

  .lv-form-card .mailerlite-form-error {
    margin-top: var(--ag-space-3xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
  }

  .lv-form-micro {
    margin: var(--ag-space-sm) 0 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: color-mix(in srgb, var(--ag-cream) 45%, transparent);
    letter-spacing: var(--ag-tracking-label);
  }

  /* ---- Bloc conversion — précommande / où trouver le livre (états 2-3) ---- */
  .lv-buy-grid {
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    gap: var(--ag-space-md);
  }

  .lv-buy-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    padding: var(--ag-space-3xl) var(--ag-space-2xl);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
  }

  .lv-buy-card.is-featured {
    border-color: var(--ag-ink);
    color: var(--ag-cream);
    background: var(--ag-ink);
  }

  .lv-buy-card h3 {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxxl);
    font-weight: var(--ag-weight-normal);
    color: inherit;
  }

  .lv-buy-tag {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-accent);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-buy-list {
    display: grid;
    gap: var(--ag-space-2xs);

    margin: 0;
    padding: 0;

    list-style: none;
  }

  .lv-buy-list li {
    position: relative;
    padding-left: var(--ag-space-md);
    font-size: var(--ag-text-base);
    color: color-mix(in srgb, var(--ag-cream) 88%, transparent);
  }

  .lv-buy-list li::before {
    content: "+";

    position: absolute;
    left: 0;

    font-weight: var(--ag-weight-bold);
    color: var(--ag-accent);
  }

  .lv-buy-desc {
    margin: 0;
    font-size: var(--ag-text-base);
    color: var(--ag-ink-soft);
  }

  .lv-buy-btn {
    align-self: flex-start;
    margin-top: var(--ag-space-3xs);
  }

  .lv-buy-affiliate {
    margin: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    letter-spacing: var(--ag-tracking-wide);
  }

  .lv-buy-retailers {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-sm);
    align-items: baseline;

    margin-top: var(--ag-space-3xs);
    padding-top: var(--ag-space-sm);
    border-top: 1px solid var(--ag-rule);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .lv-buy-retailers span {
    color: var(--ag-ink-soft);
  }

  .lv-buy-retailers a {
    padding-bottom: 1px;
    border-bottom: 1px solid var(--ag-ink);
    color: var(--ag-ink);
  }

  .lv-buy-retailers a:hover {
    border-color: var(--ag-accent-deep);
    color: var(--ag-accent-deep);
  }

  /* =============================================
   PAGE LIVRE — SECTIONS PÉDAGOGIQUES
   Port de mockup_refv2/livre.css (.lv-why*, .lv-diff*) pour
   docs/plans/2026-07-26-002-feat-page-livre-plan.md, U4. « Pour qui »
   (l6-pourqui.php) réutilise .res-audience-* déjà porté pour la fiche
   ressource — aucune règle nouvelle pour cette section.
   ============================================= */

  /* ---- 3 · Pourquoi ce livre (photo + prose, contenu fixe R20) ---- */
  .lv-why {
    display: grid;
    grid-template-columns: 0.85fr 1.15fr;
    gap: var(--ag-space-5xl);
    align-items: start;
  }

  .lv-why-photo {
    position: relative;
  }

  .lv-why-photo .slot {
    aspect-ratio: 4 / 5;
    border-radius: var(--ag-radius-md);
  }

  .lv-why-signature {
    margin-top: var(--ag-space-lg);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxxl);
    font-style: italic;
    line-height: var(--ag-leading-none);
    color: var(--ag-accent-deep);
  }

  .lv-why-sign-role {
    display: block;

    margin-top: var(--ag-space-2xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-style: normal;
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-why-num {
    display: block;
    margin-bottom: var(--ag-space-sm);
  }

  .lv-why-title {
    max-width: 16ch;
    margin: 0 0 var(--ag-space-xl);
  }

  .lv-why-title em {
    color: var(--ag-accent);
  }

  .lv-why-prose {
    font-size: var(--ag-text-md);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .lv-why-prose p {
    margin: 0 0 var(--ag-space-lg);
  }

  .lv-why-prose p:first-child::first-letter {
    float: left;

    margin: var(--ag-space-2xs) var(--ag-space-sm) -4px 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    font-style: italic;
    line-height: var(--ag-leading-display);
    color: var(--ag-accent);
  }

  .lv-why-prose strong {
    font-weight: var(--ag-weight-semibold);
    color: var(--ag-ink);
  }

  /* ---- 4 · Pourquoi différent (grille de quatre cartes) ---- */
  .lv-diff-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ag-space-sm);
  }

  .lv-diff-card {
    display: flex;
    flex-direction: column;

    padding: var(--ag-space-xl) var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);

    transition:
      transform var(--ag-dur-slow) ease,
      border-color var(--ag-dur-base) ease,
      background var(--ag-dur-base) ease;
  }

  .lv-diff-card:hover {
    transform: translateY(-3px);
    border-color: var(--ag-ink);
    background: var(--ag-paper-deep);
  }

  .lv-diff-num {
    margin-bottom: var(--ag-space-md);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-huge);
    font-style: italic;
    line-height: var(--ag-leading-none);
    color: var(--ag-accent);
  }

  .lv-diff-card h3 {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .lv-diff-card p {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .lv-diff-items {
    display: grid;
    gap: var(--ag-space-2xs);

    margin: var(--ag-space-md) 0 0;
    padding: var(--ag-space-sm) 0 0;
    border-top: 1px solid var(--ag-rule);

    list-style: none;
  }

  .lv-diff-items li {
    position: relative;

    padding-left: var(--ag-space-sm);

    font-size: var(--ag-text-xs);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .lv-diff-items li::before {
    content: "→";

    position: absolute;
    left: 0;

    font-size: var(--ag-text-xxs);
    color: var(--ag-accent);
  }

  @media (width <= 900px) {
    .lv-hero-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .lv-cover-wrap {
      max-width: 380px;
    }

    .lv-inscription {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .lv-buy-grid {
      grid-template-columns: 1fr;
    }

    .lv-why {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .lv-diff-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 560px) {
    .lv-form-card .mailerlite-form-inputs {
      flex-direction: column;
      border-radius: var(--ag-radius-md);
    }

    .lv-form-card .mailerlite-subscribe-submit {
      width: 100%;
    }

    .lv-diff-grid {
      grid-template-columns: 1fr;
    }
  }
}

@layer components {
  /* =============================================
   PAGE LIVRE — LES MOTIFS DU LIVRE
   Port de mockup_refv2/livre.css (.lv-motifs-grid, .lv-motif-*) pour
   docs/plans/2026-07-26-002-feat-page-livre-plan.md, U5. Les cartes sont
   parfois des <a> (motif_lien renseigné), parfois des <div> (teaser non
   cliquable) : les mêmes classes s'appliquent aux deux, d'où `color: inherit`
   et `text-decoration: none` plutôt qu'un style spécifique au lien.
   L'aperçu (feuilleter) réutilise les classes .angles- et .gallery-label
   existantes (r6-galerie.php) ; seuls le cadrage et le contraste des flèches
   lui sont propres, ci-dessous.
   ============================================= */

  /* Les fiches patron et ressource montrent des photos cadrées exprès en 4/3,
     que `cover` sert bien. Ici ce sont des pages de livre — portrait, paysage
     ou carré selon la page photographiée — et le recadrage coupait le haut et
     le bas des couvertures. La page doit se lire en entier sans ouvrir la
     lightbox, donc `contain` dans un cadre stable : la hauteur ne bouge pas
     d'une image à l'autre pendant la navigation. */
  #lv-apercu .angles-main .slot img {
    object-fit: contain;
  }

  /* Fond uni plutôt que le motif hachuré : avec `contain`, ce qui entoure
     l'image n'est plus un trou à combler mais la marge de la page. */
  #lv-apercu .angles-main .slot {
    background: var(--ag-paper-deep);
  }

  /* Les flèches se posent maintenant sur cette marge claire et non plus sur la
     photo : le disque blanc de la visionneuse partagée y était invisible. Même
     pastille encrée que « Agrandir » et le compteur, dans le même cadre. */
  #lv-apercu .angles-nav {
    color: var(--ag-paper);
    background: color-mix(in srgb, var(--ag-ink) 75%, transparent);
  }

  .lv-motifs-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--ag-space-lg);
  }

  .lv-motif-card {
    overflow: hidden;
    display: flex;
    flex-direction: column;

    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    color: inherit;
    text-decoration: none;

    background: var(--ag-paper);

    transition:
      border-color var(--ag-dur-base) ease,
      transform var(--ag-dur-slow) var(--ag-ease);
  }

  .lv-motif-card:hover {
    transform: translateY(-3px);
    border-color: var(--ag-ink);
  }

  .lv-motif-media .slot {
    border-radius: 0;
  }

  .lv-motif-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    padding: var(--ag-space-xl) var(--ag-space-lg) var(--ag-space-lg);
  }

  .lv-motif-body h3 {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .lv-motif-body p {
    margin: 0 0 var(--ag-space-md);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .lv-motif-link {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    margin-top: auto;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent-deep);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-motif-card:hover .lv-motif-link .btn-arrow {
    transform: translateX(3px);
  }
}

@layer components {
  /* =============================================
   PAGE LIVRE — SÉRIE VIDÉO ET RENCONTRONS-NOUS
   Port de mockup_refv2/livre.css (.lv-ep-*, .lv-events-grid, .lv-event-*)
   pour docs/plans/2026-07-26-002-feat-page-livre-plan.md, U6. Le statut
   utilise les modificateurs .is-publie / .is-a-venir (valeurs du champ ACF
   `ep_statut`) plutôt que les .published / .soon de la maquette, pour que
   le vocabulaire de classes suive les données plutôt que d'en introduire un
   second. `.lv-ep-cell` est tantôt un <a> (épisode publié), tantôt un <div>
   (à venir) : mêmes règles pour les deux, d'où `color: inherit` et
   `text-decoration: none`, comme `.lv-motif-card` ci-dessus.
   ============================================= */

  .lv-ep-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-lg) var(--ag-space-md);
  }

  .lv-ep-cell {
    display: flex;
    flex-direction: column;
    color: inherit;
    text-decoration: none;
  }

  .lv-ep-media {
    position: relative;
  }

  .lv-ep-cell .lv-ep-media {
    margin-bottom: var(--ag-space-sm);
  }

  .lv-ep-cell .lv-ep-media .slot {
    aspect-ratio: 16 / 9;
    border-radius: var(--ag-radius-sm);
  }

  .lv-ep-soon-veil {
    position: absolute;
    inset: 0;

    display: flex;
    align-items: center;
    justify-content: center;

    border-radius: var(--ag-radius-sm);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);

    background: color-mix(in srgb, var(--ag-paper) 62%, transparent);
    backdrop-filter: blur(1px);
  }

  /* Pastille YouTube, comme .yt-card-play : ces cellules sont des liens vers
     l'épisode, mais elles annoncent une vidéo et doivent la marquer comme
     partout ailleurs sur le site. */
  .lv-ep-play {
    --yt-brand-red: #f00;
    --yt-brand-red-pressed: #c00;
    --yt-brand-arrow: #fff;

    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    display: block;

    width: 64px;
    height: 64px;

    transition: transform var(--ag-dur-slow) ease;
  }

  .lv-ep-play svg {
    display: block;
    width: 100%;
    height: 100%;
  }

  .lv-ep-play .yt-card-play__bg {
    fill: var(--yt-brand-red);
    transition: fill var(--ag-dur-base) ease;
  }

  .lv-ep-play .yt-card-play__arrow {
    fill: var(--yt-brand-arrow);
  }

  .lv-ep-cell:hover .lv-ep-play {
    transform: translate(-50%, -50%) scale(1.08);
  }

  .lv-ep-cell:hover .lv-ep-play .yt-card-play__bg {
    fill: var(--yt-brand-red-pressed);
  }

  .lv-ep-kicker {
    margin-bottom: var(--ag-space-2xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  .lv-ep-status {
    display: inline-flex;
    gap: 7px;
    align-items: center;

    margin-bottom: var(--ag-space-sm);
    padding: var(--ag-space-2xs) var(--ag-space-sm);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-ep-status.is-publie {
    color: var(--ag-accent-deep);
    background: color-mix(in srgb, var(--ag-accent) 10%, transparent);
  }

  .lv-ep-status.is-publie .d {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ag-accent);
  }

  .lv-ep-status.is-a-venir {
    border: 1px solid var(--ag-rule);
    color: var(--ag-ink-soft);
    background: var(--ag-paper-deep);
  }

  .lv-ep-status.is-a-venir .d {
    width: 6px;
    height: 6px;
    border: 1.5px solid var(--ag-ink-soft);
    border-radius: 50%;
  }

  .lv-ep-title {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .lv-ep-desc {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  /* ---- Rencontrons-nous — cartes d'événements ---- */
  .lv-events-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-md);
  }

  .lv-event-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);

    padding: var(--ag-space-xl) var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
  }

  .lv-event-date {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent-deep);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-event-card h3 {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink);
  }

  .lv-event-city {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-event-card .btn {
    align-self: flex-start;
    margin-top: var(--ag-space-2xs);
  }

  @media (width <= 900px) {
    .lv-ep-grid,
    .lv-events-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .lv-ep-grid,
    .lv-events-grid {
      grid-template-columns: 1fr;
    }
  }
}

@layer components {
  /* =============================================
   PAGE LIVRE — PRESSE & PODCASTS, RAPPEL, FAQ, AVIS LECTEURS
   Port de mockup_refv2/livre.css (.lv-press-*, .lv-reminder, .lv-faq,
   .lv-reviews-grid/.lv-review-*) pour
   docs/plans/2026-07-26-002-feat-page-livre-plan.md, U7. Le bloc Alice de la
   maquette (.lv-alice*) est devenu le composant partagé `.ag-autrice*`, plus
   bas — même carte en fin d'article. `.lv-press-type`
   est nouveau — voir le commentaire d'en-tête de l11-presse.php : la
   maquette ne rendait jamais son champ `kind` de démonstration, mais le
   champ ACF `presse_type` est bien destiné à être édité, d'où ce petit
   kicker au-dessus de `.lv-press-media`.
   ============================================= */

  /* ---- Presse & podcasts ---- */
  .lv-press-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-md);
  }

  .lv-press-card {
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);

    padding: 0 0 var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    color: inherit;
    text-decoration: none;

    background: var(--ag-paper);

    transition:
      border-color var(--ag-dur-base) ease,
      transform var(--ag-dur-slow) var(--ag-ease);
  }

  .lv-press-card:hover {
    transform: translateY(-3px);
    border-color: var(--ag-ink);
  }

  .lv-press-visual .slot {
    aspect-ratio: 16 / 9;
    border-radius: 0;
  }

  .lv-press-type {
    display: block;

    margin-top: var(--ag-space-md);
    padding: 0 var(--ag-space-lg);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  .lv-press-media {
    display: block;

    margin-top: var(--ag-space-2xs);
    padding: 0 var(--ag-space-lg);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    color: var(--ag-ink);
  }

  .lv-press-type + .lv-press-media {
    margin-top: 0;
  }

  .lv-press-card p {
    margin: 0;
    padding: 0 var(--ag-space-lg);

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .lv-press-cta {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    padding: 0 var(--ag-space-lg);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .lv-press-card:hover .lv-press-cta {
    color: var(--ag-accent-deep);
  }

  .lv-press-cta .btn-arrow {
    transition: transform var(--ag-dur-base) ease;
  }

  .lv-press-card:hover .lv-press-cta .btn-arrow {
    transform: translateX(3px);
  }

  /* ---- Rappel / relance (états 1-2) ---- */
  .lv-reminder {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-lg);
    align-items: center;
    justify-content: space-between;

    padding: var(--ag-space-xl) var(--ag-space-2xl);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper-deep);
  }

  .lv-reminder h3 {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink);
  }

  .lv-reminder p {
    margin: 0;
    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
  }

  /* ---- FAQ (réutilise .faq-item global ; conteneur dédié uniquement) ---- */
  .lv-faq {
    max-width: 880px;
  }

  /* ---- Avis lecteurs (masquée par défaut, R24) ---- */
  .lv-reviews-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-lg);
  }

  .lv-review-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-md);

    padding: var(--ag-space-xl) var(--ag-space-lg);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper);
  }

  .lv-review-quote {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-style: italic;
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink);
  }

  .lv-review-credit {
    display: flex;
    flex-direction: column;
    gap: 3px;

    padding-top: var(--ag-space-md);
    border-top: 1px solid var(--ag-rule);
  }

  .lv-review-name {
    font-weight: var(--ag-weight-medium);
    color: var(--ag-ink);
  }

  .lv-review-role {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  @media (width <= 900px) {
    .lv-press-grid,
    .lv-reviews-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .lv-press-grid,
    .lv-reviews-grid {
      grid-template-columns: 1fr;
    }

    .lv-reminder {
      flex-direction: column;
      align-items: flex-start;
      text-align: left;
    }
  }
}

@layer components {
  /* =============================================
   BLOC « L'AUTRICE » — composant partagé
   Une seule carte pour la page Livre (section `alice`) et la fin d'article
   (template-parts/bloc-autrice.php). Port de mockup_refv2/livre.css
   (.lv-alice*), renommé `.ag-autrice*` puisqu'il n'appartient plus au livre.
   ============================================= */

  .ag-autrice {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: var(--ag-space-3xl);
    align-items: center;

    max-width: 960px;
    margin: 0 auto;
    padding: var(--ag-space-4xl);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-paper-deep);
  }

  .ag-autrice-photo .slot {
    overflow: hidden;
    aspect-ratio: 1 / 1;
    border-radius: var(--ag-radius-pill);
  }

  .ag-autrice-name {
    margin: var(--ag-space-sm) 0 var(--ag-space-md);
    font-size: var(--ag-text-xxxl);
    color: var(--ag-ink);
  }

  .ag-autrice-body p {
    margin: 0 0 var(--ag-space-md);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .ag-autrice-links {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .ag-autrice-links a {
    padding-bottom: 2px;
    border-bottom: 1px solid var(--ag-ink);
    color: var(--ag-ink);
  }

  .ag-autrice-links a:hover {
    border-color: var(--ag-accent-deep);
    color: var(--ag-accent-deep);
  }

  .ag-autrice-links .dot {
    margin: 0 var(--ag-space-xs);
    color: var(--ag-ink-soft);
  }

  @media (width <= 720px) {
    .ag-autrice {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
      padding: var(--ag-space-xl);
      text-align: center;
    }

    /*
     * `width` is load-bearing: `.slot img` is absolutely positioned, so the
     * slot has no intrinsic width, and the auto inline margins make this grid
     * item shrink-to-fit — it would resolve to 0 and hide the portrait.
     */
    .ag-autrice-photo {
      width: 100%;
      max-width: 160px;
      margin: 0 auto;
    }
  }
}

@layer wp-overrides {
  /* Quantité — deux cas où l'on masque le champ sur la fiche produit :

     1) sold_individually=true (rare — laissé au choix admin par produit) :
        WooCommerce bascule le champ en type="hidden" mais garde son
        conteneur .quantity, une div vide qui flotte encore dans le
        formulaire. Ce cas ne concerne aujourd'hui aucun produit du
        catalogue par défaut, mais reste actionable côté admin.

     2) Produits téléchargeables (patrons PDF, papeterie) : sold_individually
        reste à false pour permettre l'achat multiple depuis le drawer
        (offrir à des amies), mais on ne veut pas exposer le champ quantité
        sur la fiche — un clic Ajouter au panier doit rester un exemplaire.
        body.ag-hide-qty est posé par functions.php (filter body_class) sur
        les fiches téléchargeables. L'input reste dans le DOM avec value=1,
        donc le POST natif et l'interception cart.js lisent 1.

     Le sélecteur se limite à `form.cart` — les templates thème
     (s1/r1/a2-hero.php) rendent le formulaire dans `.ag-fiche-patron.product`
     sans wrapper `.woocommerce`, donc le sélecteur canonique WC
     `.woocommerce div.product form.cart .quantity` ne matche pas.

     C'est bien `.ag-qty` qu'on masque, pas `.quantity` : le stepper − / + de
     `add-to-cart/simple.php` encadre le champ, et n'aurait plus rien à piloter.

     `!important` est nécessaire dans les deux cas : le `float` du champ vient
     du CSS non-layered de WooCommerce, qui l'emporte sur une règle layered
     ordinaire (voir docs/solutions/theme-quality/). */
  form.cart .ag-qty:has(input[type="hidden"]),
  body.ag-hide-qty form.cart .ag-qty {
    display: none !important;
  }

  /* Dans le bloc Cart, `quantity_limits.editable` à false retire les boutons
     − / + et laisse un champ readonly figé sur 1 : une boîte de saisie inerte
     à côté d'un PDF. Le sélecteur reste intact pour les accessoires. */
  .wc-block-components-quantity-selector:has(input[readonly]) {
    display: none;
  }
}

@layer wp-overrides {
  /* WooCommerce's own error styling ships a hardcoded red (--wc-red: #a00,
     .woocommerce-error border-top: #b81c23) that never goes through the
     theme's palette — off-brand next to every custom error surface here
     (.porte-error, .contact-form-error, .coupon-error, .tunnel-submit-error,
     .ag-cart-error), which all use --ag-accent. This surfaces wherever
     wc_print_notices() and native WooCommerce form-field markup render
     inside the theme's own account shell (inc/compte-shell.php): edit
     account/address, lost/reset password, and any other native fallback
     tab. Overriding --wc-red recolors every native consumer at once —
     invalid field borders/labels, the required-field asterisk,
     coupon-error-notice, checkout-inline-error-message, the #terms
     outline — since they all read var(--wc-red) rather than a literal.
     .woocommerce-error's border-top is a literal, not the variable, so it
     needs its own line. Both need !important: WooCommerce's declarations
     are unlayered and outrank a normal layered rule regardless of
     specificity (see docs/solutions/theme-quality/css-architecture.md). */
  :root {
    --wc-red: var(--ag-accent) !important;
  }

  .woocommerce-error {
    border-top-color: var(--ag-accent) !important;
  }
}

/* ==========================================================================
   Boutique hub — hero
   Décalqué de mockup_refv2/boutique.css, valeurs brutes remplacées par les
   jetons --ag-*. La grille passe à une colonne au point de rupture tablette,
   avant que le titre en clamp() ne mange la colonne de droite.
   ========================================================================== */

@layer components {
  .shop-hero {
    padding-top: var(--ag-space-3xl);
    padding-bottom: var(--ag-space-5xl);
  }

  .shop-hero-grid {
    display: grid;
    grid-template-columns: 1.45fr 1fr;
    gap: var(--ag-space-5xl);
    align-items: end;
  }

  /* Le titre est un hors-échelle nommé, comme le marquee et le hero-stat :
     la maquette le pousse plus haut que display-xl et le serre plus fort
     (0,9 contre 1,1), et c'est ce contraste qui tient la page. */
  .shop-hero-title {
    margin: 0;
    font-size: var(--ag-text-shop-hero);
    line-height: var(--ag-leading-hero);
    letter-spacing: var(--ag-tracking-tight);
  }

  .shop-hero-title .serif-it {
    color: var(--ag-accent);
  }

  .shop-hero-aside {
    padding-bottom: var(--ag-space-3xs);
  }

  .shop-hero-trust {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs) var(--ag-space-lg);

    margin: var(--ag-space-md) 0 0;
    padding: 0;

    list-style: none;
  }

  /* La coche est décorative et vient du CSS, pas de la chaîne : la maquette
     l'écrit dans son JSX, mais la mettre dans le `msgid` la ferait traduire et
     obligerait chaque libellé à la reporter. */
  .shop-hero-trust li {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    letter-spacing: var(--ag-tracking-wide);
  }

  .shop-hero-trust li::before {
    content: "✓";
    margin-right: var(--ag-space-3xs);
  }

  .shop-hero-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-lg);
    align-items: center;

    margin-top: var(--ag-space-3xl);
    padding-top: var(--ag-space-md);
    border-top: 1px solid var(--ag-rule);
  }

  .shop-hero-nav-label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
    white-space: nowrap;
  }

  .shop-hero-nav-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-2xs);
  }

  .shop-hero-nav-links a {
    padding: var(--ag-space-2xs) var(--ag-space-sm);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-wide);

    transition:
      border-color var(--ag-dur-base) var(--ag-ease),
      background var(--ag-dur-base) var(--ag-ease),
      color var(--ag-dur-base) var(--ag-ease);
  }

  .shop-hero-nav-links a:hover {
    border-color: var(--ag-ink);
    color: var(--ag-accent-deep);
    background: var(--ag-paper-deep);
  }

  @media (width <= 900px) {
    .shop-hero-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
      align-items: start;
    }
  }

  @media (width <= 720px) {
    .shop-hero-nav {
      flex-direction: column;
      gap: var(--ag-space-sm);
      align-items: flex-start;
    }
  }
}

/* Boutique hub — carnet, vedette, suggestions */

@layer components {
  /* La maquette donne au carnet bien plus d'air qu'aux autres bandeaux : c'est
     le seul qui présente une gamme entière, et l'éventail de vignettes déborde
     de la photo — il lui faut la place de déborder. */
  #shop-carnet {
    padding-top: var(--ag-space-5xl);
    padding-bottom: var(--ag-space-5xl);
  }

  /* Deux colonnes égales sur un bandeau pleine largeur : le carnet est une
     gamme, pas une sous-section du parcours patrons. */
  .shop-carnet-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--ag-space-5xl);
    align-items: center;
  }

  .shop-carnet-body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .shop-carnet-title {
    margin: 0;
    line-height: var(--ag-leading-display);
  }

  .shop-carnet-title .serif-it {
    color: var(--ag-accent);
  }

  .shop-carnet-lede {
    max-width: 46ch;
    margin: var(--ag-space-lg) 0;
    color: var(--ag-ink-soft);
  }

  .shop-carnet-benefits {
    margin-bottom: var(--ag-space-xl);
  }

  /* L'éventail de vignettes déborde à droite de la photo ; sur une colonne il
     n'a plus de place et se replierait sur le texte. */
  @media (width <= 900px) {
    .shop-carnet-grid {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }

    .shop-carnet-photo .res-hero-side {
      display: none;
    }
  }
}

/* ==========================================================================
   Boutique hub — vedette éditoriale
   Décalqué de mockup_refv2/boutique.css (.shop-favoris-layout, .shop-icon-*).
   Remplace les familles .shop-suggestions*, qui n'existaient pas dans la
   maquette : elles rendaient les suggestions en cartes de texte encadrées, là
   où la maquette pose une liste illustrée sous une mise en scène.
   ========================================================================== */

@layer components {
  .shop-favoris-layout {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: var(--ag-space-5xl);
    align-items: start;
  }

  .shop-icon-feature {
    display: grid;
    grid-template-columns: 0.75fr 1fr;
    gap: var(--ag-space-2xl);
    align-items: center;
  }

  .shop-icon-photo {
    overflow: hidden;
    display: block;
    border-radius: var(--ag-radius-md);
  }

  .shop-icon-photo .slot {
    border-radius: var(--ag-radius-md);
    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .shop-icon-photo:hover .slot {
    transform: scale(1.03);
  }

  .shop-icon-badge {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-accent-deep);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .shop-icon-title {
    margin: var(--ag-space-xs) 0 0;
    font-size: var(--ag-text-display-s);
  }

  .shop-icon-text {
    max-width: 40ch;
    margin-top: var(--ag-space-sm);

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .shop-icon-cta {
    margin-top: var(--ag-space-lg);
  }

  .shop-icon-others-label {
    display: block;

    margin-bottom: var(--ag-space-md);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .shop-icon-others-list {
    display: flex;
    flex-direction: column;
  }

  /* Une liste réglée, pas des cartes : les filets portent le rythme, et le
     décalage au survol remplace un cadre qui alourdirait la colonne. */
  .shop-icon-other-item {
    display: grid;
    grid-template-columns: 96px 1fr auto;
    gap: var(--ag-space-md);
    align-items: center;

    padding: var(--ag-space-md) var(--ag-space-3xs);
    border-bottom: 1px solid var(--ag-rule);

    transition:
      padding var(--ag-dur-fast) var(--ag-ease),
      color var(--ag-dur-fast) var(--ag-ease);
  }

  .shop-icon-other-item:first-child {
    border-top: 1px solid var(--ag-rule);
  }

  .shop-icon-other-item:hover {
    padding-left: var(--ag-space-2xs);
    color: var(--ag-accent-deep);
  }

  .shop-icon-other-photo {
    overflow: hidden;
    display: block;
    flex: none;

    width: 96px;
    height: 96px;
    border-radius: var(--ag-radius-md);
  }

  .shop-icon-other-photo .slot {
    aspect-ratio: 1 / 1;
    width: 100%;
    height: 100%;
    border-radius: var(--ag-radius-md);

    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .shop-icon-other-item:hover .shop-icon-other-photo .slot {
    transform: scale(1.05);
  }

  .shop-icon-other-name {
    display: block;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-tight);
    letter-spacing: var(--ag-tracking-snug);
  }

  .shop-icon-other-reason {
    display: block;

    margin-top: var(--ag-space-3xs);

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink-soft);
  }

  .shop-icon-other-arrow {
    font-family: var(--ag-font-mono);
    color: var(--ag-ink-soft);
    transition: transform var(--ag-dur-base) var(--ag-ease);
  }

  .shop-icon-other-item:hover .shop-icon-other-arrow {
    transform: translateX(4px);
  }

  @media (width <= 900px) {
    .shop-favoris-layout {
      grid-template-columns: 1fr;
      gap: var(--ag-space-2xl);
    }
  }

  @media (width <= 720px) {
    .shop-icon-feature {
      grid-template-columns: 1fr;
      gap: var(--ag-space-lg);
    }
  }
}

/* ==========================================================================
   Boutique hub — les trois axes
   Décalqué de mockup_refv2/boutique.css (ShopProjets, ShopTechniques,
   ShopProfils), valeurs brutes remplacées par les jetons --ag-*.
   ========================================================================== */

@layer components {
  /* Les six sections patrons se lisent d'un seul tenant, sur un fond
     légèrement teinté — un parcours, pas six sections blanches contiguës.
     Les bandeaux pleine largeur qu'il contient gardent leur pleine largeur :
     `.band` la tire de son parent, pas d'un `100vw`. */
  .shop-patrons-block {
    background: var(--ag-paper-deep);
  }

  .shop-patrons-title {
    max-width: 18ch;
    margin: 0;
  }

  .shop-patrons-title .serif-it {
    color: var(--ag-accent);
  }

  .shop-patrons-lede {
    max-width: 58ch;
    margin-top: var(--ag-space-md);
  }

  .shop-axe-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-xl);
    align-items: baseline;
    justify-content: space-between;

    margin-bottom: var(--ag-space-2xl);
  }

  .shop-axe-head--stacked {
    display: block;
  }

  /* Pas de `max-width` par défaut : la maquette laisse les titres d'axe tenir
     sur une ligne et n'en borne que deux, « Pour qui tricotez-vous ? » et
     l'intro patrons. Poser la borne partout cassait « Que souhaitez-vous
     tricoter ? » et « Les patrons préférés des tricoteuses » en deux lignes. */
  .shop-axe-title {
    margin: 0;
  }

  .shop-axe-title--narrow {
    max-width: 20ch;
  }

  .shop-axe-title .serif-it {
    color: var(--ag-accent);
  }

  /* --- Axe projet : orbes circulaires, nom en surimpression --- */

  .shop-collections-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ag-space-xl);
  }

  .shop-collection-card {
    position: relative;
    overflow: hidden;
    display: block;
    border-radius: 50%;
  }

  .shop-collection-card .slot {
    border-radius: 50%;
    transition: transform var(--ag-dur-slow) var(--ag-ease);
  }

  .shop-collection-card:hover .slot {
    transform: scale(1.08);
  }

  .shop-collection-overlay {
    position: absolute;
    inset: 0;

    display: flex;
    align-items: center;
    justify-content: center;

    border-radius: 50%;

    background: rgb(20 32 51 / 34%);

    transition: background var(--ag-dur-slow) var(--ag-ease);
  }

  .shop-collection-card:hover .shop-collection-overlay {
    background: rgb(20 32 51 / 42%);
  }

  .shop-collection-name {
    padding: 0 var(--ag-space-sm);
    font-size: var(--ag-text-xl);
    color: var(--ag-paper);
    text-align: center;
  }

  /* --- Axe technique : galerie, une tuile pilier et trois mini --- */

  .shop-tech-gallery {
    display: grid;
    grid-template-columns: 2.1fr 0.85fr 0.85fr 0.85fr;
    gap: var(--ag-space-sm);
    height: 520px;
  }

  .shop-tech-tile {
    position: relative;

    overflow: hidden;
    display: block;

    border-radius: var(--ag-radius-md);

    transition: transform var(--ag-dur-base) var(--ag-ease);
  }

  .shop-tech-tile:hover {
    transform: translateY(-4px);
  }

  .shop-tech-tile-photo {
    position: absolute;
    inset: 0;
  }

  .shop-tech-tile-photo .slot {
    aspect-ratio: auto;
    width: 100%;
    height: 100%;
    border-radius: 0;
  }

  .shop-tech-tile-scrim {
    position: absolute;
    inset: 0;
  }

  .shop-tech-tile-main .shop-tech-tile-scrim {
    background: linear-gradient(
      180deg,
      rgb(16 26 42 / 6%) 0%,
      rgb(16 26 42 / 18%) 50%,
      rgb(16 26 42 / 90%) 100%
    );
  }

  .shop-tech-tile-mini .shop-tech-tile-scrim {
    background: linear-gradient(
      180deg,
      rgb(16 26 42 / 5%) 0%,
      rgb(16 26 42 / 78%) 100%
    );
  }

  .shop-tech-tile-body {
    position: absolute;
    z-index: var(--ag-z-raised);
    right: 0;
    bottom: 0;
    left: 0;

    padding: var(--ag-space-lg);

    color: var(--ag-paper);
  }

  .shop-tech-tile-kicker {
    display: block;

    margin-bottom: var(--ag-space-2xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);

    opacity: 0.8;
  }

  /* La tuile pilier porte le nom de la collection à un cran nettement plus
     haut que display-s, qui l'écrasait à 37px là où la maquette en donne 52 :
     c'est ce nom qui distingue le pilier des trois mini. Hors-échelle nommé. */
  .shop-tech-tile-name {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-shop-tech-tile);
    font-weight: 400;
    line-height: var(--ag-leading-display);
  }

  .shop-tech-tile-name .serif-it {
    color: var(--ag-accent);
  }

  .shop-tech-tile-desc {
    max-width: 34ch;
    margin-top: var(--ag-space-sm);

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-on-dark);
  }

  .shop-tech-tile-cta {
    display: inline-flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    margin-top: var(--ag-space-md);
    padding-bottom: var(--ag-space-3xs);
    border-bottom: 1px solid var(--ag-accent);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-paper);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .shop-tech-tile-name-mini {
    margin: 0;
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-style: italic;
  }

  .shop-tech-tile-arrow {
    position: absolute;
    z-index: var(--ag-z-raised);
    top: var(--ag-space-md);
    right: var(--ag-space-md);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-sm);
    color: var(--ag-paper);

    opacity: 0.85;

    transition: transform var(--ag-dur-base) var(--ag-ease);
  }

  .shop-tech-tile-mini:hover .shop-tech-tile-arrow {
    transform: translateX(3px);
  }

  /* --- Axe public : pastilles légères --- */

  .shop-profil-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ag-space-sm);
  }

  .shop-profil-card {
    display: flex;
    gap: var(--ag-space-md);
    align-items: center;

    padding: var(--ag-space-sm) var(--ag-space-lg) var(--ag-space-sm)
      var(--ag-space-sm);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);

    transition:
      border-color var(--ag-dur-base) var(--ag-ease),
      transform var(--ag-dur-base) var(--ag-ease),
      background var(--ag-dur-base) var(--ag-ease);
  }

  .shop-profil-card:hover {
    transform: translateY(-2px);
    border-color: var(--ag-ink);
    background: var(--ag-paper-deep);
  }

  .shop-profil-thumb {
    overflow: hidden;
    flex: 0 0 auto;

    width: 56px;
    height: 56px;
    border-radius: 50%;
  }

  .shop-profil-thumb .slot {
    display: block;

    aspect-ratio: 1;
    width: 100%;
    height: 100%;
    border-radius: 50%;
  }

  /* La maquette pose 23px, entre deux crans : xl (24) en est le plus proche,
     là où lg (20) l'arrondissait du mauvais côté. */
  .shop-profil-label {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-tight);
    letter-spacing: var(--ag-tracking-snug);
  }

  .shop-profil-count {
    display: block;

    margin-top: var(--ag-space-3xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  @media (width <= 900px) {
    .shop-tech-gallery {
      grid-template-columns: 1fr 1fr;
      height: auto;
    }

    .shop-tech-tile-main {
      grid-column: 1 / -1;
      height: 380px;
    }

    .shop-tech-tile-mini {
      height: 260px;
    }

    .shop-collections-grid {
      grid-template-columns: repeat(2, 1fr);
      gap: var(--ag-space-md);
    }

    .shop-profil-grid {
      grid-template-columns: 1fr;
    }
  }

  @media (width <= 560px) {
    .shop-collections-grid {
      gap: var(--ag-space-sm);
    }

    .shop-collection-name {
      font-size: var(--ag-text-md);
    }
  }
}

/* En-tête de section réutilisable du hub (ShopHead de la maquette) */

@layer components {
  .shop-shead {
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: var(--ag-space-2xl);
    align-items: end;

    margin-bottom: var(--ag-space-2xl);
  }

  .shop-shead-title {
    margin: 0;
  }

  .shop-shead-title .serif-it {
    color: var(--ag-accent);
  }

  .shop-shead-aside {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-sm);
    align-items: flex-start;
  }

  @media (width <= 900px) {
    .shop-shead {
      grid-template-columns: 1fr;
      gap: var(--ag-space-md);
    }
  }
}

/* ==========================================================================
   Boutique hub — cartes produit compacte et frise
   Décalqué de mockup_refv2/boutique.css (.shop-woo-*, .shop-frise-*), valeurs
   brutes remplacées par les jetons --ag-*. Ce sont les deux variantes que rend
   woocommerce/content-product.php quand `ag_card_variant` vaut `compact` ou
   `frise` ; la troisième forme, la carte du catalogue, garde ses `.patron-card`.
   ========================================================================== */

@layer components {
  .shop-woo-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ag-space-lg);
  }

  .shop-woo-card {
    display: block;
    min-width: 0;
  }

  .shop-woo-photo {
    position: relative;
  }

  .shop-woo-photo .slot {
    aspect-ratio: 4 / 5;
  }

  /* Les pastilles se posent sur la photo, comme la maquette — le nom et le
     prix gardent leur ligne pour eux seuls. */
  .shop-woo-flags {
    position: absolute;
    z-index: var(--ag-z-raised);
    top: var(--ag-space-xs);
    left: var(--ag-space-xs);

    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-3xs);
  }

  /* Nom et prix sur une même ligne de base, le type sous les deux : c'est la
     grille qui les tient alignés, pas un réglage de marge. */
  .shop-woo-body {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: var(--ag-space-xs);
    align-items: baseline;

    margin-top: var(--ag-space-sm);
  }

  .shop-woo-name {
    min-width: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-none);
    letter-spacing: var(--ag-tracking-snug);
  }

  .shop-woo-price {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-variant-numeric: tabular-nums;
    line-height: var(--ag-leading-none);
    white-space: nowrap;
  }

  .shop-woo-type {
    grid-column: 1 / -1;

    margin-top: var(--ag-space-3xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  /* --- Frise : la photo seule, serrée, sans texte --- */

  /* --- Section anneaux : en-tête discret, frise serrée --- */

  .shop-anneaux-section {
    padding-top: var(--ag-space-2xl);
    padding-bottom: var(--ag-space-4xl);
  }

  .shop-anneaux-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-lg);
    align-items: center;
    justify-content: space-between;

    margin-bottom: var(--ag-space-lg);
  }

  .shop-anneaux-title {
    margin: 0;
  }

  .shop-anneaux-lede {
    margin: var(--ag-space-2xs) 0 0;
    font-size: var(--ag-text-sm);
  }

  .shop-anneaux-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: var(--ag-space-sm);
  }

  .shop-frise-grid {
    gap: var(--ag-space-3xs);
  }

  .shop-frise-card {
    display: block;
  }

  .shop-frise-card .slot {
    border-radius: var(--ag-radius-sm);
    transition: transform var(--ag-dur-base) var(--ag-ease);
  }

  .shop-frise-card:hover .slot {
    transform: scale(1.04);
  }

  /* Seuils du thème (900 / 720 / 560, cf. DESIGN.md), pas ceux de la maquette :
     le reste de la CSS boutique les suit, et deux systèmes de rupture sur une
     même page se contredisent dès qu'une largeur tombe entre les deux. */
  @media (width <= 900px) {
    .shop-woo-grid {
      grid-template-columns: repeat(2, 1fr);
    }

    .shop-anneaux-grid {
      grid-template-columns: repeat(3, 1fr);
    }
  }

  @media (width <= 560px) {
    .shop-woo-grid {
      gap: var(--ag-space-xs);
    }

    .shop-woo-name {
      font-size: var(--ag-text-md);
    }

    .shop-anneaux-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }
}

@layer components {
  /* =============================================
   CART DRAWER (side sheet)
   Slide-in droite plein-hauteur, alimenté par assets/js/cart.js via
   wc/store/cart. Le shell est rendu par inc/cart-drawer.php dans wp_footer.
   Valeurs alignées sur mockup_refv2/mini-cart.css (drawer 440px, overlay
   voile 42% ink, transition 0.45s out-expo, thumb 84×105 aspect 4/5, item
   en grille 2 colonnes 84px+1fr avec .body flex-col ; stepper 26×26 boutons
   sur --paper avec value sur --paper-deep pour segmentation visible).
   ============================================= */

  body.ag-cart-lock {
    overflow: hidden;
  }

  /* Badge du header — cart-count posé par ag_render_cart_count() dans le
     lien Panier. Rendu vide côté PHP (contenu par-utilisateur, incompatible
     avec le cache CDN). cart.js remplit le textContent après hydration
     Store API. Le min-width réserve l'espace pour un compte à un chiffre
     et évite le layout shift quand JS injecte "(1)" quelques ms plus tard.
     Passer à `4ch` si un jour l'affichage pouvait dépasser 9 items. */
  .ag-cart-count {
    display: inline-block;
    min-width: 3ch;
    color: var(--ag-ink-soft);
    text-align: center;
  }

  /* Les parenthèses vivent en pseudo-éléments, pas dans le textContent :
     cart.js écrit le nombre nu, ce qui laisse la pilule mobile (icône +
     chiffre) s'en passer sans dupliquer la logique de peinture côté JS.
     `:not(:empty)` couvre les deux états sans compteur — avant hydratation
     Store API et panier vide — où « () » s'afficherait tout seul. */
  .ag-cart-count:not(:empty)::before {
    content: "(";
  }

  .ag-cart-count:not(:empty)::after {
    content: ")";
  }

  /* Backdrop — voile ink 42% (mockup), pas un fond opaque. */
  .ag-cart-drawer-backdrop {
    position: fixed;
    z-index: calc(var(--ag-z-overlay) - 1);
    inset: 0;

    visibility: hidden;
    opacity: 0;
    background: rgb(20 32 51 / 42%);

    transition:
      opacity var(--ag-dur-slow) var(--ag-ease),
      visibility 0s linear var(--ag-dur-slow);
  }

  .ag-cart-drawer-backdrop.is-open {
    visibility: visible;
    opacity: 1;
    transition:
      opacity var(--ag-dur-slow) var(--ag-ease),
      visibility 0s;
  }

  /* Drawer — 440px, out-expo cubic-bezier pour un slide-in ample et doux. */
  .ag-cart-drawer {
    position: fixed;
    z-index: var(--ag-z-overlay);
    top: 0;
    right: 0;
    transform: translateX(100%);

    display: flex;
    flex-direction: column;

    /* stylelint-disable declaration-property-value-no-unknown -- var() with dynamic length composed in a shorthand is misread by the value-no-unknown plugin. */
    width: min(440px, 100vw);
    /* stylelint-enable declaration-property-value-no-unknown */
    height: 100vh;
    height: 100dvh;

    color: var(--ag-ink);

    visibility: hidden;
    background: var(--ag-paper);

    /* Ombre gauche seule (le drawer sort à droite), plus douce qu'un shadow
       centré comme --ag-shadow-lg. Valeurs directes du mockup. */
    box-shadow: -24px 0 64px -20px rgb(20 32 51 / 28%);

    transition:
      transform 0.45s cubic-bezier(0.19, 1, 0.22, 1),
      visibility 0s linear 0.45s;
  }

  .ag-cart-drawer.is-open {
    transform: translateX(0);
    visibility: visible;
    transition:
      transform 0.45s cubic-bezier(0.19, 1, 0.22, 1),
      visibility 0s;
  }

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

  /* Header — padding asymétrique, count en eyebrow mono à côté du titre. */
  .ag-cart-drawer-header {
    display: flex;
    flex: 0 0 auto;
    gap: var(--ag-space-sm);
    align-items: baseline;
    justify-content: space-between;

    padding: var(--ag-space-lg) var(--ag-space-xl) var(--ag-space-md);
    border-bottom: 1px solid var(--ag-rule);
  }

  .ag-cart-drawer-title-wrap {
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: baseline;
  }

  .ag-cart-drawer-title {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxl);
    font-weight: var(--ag-weight-normal);
    letter-spacing: var(--ag-tracking-snug);
  }

  .ag-cart-drawer-count {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .ag-cart-drawer-close {
    cursor: pointer;

    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;

    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-pill);

    color: var(--ag-ink);

    background: transparent;

    transition:
      background var(--ag-dur-fast) var(--ag-ease),
      color var(--ag-dur-fast) var(--ag-ease),
      border-color var(--ag-dur-fast) var(--ag-ease);
  }

  .ag-cart-drawer-close:hover {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(--ag-ink);
  }

  /* Bandeau de confirmation — mint doux, slide-in 3,2 s après un ajout. */
  .ag-cart-drawer-confirm {
    overflow: hidden;
    display: flex;
    gap: var(--ag-space-2xs);
    align-items: center;

    max-height: 70px;
    padding: var(--ag-space-xs) var(--ag-space-xl);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    font-weight: var(--ag-weight-medium);
    color: var(--ag-secondary);

    opacity: 1;
    background: var(--ag-mint);

    transition:
      max-height var(--ag-dur-slow) var(--ag-ease),
      padding var(--ag-dur-slow) var(--ag-ease),
      opacity var(--ag-dur-slow) var(--ag-ease);
  }

  .ag-cart-drawer-confirm[hidden] {
    display: flex;

    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;

    opacity: 0;
  }

  .ag-cart-drawer-confirm svg {
    flex-shrink: 0;
  }

  /* Body — scrollable. */
  .ag-cart-drawer-body {
    overflow-y: auto;
    flex: 1 1 auto;
    padding: 0 var(--ag-space-xl);
  }

  .ag-cart-drawer-items {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* Item — grille 2 colonnes 84px+1fr, .body flex-col avec name/price en
     haut et stepper/remove en bas (margin-top:auto pousse en bas quand
     .body est étiré à la hauteur du thumb 105px). */
  .ag-cart-drawer-item {
    display: grid;
    grid-template-columns: 84px 1fr;
    gap: var(--ag-space-md);

    padding: var(--ag-space-lg) 0;
    border-bottom: 1px solid var(--ag-rule);
  }

  .ag-cart-drawer-item:last-child {
    border-bottom: 0;
  }

  .ag-cart-drawer-thumb {
    overflow: hidden;

    aspect-ratio: 4 / 5;
    width: 84px;
    border-radius: var(--ag-radius-sm);

    background: var(--ag-paper-deep);
  }

  .ag-cart-drawer-thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Fallback quand aucune image : slot hachuré (ink lines on paper),
     patron défini dans DESIGN.md. Rendu quand la thumb ne contient pas
     de <img> (le JS ne l'insère que si item.images[0] est utilisable). */
  .ag-cart-drawer-thumb:not(:has(img)) {
    background: repeating-linear-gradient(
      135deg,
      var(--ag-paper) 0 6px,
      color-mix(in srgb, var(--ag-ink) 8%, var(--ag-paper)) 6px 7px
    );
  }

  .ag-cart-drawer-item-body {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-3xs);
    min-width: 0;
  }

  .ag-cart-drawer-item-top {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: baseline;
    justify-content: space-between;
  }

  .ag-cart-drawer-item-name {
    margin: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
    text-decoration: none;
    letter-spacing: var(--ag-tracking-snug);
  }

  .ag-cart-drawer-item-name:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
  }

  .ag-cart-drawer-item-price {
    flex-shrink: 0;

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-md);
    font-weight: var(--ag-weight-normal);
    font-variant-numeric: tabular-nums;
    color: var(--ag-ink);
    white-space: nowrap;
  }

  .ag-cart-drawer-item-meta {
    margin: var(--ag-space-3xs) 0 0;
  }

  .ag-cart-drawer-item-bottom {
    display: flex;
    gap: var(--ag-space-xs);
    align-items: center;
    justify-content: space-between;

    margin-top: auto;
  }

  /* Stepper — dans un flex normal, sized to content. Boutons sur --paper,
     value sur --paper-deep pour un contraste subtil qui identifie chaque
     segment même sans compter sur les bordures. */
  .ag-cart-drawer-qty {
    overflow: hidden;
    display: flex;
    align-items: stretch;

    border: 1px solid var(--ag-rule-strong);
    border-radius: 6px;
  }

  .ag-cart-drawer-qty-btn {
    cursor: pointer;

    display: flex;
    align-items: center;
    justify-content: center;

    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;

    font-family: inherit;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-none);
    color: var(--ag-ink-soft);

    background: var(--ag-paper);

    transition:
      background var(--ag-dur-fast) var(--ag-ease),
      color var(--ag-dur-fast) var(--ag-ease);
  }

  .ag-cart-drawer-qty-btn:hover:not(:disabled) {
    color: var(--ag-ink);
    background: var(--ag-paper-deep);
  }

  .ag-cart-drawer-qty-btn:disabled {
    cursor: not-allowed;
    opacity: 0.4;
  }

  .ag-cart-drawer-qty-value {
    display: flex;
    align-items: center;
    justify-content: center;

    width: 28px;
    height: 26px;
    border-right: 1px solid var(--ag-rule-strong);
    border-left: 1px solid var(--ag-rule-strong);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--ag-ink);

    background: var(--ag-paper-deep);
  }

  .ag-cart-drawer-remove {
    padding: 0;
    border: 0;

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-cap);
    color: var(--ag-ink-soft);
    text-decoration: underline;
    text-underline-offset: 2px;

    background: none;

    transition: color var(--ag-dur-fast) var(--ag-ease);
  }

  .ag-cart-drawer-remove:hover {
    cursor: pointer;
    color: var(--ag-accent);
  }

  /* État vide — icône ronde + texte centré + CTA continuer.
     `display:flex` overrides the UA `[hidden]{display:none}` rule, so the
     hidden attribute set by cart.js needs an explicit reinstatement. */
  .ag-cart-drawer-empty {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--ag-space-md);
    align-items: center;
    justify-content: center;

    padding: var(--ag-space-5xl) var(--ag-space-xl);

    text-align: center;
  }

  .ag-cart-drawer-empty[hidden] {
    display: none;
  }

  .ag-cart-drawer-empty-icon {
    display: flex;
    align-items: center;
    justify-content: center;

    width: 56px;
    height: 56px;
    border: 1px solid var(--ag-rule-strong);
    border-radius: var(--ag-radius-pill);

    color: var(--ag-ink-soft);
  }

  .ag-cart-drawer-empty-text {
    max-width: 30ch;
    margin: 0;

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  /* Footer — sticky bas, fond paper-deep pour délimiter du corps. */
  .ag-cart-drawer-footer {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    gap: var(--ag-space-md);

    padding: var(--ag-space-lg) var(--ag-space-xl) var(--ag-space-md);
    border-top: 1px solid var(--ag-rule);

    background: var(--ag-paper-deep);
  }

  .ag-cart-drawer-footer[hidden] {
    display: none;
  }

  .ag-cart-drawer-total {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
  }

  .ag-cart-drawer-total-label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  .ag-cart-drawer-total-value {
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xxxl);
    font-weight: var(--ag-weight-normal);
    font-variant-numeric: tabular-nums;
    color: var(--ag-ink);
    letter-spacing: var(--ag-tracking-snug);
  }

  .ag-cart-drawer-discounts {
    margin: 0 0 var(--ag-space-xs);
    padding: 0;
    list-style: none;
  }

  /* Sans coupon, cart.js vide la liste mais la laisse dans le DOM : à hauteur
     nulle elle restait un enfant flex du pied, donc sa marge et le `gap: 20px`
     de .ag-cart-drawer-footer s'appliquaient quand même — 32 px de vide au-dessus
     de TOTAL, dans le cas le plus courant. */
  .ag-cart-drawer-discounts:empty {
    display: none;
  }

  .ag-cart-drawer-discounts li {
    display: flex;
    justify-content: space-between;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-cap);
    color: var(--ag-accent-deep);
    letter-spacing: var(--ag-tracking-label);
  }

  /* Renvoie vers /panier/, seule surface de saisie : le drawer reste compact. */
  .ag-cart-drawer-promo-link {
    display: inline-block;

    margin-top: var(--ag-space-xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-decoration: underline;
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow-lg);
  }

  .ag-cart-drawer-promo-link:hover { color: var(--ag-accent); }

  /* Un display porté par une classe l'emporte sur celui de [hidden]. */
  .ag-cart-drawer-promo-link[hidden] { display: none; }

  .ag-cart-drawer-actions {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
  }

  /* Les CTAs prennent toute la largeur, .btn est inline-flex par défaut. */
  .ag-cart-drawer-cta {
    display: flex;
    justify-content: center;
    padding: var(--ag-space-sm);
  }

  .ag-cart-drawer-reassurance {
    display: grid;
    gap: var(--ag-space-2xs);

    margin: 0;
    padding: var(--ag-space-md) 0 0;
    border-top: 1px solid var(--ag-rule);

    font-size: var(--ag-text-cap);
    line-height: var(--ag-leading-tight);
    color: var(--ag-ink-soft);
    list-style: none;
  }

  .ag-cart-drawer-reassurance li {
    display: grid;
    grid-template-columns: 14px 1fr;
    gap: var(--ag-space-2xs);
    align-items: baseline;
  }

  .ag-cart-drawer-reassurance li::before {
    content: "✓";
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-bold);
    color: var(--ag-accent);
  }

  /* Message d'erreur inline (Store API dispatch rejeté). */
  .ag-cart-error {
    margin: var(--ag-space-2xs) 0 0;
    font-size: var(--ag-text-sm);
    color: var(--ag-accent);
  }

  /* Panier compact sous 900px — la pilule tombe à icône + chiffre, le mot
     « Panier » sort. C'est lui qui poussait le cluster droit (compte, panier,
     burger) au-delà d'un viewport de 375px. Le lien garde son `aria-label`,
     donc le texte retiré n'était de toute façon pas annoncé.

     Calé sur la largeur seule, sans la clause `(hover: none)` qui accompagne
     le basculement burger plus haut : une machine tactile large affiche le
     burger mais a de la place de reste, et n'a aucune raison de perdre le mot.

     Ce bloc vit ici, dans la section badge, et non près du reste du header :
     `.ag-cart-count` est (re)défini juste au-dessus, dans le même layer et à
     spécificité égale. Placé plus haut dans le fichier, il perdrait le
     `min-width: 3ch` en source order sans rien signaler. */
  @media (width <= 900px) {
    .ag-cart-link {
      padding: var(--ag-space-xs) 14px;
    }

    .ag-cart-link .ag-cart-word {
      display: none;
    }

    /* `1ch` remplace les `3ch` du desktop : la réservation anti-layout-shift
       de l'hydratation reste, elle ne coûte plus que la largeur d'un chiffre. */
    .ag-cart-count {
      min-width: 1ch;

      font-family: var(--ag-font-mono);
      font-size: var(--ag-text-xs);
      font-weight: var(--ag-weight-semibold);
      color: var(--ag-ink);
    }

    .ag-cart-count:not(:empty)::before,
    .ag-cart-count:not(:empty)::after {
      content: none;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .ag-cart-drawer,
    .ag-cart-drawer-backdrop,
    .ag-cart-drawer-confirm {
      transition: none;
    }
  }

  @media (width <= 520px) {
    .ag-cart-drawer {
      width: 100%;
    }
  }
}

/* ==========================================================================
   Page À propos — portage de mockup_refv2/styles.css § PAGE À PROPOS
   ==========================================================================
   Les jetons de la maquette (--ink-soft, --muted, --rule, --accent-deep,
   --font-mono, --font-display) n'existent pas ici : chaque référence est
   traduite vers son alias --ag-*. Les tailles hors échelle sont ramenées au
   cran le plus proche, égalité au cran inférieur — écarts à contrôler en
   vérification visuelle : gap hero 22->20, gap frise 28->24, titre frise
   21->20, texte frise 13.5->14, prose 17.5->18, note hero 15.5->16, texte
   univers 15->16, chiffre repère 26->24.

   La grille générique `grid-12` + spans inline de la maquette devient des
   grilles nommées aux mêmes proportions ; comme elle, elles ne s'effondrent
   qu'à 720px. La section « Dans les coulisses » n'est pas portée : la
   maquette la définit mais ne la rend pas.
   ========================================================================== */

@layer components {
  /* La clôture est une bande pleine largeur : elle doit toucher le pied de
     page, sans la respiration que les pages ordinaires laissent. */
  .apropos-page + .footer {
    margin-top: 0;
  }

  /* --- Hero --------------------------------------------------------------- */
  .ap-hero {
    padding-top: var(--ag-space-4xl);
    padding-bottom: var(--ag-space-4xl);
  }

  .ap-hero-grid {
    display: grid;
    grid-template-columns: 5fr 7fr;
    gap: var(--ag-space-md);
    align-items: center;
  }

  .ap-hero-photo {
    position: relative;
  }

  .ap-hero-photo .slot {
    min-height: 480px;
  }

  .ap-hero .eyebrow {
    display: block;
    margin-bottom: var(--ag-space-lg);
  }

  .ap-hero-title {
    max-width: 13ch;
    margin: 0;
  }

  .ap-hero-title .serif-it {
    color: var(--ag-accent);
  }

  .ap-hero-note {
    max-width: 46ch;
    margin-top: var(--ag-space-lg);
    font-size: var(--ag-text-base);
    color: var(--ag-ink-soft);
  }

  .ap-hero-cta {
    margin-top: var(--ag-space-lg);
  }

  /* La note débogue volontairement à gauche de la photo : c'est ce débord qui
     la fait lire comme un post-it posé dessus, pas comme une légende. */
  .ap-hero-note-sticky {
    position: absolute;
    bottom: var(--ag-space-lg);
    left: -14px;
  }

  /* --- 01 · Mon histoire -------------------------------------------------- */
  .ap-histoire-grid {
    display: grid;
    grid-template-columns: 7fr 5fr;
    gap: var(--ag-space-4xl);
    align-items: start;
  }

  .ap-histoire-body .eyebrow {
    display: block;
    margin-bottom: var(--ag-space-md);
  }

  .ap-histoire-title {
    margin: 0 0 var(--ag-space-lg);
  }

  .ap-histoire-body .article-prose {
    font-size: var(--ag-text-md);
    color: var(--ag-ink-soft);
  }

  .ap-histoire-photos {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-md);
  }

  /* La seconde photo est décalée vers la droite pour casser l'alignement de
     la colonne et éviter l'effet catalogue. */
  .ap-histoire-photos > :nth-child(2) {
    width: 84%;
    margin-left: 16%;
  }

  /* --- Frise chronologique ------------------------------------------------ */
  .ap-frise-row {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--ag-space-lg);

    padding-top: var(--ag-space-xs);
    border-top: 1px solid var(--ag-rule);
  }

  .ap-frise-step {
    display: block;
  }

  .ap-frise-photo {
    overflow: hidden;
    margin-bottom: var(--ag-space-md);
    border-radius: var(--ag-radius-sm);
  }

  /* 0,5s : la maquette étire volontairement ce zoom au-delà de --ag-dur-slow
     pour que le mouvement se lise comme un travelling, pas comme un survol. */
  .ap-frise-photo img {
    transition: transform 0.5s var(--ag-ease);
  }

  .ap-frise-step:hover .ap-frise-photo img {
    transform: scale(1.045);
  }

  .ap-frise-date {
    display: block;

    margin-bottom: var(--ag-space-2xs);

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-accent-deep);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-eyebrow);
  }

  .ap-frise-title {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    line-height: var(--ag-leading-snug);
    color: var(--ag-ink);
  }

  .ap-frise-text {
    margin: 0 0 var(--ag-space-xs);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  .ap-frise-link {
    display: inline-flex;
    gap: var(--ag-space-3xs);
    align-items: center;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);

    transition: color var(--ag-dur-fast) var(--ag-ease);
  }

  .ap-frise-step:hover .ap-frise-link {
    color: var(--ag-accent-deep);
  }

  .ap-frise-step:hover .ap-frise-link .btn-arrow {
    transform: translateX(4px);
  }

  /* --- 02 · Ma vision ----------------------------------------------------- */
  .ap-vision .eyebrow {
    display: block;
    margin-bottom: var(--ag-space-md);
  }

  .ap-vision-title {
    max-width: 14ch;
    margin: 0 0 var(--ag-space-4xl);
  }

  .ap-vision-body {
    display: grid;
    grid-template-columns: 1fr 0.82fr;
    gap: 0 var(--ag-space-4xl);
    align-items: start;

    margin-bottom: var(--ag-space-4xl);
  }

  .ap-vision-text {
    max-width: 56ch;
    padding-top: var(--ag-space-3xs);
  }

  .ap-vision-text .article-prose {
    font-size: var(--ag-text-md);
    color: var(--ag-ink-soft);
  }

  /* La photo descend sous la première ligne de texte : le décalage crée la
     diagonale qui tient la section. */
  .ap-vision-photo {
    margin-top: var(--ag-space-3xl);
  }

  .ap-vision-highlight {
    max-width: 20ch;
    margin: 0 0 0 auto;

    font-family: var(--ag-font-display);
    font-size: clamp(24px, 2.6vw, 34px);
    font-style: italic;
    line-height: var(--ag-leading-exergue);
    color: var(--ag-ink);
    text-align: right;
  }

  /* --- 03 · Mon univers --------------------------------------------------- */
  .ap-univers-head {
    max-width: 58%;
    margin-bottom: var(--ag-space-2xl);
  }

  .ap-univers-head .eyebrow {
    display: block;
    margin-bottom: var(--ag-space-md);
  }

  .ap-univers-title {
    margin: 0;
  }

  .ap-univers-grid {
    display: grid;
    grid-template-columns: 5fr 7fr;
    gap: var(--ag-space-lg);
    align-items: stretch;
  }

  .ap-univers-eds {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
  }

  .ap-univers-ed {
    display: block;

    padding: var(--ag-space-lg) 0;
    border-bottom: 1px solid var(--ag-rule);

    text-decoration: none;

    transition: padding var(--ag-dur-base) var(--ag-ease);
  }

  .ap-univers-ed:first-child {
    padding-top: 0;
  }

  .ap-univers-ed:hover {
    padding-left: var(--ag-space-2xs);
  }

  .ap-univers-ed-title {
    margin: 0 0 var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink);
  }

  .ap-univers-ed-text {
    max-width: 58ch;
    margin: 0;

    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-base);
    color: var(--ag-ink-soft);
  }

  /* --- Repères chiffrés --------------------------------------------------- */
  .ap-reperes-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-4xl);
    justify-content: center;
  }

  .ap-repere {
    text-align: center;
  }

  .ap-repere-num {
    display: block;

    margin-bottom: var(--ag-space-2xs);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-xl);
    line-height: var(--ag-leading-none);
    color: var(--ag-ink);
  }

  .ap-repere-label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xxs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  /* --- Clôture ------------------------------------------------------------ */
  .ap-closing {
    text-align: center;
  }

  .ap-closing .eyebrow {
    display: block;
    margin-bottom: var(--ag-space-md);
  }

  .ap-closing-title {
    margin: 0;
  }

  .ap-closing-title .serif-it {
    color: var(--ag-accent);
  }

  .ap-closing-lede {
    margin-top: var(--ag-space-lg);
  }

  .ap-closing-paper {
    background: var(--ag-paper-deep);
  }

  /* Le ghost par défaut est calibré pour le papier pur ; sur paper-deep il
     lui faut un filet plus marqué pour ne pas disparaître. */
  .ap-closing-paper .btn-ghost {
    border-color: var(--ag-rule-strong);
    color: var(--ag-ink);
  }

  .ap-closing-paper .btn-ghost:hover {
    border-color: var(--ag-ink);
    color: var(--ag-cream);
    background: var(--ag-ink);
  }

  .ap-closing-inner {
    display: flex;
    flex-direction: column;
    align-items: center;

    max-width: 640px;
    margin: 0 auto;
  }

  .ap-closing-ctas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ag-space-sm);
    justify-content: center;

    margin-top: var(--ag-space-xl);
  }

  @media (width <= 900px) {
    .ap-vision-body {
      grid-template-columns: 1fr;
      gap: var(--ag-space-xl);
    }

    /* La photo remonte au-dessus du texte : en une colonne, la diagonale ne
       tient plus et l'image doit rester l'entrée de la section. */
    .ap-vision-photo {
      order: -1;
      margin-top: 0;
    }

    .ap-vision-highlight {
      max-width: none;
      margin: 0;
      text-align: left;
    }

    .ap-frise-row {
      grid-template-columns: repeat(3, 1fr);
      gap: var(--ag-space-xl) var(--ag-space-md);
    }

    .ap-univers-head {
      max-width: none;
    }
  }

  @media (width <= 720px) {
    .ap-hero {
      padding-top: var(--ag-space-xl);
    }

    .ap-hero-grid,
    .ap-histoire-grid,
    .ap-univers-grid {
      grid-template-columns: 1fr;
    }

    .ap-hero-photo .slot {
      min-height: 320px;
    }

    .ap-histoire-photos > :nth-child(2) {
      width: 92%;
      margin-left: 8%;
    }

    .ap-frise-row {
      grid-template-columns: 1fr 1fr;
    }

    .ap-repere {
      flex: 1 1 45%;
    }
  }
}

/* ==========================================================================
   Page Contact — portage de mockup_refv2/contact.css
   ==========================================================================
   Jetons de la maquette absents ici : --muted -> --ag-ink-soft (KTD11). Les
   deux dessins de champ du site (tunnel encadré, contact souligné) sont
   incompatibles plutôt que divergents à la marge (KTD10) : la recette de
   .contact-field ne réutilise donc rien de assets/css/tunnel.css. Points de
   rupture du thème (900 / 720), jamais le 800px unique de la maquette
   (KTD11) — la grille de cartes suit .grid-auto (3 -> 2 -> 1).
   ========================================================================== */

@layer components {
  /* --- Hero ----------------------------------------------------------------- */
  .contact-hero {
    max-width: 640px;
    padding-top: var(--ag-space-5xl);
    padding-bottom: var(--ag-space-3xl);
  }

  .contact-hero .lede {
    max-width: 52ch;
    margin-top: var(--ag-space-md);
  }

  /* --- Orientation : trois cartes -------------------------------------------- */
  .contact-orientation-eyebrow {
    margin-bottom: var(--ag-space-xl);
  }

  /* Même mécanique que .tech-grid (style.css:4918) : le filet d'1px entre
     cellules est le fond de la grille lui-même, visible à travers le gap —
     aucune double bordure possible quel que soit le nombre de colonnes. */
  .contact-cards {
    overflow: hidden;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px; /* 1px : filet entre cellules, intentionnel */

    margin-bottom: var(--ag-space-5xl);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-md);

    background: var(--ag-rule);
  }

  .contact-card {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-md);

    padding: var(--ag-space-2xl) var(--ag-space-xl);

    background: var(--ag-paper);
  }

  .contact-card h3 {
    margin: 0;
    font-family: var(--ag-font-body);
    font-size: var(--ag-text-md);
    font-weight: var(--ag-weight-semibold);
  }

  .contact-card p {
    flex: 1;

    margin: 0;

    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .contact-card .btn {
    align-self: flex-start;
    white-space: nowrap;
  }

  /* --- Formulaire ------------------------------------------------------------- */
  .contact-form-block {
    margin-bottom: var(--ag-space-5xl);
    padding: var(--ag-space-3xl) var(--ag-space-5xl);
    border-radius: var(--ag-radius-md);
    background: var(--ag-paper-deep);
  }

  .contact-form-block .display-s {
    margin: 0 0 var(--ag-space-2xl);
  }

  .contact-form {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-xl);
  }

  .contact-form .row-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ag-space-xl);
    max-width: 680px;
  }

  /* Deux dessins de champ incompatibles cohabitent sur le site (KTD10) : le
     tunnel encadre, cette page souligne. Rien n'est promu ni partagé. */
  .contact-field {
    display: flex;
    flex-direction: column;
    gap: var(--ag-space-2xs);
    max-width: 680px;
  }

  .contact-field:has(textarea),
  .contact-field.contact-demande {
    max-width: none;
  }

  .contact-field label {
    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .contact-field input,
  .contact-field select,
  .contact-field textarea {
    padding: var(--ag-space-2xs) 0;
    border: none;
    border-bottom: 1px solid var(--ag-rule);
    border-radius: 0;

    font: inherit;
    font-size: var(--ag-text-base);
    color: var(--ag-ink);

    background: transparent;

    transition: border-color var(--ag-dur-base) ease;
  }

  .contact-field input:focus,
  .contact-field select:focus,
  .contact-field textarea:focus {
    border-color: var(--ag-ink);
    outline: 2px solid transparent;
    outline-offset: 2px;
  }

  /* Le filet seul ne porte pas le focus assez fort (KTD8 pose la même règle
     pour les pastilles) : un contour visible double la couleur. */
  .contact-field input:focus-visible,
  .contact-field select:focus-visible,
  .contact-field textarea:focus-visible {
    outline: 2px solid var(--ag-ink);
  }

  .contact-field textarea {
    /* Widely supported since 2010 across every current browser; the
       plugin's baseline dataset just lags on this one. */
    /* stylelint-disable-next-line plugin/use-baseline */
    resize: vertical;
    min-height: 110px;
    line-height: var(--ag-leading-relaxed);
  }

  .contact-field .req {
    margin-left: var(--ag-space-3xs);
    color: var(--ag-accent);
  }

  .contact-field .ag-optional {
    margin-left: var(--ag-space-2xs);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-xs);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink-soft);
    text-transform: none;
    letter-spacing: normal;
  }

  .contact-demande fieldset {
    margin: 0;
    padding: 0;
    border: none;
  }

  .contact-demande legend {
    padding: 0;

    font-family: var(--ag-font-mono);
    font-size: var(--ag-text-xs);
    color: var(--ag-ink-soft);
    text-transform: uppercase;
    letter-spacing: var(--ag-tracking-label);
  }

  .contact-help ul {
    margin: var(--ag-space-2xs) 0 var(--ag-space-2xs) var(--ag-space-md);
    padding: 0;
  }

  .contact-form-note {
    margin: var(--ag-space-2xs) 0 0;
    font-size: var(--ag-text-cap);
    color: var(--ag-ink-soft);
  }

  .contact-form-success {
    padding: var(--ag-space-xl) 0;
  }

  .contact-form-success-title {
    margin: 0 0 var(--ag-space-sm);
    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
  }

  .contact-form-error {
    margin: 0 0 var(--ag-space-lg);
    padding: var(--ag-space-sm) var(--ag-space-md);
    border-left: 2px solid var(--ag-accent);

    color: var(--ag-ink);

    background: var(--ag-paper);
  }

  /* --- Mention d'information (R19, KTD13) -------------------------------------- */
  .contact-privacy {
    margin-top: var(--ag-space-xl);
    padding-top: var(--ag-space-lg);
    border-top: 1px solid var(--ag-rule);
  }

  .contact-privacy-short {
    margin: 0;
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .contact-privacy-details {
    margin-top: var(--ag-space-2xs);
    font-size: var(--ag-text-sm);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .contact-privacy-details summary {
    cursor: pointer;
    color: var(--ag-ink);
    text-decoration: underline;
  }

  .contact-privacy-details[open] summary {
    margin-bottom: var(--ag-space-sm);
  }

  .contact-privacy-details p {
    margin: 0 0 var(--ag-space-sm);
  }

  .contact-privacy-heading {
    color: var(--ag-ink);
  }

  /* --- Pastilles radio (KTD8) --------------------------------------------------
     Nouvelle classe, distincte de .chip : le survol de .chip inverse déjà en
     encre pleine, ce qui rendrait le survol indistinct de la sélection ici. */
  .pills {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--ag-space-2xs);
  }

  .pill {
    position: relative;
    display: inline-flex;
  }

  /* Posé aux dimensions de la pastille (label ci-dessous), jamais au pixel :
     un lecteur d'écran tactile qui explore l'écran au doigt ne trouverait pas
     une cible d'un pixel. */
  .pill input {
    cursor: pointer;

    position: absolute;
    inset: 0;

    margin: 0;

    opacity: 0;
  }

  .pill label {
    display: inline-flex;
    align-items: center;

    padding: var(--ag-space-2xs) var(--ag-space-md);
    border: 1px solid var(--ag-rule);
    border-radius: var(--ag-radius-pill);

    font-family: var(--ag-font-body);
    font-size: var(--ag-text-sm);
    color: var(--ag-ink-soft);
    white-space: nowrap;

    background: var(--ag-paper);

    transition:
      background var(--ag-dur-base) ease,
      color var(--ag-dur-base) ease,
      border-color var(--ag-dur-base) ease;
  }

  /* :hover sur .pill, jamais sur label : l'input transparent est au-dessus du
     label dans l'empilement, il capterait seul le survol sinon. */
  .pill:hover label {
    border-color: var(--ag-ink);
  }

  .pill input:checked + label {
    border-color: var(--ag-ink);
    color: var(--ag-paper);
    background: var(--ag-ink);
  }

  .pill input:focus-visible + label {
    outline: 2px solid var(--ag-ink);
    outline-offset: 2px;
  }

  /* --- Aide conditionnelle (KTD9) -----------------------------------------------
     Révélée en CSS par :has(), le texte reste en permanence dans le document :
     un lecteur d'écran l'annonce même replié, et l'ordre du document le place
     juste après le groupe de choix. Ni fond ni filet, conformément à la
     maquette. Plafond de hauteur relevé par rapport à la maquette (220px) :
     replié sur un écran étroit, l'aide « Un patron de tricot » le dépasserait
     et perdrait sa dernière ligne sans aucun signe. */
  .contact-help {
    overflow: hidden;

    max-height: 0;
    margin: 0;
    padding: 0;

    opacity: 0;

    transition:
      max-height var(--ag-dur-slow) ease,
      opacity var(--ag-dur-base) ease;
  }

  .contact-demande:has(#ag-contact-demande-commande:checked) .contact-help[data-demande='commande'],
  .contact-demande:has(#ag-contact-demande-patron:checked) .contact-help[data-demande='patron'],
  .contact-demande:has(#ag-contact-demande-presse:checked) .contact-help[data-demande='presse'] {
    max-height: 420px;
    margin-top: calc(var(--ag-space-2xs) * -1);
    padding-top: var(--ag-space-sm);
    opacity: 1;
  }

  @media (width <= 900px) {
    .contact-cards {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @media (width <= 720px) {
    .contact-hero {
      padding-top: var(--ag-space-3xl);
      padding-bottom: var(--ag-space-xl);
    }

    .contact-cards {
      grid-template-columns: 1fr;
    }
  }

  /* Le contraste forcé du système ignore les couleurs de fond : l'épaisseur du
     filet redouble alors seule la sélection (KTD8, R22). */
  @media (forced-colors: active) {
    .pill input:checked + label {
      border-width: 3px;
    }
  }

  @media (width <= 720px) {
    .contact-form-block {
      padding: var(--ag-space-xl) var(--ag-space-lg);
    }

    .contact-form .row-2 {
      grid-template-columns: 1fr;
    }

    /* Défaut de Q3 : la maquette n'a pas de point de rupture pour les
       pastilles et déborde sur mobile sans lui. */
    .pills {
      flex-wrap: wrap;
    }
  }
}

/* ==========================================================================
   Page Dessins — portage de mockup_refv2/dessins.css
   ==========================================================================
   Jetons de la maquette absents ici : --paper -> --ag-paper, --rule ->
   --ag-rule, --ink -> --ag-ink, --ink-soft -> --ag-ink-soft, --font-display
   -> --ag-font-display. --section-y (120px côté maquette) n'a pas
   d'équivalent direct — --ag-space-section (30px) est un token différent
   malgré le nom proche, donc chaque occurrence est ramenée au cran
   --ag-space-* le plus proche comme n'importe quelle valeur hors échelle.

   Cadrans hors échelle -> cran le plus proche, égalité au cran inférieur
   (même règle que la page À propos) : hero padding-top 72->80, gallery
   padding-bottom / thread padding 120->80, gallery gap 88->80, card-title
   margin-top 18->16, thread p margin-bottom 18->16, thread p taille 17->16
   (égalité base/md, cran inférieur), mobile gallery-section padding-bottom
   60->56, mobile gallery/row gap 44->40 (égalité, cran inférieur).

   .dessins-lightbox* n'est pas porté : la lightbox partagée (.ag-lightbox,
   assets/js/product-page.js) couvre ce besoin (KTD1). .dessins-back* n'est
   pas porté non plus : cette page n'a pas de lien retour (R3).
   ========================================================================== */

@layer components {
  .dessins-page {
    background: var(--ag-paper);
  }

  /* --- Hero ------------------------------------------------------------- */
  .dessins-hero {
    max-width: 900px;
    padding-top: var(--ag-space-5xl);
    padding-bottom: var(--ag-space-2xl);
  }

  .dessins-hero-title {
    margin: 0 0 var(--ag-space-lg);
  }

  .dessins-hero-sub {
    max-width: 62ch;
  }

  /* --- Galerie ------------------------------------------------------------ */
  .dessins-gallery-section {
    padding: var(--ag-space-lg) 0 var(--ag-space-5xl);
  }

  /* Pinterest-style masonry, no JS. `columns` (near-universal support) is
     the baseline; `display: grid-lanes` (Safari 26+, others behind flags as
     of 2026 — see docs/solutions for the browser-support note) is layered
     on top via @supports where available, since it keeps DOM/reading order
     instead of the visual reordering `columns` does top-to-bottom-per-column. */
  .dessins-gallery {
    columns: 300px;
    column-gap: var(--ag-space-4xl);
  }

  @supports (display: grid-lanes) {
    .dessins-gallery {
      display: grid-lanes;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: var(--ag-space-4xl);

      /* stylelint-disable-next-line plugin/use-baseline */
      reading-flow: grid-columns;
    }
  }

  .dessin-card {
    cursor: pointer;

    display: block;

    width: 100%;
    margin: 0;
    padding: 0;
    border: none;

    font-family: inherit;
    text-align: left;

    background: none;
  }

  /* Un travail pas encore importé (ag_dessins_photo() found:false) rend le
     bouton `disabled` — pas de zoom hover ni de curseur pointer à promettre
     pour une carte qui n'ouvre rien. */
  .dessin-card:disabled {
    cursor: default;
  }

  .dessin-card .slot {
    overflow: hidden;
    border-radius: var(--ag-radius-sm);
  }

  /* 0,5s : la maquette étire volontairement ce zoom au-delà de --ag-dur-slow
     pour que le mouvement se lise comme un travelling, pas comme un survol —
     même raisonnement que .ap-frise-photo img (style.css:12206). */
  .dessin-card .slot img {
    transition: transform 0.5s var(--ag-ease);
  }

  .dessin-card:hover .slot img,
  .dessin-card:focus-visible .slot img {
    transform: scale(1.015);
  }

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

  .dessin-card-title {
    display: block;

    margin-top: var(--ag-space-sm);

    font-family: var(--ag-font-display);
    font-size: var(--ag-text-lg);
    font-weight: var(--ag-weight-normal);
    color: var(--ag-ink);
  }

  /* 0,8s : même raisonnement que le zoom de carte ci-dessus — la maquette
     étire volontairement cette apparition au scroll au-delà de
     --ag-dur-slow pour un fondu progressif, pas un simple crossfade. */
  .dessin-reveal {
    transform: translateY(18px);

    break-inside: avoid;

    /* `margin-bottom` stands in for the vertical gap `columns` has no
       property for; `grid-lanes`'s `gap` covers that instead, so this is
       zeroed back out inside the @supports block below. */
    margin-bottom: var(--ag-space-4xl);

    opacity: 0;

    transition:
      opacity 0.8s var(--ag-ease),
      transform 0.8s var(--ag-ease);
  }

  .dessin-reveal.is-visible {
    transform: none;
    opacity: 1;
  }

  @supports (display: grid-lanes) {
    .dessin-reveal {
      margin-bottom: 0;
    }
  }

  /* --- Le fil conducteur --------------------------------------------------- */
  .dessins-thread-wrap {
    border-top: 1px solid var(--ag-rule);
  }

  .dessins-thread {
    max-width: 68ch;
    padding: var(--ag-space-5xl) 0;
  }

  .dessins-thread p {
    margin: 0 0 var(--ag-space-sm);
    font-size: var(--ag-text-base);
    line-height: var(--ag-leading-relaxed);
    color: var(--ag-ink-soft);
  }

  .dessins-thread p:last-child {
    margin-bottom: 0;
  }

  .dessins-thread-title .serif-it {
    color: var(--ag-accent);
  }

  /* No 900px column-count override needed: `columns: 300px` and
     `grid-template-columns: repeat(auto-fill, minmax(300px, 1fr))` both
     compute their own column count from the available width. */
  @media (width <= 720px) {
    .dessins-hero {
      padding-top: var(--ag-space-2xl);
      padding-bottom: var(--ag-space-lg);
    }

    .dessins-gallery-section {
      padding: var(--ag-space-sm) 0 var(--ag-space-4xl);
    }

    .dessins-gallery {
      column-gap: var(--ag-space-2xl);
    }

    .dessin-reveal {
      margin-bottom: var(--ag-space-2xl);
    }
  }

  @supports (display: grid-lanes) {
    @media (width <= 720px) {
      .dessins-gallery {
        gap: var(--ag-space-2xl);
      }
    }
  }
}
