/* ═══════════════════════════════════════════════════════════════
   Patisserie Manon — liquid glass layer (iOS 26 direction)
   Loaded AFTER /assets/site.css and BEFORE each page's inline <style>.
   Overrides site.css. Cannot override page-local rules — by design.
   Spec: docs/UI-GLASS-SPEC.md   Do not edit outside the Foundation phase.
   ═══════════════════════════════════════════════════════════════ */

:root {
  /* — glass tints: backdrop hue-locked, +6pp saturation, +7pp lightness (cap 97%), 58–62% alpha — */
  --glass-tint:         rgba(253, 249, 242, 0.62);   /* on --mn-cream  #F6EEDF -> #FAF5EB */
  --glass-tint-band:    rgba(55, 35, 22, 0.60);      /* on --mn-dark   #1D130C -> #2D1D12 */
  --glass-tint-band-2:  rgba(69, 43, 25, 0.58);      /* on --mn-dark-2 #2A1B10 -> #3A2515 */

  --glass-solid:        #FAF5EB;
  --glass-solid-band:   #2D1D12;
  --glass-solid-band-2: #3A2515;

  --glass-edge:         rgba(255, 255, 255, 0.72);
  --glass-edge-band:    rgba(243, 233, 218, 0.16);
  --glass-divider:      rgba(33, 23, 16, 0.10);
  --glass-fill-2:       rgba(255, 255, 255, 0.42);
  --glass-fill-2-band:  rgba(243, 233, 218, 0.08);

  --glass-sheen:        linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0) 44%);
  --glass-sheen-band:   linear-gradient(180deg, rgba(243,233,218,0.07) 0%, rgba(243,233,218,0) 44%);

  --glass-inner-hi:      inset 0 1px 0 rgba(255, 255, 255, 0.55);
  --glass-inner-hi-band: inset 0 1px 0 rgba(243, 233, 218, 0.10);
  --glass-ring:          0 0 0 0.5px rgba(33, 23, 16, 0.10);
  --glass-ring-band:     0 0 0 0.5px rgba(0, 0, 0, 0.35);
  --glass-drop:          0 18px 44px rgba(56, 37, 22, 0.13), 0 3px 10px rgba(56, 37, 22, 0.07);
  --glass-drop-band:     0 18px 44px rgba(0, 0, 0, 0.42),    0 3px 10px rgba(0, 0, 0, 0.28);

  --glass-blur:    blur(24px) saturate(1.7);
  --glass-blur-sm: blur(14px) saturate(1.5);

  /* — geometry — */
  --r-glass:    22px;
  --r-glass-lg: 26px;
  --r-frame:    var(--r-lg) var(--r-lg) var(--r-md) var(--r-md);  /* 22 22 14 14 */
  --r-btn-sm:   10px;
  --r-btn:      12px;
  --r-btn-lg:   14px;

  --glass-pad:       clamp(20px, 2.6vw, 30px);
  --glass-pad-tight: clamp(14px, 1.8vw, 18px);
  --glass-pad-roomy: clamp(26px, 3.4vw, 40px);

  --icon-size: 18px;
}

html[data-theme="dark"] {
  --glass-tint:         rgba(57, 36, 23, 0.58);   /* on --mn-cream  #1F140D -> #2E1D13 */
  --glass-tint-band:    rgba(49, 28, 13, 0.58);   /* on --mn-dark   #150C06 -> #25150A */
  --glass-tint-band-2:  rgba(55, 35, 22, 0.58);   /* on --mn-dark-2 #1D130C -> #2C1D12 */

  --glass-solid:        #2E1D13;
  --glass-solid-band:   #25150A;
  --glass-solid-band-2: #2C1D12;

  --glass-edge:         rgba(243, 233, 218, 0.14);
  --glass-edge-band:    rgba(243, 233, 218, 0.12);
  --glass-divider:      rgba(243, 233, 218, 0.10);
  --glass-fill-2:       rgba(243, 233, 218, 0.08);

  --glass-sheen:        linear-gradient(180deg, rgba(243,233,218,0.07) 0%, rgba(243,233,218,0) 44%);
  --glass-inner-hi:     inset 0 1px 0 rgba(243, 233, 218, 0.10);
  --glass-ring:         0 0 0 0.5px rgba(0, 0, 0, 0.35);
  --glass-drop:         0 18px 44px rgba(0, 0, 0, 0.42), 0 3px 10px rgba(0, 0, 0, 0.28);
}

/* ── the panel ───────────────────────────────────────────────── */
.glass {
  position: relative;
  border-radius: var(--r-glass);
  padding: var(--glass-pad);
  background-color: var(--glass-tint);
  background-image: var(--glass-sheen);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-inner-hi), var(--glass-ring), var(--glass-drop);
}

.glass--band {
  background-color: var(--glass-tint-band);
  background-image: var(--glass-sheen-band);
  border-color: var(--glass-edge-band);
  box-shadow: var(--glass-inner-hi-band), var(--glass-ring-band), var(--glass-drop-band);
}
.glass--band-2 {
  background-color: var(--glass-tint-band-2);
  background-image: var(--glass-sheen-band);
  border-color: var(--glass-edge-band);
  box-shadow: var(--glass-inner-hi-band), var(--glass-ring-band), var(--glass-drop-band);
}

.glass--hug   { width: fit-content; max-width: 100%; }
.glass--tight { padding: var(--glass-pad-tight); }
.glass--roomy { padding: var(--glass-pad-roomy); }
.glass--lg    { border-radius: var(--r-glass-lg); }
.glass--flat  { box-shadow: var(--glass-inner-hi), var(--glass-ring); }
.glass--flat.glass--band,
.glass--flat.glass--band-2 { box-shadow: var(--glass-inner-hi-band), var(--glass-ring-band); }

/* inset grouped list: ONE pane, hairline-divided rows (never one pane per row) */
.glass-list { padding: 0; overflow: hidden; }
.glass-list > *       { padding: var(--glass-pad-tight) var(--glass-pad); }
.glass-list > * + *   { border-top: 1px solid var(--glass-divider); }

/* chip floating over photography — see spec §1.8 */
.glass--photo {
  background-color: var(--glass-tint);
  background-image: none;
  -webkit-backdrop-filter: var(--glass-blur-sm);
          backdrop-filter: var(--glass-blur-sm);
  box-shadow: var(--glass-inner-hi), var(--glass-ring), var(--glass-drop);
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .glass--photo { background-color: color-mix(in srgb, var(--glass-solid) 86%, transparent); }
}

/* guard: nesting glass in glass is forbidden. If it happens anyway,
   degrade to a flat fill instead of stacking two blurs into mud. */
.glass .glass,
.glass .glass-list,
.glass-list .glass,
.glass .mn-btn-glass {
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  background-color: var(--glass-fill-2);
  background-image: none;
  box-shadow: none;
}
.mn-dark .glass .mn-btn-glass { background-color: var(--glass-fill-2-band); }

/* ── image frames: every arch becomes the gallery's rounded rectangle ── */
.pm-frame {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-frame);
  border: 1px solid var(--mn-hairline);
  background: var(--linen);
  box-shadow: var(--elev-1);
}
.pm-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pm-frame { transition: transform 0.5s var(--mn-ease), box-shadow 0.5s var(--mn-ease); }
  .pm-frame:hover { transform: translateY(-6px) scale(1.015); box-shadow: var(--elev-3); }
}

/* ── controls: rectangular, never ovular ─────────────────────── */
.mn-btn                  { border-radius: var(--r-btn); }
.mn-btn:focus-visible,
.cart-pill:focus-visible { border-radius: var(--r-btn); }
.cart-pill               { border-radius: var(--r-btn); }
.cart-pill .cart-count   { border-radius: 7px; }
.mn-nav-link,
.mn-nav-link:focus-visible { border-radius: var(--r-btn-sm); }
.mn-nav-burger,
.mn-mobile-close,
.mn-theme-toggle         { border-radius: var(--r-btn-lg); }
.pm-badge                { border-radius: 6px; } /* ~23px tall: 10px would render a stadium (radius ≈ 88% of half-height) */
.pm-input, .pm-select, .pm-textarea { border-radius: var(--r-btn); }

/* ADDITION to spec Appendix A (Foundation phase, reported upward).
   §0.2's file audit lists site.css but not /assets/search.css, which also
   loads before this file and ships two --r-pill controls — one of them the
   42px search button sitting in the nav of every page. Leaving it round
   breaks rule 3 ("more rectangular, less ovular") on all eleven pages and
   no page agent can reach it without duplicating the fix six times.
   Radius-only, additive, no token touched. Same for the two injected
   round closers in site.css that appear on the storefront pages. */
.pm-search-btn,
.pm-search-btn:focus-visible { border-radius: var(--r-btn-lg); }
.pm-search-clear,
.pm-ticker-close             { border-radius: var(--r-btn-sm); }
.pm-expand-close             { border-radius: var(--r-btn-lg); }

/* secondary CTA that reads as glass on a bare section backdrop */
.mn-btn-glass {
  color: var(--mn-ink);
  background-color: var(--glass-tint);
  background-image: var(--glass-sheen);
  -webkit-backdrop-filter: var(--glass-blur-sm);
          backdrop-filter: var(--glass-blur-sm);
  border-color: var(--glass-edge);
  box-shadow: var(--glass-inner-hi), var(--glass-ring);
}
.mn-dark .mn-btn-glass {
  color: var(--mn-ondark);
  background-color: var(--glass-tint-band);
  background-image: var(--glass-sheen-band);
  border-color: var(--glass-edge-band);
  box-shadow: var(--glass-inner-hi-band), var(--glass-ring-band);
}
@media (hover: hover) {
  .mn-btn-glass:hover { border-color: var(--mn-ink); transform: translateY(-2px); }
  .mn-dark .mn-btn-glass:hover { border-color: var(--mn-ondark); }
}

/* ── Iconsax <iconsax-icon> host: reserve the box, kill CLS,
      keep the injected <svg> out of event delegation ─────────── */
iconsax-icon {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
  width: var(--icon-size, 18px);
  height: var(--icon-size, 18px);
  line-height: 0;
  vertical-align: -0.18em;
  pointer-events: none;
}
iconsax-icon svg { display: block; width: 100%; height: 100%; }
.mn-btn iconsax-icon      { --icon-size: 18px; }
.mn-btn-lg iconsax-icon   { --icon-size: 20px; }
.mn-eyebrow iconsax-icon,
.pm-label iconsax-icon    { --icon-size: 14px; }
.icon-gold                { color: var(--mn-gold-deep); }
.mn-dark .icon-gold       { color: var(--mn-gold-bright); }

/* ── Final-review additions (post-judge). Shared fixes every page
      judge requested independently but could not make here. ────── */

/* Keyboard focus ring on in-panel secondary CTAs: the nested-glass guard
   above zeroes box-shadow at (0,2,0), which outranks site.css's
   a:focus-visible ring at (0,1,1). WCAG 2.4.7. (Several pages carry the
   same rule locally; identical declarations, harmless.) */
.glass .mn-btn-glass:focus-visible,
.glass-list .mn-btn-glass:focus-visible {
  box-shadow: var(--focus-ring);
  border-radius: var(--r-btn);
}

/* The site.js-injected toast was the last --r-pill survivor on the
   storefront (owner rule 3: no pills). Dark theme re-colors but does not
   re-radius, so one rule covers both themes. */
.pm-toast { border-radius: var(--r-btn-lg); }

/* Every page's mobile-menu close glyph ships size="20"; without this the
   host box stays at the 18px default and attribute/box disagree (§4.4). */
.mn-mobile-close iconsax-icon { --icon-size: 20px; }

/* Light-theme "Gluten-free" chip fails AA at 4.13:1 on the card ground.
   #5A7354 = 5.00:1 and keeps the sage character. Scoped so dark theme's
   --sage (#8FAE89, passing) is restored untouched. Not fixed in site.css
   because --sage is shared with protected pages (admin/baker/bread/counts). */
.pm-card-gf { color: #5A7354; border-color: #5A7354; }
html[data-theme="dark"] .pm-card-gf { color: var(--sage); border-color: var(--sage); }

/* ── band seams: a section must never draw its own horizon ─────
   Reported upward as a shared fix (owner: "the background is still split
   … the background being blurred is perfect, it's just ruined by the lines").

   A "band" is a full-bleed section that paints its own ground and clips a
   section-scoped bloom: the espresso strips (.pm-notice & co) and .mn-footer.
   Two separate artefacts stack into the horizontal strata the owner saw:

   1. THE GROUND STEP. In LIGHT theme the band is the designed espresso-on-cream
      block — high contrast, crisp, intentional; it stays exactly as drawn.
      In DARK theme --mn-dark (#150C06) and --mn-cream (#1F140D) are within ~10
      levels of each other, so the same edge stops reading as design and starts
      reading as a seam. Dark theme therefore drops the ground entirely: the
      band lets body's background AND body::before's fixed ambient blooms run
      straight through, so there is nothing to step at the boundary. The pane
      still has plenty to blur — the fixed blooms plus the band's own bloom.
      `transparent`, not "the body colour": an opaque repaint of the body colour
      would still cut the fixed blooms at the section edge.

   2. THE CLIPPED GLOW. The bloom pseudo-elements are radial gradients whose
      centres sit ON or NEAR the band's top/bottom edge (…at 10% 8%, …at 14% 0%),
      so they are still at ~90% strength when `overflow:hidden` slices them.
      That slice is a hard line in BOTH themes. Fixing the ground alone leaves it.
      The mask fades every bloom to zero alpha before it can reach a clipped
      edge — the glow keeps its shape in the middle, where the pane blurs it.

   USAGE. The mask (2) is safe everywhere and is wired up for every page's
   footer unconditionally — it only deletes a glow that was being sliced.
   Dropping the ground (1) is OPT-IN, `class="pm-band"` on the section, because
   it is only correct when the band is surrounded by page background. Two bands
   that ABUT — cakes.html sets `.mn-footer { margin-top: 0 }` under a
   `.pm-studio-strip mn-dark` — currently read as one continuous dark region;
   converting one and not the other would open a seam where there was none. So
   a page converts all of its adjacent bands together, or none of them.
   `html[data-theme="dark"] .pm-band` is (0,2,1) and out-specifies a page-local
   `.pm-notice { background }` at (0,1,0), so no page has to restate it; the
   ::before rule only sets mask, never background, so it cannot collide with a
   page's own bloom whatever order the two stylesheets parse in. */
:root {
  /* ramp long enough to swallow the glow, short enough to clear the pane's
     top edge: the bands pad 44-76px and the footer 48-88px before content */
  --band-bloom-fade: clamp(48px, 11%, 128px);
  /* smoothstep, not a straight ramp: a linear fade lands its full slope in one
     row at each end, and that corner is exactly what Mach banding renders as a
     faint line. The 0.09/0.5/0.91 knots ease both ends in and out. */
  --band-bloom-mask: linear-gradient(180deg,
    rgba(0, 0, 0, 0)    0,
    rgba(0, 0, 0, 0.09) calc(var(--band-bloom-fade) * 0.25),
    rgba(0, 0, 0, 0.5)  calc(var(--band-bloom-fade) * 0.5),
    rgba(0, 0, 0, 0.91) calc(var(--band-bloom-fade) * 0.75),
    #000                var(--band-bloom-fade),
    #000                calc(100% - var(--band-bloom-fade)),
    rgba(0, 0, 0, 0.91) calc(100% - var(--band-bloom-fade) * 0.75),
    rgba(0, 0, 0, 0.5)  calc(100% - var(--band-bloom-fade) * 0.5),
    rgba(0, 0, 0, 0.09) calc(100% - var(--band-bloom-fade) * 0.25),
    rgba(0, 0, 0, 0)    100%);
}
.pm-band::before,
.mn-footer::before {
  -webkit-mask-image: var(--band-bloom-mask);
          mask-image: var(--band-bloom-mask);
  /* belt and braces: mask-size:auto already fits a gradient to the box on every
     engine that ships masks, but no-repeat means a disagreement can't tile it */
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}
html[data-theme="dark"] .pm-band { background: transparent; }

/* ═══════════════════════════════════════════════════════════════
   §F  LA VITRINE — the page frame
   ═══════════════════════════════════════════════════════════════
   Owner: "the pages don't fill the window." Measured with
   tools/page-shots.cjs + a geometry probe at 1440x900 and 1920x1080:
   .mn-wrap caps at 1200px, so the page ground shows 120px each side at
   1440 and 360px each side at 1920 — a gutter that grows, never fills,
   and currently reads as void.

   The answer is NOT to stretch content (a 1200px measure is the maison's
   editorial column and 1920px of body copy is unreadable). It is to make
   the gutter intentional: a viewport-fixed vitrine frame, so the window
   edge becomes the shop window and the gutter becomes the reveal between
   the glass and the display. Page ground + the fixed ambient blooms
   already run edge-to-edge behind it (body / body::before, inset:0
   fixed on every storefront page), so nothing inside the frame is void.

   OPT-IN: one class, `body.pm-framed`. Nothing else. Studio and admin
   adopt in their own workstreams by adding the same single class.

   Z-INDEX 45 — chosen against the shipped stack (site.css / search.css):
     -1 body::before blooms · 40 .mn-nav · [45 the frame] · 54 .pm-ticker
     · 55 .pm-float-cart · 60 .mn-mobile-menu · 80 .pm-expand / .pm-search
     · 90 .pm-skip · 100 .pm-toast
   Above the page ground AND above the sticky nav, so the frame reads as
   one continuous window in front of the room; below every modal, overlay,
   skip link and toast, so it can never sit on top of an interaction.
   pointer-events:none — it is chrome, never a target.                */

body.pm-framed::after {
  content: "";
  position: fixed;
  inset: var(--vitrine-inset, 12px);
  z-index: 45;
  pointer-events: none;
  border: 1px solid var(--mn-hairline);
  /* F1 rework (owner 2026-07-27): "a straight line across the top
     sectioning the header section", "weird corners in the top left",
     "the border and the header section intersect hard on the eyes".
     The straight top rail is GONE: a clip-path bite removes the rail
     between the corners, so the top of the frame reads as two curved
     sweeps instead of a hard line — the curve is what the eye follows.
     K8 (owner 2026-07-27): the sweeps drop from an off-token 30px to
     --r-glass-lg (26px) — the token scale's top — so frame, plaque
     (--r-btn-lg 14) and cards (--r-frame) speak one radius language.
     Bite geometry: keep the outermost 26px of each top corner — exactly
     the corner sweeps, nothing more — and remove the top 6px between
     them (the 1px rail never rises above y=1, so the arcs are never
     touched). No straight stub: the nav's side padding
     (clamp 20px/4vw/56px) puts the brand pane's left edge at 41px at
     1024px wide, and the kept stroke ends at inset+keep = 12+keep; a
     50px keep crossed the pane's rounded corner (~20px at 1024, ~6px
     at 1440 — the "weird top-left corner" the owner flagged). At 26px
     the stroke ends at x=38, clear of the pane at every framed width,
     and the bite cuts the stroke square at the arc's endpoint. */
  border-radius: var(--r-glass-lg) var(--r-glass-lg) var(--r-md) var(--r-md);
  -webkit-clip-path: polygon(
    0 0, 0 100%, 100% 100%, 100% 0,
    calc(100% - 26px) 0, calc(100% - 26px) 6px,
    26px 6px, 26px 0
  );
  clip-path: polygon(
    0 0, 0 100%, 100% 100%, 100% 0,
    calc(100% - 26px) 0, calc(100% - 26px) 6px,
    26px 6px, 26px 0
  );
  /* SIGNATURE — the maker's notch, remounted on the BOTTOM rail (the
     top no longer has a rail to hang from, and the bottom rail is the
     one empty edge on every page). The plaque now hangs INTO the page
     from the bottom rail with a transparent interior — no page-ground
     fill, so it can never mismatch the ambient blooms (the light-theme
     bottom-center bloom sits at ~0.09 alpha; the old flat fill was only
     ever exact at top-centre). The plaque outline has NO bottom edge —
     the path is open (`v8`, no `Z`) so the 1px bottom rail itself is
     the plaque's floor; a closed path double-drew that 64px segment at
     ~1.75× stroke alpha. Monogram unchanged, same 1.2px linear
     stroke language as the Iconsax set. */
  background-repeat: no-repeat;
  background-position: bottom center;
  background-size: 64px 18px;
  background-origin: border-box;
  background-clip: border-box;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 18' fill='none'%3E%3Cpath d='M.5 17.5v-8a9 9 0 0 1 9-9h45a9 9 0 0 1 9 9v8' fill='none' stroke='%23211710' stroke-opacity='.14'/%3E%3Cg stroke='%237A5C24' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M25.4 13.4V4.9h3a2.4 2.4 0 0 1 0 4.8h-3'/%3E%3Cpath d='M33.8 13.4V4.9l2.5 3.5 2.5-3.5v8.5'/%3E%3C/g%3E%3C/svg%3E");
}
html[data-theme="dark"] body.pm-framed::after {
  /* same hairline token, no glow — the dark frame is a line, not a light */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 18' fill='none'%3E%3Cpath d='M.5 17.5v-8a9 9 0 0 1 9-9h45a9 9 0 0 1 9 9v8' fill='none' stroke='%23F3E9DA' stroke-opacity='.15'/%3E%3Cg stroke='%23D8B366' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M25.4 13.4V4.9h3a2.4 2.4 0 0 1 0 4.8h-3'/%3E%3Cpath d='M33.8 13.4V4.9l2.5 3.5 2.5-3.5v8.5'/%3E%3C/g%3E%3C/svg%3E");
}
/* K8: seat the plaque INSIDE the frame's top band. With the old 8px the
   brand box (~52.6px tall, centred in the 66px nav row) put its top edge
   at y≈10.2 — ~2px ABOVE the frame's top-rail plane (y=12), the owner's
   "sits just above where I think it should", literally true at every
   framed width. 22px of headroom landed the plaque's top edge at ~y17.7.
   Owner follow-up 2026-07-27: "shift the entire header line just a few
   pixels above where it currently is" — 19px lifts the whole row (logo
   AND nav links) 3px while the plaque top stays ~2.7px below the rail's
   inner edge; it never re-crosses the frame plane. Probe after moving. */
/* owner 2026-07-27: clear air BELOW the plaque too — 12px between the
   box's bottom edge and the hairline that separates header from body. */
body.pm-framed .mn-nav { padding-top: 19px; padding-bottom: 12px; }
/* the stuck nav's hairline no longer T-junctions the frame's side rails:
   it runs rail-to-rail (12px insets) instead of 0→100vw. Only where the
   frame exists — the 1023px kill-switch below restores the full-width
   rule. */
@media (min-width: 1024px) {
  body.pm-framed .mn-nav.is-scrolled { border-bottom-color: transparent; }
  body.pm-framed .mn-nav.is-scrolled::after {
    content: "";
    position: absolute; left: 12px; right: 12px; bottom: 0;
    border-bottom: 1px solid var(--mn-hairline);
  }
}

/* Below 1024px the window IS the page — there is no gutter to reframe and
   a fixed hairline would only steal 24px of a phone's width. Frame off. */
@media (max-width: 1023px) {
  body.pm-framed::after      { content: none; }
  body.pm-framed .mn-nav     { padding-top: 0; padding-bottom: 0; }
}
/* Windows High Contrast strips decoration; a fixed frame and plaque would
   be noise without the palette behind them. Drop the whole frame. */
@media (forced-colors: active) {
  body.pm-framed::after { content: none; }
}
@media print {
  body.pm-framed::after { content: none; }
}

/* ═══════════════════════════════════════════════════════════════
   §N  NAV — boxed brand, icon-with-word links
   ═══════════════════════════════════════════════════════════════ */

/* — the brand block: a glass pane box around the two-line wordmark —
   No backdrop-filter on purpose. .mn-nav.is-scrolled already carries
   blur(16px); a second blurred layer inside it is the "glass in glass"
   §1.7 rule 1 forbids (two filters blur each other into mud at double
   the cost). The tint + inner highlight + hairline carry the material. */
.mn-nav-brand {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  /* owner 2026-07-27 (third pass, blue-line sketch): the OUTLINE must sit
     clearly off the words — ~6px more air above and below than the old
     10px gave. The words keep their size; only the box grows. Mobile
     overrides below keep their tighter paddings (they exist to prevent
     the measured 412-430px overflow — do not scale them up). */
  padding: 16px 18px;
  border: 1px solid var(--mn-hairline);
  border-radius: var(--r-btn-lg);            /* 14px */
  background-color: var(--glass-tint);
  background-image: var(--glass-sheen);
  box-shadow: var(--glass-inner-hi);
  line-height: 1.04;
  transition: border-color 0.2s, background-color 0.2s;
}
.mn-nav-brand:focus-visible { border-radius: var(--r-btn-lg); }
@media (hover: hover) {
  .mn-nav-brand:hover { border-color: var(--mn-ink); }
}
.mn-brand-name { display: block; }
.mn-brand-sub {
  display: block;
  font-family: var(--font-body);
  font-size: 9.5px; font-weight: 500; font-style: normal;
  letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--mn-gold-deep);
}
@media (max-width: 940px) {
  .mn-nav-brand { padding: 8px 11px; }
  .mn-brand-sub { letter-spacing: 0.22em; }
}
/* JUDGE FIX — §N spends row width the shipped nav did not have: the boxed
   wordmark can no longer wrap to "Patisserie / Manon" (its min-content is now
   LA COLLECTION + 22px of padding, +28px), and the cart pill grew a bag glyph
   (+17px). .mn-nav-burger is flex:none, so the surplus pushed the DOCUMENT
   sideways: measured scrollWidth 439 against clientWidth 412/414/430 on all
   seven storefront pages — i.e. every iPhone XR / 11 / 14 Pro Max scrolls
   horizontally. main@47f2148 has no overflow at any of those widths.
   Below 940px the inline links are already gone, so the cheapest 36px is the
   gutter between the utility buttons plus the box's own padding — no glyph and
   no word has to be dropped to pay for it. */
@media (max-width: 560px) {
  .mn-nav       { gap: 12px; }
  .mn-nav-brand { padding: 7px 9px; }
  /* A2(a): the sub-line stands down on phone — the wordmark alone is the
     logo (site.css shrinks its type at the same width). Dropping LA
     COLLECTION also releases the box's min-content width, so the §N
     overflow math only ever improves. */
  .mn-brand-sub { display: none; }
}

/* — every link is an icon and its word, centred as one unit —
   site.css already owns colour, size, tracking and padding; this only
   turns the box into a centred flex row and reserves the icon slot. */
.mn-nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
}
.mn-nav-link iconsax-icon,
.mn-mobile-menu .mn-nav-link iconsax-icon { --icon-size: 18px; }
/* site.css draws the active marker as a block ::after in normal flow. Inside
   a flex row that becomes a third flex ITEM — a gold sliver beside the word
   instead of a rule beneath it. Lift it out of the row and span the unit. */
.mn-nav-link.is-active::after {
  position: absolute;
  left: 13px; right: 13px; bottom: 6px;
  margin: 0;
}

/* — "Your order": Iconsax `bag-2`, LINEAR, drawn as a currentColor mask —
   §N maps order -> bag-2, which lives in the `shop` chunk. home.html is
   already at the spec's hard ceiling of 4 category chunks (essential,
   call, location, time = ~157 KB br against a 170 KB budget), so an
   <iconsax-icon name="bag-2"> in a nav that must be identical on all
   eight pages would blow both the chunk count and the byte budget on
   home — §4.5 is not negotiable. The geometry below is the authentic
   bag-2 `linear` artwork lifted from vendor/iconsax/data/shop.json,
   painted with background-color: currentColor through a mask, so it
   still inherits text colour and still costs zero network. One rule,
   every page, no markup churn. */
:root {
  --pm-icon-bag: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 7.67V6.7c0-2.25 1.81-4.46 4.06-4.67 2.68-.26 4.94 1.85 4.94 4.48v1.38'/%3E%3Cpath d='M9 22h6c4.02 0 4.74-1.61 4.95-3.57l.75-6C20.97 9.99 20.27 8 16 8H8c-4.27 0-4.97 1.99-4.7 4.43l.75 6C4.26 20.39 4.98 22 9 22Z'/%3E%3Cpath d='M15.5 12h.01' stroke-width='2'/%3E%3Cpath d='M8.49 12h.01' stroke-width='2'/%3E%3C/svg%3E");
}
@supports ((mask-image: url(i.svg)) or (-webkit-mask-image: url(i.svg))) {
  .cart-pill::before,
  .mn-mobile-menu .mn-nav-link[href="/cart"]::before {
    content: "";
    flex: none;
    width: 18px; height: 18px;
    background-color: currentColor;
    -webkit-mask: var(--pm-icon-bag) center / contain no-repeat;
            mask: var(--pm-icon-bag) center / contain no-repeat;
  }
}

/* The five section links carry their icons as real <iconsax-icon> elements
   (cake / coffee / reserve / weight / 3dcube — all in `essential`, which
   every page already pays for, so the nav costs nothing extra anywhere).

   Measured: brand box + five icon+word units + search + theme + cart pill
   need 1118px of row, so the inline nav only really fits from ~1240px up.
   Below that the row was already over-subscribed BEFORE this change — at
   960px the shipped nav wraps "Your order" onto two lines — so the honest
   fix is to hand 941–1239px to the drawer that already exists, instead of
   letting five links, a wordmark and a pill fight over one row.

   Guarded by :has(~ .mn-mobile-menu): a page may only lose its inline links
   if a mobile drawer is actually there to receive them. index.html and
   cake-studio-ipad.html carry .mn-nav-links with NO drawer — collapsing
   them would strand the studio's navigation, and §S is adding glass.css to
   that pair in a parallel branch. Engines without :has() keep the shipped
   text-only row (icons stand down, links stay shrinkable) — identical to
   today's behaviour at those widths, never worse. */
@media (max-width: 1239px) {
  @supports selector(:has(*)) {
    .mn-nav:has(~ .mn-mobile-menu) .mn-nav-links  { display: none; }
    .mn-nav:has(~ .mn-mobile-menu) .mn-nav-burger { display: inline-flex; }
    /* .mn-nav-links carried the margin-right:auto that pins the brand left
       and clusters the utilities right; it leaves with them */
    .mn-nav:has(~ .mn-mobile-menu) .mn-nav-brand  { margin-right: auto; }
  }
  @supports not selector(:has(*)) {
    .mn-nav-links .mn-nav-link iconsax-icon { display: none; }
    .mn-nav-links .mn-nav-link { gap: 0; white-space: normal; }
  }
}

/* ── the phone drawer becomes the app shell (A2 phone bundle) ───────
   Owner: phone = quick purchases, and this drawer feeds a future iOS
   app. At phone widths the drawer's links become icon-led rows — the
   icons the links already carry (all in `essential`; zero new chunks)
   grow to 26px inside full-width glass rows with 58px tap targets;
   the wordy labels go secondary. The theme toggle leaves the cramped
   nav row and nests here as its own row (site.js mirrors the button;
   site.css hides the drawer copy by default). Gated ≤760px — the
   761-1239px tablet drawer keeps the shipped centered look, and the
   desktop nav row is untouched. Sits AFTER the base --icon-size and
   is-active rules above so the equal-specificity overrides here win. */
@media (max-width: 760px) {
  .mn-mobile-menu {
    align-items: stretch;
    justify-content: flex-start;
    gap: 8px;
    padding: 84px clamp(22px, 7vw, 44px) 30px;
    overflow-y: auto;
  }
  /* the eight stacked rows are taller than a short phone's viewport
     (~690px of content), so the drawer above is a scroll container now.
     `.mn-mobile-close` is absolutely positioned INSIDE it, which means it
     scrolls out of reach the moment the list moves — the only way back
     out would be Esc, which a phone has no key for. Pin it to the
     viewport instead: the panel is `position:fixed; inset:0`, so a fixed
     child lands in exactly the same 14px/clamp() corner it did before,
     and it now sits still while the rows travel under it. Opaque + z2 so
     nothing scrolls through it. */
  .mn-mobile-menu .mn-mobile-close {
    position: fixed;
    z-index: 2;
    background: var(--mn-cream);
  }
  .mn-mobile-menu .mn-nav-link {
    justify-content: flex-start;
    gap: 16px;
    min-height: 58px;
    padding: 8px 14px;
    font-size: 12px;
    border: 1px solid var(--mn-hairline);
    border-radius: var(--r-btn-lg);
    background-color: var(--glass-tint);
    background-image: var(--glass-sheen);
  }
  .mn-mobile-menu .mn-nav-link iconsax-icon {
    --icon-size: 26px;
    flex: none;
    color: var(--mn-gold-deep);
  }
  /* the cart row's mask glyph grows to match the iconsax rows */
  .mn-mobile-menu .mn-nav-link[href="/cart"]::before {
    width: 26px; height: 26px;
    color: var(--mn-gold-deep);
  }
  /* the active row reads through its gold frame, not the underline */
  .mn-mobile-menu .mn-nav-link.is-active { border-color: var(--mn-gold); }
  .mn-mobile-menu .mn-nav-link.is-active::after { display: none; }
  .mn-mobile-menu .pm-menu-call { justify-content: center; }

  /* theme toggle: nav-row button stands down, the drawer row takes over */
  .mn-nav .mn-theme-toggle { display: none; }
  .mn-mobile-menu .mn-theme-toggle {
    display: inline-flex;
    width: auto; height: auto; flex: none;
    align-items: center; justify-content: flex-start;
    gap: 16px;
    min-height: 58px;
    padding: 8px 14px;
    font-family: var(--font-body);
    font-size: 12px; font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--mn-cocoa);
    border: 1px solid var(--mn-hairline);
    border-radius: var(--r-btn-lg);
    background-color: var(--glass-tint);
    background-image: var(--glass-sheen);
  }
  .mn-mobile-menu .mn-theme-toggle svg {
    width: 26px; height: 26px; flex: none;
    color: var(--mn-gold-deep);
  }
}

/* ── fallbacks ───────────────────────────────────────────────── */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass, .glass-list, .glass--photo, .mn-btn-glass {
    background-color: var(--glass-solid);
    background-image: none;
  }
  .glass--band   { background-color: var(--glass-solid-band); }
  .glass--band-2 { background-color: var(--glass-solid-band-2); }
  .mn-dark .mn-btn-glass { background-color: var(--glass-solid-band); }
}

@media (prefers-reduced-transparency: reduce) {
  .glass, .glass-list, .glass--photo, .mn-btn-glass {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background-color: var(--glass-solid);
    background-image: none;
  }
  .glass--band   { background-color: var(--glass-solid-band); }
  .glass--band-2 { background-color: var(--glass-solid-band-2); }
  .mn-dark .mn-btn-glass { background-color: var(--glass-solid-band); }
}

@media (prefers-contrast: more) {
  .glass, .glass-list, .glass--photo {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background-image: none;
    background-color: var(--glass-solid);
    border-color: var(--mn-ink);
  }
  .glass--band   { background-color: var(--glass-solid-band);   border-color: var(--mn-ondark); }
  .glass--band-2 { background-color: var(--glass-solid-band-2); border-color: var(--mn-ondark); }
}

@media (forced-colors: active) {
  .glass, .glass-list, .glass--photo, .mn-btn-glass {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: Canvas;
    background-image: none;
    border: 1px solid CanvasText;
    box-shadow: none;
  }
}

@media print {
  .glass, .glass-list, .glass--photo, .mn-btn-glass {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: #fff; background-image: none;
    border: 1px solid #ccc; box-shadow: none;
  }
}

/* ══ les réverbères — the street-lamp cast-light system ═══════════════
   Fable component 2026-07-28, promoted from home.html so every framed
   page can carry lamps. A page opts in with the .pm-lamps markup and an
   ARRANGEMENT block in its own <style>: per-lamp anchors (--tl/--tr/
   --bl/--br positioning), per-lamp --pm-lamp-dur/--pm-lamp-phase, and
   optional tint overrides (--pm-glow-a/b, --pm-beam-a/b). Everything
   else — silhouettes, glow, flame, beam, pool, flicker — lives here.
   Owner ~1:15am: "increase flickerage brightness" — peaks now reach
   full opacity and the swing is wider than the first cut. */
.pm-lamps {
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none; overflow: hidden;
}
.pm-lamp { position: absolute; }
.pm-lamp--bracket {
  width: 150px; height: 170px;
  --pm-lamp-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150 170'%3E%3Cg fill='black'%3E%3Crect x='0' y='6' width='6.5' height='50' rx='2'/%3E%3Cpath d='M86 46 L122 46 L112 33 L96 33 Z'/%3E%3Crect x='92' y='90' width='24' height='4' rx='1'/%3E%3Cpath d='M96 94 L112 94 L104 108 Z'/%3E%3Ccircle cx='104' cy='111' r='3'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round'%3E%3Cpath d='M5 13 C46 5 82 9 103 22' stroke-width='4.6'/%3E%3Cpath d='M7 47 C40 45 74 37 98 26' stroke-width='3'/%3E%3Cpath d='M7 47 C3 43 4 36 10 35 C15 34 16 40 11 41' stroke-width='2.2'/%3E%3Ccircle cx='104' cy='26' r='4.5' stroke-width='2.5'/%3E%3Cpath d='M91 48 L117 48 L113 90 L95 90 Z' stroke-width='3.4'/%3E%3Cpath d='M104 50 L104 88' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E");
}
.pm-lamp--post {
  width: 90px; height: 320px;
  --pm-lamp-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 90 320'%3E%3Cg fill='black'%3E%3Ccircle cx='45' cy='12' r='3.5'/%3E%3Cpath d='M42 15 L48 15 L47 22 L43 22 Z'/%3E%3Cpath d='M30 36 L60 36 L51 22 L39 22 Z'/%3E%3Crect x='31' y='78' width='28' height='4' rx='1'/%3E%3Cpath d='M38 82 L52 82 L50 92 L40 92 Z'/%3E%3Cpath d='M40 92 C40 99 38 102 37 106 L53 106 C52 102 50 99 50 92 Z'/%3E%3Cpath d='M40 106 L50 106 L54 272 L36 272 Z'/%3E%3Crect x='17' y='118' width='56' height='4' rx='2'/%3E%3Ccircle cx='17' cy='120' r='3'/%3E%3Ccircle cx='73' cy='120' r='3'/%3E%3Crect x='34' y='148' width='22' height='6' rx='3'/%3E%3Crect x='35' y='212' width='20' height='5' rx='2.5'/%3E%3Cpath d='M32 272 L58 272 L63 296 L27 296 Z'/%3E%3Crect x='23' y='296' width='44' height='9' rx='2'/%3E%3Crect x='18' y='305' width='54' height='10' rx='2'/%3E%3C/g%3E%3Cg fill='none' stroke='black'%3E%3Cpath d='M33 40 L57 40 L53 78 L37 78 Z' stroke-width='3.2'/%3E%3Cpath d='M45 42 L45 76' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E");
}
.pm-lamp-glow, .pm-lamp-flame, .pm-lamp-iron,
.pm-lamp-beam, .pm-lamp-pool { position: absolute; display: block; }
.pm-lamp-iron {
  inset: 0;
  background-color: rgba(56, 38, 22, 0.48);
  -webkit-mask: var(--pm-lamp-svg) center / contain no-repeat;
          mask: var(--pm-lamp-svg) center / contain no-repeat;
}
html[data-theme="dark"] .pm-lamp-iron { background-color: rgba(14, 8, 4, 0.58); }
@supports not ((mask-image: url("i.svg")) or (-webkit-mask-image: url("i.svg"))) {
  .pm-lamp-iron { display: none; }
}
.pm-lamp { --pm-glow-a: rgba(236, 196, 120, 0.32); --pm-glow-b: rgba(236, 196, 120, 0.11); }
html[data-theme="dark"] .pm-lamp { --pm-glow-a: rgba(228, 182, 104, 0.25); --pm-glow-b: rgba(228, 182, 104, 0.085); }
.pm-lamp-glow {
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--pm-glow-a), var(--pm-glow-b) 46%, transparent 72%);
  opacity: 0.8;
}
.pm-lamp--bracket .pm-lamp-glow { width: 320px; height: 320px; left: -56px; top: -91px; }
.pm-lamp--post    .pm-lamp-glow { width: 360px; height: 360px; left: -135px; top: -121px; }
.pm-lamp-flame {
  width: 10px; height: 16px; border-radius: 50%;
  background: radial-gradient(ellipse at 50% 62%, rgba(255, 233, 178, 0.98), rgba(240, 192, 112, 0.6) 55%, transparent 78%);
  filter: blur(1px);
  opacity: 0.95;
}
html[data-theme="dark"] .pm-lamp-flame { filter: blur(1px) brightness(0.88); }
.pm-lamp--bracket .pm-lamp-flame { left: 99px; top: 61px; }
.pm-lamp--post    .pm-lamp-flame { left: 40px; top: 51px; }
.pm-lamp-beam {
  background: linear-gradient(to bottom,
    var(--pm-beam-a, rgba(255, 216, 134, 0.38)) 0,
    var(--pm-beam-b, rgba(255, 216, 134, 0.155)) 52%,
    rgba(255, 216, 134, 0) 94%);
  clip-path: polygon(46% 0, 54% 0, 100% 100%, 0 100%);
  filter: blur(7px);
  opacity: 0.85;
  transform-origin: 50% 0;
}
.pm-lamp--bracket .pm-lamp-beam { width: 320px; height: 560px; left: -56px; top: 94px; }
.pm-lamp--post    .pm-lamp-beam { width: 300px; height: 226px; left: -105px; top: 90px;
  clip-path: polygon(43% 0, 57% 0, 94% 100%, 6% 100%); }
html[data-theme="dark"] .pm-lamp-beam { opacity: 1; }
html:not([data-theme="dark"]) .pm-lamp-beam {
  --pm-beam-a: rgba(214, 168, 90, 0.16); --pm-beam-b: rgba(214, 168, 90, 0.06);
}
.pm-lamp-pool {
  width: 340px; height: 64px; left: -125px; bottom: -8px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 216, 134, 0.27), rgba(255, 216, 134, 0.10) 55%, transparent 78%);
  filter: blur(5px);
  opacity: 0.95;
}
html:not([data-theme="dark"]) .pm-lamp-pool { opacity: 0.4; }
@media (prefers-reduced-motion: no-preference) {
  .pm-lamp-glow {
    animation: pm-gas-breathe var(--pm-lamp-dur, 10s) ease-in-out var(--pm-lamp-phase, 0s) infinite;
    will-change: opacity;
  }
  .pm-lamp-flame {
    animation: pm-gas-flame calc(var(--pm-lamp-dur, 10s) * 0.62) ease-in-out calc(var(--pm-lamp-phase, 0s) - 1.3s) infinite;
    will-change: opacity;
  }
  .pm-lamp-beam {
    animation:
      pm-gas-breathe var(--pm-lamp-dur, 10s) ease-in-out var(--pm-lamp-phase, 0s) infinite,
      pm-beam-sway calc(var(--pm-lamp-dur, 10s) * 1.7) ease-in-out var(--pm-lamp-phase, 0s) infinite;
    will-change: opacity, transform;
  }
  .pm-lamp-pool {
    animation: pm-gas-breathe var(--pm-lamp-dur, 10s) ease-in-out calc(var(--pm-lamp-phase, 0s) - 0.8s) infinite;
    will-change: opacity;
  }
  @keyframes pm-gas-breathe {
    0%, 100% { opacity: 0.88; }
    13%      { opacity: 0.68; }
    29%      { opacity: 1; }
    47%      { opacity: 0.62; }
    61%      { opacity: 0.94; }
    79%      { opacity: 0.72; }
  }
  @keyframes pm-gas-flame {
    0%, 100% { opacity: 1; }
    11%      { opacity: 0.74; }
    23%      { opacity: 1; }
    41%      { opacity: 0.8; }
    63%      { opacity: 0.96; }
    82%      { opacity: 0.7; }
  }
  @keyframes pm-beam-sway {
    0%, 100% { transform: rotate(-0.5deg); }
    50%      { transform: rotate(0.5deg); }
  }
}

/* ══ les silhouettes de Paris — the motif ambience layer ══════════════
   Fable component 2026-07-29 (night-plan track A5), extending the
   réverbère system above: each tab carries ONE distinct Paris motif set
   behind its lamps — welcome = Haussmann skyline + open-lattice Eiffel,
   catering = marché stalls, bakery/pastry = boulangerie enseignes +
   café terrasse set, Manon Fit = Passerelle Debilly + morning runner.
   Same discipline as the lamps: data-URI mask silhouettes, fixed
   z-index -1 layer, warm cocoa alphas, compositor-only animation (only
   the two hanging signs sway, on the `rotate` property so page-level
   transforms compose), reduced-motion static, both themes. Ambience,
   not wallpaper: far strips sit near .11 alpha, mid-ground pieces
   near .2 — never more.
   A page opts in with .pm-motifs markup placed BEFORE its .pm-lamps
   div (same z-index, so DOM order paints the lamplight OVER the
   motifs) and an ARRANGEMENT block in its own <style>: positions,
   strip mask-sizes, ink overrides (--pm-motif-ink/--pm-motif-ink-dark)
   and sway tempo (--pm-sway-dur/--pm-sway-phase). DOM order INSIDE the
   layer is depth order too: on home the Eiffel comes before the
   skyline so the roofline overlaps the tower's feet; on fit the runner
   comes before the bridge so the railing pickets pass in front of him.
   References (2026-07-29 design pass): Eiffel = open lattice at true
   proportions — 330 m on a 125 m base (~2.6:1), decks at 57/116/276 m,
   arch under the first platform (a solid wedge read as a tonal smudge;
   the tower is transparency); Haussmann roofline = flat zinc terrasson
   runs joined by true-45° mansard breaks, semicircular lucarne
   dormers, souche chimney blocks with three pots each; marché stall =
   scalloped lambrequin valance + hanging balance scale, crate slats
   vertical (horizontal slats read as windows); enseignes hang from
   ferronnier potence brackets that reuse the bracket lamp's arm
   vocabulary; fit's bridge = Passerelle Debilly, the 1900 steel
   through-arch FOOTBRIDGE (Pont Neuf stone read heritage, not
   morning-run energy). */
.pm-motifs {
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none; overflow: hidden;
}
.pm-motif {
  position: absolute; display: block;
  background-color: var(--pm-motif-ink, rgba(56, 38, 22, 0.2));
  -webkit-mask: var(--pm-motif-svg) center / contain no-repeat;
          mask: var(--pm-motif-svg) center / contain no-repeat;
}
html[data-theme="dark"] .pm-motif {
  background-color: var(--pm-motif-ink-dark, rgba(10, 6, 3, 0.36));
}
@supports not ((mask-image: url("i.svg")) or (-webkit-mask-image: url("i.svg"))) {
  .pm-motifs, .pm-motif { display: none; }
}
/* forced colors flatten the alphas into full-strength CanvasText noise */
@media (forced-colors: active) {
  .pm-motifs { display: none; }
}

/* — welcome: la tour Eiffel (open lattice) + Haussmann roofline strip — */
.pm-motif--eiffel {
  width: 120px; height: 300px;
  --pm-motif-ink: rgba(56, 38, 22, 0.15);
  --pm-motif-ink-dark: rgba(10, 6, 3, 0.32);
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 300'%3E%3Cg fill='black'%3E%3Ccircle cx='60' cy='4' r='2.6'/%3E%3Crect x='58.4' y='5' width='3.2' height='10' rx='1'/%3E%3Crect x='52' y='15' width='16' height='8' rx='1.5'/%3E%3Crect x='45' y='46' width='30' height='5' rx='1'/%3E%3Crect x='28' y='190' width='64' height='6' rx='1'/%3E%3Crect x='8' y='245' width='104' height='5.5' rx='1'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round'%3E%3Cpath d='M54.5 23 L51 46' stroke-width='3'/%3E%3Cpath d='M65.5 23 L69 46' stroke-width='3'/%3E%3Cpath d='M53 35 L67 35' stroke-width='1.6'/%3E%3Cpath d='M50 51 C49 100 46 152 37 190' stroke-width='3.4'/%3E%3Cpath d='M70 51 C71 100 74 152 83 190' stroke-width='3.4'/%3E%3Cpath d='M50 92 L71 128 M70 92 L49 128' stroke-width='1.6'/%3E%3Cpath d='M48 140 L74 178 M72 140 L46 178' stroke-width='1.6'/%3E%3Cpath d='M35 196 C31 214 22 230 9 245' stroke-width='3.4'/%3E%3Cpath d='M85 196 C89 214 98 230 111 245' stroke-width='3.4'/%3E%3Cpath d='M52 196 C50 213 44 229 33 244' stroke-width='2.8'/%3E%3Cpath d='M68 196 C70 213 76 229 87 244' stroke-width='2.8'/%3E%3Cpath d='M25 228 L95 228' stroke-width='1.6'/%3E%3Cpath d='M19 250.5 C17 266 11 282 4 296' stroke-width='3.4'/%3E%3Cpath d='M101 250.5 C103 266 109 282 116 296' stroke-width='3.4'/%3E%3Cpath d='M41 250.5 C41 264 36 281 28 295' stroke-width='2.8'/%3E%3Cpath d='M79 250.5 C79 264 84 281 92 295' stroke-width='2.8'/%3E%3Cpath d='M28 295 A33 33 0 0 1 92 295' stroke-width='4'/%3E%3C/g%3E%3C/svg%3E");
}
.pm-motif--skyline {
  height: 90px;
  --pm-motif-ink: rgba(56, 38, 22, 0.11);
  --pm-motif-ink-dark: rgba(10, 6, 3, 0.26);
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 620 90'%3E%3Cg fill='black'%3E%3Cpath d='M0 90 L0 40 L46 40 L60 26 L112 26 L126 40 L158 40 L158 48 L204 48 L204 30 L258 30 L272 44 L346 44 L346 36 L398 36 L412 22 L448 22 L462 36 L510 36 L510 44 L562 44 L576 30 L606 30 L616 40 L620 40 L620 90 Z'/%3E%3Cpath d='M68 26 a4.2 4.2 0 0 1 8.4 0 Z M88 26 a4.2 4.2 0 0 1 8.4 0 Z M356 36 a4.2 4.2 0 0 1 8.4 0 Z M374 36 a4.2 4.2 0 0 1 8.4 0 Z M419 22 a4.2 4.2 0 0 1 8.4 0 Z M433 22 a4.2 4.2 0 0 1 8.4 0 Z'/%3E%3Cpath d='M12 40 L12 28 L29 28 L29 40 Z M14 28 L14 20 L17.5 20 L17.5 28 Z M19.5 28 L19.5 20 L23 20 L23 28 Z M25 28 L25 20 L28.5 20 L28.5 28 Z'/%3E%3Cpath d='M230 30 L230 18 L246 18 L246 30 Z M232 18 L232 11 L235.2 11 L235.2 18 Z M237 18 L237 11 L240.2 11 L240.2 18 Z M242 18 L242 11 L245.2 11 L245.2 18 Z'/%3E%3Cpath d='M528 44 L528 33 L543 33 L543 44 Z M530 33 L530 26 L533 26 L533 33 Z M534.8 33 L534.8 26 L537.8 26 L537.8 33 Z M539.6 33 L539.6 26 L542.6 26 L542.6 33 Z'/%3E%3Cpath d='M584 30 L584 19 L599 19 L599 30 Z M586 19 L586 12 L589 12 L589 19 Z M590.8 19 L590.8 12 L593.8 12 L593.8 19 Z M595.6 19 L595.6 12 L598.6 12 L598.6 19 Z'/%3E%3Cpath d='M298 44 C300 29 340 29 342 44 Z'/%3E%3Crect x='318' y='23' width='3.4' height='7' rx='1'/%3E%3Ccircle cx='319.7' cy='21' r='2.2'/%3E%3C/g%3E%3C/svg%3E");
  /* tiles: both edges of the 620u drawing meet at y=40, so the seam is
     invisible at any width */
  -webkit-mask: var(--pm-motif-svg) left bottom / 620px 90px repeat-x;
          mask: var(--pm-motif-svg) left bottom / 620px 90px repeat-x;
}

/* — catering: marché stall (lambrequin awning, balance scale, crates;
     mirror the right-hand one with scaleX(-1) in the arrangement) — */
.pm-motif--stall {
  width: 170px; height: 150px;
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 170 150'%3E%3Cg fill='black'%3E%3Ccircle cx='85' cy='6.5' r='2.6'/%3E%3Crect x='83.9' y='8' width='2.2' height='5' rx='1'/%3E%3Cpath d='M8 26 L85 12 L162 26 L162 34 A11 8 0 0 1 140 34 A11 8 0 0 1 118 34 A11 8 0 0 1 96 34 A11 8 0 0 1 74 34 A11 8 0 0 1 52 34 A11 8 0 0 1 30 34 A11 8 0 0 1 8 34 Z'/%3E%3Crect x='10' y='34' width='5' height='112'/%3E%3Crect x='155' y='34' width='5' height='112'/%3E%3Crect x='2' y='92' width='166' height='9' rx='2'/%3E%3Cpath d='M20 92 A10 8 0 0 1 40 92 Z'/%3E%3Cpath d='M52 92 A12 9 0 0 1 76 92 Z'/%3E%3Cpath d='M120 92 A10 8 0 0 1 140 92 Z'/%3E%3Cpath d='M102 59 A10 6.5 0 0 0 122 59 Z'/%3E%3C/g%3E%3Cpath d='M112 42 L112 49 M112 49 L104 59 M112 49 L120 59' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3Cg fill='none' stroke='black' stroke-width='3'%3E%3Crect x='28' y='106' width='42' height='26'/%3E%3Cline x1='42' y1='106' x2='42' y2='132' stroke-width='2'/%3E%3Cline x1='56' y1='106' x2='56' y2='132' stroke-width='2'/%3E%3Crect x='98' y='106' width='42' height='26'/%3E%3Cline x1='112' y1='106' x2='112' y2='132' stroke-width='2'/%3E%3Cline x1='126' y1='106' x2='126' y2='132' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E");
}

/* — bakery/pastry: enseignes on their potence brackets + café set —
   croissant sign mounts from the LEFT edge, bread sign (crossed scored
   baguettes) from the RIGHT; transform-origin sits at each bracket's
   wall mount so the sway (and any mobile scale) hinges believably. */
.pm-motif--sign-croissant {
  width: 150px; height: 130px; transform-origin: 4px 14px;
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150 130'%3E%3Cg fill='black'%3E%3Crect x='0' y='6' width='6' height='64' rx='2'/%3E%3Crect x='6' y='12' width='100' height='5' rx='2'/%3E%3Crect x='78' y='17' width='2.5' height='21'/%3E%3Crect x='101' y='17' width='2.5' height='21'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round'%3E%3Cpath d='M106 14.5 C114 14.5 118 20 112 24 C108 26 106 22 109 20' stroke-width='3.5'/%3E%3Cpath d='M6 58 C40 54 76 38 100 20' stroke-width='4'/%3E%3Cpath d='M6 58 C2 54 3 47 9 46 C14 45 15 51 10 52' stroke-width='2.2'/%3E%3Ccircle cx='91' cy='72' r='34' stroke-width='6'/%3E%3C/g%3E%3Cg fill='black' transform='translate(0 3.5)'%3E%3Cpath d='M81 57 C88 52.5 94 52.5 101 57 C103.5 64 103 70.5 100 76 C94.5 73 87.5 73 82 76 C79 70.5 78.5 64 81 57 Z'/%3E%3Cpath d='M77.5 58.5 C71 62 66.5 68 65 76 C64.2 80.5 65.5 84.5 69 87 C70 82 72.5 78.5 78.5 77.5 C76.5 71.5 76.5 64.5 77.5 58.5 Z'/%3E%3Cpath d='M104.5 58.5 C111 62 115.5 68 117 76 C117.8 80.5 116.5 84.5 113 87 C112 82 109.5 78.5 103.5 77.5 C105.5 71.5 105.5 64.5 104.5 58.5 Z'/%3E%3C/g%3E%3C/svg%3E");
}
.pm-motif--sign-bread {
  width: 150px; height: 130px; transform-origin: 146px 14px;
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150 130'%3E%3Cg transform='translate(150 0) scale(-1 1)'%3E%3Cg fill='black'%3E%3Crect x='0' y='6' width='6' height='64' rx='2'/%3E%3Crect x='6' y='12' width='100' height='5' rx='2'/%3E%3Crect x='78' y='17' width='2.5' height='21'/%3E%3Crect x='101' y='17' width='2.5' height='21'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round'%3E%3Cpath d='M106 14.5 C114 14.5 118 20 112 24 C108 26 106 22 109 20' stroke-width='3.5'/%3E%3Cpath d='M6 58 C40 54 76 38 100 20' stroke-width='4'/%3E%3Cpath d='M6 58 C2 54 3 47 9 46 C14 45 15 51 10 52' stroke-width='2.2'/%3E%3Ccircle cx='91' cy='72' r='34' stroke-width='6'/%3E%3C/g%3E%3C/g%3E%3Cg fill='black' fill-rule='evenodd'%3E%3Cpath d='M35 72 C39 63.5 79 63.5 83 72 C79 80.5 39 80.5 35 72 Z M45.5 69.3 l7 -1.9 l1.1 2.4 l-7 1.9 Z M56.5 68.4 l7 -1.9 l1.1 2.4 l-7 1.9 Z M67 69 l7 -1.9 l1.1 2.4 l-7 1.9 Z' transform='rotate(45 59 72)'/%3E%3Cpath d='M35 72 C36.4 69.2 42 67.3 48.2 66.5 L48.2 77.5 C42 76.7 36.4 74.8 35 72 Z M38.8 70.2 l6.6 -1.8 l1.1 2.4 l-6.6 1.8 Z M83 72 C81.6 69.2 76 67.3 69.8 66.5 L69.8 77.5 C76 76.7 81.6 74.8 83 72 Z M71.8 68.6 l6.6 1.8 l-1.1 2.4 l-6.6 -1.8 Z' transform='rotate(-45 59 72)'/%3E%3C/g%3E%3C/svg%3E");
}
.pm-motif--cafe {
  width: 210px; height: 150px;
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 210 150'%3E%3Cg fill='black'%3E%3Crect x='118' y='38' width='84' height='7' rx='3.5'/%3E%3Crect x='157' y='45' width='6' height='76'/%3E%3Cpath d='M150 28 L170 28 L167 38 L153 38 Z'/%3E%3Crect x='146' y='38' width='28' height='2.5' rx='1'/%3E%3Cpath d='M28 88 C42 82 72 82 86 88 C72 94.5 42 94.5 28 88 Z'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round'%3E%3Cpath d='M160 118 C150 128 138 132 126 140' stroke-width='5'/%3E%3Cpath d='M160 118 C170 128 182 132 194 140' stroke-width='5'/%3E%3Cpath d='M160 118 L160 140' stroke-width='4'/%3E%3Cpath d='M36 86 L36 52 C36 30 78 30 78 52 L78 86' stroke-width='4.5'/%3E%3Cpath d='M43 86 L43 55 C43 40 71 40 71 55 L71 86' stroke-width='2.4'/%3E%3Cpath d='M33 91 C30 108 27 126 21 142' stroke-width='4'/%3E%3Cpath d='M81 91 C84 108 87 126 93 142' stroke-width='4'/%3E%3Cpath d='M42 91 C40 108 38 124 37 140' stroke-width='2.4'/%3E%3Cpath d='M72 91 C74 108 76 124 77 140' stroke-width='2.4'/%3E%3Cpath d='M27 116 C43 122 71 122 87 116' stroke-width='2.2'/%3E%3C/g%3E%3C/svg%3E");
}

/* — Manon Fit: Passerelle Debilly strip (tiles; dashed-stroke picket
     rail — dasharray 2.2/17.8 puts a baluster every 20u and 640/20
     divides exactly, so the rhythm never misses the seam; ONE pier per
     tile at x320 with the arch crown ON the seam — slope 0 at both tile
     edges — so pier spacing stays even and the arch runs unbroken at any
     width) + morning runner, mid-stride, never animated (a frozen stride
     reads "morning run"; a loop is wallpaper) — */
.pm-motif--bridge {
  height: 130px;
  --pm-motif-ink: rgba(56, 38, 22, 0.11);
  --pm-motif-ink-dark: rgba(10, 6, 3, 0.26);
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 130'%3E%3Cg fill='black'%3E%3Crect x='0' y='40' width='640' height='3'/%3E%3Crect x='0' y='65' width='640' height='7'/%3E%3Cpath d='M297 72 L343 72 L343 76 L338 76 L338 120 L302 120 L302 76 L297 76 Z'/%3E%3Crect x='318.4' y='24' width='3.2' height='16' rx='1'/%3E%3Ccircle cx='320' cy='20.5' r='3.2'/%3E%3C/g%3E%3Cline x1='0' y1='54' x2='640' y2='54' stroke='black' stroke-width='22' stroke-dasharray='2.2 17.8' stroke-dashoffset='-9' stroke-linecap='butt'/%3E%3Cpath d='M0 79 C100 79 220 90 300 112' fill='none' stroke='black' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M340 112 C420 90 540 79 640 79' fill='none' stroke='black' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M40 72 L40 79.5 M80 72 L80 81.3 M120 72 L120 84 M160 72 L160 87.4 M200 72 L200 92 M240 72 L240 99 M280 72 L280 107 M360 72 L360 107 M400 72 L400 99 M440 72 L440 92 M480 72 L480 87.4 M520 72 L520 84 M560 72 L560 81.3 M600 72 L600 79.5' fill='none' stroke='black' stroke-width='2'/%3E%3Cpath d='M0 124 Q10 120 20 124 T40 124 T60 124 T80 124 T100 124 T120 124 T140 124 T160 124 T180 124 T200 124 T220 124 T240 124 T260 124 T280 124 T300 124 T320 124 T340 124 T360 124 T380 124 T400 124 T420 124 T440 124 T460 124 T480 124 T500 124 T520 124 T540 124 T560 124 T580 124 T600 124 T620 124 T640 124' fill='none' stroke='black' stroke-width='2'/%3E%3C/svg%3E");
  -webkit-mask: var(--pm-motif-svg) left bottom / 640px 130px repeat-x;
          mask: var(--pm-motif-svg) left bottom / 640px 130px repeat-x;
}
.pm-motif--runner {
  width: 70px; height: 100px;
  --pm-motif-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 70 100'%3E%3Cg fill='black'%3E%3Ccircle cx='48' cy='13' r='7.5'/%3E%3Cpath d='M42 19 C52 24 50 40 42 54 L30 50 C34 38 36 27 42 19 Z'/%3E%3C/g%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M40 26 L26 33 L14 28' stroke-width='6'/%3E%3Cpath d='M42 27 L54 36 L66 28' stroke-width='6'/%3E%3Cpath d='M36 52 L52 63 L47 81 L55 85' stroke-width='7'/%3E%3Cpath d='M32 50 L19 65 L7 81' stroke-width='7'/%3E%3C/g%3E%3C/svg%3E");
}

/* only the hanging enseignes move — a slow hinge sway on the `rotate`
   property (compositor-only, and it composes with the arrangement
   blocks' mobile scale() transforms instead of stomping them). */
@media (prefers-reduced-motion: no-preference) {
  .pm-motif--sign-croissant, .pm-motif--sign-bread {
    animation: pm-sign-sway var(--pm-sway-dur, 13s) ease-in-out var(--pm-sway-phase, 0s) infinite;
    /* the sway animates the `rotate` property, not transform — hint both:
       rotate for the animation, transform for the arrangements' mobile scale */
    will-change: transform, rotate;
  }
  @keyframes pm-sign-sway {
    0%, 100% { rotate: -0.9deg; }
    50%      { rotate: 0.9deg; }
  }
}
