/* Les Anneaux de Saturne — BRAND B "La collection" tokens.
   A French maison d'édition: paper, ink, one bookish accent. EB Garamond carries the
   whole store (display + body) — deliberately a DIFFERENT family from klymenko.fr.
   Palettes switch via <html data-palette="b1|b2|b3"> (dev switcher; B1 default).
   Legacy variables retained while inner pages await roll-across. */

/* ── Palettes — the four offered to Fabien, all on the same cream paper (redesign 2026-06-24).
   <html data-palette="oxblood|vert|prusse|or"> · oxblood default. Only --accent/--accent-dk
   change per palette. The legacy --b-* names are ALIASED to the new tokens, so the existing
   Tailwind-classed inner pages (shop/book/à-propos/legal) follow the same switcher (var()
   resolves lazily, so overriding --accent per palette recolours the aliases too). */
:root, html[data-palette="oxblood"] {
  --bg:#F8F4EA; --alt:#EFE8D7; --card:#FFFFFF; --ink:#1C1A17; --mute:#6E665B; --line:#E3DAC7;
  --gold:#C9A35C; --on-accent:#FFF8EE;
  --band:#1C1A17; --band-ink:#F3EAD9; --band-mute:#B6ADA0; --band-line:rgba(255,255,255,.14);
  --accent:#8E2F2F; --accent-dk:#6F2424;
  /* Secondary CTA (the stacked 'Ajouter au panier' under a primary). Solid, clearly
     subordinate, never a second accent colour. Read by buy-button.js too. */
  --btn-2:#1C1A17; --btn-2-dk:#000;
  --eyebrow-on-dark:#EFD9A8;
  /* Section eyebrows on LIGHT backgrounds. Deliberately follows --accent rather than --gold:
     under the saturne palette --gold is satin silver #AEB5BD, which sits near 2:1 on the ivory
     paper and was genuinely hard to read (Connor 2026-07-20). var() resolves lazily, so each
     palette's accent supplies its own eyebrow colour and every one of them clears 3:1. */
  --eyebrow-ink:var(--accent);

  /* Brand A night tokens for the mirror-stitch band (consultations) */
  --night:#07070D; --night-ink:#F2F0EA; --night-muted:#B6B4C4;

  /* Legacy --b-* aliases → drive the existing Tailwind utility pages off the same palette. */
  --b-ground:var(--bg); --b-card:#FFFDF7; --b-ink:var(--ink); --b-muted:var(--mute);
  --b-accent:var(--accent); --b-accent-dk:var(--accent-dk); --b-accent-ink:var(--on-accent);
  --b-rule:var(--line); --b-rule-dk:#C9C0A8; --b-gold:var(--gold);
}
html[data-palette="vert"]   { --accent:#2F5243; --accent-dk:#244035; }
html[data-palette="prusse"] { --accent:#1F3A5F; --accent-dk:#172C49; }
html[data-palette="or"]     { --accent:#A8853F; --accent-dk:#876A30; }

/* "Saturne" — Fabien's proposed cooler identity (his email 2026-07-20): Prussian Blue #1C2E4A,
   Satin Silver #AEB5BD, Anthracite #30343A, Ivory #F5F3EE. Unlike the other four this is a whole
   scheme, not just an accent swap — it changes the paper off cream onto ivory, the ink off warm
   near-black onto anthracite, and critically retires --gold to satin silver, which is the
   "replace the gold accents" part of the ask. Added as a switchable option rather than made the
   default so it can be compared side by side before anyone commits. */
html[data-palette="saturne"] {
  --bg:#F5F3EE; --alt:#EAE7E0; --card:#FFFFFF; --ink:#30343A; --mute:#6B7078; --line:#DCD8D1;
  /* REVISED 2026-07-20 (Connor): as originally specified this palette had no warm or bright
     colour anywhere — Prussian blue is dark and desaturated, satin silver and anthracite are
     both grey, ivory is off-white. Everything sat in the same low-chroma band and the site read
     as dead. Two changes, both keeping blue as the lead colour:
       1. --gold STAYS satin silver, per Fabien's "replace the gold accents". Brass was trialled
          across the whole site on 2026-07-20 and pulled back the same day (Connor): the only
          place gold earns its keep is the promo bar, which now has its own --promo-hi token.
       2. --band moves off anthracite grey onto deep Prussian. The announcement bar, YouTube band
          and footer are the biggest blocks of colour on the page and they were all grey; blue
          makes the site read blue, which is what the brand is. Kept one step darker than
          --accent so accent buttons still separate from the band behind them. */
  --gold:#AEB5BD; --on-accent:#F5F3EE;
  /* The ONE surviving gold: the discount codes in the top promo bar. Silver on the deep blue
     band had no urgency at all, and that strip is the only place a warm accent is wanted. */
  --promo-hi:#C9A35C;
  /* 2026-07-21 (Connor): section eyebrows read dull in navy, so the small uppercase labels get a
     little gold — the same #C9A35C as the promo bar, its restrained second home. Revisits the
     07-20 "gold only in the promo bar" note above; kept to eyebrow labels only, not headings. */
  /* ⚠️ DEEPENED 2026-08-11 (Connor). #C9A35C is the promo-bar gold, which lives on a DARK band;
     put on the cream page as 11px uppercase it measured 2.06:1 on the base paper and 1.92:1 on
     the --alt band, under this file's own 2:1 floor and well under the 3:1 the eyebrow token was
     written to clear. It went unseen because it only bites where an eyebrow lands on --alt: the
     two collection pages and à-propos, all three of which nobody had walked.
     #9D7834 is the SAME hue (39°) and the same saturation (0.50) as his gold, dropped from 57%
     lightness to 41% — a darker gold, not a new colour, and the 07-21 "give the labels a little
     gold" call still holds. Measured on the render: 3.65:1 on #F5F3EE, 3.27:1 on #EAE7E0,
     4.04:1 on white. The promo bar, the buttons and --eyebrow-on-dark keep #C9A35C untouched:
     this token is only ever used on light grounds.
     Named as its own token because the eyebrow was not the only place it bit: .integ .scar
     ("✦ Édition reliée, quantité limitée") reads --promo-hi directly and sits on the light half
     of the Intégrale banner, measuring 1.73:1 at 390 and 1.95:1 at 1440 on the HOMEPAGE, a page
     already signed off. One token, so the next gold-on-cream label cannot get this wrong. */
  --gold-on-light:#9D7834;
  --eyebrow-ink:var(--gold-on-light);
  --band:#16253B; --band-ink:#F5F3EE; --band-mute:#A9B8CE; --band-line:rgba(255,255,255,.16);
  /* #1F3B5F is sampled from the wordmark itself (logo-las-prusse.webp) rather than picked by
     eye. Fabien's brief said Prussian Blue #1C2E4A, but that is a step darker than the logo
     and every button rendered as near-black next to it (Connor 2026-07-20). */
  --accent:#1F3B5F; --accent-dk:#16293F;
  --pc-top:#16253B;
  /* Anthracite at its literal #30343A is a MID grey — as a full-width button it reads as a
     disabled control rather than a real CTA. Deepened for the button role only; the token
     stays in the anthracite family and #30343A is still the ink/band colour everywhere else. */
  --btn-2:#22262C; --btn-2-dk:#15181C;
  /* Satin silver over the hero's black gradient reads as flat grey. Lifted to near-ivory
     so the eyebrow stays legible and intentional rather than washed out. */
  --eyebrow-on-dark:#E8E9EC;
  --b-card:#FFFFFF; --b-rule-dk:#C4C0B8;
}

/* ── Fraunces (display) + Inter (text), self-hosted variable (GDPR/CNIL — no Google CDN) ──
   Replaces EB Garamond as of the 2026-06-24 redesign. latin + latin-ext cover French. */
@font-face {
  font-family: 'Fraunces'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('fonts/fraunces-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Fraunces'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('fonts/fraunces-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces'; font-style: italic; font-weight: 300 700; font-display: swap;
  src: url('fonts/fraunces-italic-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Fraunces'; font-style: italic; font-weight: 300 700; font-display: swap;
  src: url('fonts/fraunces-italic-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/inter-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/inter-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── Base typographic intent ──────────────────────────────────── */
/* 17px base (was 16, 2026-07-15): Fabien's readership skews 40-60 — every rem size
   on every store page scales up ~6% from this one line. */
html { font-size: 17px; }
body { font-family: 'Inter', system-ui, sans-serif; }

/* Display serif carries headings + the maison wordmark; small UI stays Inter for crispness. */
button, nav a, [class*="uppercase"], .font-ui {
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
}

h1, h2, h3, .font-display, .serif { font-family: 'Fraunces', Georgia, serif; }

/* ── Brand B components ───────────────────────────────────────── */
/* The collection blanche double-rule frame */
.b-frame {
  border: 1px solid var(--b-ink);
  outline: 1px solid var(--b-ink);
  outline-offset: 4px;
}
.b-frame-soft {
  border: 1px solid var(--b-rule-dk);
  outline: 1px solid var(--b-rule-dk);
  outline-offset: 3px;
}
/* Caps-and-small-caps display treatment for the maison wordmark */
.b-smallcaps { font-variant-caps: small-caps; letter-spacing: .08em; }
/* Gold hairline rule — the family stitch */
.b-hairline { height: 1px; background: var(--b-gold); opacity: .55; }
/* Collection number badge on book cards */
.b-num {
  font-family: system-ui, sans-serif; font-size: .66rem; letter-spacing: .18em;
  color: var(--b-muted); text-transform: uppercase;
}
/* Saturn ring mark (pure CSS — circle + tilted ellipse) */
.b-saturn { position: relative; width: 22px; height: 22px; display: inline-block; vertical-align: middle; }
.b-saturn::before { content: ''; position: absolute; inset: 5px; border-radius: 50%; border: 1.5px solid var(--b-accent); }
.b-saturn::after { content: ''; position: absolute; top: 9px; left: -1px; right: -1px; height: 5px; border-radius: 50%; border: 1px solid var(--b-gold); transform: rotate(-18deg); }

/* The mirror stitch — Brand A's night as a band on the paper page.
   Georgia evokes the practice's serif without loading Playfair here (font budget). */
.a-stitch {
  background: var(--night); color: var(--night-ink);
  font-family: Georgia, 'Times New Roman', serif;
}
.a-stitch .gold { color: var(--b-gold); }

/* ── Motion (restrained · reduced-motion-safe · no-JS-safe via .js-motion) — 2026-06-19 ──
   Register: "books placed on a table" — slightly slower/longer than the site. */
.js-motion [data-reveal],
.js-motion [data-reveal-stagger] > * {
  opacity: 0; transform: translateY(16px);
  transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.2,1);
}
.js-motion [data-reveal].is-in,
.js-motion [data-reveal-stagger].is-in > * { opacity: 1; transform: none; }
.js-motion [data-reveal-stagger].is-in > * { transition-delay: var(--d, 0ms); }

/* ── CTA buttons — robust labels: centre the text vertically + horizontally, balance multi-line
   wrapping, and (via flex-parent stretch) keep side-by-side pairs equal height. Matters once
   GTranslate lengthens labels (e.g. EN "The Complete Collection — 18 Books"). Added 2026-06-20.
   Targets the shared button shape (rounded-[2px]) on links/buttons only — not inputs. */
/* Auto-width buttons (most CTAs): inline-flex, centred, shrink to content. */
a[class~="rounded-[2px]"]:not([class~="block"]):not([class~="w-full"]),
button[class~="rounded-[2px]"]:not([class~="block"]):not([class~="w-full"]) {
  display: inline-flex; align-items: center; justify-content: center;
}
/* Full-width / block buttons (liens, forms): flex, centred, keep full width. */
a[class~="rounded-[2px]"][class~="block"], a[class~="rounded-[2px]"][class~="w-full"],
button[class~="rounded-[2px]"][class~="block"], button[class~="rounded-[2px]"][class~="w-full"] {
  display: flex; align-items: center; justify-content: center;
}
/* All buttons: centre + balance multi-line wrapping (robust to translated/lengthened labels). */
a[class~="rounded-[2px]"], button[class~="rounded-[2px]"] {
  text-align: center; text-wrap: balance; line-height: 1.3;
}

/* ══════════════════════════════════════════════════════════════════════════
   HOMEPAGE REDESIGN 2026-06-24 (_mock-c promoted to the live build).
   Global chrome (promo bar · Taschen nav · drawer · footer · palette pill) +
   homepage-only components. Bare-element selectors (* reset, section) are scoped
   to .las-home so they never bleed into the Tailwind-built inner pages.
   ══════════════════════════════════════════════════════════════════════════ */
body { font-family:'Inter',system-ui,sans-serif;-webkit-font-smoothing:antialiased;overflow-x:hidden;transition:background .25s,color .25s }
.serif{font-family:'Fraunces','Georgia',serif}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
.las-home *{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
.wrap{max-width:1280px;margin:0 auto;padding:0 34px}
/* Was color:var(--gold), which the active palette resolves to #AEB5BD — a light grey-blue
   that sat at roughly 2:1 on the cream ground and was hard to read (Connor 2026-07-20).
   --eyebrow-ink is a dedicated token so section eyebrows stop inheriting a decorative
   colour chosen for accents rather than for text. */
.eyebrow{font-size:.7rem;letter-spacing:.24em;text-transform:uppercase;color:var(--eyebrow-ink);font-weight:600}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-size:.76rem;letter-spacing:.07em;text-transform:uppercase;font-weight:500;padding:14px 28px;border-radius:2px;cursor:pointer;transition:background-color .2s ease,color .2s ease,border-color .2s ease,transform .2s ease;border:1px solid transparent}
/* accessibility: visible focus + anchor offset under the sticky nav (web-interface-guidelines) */
.btn:focus-visible,.nav-links a:focus-visible,.nav-ic a:focus-visible,.drawer a:focus-visible,.las-footer a:focus-visible,#pal button:focus-visible,.pcard a:focus-visible,.tc:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}
.las-home [id]{scroll-margin-top:100px}
.btn-lg{font-size:.82rem;padding:17px 38px}
.btn-sm{font-size:.68rem;padding:10px 16px}
.btn-ox{background:var(--accent);color:var(--on-accent)}.btn-ox:hover{background:var(--accent-dk)}
.btn-out{border-color:var(--ink);color:var(--ink);background:transparent}.btn-out:hover{background:var(--ink);color:var(--bg)}
/* Secondary buttons: SOLID fill, never wireframe (Connor 2026-07-22). */
/* The cream fill (--alt #EFE8D7) sat within a few percent of the section backgrounds it was
   used on (--bg #F8F4EA and the grain-light sections), so the button had no visible edge at
   all — Connor could not see it in the Fabien section or the one above. (Connor 2026-07-29.) */
/* 2026-08-07 round 1: 13% accent tint read GREY at rest and hover filled to the primary's
   solid accent — replaced by a white + accent-border ghost. Round 3, same day: the ghost fell
   too — on mobile the funnel cards read it as "weird outline buttons". Secondary is now GOLD
   (Connor's own round-1 alternative): --promo-hi fill with dark ink text — white on this gold
   is 2.37:1, the badge already proved it — and hover deepens the gold. Still a solid fill
   (2026-07-22 ruling), never the primary's navy. */
.btn-ink{background:var(--promo-hi,var(--gold));color:#26200F;border-color:transparent}
.btn-ink:hover{background:color-mix(in srgb, var(--promo-hi,var(--gold)) 86%, #000)}
.btn-light{background:#fff;color:#111}.btn-light:hover{background:#ece4d6}
.btn-out-l{border-color:rgba(255,255,255,.55);color:#fff;background:transparent}.btn-out-l:hover{background:#fff;color:#111}

/* ── logo (palette-matched colour version) ── */
.logo-img{height:60px;width:auto;display:none}
html[data-palette="oxblood"] .lg-oxblood{display:block}
html[data-palette="vert"] .lg-vert{display:block}
html[data-palette="prusse"] .lg-prusse{display:block}
html[data-palette="or"] .lg-or{display:block}
/* saturne reuses the Prussian-blue logo — its accent is the same family and no dedicated
   artwork exists yet. If the palette is adopted, ask Fabien for a proper saturne logo file. */
html[data-palette="saturne"] .lg-prusse{display:block}
/* ⛔ parchemin was MISSING from this list (added 2026-08-11, found by Fabien himself, who wrote
   in to say the Saturn logo "doesn't seem to be there yet" on the copper page). Every .logo-img
   is display:none by default and each palette turns exactly one back on, so a palette with no
   rule here does not fall back to anything — it renders a nav with NO BRAND MARK AT ALL, which
   is what he was sent. Measured on the deployed page before the fix: 0 of 4 logos visible.
   ⚠️ ANY future palette needs a line here or it ships headless. Prusse chosen off the render:
   its navy planet is the same prussian as this palette's ink and its nav links, and it is what
   saturne already uses, so the two comparison pages differ in palette and NOTHING else, which is
   the whole point of the exercise.
   ⚙️ 2026-08-12: the gold ring is no longer a gap. Fabien saw the fixed page, said the ring was
   the one thing still in the old colour before we did, and asked in writing for "the rings in
   Saturnian Copper: #B87333". So this palette now gets its OWN artwork, lg-cuivre, and prusse
   goes back to being saturne's alone. His request and his hex are the only reason a client's
   logo was touched at all. */
html[data-palette="parchemin"] .lg-cuivre{display:block}

/* ══ PROMO BAR (Taschen-style thin announcement) ══ */
.promo{background:var(--band);height:38px;display:flex;align-items:center;justify-content:center;overflow:hidden}
/* ⛔ WIDTH IS SIZED FOR THE LONGEST TRANSLATION, NOT FOR FRENCH. Measured on the live site
   31 Aug across every language the switcher offers: FR 491px fits, but EN 610, IT 650, ES 693 and
   DE 695 ALL overflowed the old 560px cap with overflow:hidden — so the ASTRO discount line, the
   site's main promo, was cut off for EVERY non-French visitor at 901px and up. The mobile half of
   this was already found and fixed on 29 Aug (it wraps below 900px); the desktop half was never
   re-checked in another language. 760px clears German with headroom. ⚠️ Adding a longer promo
   line, or another language, means re-measuring this — a French-only pass cannot prove it fits. */
.rotating-text-wrapper{position:relative;width:min(92vw,760px);height:38px;display:flex;justify-content:center;align-items:center;overflow:hidden;font-size:.7rem;font-weight:600;color:#fff;letter-spacing:1.5px;text-transform:uppercase;text-align:center}
/* Duration and per-item delay are set INLINE by build-site.mjs, derived from how many messages
   the bar actually has. Do not hardcode them here: a stale 18s/3-slot cycle against 2 messages
   is what left the bar empty for 6s a cycle. The @keyframes are emitted with the markup too. */
.rotating-text-item{position:absolute;opacity:0;white-space:nowrap;animation:promo-scroll 12s ease-in-out infinite}
/* Falls back to --gold so the oxblood/vert/prusse/or palettes are unaffected; only saturne
   overrides --promo-hi, because there --gold is satin silver and had no urgency on the band. */
.rotating-text-item b{color:var(--promo-hi,var(--gold));font-weight:700}
@keyframes promo-scroll{0%{transform:translateY(100%);opacity:0}1.2%{transform:translateY(0);opacity:1}31%{transform:translateY(0);opacity:1}33%{transform:translateY(100%);opacity:0}100%{transform:translateY(100%);opacity:0}}
@media(prefers-reduced-motion:reduce){.rotating-text-item{animation:none}.rotating-text-item:first-child{opacity:1}}

/* ══ NAV — Taschen: links left · logo centre · icons right ══ */
header.nav{position:sticky;top:0;z-index:50;background:var(--bg);border-bottom:1px solid var(--line)}
/* min-height (not fixed) + wrap-friendly links: stays aligned when Google Translate lengthens labels. */
/* The logo is centred, so both side columns are forced equal — the right one holds only the
   cart icon while the left has to fit four links. At 34px page padding + 14px link padding the
   links needed ~605px in a 571px column and "Contact" dropped to a second row. 2026-07-19. */
/* Aligned to the content rail (Connor 2026-08-09: the first nav link sat at x=22 while page
   content starts at x=114) — same 1280px + 34px gutters as .wrap, so CONSULTATIONS opens
   exactly over the page's left rail and the cart icon closes over the right one. */
.nav-in{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;min-height:78px;padding:8px 34px;column-gap:14px;max-width:1280px;margin:0 auto}
.nav-links{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;font-weight:500;line-height:1.25;white-space:nowrap}
/* links wear a quiet pill so they read as controls, not stray text (Connor review 2026-07-15) */
.nav-links a{opacity:.82;padding:9px 10px;border-radius:100px;transition:background-color .15s ease,opacity .15s ease}
.nav-links a:hover{opacity:1;background:var(--alt)}
.nav-links a.nav-soon,.nav-links a.nav-soon:hover{background:transparent;opacity:.55}
/* nav = plain text; consultation always highlighted; the rest highlight only on their own page */
.nav-links a.nav-hl,.nav-links a[aria-current="page"]{opacity:1;color:var(--accent);background:var(--alt)}
.nav-links a.nav-soon{cursor:default}
.nav-logo{justify-self:center;display:flex}
.nav-ic{justify-self:end;display:flex;align-items:center;gap:20px}
.nav-ic a{display:flex;padding:10px;margin:-10px}
/* Cart count on the nav bag (2026-08-31). A buyer who added from shop.html and closed the drawer
   previously got NO feedback that anything was in the bag. Driven by the SDK cart's afterRender
   in buy-button.js, which counts UNITS not lines. Stays [hidden] at zero so an empty bag shows
   nothing. ⚠️ The nav link needs position:relative or the badge anchors to the page. */
.nav-ic a{position:relative}
.bag-count{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;border-radius:9px;background:var(--accent);color:var(--on-accent);font:600 10px/16px Inter,system-ui,sans-serif;text-align:center;pointer-events:none;box-shadow:0 0 0 2px var(--ground)}
.skip-link{position:absolute;left:-999px;top:8px;z-index:9999;background:var(--ink);color:var(--bg);padding:8px 12px;border-radius:2px;font-family:Inter,system-ui,sans-serif;font-size:.9rem}
.skip-link:focus{left:8px}
.nav-ic svg.ic{width:21px;height:21px;cursor:pointer;opacity:.85}.nav-ic svg.ic:hover{opacity:1}
.burger{display:none;justify-self:start;background:none;border:0;cursor:pointer;color:var(--ink);padding:4px}
.burger svg{width:24px;height:24px}
.ic-mob{display:none}
/* The mobile bag LINK, not just its icon: .nav-ic a{display:flex} outranked .ic-mob{display:none}, so
   on desktop the mobile link stayed a 20x20 invisible click box beside the real bag (axe target-size,
   measured 2026-08-29). The mirror rule for the desktop link lives in the mobile block below. */
.nav-ic a.ic-mob{display:none}

/* ── Language switcher (custom; drives Google Translate engine, no third-party widget) ── */
.lang{position:relative;display:flex}
.lang-btn{display:inline-flex;align-items:center;gap:6px;background:none;border:0;cursor:pointer;color:var(--ink);padding:4px 2px;font-family:'Inter',system-ui,sans-serif;font-size:.72rem;font-weight:600;letter-spacing:.08em;opacity:.85}
.lang-btn:hover{opacity:1}
.lang-btn .ic{width:19px;height:19px}
.lang-cur{line-height:1}
.lang-chev{width:13px;height:13px;transition:transform .2s ease}
.lang.open .lang-chev{transform:rotate(180deg)}
.lang-menu{position:absolute;top:calc(100% + 12px);right:0;min-width:148px;background:var(--bg);border:1px solid var(--line);border-radius:4px;box-shadow:0 12px 34px rgba(0,0,0,.16);padding:6px;opacity:0;visibility:hidden;transform:translateY(-6px);transition:opacity .18s ease,transform .18s ease;z-index:80}
.lang.open .lang-menu{opacity:1;visibility:visible;transform:none}
.lang-menu button{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:none;border:0;cursor:pointer;color:var(--ink);font-family:'Inter',system-ui,sans-serif;font-size:.82rem;padding:9px 12px;border-radius:3px;transition:background .14s}
/* Dropdown flags only — the drawer row keeps its two-letter codes, since at that size the
   detail collapses to mud. 16x12 is exactly the 4:3 the viewBoxes assume. The border is what
   stops the white band in the French and Italian flags bleeding into the panel; box-sizing
   keeps the outer box at 16px so the row rhythm holds. Slight desaturation keeps them a
   wayfinding cue rather than decoration. */
.lang-flag{width:16px;height:12px;flex:0 0 auto;display:block;box-sizing:border-box;
  border:1px solid rgba(0,0,0,.20);border-radius:1px;filter:saturate(.85)}
.lang-menu button.on .lang-flag{border-color:rgba(255,255,255,.45)}
.lang-menu button:hover{background:var(--alt)}
.lang-menu button.on{background:var(--accent);color:var(--on-accent)}

/* drawer language row (mobile) */
.drawer-lang{margin-top:22px;border-bottom:0}
.drawer-lang-lab{display:block;font-family:'Inter',system-ui,sans-serif;font-size:.66rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--mute);margin-bottom:12px}
.drawer-lang-row{display:flex;flex-wrap:wrap;gap:8px}
.drawer-lang-row button{border:1px solid var(--line);background:transparent;cursor:pointer;color:var(--ink);font-family:'Inter',system-ui,sans-serif;font-size:.74rem;font-weight:600;letter-spacing:.06em;padding:8px 13px;border-radius:100px;transition:.15s}
.drawer-lang-row button:hover{border-color:var(--accent);color:var(--accent)}
.drawer-lang-row button.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.drawer-lang button:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}

/* ── Suppress Google Translate's injected chrome (we drive the engine ourselves) ── */
.goog-te-banner-frame,.skiptranslate iframe,#goog-gt-tt,.goog-te-balloon-frame{display:none!important}
body{top:0!important}
.goog-text-highlight{background:none!important;box-shadow:none!important}
.goog-te-gadget,.goog-logo-link{display:none!important}
#google_translate_element{display:none!important}

/* mobile drawer */
.scrim{position:fixed;inset:0;background:rgba(0,0,0,.45);opacity:0;pointer-events:none;transition:opacity .25s;z-index:60}
.scrim.open{opacity:1;pointer-events:auto}
.drawer{position:fixed;top:0;left:0;height:100%;width:78%;max-width:320px;background:var(--bg);z-index:70;transform:translateX(-100%);transition:transform .3s ease;padding:26px;border-right:1px solid var(--line)}
.drawer.open{transform:none}
.drawer .x{background:none;border:0;font-size:1.6rem;cursor:pointer;color:var(--ink);margin-bottom:24px}
.drawer a{display:block;font-family:'Fraunces',serif;font-size:1.3rem;padding:13px 0;border-bottom:1px solid var(--line)}

/* ══ HERO — full-bleed image, gradient overlay, text on top ══ */
.hero{position:relative;height:clamp(480px,72vh,680px);background:var(--band);overflow:hidden}
.hero>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 0%}
/* Ken Burns settle — one slow zoom-out on load, video feel at zero bytes (Connor, 2026-07-15) */
@media (prefers-reduced-motion: no-preference){
  /* Breathing (Connor 2026-08-28): zoom out slowly, then back in slowly, for ever, no reset. Origin at the
     top edge so the crop, when the window is short, comes off the bottom and never off Saturn's head. */
  .hero>img{transform-origin:50% 0%;animation:hero-breathe 28s ease-in-out infinite alternate}
  @keyframes hero-breathe{from{transform:scale(1.10)}to{transform:scale(1)}}
}
/* HERO ROTATION — Connor's pick 2026-07-18: Ptolémée planisphere → real covers collage →
   zodiac hemisphere, 8 s per slide, crossfade, per-slide Ken Burns. Slides sit inside .rot
   so the single-image .hero>img rules above stay intact for any other hero. */
.hero .rot{position:absolute;inset:0;overflow:hidden}
.hero .rot .slide{position:absolute;inset:0;opacity:0}
.hero .rot img.slide{width:100%;height:100%;object-fit:cover}
/* Portrait illuminations (De Sphaera plates, ~0.78 ratio) in a wide hero. `contain` was tried
   first so the whole plate showed, but it left heavy black bars either side and the H1 landed
   straight across the figure. These stay full-bleed instead, framed on the celestial roundel in
   the upper half of the plate (object-position), so what fills the hero is the zodiac medallion
   rather than the workshop scene along the bottom. Connor 2026-07-20. */
.rot img.slide.plate{object-fit:cover;object-position:50% 34%}
.hero .collage-wrap{position:absolute;inset:0;overflow:hidden;background:color-mix(in srgb, var(--band) 80%, #000)}
.hero .collage-wrap::after{content:'';position:absolute;inset:0;background:
  radial-gradient(ellipse at 50% 30%, rgba(142,47,47,.18), transparent 55%),
  radial-gradient(ellipse at 80% 80%, rgba(201,162,94,.10), transparent 50%)}
.hero .collage{position:absolute;left:50%;top:50%;width:130%;display:grid;
  grid-template-columns:repeat(6,1fr);gap:2.2vw;transform:translate(-50%,-50%) rotate(-7deg)}
/* Covers as physical books, not flat rectangles (Connor 2026-07-19). Three cheap tricks do all
   the work at hero scale: a perspective turn so the right edge recedes, a spine slab standing off
   the left edge, and binding shading across the cover itself. No new assets — same 12 covers. */
.hero .collage .bk{position:relative;display:block;transform:perspective(1200px) rotateY(15deg);
  transform-origin:0% 50%;transform-style:preserve-3d}
.hero .collage .bk:nth-child(odd){transform:perspective(1200px) rotateY(15deg) translateY(-1.6vw)}
.hero .collage img{width:100%;display:block;border-radius:1px 3px 3px 1px;
  box-shadow:0 26px 54px -18px rgba(0,0,0,.8),0 3px 10px -4px rgba(0,0,0,.6)}
/* Spine: a slab hinged off the cover's left edge and turned back into the page, so the book
   reads as having a thickness you could pull off a shelf. Neutral dark — the covers vary too
   much for a tinted spine, and at this scale the shading sells it more than the hue. */
.hero .collage .bk::after{content:'';position:absolute;top:0;bottom:0;right:100%;width:7%;
  transform:rotateY(-38deg);transform-origin:100% 50%;border-radius:2px 0 0 2px;
  background:linear-gradient(90deg,color-mix(in srgb, var(--band) 35%, #000) 0%,color-mix(in srgb, var(--band) 75%, #000) 45%,var(--band) 100%);
  box-shadow:inset -1px 0 2px rgba(0,0,0,.6)}
/* Binding shading on the cover: dark at the hinge, a thin highlight just off it, falling away
   to a soft shadow at the fore-edge. This is what stops it reading as a printed sheet. */
.hero .collage .bk::before{content:'';position:absolute;inset:0;z-index:2;pointer-events:none;
  border-radius:1px 3px 3px 1px;background:linear-gradient(90deg,
    rgba(0,0,0,.45) 0%,rgba(0,0,0,.18) 4%,rgba(255,255,255,.07) 9%,
    rgba(255,255,255,.02) 18%,transparent 34%,transparent 86%,rgba(0,0,0,.28) 100%)}
@media (max-width:700px){.hero .collage{width:210%;grid-template-columns:repeat(4,1fr)}}
@media (prefers-reduced-motion: no-preference){
  .hero .rot .slide{animation:rot-fade 32s infinite}
  .hero .rot img.slide{transform-origin:50% 42%;animation:rot-fade 32s infinite, rot-kb 32s infinite}
  .hero .rot img.slide.plate{transform-origin:50% 50%;animation:rot-fade 32s infinite, rot-kb-plate 32s infinite}
  /* These MUST out-specify (and follow) the .plate rule above. That rule uses the `animation`
     shorthand, which resets animation-delay to 0 — with the old `.hero .rot .slide.sN` selectors
     it silently stripped the offsets off slides 2 and 3, stacking three slides on the same
     timing and leaving a window where every slide was transparent and the hero went black.
     Matching img.slide.sN keeps specificity level with .plate and source order decides. */
  .hero .rot img.slide.s2{animation-delay:8s}
  .hero .rot img.slide.s3{animation-delay:16s}
  .hero .rot img.slide.s4{animation-delay:24s}
  @keyframes rot-fade{0%{opacity:0}3%{opacity:1}25%{opacity:1}28%{opacity:0}100%{opacity:0}}
  /* Ken Burns floor raised to 1.16 and the travel halved (Fabien, 2026-07-20): the engravings
     have a paper margin baked into the scan, so the old zoom-out to 1.02 drifted far enough to
     reveal the sheet edge inside the frame. Staying above 1.16 keeps the crop inside the artwork
     at every point of the cycle, and the smaller delta over the same 24s reads as a slower drift. */
  @keyframes rot-kb{0%{transform:scale(1.20)}28%{transform:scale(1.12)}100%{transform:scale(1.12)}}
  @keyframes rot-kb-plate{0%{transform:scale(1.06)}28%{transform:scale(1)}100%{transform:scale(1)}}
  @keyframes collage-pan{0%{transform:translate(-50%,-53%) rotate(-7deg) scale(1.14)}38%,100%{transform:translate(-50%,-50%) rotate(-7deg) scale(1)}}
  /* 3-slide variant (2026-08-25, Fabien's AI Saturn candidates, for review before he picks one).
     The 4-slide rot-fade keyframe is keyed to 25%/28% because 8s of 32s = 25% per slide — reused
     verbatim at a shorter duration it would hold each slide for only 25% of 24s (6s, not 8s) and
     leave a 2s gap of pure black between slides 28%→33%, since delays are 0/8/16s = 0/33/66% of a
     24s cycle. Needs its own keyframe at the correct 33%-per-slide boundary, not just a duration
     override. Higher specificity (.hero.sat3 ...) than the base rules, so the 4-slide hero is
     untouched. */
  .hero.sat3 .rot .slide{animation-duration:24s}
  .hero.sat3 .rot img.slide{animation-duration:24s;animation-name:rot-fade3,rot-kb}
  .hero.sat3 .rot img.slide.s2{animation-delay:8s}
  .hero.sat3 .rot img.slide.s3{animation-delay:16s}
  @keyframes rot-fade3{0%{opacity:0}4%{opacity:1}29%{opacity:1}33%{opacity:0}100%{opacity:0}}
  /* 2-slide variant (2026-08-25): one of Fabien's 3 AI candidates had marketing copy baked
     into the pixels themselves (a ghosted duplicate of the real HTML headline, caught on the
     hero-ai-test render, not from the docx preview) — dropped rather than shipped. 16s cycle,
     8s each, same crossfade shape as the others, just re-timed for 2 slides not 3 or 4. */
  .hero.sat2 .rot .slide{animation-duration:16s}
  .hero.sat2 .rot img.slide{animation-duration:16s;animation-name:rot-fade2,rot-kb}
  .hero.sat2 .rot img.slide.s2{animation-delay:8s}
  @keyframes rot-fade2{0%{opacity:0}6%{opacity:1}44%{opacity:1}50%{opacity:0}100%{opacity:0}}
}
@media (prefers-reduced-motion: reduce){.hero .rot .slide.s1{opacity:1}}
.hero .grad{position:absolute;inset:0;background:linear-gradient(180deg,rgba(6,5,3,.34) 0%,rgba(6,5,3,.26) 28%,rgba(6,5,3,.48) 55%,rgba(6,5,3,.70) 78%,rgba(6,5,3,.88) 100%)}
.hero .inner{position:absolute;left:0;right:0;bottom:0;text-align:center;padding:0 34px clamp(78px,14vh,160px);z-index:2;color:#fff}
/* guaranteed dark pool behind the text block, regardless of which covers sit behind */
.hero .inner::before{content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:160%;height:165%;z-index:-1;pointer-events:none;background:radial-gradient(ellipse 58% 76% at 50% 92%,rgba(6,5,3,.66),rgba(6,5,3,.34) 52%,transparent 76%)}
/* Eyebrow sized up from .76rem and h1's bottom margin opened from 28px (Connor 2026-07-22):
   the standfirst read as fine print and the CTA sat too close under the headline. */
/* max-width is generous because .24em letter-spacing makes each glyph ~1.25x a `ch`, so a 42ch
   cap wrapped this to three lines and orphaned "d'aujourd'hui". Sized to break cleanly in two. */
.hero .inner .eyebrow{color:var(--eyebrow-on-dark);text-shadow:0 1px 14px rgba(0,0,0,.6);display:block;font-size:.88rem;max-width:56ch;margin:0 auto;line-height:1.85}
.hero h1{font-size:clamp(3.1rem,6.6vw,5.6rem);font-weight:300;line-height:1.04;letter-spacing:-.02em;margin:20px auto 46px;max-width:16ch;color:#fff;text-shadow:0 2px 28px rgba(0,0,0,.55)}
.hero h1 em{font-style:italic;color:#f3dca8}

/* ── LIGHT HERO (Connor 2026-07-20) ────────────────────────────────────────────────────────
   Fabien's own backgrounds are pale cream parchment, so the dark-on-image treatment above
   inverts: white text and the black scrim would both be invisible on them. Only colour and
   scrim change here — the layout, type scale, rotation and CTA are untouched, because the
   structure was already right and this is a background swap, not a redesign.
   The scrim stays (softened, and cream rather than black) because the plates carry faint
   motifs that would otherwise run under the headline. */
.hero.hero-light .grad{background:linear-gradient(180deg,
  rgba(245,243,238,.10) 0%,rgba(245,243,238,.28) 42%,rgba(245,243,238,.62) 74%,rgba(245,243,238,.86) 100%)}

/* ── CELESTIAL HERO (Connor 2026-07-22) ────────────────────────────────────────────────────
   Replaces the slide rotation. The bodies are SVG on three depth layers; each layer drifts at
   its own speed under one constant slow zoom, so the field has parallax instead of a single
   flat plane sliding about. Zoom and drift are on SEPARATE nested groups on purpose — both
   animate `transform`, so sharing one element would make the later rule win and kill the other.
   All GPU-composited transforms: no layout, no repaint, no scroll JS. */
.hero-cel{background:var(--bg)}
.hero-cel .sky{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;
  /* multiply so the ink sits IN the cream rather than as a cut-out layer on top of it;
     opacity washes the whole field back a step further — matte, imprinted, never a sticker
     (Connor 2026-07-25, against his concept mock). overflow clips the zoom scale. */
  mix-blend-mode:multiply;opacity:.8;overflow:hidden}
/* the three depth layers — stacked svgs, one per drift speed (see celField in build-site.mjs) */
.hero-cel .sky>svg{position:absolute;inset:0;width:100%;height:100%}
/* Landscape field on desktop, portrait field on phones. Two compositions rather than one
   rescaled: slice crops the long axis, so the landscape field on a portrait screen showed only
   its empty middle and the mobile hero rendered bare. */
.hero-cel .sky-m{display:none}
@media (max-width:760px){
  .hero-cel .sky-d{display:none}
  .hero-cel .sky-m{display:block}
}

/* ── SECTION PANEL BAND (Connor 2026-07-22) ───────────────────────────────────────────────
   "Nos collections" was a flat --alt block and read as basic. This lays one of Fabien's own
   cream panels behind the section at low opacity, faded to nothing top and bottom so it
   dissolves into the band instead of ending on a hard rectangle edge — the seam he spotted.
   It sits OVER the existing --alt tint rather than replacing it, because this section and the
   intégrale below deliberately share one continuous background; swapping the colour here would
   have split them. Decoration only, so it is inert to pointers and hidden from AT. */
.sec-panel{position:relative;isolation:isolate}
.sec-panel::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  /* constellation panel, not the Saturn one — the hero already has a Saturn, and Connor
     2026-07-25: "don't have too many Saturns, don't make it repeat too much" */
  background:url("/images/hero-cream-constellation.webp") center/cover no-repeat;
  opacity:.5;mix-blend-mode:multiply;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 18%,#000 82%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 18%,#000 82%,transparent 100%);
}
.sec-panel > *{position:relative;z-index:1}
/* Round 4 (Connor 2026-07-27): the sky is STATIC everywhere — this panel's 44s drift was the
   last moving celestial element on the homepage and went with the hero zoom, twinkle and float.
   Keyframes kept unused for now; deleting them is not this round's job. */
@keyframes cel-panel{from{transform:scale(1.04)}to{transform:scale(1.13)}}

/* ── CELESTIAL GUTTER ACCENTS (Connor 2026-07-25, from his concept mock) ──────────────────
   Small matte bodies in the empty section margins, site-wide — see celDeco() in build-site.mjs.
   Multiply sinks them into the cream; .on-dark flips to screen for the navy bands. Hidden under
   1360px: .wrap is 1280px, so below that the gutters vanish and anything left there lands on
   content (offsets are px-from-edge for the same reason — % offsets drift onto cards). */
.cel-deco{position:absolute;pointer-events:none;z-index:0;mix-blend-mode:multiply;opacity:.85}
.cel-deco svg{display:block}
/* ── Living-background pass (Connor OK'd 2026-07-25, from the reference research) ─────────
   1. Twinkle: each sparkle pulses opacity around its OWN resting value (--two), on its own
      duration/phase (--twd/--twdel, baked per-star at build time) — candlelight, not neon.
      NB opacity animation on inner SVG paths DOES repaint in Chrome; transforms don't
      (that was the frozen-hero bug). Keep this rule animating opacity only.
   2. Float: each .cel-deco span bobs on its own duration/phase (--fld/--fldel). Spans are
      real CSS boxes, so transform animation composites fine. .cd-still (arcs, constellation)
      stays anchored — a drifting orbit line looks unmoored.
   3. Constellation self-draw: the About constellation carries data-reveal, so motion.js
      adds .is-in when scrolled into view and the line draws via stroke-dashoffset.
      dasharray 420 > real line length → no-JS renders it as a plain solid line. */
/* Round 4 (Connor 2026-07-27): the site is fully STATIC — twinkle + float retired.
   The design carries the sky; nothing drifts, nothing pulses. Keyframes kept below only
   because deleting them is not this round's job. */
@keyframes cel-tw{0%,100%{opacity:var(--two,.8)}50%{opacity:calc(var(--two,.8)*.3)}}
@keyframes cel-float{from{transform:translateY(0) rotate(0deg)}to{transform:translateY(-9px) rotate(1.2deg)}}
.js-motion .cel-deco[data-reveal] polyline{stroke-dashoffset:420;transition:stroke-dashoffset 1.9s ease-out .35s}
.js-motion .cel-deco[data-reveal].is-in{opacity:.85} /* generic .is-in rule would lift it to 1 */
.js-motion .cel-deco[data-reveal].is-in polyline{stroke-dashoffset:0}
.cel-deco.on-dark{mix-blend-mode:screen;opacity:.55}
/* the big tone-on-tone watermark planet on the association band — white-at-low-alpha fills,
   so normal blend at full opacity IS the watermark; screen would turn it into a glow */
.cel-deco.cel-assoc{mix-blend-mode:normal;opacity:1}
/* clip the watermark planet's edge-bleed inside the band, like the mock crops its planet */
.las-home .assoc{overflow:hidden}
/* Round 4: raised 1359 → 1439. At 1360 the gutters are only 40px, so even the sparks landed on
   cards; the big pieces already hide below 1440, so the whole decoration layer now switches off
   at one breakpoint instead of two. */
@media (max-width:1439px){.cel-deco{display:none}}

/* ── RASTER ART PIECES (Connor 2026-07-27, round 4) ───────────────────────────────────────
   The flat SVG bodies are replaced by slices of the actual hand-drawn panels
   (store/make-cel-assets.mjs → images/cel/). ALL pieces carry BAKED alpha and render with
   normal blend — never mix-blend-mode: `.las-home > section` is a z-index:1 stacking
   context with a TRANSPARENT background (body paints the cream), so a blend inside a
   section composites against nothing and a white-bg piece ships its raw white box.
   Width comes via --cw so the 1440–1679 tier can shrink big pieces without fighting the
   inline style (--cw-sm); the piece keeps its aspect from the img's width/height attrs. */
.cel-img{width:var(--cw);mix-blend-mode:normal;animation:none} /* static: motion is HERO-ONLY (Connor checkpoint call) */
.cel-img img{display:block;width:100%;height:auto}
.cel-img.cel-ghost{opacity:.5}   /* intégrale ghost planet (.35 was "really faint" — Connor) */
.cel-assoc.cel-comet{opacity:.8}
.cel-flip img{transform:scaleX(-1)}  /* mirror a piece so its sweep can sit on the other page edge */
/* Hero = Fabien's orbit-saturn panel, full-bleed and static (Connor 2026-07-27).
   object-position keeps the big saturn (right side of the panel) in frame on phones. */
.hero-art{position:absolute;inset:0;overflow:hidden}
/* 80%: bias the crop toward the panel's saturn (right side) without losing the
   constellation left. NEVER position:relative on .hero .inner — it is absolute
   bottom-anchored, and flattening it paints its radial scrim's bottom edge as a
   hard seam across the hero (caught 2026-07-27). */
/* scale gives the cover-fit some vertical slack so translateY can drop the saturn a touch
   lower in frame (Connor 2026-07-27: "move it down a touch") — without the scale, the panel's
   3.28 aspect leaves no vertical crop room and translateY would expose the panel edge. */
.hero-art img{width:100%;height:100%;object-fit:cover;object-position:80% center;transform:scale(1.09) translate(-2.4%,3.5%)}
/* ^ translateX pulls the saturn back fully into frame — scale alone pushed its ring off the
   right edge (verified on a render, not reasoned about). */
@media (max-width:760px){.hero-art img{object-position:74% center}}
/* PLATE HERO (Connor 2026-07-28) — Cellarius's Planisphaerium Ptolemaicum, full-bleed and
   static, restored from a screenshot of the pre-2026-07-22 hero. The plate is 1.19:1 inside a
   ~2.4:1 letterbox, so cover keeps the middle band, which is the golden planetary circle: the
   subject survives the crop at every width, which is why THIS plate works full-bleed where the
   portrait De Sphaera figures did not. transform:none — the scale/translate above exists only to
   nudge the saturn in the cream panel. */
.hero-plate .hero-art img{transform:none;object-position:center 50%}
/* Fabien's Saturn hero (2026-08-28): keep his head + the arch's lettering in frame on every
   crop, and push the bottom third dark enough that the headline reads over the books. */
.hero-fabien .hero-art img{object-position:center 0%;transform-origin:50% 0%;transform:none}
@media (prefers-reduced-motion: no-preference){
  /* Breathing (Connor 2026-08-28): slow zoom out, slow zoom back in, for ever, no reset; anchored to the top so a
     short window crops the bottom of the picture and never Saturn's head. Same on the AI test page's slides. */
  .hero-fabien .hero-art img{animation:hero-breathe 28s ease-in-out infinite alternate}
  .hero.sat2 .rot img.slide,.hero.sat3 .rot img.slide{object-position:50% 0%;transform-origin:50% 0%;animation-name:rot-fade2,hero-breathe;animation-duration:16s,28s;animation-iteration-count:infinite,infinite;animation-direction:normal,alternate;animation-timing-function:ease-in-out,ease-in-out}
}
.hero-fabien .grad{background:linear-gradient(180deg,rgba(6,5,3,.28) 0%,rgba(6,5,3,.14) 28%,rgba(6,5,3,.42) 52%,rgba(6,5,3,.80) 76%,rgba(6,5,3,.95) 100%)}
.hero-fabien .inner::before{background:radial-gradient(ellipse 62% 80% at 50% 94%,rgba(6,5,3,.86),rgba(6,5,3,.55) 50%,transparent 78%)}
@media (max-width:760px){.hero-plate .hero-art img{object-position:center 46%}}
/* Size tiers against the 1280px content rail (Connor's red-line rule: bodies NEVER cross
   into the content column). ≥1680 gutters are ≥200px → full size; 1440–1679 big pieces
   shrink to --cw-sm (half-cropping at the page edge is the mock's own mechanism); below
   1440 the gutter maths stops working for md/lg so they hide; sparks keep the 1359 rule. */
/* ⚠️ 1440-1919 is ONE band in this rule and the gutter is NOT one band across it: 80px at 1440,
   200px at 1680. A --cw-sm chosen to look right at 1680 lands ON the content at 1440 — that is
   how the homepage's own crescent came to overlap the Astro-Mug panel by 42px at 1440 while
   measuring clean at 1680, 1920 and 2560 (found 2026-08-31, auditing widths the old single-page
   rail-audit never ran). The fix is NOT a third size tier: the four pieces that were tight are
   anchored to the rail now (.cel-l/.cel-r above), which holds one clearance at every width and
   crops them off the page edge instead of shrinking them. This rule is unchanged. */
/* ⛔ 2026-09-11 (Connor, approved in chat): the --cw-sm shrink tier is RETIRED. It is what made the
   homepage's two edge-cropped constellations (right:-150px / left:-150px, the only .cel-lg pieces)
   show 19-26 % of themselves from 1440 to 1919, a stub. They now HIDE from 1440 to 1679 (the gutter
   is 80-200px there, and at full size they reach the Intégrale text) and render at their one
   full size from 1680, which is exactly their 1920 composition (46-50 % visible, Connor's own
   half-crop). Nothing about where they sit changed; only the band they show in. */
/* 2026-09-15: the 1440-1679 hide for .cel-lg is replaced by the SCALE BAND below. */
@media (max-width:1439px){.cel-lg,.cel-md{display:none}}
/* .cel-far = a spark placed deeper than the 1440 gutter (80px). Those only have room once the
   gutters hit 200px, so they hide below 1680 — otherwise they land on a card, which is the one
   thing Connor's red-line annotation says must never happen. Verified by rail-audit.mjs, which
   measures real text rects and card boxes rather than container boxes. */
@media (max-width:1439px){.cel-far{display:none}}
/* ── 1440-1919 SCALE (Connor 2026-09-15, in chat, looking at 1440 on his MacBook: "I would like the elements
   to still be visible on 1440 ... scaling them down in comparison of the screen size so that there is still
   the same margin of spacing ... when there's just a star it doesn't have anywhere near as good an effect";
   of 1920 and up: "the positioning of everything is great". Round 2, same day, after seeing the first
   version: "a little bit too small ... I don't think they've been scaled down relatively to the screen size
   ... does it just change all of a sudden or is it like a scale down").
   ⚠️ Round 1 (be0a380d) sized bodies to the free gutter only: 25-40 % of their 1920 width at 1440 against a
   screen 75 % as wide, and it JUMPED at 1680 (a constellation went 213px → 318px across one pixel of window)
   because 1680-1919 still ran the 11 Sept rules. This block replaces both.
   The gutter is (100vw − 1280px) / 2: 80px at 1440, 200 at 1680, 320 at 1920.
   BODIES on the 1280px rail (.cel-l/.cel-r, and the homepage's two edge hung .cel-lg constellations), from
   1440 to 1919, one continuous rule that equals the 1920 layout at 1920:
   - width = the screen's share of the 1920 width (100vw × --wn: 75 % at 1440), never wider than at 1920;
   - it shows the SAME share of itself as at 1920 (--v), so what sits at the page edge at 1920 is still there;
   - clearance to text = the 1920 clearance scaled by the gutter, or 16px to the painted corner, whichever is
     more. The width gives way, never the share. ⚠️ Round 1 (44px floor) was "a little bit too small"; round 2
     (f050f70d) cropped to 75 % of the 1920 share to gain size and Connor saw the planets cut off. Round 3 keeps
     round 1's look and buys the size from the clearance instead (size gains at 1440 vary by piece);
   - --pk moves a rotated body out by the reach of its corners, so the clearance is measured to what paints (16px minimum).
   Nothing hides. Pages with their own narrower column (--rh on an ancestor: legal, 404, contact, rétractation)
   already have wide gutters and keep the rail rules below. .cel-far sparks (22-30px, 104-158px from the page
   edge) keep their size and move outward with the gutter from 1440 to 1679, never closer than 12px to the rail. */
@media (min-width:1440px) and (max-width:1679px){
  .cel-far.cel-el{left:min(calc((100vw - 1280px) * var(--ok)),calc((100vw - 1280px) / 2 - var(--cw) - 12px)) !important}
  .cel-far.cel-er{right:min(calc((100vw - 1280px) * var(--ok)),calc((100vw - 1280px) / 2 - var(--cw) - 12px)) !important}
}
@media (min-width:1440px) and (max-width:1919px){
  .cel-img.cel-l:not([style*="--rh"] *),.cel-img.cel-r:not([style*="--rh"] *),.cel-lg.cel-el,.cel-lg.cel-er{
    --gs:calc((100vw - 1280px) * var(--tk));
    --bw:min(var(--cw),calc(100vw * var(--wn)),calc(((100vw - 1280px) / 2 + 34px - var(--gs)) / var(--v)),calc(((100vw - 1280px) / 2 + 18px) / (var(--v) + var(--pk))));
    width:var(--bw) !important}
  .cel-img.cel-l:not([style*="--rh"] *),.cel-lg.cel-el{right:calc(50% + 640px + max(calc(var(--gs) - 34px),calc(var(--bw) * var(--pk) - 18px))) !important;left:auto !important}
  .cel-img.cel-r:not([style*="--rh"] *),.cel-lg.cel-er{left:calc(50% + 640px + max(calc(var(--gs) - 34px),calc(var(--bw) * var(--pk) - 18px))) !important;right:auto !important}
}
/* sections whose art deliberately bleeds off the page edge — clips the overhang so it can't
   widen the document (a negative right offset otherwise adds horizontal scroll) */
.las-home .cel-clip{overflow:hidden}

/* ── PAGE-LEVEL DECORATION LAYER (2026-08-31) ─────────────────────────────────────────────
   The inner templates are not built on the .las-home section system, and three of them opened
   <main> as the CONTENT COLUMN ITSELF (shop.html was class="wrap grain-page", the legal pages
   max-w-3xl, 404 max-w-2xl). An absolutely-positioned piece inside one of those is offset from
   the 1280/768/672px column, not from the page — which is why every decoration on the shop page
   was sitting UNDER a product card: measured 2026-08-31, six of its eight pieces at ZERO
   clearance at 1440, 1680 and 1920, on a page nobody had ever audited because rail-audit.mjs
   only ever loaded /index.html. Those mains are full width now with the column nested inside,
   and the pieces live in this layer: the full width of the main, the full height of the page,
   and CLIPPED, so a body may hang off the page edge without adding horizontal scroll.
   (.las-home sections already are position:relative + overflow:hidden, so the homepage, About,
   Contact and Retractation keep their pieces inside the section and need no layer.) */
.cel-layer{position:absolute;inset:0;pointer-events:none;z-index:0;overflow:hidden;overflow:clip}

/* ── RAIL-ANCHORED BODIES (2026-08-31) ────────────────────────────────────────────────────
   `left:30px` holds a piece 30px from the PAGE edge while the gutter shrinks from 320px at 1920
   to 80px at 1440 underneath it. That is how the product page's crescent came to sit 5px from
   the cover at 1440 while measuring a comfortable 200px at 1920 — Connor's "one moon that's
   really close". The content rail is 1280px wide at EVERY viewport, so anchoring to the RAIL
   instead gives one constant clearance and lets the piece crop off the page edge as the window
   narrows — which is his own "half-cropped off the page edges" move, not a compromise.
   --cg is the gap to the rail box; true clearance to text is --cg plus the .wrap's own 34px of
   padding. A body placed this way needs NO .cel-lg / --cw-sm shrink tier: one size, every width.
   Works inside any centred container (full-width main, .wrap, max-w-3xl, max-w-2xl) because 50%
   of a centred box always resolves to the page centre.
   --rh is HALF the content column this page actually uses: 640px for the 1280px rail (home,
   shop, product, collection), 384px for the 768px legal column, 336px for the 672px 404 column,
   320px for the 640px contact/retractation column. Set it once on the .cel-layer (or the
   section) and every piece inside hangs off that column's edge. Getting it wrong does not break
   the page, it just parks the art further out than it needs to be. */
.cel-l{right:calc(50% + var(--rh,640px) + var(--cg,24px));left:auto}
.cel-r{left:calc(50% + var(--rh,640px) + var(--cg,24px));right:auto}

/* ── THE 1440-1919 BAND FOR RAIL-ANCHORED BODIES (Connor 2026-09-11, approved in chat) ─────
   The rail anchor holds one clearance at every width, so as the window narrows the gutter shrinks
   out from under a 300-380px body and it paints 11-19 % of itself at 1440 and 17-33 % at 1536: a
   curved stub cut dead at the page edge, which is what Connor called "lines cut off" on 2 Sept
   (DECO-PREVIEW-REVIEW-2026-09-11.md, F1). Three rules, and NONE of them moves a piece: the edge
   that faces the content column stays exactly where --cg puts it; only visibility and size change.
   1. 1440-1535 on the 1280px rail: hide the bodies. An 80-128px gutter cannot hold a body that is
      both clear of the content and readable, so the sparks carry the page there. Pages with their
      own narrow column (--rh on the layer: legal 384, 404 336) have a wide gutter and keep theirs.
   2. 1440-1679: a body is sized to the free gutter so at least 70 % of it shows (--kv:.7), mostly
      whole rather than a stub. min() means a body the gutter already holds keeps its full --cw.
   3. 1680-1919: the same, at 50 %, which only ever touches a body that was showing less than half
      of itself (the homepage orbit-saturn, 37 % at 1680). At 1920 and up nothing here applies, so
      Connor's placements there are byte-for-byte what they were.
   A body deeper than the 1536 gutter can hold (--cg >= ~90, the homepage's two crescents) carries
   .cel-far instead, or rule 2 would size it to nothing. Gated: deco-audit.mjs fails any displayed
   body under 40 % visible, run at 1440, 1536 and 1920 by gates.sh. */
/* 2026-09-15: rule 1's 1440-1535 hide is gone. On the 1280px rail, 1440-1919 is the 1440-1919 SCALE block above
   (every body shown, one continuous scale to the 1920 layout); rules 2 and 3 now govern only --rh pages. */
@media (min-width:1440px) and (max-width:1679px){.cel-l,.cel-r{--kv:.7}}
@media (min-width:1680px) and (max-width:1919px){.cel-l,.cel-r{--kv:.5}}
@media (min-width:1440px) and (max-width:1919px){
  .cel-img.cel-l,.cel-img.cel-r{width:min(var(--cw),calc((50% - var(--rh,640px) - var(--cg,24px)) / var(--kv)))}
}

/* ── PAPER GRAIN + FOOTER STARFIELD (Connor 2026-07-27: "matte/paperish feel… replicated
   across the site"; "the little white specs… 100% add this in our footer") ──────────────
   Tiles carry BAKED alpha (flecks extracted from the panels' own empty paper), so no blend
   modes: plain repeat at low opacity. Per-section ::after — a fixed body-level layer would
   need a z-index above content and repaints on scroll. Content is lifted by the .wrap rule
   below; decoration spans stay at z 0 beside the grain, which is fine — they never overlap
   content by the rail rule. */
.grain-l::after,.grain-d::after{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;background:url("/images/cel/grain-cream.webp") repeat;
  background-size:512px 512px;opacity:.5}
.grain-d::after{background-image:url("/images/cel/grain-navy.webp");
  background-size:384px 384px;opacity:.55} /* .4 → .55: Connor checkpoint, "more paper" */
.grain-l>.wrap,.grain-d>.wrap{position:relative;z-index:1}
/* Page-level paper for the inner pages (Connor's annotation: the matte feel belongs on "the
   crème pages / rest of the site too", not just the homepage). Those templates are not built
   on the .las-home section system, so the per-section ::after above has nothing positioned to
   attach to. This variant makes its own stacking context and paints the tile BEHIND everything
   in the page (z-index:-1) — no .wrap lifting needed, and it cannot land on top of text.
   A section with its own background (.alt, .assoc) still covers it; those carry grain-l/grain-d. */
.grain-page{position:relative;z-index:0}
.grain-page::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:url("/images/cel/grain-cream.webp") repeat;background-size:512px 512px;opacity:.5}
.ytband.grain-d{position:relative;overflow:hidden}
footer.las-footer{position:relative;overflow:hidden}
.las-footer.f-stars::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:url("/images/cel/specks-tile.webp") repeat;background-size:2025px auto;
  opacity:.14; /* dialled down THREE times (Connor: "still far too many dots"); slicer bias 32 + blob filter keep only a sparse handful of true stars */
  /* Masked off the brand column (Connor 2026-08-09: a fleck landed between the social icons
     and read as a stray dot) — specks fade in from ~40% across, clear of logo/icons/lettre. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0 34%,#000 48%);
  mask-image:linear-gradient(90deg,transparent 0 34%,#000 48%)}
.las-footer.f-stars .wrap{position:relative;z-index:1}
@media (prefers-reduced-motion: no-preference){
  /* Durations came down from 58–92s (Connor 2026-07-25: "none of them actually move") — at
     those speeds the drift was ~0.3px/s, invisible unless you stared for a minute. These are
     still slow-cloud slow, but you can SEE them within a couple of seconds of looking. */
  .hero-cel .sky{animation:cel-zoom 26s ease-in-out infinite alternate}
  .hero-cel .cel-l1{animation:cel-d1 34s ease-in-out infinite alternate}
  .hero-cel .cel-l2{animation:cel-d2 24s ease-in-out infinite alternate}
  .hero-cel .cel-l3{animation:cel-d3 18s ease-in-out infinite alternate}
}
@keyframes cel-zoom{from{transform:scale(1)}to{transform:scale(1.12)}}
@keyframes cel-d1{from{transform:translate(0,0)}to{transform:translate(-16px,9px)}}
@keyframes cel-d2{from{transform:translate(0,0)}to{transform:translate(20px,-12px)}}
@keyframes cel-d3{from{transform:translate(0,0)}to{transform:translate(-24px,14px)}}
.hero.hero-light .inner{color:var(--ink)}
/* The radial pool exists to guarantee contrast behind the text whatever sits behind it.
   Same job, inverted: a soft cream wash instead of a black one. */
.hero.hero-light .inner::before{background:radial-gradient(ellipse 58% 76% at 50% 92%,
  rgba(245,243,238,.82),rgba(245,243,238,.45) 54%,transparent 78%)}
.hero.hero-light .inner .eyebrow{color:var(--accent);text-shadow:none}
.hero.hero-light h1{color:var(--ink);text-shadow:none}
.hero.hero-light h1 em{color:var(--accent)}

/* ══ SECTION SHELL ══ */
.las-home section{padding:84px 0;position:relative;overflow:hidden}
.las-home section.alt{background:var(--alt)}
/* Where two sections share a background there is no colour change to mark the boundary, so their
   stacked 84+84 padding reads as a 168px void instead of a section break — the "weird spacing"
   between Nos collections/L'Intégrale and between Les objets/le thème astral (Connor 2026-07-19).
   Collapsing the second section's top padding leaves one 84px rhythm unit. Deliberately targeted
   at these two joins rather than a generic adjacent-sibling rule, which would also strip the top
   padding off the first section after the hero. */
.las-home section.alt + .integ{padding-top:0}
.las-home #objets + section{padding-top:0}
/* 2026-08-07 (Connor): the free-chart card floated ~140px below the mug tiles — 84px section
   gap + the card's own 54px top pad read as dead space. Objets' bottom pad carries the whole
   join (the next section's top pad is already 0 above), so it alone shrinks. */
.las-home #objets{padding-bottom:44px}

/* ── SHOP FILTER TABS (Connor 2026-07-22) ─────────────────────────────────────────────────
   Real show/hide filter, not anchor-scroll. "Tout" is selected on load. */
.shop-filter{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:2.6rem}
.shop-filter-btn{font-family:'Inter',system-ui,sans-serif;font-size:.72rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;padding:9px 18px;border-radius:100px;border:1px solid var(--line);background:transparent;color:var(--mute);cursor:pointer;transition:background-color .15s ease,color .15s ease,border-color .15s ease}
.shop-filter-btn:hover{border-color:var(--accent);color:var(--accent)}
.shop-filter-btn.is-on{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
[data-shop-cat][hidden]{display:none}

/* ── COLLECTION PAGE HEADER (package presentation, Connor 2026-07-22) ── */
.coll-hero{background:var(--alt);padding:2.2rem 0 3rem;position:relative;overflow:hidden}
.coll-crumb{font-size:0.68rem;letter-spacing:0.04em;color:var(--mute);opacity:.7;margin-bottom:2rem}
.coll-crumb a{color:inherit}
.coll-hero-in{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:center}
/* Round 10 (Connor): the 5-cover fan is retired — the hero shows ALL the collection's books as
   the paperback objects, wrapping onto a second row when a path holds 8-9 titles. */
.coll-fan{display:flex;justify-content:center;padding:10px 0}
.coll-fan.coll-all{flex-wrap:wrap;gap:22px 26px;align-items:flex-end;justify-content:flex-start}
.coll-fan.coll-all .bk{width:clamp(88px,7.6vw,118px)}
/* ── Bookcase (Connor 2026-08-27): books standing on wooden shelves behind a glass front. Used
   for the Intégrale (6 x 3) and every collection hero (3 / 5 / 4+4). Rows are cut in
   build-site.mjs (bookcase()), one .shelf per row, the plank is the shelf's ::after so it
   always sits under exactly that row. Wood is pure CSS: a warm gradient with a faint vertical
   grain; the glass is the case's ::after, a diagonal sheen + hairline edge above the books. */
.bookcase{--wood:#5b3a22;--wood-hi:#8c5e39;--wood-lo:#3a2314;position:relative;padding:16px 16px 6px;border-radius:5px;
  background:linear-gradient(180deg,rgba(255,255,255,.04),rgba(0,0,0,.2)),
    repeating-linear-gradient(90deg,rgba(255,255,255,.028) 0 2px,rgba(0,0,0,0) 2px 7px),
    linear-gradient(180deg,#2b1b11,#1d120b);
  border:10px solid var(--wood);border-image:linear-gradient(160deg,var(--wood-hi),var(--wood) 45%,var(--wood-lo)) 1;
  box-shadow:inset 0 0 44px rgba(0,0,0,.6),0 34px 60px -30px rgba(0,0,0,.6)}
.bookcase .shelf{display:grid;grid-template-columns:repeat(var(--per,5),1fr);gap:0 clamp(8px,1.2vw,16px);align-items:end;padding:22px 8px 0}
.bookcase .shelf:first-child{padding-top:8px}
.bookcase .shelf::after{content:"";grid-column:1/-1;height:13px;background:linear-gradient(180deg,var(--wood-hi) 0,var(--wood) 55%,var(--wood-lo));box-shadow:0 10px 14px -4px rgba(0,0,0,.65);border-radius:1px}
.bookcase .shelf .bk{display:block;width:100%;aspect-ratio:8/11;margin:0;box-shadow:6px 8px 16px -8px rgba(0,0,0,.85)}
.bookcase .shelf .bk img{width:100%;height:100%;object-fit:cover}
.bookcase .shelf .bk::after{z-index:3}
.bookcase.glass::after{content:"";position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:2px;
  background:
    linear-gradient(118deg,rgba(255,255,255,0) 18%,rgba(255,255,255,.34) 26%,rgba(255,255,255,.10) 33%,rgba(255,255,255,0) 38%,rgba(255,255,255,0) 54%,rgba(255,255,255,.16) 58%,rgba(255,255,255,0) 62%),
    linear-gradient(180deg,rgba(255,255,255,.14) 0,rgba(255,255,255,0) 18%,rgba(0,0,0,0) 82%,rgba(0,0,0,.18) 100%),
    linear-gradient(180deg,rgba(170,195,230,.10),rgba(170,195,230,.04));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55),inset 0 0 0 1px rgba(255,255,255,.28),inset 0 0 40px rgba(255,255,255,.06),inset 0 -24px 40px -30px rgba(0,0,0,.5)}
.bookcase a.bk:hover{transform:translateY(-4px);transition:transform .3s}
.bookgrid{position:relative;padding:6px 2px}
.bookgrid .shelf{display:grid;grid-template-columns:repeat(var(--per,5),1fr);gap:0 clamp(14px,1.6vw,24px);align-items:end;padding:0 4px 26px}
.bookgrid .shelf:last-child{padding-bottom:6px}
.bookgrid .shelf .bk{display:block;width:100%;aspect-ratio:8/11;margin:0}
.bookgrid .shelf .bk img{width:100%;height:100%;object-fit:cover}
@media (max-width:760px){
  .bookgrid .shelf{grid-template-columns:repeat(3,1fr);gap:16px 12px;padding:0 0 16px}
  .bookcase{padding:6px 8px 4px;border-width:7px}
  .bookcase .shelf{grid-template-columns:repeat(3,1fr);gap:14px 10px;padding:12px 6px 6px}
  .bookcase .shelf::after{display:none}
}
/* ── Round 3 (Connor 2026-08-28) ── */
/* Intégrale media column: the 18 covers tight on one card, as product images (no link, no hover). */
.integ-plate{position:relative;background:var(--card);border:1px solid var(--line);outline:1px solid var(--line);outline-offset:-8px;border-radius:4px;padding:32px 30px 24px;box-shadow:0 30px 60px -30px rgba(0,0,0,.3)}
.integ-plate .cap{text-align:center;font-family:'Inter',sans-serif;font-weight:600;font-size:.62rem;letter-spacing:.24em;text-transform:uppercase;color:var(--mute);margin-bottom:22px}
.integ-plate .row{display:grid;grid-template-columns:repeat(3,1fr);gap:0 14px;padding-bottom:22px;position:relative}
/* Realistic shadows (Connor 2026-08-28): each book casts its own. A tight dark contact shadow at
   the base, a softer ambient one below and to the right (the fore-edge side), plus a faint floor
   pool under the row. */
.integ-plate .row::after{content:"";position:absolute;left:6%;right:6%;bottom:6px;height:12px;border-radius:50%;background:radial-gradient(ellipse at center,rgba(40,30,15,.16),transparent 72%)}
.integ-plate .bk{display:block;aspect-ratio:8/11;margin:0;box-shadow:0 2px 3px rgba(30,20,10,.38),0 10px 16px -6px rgba(30,20,10,.42),8px 16px 30px -12px rgba(30,20,10,.38)}
/* Desktop only: on phones the generic mobile rules below must win (these two-class selectors
   out-ranked them and left 17px covers + a sideways scroll at 390, caught on the render). */
/* 6 across x 3 down, and the plate stretches to the height of the copy column so the three rows
   distribute down it instead of leaving a block of white space beside the FAQ (Connor 2026-08-28).
   align-items:stretch on the grid is what lets height:100% mean anything here. */
@media (min-width:901px){
  .pdp-grid.pdp-bundle{align-items:stretch}
  .integ-plate{height:100%;display:flex;flex-direction:column;justify-content:space-between}
  .integ-plate .row{padding-bottom:0}
}
.integ-plate .bk img{width:100%;height:100%;object-fit:cover}
/* Banner price line (Connor 2026-08-28: "a little bit of padding between the prices ... looks weird
   with the hierarchy"). Was a run-on sentence with a stray space before the comma. */
.ib-line{display:inline-flex;align-items:baseline;flex-wrap:wrap;gap:0 14px}
.ib-line .ib-sep{opacity:.45}
.ib-line .ib-now{font-size:1.15em}
.ib-line .ib-was{text-decoration:line-through;opacity:.7;font-size:.92em;margin-left:-6px}
.integ-plate.coll-plate{height:auto;justify-content:center;padding:34px 30px 30px}
.integ-plate.coll-plate .row{padding-bottom:12px}
.integ-plate .cap2{text-align:center;font-family:'Fraunces',serif;font-style:italic;font-size:.86rem;color:var(--mute);margin-top:2px}
@media (max-width:760px){.integ-plate{padding:18px 14px 14px}.integ-plate .row,.integ-plate.tall .row{grid-template-columns:repeat(3,1fr);gap:0 10px;padding:0 4px 22px}}
/* Price + free shipping on one baseline. */
.pdp-price{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin-bottom:1.6rem}
.pdp-price .font-display{font-size:1.6rem;font-weight:600;color:var(--accent)}
.pdp-ship{font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;color:var(--mute)}
/* Collection hero H2: centred copy, one row of books, one meta line. */
.coll-hero-c{text-align:center;max-width:64ch;margin:0 auto}
.coll-hero-c .eyebrow{font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);font-weight:600}
.coll-hero-c h1{font-family:'Fraunces',serif;font-size:clamp(2rem,4vw,3rem);font-weight:400;line-height:1.1;margin:12px 0 14px}
.coll-hero-c p{color:var(--mute);line-height:1.75;margin:0 auto 6px;max-width:56ch}
.coll-row{display:flex;flex-wrap:wrap;justify-content:center;gap:26px;margin:36px auto 34px;max-width:1000px}
.coll-row .bk{display:block;width:clamp(96px,10vw,150px);aspect-ratio:8/11}
.coll-row .bk img{width:100%;height:100%;object-fit:cover}
.coll-hero-c .coll-meta{justify-content:center;align-items:baseline;gap:14px;margin-bottom:26px}
.coll-meta .sep{color:var(--line)}
.coll-row.n8{max-width:700px}
@media (max-width:760px){.coll-row{gap:14px;max-width:340px}.coll-row .bk{width:26vw;max-width:100px}}
/* Smooth show for anything the shop filter or the quick-look toggles from display:none. */
@keyframes lasFade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
[data-shop-cat]{animation:lasFade .4s ease both}
#ql.flex{animation:lasFade .28s ease both}
.coll-lede h1{font-family:'Fraunces',serif;font-size:clamp(2rem,4vw,3rem);font-weight:400;line-height:1.1;margin:12px 0 14px}
.coll-lede p{color:var(--mute);line-height:1.75;margin-bottom:22px;max-width:46ch}
.coll-meta{display:flex;align-items:baseline;gap:18px;margin-bottom:26px}
.coll-meta .coll-count{font-family:'Inter',sans-serif;font-size:0.72rem;letter-spacing:0.12em;text-transform:uppercase;color:var(--mute)}
.coll-meta .coll-total{font-family:'Fraunces',serif;font-size:1.7rem;font-weight:600;color:var(--accent);white-space:nowrap}
@media (max-width:760px){
  .coll-hero-in{grid-template-columns:1fr;gap:30px;text-align:center}
  .coll-lede p{margin-left:auto;margin-right:auto}
  .coll-meta{justify-content:center}
  .coll-fan{max-width:340px;margin:0 auto}
  .bookcase.coll-case,.bookgrid.coll-case{max-width:360px;margin:0 auto}
}

/* Inline FAQ in the product page's right column (2026-08-28): the full-width section is gone,
   so this sits under the description at the same width as the copy, quieter type, tighter rows. */
.pdp-faq-inline{margin-top:2.4rem;padding-top:1.6rem;border-top:1px solid var(--line)}
.pdp-faq-inline .faq-lab{font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--mute);margin-bottom:.4rem}
.pdp-faq-inline .pdp-faq{border-top:none}
.pdp-faq-inline .pdp-faq summary{font-size:.98rem;padding:15px 2px}
.pdp-faq-inline .pdp-faq p{font-size:.9rem;margin-bottom:15px}
/* ── PDP FAQ (native <details>, no JS) ── */
/* Roomier since round 10 (Connor: "very thin, middle aligned, looked weird") — the block sits
   wider via its wrapper, questions bigger, first row carries a top rule so it reads as a table. */
.pdp-faq{border-top:1px solid var(--line)}
.pdp-faq details{border-bottom:1px solid var(--line)}
.pdp-faq summary{list-style:none;cursor:pointer;padding:22px 2px;font-family:'Fraunces',serif;font-size:1.12rem;color:var(--ink);display:flex;justify-content:space-between;align-items:center;gap:16px}
.pdp-faq summary::-webkit-details-marker{display:none}
.pdp-faq summary::after{content:"+";font-family:'Inter',sans-serif;color:var(--accent);font-size:1.3rem;line-height:1;transition:transform .2s ease}
.pdp-faq details[open] summary::after{content:"–"}
.pdp-faq .faq-panel{overflow:hidden}
.pdp-faq p{color:var(--mute);line-height:1.75;margin:0 2px 20px;max-width:64ch;font-size:.95rem}

/* ── ASTRO-MUG "how it works" steps ── */
.mug-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
.mug-step{display:flex;gap:16px;align-items:flex-start}
.mug-step .n{flex:none;width:38px;height:38px;border-radius:50%;background:var(--accent);color:var(--on-accent);display:flex;align-items:center;justify-content:center;font-family:'Fraunces',serif;font-weight:600;font-size:1.05rem}
.mug-step h3{font-family:'Fraunces',serif;font-size:1.05rem;font-weight:500;margin:6px 0 6px}
.mug-step p{color:var(--mute);line-height:1.65;font-size:.92rem;margin:0}
@media (max-width:760px){.mug-steps{grid-template-columns:1fr;gap:20px}}

/* ── ASTRO-MUG FEATURE (single product, full-width panel) ── */
/* Navy since 2026-08-09 (Connor: "the colours from the homepage replicated… that one just
   looks a bit ugly") — the shop's Astro-Mug panel now speaks the homepage tiles' language:
   navy ground, gold eyebrow, white heading, gold buy button beside a white price. */
.mug-feature{display:grid;grid-template-columns:1fr 1fr;gap:0;border:none;border-radius:14px;overflow:hidden;background:var(--band);margin-bottom:4rem}
.mug-feature-media{background:var(--alt);min-height:340px}
.mug-feature-media img{width:100%;height:100%;object-fit:cover;display:block}
.mug-feature-body{padding:clamp(28px,4vw,52px);display:flex;flex-direction:column;justify-content:center}
.mug-feature-body .eyebrow{color:var(--promo-hi,var(--gold))}
.mug-feature-body h2{font-size:clamp(1.6rem,2.6vw,2.2rem);font-weight:400;line-height:1.15;margin:12px 0 16px;color:var(--band-ink)}
.mug-feature-body p{color:var(--band-mute);line-height:1.8;margin-bottom:24px;max-width:46ch}
.mug-feature-buy{display:flex;align-items:center;gap:22px;flex-wrap:wrap}
.mug-feature-buy .price{font-size:1.5rem;color:var(--band-ink);font-weight:600}
.mug-feature-buy .shopify-embed-slot{flex:1;min-width:200px}
/* Homepage variant (2026-08-28): the photo whole on the panel ground, not cropped; the
   "Le plus offert" tag is a chip beside the eyebrow, not a badge over the picture. */
.mug-feature.home{margin-bottom:0}
/* The Astro-Mug photo is 1200x1200, PERFECTLY SQUARE. The home variant used to force it into a
   non-square box (max-height:420 inside min-height:380) with object-fit:contain, so it letterboxed
   against the cream ground: measured 31 Aug, a 550x420 element holding a 420x420 image (65px cream
   bands each side at 1440) and a 322x380 wrapper holding 266x266 (bands top and bottom at 390).
   Connor: "the mug doesn't fill in the full thing." Fixed by matching the BOX to the image's own
   aspect rather than cropping it: object-fit:cover would have filled it too, but the mug's margins
   are tight (~10% top, ~12% bottom) and at 390 the box is TALLER than wide, so cover would have
   sliced 7.5% off each side and clipped the handle. Never crop a product shot to fix a layout bug. */
.mug-feature.home .mug-feature-media{display:flex;align-items:center;justify-content:center;padding:28px;min-height:0}
.mug-feature.home .mug-feature-media img{width:100%;height:auto;aspect-ratio:1;max-height:none;object-fit:cover}
/* ⛔ THE HOME PANEL MUST STACK BELOW 960, NOT 720. Swept 320-2560 after squaring the photo:
   721-959 was still TWO columns, so the text column set the row height while the media column was
   too narrow for a matching square — measured padding 56 across but 257 down at 740, 225 at 768,
   108 at 900. Even at 960+. That is CLAUDE.md's recurring shape exactly: a grid whose collapse
   breakpoint and whose content rules disagree, leaving a band that renders the desktop composition
   badly. Scoped to .home ON PURPOSE — the shop panel uses object-fit:cover, its image fills its box
   at every width (measured), and collapsing it early would change a layout that is not broken. */
@media (max-width:959px){ .mug-feature.home{grid-template-columns:1fr} }
.mug-feature .chip{display:inline-block;margin-left:10px;vertical-align:middle;background:var(--accent);color:var(--on-accent);font-size:.6rem;letter-spacing:.1em;text-transform:uppercase;font-weight:700;padding:4px 9px;border-radius:100px}
@media (max-width:720px){
  .mug-feature{grid-template-columns:1fr}
  .mug-feature-media{min-height:260px}
}
.las-home section>.wrap{position:relative;z-index:1}
/* decorative Saturn-ring motifs */
.deco{position:absolute;border-radius:50%;pointer-events:none;z-index:0}
.deco.r-gold{border:1.5px solid var(--gold)}
.deco.r-accent{border:1.5px solid var(--accent)}
.deco.fill-accent{background:var(--accent)}
.deco.fill-gold{background:var(--gold)}
.deco.fill-ink{background:var(--ink)}
.assoc .deco{border-color:rgba(255,255,255,.55)!important}
.orbit{position:absolute;border-radius:50%;pointer-events:none;z-index:0;border:1.5px solid currentColor;color:rgba(28,26,23,.5)}
.orbit::before,.orbit::after{content:"";position:absolute;border-radius:50%;border:1.5px solid currentColor}
.orbit::before{inset:17%}
.orbit::after{inset:36%}
.assoc .orbit{color:rgba(255,255,255,.6)}
.chead{text-align:center;margin-bottom:46px}
.chead h2{font-size:clamp(1.8rem,2.9vw,2.4rem);font-weight:400;margin-top:8px}
.chead p{color:var(--mute);margin-top:12px;font-size:1rem;max-width:54ch;margin-left:auto;margin-right:auto;line-height:1.6}
.ctr{text-align:center;margin-top:46px}

/* product row */
.prow{display:grid;grid-template-columns:repeat(4,1fr);gap:28px;align-items:stretch}
/* Product-detail top layout (cover | infos) — was an inline style, which beat the
   mobile media query and squeezed a 2-col grid into 375px (audit 2026-07-17). */
.pdp-grid{display:grid;grid-template-columns:1fr 1fr;gap:5rem;align-items:start}
.pcard{position:relative;display:flex;flex-direction:column;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:18px 18px 22px;transition:box-shadow .3s,transform .3s,border-color .3s}
.pcard:hover{box-shadow:0 22px 44px -26px rgba(30,20,12,.55);transform:translateY(-4px);border-color:var(--accent)}
.pcard .stretch{position:absolute;inset:0;z-index:1;border-radius:12px}
.pcard .acts{position:relative;z-index:2}
/* Tile background dropped round 10 (Connor: "I don't know about this little grey background…
   maybe just have the books floating there") — the paperback floats on the page itself. */
.pcard .cov{display:flex;align-items:center;justify-content:center;aspect-ratio:5/7;border-radius:4px;overflow:hidden;background:none}
/* The .bk shadow (offset 10/14, blur 22, spread -12) paints ~9px right of and ~13px below the
   book, but at 390 the tile spares only 11.9 and 9.8 — so the bottom 3.2px came off as a flat
   horizontal cut on 5 of 6 cards (Connor 2026-08-10: "the shadow overlapping and getting cut
   off… a regular occurrence"). Book tiles don't need the clip at all: .bk is width-driven and
   never overruns the tile. Bare-image tiles keep it — they rely on it for object-fit + hover
   scale. :has() is unsupported below Firefox 121, where this simply degrades to today's crop. */
.pcard .cov:has(.bk){overflow:visible}
/* Collection tile inside a product row (Connor 2026-08-28): the homepage collection card's look, not three strips */
.pcard .cov.pc-cov{background:var(--pc-top,#1F3B5F);align-items:center;padding:6% 6%;overflow:hidden;border-radius:4px;aspect-ratio:5/7}
.pcard .cov.pc-cov .stack{position:relative;z-index:2;display:flex;justify-content:center;align-items:flex-end;width:100%}
.pcard .cov.pc-cov .thumb{width:46%;aspect-ratio:5/7;overflow:visible;flex:none}
.pcard .cov.pc-cov .thumb .bk{display:block;width:100%;height:100%}
.pcard .cov.pc-cov .thumb .bk img{width:100%;height:100%;object-fit:cover;transform:none}
.pcard .cov.pc-cov .thumb:nth-child(1){margin-right:-12%;transform-origin:100% 100%;transform:rotate(-7deg);z-index:1}
.pcard .cov.pc-cov .thumb:nth-child(2){width:52%;z-index:3}
.pcard .cov.pc-cov .thumb:nth-child(3){margin-left:-12%;transform-origin:0% 100%;transform:rotate(7deg);z-index:1}
/* Pre-order chip (2026-08-11). Sits on .pcard, not inside .cov, because .cov is overflow:hidden
   for every card that is not a .bk paperback and would slice it. Above .stretch (z-index 1) so it
   is never the thing swallowing the tap, and pointer-events:none so the whole card stays one
   target. Accent fill rather than gold: it is a state, not a decoration. */
/* ⚠️ z-index 4, and the number is load-bearing. At 2 the chip measured perfectly in the DOM,
   10px inside the card on both viewports, and was INVISIBLE on the render: `.bk img` is also
   position:relative z-index:2 (line ~774), equal z means DOM order decides, and the cover comes
   later, so the book painted straight over it and only a 10px sliver survived past the cover's
   right edge. Found by looking at a 390 render, not by measuring boxes. 4 clears the cover's 2
   and .acts' 3 without going near the drawer or the promo bar. */
.pcard .pre-chip{position:absolute;z-index:4;top:10px;right:10px;pointer-events:none;
  font-size:.5rem;letter-spacing:.09em;text-transform:uppercase;font-weight:700;
  background:var(--accent);color:var(--on-accent);padding:4px 7px;border-radius:2px;
  box-shadow:0 2px 8px rgba(0,0,0,.28)}
.pcard a.cov{cursor:pointer}
/* Physical paperback (Fitzcarraldo steal — Connor 2026-08-07 round 5, pending Fabien's view):
   the flat scan becomes a book object. Soft drop shadow; dark spine crease down the left edge
   with a highlight ridge beside it (the "indent line"); shaded page-block sliver on the right.
   All CSS over the untouched scan. Books only — build-site.mjs wraps book covers in .bk and
   leaves mug/candle photos bare. */
/* The paperback object, GENERIC since round 10 — .bk works anywhere (cards, collection heroes),
   only the card-specific sizing stays scoped to .pcard. */
.bk{position:relative;box-shadow:10px 14px 22px -12px rgba(35,28,18,.5)}
.bk img{width:100%;height:auto;display:block;position:relative;z-index:2}
/* Fore-edge, take 3 (round 7 — "the pages still don't look good"): thinner (8px), warmer
   paper gradient, hairline top/bottom edges, and the ::after adds a contact shade where the
   cover's right edge sits over the pages. Slightly SHORTER than the cover, like a real
   paperback's page block under its overhanging cover. */
.bk::before{content:"";position:absolute;z-index:1;top:3px;right:-6px;bottom:2px;
  width:clamp(6px,6.5%,13px); /* scales with the book (2026-08-09) — a fixed 8px read thin on
  the large PDP/collection-hero books */
  background:linear-gradient(90deg,#EDE6D6 0,#FAF7EF 35%,#F1EBDD 70%,#D8CFB9 100%);
  border-radius:0 2.5px 2.5px 0;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6), inset 0 -1px 0 rgba(120,105,80,.18)}
/* Spine crease left + cover-over-pages shade right. */
.bk::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;background:
  linear-gradient(90deg, rgba(0,0,0,.18), rgba(0,0,0,0) 3%),
  linear-gradient(90deg, rgba(0,0,0,0) 3%, rgba(255,255,255,.30) 5%, rgba(0,0,0,.07) 7.5%, rgba(0,0,0,0) 10%),
  linear-gradient(270deg, rgba(0,0,0,.15), rgba(0,0,0,0) 2.5%)}
/* 88% + margin-right (round 7): the book nearly fills the tile, shifted a touch left so the
   fore-edge + shadow keep clear air. Tile aspect 8/11 so the tallest scans fit. */
.pcard .cov .bk{width:88%;margin-right:4%;flex:none;transition:transform .4s}
/* Desktop title/price/actions live in .pinfo now — display:contents keeps the card's flex
   layout exactly as before; the MOBILE pattern below repurposes it as the tap overlay. */
.pcard .pinfo{display:contents}
/* the Shopify add-to-cart slot fills the action column like a button */
.pcard .acts .shopify-embed-slot{width:100%}
/* On mount the SDK writes `max-width:280px` INLINE onto the slot div itself (not the iframe —
   the iframe is already width:100%, and it carries no class, so the old .shopify-buy-frame
   selector never matched anything). That inline cap is what made every PDP button paint
   full-width as the fallback <a> and then snap to ~280px half a second later — the "buttons
   flash then go narrow" bug (Connor 2026-07-19). Only !important beats an inline style.
   .assoc-cta is excluded: that slot is inline-flex on purpose and must stay content-width. */
.shopify-embed-slot:not(.assoc-cta *){max-width:none!important}
.shopify-embed-slot .shopify-buy__btn{width:100%!important}
/* > combinator on purpose: bare (non-book) images only — .bk img sizes itself above.
   cover, not contain, since 2026-08-09 (Connor: cross-sell photos "aren't stretched across
   the full card") — object tiles are square now, so product shots fill edge to edge. */
.pcard .cov>img{width:100%;height:100%;object-fit:cover;transform:none;transition:transform .4s}
.pcard:hover .cov>img{transform:scale(1.04)}
.pcard:hover .cov .bk{transform:translateY(-3px)}
.pcard h3{font-size:.98rem;font-weight:500;margin:16px 0 6px;line-height:1.32;min-height:2.5em;text-align:center;display:flex;align-items:center;justify-content:center}
/* margin-top:auto lives on the PRICE, not .acts (Connor 2026-07-22): it used to sit on .acts, so
   only the buttons bottom-aligned and a title that wrapped to an extra line pushed that card's
   price out of line with its neighbours. Anchoring the price instead bottom-aligns price+button
   as one block, so both stay on a shared line across the whole row. */
.pcard .price{color:var(--accent);font-family:'Fraunces',serif;font-weight:600;font-size:1.15rem;text-align:center;margin-top:auto;margin-bottom:14px}
.pcard .acts{display:flex;flex-direction:column;align-items:center;gap:18px}
.pcard .acts .btn{width:100%}
.pcard .vlink{position:relative;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--mute);font-weight:500}
.pcard .vlink::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:1px;background:var(--accent);transform:scaleX(0);transform-origin:right;transition:transform .35s ease}
.pcard:hover .vlink{color:var(--accent)}
.pcard:hover .vlink::after{transform:scaleX(1);transform-origin:left}

/* NASDAQ digital-product tile (Direction A) — no photo; engraved Saturn motif + tier numeral.
   Reuses .pcard for frame/hover/title/price/actions; only the .cov panel is re-skinned. */
.ncard .cov{aspect-ratio:1/1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:radial-gradient(120% 100% at 50% 0%, color-mix(in srgb, var(--accent) 8%, var(--bg)) 0%, var(--bg) 66%);border:1px solid var(--line)}
.ncard .cov .n-saturn{width:50px;height:50px}
.ncard .cov .n-num{font-family:'Fraunces',serif;font-weight:600;font-size:2.8rem;line-height:1;color:var(--accent)}
.ncard .cov .n-unit{font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--mute);font-weight:600}

/* collections (parcours) */
.parc{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2vw,26px)}
.pc{border:1px solid var(--line);border-radius:16px;background:var(--card);overflow:hidden;display:flex;flex-direction:column;transition:box-shadow .3s,transform .3s,border-color .3s}
.pc:hover{box-shadow:0 26px 50px -28px rgba(30,20,12,.5);transform:translateY(-4px);border-color:var(--accent)}
.pc .top{position:relative;min-height:0;display:flex;align-items:flex-end;justify-content:center;padding:28px 22px 0;overflow:hidden}
/* One shared dark panel across all three (Connor 2026-07-19). The per-card blue/gold/green
   read as three unrelated products sitting in one row, and clashed with the oxblood palette
   the rest of the page runs on. The covers are already the colour in this row. */
/* Warm espresso — leather-binding brown (Connor 2026-07-19, chosen over muted oxblood and the
   original near-black). Same warm family as the cream page so the panel recedes instead of
   competing, while the covers' navy/green/pink/red all still read as objects against it.
   Fixed hex, not palette-derived: this is a neutral shelf colour, and mixing it from --accent
   would swing it green/blue under the other palettes. */
/* Backdrop behind each collection's cover stack. Was a hardcoded #3A2E26 warm near-black that
   ignored the palette entirely and read as dark grey on the blue scheme (Connor 2026-07-20).
   Now a token so each palette supplies its own; the default keeps the original warm value. */
.pc .top{background:var(--pc-top,#3A2E26)}
/* Under the cool saturne scheme the warm espresso panel reads as a mismatch, so it follows
   that palette's anthracite instead. */
/* Removed 2026-07-20: this pinned the collection backdrop to anthracite #30343A for saturne and
   out-specified the --pc-top token, so the three collection panels stayed dark grey while the
   rest of the palette went blue. The token on the palette block now supplies it. */
.pc .top::after{content:"";position:absolute;inset:0;background-image:radial-gradient(1.4px 1.4px at 16% 24%, var(--gold), transparent),radial-gradient(1.4px 1.4px at 82% 20%, var(--gold), transparent),radial-gradient(1.2px 1.2px at 64% 76%, var(--ink), transparent),radial-gradient(1.2px 1.2px at 30% 82%, var(--gold), transparent),radial-gradient(1px 1px at 46% 16%, var(--ink), transparent),radial-gradient(1px 1px at 88% 60%, var(--gold), transparent);opacity:.4;pointer-events:none}
.pc .save{position:absolute;top:14px;right:14px;background:var(--accent);color:var(--on-accent);font-size:.7rem;letter-spacing:.08em;font-weight:600;padding:5px 11px;border-radius:100px;z-index:5}
.pc .stack{position:relative;z-index:2;display:flex;justify-content:center;align-items:flex-end;margin-bottom:-10px;transition:transform .4s cubic-bezier(.2,.7,.3,1)}
.pc:hover .stack{transform:translateY(-6px)}
/* 2026-08-25: .thumb was the visual box itself (overflow:hidden, its own radius + shadow).
   Now it's a plain sizing wrapper — .bk nested inside is the visual box, and overflow can't
   stay hidden or .bk's fore-edge strip (right:-6px) gets clipped off. */
.pc .stack .thumb{width:clamp(84px,38%,150px);aspect-ratio:5/7;overflow:visible} /* % of the card (2026-08-28): in a 4-up cross-sell row the fixed px fan collapsed into three strips */
.pc .stack .thumb .bk{display:block;width:100%;height:100%}
.pc .stack .thumb .bk img{width:100%;height:100%;object-fit:cover;transform:none}
.pc .stack .thumb:nth-child(1){margin-right:-14%;transform-origin:100% 100%;transform:rotate(-7deg);z-index:1}
.pc .stack .thumb:nth-child(2){width:clamp(92px,42%,160px);z-index:3}
.pc .stack .thumb:nth-child(3){margin-left:-14%;transform-origin:0% 100%;transform:rotate(7deg);z-index:1}
/* PDP main image as the paperback object, like every card (Connor 2026-08-28) */
.pdp-bk{display:block;width:100%;aspect-ratio:8/11;box-shadow:0 30px 70px -20px rgba(0,0,0,.22)}
.pdp-bk img{width:100%;height:100%;object-fit:cover}
.pc .body{padding:26px 26px 28px;text-align:center;display:flex;flex-direction:column;flex:1}
.pc h3{font-size:1.28rem;font-weight:500;margin-bottom:8px}
.pc p{font-size:.94rem;color:var(--mute);line-height:1.6;flex:1;margin-bottom:16px}
.pc .meta{font-size:.92rem;margin-bottom:18px}
.pc .meta .was{text-decoration:line-through;color:var(--mute);margin-right:9px;font-size:.85rem}
.pc .meta .now{color:var(--accent);font-family:'Fraunces',serif;font-weight:600;font-size:1.15rem}
/* Was hardcoded oxblood, so the collection CTAs stayed red under every other palette —
   caught testing Fabien's saturne scheme (2026-07-20). */
.pc .buy{align-self:center;background:var(--accent);color:var(--on-accent)}
.pc .buy:hover{background:var(--accent-dk)}

/* latest release */
.release{display:grid;grid-template-columns:.78fr 1.22fr;gap:56px;align-items:center}
.rel-cover{position:relative;justify-self:start;max-width:300px;width:100%}
@media(max-width:768px){.rel-cover{justify-self:start;max-width:min(260px,70vw)}}
/* Round 2026-08-24 (Connor): was a bare rounded-corner img — flat, next to the real paperback
   treatment used everywhere else on the store. .bk is generic (works anywhere, see its own
   comment), so this drops in with no new asset: the flat cover, spine + page-edge and all. */
.rel-cover .bk{display:block;width:100%}
.rel-cover .bk img{width:100%}
/* Starburst sticker — the shape a "best seller" flash traditionally takes in a bookshop.
   Normally red; here in the brand blue so it belongs to the site (Connor 2026-07-20). Replaces
   first a square label that crowded the author name, then a 45deg ribbon that read worse than
   the original. Spikes are a 14-point clip-path; the text is centred with its own line-height
   so two words stack inside the disc instead of spilling past the points. */
/* Best-seller seal: WHITE (Connor 2026-07-27 — the gold seal "looks a bit ugly"). */
/* z-index bumped 2->5, 2026-08-25: since the cover got wrapped in .bk (round 1 today), .bk::after
   (the spine/shading pseudo-element, z-index:3) started painting OVER this badge — .bk has no
   z-index of its own so it never contains its children's stacking, they compete directly against
   siblings in .rel-cover. Caught by Connor looking at the actual render, not from any check —
   the badge was reading as "behind the book". */
.rel-cover .badge{position:absolute;top:-40px;left:-40px;z-index:5;
  width:124px;height:124px;display:flex;align-items:center;justify-content:center;text-align:center;
  /* Gold starburst, white text (Connor 2026-07-29). It was a white badge on a cream section,
     so the shape only read from its shadow. NOTE: --gold is satin SILVER in the saturne palette
     because Fabien asked for the gold accents to go, so this uses --promo-hi, the one gold token
     that survived that call and already sets the section eyebrows. White on #C9A35C measures
     2.37:1, which is under WCAG AA for text this size — flagged to Connor. */
  background:var(--promo-hi,var(--gold));color:#fff;box-shadow:0 2px 14px rgba(22,37,59,.18);
  font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;font-weight:700;line-height:1.25;
  padding:0 24px;border-radius:0;transform:rotate(-14deg);
  clip-path:polygon(50.0% 0.0%,59.2% 9.5%,71.7% 5.0%,75.9% 17.6%,89.1% 18.8%,87.4% 32.0%,98.7% 38.9%,91.5% 50.0%,98.7% 61.1%,87.4% 68.0%,89.1% 81.2%,75.9% 82.4%,71.7% 95.0%,59.2% 90.5%,50.0% 100.0%,40.8% 90.5%,28.3% 95.0%,24.1% 82.4%,10.9% 81.2%,12.6% 68.0%,1.3% 61.1%,8.5% 50.0%,1.3% 38.9%,12.6% 32.0%,10.9% 18.8%,24.1% 17.6%,28.3% 5.0%,40.8% 9.5%)}
/* Mobile seal, round 5: neither round 3 (straddling a CENTRED cover — floated mid-page) nor
   round 4 (inset ON the cover — "floating in the middle of the book") read right. The cover
   goes back to the LEFT rail, so the seal straddling its corner lands at the very top-left of
   the content column — "it needs to be on the very top left". */
/* Round 13 (Connor 2026-08-10: "make sure it sticks on the top left corner, I don't want to be
   able to see the top corner of the book"). A 14-point star's VALLEYS reach only 0.415×W from
   its centre, so covering the cover's square corner is a distance problem, not a nudge:
   at -10px the seal's centre sat 45.3px from the corner against a 34.9px valley radius, and the
   navy corner poked through the notch. -22px puts the centre 28.3px out — inside the valley with
   6.6px to spare — and the seal still clears the viewport edge by 3px at 390.
   The breakpoint moves 900 → 1327 because the LARGE seal does not fit the page gutter: rotated
   -14deg its box is 1.212× its width, so at 124px/-40px it needs 53px of gutter and the wrap only
   gives 34px until the viewport passes ~1327px — it was hanging 19px past the left edge and being
   sliced by body{overflow-x:hidden} on every screen from 880 to 1300. Above 1327 the gutter is
   wide enough and the full-size seal returns untouched. */
@media(max-width:1327px){.rel-cover .badge{width:84px;height:84px;top:-22px;left:-22px;font-size:.54rem;padding:0 15px}}
.release h2{font-size:clamp(1.9rem,3.2vw,2.6rem);font-weight:300;margin:12px 0 16px;line-height:1.12}
.release p{color:var(--mute);line-height:1.75;margin-bottom:24px;max-width:46ch}
.release .acts{display:flex;gap:14px;flex-wrap:wrap}

/* about */
.about-in{display:grid;grid-template-columns:.82fr 1.18fr;gap:64px;align-items:center}
.about .portrait{justify-self:start;width:100%;max-width:400px}
.about .portrait img{width:100%;display:block;filter:drop-shadow(0 24px 44px rgba(30,20,12,.32))}
.about h2{font-size:clamp(1.9rem,3.2vw,2.6rem);font-weight:300;margin:14px 0 20px;line-height:1.16}
.about p{color:var(--mute);line-height:1.8;margin-bottom:16px;font-size:1.02rem}
.about .acts{display:flex;gap:14px;flex-wrap:wrap;margin-top:26px}

/* youtube — full-width band */
.ytband{background:var(--band);padding:26px 0}
.ytstrip{display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;color:var(--band-ink)}
.ytstrip .l{display:flex;align-items:center;gap:18px}
/* Unchanged from the original in every dimension except colour (Connor 2026-07-20): same 60x42
   tile, same 12px radius, same 22px play triangle. Only the tile colour moves off the navy
   accent onto red. Deliberately NOT YouTube's #FF0000 — at full saturation it screamed against
   the muted paper-and-ink palette. This is the brand red taken down to sit with it. */
.ytstrip .ply{width:60px;height:42px;border-radius:12px;background:#B5362C;display:flex;align-items:center;justify-content:center;flex:none;transition:background .2s,transform .2s}
.ytstrip .ply:hover{background:#982C24;transform:scale(1.05)}
.ytstrip .ply svg{width:22px;height:22px;color:#fff;margin-left:2px}
.ytstrip b{font-family:'Fraunces',serif;font-size:1.15rem;font-weight:500;display:block;color:var(--band-ink);margin-bottom:2px}
.ytstrip .l span{font-size:.9rem;color:var(--band-mute)}
.ytstrip .r{display:flex;gap:12px;flex-wrap:wrap}

/* chart — card + modal popup */
/* padding was 54px 44px (Connor 2026-08-07: "too much padding around") — top cut hardest so
   the card hangs closer to the section above; bottom keeps a touch more so the CTA can breathe. */
.chart-card{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:38px 44px 46px;text-align:center;max-width:780px;margin:0 auto;position:relative;overflow:hidden}
.chart-card.full{max-width:none;width:100%}   /* full-width instance aligned to the content container (homepage + shop) */
.chart-card .natal-wheel{width:92px;height:92px;margin:0 auto 18px;display:block;opacity:.9}
.chart-card h2{font-size:clamp(1.7rem,3vw,2.4rem);margin:10px 0 0;font-weight:400}
.chart-card p{color:var(--mute);max-width:48ch;margin:14px auto 26px;line-height:1.6}
/* ⛔ TOP PADDING CLEARS THE STICKY NAV, AND IT IS NOT DECORATION. The scrim is fixed inset:0 and
   centres the modal in the WHOLE viewport, while the nav is sticky and paints above it — so the
   centred position put the chart panel's top at 66px against a nav bottom of 79px, i.e. 13px of
   the panel hidden behind the bar. Measured 2026-08-28 at every width from 390 to 900 (all
   phones AND tablets, clear only from 1024 up), after Connor: "this should be sent on my page at
   the moment it's stuck to the top behind the bar". Padding the scrim means the centring happens
   in the region BELOW the nav instead of behind it. 78px is .nav-in's min-height. */
.modal-scrim{position:fixed;inset:0;background:rgba(10,8,6,.62);opacity:0;pointer-events:none;transition:opacity .25s;z-index:80;display:flex;align-items:center;justify-content:center;padding:calc(78px + 16px) 18px 24px;overflow:auto}
.modal-scrim.open{opacity:1;pointer-events:auto}
.modal{background:var(--bg);border-radius:18px;max-width:580px;width:100%;margin:auto;padding:40px 38px;position:relative;transform:translateY(14px) scale(.985);transition:transform .25s}
.modal-scrim.open .modal{transform:none}
.modal .x{position:absolute;top:16px;right:18px;background:none;border:0;font-size:1.7rem;cursor:pointer;color:var(--mute)}

/* ── BIRTH CHART RESULT (rebuilt 2026-07-28) ──────────────────────────────────────────────
   Connor: "why on a landscape computer screen is this thing so thin and stretching off the page?
   I have to scroll down to see it — put the chart on the left and the actions on the right."
   It was a 580px column ~1400px tall inside a 900px window: a phone layout on a desktop. The
   result is now a two-column landscape layout that fits a laptop in one frame, and every card and
   button below is the site's own — chart.js used to invent its own from inline styles, which is
   why the tool read as a different website. Markup: chart.js render()/showChart(). */
/* 1140 left ~280px of dead space either side on a normal laptop and pushed the funnel row
   below the fold. Wider frame, so the wheel and the full position list sit in one view. */
.modal.is-chart{max-width:1380px;padding:34px 34px 30px}
.bc-wrap{display:grid;grid-template-columns:1fr;gap:22px}
@media (min-width:1000px){
  .modal.is-chart{padding:38px 42px 34px}
  .bc-wrap{grid-template-columns:minmax(0,520px) minmax(0,1fr);gap:44px;align-items:start}
  /* the wheel is the point of the page — give it the room and stop it scrolling away */
  .bc-chart{position:sticky;top:0}
}
.bc-chart svg{display:block;width:100%;height:auto}
.bc-head{margin:0 0 16px}
.bc-head .eyebrow{display:block;margin-bottom:8px}
/* .modal h3 sets text-align:center and is (0,1,1) against .bc-title's (0,1,0), so the generic
   modal rule was winning and the title sat centred above a left-aligned eyebrow and date line.
   That is the "half left, half centre" Connor saw. Qualified so it actually applies. */
.modal h3.bc-title,.bc-title{font-family:'Fraunces',Georgia,serif;font-size:1.7rem;font-weight:400;line-height:1.15;color:var(--ink);margin:0 0 6px;text-align:left}
.bc-birth{font-size:.85rem;color:var(--mute);margin:0}
/* Now under the wheel, so it needs space above it rather than below */
.bc-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:20px 0 0}
.bc-tile{border:1px solid var(--line);background:var(--card);padding:12px 8px;text-align:center}
.bc-tg{display:block;font-size:1.15rem;line-height:1;color:var(--ink);opacity:.75}
.bc-tl{display:block;font-size:.55rem;letter-spacing:.14em;text-transform:uppercase;color:var(--mute);margin:7px 0 3px}
.bc-tv{display:block;font-family:'Fraunces',Georgia,serif;font-size:.98rem;color:var(--ink)}
/* One ink colour and a fixed glyph column: the old table tinted each glyph its planet colour at
   1.05em inside the name cell, so the symbols read as a ragged coloured jumble. Colour still
   does its job in the WHEEL, where the planets have to be told apart. */
.bc-tbl{border-collapse:collapse;width:100%;font-size:.92rem}
.bc-tbl td{padding:7px 0;border-bottom:1px solid var(--line)}
.bc-tbl tr:last-child td{border-bottom:0}
.bc-g{width:22px;color:var(--ink);opacity:.55;font-size:1rem;text-align:center}
.bc-n{padding-left:10px !important;color:var(--ink)}
.bc-s{font-weight:600;color:var(--ink);text-align:right}
.bc-d{padding-left:14px !important;color:var(--mute);text-align:right;white-space:nowrap}
.bc-rx{opacity:.7}
.bc-asp{margin-top:16px;border-top:1px solid var(--line)}
.bc-asp>summary{font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;color:var(--mute);cursor:pointer;padding:12px 0 4px;list-style:none}
.bc-asp>summary::-webkit-details-marker{display:none}
.bc-aspin{overflow-x:auto;padding-bottom:8px}
/* The three offers run as one row under both columns, so the chart and the full position list
   stay above the fold on a laptop. They stack on narrow screens. */
/* 4px let the wheel sit right on top of the cards once you scrolled down. The row now has real
   separation and a hairline, so it reads as a distinct band rather than more of the chart. */
.bc-foot{grid-column:1/-1;margin-top:38px;padding-top:30px;border-top:1px solid var(--line)}
.bc-foot #chart-funnel{display:grid;grid-template-columns:1fr;gap:14px}
/* #chart-reco is a wrapper holding the consultation card AND the book card; without this it
   counts as ONE grid item and the two stack in a single column while the third sits empty. */
.bc-foot #chart-reco{display:contents}
@media (min-width:1000px){.bc-foot #chart-funnel{grid-template-columns:repeat(3,1fr);align-items:start}}
.bc-foot .bc-cta,.bc-foot .bc-book,.bc-foot .bc-mug{margin-top:0;height:100%}
.bc-mug{border:1px solid var(--line);background:var(--card);padding:18px 20px;text-align:left}
.bc-mug .eyebrow,.bc-book .eyebrow{display:block;margin-bottom:10px;font-size:.6rem}
/* CTA cards — same border/paper as every other card on the store, not a bespoke accent box */
.bc-cta{border:1px solid var(--line);background:var(--card);padding:22px 22px 24px;margin-top:20px;text-align:center}
.bc-cta-t{font-family:'Fraunces',Georgia,serif;font-size:1.25rem;line-height:1.25;color:var(--ink);margin:10px 0 8px}
.bc-cta-p{font-size:.88rem;color:var(--mute);line-height:1.6;max-width:46ch;margin:0 auto 18px}
.bc-book{border:1px solid var(--line);background:var(--card);padding:18px 20px;margin-top:14px;text-align:left}
.bc-book-in{display:flex;gap:16px;align-items:flex-start;margin-top:10px}
.bc-book-img{flex-shrink:0}
/* The cover was a bare 56px image with no defined shape, so it floated next to the text at
   whatever aspect the file happened to be. Fixed book proportions and a hairline make it read
   as a product thumbnail, matching how covers appear everywhere else on the store. */
.bc-book-img img{width:62px;aspect-ratio:2/3;object-fit:cover;display:block;border:1px solid var(--line)}
.bc-book-t{font-family:'Fraunces',Georgia,serif;font-size:.95rem;margin-bottom:6px;color:var(--ink)}
.bc-book-t-1line{white-space:nowrap}
@media (max-width:420px){.bc-book-t-1line{font-size:.86rem}}
.bc-book-p{font-size:.85rem;color:var(--mute);line-height:1.6;margin:0 0 12px}
.bc-book .btn,.bc-cta .btn{padding:11px 20px;font-size:.7rem}
/* ── The funnel row reads as ONE row (Connor 2026-08-05) ──────────────────────────────
   It did not. The three cards were three different components with three different rules:
   .bc-cta centred at 22/22/24 with a 1.25rem heading, .bc-book and .bc-mug left at 18/20
   with a .95rem heading, and nothing pinning the buttons to a shared baseline, so they sat
   at three different heights. Inside .bc-foot they are now one card: same padding, same
   alignment, same heading size, button pushed to the bottom. The ONLY difference left is
   button weight, which is deliberate hierarchy — the consultation is the money action. */
.bc-foot .bc-cta,.bc-foot .bc-book,.bc-foot .bc-mug{
  display:flex;flex-direction:column;padding:20px;text-align:left}
.bc-foot .bc-cta-t,.bc-foot .bc-book-t{
  font-family:'Fraunces',Georgia,serif;font-size:1rem;line-height:1.3;margin:0 0 7px}
.bc-foot .bc-cta-p,.bc-foot .bc-book-p{
  font-size:.85rem;line-height:1.6;max-width:none;margin:0 0 14px}
/* .bc-book nests its copy inside .bc-book-in, so the bottom-pin has to reach through it */
.bc-foot .bc-book-in{margin-top:0;align-items:flex-start;gap:14px}
.bc-foot .bc-book-txt{flex:1;min-width:0}
/* Every card's button is a direct child now, so all three land on the card's left padding edge
   and on the same baseline. */
.bc-foot .bc-cta>.btn,.bc-foot .bc-mug>.btn,.bc-foot .bc-book>.btn{
  margin-top:auto;align-self:flex-start}
/* A bigger cover so the card carries the same visual weight as the copy in the other two, and
   the title sits level with the top of it rather than floating. */
.bc-foot .bc-book-img img{width:74px}
.bc-foot .bc-book-t{margin-top:-2px}
.modal h3{font-family:'Fraunces',serif;font-size:1.55rem;font-weight:500;text-align:center;margin-bottom:6px}
/* ⚠️ DESCENDANT, not direct child. This was `.modal>p.lead`, and every .lead in the chart tool
   lives inside #chart-step1 / #chart-step2, so the rule never matched a single one: the opening
   line sat left aligned under a centred heading with no space beneath it, which is exactly what
   Connor saw. The selector was written when the paragraph was a direct child and was never
   revisited when the steps were introduced. */
.modal p.lead{text-align:center;color:var(--mute);font-size:.9rem;margin-bottom:24px}
#chart-form{display:grid;gap:14px}
#chart-form label{font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--mute);font-weight:600;margin-bottom:6px;display:block}
#chart-form .dob{display:grid;grid-template-columns:1fr 1.3fr 1fr;gap:10px}
#chart-form .two{display:grid;grid-template-columns:1fr 1fr;gap:14px}
#chart-form select,#chart-form input{width:100%;height:50px;box-sizing:border-box;border:1px solid var(--line);border-radius:6px;padding:0 14px;font-family:Inter,sans-serif;font-size:.95rem;background:var(--card);color:var(--ink);appearance:none;-webkit-appearance:none}
/* custom caret so all three date selects match (no native arrow size differences) */
#chart-form select{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%236E665B' stroke-width='1.6'/></svg>");background-repeat:no-repeat;background-position:right 14px center;padding-right:34px}
#chart-form select:focus-visible,#chart-form input:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-color:var(--accent)}
#chart-form input[type=time]{appearance:auto;-webkit-appearance:none}
#chart-form button{margin-top:8px}

/* Generic contact-style form (2026-08-24) — same field look as #chart-form, generalised off the
   id so any page can use it. Contact page needed a REAL form; it had a raw mailto: button and
   nothing else (Connor: "there is no form or anything, that's awful"). */
.cform{display:grid;gap:14px;text-align:left}
.cform label{font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--mute);font-weight:600;margin-bottom:6px;display:block}
.cform input,.cform textarea{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:6px;padding:14px;font-family:Inter,sans-serif;font-size:.95rem;background:var(--card);color:var(--ink);text-transform:none;letter-spacing:normal;font-weight:400}
.cform input{height:50px;padding:0 14px}
.cform textarea{min-height:140px;resize:vertical;line-height:1.5}
.cform input:focus-visible,.cform textarea:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-color:var(--accent)}
.cform button{margin-top:4px;width:100%}
.cform .send-err{color:#c0392b}
/* Mobile (Connor 2026-07-29): the form had NO small-screen rules, so at 390px the modal's
   ~279px of usable width was split into a 3-column date row and a 2-column row holding a
   nested 2-column time row. Each time select ended up ~61px wide against 48px of horizontal
   padding, leaving 13px for text: "Heure" and "Min" rendered as "H" and "M", and "Année" as
   "Ann". Stacking the two-up row gives the date and time rows the full width, and the tighter
   padding buys back the rest. Verified at 390px and 360px. */
@media (max-width:560px){
  #chart-form .two{grid-template-columns:1fr}
  #chart-form .dob{gap:8px;grid-template-columns:1fr 1.25fr 1.15fr}
  #chart-form select,#chart-form input{padding:0 10px;font-size:.9rem}
  #chart-form select{padding-right:28px;background-position:right 10px center}
}
/* Narrow phones (360px and below): the date row is three selects whose longest labels are
   "Jour" and "Année", so equal columns beat a weighted grid here, and the caret gutter has to
   come in again or those two clip. Verified at 360px and 320px. */
@media (max-width:420px){
  #chart-form .dob{gap:6px;grid-template-columns:1fr 1fr 1.15fr}
  #chart-form select,#chart-form input{padding:0 8px;font-size:.86rem}
  #chart-form select{padding-right:22px;background-position:right 7px center}
}
/* 320px (iPhone SE 1st gen): "Année" is 5 characters plus a caret in a third of ~200px. */
@media (max-width:340px){
  #chart-form select,#chart-form input{font-size:.78rem;padding:0 7px}
  #chart-form select{padding-right:19px;background-position:right 6px center}
}
#chart-result{margin-top:8px;color:var(--ink);--chart-panel:var(--card);--chart-accent:var(--gold)}
.cap-email{max-width:520px;margin:18px auto 20px;text-align:center}
.cap-email h4{font-family:'Fraunces',serif;font-size:1.15rem;font-weight:500;margin-bottom:6px}
.cap-email p{font-size:.86rem;color:var(--mute);margin-bottom:14px}
.cap-email form{display:flex;gap:10px;flex-wrap:wrap}
.cap-email input{flex:1;min-width:200px;border:1px solid var(--line);border-radius:6px;padding:13px 15px;background:var(--card);color:var(--ink);font-family:Inter,sans-serif}
.reco3{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;text-align:left}
.reco3 .r{border:1px solid var(--line);border-radius:10px;padding:15px;background:var(--card);display:flex;flex-direction:column}
.reco3 .r .k{font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;color:var(--gold);margin-bottom:8px}
.reco3 .r img{width:48px;aspect-ratio:3/4;object-fit:cover;border-radius:3px;margin-bottom:9px}
.reco3 .r h5{font-family:'Fraunces',serif;font-size:.92rem;font-weight:500;margin-bottom:9px;line-height:1.25;flex:1}
.reco3 .r a{font-size:.7rem;color:var(--accent);font-weight:600;text-transform:uppercase;letter-spacing:.05em}

/* objets */
.objrow{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
/* Objects row with fewer tiles (candles + T-shirts hidden, Fabien 2026-08-27): keep the tile at
   card width and centre it rather than stretching one tile across three columns. */
.objrow.n1{grid-template-columns:minmax(0,520px);justify-content:center}
.objrow.n2{grid-template-columns:repeat(2,minmax(0,520px));justify-content:center}
.tc{position:relative;border-radius:14px;overflow:hidden;min-height:400px;display:flex;align-items:flex-end;color:#fff}
.tc .tag{position:absolute;top:14px;right:14px;background:var(--accent);color:var(--on-accent);font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;font-weight:700;padding:5px 11px;border-radius:100px;z-index:3}
.tc img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .5s}
.tc:hover img{transform:scale(1.04)}
.tc .ph{position:absolute;inset:0;background:linear-gradient(135deg,var(--band),color-mix(in srgb, var(--band) 45%, #000))}
.tc .ov{position:absolute;inset:0;background:linear-gradient(0deg,rgba(0,0,0,.82),rgba(0,0,0,.12) 58%,transparent)}
.tc .slot{position:absolute;top:10px;left:10px;background:rgba(0,0,0,.5);color:#ffd479;font-size:.64rem;padding:4px 8px;border-radius:3px;z-index:3}
.tc .tx{position:relative;z-index:2;padding:34px}
.tc h3{font-family:'Fraunces',serif;font-size:1.7rem;font-weight:500;margin-bottom:6px}
.tc p{font-size:.96rem;color:var(--band-ink);margin-bottom:16px;max-width:32ch}

/* integrale */
.integ-in{display:grid;grid-template-columns:0.92fr 1.35fr;gap:56px;align-items:center}
/* "Édition reliée, quantité limitée" in gold rather than accent (Connor 2026-07-22). Uses
   --promo-hi (the real gold) because under saturne --gold is satin silver. Deliberately the ONLY
   gold on the page — the brief was a single warm accent here, not gold reintroduced site-wide. */
/* --gold-on-light, not --promo-hi (2026-08-11): this label sits on the LIGHT half of the
   Intégrale banner, where the promo-bar gold measured 1.73:1 at 390 and 1.95:1 at 1440. It is
   the only .scar in the store and it is on a light ground at both widths, so the deepened gold
   is unconditional here rather than scoped. Fallback chain kept for any palette without the
   token. Measured after: 2.98:1 at 390, 3.35:1 at 1440. */
.integ .scar{display:inline-flex;gap:8px;align-items:center;font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;color:var(--gold-on-light,var(--promo-hi,var(--gold)));font-weight:600;margin-bottom:14px}
.integ h2{font-size:clamp(2.1rem,3.6vw,3rem);font-weight:300;margin:6px 0 18px;line-height:1.08}
.integ .lede{color:var(--mute);line-height:1.75;margin-bottom:26px;max-width:44ch;font-size:1rem}
/* 26px, was 8 (Connor 2026-08-07): the CTA practically hugged the 339 € figure. */
.integ .pr{display:flex;align-items:baseline;gap:14px;margin-bottom:26px}
.integ .price{font-family:'Fraunces',serif;font-size:3rem;color:var(--ink);line-height:1}
.integ .was{color:var(--mute);text-decoration:line-through;font-size:1.15rem}
.integ .save{color:var(--accent);font-weight:600;font-size:.85rem;letter-spacing:.04em;margin-bottom:28px;display:block}
.integ .composite{border-radius:12px;overflow:hidden;box-shadow:0 36px 70px -34px rgba(0,0,0,.55)}

/* association band */
.assoc{background:var(--accent);color:var(--on-accent);text-align:center;overflow:hidden}
/* The band lost its top padding when the chart section above it went (a sibling rule zeroes padding-top); pin it at the section rule's own specificity (Connor 2026-08-28: "add the padding back") */
.las-home section.assoc,.las-home #objets + section.assoc{padding-top:84px;padding-bottom:84px} /* #objets + section zeroes the top for the section that used to follow it */
.assoc .eyebrow{color:rgba(255,255,255,.72)}
.assoc h2{font-family:'Fraunces',serif;font-size:clamp(1.7rem,2.9vw,2.4rem);font-weight:400;margin:12px auto 14px;max-width:34ch}
.assoc p{color:rgba(255,255,255,.86);line-height:1.7;max-width:56ch;margin:0 auto 24px}
/* Under PREVIEW_LOCK the .assoc-cta button is stripped, so the last <p>'s 24px bottom margin
   left the band 84px top / 108px bottom — visibly off-centre on Fabien's preview only. */
.assoc p:last-child{margin-bottom:0}

/* newsletter */
.news-card{display:grid;grid-template-columns:1.1fr 1fr;gap:48px;align-items:center}
/* Capped at 1.7rem + nowrap on desktop (Connor 2026-08-09): at 2rem the headline broke onto
   two lines inside its grid column. Mobile keeps the wrap — one line is impossible at 390. */
.news-card h2{font-size:clamp(1.5rem,2.5vw,2rem);font-weight:400;margin:10px 0 12px}
@media(min-width:901px){.news-card h2{font-size:clamp(1.4rem,1.9vw,1.7rem);white-space:nowrap}}
.news-card p{color:var(--mute);line-height:1.65;font-size:.98rem}
.news-card .formside form{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.news-card input{flex:1;min-width:180px;border:1px solid var(--line);border-radius:6px;padding:14px 16px;font-family:Inter,sans-serif;background:var(--bg);color:var(--ink)}
.news-card .fine{font-size:.78rem;color:var(--mute)}

/* footer (homepage chrome) */
footer.las-footer{background:var(--band);color:var(--band-mute);padding:0 0 30px}
.las-footer .f-cta{border-bottom:1px solid var(--band-line);text-align:center;padding:60px 34px 56px}
.las-footer .f-cta .eyebrow{color:var(--gold)}
.las-footer .f-cta h3{font-family:'Fraunces',serif;color:var(--band-ink);font-size:clamp(1.6rem,2.8vw,2.3rem);font-weight:400;margin:12px 0 22px}
.las-footer .f-in{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:40px;padding-top:56px}
.las-footer .f-in.cols5{grid-template-columns:1.6fr 1fr 1fr 1fr 1fr}/* unlocked: + Aide column */
.las-footer .f-in>div:first-child p{max-width:34ch;line-height:1.6;font-size:.92rem;margin-top:16px}
.las-footer .flogo{height:48px;margin-bottom:4px}
/* ^ invert+screen died the same stacking-context death as the hero pieces (the lifted
   z-index:1 .wrap isolates the blend → the inverted plate painted raw BLACK). The footer
   now uses a pre-baked white-alpha logo from make-cel-assets.mjs instead of blending. */
/* Column headings gold to match the personal-site footer (Connor 2026-07-22). --promo-hi is the
   real gold; --gold is satin silver under saturne. On the dark footer band gold reads warm and
   is the one place it clearly earns its keep. */
.las-footer h5{color:var(--promo-hi,var(--gold));font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;margin-bottom:14px}
/* Social row, cloned from the personal-site footer: circular buttons on the dark band. */
.las-footer .f-in a{color:var(--band-mute);display:block;padding:5px 0;font-size:.92rem}.las-footer .f-in a:hover{color:var(--band-ink)}
/* .f-social AFTER .f-in a on purpose — the social row sits inside .f-in, the selectors tie on
   specificity, and source order decides. With the order reversed, .f-in a's display:block +
   padding:5px shoved every icon to the top-left of its circle (Connor 2026-07-25). */
.las-footer .f-social{display:flex;gap:12px;margin-top:20px}
.las-footer .f-social a{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;padding:0;border-radius:50%;background:rgba(255,255,255,.08);color:var(--band-mute);transition:background-color .18s ease,color .18s ease}
.las-footer .f-social a:hover{background:var(--promo-hi,var(--gold));color:var(--band)}
.las-footer .f-social svg{width:18px;height:18px}
/* The Saturn runs bigger than the other five (Connor 2026-08-11: "make the saturne icon a bit
   bigger"). It is not a taste tweak, it is an optical correction: measured off the geometry, the
   five logo glyphs paint 83-92% of their 24-box width and ~87% of its height, while a ringed
   planet is a wide FLAT shape — the ellipse spans 79.6% of the width but only 42.5% of the
   height, so at a matched 18px box it reads as the small one in the row. 24px brings its painted
   height to ~10.2px against the siblings' ~15.7px. It cannot ever reach them without redrawing
   the mark, and the mark is settled (round 13). Everything else about the row is untouched: the
   38px circle, the 12px gap and the five other glyphs all hold. */
.las-footer .f-social a.f-saturn svg{width:24px;height:24px}
/* Footer cross-reference button (2026-08-09) — mirrors klymenko.fr's bookshop button.
   Selector carries .f-in a's specificity: the footer link rule (display:block, padding:5px,
   band-mute text) was flattening the .btn into a white bar with unreadable text. */
.las-footer .f-in a.f-consult{display:inline-flex;margin-top:22px;padding:14px 24px;color:#111;font-size:.76rem}
.las-footer .f-in a.f-consult:hover{color:#111;background:#ece4d6}
/* LA LETTRE in the footer (2026-08-09) — the newsletter's new home, structure cloned from the
   site's a-foot footer: gold label, white pill with the gold submit inside it, RGPD line under. */
.las-footer .foot-lettre{margin-top:26px;max-width:360px}
.las-footer .foot-lettre .lab{color:var(--promo-hi,var(--gold));font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;font-weight:600;margin-bottom:10px}
.las-footer .foot-lettre .inpill{display:flex;align-items:stretch;background:#fff;border-radius:6px;overflow:hidden}
.las-footer .foot-lettre input{flex:1 1 auto;min-width:0;border:none;background:transparent;padding:13px 14px;font-family:Inter,sans-serif;font-size:.92rem;color:#1C1A17;outline:none}
.las-footer .foot-lettre input:focus-visible{outline:2px solid var(--promo-hi,#C9A35C);outline-offset:-2px}
.las-footer .foot-lettre .inpill button{border:none;cursor:pointer;background:var(--promo-hi,#C9A35C);color:#26200F;font-family:Inter,sans-serif;font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;font-weight:600;padding:0 18px}
.las-footer .foot-lettre .inpill button:hover{background:#AC8B4E}
.las-footer .foot-lettre .sub{font-size:.76rem;line-height:1.55;color:var(--band-mute);margin:10px 0 0}
.las-footer .foot-lettre .sub a{display:inline;padding:0;text-decoration:underline;text-underline-offset:2px}
.las-footer .f-cta .btn{color:#111}
.las-footer .copy{border-top:1px solid var(--band-line);margin-top:44px;padding-top:22px;display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;font-size:.82rem;color:var(--band-mute)}
.las-footer .copy .soc{display:flex;gap:18px}
.las-footer .copy .soc a{display:inline;padding:0}

/* palette switcher (DEV — strip before launch) */
#pal{position:fixed;bottom:18px;right:18px;z-index:90;background:var(--card);border:1px solid var(--line);border-radius:100px;padding:6px 7px;display:flex;gap:4px;align-items:center;box-shadow:0 14px 34px -12px rgba(0,0,0,.45)}
#pal .lab{font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--mute);padding:0 8px}
#pal button{border:0;cursor:pointer;border-radius:100px;padding:8px 13px;font-size:.7rem;font-weight:500;color:var(--ink);background:transparent;transition:.15s;white-space:nowrap}
#pal button:hover{background:var(--alt)}
#pal button.on{background:var(--accent);color:var(--on-accent)}

/* Nav switches to the burger drawer at 1400px, not 900px (2026-07-19). The four links need
   ~587px and the centred logo forces both side columns equal, so the row only fits above
   ~1400px — between 901 and 1400 (1366 and 1280 laptops included) "Contact" dropped to a
   second line. Verified by stepping the container: 1 row at 1440+, 2 rows at 1366 and below.
   The drawer already exists and carries the same links, so this is a clean either/or. */
@media(max-width:1400px){
  .nav-links{display:none}
  .nav-in{grid-template-columns:auto 1fr auto}
  .burger{display:inline-flex}
}
@media(max-width:900px){
  .nav-in{height:68px}
  .logo-img{height:46px}
  .nav-ic svg.ic:not(.ic-mob){display:none}
  .nav-ic .ic-mob{display:block}
  /* Hide the desktop bag LINK on phones, not just its icon: it stayed a 20x20 invisible click box
     next to the 41x41 mobile bag (measured 2026-08-29 at 390). */
  .nav-ic a:not(.ic-mob){display:none}
  .nav-ic a.ic-mob{display:block}
  .lang{display:none}/* language pill moves into the mobile drawer */
  .prow{grid-template-columns:repeat(2,1fr);gap:16px}
  .pdp-grid{grid-template-columns:1fr;gap:2.2rem;max-width:420px;margin:0 auto}
  .parc{grid-template-columns:1fr}
  .about-in,.integ-in,.news-card,.objrow,.release{grid-template-columns:1fr;gap:30px}
  /* Objets tiles, round 13 (Connor 2026-08-10: "the pattern of things and the space in between
     them just looks weird"). The tiles keep desktop's 1.7rem title and 34px padding on a 322px
     card, so "Bougies des planètes" wrapped to two lines, made that tile's text block taller than
     its neighbours, and pushed it up out of the scrim's dark zone (the gradient is only opaque
     below 58%) — the title landed ON the candles and the three titles sat at three different
     heights down the column. One-line titles and a tighter text block put all three back on the
     same rhythm and back in the dark. */
  /* Intégrale banner, round 13 (Connor 2026-08-10: "why is it left aligned and not centre
     aligned?"). Its body is a 600px block pinned to the left of a full-bleed image, which is
     right on a wide screen and wrong on a phone: at 390 the block IS the whole width, so
     left-setting just made the button look dropped in the corner. The scrim also ran left-to-
     right, so its dark end no longer sits under the text once the text is centred — it becomes
     bottom-up here, which is also what stops the headline landing on the bright half. */
  .integ-banner .ib-scrim{background:linear-gradient(0deg,rgba(6,5,3,.92) 0%,rgba(6,5,3,.8) 50%,rgba(6,5,3,.7) 100%)!important}
  .integ-banner .ib-body{max-width:none!important;text-align:center}
  .integ-banner .ib-cta{width:100%}
  .tc{min-height:340px}
  .tc .tx{padding:22px}
  .tc h3{font-size:1.35rem;margin-bottom:4px}
  .tc p{font-size:.9rem;margin-bottom:14px}
  .reco3{grid-template-columns:1fr}
  .news-card{padding:34px 28px}
  /* .cols5 (unlocked builds) out-specified the plain .f-in rule here, so the footer stayed
     5 columns wide on a phone and clipped off-screen — exactly the state Connor reviews on
     the review URL. Both variants now collapse (Connor 2026-08-07 round 3: "the footer is
     completely broken on mobile"). */
  .las-footer .f-in,.las-footer .f-in.cols5{grid-template-columns:1fr 1fr;gap:30px 22px}
  /* Round 9: the brand column now carries the consultation button + the La lettre pill, whose
     min-content width blew past a half-width track and shoved the link columns off-screen.
     Full row for the brand block; the link columns pair up beneath it. */
  .las-footer .f-in>div:first-child{grid-column:1/-1;min-width:0}
  .las-footer .foot-lettre{max-width:none}
  /* Legal bottom bar, round 13 (Connor 2026-08-10: the legal links are "far too long" on mobile).
     .copy .soc is a nowrap flex row with an 18px gap — on the unlocked build that is four legal
     links on one line at 390, so it squashed and ran off. Wrap it, tighten the gap, and let the
     row centre under the © line instead of fighting space-between. */
  .las-footer .copy{margin-top:32px;padding-top:18px;gap:10px;justify-content:center;text-align:center}
  .las-footer .copy .soc{flex-wrap:wrap;justify-content:center;gap:6px 16px}
  .las-home section{padding:56px 0}
  .rotating-text-wrapper{width:100vw;font-size:.6rem;letter-spacing:1px;padding:0 12px}
  /* The ASTRO line is 404px at this size and the wrapper is 288-382px wide on phones with
     overflow:hidden, so "−25 %" and "(hors Intégrale)" were both clipped on EVERY page at 320-414
     (measured 2026-08-29; only a phone render shows it). Let it wrap onto two lines and give the
     band the height for them. */
  .promo,.rotating-text-wrapper{height:50px}
  .rotating-text-item{white-space:normal;line-height:1.3;max-width:100%;padding:0 4px}
  /* YT band. Round 3 (2026-08-07) was Connor's verbatim spec — icon + title, description under,
     button under that — which SUPERSEDED here in round 13 (2026-08-10: "on mobile it doesn't
     need a description text, should just be like a thin banner"). The description line carried
     no information the title and the button don't already give, and it was the row that made the
     band four deep. One row now: icon, title, button. 230px → ~80px.
     display:contents promotes the title/desc out of their wrapper into the grid. */
  .ytband{padding:18px 0}
  .ytstrip{display:grid;grid-template-columns:48px 1fr;grid-template-areas:"icon title" "btn btn";gap:14px 12px;align-items:center}
  .ytstrip .l,.ytstrip .l>div{display:contents}
  .ytstrip .ply{grid-area:icon;width:48px;height:34px;border-radius:10px}
  .ytstrip .ply svg{width:18px;height:18px}
  /* one line now it has the whole row to itself: 28 chars at .95rem needs ~195px of the 294 */
  .ytstrip b{grid-area:title;font-size:.95rem;line-height:1.3;margin:0}
  /* the row that had to go — the button and title already say it */
  .ytstrip .l span{display:none}
  .ytstrip .r{grid-area:btn;display:flex}
  /* stays full-width and full-size: the readers are older, so this is the wrong place to shrink */
  .ytstrip .r .btn{width:100%;padding:12px 18px}
  /* Round 5: best-seller text back to LEFT (with the cover at the rail and the seal on its
     corner, centred text underneath read as another half-and-half mix). Uniform full-width
     CTAs stay — that part of round 3 landed. */
  .release .acts,.about .acts{flex-direction:column;gap:10px}
  .release .acts .btn,.about .acts .btn{width:100%}
  .about .portrait{max-width:300px;justify-self:center}
  /* Round 4: centred eyebrow/h2 over left paragraphs was "half central and half left" —
     the La maison text block is ALL left again; only the portrait centres. */
  /* Intégrale: the 18-volume photo leads, text follows (round 3: "I don't know why you put
     the photo of the books at the very bottom"). Price scaled for 390 and the CTA matches
     the full-width buttons every other section now uses. */
  .integ-in .composite{order:-1}
  .integ .price{font-size:2.3rem}
  .integ .pr{margin-bottom:18px}
  .integ-in .btn{width:100%}
  /* Dark bands: the navy goes FLAT on mobile — no paper grain, no star specks (round 3:
     "remove this on mobile… see it on the YouTube section… the footer as well"). */
  .grain-d::after{display:none}
  .las-footer.f-stars::before{display:none}
  /* Newsletter, round 4: "part of the actual form" — the button is GLUED to the field as one
     control (shared radius, no gap). The round-3 overflow cause was the grid item's implicit
     min-width:auto: the nowrap flex row set the column's min-content wider than the track and
     pushed the button off the card edge. min-width:0 on the grid child is the real fix. */
  .news-card .formside{min-width:0}
  .news-card .formside form{display:flex;flex-wrap:nowrap;align-items:stretch;gap:0;width:100%;max-width:100%}
  .news-card input{flex:1 1 auto;min-width:0;border-radius:6px 0 0 6px;border-right:none}
  .news-card .formside form .btn{flex:0 0 auto;border-radius:0 6px 6px 0;padding:0 16px;font-size:.7rem}
  #pal{left:auto;right:14px;bottom:14px;padding:6px}
  #pal .lab{display:none}
  #pal button{width:24px;height:24px;padding:0;border-radius:50%;font-size:0;border:2px solid var(--line)}
  #pal button[data-p=oxblood]{background:#8E2F2F}
  #pal button[data-p=vert]{background:#2F5243}
  #pal button[data-p=prusse]{background:#1F3A5F}
  #pal button[data-p=or]{background:#A8853F}
  #pal button[data-p=saturne]{background:#1C2E4A}
  #pal button.on{border-color:var(--ink);box-shadow:0 0 0 2px var(--bg) inset}
}

/* ── MOBILE CARD PASS (Connor 2026-08-07 round 3) ─────────────────────────────
   Book cards at 390 were 2-up: ~170px wide, ~500px tall — "so tall but so thin" — with the
   cover letterboxed on cream (object-fit:contain in a 5/7 box reads as "pattern around the
   outside"). One horizontal media-card per row instead: cover hard against the left edge,
   title/price/actions right. Applies to the homepage row and the shop grids (the tw build
   has no grid-cols-1, so the collapse lives here; tokens.css loads after tw and wins). */
@media(max-width:640px){
  /* Round 6 — variant B picked from cards-preview.html (Connor: "b is the best for mobile"):
     a 2-up grid of book tiles with a quiet CAPTION under each — 2-line title + price — so the
     cards read as products without a tap. First tap still opens the BUY overlay (buy button +
     Lire plus over the ghosted cover); a tap off the card closes it; tapping an open card's
     caption follows the stretch link to the book page. Desktop unchanged (.pinfo is contents
     everywhere now; only .acts becomes the overlay here). */
  .prow{grid-template-columns:1fr 1fr;gap:20px 14px}
  .pcard{display:block;position:relative;padding:0;border:none;background:none;border-radius:4px}
  .pcard:hover{box-shadow:none;transform:none;border-color:transparent}
  .pcard .cov{aspect-ratio:8/11}
  .pcard .pinfo{display:contents}
  .pcard h3{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:calc(2 * 1.3em);margin:9px 0 0;font-size:.82rem;line-height:1.3;text-align:left;justify-content:flex-start}
  .pcard .price{text-align:left;font-size:.92rem;margin:3px 0 0}
  /* The buy overlay covers the TILE only (same aspect as .cov, pinned to the card top).
     Hidden via visibility, NOT display:none — the Shopify iframe initialises inside it, and
     an iframe born in display:none renders 0×0 and stays that way when revealed. */
  .pcard .acts{position:absolute;top:0;left:0;width:100%;aspect-ratio:8/11;z-index:3;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:14px;overflow:hidden;background:color-mix(in srgb, var(--card) 88%, transparent);border-radius:4px;visibility:hidden;opacity:0;pointer-events:none;margin:0}
  .pcard.is-open .acts{visibility:visible;opacity:1;pointer-events:auto}
  .pcard.is-open .cov .bk,.pcard.is-open .cov>img{opacity:.35}
  .pcard .acts .btn{width:100%;padding:11px 10px;font-size:.68rem;white-space:nowrap}
  .pcard .vlink{flex:none}
  /* Collections fan, round 5 (Connor: "make them all the same size… push them out a little
     bit… make the box behind the one in the middle more visible"): three EQUAL covers at
     102px, overlap down to -24 so the middle cover and the panel behind it both read.
     102×3 − 48 = 258px inside the ~278px panel — fits with margins, nothing crops. */
  /* Round 13 (Connor 2026-08-10: the collection covers are "absolutely tiny… need to be a
     little bit bigger and further up"). At 102px in a 200px panel the covers left 67px of dead
     navy above them and still lost 10px off the bottom to the panel edge. Bigger covers close
     the gap from both ends; the side padding drops 22 → 12 to buy the width back, and the
     overlap deepens to -32 so the trio still fits inside the panel. */
  .pc .top{min-height:0;padding:22px 12px 0}
  /* the desktop stack hangs 10px past the panel on purpose; on a phone that bleed plus the ±7deg
     rotation was taking 24px off the outer covers' bottom corners, which is the "cut off" look —
     so the phone stack sits flush instead */
  .pc .stack{margin-bottom:0}
  .pc .stack .thumb{width:112px}
  .pc .stack .thumb:nth-child(2){width:120px}
  .pc .stack .thumb:nth-child(1){margin-right:-34px}
  .pc .stack .thumb:nth-child(3){margin-left:-34px}
}

/* Chart result on a phone (round 3: "make it not as long or like scroll through everything"):
   every position stays, but the planet table scrolls inside itself instead of running the
   modal out to ~3 screens. Funnel CTAs go full-width so the three cards' buttons align. */
@media(max-width:999px){
  .modal .bc-tbl{display:block;max-height:300px;overflow-y:auto;overscroll-behavior:contain}
  .bc-foot .bc-cta>.btn,.bc-foot .bc-mug>.btn,.bc-foot .bc-book>.btn{align-self:stretch;width:100%;text-align:center;justify-content:center}
}
/* The mug funnel card's thumbnail is a square object shot, not a 2/3 book cover. */
.bc-mug .bc-book-img img{aspect-ratio:1/1}

/* ── COOKIE CONSENT: the VENDOR banner never paints. Ported from klymenko.fr 2026-08-28.
   History: the 2026-08-07 restyle that lived here forced #tarteaucitronAlertBig to
   display:flex!important so it could be laid out as two buttons. After Accepter/Refuser the
   vendor hides its banner with an INLINE display:none, which a stylesheet !important beats,
   so the banner stayed painted at opacity:0, pointer-events:auto, z-index 2147483645 across
   the whole bottom strip (1440x70 desktop, 390x163 phone) on every page: Connor 2026-08-28,
   "an invisible div along the bottom strip, impossible to click anything". Measured with
   document.elementFromPoint at bottom-centre returning the invisible #tarteaucitronPersonalize2.
   The restyle is gone. Our own card (#cp-consent) and panel (#cp-panel, end of this file)
   render instead, consent.js muzzles the vendor nodes inline as well, and this rule closes the
   gap before consent.js runs. Nothing of the vendor UI is ever visible. */
#tarteaucitronRoot #tarteaucitronAlertBig,#tarteaucitronRoot #tarteaucitronAlertSmall,#tarteaucitronRoot #tarteaucitronIcon{display:none!important}

/* ── Continuous celestial backdrop (2026-06-25) ───────────────────────────────
   One layer behind the whole homepage: a tiled starfield + Saturn-ring motifs +
   planet dots. Rings bleed off the PAGE edges (intentional) instead of being
   clipped mid-section. Sections sit above it; .alt bands go translucent so the
   sky shows through. Replaces the per-section .orbit rings (now hidden). */
.las-home{position:relative;overflow:hidden}
.las-home > section, .las-home > div:not(.cosmos):not(.modal-scrim){position:relative;z-index:1}
.las-home section.alt{background:color-mix(in srgb, var(--alt) 84%, transparent)}
.las-home .orbit{display:none}            /* retire the clipped per-section rings */
.las-home .deco{display:none}             /* retire the stray gold decorative dots on the homepage */
.cosmos{position:absolute;inset:0;z-index:0;pointer-events:none}

/* association band — "En savoir plus" + "Faire un don" side by side */
.assoc-cta{display:flex;gap:14px;justify-content:center;align-items:center;flex-wrap:wrap;margin-top:6px}
/* 3-up info/step cards (a-propos "restauration" + contact page) */
.steps3{display:grid;grid-template-columns:repeat(3,1fr);gap:22px}
/* Contact page (2026-08-24): only 2 cards there once the form covers "La boutique" directly. An
   inline style override on grid-template-columns would beat the mobile media query below (inline
   specificity always wins), so this is a real class instead. */
.steps3.n2{grid-template-columns:repeat(2,1fr)}
.steps3 .st{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:30px 28px}
.steps3 .num{font-family:'Fraunces',serif;color:var(--gold);letter-spacing:.08em;margin-bottom:12px}
.steps3 h3{font-size:1.3rem;font-weight:500;margin-bottom:8px}
.steps3 .st p{color:var(--mute);font-size:.96rem;line-height:1.7;margin-bottom:0}
.steps3 .st .btn{margin-top:18px}
@media(max-width:900px){.steps3,.steps3.n2{grid-template-columns:1fr;gap:16px}}
/* Candles PDP per-candle cards (2026-08-09, "temp sections for each candle" — presentational
   until Fabien unblocks individual sale). The wax column is the votive itself: the planet's
   colour from the product description, a soft top melt, the glyph embossed. A card grows a
   price + buy slot later without changing shape. */
.cndl7{display:grid;grid-template-columns:repeat(7,1fr);gap:18px}
@media(max-width:1100px){.cndl7{grid-template-columns:repeat(4,1fr)}}
@media(max-width:640px){.cndl7{grid-template-columns:repeat(2,1fr);gap:14px}}
.cndl-card{display:flex;flex-direction:column;align-items:center;gap:10px;border:1px solid var(--line);background:var(--card);border-radius:12px;padding:22px 12px 18px;text-align:center}
/* .cndl-wax was a CSS stand-in for a candle, drawn while no photography existed. Fabien sent the
   real seven on 2026-08-13, so the cards carry his own photographs now. Rule kept rather than
   deleted: if a photo is ever missing, the card still has something to draw. */
.cndl-wax{position:relative;width:56px;height:118px;border-radius:10px 10px 4px 4px;background:linear-gradient(180deg, color-mix(in srgb, var(--wax) 78%, #fff) 0 9%, var(--wax) 22%);box-shadow:inset 3px 0 5px rgba(255,255,255,.28), inset -4px 0 7px rgba(0,0,0,.16), 0 8px 16px -8px rgba(35,28,18,.35);display:flex;align-items:center;justify-content:center}
.cndl-wax span{color:var(--wink);font-size:1.35rem;line-height:1;opacity:.85}
/* The photographs are 3:4 and all seven are framed identically, so the tiles need no cropping:
   object-fit contain keeps every candle at its true proportions and the shots already agree on
   scale. cover would crop the lids and the planet glyphs, which are the whole point. */
.cndl-photo{width:100%;max-width:150px;aspect-ratio:3/4;object-fit:contain;border-radius:8px;display:block;background:var(--alt)}
.cndl-name{font-size:1.05rem;color:var(--ink)}
.cndl-col{font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
/* The seven are buyable one at a time now, so each card is a link to its own product page and
   carries its price. Hover lifts it the same way .pcard does, so the two card families behave
   alike rather than one being inert. */
.cndl-card{text-decoration:none;transition:box-shadow .3s,transform .3s,border-color .3s}
a.cndl-card:hover{box-shadow:0 18px 34px -22px rgba(30,20,12,.5);transform:translateY(-3px);border-color:var(--accent)}
.cndl-price{font-size:.9rem;color:var(--accent);font-weight:600}
/* Honest stand-in for a buy button on a product the checkout does not know about yet. */
.soon{display:flex;flex-direction:column;gap:6px;padding:14px 16px;border:1px dashed var(--line);border-radius:4px;background:var(--alt);font-size:.82rem;color:var(--mute);margin-bottom:1.8rem}
.soon a{color:var(--accent);font-weight:600;text-decoration:none}
.soon a:hover{text-decoration:underline}
.assoc-cta .shopify-embed-slot{display:inline-flex}

/* objets — designed "soon" placeholder for the t-shirt card (awaiting a real photo) */
.tc-soon .ph{background:linear-gradient(150deg,color-mix(in srgb, var(--band) 88%, #000),color-mix(in srgb, var(--band) 40%, #000) 70%)}
.tc-icon{position:absolute;top:38%;left:50%;transform:translate(-50%,-50%);width:64px;height:64px;color:var(--gold);opacity:.4;z-index:2}

/* mobile nav: give the burger + bag icons breathing room from the screen edges */
@media(max-width:900px){
  .nav-in{padding-left:20px;padding-right:20px}
  .promo{padding:0 16px}
}

/* (Consent banner brand skin removed 2026-08-28: the vendor banner is hidden outright, see the
   COOKIE CONSENT block above; the styled UI is #cp-consent / #cp-panel at the end of this file.) */

/* ── "Parchemin" — Fabien's own proposal, his message 2026-08-11 ────────────────────────────
   His three colours, verbatim: Parchment #F5F1E8, Prussian Blue #0B2D48, Saturnian Copper
   #B87333. His reasoning: parchment is "warmer and more refined, closer to the world of antique
   books, libraries and traditional publishing"; prussian keeps "the depth and seriousness";
   copper is "more distinctive and sophisticated than a classic gold ... old book bindings,
   engravings".

   ⚠️ THIS IS A THIRD COMBINATION NOBODY HAS SEEN, including him. The panels he was shown
   compared copper on dark navy against gold on parchment. He has asked for COPPER ON PARCHMENT
   — the light ground with the warm accent — which neither panel rendered.

   It is also a direct answer to the fault this file already records at line 47: the saturne
   palette "had no warm or bright colour anywhere ... everything sat in the same low-chroma band
   and the site read as dead", which is why --promo-hi and the gold eyebrow had to be added back
   piecemeal. Copper as the actual accent removes the need for both patches.

   Only the three hexes are his. Every other value here is DERIVED from them (tints, shades and
   desaturations) rather than picked — no new brand colour is introduced.

   Added as a switchable palette, exactly like saturne was, so both serve at once and can be
   compared before anyone commits. Nothing above this line is modified. */
html[data-palette="parchemin"] {
  --bg:#F5F1E8; --alt:#EBE5D8; --card:#FDFBF6; --ink:#0B2D48; --mute:#5A6B7C; --line:#DFD8C8;
  /* ⚠️ CORRECTED 2026-08-11 (Connor). First pass set BOTH --accent and --promo-hi to copper,
     which collapsed the two-button pair: .btn-ox reads --accent and .btn-ink reads
     --promo-hi, so "Découvrir le livre / Toute la collection" rendered copper on copper, and
     the cookie bar showed two identical copper buttons. Saturne pairs prussian with gold; this
     palette must pair prussian with COPPER. Structure mirrors saturne one-for-one, gold→copper.
     Blue stays the structural colour. Copper is the metal, not the primary. */
  --gold:#B87333; --on-accent:#F5F1E8;
  --promo-hi:#B87333;
  /* Eyebrows follow the metal, exactly as saturne does — this is what took the small uppercase
     labels off 2.13:1 and is the measured win, so it must survive the correction.
     Re-measured 2026-08-11 when saturne's gold eyebrow had to be deepened: copper needs no such
     fix, it already clears on every light ground here — 3.36:1 on #F5F1E8, 3.02:1 on #EBE5D8,
     3.67:1 on #FDFBF6. Left on the metal verbatim, and --gold-on-light points at the same copper
     so this palette answers that token too rather than inheriting saturne's deepened gold. */
  --gold-on-light:var(--promo-hi);
  --eyebrow-ink:var(--promo-hi);
  /* ⛔ CORRECTED AGAIN 2026-08-24 (Connor: "the blue on the planet doesn't look like the same
     sort of blue that's on the icons... make it match the live blue"). The 08-11 fix flagged
     this and left it unresolved ("worth a look at whether buttons read near-black against the
     band") — it does. His brief's #0B2D48 is a step darker than logo-las-prusse.webp's actual
     navy, same class of problem saturne already hit and fixed the same way: sampled off the
     wordmark (averaged a clean patch of the planet body, 2026-08-24) rather than the brief's
     literal value. Both palettes share the one logo file, so this palette now uses saturne's
     own --accent/--accent-dk/--band verbatim — "blue stays the structural colour" (comment
     above) means literally the same blue, not a separate near-miss. --band follows on the same
     ratio it always did, now against the corrected --accent. */
  --band:#16253B; --band-ink:#F5F1E8; --band-mute:#9FB3C6; --band-line:rgba(255,255,255,.16);
  --accent:#1F3B5F; --accent-dk:#16293F;
  --pc-top:#16253B;
  /* Secondary CTA stays a dark neutral and never a third colour, as saturne does. */
  --btn-2:#22262C; --btn-2-dk:#15181C;
  --eyebrow-on-dark:#EBD9C4;
  --b-card:#FDFBF6; --b-rule-dk:#CFC6B2;
}

/* Copper button text: white, for consistency with every other filled button on the site
   (Connor 2026-08-11). Scoped to this palette so saturne's gold button keeps its dark ink,
   where the pairing is correct. Measured: dark #26200F on copper is 4.27:1, white is 3.79:1,
   so this is a small step DOWN in contrast bought for consistency — a deliberate trade, noted
   rather than hidden. Both sit under the 4.5 AA line for 12px bold either way; if it ever needs
   to clear it, deepening the copper for the button role only is the lever, not the text. */
html[data-palette="parchemin"] .btn-ink{color:#26200F}
html[data-palette="parchemin"] .btn-ink:hover{color:#26200F}

/* ══ CHART RESULT: ONE FRAME, NO DESKTOP SCROLL (Connor 2026-08-13) ══════════════════════════
   "I want zero vertical scroll on desktop, zero. I don't want to have to scroll down to see the
   action... they're just gonna press the X instead."

   Measured before touching it, which is where the budget comes from. The modal stood 975px at
   1440x900 and 998px at 1280x800 against a 752px usable box, so it overflowed by 123px, 163px
   and 246px at the three common laptop sizes. Components were wheel 440, big-three tiles 95,
   position table 404, CTA row 258.

   The fix is a height budget, not a nudge: the wheel is sized from the VIEWPORT rather than a
   fixed 440, the table rows tighten, and the CTA row becomes one compact band. Nothing is
   removed, and the three actions are on screen without scrolling, which was the whole point. */
@media (min-width:1000px){
  .modal-scrim:has(.modal.is-chart){padding:16px;overflow:hidden}
  .modal.is-chart{max-height:calc(100dvh - 32px);display:flex;flex-direction:column;
    padding:24px 30px 22px;margin:0}
  /* The wheel answers to the window, and it FILLS the left column. The position list is the
     taller of the two columns, so any height the wheel takes below that costs nothing and the
     300px of dead space under the big-three tiles disappears. Capped at 54dvh so it still gives
     height back on a short laptop, which is what keeps the actions on screen. */
  /* 42dvh, measured not guessed: at 1280x800 the modal already fills its box exactly, so there
     is NO spare height there and a bigger wheel simply overflows (54dvh cost 42px). Keeping the
     cap viewport-relative lets a 1920 screen draw a 453px wheel while a 1280 laptop draws 336
     and still shows all three actions without scrolling. */
  .modal.is-chart #chart-result svg{max-width:min(520px,42dvh) !important;width:100% !important}
  .modal.is-chart #chart-result{display:flex;justify-content:center}
  .modal.is-chart .bc-tiles{max-width:520px;margin-left:auto;margin-right:auto}
  /* the position list carried 40px a row for ten rows; 29px keeps all ten and returns ~110px */
  .modal.is-chart .bc-tbl td{padding:4px 0}
  .modal.is-chart .bc-tbl{font-size:.86rem}
  .modal.is-chart .bc-tiles{margin-top:14px;gap:8px}
  .modal.is-chart .bc-tile{padding:8px 6px}
  .modal.is-chart .bc-title{font-size:1.35rem}
  /* the actions become a band, not three tall boxes: thumb left, copy and button right */
  .modal.is-chart .bc-foot{margin-top:18px;padding-top:16px}
  .modal.is-chart .bc-foot .bc-cta,
  .modal.is-chart .bc-foot .bc-book,
  .modal.is-chart .bc-foot .bc-mug{padding:13px 15px}
  .modal.is-chart .bc-foot .bc-cta-t,
  .modal.is-chart .bc-foot .bc-book-t{font-size:.92rem;margin:0 0 4px}
  .modal.is-chart .bc-foot .bc-cta-p,
  .modal.is-chart .bc-foot .bc-book-p{font-size:.78rem;line-height:1.45;margin:0 0 10px;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .modal.is-chart .bc-foot .bc-book-img img{width:44px}
  .modal.is-chart .bc-foot .btn{padding:9px 16px;font-size:.64rem}
  .modal.is-chart .bc-asp{margin-top:10px}
  .modal.is-chart .bc-asp>summary{padding:8px 0 2px}
}
/* Phone keeps its vertical scroll, deliberately: everything cannot fit and Connor said so.
   The wheel pins to the top while the position list scrolls under it, so the chart you came for
   never leaves the screen. */
@media (max-width:999px){
  .modal.is-chart #chart-result{position:sticky;top:0;z-index:3;background:var(--bg);
    padding-bottom:10px;margin-bottom:2px}
  .modal.is-chart #chart-result svg{max-width:min(320px,38dvh) !important}
}

/* ── #cp-consent: OUR consent card, ported from klymenko.fr (site/assets/tokens.css) on
   2026-08-28 and mapped onto the store tokens: card paper, prussian ink, Inter body, Fraunces
   title, copper (--promo-hi) for the icon, the section labels and Accepter, ink for Refuser —
   the same pairing as every .btn-ink / .btn-ox pair on the site, so the two buttons carry
   equal weight (CNIL: refusing as easy as accepting). Square 2px corners on the buttons like
   every other button here, 12px on the card like .pcard. All layout lives here, no vendor
   selector can touch it. Bottom-centred, never screen-centred: dead centre put an invisible
   hover wall over the nav dropdown on klymenko.fr. */
#cp-consent{
  position:fixed; bottom:16px; left:50%; transform:translateX(-50%); z-index:2147483000;
  width:min(400px, calc(100vw - 32px)); box-sizing:border-box;
  background:var(--card); color:var(--ink);
  border:1px solid var(--line);
  border-radius:12px; padding:24px 24px 20px;
  box-shadow:0 18px 50px rgba(11,45,72,.22);
  font-family:'Inter',system-ui,-apple-system,sans-serif;
}
/* #cp-panel = the management panel opened from the footer (Gestion des cookies, #consentements).
   Same card language, CENTRED as a modal, with a plain × and the recorded choice. It replaces
   the vendor panel entirely — see consent.js. Scrolls inside itself on a short viewport. */
#cp-panel{
  position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:2147483000;
  width:min(440px, calc(100vw - 24px)); box-sizing:border-box;
  max-height:min(86vh, 720px); overflow-y:auto; overscroll-behavior:contain;
  background:var(--card); color:var(--ink);
  border:1px solid var(--line);
  border-radius:12px; padding:24px 24px 20px;
  box-shadow:0 18px 50px rgba(11,45,72,.22);
  font-family:'Inter',system-ui,-apple-system,sans-serif;
}
#cp-panel .cp-x{ position:absolute; top:10px; right:12px; background:none; border:0;
  color:var(--mute); font-size:24px; line-height:1; cursor:pointer; padding:4px 8px; }
#cp-panel .cp-x:hover{ color:var(--ink); }
#cp-panel .cp-sec{ margin:16px 0 0; }
#cp-panel .cp-lab{ display:block; font-size:.68rem; letter-spacing:.14em; text-transform:uppercase;
  font-weight:600; color:var(--eyebrow-ink); margin:0 0 6px; }
#cp-panel .cp-note{ margin:0 0 12px; color:var(--mute); font-size:.82rem; line-height:1.55; }
#cp-panel .cp-static{ display:inline-block; border-radius:100px; padding:8px 16px;
  font-size:.7rem; font-weight:600; letter-spacing:.07em; text-transform:uppercase;
  color:var(--mute); background:var(--alt); }
#cp-panel .cp-hr{ height:1px; background:var(--line); margin:18px 0 2px; }
/* One measured cookie per row: name and lifetime on the top line, what it is for underneath. */
#cp-panel .cp-ck{ display:grid; grid-template-columns:1fr auto; gap:1px 12px; padding:9px 0;
  border-top:1px solid var(--line); }
#cp-panel .cp-ck:first-of-type{ border-top:0; padding-top:2px; }
#cp-panel .cp-ck code{ font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.74rem;
  color:var(--ink); overflow-wrap:anywhere; }
#cp-panel .cp-ck em{ font-style:normal; font-size:.66rem; letter-spacing:.04em; white-space:nowrap;
  color:var(--mute); align-self:center; }
#cp-panel .cp-ck span{ grid-column:1 / -1; font-size:.76rem; line-height:1.5; color:var(--mute); }
#cp-panel .cp-sec .cp-static{ margin-top:12px; }
/* The pair shows the RECORDED choice: both keep their fill (no outline buttons anywhere in the
   consent UI), the un-chosen one just sits dimmed. Guarded by :has because before ANY choice
   both are aria-pressed="false" and dimming the whole pair reads as a disabled panel. */
#cp-panel .cp-row:has(button[aria-pressed="true"]) button[aria-pressed="false"]{ opacity:.45; }
#cp-panel .cp-row:has(button[aria-pressed="true"]) button[aria-pressed="false"]:hover{ opacity:1; }
#cp-consent .cp-head, #cp-panel .cp-head{ display:flex; align-items:center; gap:10px; margin:0 0 10px; }
#cp-consent .cp-head svg, #cp-panel .cp-head svg{ width:24px; height:24px; color:var(--promo-hi,var(--gold)); flex:none; }
#cp-consent .cp-title, #cp-panel .cp-title{ font-family:'Fraunces',Georgia,serif; font-weight:500;
  font-size:1.35rem; line-height:1.1; color:var(--ink); }
#cp-consent .cp-text, #cp-panel .cp-text{ margin:0 0 16px; color:var(--mute); font-size:.85rem; line-height:1.55; }
#cp-consent .cp-row, #cp-panel .cp-row{ display:flex; gap:10px; }
#cp-consent .cp-row button, #cp-panel .cp-row button{
  flex:1 1 0; min-width:0; min-height:44px; cursor:pointer; border:1px solid transparent; border-radius:2px;
  padding:12px 8px; font-family:inherit; font-size:.72rem; font-weight:600;
  letter-spacing:.07em; text-transform:uppercase; line-height:1.2;
  white-space:normal; overflow-wrap:anywhere;
  transition:background-color .2s ease,color .2s ease;
}
#cp-consent .cp-row button:focus-visible, #cp-panel .cp-row button:focus-visible, #cp-panel .cp-x:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
/* Copper with white text, exactly as .btn-ink renders under the parchemin palette (its
   measured 3.79:1 is a noted trade for consistency with every filled copper button). */
#cp-consent .cp-accept, #cp-panel .cp-accept{ background:var(--promo-hi,var(--gold)); color:#FFFFFF; }
#cp-consent .cp-accept:hover, #cp-panel .cp-accept:hover{ background:color-mix(in srgb, var(--promo-hi,var(--gold)) 86%, #000); }
#cp-consent .cp-refuse, #cp-panel .cp-refuse{ background:var(--ink); color:var(--bg); }
#cp-consent .cp-refuse:hover, #cp-panel .cp-refuse:hover{ background:var(--accent); }

/* ── ALIGNMENT FIXES 2026-09-14 (live audit, Connor: "an alignment issue on the live client site") ── */
/* Live audit 2026-09-14: every rule below was measured broken on the live site, then proven by injection on all 34 pages
   (Chromium 26 widths + WebKit 14 widths, FR and EN, overlay/FAQ/read-more states, Shopify buttons mounted) to fix its fault
   and move nothing outside its own component. Evidence and the rules left out: agency-admin/outputs (alignment fixes 2026-09-14). */
/* c1: Wrapped button labels sat flush left inside centred .btn boxes (91 cases; boxes do not move). */
.btn{text-align:center}
/* c5: Card links (Voir la collection / Voir l'ouvrage) wrapped flush left. */
.pcard .vlink{text-align:center}
/* c4: Phone tap overlay: the collection card label ran past both edges of its button (collection card only). */
@media(max-width:640px){.pcard:has(.pc-cov) .acts .btn{white-space:normal;line-height:1.25}}
/* c2: La maison recommande: the collection card has one action fewer than the book cards, so its price dropped below the row line leaving a hole under the title. A spacer that can only absorb free space (never adds height) fills the Commander slot; tighter side padding stops the label wrapping where Ajouter does not. */
@media(min-width:641px){.pcard:has(.pc-cov) .acts .btn{padding-left:12px;padding-right:12px}.pcard:has(.pc-cov) .pinfo::after{content:"";order:1;flex:1 0 0;max-height:67px}.pcard:has(.pc-cov) .acts{order:2}}
/* c13: Menu drawer could not scroll: Contact, Consultations and the language switcher unreachable on short or landscape phones. */
.drawer{overflow-y:auto;overscroll-behavior:contain}
/* c15: Integrale plate 960-1250: six rows of covers spread apart with gaps bigger than the books (bundle only, not the collection pages). */
@media (min-width:901px) and (max-width:1259px){.pdp-grid.pdp-bundle:not(:has(.coll-plate)){align-items:start}.pdp-bundle .integ-plate:not(.coll-plate){height:auto;justify-content:flex-start;gap:8px;position:sticky;top:96px}}
/* c17: Header logo 38px left of centre at 901-1400 and 5.5px right at 320-900: side columns were unequal. */
@media(max-width:1400px){.nav-in{grid-template-columns:1fr auto 1fr}}
/* c18: #mugs and the CGV formulaire-type anchor landed under the 79px sticky header. */
#mugs,.legal [id]{scroll-margin-top:100px}
/* c24: Shop Integrale banner at 320-344: wrapped price line hugged the left with a dangling separator. */
@media(max-width:900px){.integ-banner .ib-line{justify-content:center}}@media(max-width:344px){.integ-banner .ib-sep{display:none}}
/* ── FIXES ROUND 2, 15 Sept 2026 (Connor rulings) ── */
/* k1: Footer on phones: one link column per row (Connor ruling 12) */
@media(max-width:640px){.las-footer .f-in,.las-footer .f-in.cols5{grid-template-columns:1fr}}
/* k2: Links in legal and contact text: text colour plus underline (Connor 14 Sept rule) */
.legal a:not(.btn),main p a:not([class]){color:inherit;text-decoration:underline;text-underline-offset:2px}
/* k3: Closed menu drawer 1px line down the left edge at 320-375 (ruling 13) */
.drawer:not(.open){transform:translateX(calc(-100% - 4px))}
/* k6: Menu drawer compact on short screens so it fits one screen (ruling 14) */
@media(max-height:700px){.drawer .x{margin-bottom:10px}.drawer a{font-size:1.12rem;padding:9px 0}.drawer-lang{margin-top:12px}.drawer-lang-lab{margin-bottom:8px}}
/* k7: PRÉCOMMANDE tag sits on the card edge, off the cover (ruling 5) */
.pcard .pre-chip{top:-11px;right:12px}.pcard.is-open .pre-chip{opacity:0}
/* k4c: La maison recommande at 901-1179: 3 per row showing exactly 3 cards (full rows only) */
@media(min-width:901px) and (max-width:1179px){.prow{grid-template-columns:repeat(3,1fr)}.prow>.pcard:nth-child(n+4){display:none}}
/* k5b: Shop grid: 3 books per row from 768px up, so 18 books always make full rows */
@media(min-width:768px){#livres .grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* k8: Collection pages: every book shows, and a short last row is centred */
#coll-books .grid{display:flex;flex-wrap:wrap;justify-content:center}#coll-books .grid>*{width:calc((100% - 1.5rem)/2)}@media(min-width:768px){#coll-books .grid>*{width:calc((100% - 3rem)/3)}}

/* ── FIXES ROUND 3, 15 Sept 2026 (Connor rulings) ── */
/* r3c-social: Footer social icons stay round at 320-355 (they squashed to 32x38 ovals) */
@media(max-width:355px){.las-footer .f-social{gap:clamp(8px,calc((100% - 228px) / 5),12px)}.las-footer .f-social a{height:auto;aspect-ratio:1/1}}
/* r3c-news: Newsletter placeholder "vous@exemple.fr" not cut at 320-359 */
@media(max-width:359px){.las-footer .foot-lettre input{padding-left:12px;padding-right:6px}.las-footer .foot-lettre .inpill button{padding-left:12px;padding-right:12px}}
/* r3c-siren: Footer legal line: SIREN number and postcode never split (needs the html patch) */
.las-footer .copy .nw{white-space:nowrap}
/* r3c-chips: Menu language chips on one row on phones (IT was alone on a second row at 320-396) */
@media(max-width:410px){.drawer-lang-row{gap:6px}.drawer-lang-row button{padding-left:clamp(7px,calc((100% - 124px) / 10),13px);padding-right:clamp(7px,calc((100% - 124px) / 10),13px)}}
/* r3c-promo: Translated promo bar: the whole "shipped the next day" line highlighted (Google moved the bold edge mid-phrase); French untouched */
html.translated-ltr .promo .rotating-text-item:nth-child(2){color:var(--promo-hi,var(--gold));font-weight:700}
/* r3c-cookie: First-visit cookie card hidden while the menu is open (it covered the bottom of the menu), back when the menu closes */
.drawer.open~#cp-consent{visibility:hidden}
/* r3p-mug: Mug photo at its natural shape: no paperback frame, nothing cropped (Connor ruling 17) */
.pdp-obj{aspect-ratio:auto}.pdp-obj img{height:auto}
/* r3p-parc: Book pages, collection card: price level with the book cards even when "Découvrir la collection" wraps (901-935, 1180-1215) */
@media(min-width:641px){.pcard:has(.pc-cov) .pinfo::after{content:none}.pcard:has(.pc-cov) .acts{min-height:152px;justify-content:flex-end}}
/* r3p-divider: Bundle and mug: divider no longer touches the Ajouter button */
.pdp-price + div + hr{margin-top:1.8rem}
/* r3p-ship: English shipping label stays beside the price instead of dropping under it */
.pdp-price{flex-wrap:nowrap}.pdp-price>:first-child{flex:none;white-space:nowrap}.pdp-price .pdp-ship{min-width:0}
/* r3p-faqline: Product pages: no second hairline 80px under the last FAQ row (the section rule below closes it) */
.pdp-faq-inline .pdp-faq details:last-child{border-bottom:0}
/* r3p-plate: Collection hero plate: a short last row of covers is centred (mondiale 3+2, praticien 3+3+2) */
.integ-plate.coll-plate .row:has(> :last-child:nth-child(2)){grid-template-columns:repeat(2,calc((100% - 28px) / 3));justify-content:center}.integ-plate.coll-plate .row:has(> :last-child:nth-child(2))::after{left:calc((100% + 14px) / 6 + 4%);right:calc((100% + 14px) / 6 + 4%)}@media (max-width:760px){.integ-plate.coll-plate .row:has(> :last-child:nth-child(2)){grid-template-columns:repeat(2,calc((100% - 20px) / 3))}.integ-plate.coll-plate .row:has(> :last-child:nth-child(2))::after{left:calc((100% + 10px) / 6 + 4%);right:calc((100% + 10px) / 6 + 4%)}}
/* r3p-eyebrow: Collection pages: gap between the hero eyebrow and the H1 */
.pdp-bundle .eyebrow{display:block;margin-bottom:.5rem}
/* r3p-hero: Homepage headline on phones under 375px: "Le" no longer alone, "astrologique" inside the box */
@media (max-width:374px){.hero.hero-fabien h1{font-size:clamp(2.4rem,12vw,3.1rem)}}
/* r3p-bookcase: Homepage Intégrale bookcase at 641-760: the desktop shelf (6 per row) instead of the phone shelf (1,600px tall) */
@media (min-width:641px) and (max-width:760px){.bookcase{padding:16px 16px 6px;border-width:10px}.bookcase .shelf{grid-template-columns:repeat(var(--per,5),1fr);gap:0 clamp(8px,1.2vw,16px);padding:22px 8px 0}.bookcase .shelf:first-child{padding-top:8px}.bookcase .shelf::after{display:block}}
/* r3p-release: Homepage best-seller on tablets (641-900): cover beside the text, as on desktop, instead of a small cover beside empty space */
@media (min-width:641px) and (max-width:900px){.release{grid-template-columns:260px 1fr;gap:36px}}
/* r3p-hieroz: Hiéroz cover: publisher badge no longer cut off (frame follows the scan, this cover only) */
#book-media-hieroz .pdp-bk{aspect-ratio:502/716}
/* r3t-gutter: Legal pages and 404: text column on the site gutter (34px) instead of 21px on phones and tablets */
#main.max-w-3xl.px-5,#main>.max-w-3xl.px-5{padding-left:clamp(1.25rem,calc(34px - (100vw - 48rem) / 2),34px);padding-right:clamp(1.25rem,calc(34px - (100vw - 48rem) / 2),34px)}#main>.max-w-2xl.px-5{padding-left:clamp(1.25rem,calc(34px - (100vw - 42rem) / 2),34px);padding-right:clamp(1.25rem,calc(34px - (100vw - 42rem) / 2),34px)}
/* r3t-acts: À propos: the two buttons stack as one equal-width column at 901-1048 instead of a staircase */
@media (min-width:901px) and (max-width:1048px){.about .acts:has(.btn+.btn){display:grid;grid-template-columns:max-content;gap:10px}}
/* r3t-labels: Rétractation and contact forms: 6px between each label and its field (was 1.9px) */
.cform label>span{display:block;margin-bottom:6px}
/* r3t-balance: Centred headings: no single word left alone on the last line */
.chead h2,.assoc h2,.text-center>h1,.wrap[style*="text-align:center"]>h1{text-wrap:balance}

/* ── FIXES ROUND 4, 15 Sept 2026 (Connor rulings) ── */
/* r4-promo: promo bar always on ONE line on phones (Connor 15 Sept): short French line under 641px, translated pages sized to fit */
.promo .ps{display:none}.promo .rotating-text-item{white-space:nowrap}@media(max-width:640px){.promo .pl{display:none}.promo .ps{display:inline}html.translated-ltr .promo .rotating-text-item{letter-spacing:0;font-size:clamp(8.5px,2.8vw,10.2px)}}
/* r4-mug: mug page lead photo shows the whole mug; the empty bottom of the photo is trimmed */
.pdp-obj{aspect-ratio:1200/1056;overflow:hidden}.pdp-obj img{height:100%;object-fit:cover;object-position:50% 0}
/* r4-mugbuy: mug blocks on the shop and homepage carry the same three actions as every product card */
.mug-feature-buy{flex-direction:column;align-items:stretch;gap:12px}.mug-feature-buy .price{margin-bottom:4px}.mug-feature-buy .shopify-embed-slot{flex:none;min-width:0}.mug-feature-buy .vlink{display:block;text-align:center;color:var(--band-mute);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;margin-top:4px}
/* r4-about: YouTube icon at the start of the secondary button; hidden on narrow phones where the label wraps, so the text stays centred */
.about .acts .btn .yt{flex:none}@media(max-width:399px){.about .acts .btn .yt{display:none}}
/* r4-banner: shop Intégrale banner a little darker behind the copy, not black */
.integ-banner .ib-scrim{background:linear-gradient(to right,rgba(6,5,3,.92) 0%,rgba(6,5,3,.84) 38%,rgba(6,5,3,.45) 70%,rgba(6,5,3,.14) 100%)!important}@media (max-width:900px){.integ-banner .ib-scrim{background:linear-gradient(0deg,rgba(6,5,3,.9) 0%,rgba(6,5,3,.8) 55%,rgba(6,5,3,.72) 100%)!important}}
/* r4-grid: shop books 4 per row from 1180px, covers a little smaller so the next row starts inside a 1440 laptop screen; the short last row is centred (Connor 15 Sept) */
@media(min-width:1180px){#livres .grid{display:flex;flex-wrap:wrap;justify-content:center}#livres .grid>*{width:calc((100% - 4.5rem)/4)}#livres .pcard .cov{width:74%;margin-inline:auto}}

/* ── 4B: mug price, mug note, cart birth-details box ── */
/* r4b-mugprice: mug block price larger and sitting on its own line above the three actions */
.mug-feature-buy .price{font-size:clamp(1.9rem,2.6vw,2.3rem);line-height:1.1;margin-bottom:6px}
/* r4b-mugnote: where the Astro-Mug birth details go, under the mug's buttons */
.mug-note{font-size:.84rem;line-height:1.55;color:var(--mute);margin:10px 0 0;text-align:center}.mug-feature-buy .mug-note{color:var(--band-mute);margin-top:4px}
/* r4b-mugnote-gap: on the mug page the note sits between the buttons and the divider; keep the divider's 1.8rem of air */
.pdp-price + div + .mug-note{margin-bottom:1.8rem}

/* ── FIXES ROUND 5, 16 Sept 2026 (Connor rulings) ── */
/* r5-parc-acts: collection cards carry the same three actions as every product card (Connor 15-16 Sept); "Voir la collection" styled exactly like "Voir l'ouvrage" */
.parc .pc .acts{display:flex;flex-direction:column;align-items:stretch;gap:12px;width:100%}.parc .pc .acts .shopify-embed-slot{width:100%}.parc .pc .acts .btn{width:100%}
.parc .pc .acts .vlink{position:relative;display:block;align-self:center;text-align:center;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--mute);font-weight:500;margin-top:6px}
.parc .pc .acts .vlink::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:1px;background:var(--accent);transform:scaleX(0);transform-origin:right;transition:transform .35s ease}
.parc .pc:hover .acts .vlink{color:var(--accent)}.parc .pc:hover .acts .vlink::after{transform:scaleX(1);transform-origin:left}

/* ── PRODUCT PAGE vs FITZCARRALDO, 17 Sept 2026 (Connor, side by side at 768 and 1024) ──
   Reference: https://fitzcarraldoeditions.com/books/the-mulai/ (PROJECT-PLAN.md, design references).
   Measured before: our page ran 787px longer at 768 and 558px longer at 1024, and 581/651px of that was
   the "La maison recommande" cards, not the top section. Every card keeps its three actions (ruling 09-15). */
/* p1: the book sits on a pale panel at the width the real-book renders use (340px), so the page block
   and spine read like the Shopify images instead of a flat scan capped at a 13px edge. */
.pdp-panel{display:flex;align-items:center;justify-content:center;padding:clamp(28px,8%,56px) 0;
  background:color-mix(in srgb,var(--alt) 55%,var(--bg))}
.pdp-panel .pdp-bk{width:min(340px,76%);box-shadow:10px 14px 22px -12px rgba(35,28,18,.5)}
/* p2: tablet uses the full width like the reference, instead of a 420px column with empty margins. */
@media(min-width:641px) and (max-width:900px){.pdp-grid:not(.pdp-bundle){max-width:none;gap:1.8rem}}
/* p3: top section spacing. */
.pdp-page .pdp-price{margin-bottom:1.2rem}
.pdp-page .pdp-faq-inline{margin-top:1.8rem;padding-top:1.2rem}
.pdp-page .pdp-faq-inline .pdp-faq summary{padding:12px 2px}
/* p4: La maison recommande, compact: smaller covers, slimmer buttons. Four across only from 1180px; at
   901-1179 ruling k4c's three per row stands (four there wrapped "AJOUTER À MA SÉLECTION" onto two lines).
   Phones keep their tap-overlay card untouched. */
@media(min-width:1180px){.pdp-related .prow{grid-template-columns:repeat(4,minmax(0,1fr));gap:18px}}
@media(min-width:641px){
  .pdp-related .pcard{padding:12px 12px 14px}
  .pdp-related .pcard .cov{aspect-ratio:1/1}
  .pdp-related .pcard .cov .bk{width:58%;margin-right:0}
  .pdp-related .pcard .cov.pc-cov{aspect-ratio:1/1}
  .pdp-related .pcard h3{font-size:.9rem;margin:10px 0 4px}
  .pdp-related .pcard .price{font-size:1rem;margin-bottom:10px}
  .pdp-related .pcard .acts{gap:6px}
  .pdp-related .pcard .acts .btn{padding:10px 10px;font-size:.66rem;letter-spacing:.06em}
  .pdp-related .pcard .vlink{margin-top:4px}
}
