/* ===========================================================================
   lab.css — twelve directions for /en/buy/, built on the Ting arch.

   DESIGN SOURCE: the "vendre appartement paris" reference page.
     ground  #040404      gold  #F6D27A → #D9A83F 52% → #8F6612
     ink     #F5F2EA      hair  rgba(246,210,122,.15)
     display Sora 700/800 · body Figtree 400/500/600
     grain   feTurbulence, 7s steps(9), opacity .05

   WHY THE ARCH IS THE BRAND, not a borrowed shape: tingicon.svg is an arched
   capsule and logo-mark-white.svg names its own gradient `tingArch`. The mark
   is already a doorway. `border-radius:999px 999px 0 0` with the #FFCC00 →
   transparent glow IS the Ting logo, scaled. Every direction below is built
   from that one primitive, so the motion is branded rather than decorated.

   WHAT VARIES: each direction owns ONE signature motion of the door —
   passing through it, walking a colonnade of them, opening it, rising
   through it, being lit by it. The content architecture is shared this time;
   the animation is the variable.
   =========================================================================== */

/* ── the page's own frame gets out of the way ───────────────────────────── */
html[data-dir] .page{max-width:none;padding:0;margin:0;}
html[data-dir] .theme-toggle{display:none;}
/* font-family deliberately NOT set here: .labpage already carries its own
   Figtree stack (below), and this rule targets bare body — which is also the
   shipped hero's ancestor. Setting font-family here silently overrode the
   hero's Outfit title/composer with Figtree; a weight bumped on the Outfit
   rule then had no visible effect because Figtree's own Google Fonts request
   only loads 400/500/600 (see build-buy-directions.mjs). */
html[data-dir] body{background:#040404;color:#F5F2EA;line-height:1.65;}
html[data-dir] body .site-header{
  background:rgba(4,4,4,.72);border-bottom-color:rgba(246,210,122,.12);
  -webkit-backdrop-filter:saturate(150%) blur(16px);backdrop-filter:saturate(150%) blur(16px);
}
/* 20px edge padding on this header only — not a --gutter change, which is
   shared by the hero padding, sidebar offsets and composer width elsewhere
   on the site. */
html[data-dir] body .site-header .bar{padding:0 20px;}
html[data-dir] body .site-header.is-solid{
  background:rgba(4,4,4,.9);border-bottom:1px solid rgba(246,210,122,.18);
  -webkit-backdrop-filter:saturate(150%) blur(20px);backdrop-filter:saturate(150%) blur(20px);
  box-shadow:0 12px 40px -26px rgba(0,0,0,.95);
}
html[data-dir] body .site-header.is-solid .brand-mark{content:url(/pages-assets/logo-mark-white.svg);}
html[data-dir] body .site-header .brand,
html[data-dir] body .site-header .area-name,
html[data-dir] body .lang-btn,html[data-dir] body .search input{color:#F5F2EA;}
html[data-dir] body .search,
html[data-dir] body .site-header.is-solid .search{
  background:rgba(246,210,122,.05);border-color:rgba(246,210,122,.15);
}
html[data-dir] body .site-header.is-solid .lang-btn,
html[data-dir] body .site-header.is-solid .lang-btn--solo{
  background:rgba(246,210,122,.07);border-color:rgba(246,210,122,.18);
  box-shadow:none;backdrop-filter:none;color:#F5F2EA;
}
html[data-dir] body:has(.globe-intent) .site-header .area-name{display:none;}
html[data-dir] body .site-header .lang-menu summary.lang-btn,
html[data-dir] body:has(.globe-wrap) .site-header .lang-btn,
html[data-dir] body:has(.globe-intent) .site-header .lang-btn,
html[data-dir] body .site-header.is-solid .lang-menu summary.lang-btn{
  background:#f6f7f8;
  color:#16171a;
}
html[data-dir] body .site-header .lang-menu summary.lang-btn .lang-code,
html[data-dir] body .site-header .lang-menu summary.lang-btn .lang-arrow,
html[data-dir] body:has(.globe-wrap) .site-header .lang-code,
html[data-dir] body:has(.globe-wrap) .site-header .lang-arrow,
html[data-dir] body:has(.globe-intent) .site-header .lang-code,
html[data-dir] body:has(.globe-intent) .site-header .lang-arrow{
  color:#16171a;
}
html[data-dir] body .site-header .lang-menu summary.lang-btn:hover,
html[data-dir] body:has(.globe-wrap) .site-header .lang-btn:hover,
html[data-dir] body:has(.globe-intent) .site-header .lang-btn:hover{
  background:#f6f7f8;
}

/* White over the dark planet; black once the camera has zoomed into the
   light streets map. globe.js toggles .is-zoomed from the camera zoom. */
.intent-hero-top h1{color:#fff;transition:color .5s ease;margin-bottom:0;}
.intent-hero.is-zoomed .intent-hero-top h1{color:#000;}
.intent-hero-top{
  /* 10px of clearance UNDER THE HEADER, which is the only thing that can be
     measured from here: on this page the header is transparent and sits over
     the map rather than above it, so nothing reserves that band and a padding
     measured from the top of the viewport puts the title through the wordmark
     and the CTA.

     70px is `.site-header .bar` in common.css — a fixed height, declared once,
     with no media-query override, so this holds at every width. Named rather
     than folded into an 80px literal so the next person can see which part is
     the chrome and which part is the gap. */
  --header-h:70px;
  top:0;padding-top:calc(var(--header-h) + 10px);
  display:flex;flex-direction:column;align-items:center;gap:20px;
}
.intent-hero-top .intent-sub{
  /* 50% of the hero is a comfortable measure on a desktop and a 175px, seven-line
     ribbon on a phone. Cap by characters instead, so the line length is what is
     actually being controlled and it simply stops narrowing once the screen is. */
  width:min(100%,52ch);margin-left:auto;margin-right:auto;text-align:center;
  /* The sub-line needs the same swap as the heading above it, and did not have
     one: common.css paints it #ffffffb3, which is legible over the dark planet
     and gone the moment the streets tiles arrive underneath it. */
  color:rgba(255,255,255,.72);

  /* VARIANT 04 · AUBE — the sub-line rides a glass plate.
     Geometry only, here: the padding, the radius and the box-sizing are the
     same in BOTH states so that lighting the plate cannot reflow the line. On
     the dark planet the box is simply transparent, which is why the border is
     declared here as transparent rather than added later — a border appearing
     from nothing would shift the text by a pixel at the moment it fades in.

     `backdrop-filter: blur(0)` for the same reason the border is transparent:
     the filter has to exist in both states for the transition to interpolate,
     and it also makes this element a containing block from the start rather
     than at the moment the class lands. */
  box-sizing:border-box;
  position:relative;
  padding:17px 26px;
  border:1px solid transparent;
  border-radius:20px;
  background:transparent;
  -webkit-backdrop-filter:blur(0px);backdrop-filter:blur(0px);
  transition:color .5s ease, background-color .5s ease, border-color .5s ease,
             box-shadow .5s ease, backdrop-filter .5s ease;
}

/* The gold pip on the plate's left edge — Aube's, verbatim. Rides outside the
   box, which is safe: the sub-line is centred within a hero that is always
   wider than its 52ch measure, so -5px never reaches the viewport edge. */
.intent-hero-top .intent-sub::before{
  content:"";position:absolute;top:22px;left:-5px;
  width:10px;height:10px;border-radius:50%;
  background:#ffcc00;box-shadow:0 0 0 5px rgba(255,204,0,.22);
  opacity:0;transition:opacity .5s ease;
  pointer-events:none;
}

/* Lit only once the tiles are under it. Over the dark planet a pale glass panel
   would be an object floating in space; the plate exists to hold the line off
   the MAP, so it arrives with the map. */
.intent-hero.is-zoomed .intent-hero-top .intent-sub{
  color:#16171a;
  /* GLASS, not a card. Aube ships .80 white behind blur(14px), which on this
     page reads as an opaque panel with the map deleted underneath it — the
     alpha alone is nearly solid, and 14px of blur destroys whatever detail
     survives it, so the plate hid the very thing the hero is showing.
     .32 over a 2px blur keeps the map legible through the line — the coast,
     the road shields and the boundary all read — while the veil, the gold
     hairline and the warm shadow still separate the type from it. Compared
     settled, side by side: past about .46 the detail starts veiling over
     again, so this is the top of the range that still shows the map. */
  background:rgba(255,255,255,.32);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  border-color:rgba(255,204,0,.30);
  box-shadow:0 1px 2px rgba(90,66,0,.05), 0 22px 46px -30px rgba(120,88,0,.5);
}
.intent-hero.is-zoomed .intent-hero-top .intent-sub::before{opacity:1;}

/* The activity bubble lives in components/SocialBubble.astro now, fixed to the
   viewport rather than parked in the hero, and carries its own styles there —
   common.css's `.intent-toast` four-up cycle is a different mechanism from the
   queue ting.ad/ actually runs, so none of it is overridden here any more. */

/* Header sits outside the hero, so :has is what reaches the mark. White wordmark
   on the dark globe; black wordmark (logo-mark.svg) once streets tiles fill in. */
html[data-dir] body:has(.intent-hero.is-zoomed) .site-header .brand-mark,
html[data-dir] body:has(.intent-hero.is-zoomed) .site-header.is-solid .brand-mark{
  content:url(/pages-assets/logo-mark.svg);filter:none;
}

/* Globe-map case only. The force-dark bar above paints rgba(4,4,4,.72) over
   the hero, and common.css insets the canvas 210px from the top — together
   they hide the map under a black header. Keep the chrome clear and let the
   tiles run under it. html[data-dir].is-through (further down) still paints
   the header once the reader has walked through the door. */
html[data-dir] body:has(.globe-intent) .site-header,
html[data-dir] body:has(.globe-intent) .site-header.is-solid{
  background:transparent;border-bottom:0;box-shadow:none;
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
html[data-dir] body:has(.globe-intent) .globe-wrap.has-globe .globe-canvas-host{
  top:0;bottom:0;
}

/* ── the reset the reference got from a bare document ───────────────────── */
.labpage,.labpage *,.labpage *::before,.labpage *::after{box-sizing:border-box;}
.labpage{
  --noir:#040404; --or1:#F6D27A; --or2:#D9A83F; --or3:#8F6612;
  --blanc:#F5F2EA; --bleu:#4C7DFF; --vert:#3ECF83; --rouge:#E88484;
  --ting:#FFCC00;
  --hair:rgba(246,210,122,.15);
  --grad:linear-gradient(180deg,#F6D27A,#D9A83F 52%,#8F6612);
  --ease:cubic-bezier(.2,.8,.2,1);
  font-family:'Figtree',-apple-system,'Segoe UI',Helvetica,Arial,sans-serif;
  line-height:1.65;flex:1 0 auto;width:100%;min-width:0;
  -webkit-font-smoothing:antialiased;
}
.labpage h1,.labpage h2,.labpage h3{
  font-family:'Sora',-apple-system,'Segoe UI',Helvetica,Arial,sans-serif;
  font-weight:800;line-height:1.06;letter-spacing:-.028em;margin:0;
}
.labpage p{margin:0;}
.labpage a{color:inherit;text-decoration:none;}
.labpage a:hover{text-decoration:none;}
.labpage img{max-width:100%;display:block;}
.labpage button{font:inherit;color:inherit;}
.labpage canvas{display:block;}
.labpage ul,.labpage ol{list-style:none;margin:0;padding:0;}

.wrap{max-width:1120px;margin:0 auto;padding:0 28px;}
.narrow{max-width:780px;margin:0 auto;padding:0 28px;}
.eyebrow{
  display:block;font-family:'Sora',sans-serif;font-weight:700;font-size:11px;
  letter-spacing:.32em;text-transform:uppercase;color:var(--or2);margin-bottom:20px;
}
.gold{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;}
.cta{
  display:inline-flex;align-items:center;gap:12px;background:var(--grad);color:#221703;
  font-family:'Sora',sans-serif;font-weight:700;font-size:15.5px;padding:19px 36px;
  border-radius:999px;transition:transform .3s,box-shadow .3s;
  box-shadow:0 0 0 1px rgba(246,210,122,.3),0 18px 50px -12px rgba(217,168,63,.45);
  will-change:transform;
}
.cta:hover{transform:translateY(-2px);}

/* film grain — the reference's exact recipe */
.labpage .grain{
  content:"";position:fixed;inset:-100%;pointer-events:none;z-index:99;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 7s steps(9) infinite;
}
@keyframes grain{
  0%,100%{transform:translate(0,0)}20%{transform:translate(-4%,3%)}
  40%{transform:translate(3%,-4%)}60%{transform:translate(-3%,-2%)}80%{transform:translate(2%,4%)}
}

/* ═══════════════════════════════════════════════════════ THE ARCH PRIMITIVE
   One shape, used at every scale: the gate you walk through, the frame round
   a figure, the bullet on a list, the tick before a step number. */
.arch{border-radius:999px 999px 0 0;}
.arch-b::before{
  content:"";display:block;width:44px;height:26px;border-radius:99px 99px 0 0;
  border:1px solid var(--or2);border-bottom:none;margin-bottom:16px;
  background:linear-gradient(180deg,rgba(217,168,63,.25),transparent);
}

/* ═══════════════════════════════════════════════════════════════ THE DOOR
   The branded gate. Shared shell; each direction drives it differently from
   lab.js — that is the whole point of these twelve. */
/* The gate is a sticky 100vh viewport, so anything after it in flow is
   off-screen until the gate ends — which is why the door used to finish onto
   a long stretch of black before the content arrived. The negative margin
   pulls the body back up over the tail of the gate, so it scrolls INTO the
   still-pinned doorway while the door is opening. */
.gate{position:relative;margin-bottom:var(--gate-pull,-124svh);}
[data-emerge]{position:relative;z-index:2;}

/* How far the content is pulled up over the pinned door.
   I tried to guess per direction which doors leave something on screen and
   which empty it — and guessed wrong twice (d1, then d5). So the large pull
   is now the DEFAULT: the content rides up through the doorway for most of
   the gate on every direction, which is the behaviour asked for.
   d12 is pinned to the smaller value because it is the one confirmed right
   by eye; its ripple rings hold the screen on their own and it does not need
   the content arriving early. */
.d12{--gate-pull:-72svh;}
/* d1 pulls by exactly one viewport, and its gate is one viewport longer to
   pay for it (.d1 .gate below) — the same total scroll as the pull-free
   reference, with the dead viewport between the pin release and the article
   turned into the hand-over instead. -100vh, not -100svh: d1 is the one
   direction measured in vh throughout (see .d1 .gate .stick), and a pull in
   the other unit would put the article's resting place a phone's toolbar
   height away from the pin release rather than exactly on it. */
.d1{--gate-pull:-100vh;}

/* The first section's own top padding was delaying the visible text by about
   half a viewport after its box had already entered — the box arrived on
   time and the words did not. */
[data-emerge] .sec:first-of-type{padding-top:3vh;}
.gate .stick{
  position:sticky;top:0;height:100svh;display:flex;align-items:center;
  justify-content:center;overflow:hidden;
}
/* d1 only: plain 100vh, matching the reference artifact's own CSS exactly
   (the other directions keep 100svh — see the mobile black-screen fix). */
.d1 .gate .stick{height:100vh;}
.gate .halo{
  position:absolute;left:50%;top:58%;transform:translate(-50%,-50%);
  width:140vmin;height:140vmin;will-change:opacity;
  background:radial-gradient(circle,rgba(217,168,63,.13),transparent 60%);
}
/* the door itself — the Ting mark, at architectural scale */
/* Matches the reference artifact's own .archz exactly: min(28vh,240px). */
.labpage{--door-w:min(28vh,240px);}
.door-mark{
  position:relative;width:var(--door-w);aspect-ratio:10/14;
  will-change:transform;transform-origin:50% 60%;margin-top:6vh;
}
.door-mark .frame{
  position:absolute;inset:0;border-radius:999px 999px 0 0;
  border:2px solid rgba(246,210,122,.85);border-bottom:none;
  box-shadow:0 0 60px -8px rgba(217,168,63,.55),inset 0 0 70px -20px rgba(217,168,63,.5);
}
.door-mark .frame::before{
  content:"";position:absolute;inset:12px 12px 0;border-radius:999px 999px 0 0;
  border:1px solid rgba(246,210,122,.28);border-bottom:none;
}
/* the mark's own gradient: #FFCC00 → transparent at 81%, straight off tingicon.svg */
.door-mark .inner{
  position:absolute;inset:0;border-radius:999px 999px 0 0;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,204,0,.30),rgba(255,208,0,0) 81%);
}
.door-mark .light{
  position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:180%;height:60%;
  background:radial-gradient(50% 100% at 50% 100%,rgba(246,210,122,.5),transparent 68%);
  filter:blur(6px);
}
.gtext{
  position:absolute;left:50%;transform:translateX(-50%);text-align:center;
  width:min(92vw,940px);will-change:opacity,transform;padding:0 20px;
}
.gt1{top:10vh;}
.gt1 h1{font-size:clamp(32px,5vw,62px);}
.gt1 p{
  margin-top:16px;color:rgba(245,242,234,.55);font-size:clamp(15px,1.6vw,18px);
  max-width:620px;margin-left:auto;margin-right:auto;
}
.gt1 .gate-h1{
  font-size:30px;font-weight:600;color:#fff;opacity:1;margin-top:0;
}
.gt1 .gate-h1 + p{
  font-size:18px;color:rgba(255,255,255,.8);margin-top:5px;
}
.gt2{top:50%;transform:translate(-50%,-50%);opacity:0;}
.gt2 .line{
  font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(28px,4.4vw,54px);
  letter-spacing:-.028em;line-height:1.12;
}
.gt2 .line span{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;}
/* When the gate ends on the article's own first question, lab.js sizes this
   line to the heading's measure — narrower than .gtext — so the BOX has to sit
   centred in .gtext, and .labpage p{margin:0} would otherwise pin it to the
   left edge. The text inside it stays centred on .gtext's own text-align.
   Inert on the product-line fallback, which carries no width and fills the box
   as it always did. */
.gt2 .line{margin-left:auto;margin-right:auto;}
.flash{
  position:absolute;inset:0;opacity:0;pointer-events:none;will-change:opacity;
  background:radial-gradient(circle at 50% 55%,#FFF8E1 0%,rgba(246,210,122,.85) 28%,rgba(217,168,63,.25) 55%,rgba(4,4,4,0) 75%);
}
.hint{
  position:absolute;bottom:26px;left:50%;transform:translateX(-50%);font-size:11px;
  letter-spacing:.3em;text-transform:uppercase;color:rgba(245,242,234,.4);
  display:flex;flex-direction:column;align-items:center;gap:10px;
}
.hint::after{
  content:"";width:1px;height:34px;
  background:linear-gradient(180deg,var(--or2),transparent);animation:drop 1.6s ease-in-out infinite;
}
@keyframes drop{
  0%{transform:scaleY(0);transform-origin:top}55%{transform:scaleY(1);transform-origin:top}
  56%{transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}
}

/* ═══════════════════════════════════════════════════════ SHARED SECTIONS */
.sec{padding:11vh 0 5vh;}
.sec .head{max-width:780px;margin:0 auto 66px;text-align:center;padding:0 28px;}
.sec h2{font-size:clamp(28px,3.8vw,48px);margin-bottom:18px;}
.sec .head p{color:rgba(245,242,234,.6);font-size:17px;}

/* figures — three big numbers, the reference's .mgrid */
.figs{
  display:grid;grid-template-columns:repeat(2,1fr);max-width:1020px;margin:0 auto;
  text-align:center;padding:0 28px;
}
@media(min-width:820px){.figs{grid-template-columns:repeat(4,1fr);}}
.fig{padding:22px 24px;position:relative;}
.fig + .fig::before{content:"";position:absolute;left:0;top:12%;bottom:12%;width:1px;background:var(--hair);}
.fig .n{
  font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(38px,4.6vw,60px);
  letter-spacing:-.04em;line-height:1;background:var(--grad);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  font-variant-numeric:tabular-nums;
}
.fig .k{
  margin-top:12px;font-family:'Sora',sans-serif;font-weight:700;font-size:11px;
  letter-spacing:.18em;text-transform:uppercase;color:var(--or2);
}
.fig .l{margin-top:8px;font-size:14px;color:rgba(245,242,234,.55);max-width:250px;margin-left:auto;margin-right:auto;}

/* prose */
.prose p{color:rgba(245,242,234,.68);font-size:16.5px;margin-bottom:20px;}
.prose p b{color:var(--blanc);font-weight:600;}
.prose h3{font-size:clamp(20px,2.3vw,26px);margin:44px 0 16px;}

/* the three benefits, as arch-topped cards */
.trio{display:grid;grid-template-columns:1fr;gap:26px;max-width:1020px;margin:0 auto;padding:0 28px;}
@media(min-width:840px){.trio{grid-template-columns:repeat(3,1fr);}}
.tcard{position:relative;padding:34px 26px 30px;border:1px solid var(--hair);border-radius:120px 120px 22px 22px;
  background:linear-gradient(180deg,rgba(246,210,122,.045),rgba(246,210,122,.006) 70%);
  transition:border-color .5s var(--ease),transform .5s var(--ease);text-align:center;}
.tcard:hover{border-color:rgba(246,210,122,.5);transform:translateY(-6px);}
.tcard .ix{font-family:'Sora',sans-serif;font-weight:700;font-size:11px;letter-spacing:.24em;color:var(--or2);}
.tcard h3{font-size:19px;margin:14px 0 10px;letter-spacing:-.02em;}
.tcard p{font-size:14.5px;color:rgba(245,242,234,.6);}

/* the four chapters, as numbered steps */
.step{
  display:grid;grid-template-columns:1fr;gap:16px;max-width:960px;margin:0 auto;
  padding:52px 28px;border-top:1px solid var(--hair);
}
@media(min-width:860px){.step{grid-template-columns:200px 1fr;gap:clamp(28px,5vw,80px);}}
.step:last-of-type{border-bottom:1px solid var(--hair);}
.step .num{
  font-family:'Sora',sans-serif;font-weight:800;font-size:14px;letter-spacing:.24em;
  color:var(--or2);text-transform:uppercase;padding-top:8px;
}
.step h3{font-size:clamp(20px,2.4vw,28px);margin-bottom:12px;letter-spacing:-.02em;}
.step p{font-size:16px;color:rgba(245,242,234,.62);max-width:600px;margin-bottom:14px;}
.step .ex{
  display:block;margin-top:16px;padding-left:20px;border-left:2px solid var(--or3);
  font-size:15px;color:rgba(246,210,122,.75);font-style:italic;
}
.step ul{display:grid;gap:11px;margin-top:18px;}
.step ul li{display:flex;gap:13px;font-size:15px;color:rgba(245,242,234,.7);}
.step ul li::before{content:"";flex:0 0 16px;height:10px;margin-top:8px;background:var(--grad);border-radius:9px 9px 0 0;}
.step .rev{margin-top:18px;font-size:14.5px;color:rgba(245,242,234,.55);}
.step .rev b{color:var(--or1);font-weight:600;}

/* ═══ FIGURES — the reference's .archfig, arched photo/art frames ═══ */
.figrow{display:grid;grid-template-columns:1fr;gap:28px;max-width:940px;margin:60px auto;padding:0 28px;}
@media(min-width:700px){.figrow{grid-template-columns:1fr 1fr;}}
figure.archfig{margin:0;}
figure.archfig.solo{max-width:640px;margin:60px auto;padding:0 28px;grid-column:1/-1;}
.archfig .ph{position:relative;aspect-ratio:4/3;border-radius:180px 180px 24px 24px;overflow:hidden;
  border:1px solid var(--hair);background:linear-gradient(180deg,#0B0A08,#060605);}
.archfig .ph svg.art{position:absolute;inset:0;width:100%;height:100%;}
.archfig .ph::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(4,4,4,0) 55%,rgba(4,4,4,.55));pointer-events:none;}
.archfig figcaption{margin-top:14px;font-size:13px;color:rgba(245,242,234,.45);text-align:center;}

/* ═══ MARKET CURVE — the reference's price/index line chart ═══ */
.curve{max-width:860px;margin:70px auto 0;padding:0 28px;}
.curve .box{border:1px solid var(--hair);border-radius:26px;padding:34px 30px 24px;background:rgba(255,255,255,.012);}
.curve h3{font-size:17px;margin-bottom:6px;}
.curve .sub{font-size:13px;color:rgba(245,242,234,.45);margin-bottom:18px;}
.curve svg{width:100%;height:auto;display:block;}

/* ═══ MARKET TABLE — the reference's arrondissement price table ═══ */
.tbl{max-width:860px;margin:70px auto 0;padding:0 28px;}
.tbl h3{font-size:clamp(20px,2.4vw,27px);margin-bottom:8px;}
.tbl .sub{font-size:14px;color:rgba(245,242,234,.5);margin-bottom:26px;}
/* the scroll container, not the page, takes any horizontal overflow —
   narrow phones get a contained scroller instead of a wider viewport. */
.tbl .tblwrap{overflow-x:auto;}
.tbl table{width:100%;min-width:420px;border-collapse:collapse;font-size:14.5px;}
.tbl thead th{font-family:'Sora',sans-serif;font-weight:700;font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--or2);text-align:left;padding:0 14px 14px;
  border-bottom:1px solid rgba(246,210,122,.35);}
.tbl thead th:last-child,.tbl tbody td:last-child{text-align:right;}
.tbl tbody td{padding:12.5px 14px;border-bottom:1px solid rgba(255,255,255,.06);color:rgba(245,242,234,.75);}
.tbl tbody tr:hover td{background:rgba(246,210,122,.04);}
.tbl tbody td b{font-family:'Sora',sans-serif;font-weight:700;color:var(--blanc);}
.tbl td .up{color:var(--vert);}
.tbl td .dn{color:var(--rouge);}
.tbl .note{margin-top:14px;font-size:12.5px;color:rgba(245,242,234,.35);}

/* ═══ GUIDE — checklist + warning boxes, the reference's .checks/.warn ═══ */
/* Title on row 1, description on row 2 — flex put <b> and the text node
   side-by-side, which crushed titles into one-word columns on mobile. */
.checks{list-style:none;display:grid;gap:18px;margin:22px 0 8px;padding:0;}
.checks li{
  display:grid;grid-template-columns:18px 1fr;column-gap:13px;row-gap:4px;
  font-size:15.5px;color:rgba(245,242,234,.72);align-items:start;
}
.checks li::before{content:"";grid-row:1 / span 2;width:18px;height:11px;margin-top:6px;background:var(--grad);border-radius:9px 9px 0 0;}
.checks li b{grid-column:2;color:var(--blanc);font-weight:600;line-height:1.3;}
.checks li span{grid-column:2;display:block;line-height:1.55;}
.warn{border:1px solid rgba(232,132,132,.3);border-radius:20px;padding:22px 26px;margin:26px 0;
  background:rgba(232,132,132,.04);}
.warn p{color:rgba(245,242,234,.7);font-size:15px;margin:0;}
.warn b{color:var(--rouge);}

/* ═══ MARKETS GRID — the reference's .hoods/.hgrid arrondissement chips ═══ */
.hoods{padding:10vh 28px 6vh;}
.hoods .head{max-width:760px;margin:0 auto 60px;text-align:center;}
.hoods h2{font-size:clamp(26px,3.4vw,42px);margin-bottom:14px;}
.hoods .head p{color:rgba(245,242,234,.55);font-size:16px;}
.hgrid{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;max-width:940px;margin:0 auto;list-style:none;padding:0;}
.hood{display:inline-flex;align-items:center;gap:10px;border:1px solid var(--hair);border-radius:999px;
  padding:12px 22px;font-family:'Sora',sans-serif;font-weight:600;font-size:13.5px;
  color:rgba(245,242,234,.75);transition:border-color .3s,color .3s,background .3s;}
.hood:hover{border-color:rgba(246,210,122,.6);color:var(--or1);background:rgba(246,210,122,.05);}
.hood::before{content:"";width:7px;height:9px;border-radius:99px 99px 0 0;background:var(--grad);opacity:.8;}

/* the group call — arch doors with a speaking spotlight */
.call{padding:6vh 0 10vh;text-align:center;}
.call h2{font-size:clamp(28px,3.8vw,48px);max-width:880px;margin:0 auto 14px;padding:0 28px;}
.call .sub{color:rgba(245,242,234,.55);max-width:620px;margin:0 auto 70px;font-size:16.5px;padding:0 28px;}
/* Headroom for the tallest card: .door.me is 50px taller than the others
   AND lifts -12px extra while speaking — without slack above the row, that
   card's rounded top can crowd or clip against whatever sits right above it
   on shorter viewports. (margin-top must live in the shorthand below —
   a prior `margin:0 auto` was wiping a separate margin-top:24px.) */
.doorrow{
  display:flex;align-items:flex-end;justify-content:center;gap:clamp(12px,2.6vw,34px);
  max-width:1000px;margin:28px auto 0;padding:20px 24px 12px;position:relative;flex-wrap:wrap;
}
.doorrow::after{
  content:"";position:absolute;left:6%;right:6%;bottom:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(246,210,122,.4) 18%,rgba(246,210,122,.4) 82%,transparent);
}
.door{flex:0 1 148px;text-align:center;transition:transform .5s var(--ease);}
.door .frame{
  position:relative;aspect-ratio:10/14;border-radius:999px 999px 0 0;
  border:1px solid var(--hair);border-bottom:none;overflow:hidden;
  background:linear-gradient(180deg,rgba(246,210,122,.045),rgba(246,210,122,.005) 78%);
  transition:border-color .5s,box-shadow .5s;
}
.door .sil{position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:60%;}
.door .glow{
  position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:150%;height:55%;opacity:.25;
  background:radial-gradient(55% 95% at 50% 100%,rgba(217,168,63,.4),transparent 70%);transition:opacity .5s;
}
.door .eq{position:absolute;top:16%;left:50%;transform:translateX(-50%);display:flex;gap:3.5px;align-items:flex-end;height:16px;opacity:0;transition:opacity .4s;}
.door .eq i{width:2.5px;background:var(--or1);border-radius:2px;animation:eq .9s ease-in-out infinite;}
.door .eq i:nth-child(1){height:40%}.door .eq i:nth-child(2){height:100%;animation-delay:.15s}
.door .eq i:nth-child(3){height:60%;animation-delay:.3s}.door .eq i:nth-child(4){height:85%;animation-delay:.45s}
@keyframes eq{50%{transform:scaleY(.3)}}
.door .meta{margin-top:16px;}
.door .meta b{display:block;font-family:'Sora',sans-serif;font-weight:700;font-size:14px;}
.door .meta span{display:block;font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;margin-top:4px;color:rgba(245,242,234,.4);}
.door .meta i{display:inline-block;width:5px;height:5px;border-radius:50%;margin-right:6px;vertical-align:1.5px;background:var(--bleu);}
.door.me{flex:0 1 184px;}
.door.me .frame{border-color:rgba(246,210,122,.6);background:linear-gradient(180deg,rgba(246,210,122,.12),rgba(246,210,122,.015) 80%);}
.door.me .meta b{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;}
.door.speaking{transform:translateY(-12px);}
.door.speaking .frame{border-color:rgba(246,210,122,.9);box-shadow:0 0 70px -12px rgba(217,168,63,.65);}
.door.speaking .glow{opacity:1;}
.door.speaking .eq{opacity:1;}
/* Name on its own row; quote underneath — side-by-side cramps on mobile and
   overlaps the door metas when the row wraps. Keep clear of the doorrow
   floor line (::after at bottom:0) so the speaker name never kisses it. */
.livecap{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  margin-top:28px;padding-top:16px;font-size:14.5px;color:rgba(245,242,234,.5);
  min-height:2.6em;padding-left:24px;padding-right:24px;line-height:1.45;text-align:center;
}
.livecap b{color:var(--or1);font-weight:600;}
.livecap span{display:block;max-width:36em;}
@media(max-width:700px){
  /* Sticky header is 70px; wrapped door rows otherwise park their meta flush
     under the bar. Extra top pad + softer speaking lift keeps Omar clear. */
  .call{padding-top:8vh;}
  .call .sub{margin-bottom:36px;}
  .doorrow{margin-top:12px;padding:32px 16px 14px;gap:18px 14px;}
  .door{flex:0 1 132px;}
  .door.me{flex:0 1 152px;}
  .door.speaking{transform:translateY(-6px);}
  .door .meta{margin-top:12px;padding-bottom:4px;}
  .livecap{margin-top:32px;padding:24px 20px 0;}
  .narrow.prose h3{scroll-margin-top:88px;padding-top:8px;}
}

/* ticker */
.ticker{
  margin:4vh 0 0;border-top:1px solid var(--hair);border-bottom:1px solid var(--hair);
  background:linear-gradient(180deg,rgba(246,210,122,.05),rgba(246,210,122,.02));overflow:hidden;padding:20px 0;
}
.ticker .track{display:flex;width:max-content;animation:tick 26s linear infinite;}
.ticker:hover .track{animation-play-state:paused;}
.ticker .item{display:inline-flex;align-items:center;padding:0 34px;font-family:'Sora',sans-serif;font-weight:700;font-size:15px;white-space:nowrap;gap:16px;}
.ticker .item .n{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;font-size:22px;font-weight:800;}
.ticker .item::after{content:"";width:8px;height:10px;border-radius:99px 99px 0 0;background:var(--grad);margin-left:34px;opacity:.7;}
@keyframes tick{to{transform:translateX(-50%)}}

/* faq */
.faq{max-width:820px;margin:0 auto;padding:6vh 28px 10vh;}
.faq h2{font-size:clamp(26px,3.4vw,42px);text-align:center;margin-bottom:52px;}
.faq details{border-top:1px solid var(--hair);}
.faq details:last-of-type{border-bottom:1px solid var(--hair);}
.faq summary{
  cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center;
  gap:20px;padding:25px 2px;font-family:'Sora',sans-serif;font-weight:700;font-size:16.5px;
}
.faq summary::-webkit-details-marker{display:none;}
.faq summary .pl{flex:0 0 20px;height:20px;position:relative;}
.faq summary .pl::before,.faq summary .pl::after{content:"";position:absolute;background:var(--or2);left:50%;top:50%;transform:translate(-50%,-50%);}
.faq summary .pl::before{width:13px;height:1.5px;}
.faq summary .pl::after{width:1.5px;height:13px;transition:transform .3s;}
.faq details[open] summary .pl::after{transform:translate(-50%,-50%) scaleY(0);}
.faq details p{padding:0 2px 26px;color:rgba(245,242,234,.6);font-size:15.5px;max-width:680px;}

/* internal links */
.mesh{padding:0 28px 10vh;}
.mesh .box{max-width:960px;margin:0 auto;border-top:1px solid var(--hair);padding-top:60px;}
.mesh h2{font-size:15px;font-family:'Sora',sans-serif;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:rgba(245,242,234,.45);margin-bottom:24px;}
.mesh ul{display:flex;flex-direction:column;gap:12px;}
.mesh a{color:rgba(245,242,234,.72);font-size:16.5px;transition:color .3s,padding-left .4s var(--ease);display:inline-block;}
.mesh a::before{content:"→ ";color:var(--or2);}
.mesh a:hover{color:var(--or1);padding-left:8px;}

/* final */
/* overflow:hidden clips .beam (1100px, decorative, meant to bleed softly
   past its own section) — was previously masked by a global overflow-x:hidden
   that has since been removed (it broke position:sticky for the door).
   Scoped here instead: .final has nothing to do with the sticky chain, so
   this can't touch that. */
.final{padding:4vh 28px 18vh;text-align:center;position:relative;overflow:hidden;}
.final .beam{
  position:absolute;left:50%;bottom:-10%;transform:translateX(-50%);width:1100px;height:600px;
  background:radial-gradient(50% 70% at 50% 100%,rgba(217,168,63,.17),transparent 70%);pointer-events:none;
}
.final h2{font-size:clamp(32px,5vw,62px);margin-bottom:18px;position:relative;}
.final p{color:rgba(245,242,234,.55);margin-bottom:42px;font-size:17px;max-width:580px;margin-left:auto;margin-right:auto;position:relative;}
.final .cta{position:relative;}
.labfoot{padding:0 28px 46px;text-align:center;font-size:13px;color:rgba(245,242,234,.3);}

/* ── entrance primitives, shared by every direction ─────────────────────── */
[data-rise]{opacity:0;transform:translateY(26px);
  transition:opacity .85s var(--ease),transform .85s var(--ease);
  transition-delay:calc(var(--d,0) * 80ms);}
[data-rise].lit{opacity:1;transform:none;}
[data-wipe]{clip-path:inset(0 100% 0 0);transition:clip-path 1.05s cubic-bezier(.76,0,.24,1);
  transition-delay:calc(var(--d,0) * 80ms);}
[data-wipe].lit{clip-path:inset(0 0 0 0);}
.w{display:inline-block;overflow:hidden;vertical-align:bottom;}
.w i{display:inline-block;font-style:inherit;transform:translateY(105%);
  transition:transform .9s var(--ease);transition-delay:calc(var(--d,0) * 45ms);}
.lit .w i{transform:none;}

/* the lab switcher */
.labbar{
  position:fixed;right:14px;bottom:14px;z-index:9999;display:flex;align-items:center;gap:5px;
  padding:6px;max-width:calc(100vw - 28px);overflow-x:auto;scrollbar-width:none;
  background:rgba(6,5,4,.94);border:1px solid rgba(246,210,122,.28);border-radius:999px;
  box-shadow:0 18px 44px -20px rgba(0,0,0,.85);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  font-family:'Sora',system-ui,sans-serif;
}
.labbar::-webkit-scrollbar{display:none;}
.labbar b{flex:0 0 auto;color:var(--or1);font-size:10px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;padding:0 8px 0 10px;}
.labbar a{flex:0 0 auto;padding:6px 11px;border-radius:999px;border:1px solid transparent;font-size:12px;font-weight:600;color:rgba(245,242,234,.62);white-space:nowrap;}
.labbar a:hover{color:#fff;border-color:rgba(246,210,122,.4);}
.labbar a[aria-current="page"]{background:var(--grad);color:#221703;}
@media print{.labbar{display:none;}}

@media(prefers-reduced-motion:reduce){
  .labpage *{animation:none!important;transition:none!important;}
  /* The pull has to go with the height: a collapsed gate that still carries
     margin-bottom:-100vh drags the article a full viewport up over it. */
  .gate{height:auto!important;margin-bottom:0!important;}
  .gate .stick{position:relative;height:auto;padding:120px 0;}
  .gt2{position:relative;opacity:1;transform:none;margin-top:60px;top:auto;left:auto;}
  .door-mark{transform:none!important;}
  [data-rise],[data-wipe]{opacity:1;transform:none;clip-path:none;}
  .w i{transform:none;}
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE TWELVE DOORS
   One primitive, twelve ways of moving through it. Each block styles only
   what its own motion needs; lab.js drives the transform per direction.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 01 · THRESHOLD — the door scales to 10× and you pass through it, and the
   page comes out the other side in daylight (see DAYLIGHT, at the foot of
   this file).

   440vh where the reference had 340vh, against a -100vh pull: gate-top to
   article-top is 340vh either way, so the reader scrolls exactly as far as
   before. What changes is that the last viewport of it is spent inside the
   pinned doorway — the line answering the door, then the article rising into
   it — instead of on one screen of empty ground between the two. The door's
   own beat still runs over the first 240vh; lab.js reads it against `d`. */
.d1 .gate{height:440vh;}
.d1 .door-mark{margin-top:14vh;}
@media(max-width:880px){.d1 .gate{height:380vh;}}

/* 02 · COLONNADE — a corridor of doors receding into the dark; scroll walks it. */
.d2 .gate{height:260svh;}
.d2 .colonnade{position:absolute;inset:0;perspective:900px;perspective-origin:50% 48%;}
.d2 .col-arch{
  position:absolute;left:50%;top:50%;width:var(--door-w);aspect-ratio:10/14;
  transform-origin:50% 50%;will-change:transform,opacity;
  border-radius:999px 999px 0 0;border:1.5px solid rgba(246,210,122,.7);border-bottom:none;
  box-shadow:0 0 50px -14px rgba(217,168,63,.5);
}
.d2 .col-arch::before{
  content:"";position:absolute;inset:0;border-radius:999px 999px 0 0;
  background:linear-gradient(180deg,rgba(255,204,0,.14),transparent 81%);
}
.d2 .door-mark{display:none;}

/* 03 · KEYHOLE — the page is revealed through the door, which widens. */
.d3 .gate{height:240svh;}
.d3 .keyhole{
  position:absolute;inset:0;background:#040404;will-change:clip-path;
  clip-path:polygon(0 0,100% 0,100% 100%,0 100%);
}
.d3 .keyview{position:absolute;inset:0;overflow:hidden;}
.d3 .keyview .kimg{
  position:absolute;inset:0;
  background:radial-gradient(60% 50% at 50% 42%,rgba(255,204,0,.22),transparent 62%),
             linear-gradient(180deg,#0B0A07,#040404 70%);
}
.d3 .door-mark .inner{background:none;}

/* 04 · ASCENT — doors stacked as storeys; you rise through them. */
.d4 .gate{height:270svh;}
.d4 .shaft{position:absolute;inset:0;overflow:hidden;}
.d4 .storey{
  position:absolute;left:50%;transform:translateX(-50%);width:var(--door-w);aspect-ratio:10/14;
  border-radius:999px 999px 0 0;border:1.5px solid rgba(246,210,122,.55);border-bottom:none;
  will-change:transform,opacity;
}
.d4 .storey .lbl{
  position:absolute;left:50%;bottom:-26px;transform:translateX(-50%);
  font-family:'Sora',sans-serif;font-size:10px;letter-spacing:.28em;text-transform:uppercase;
  color:rgba(246,210,122,.6);white-space:nowrap;
}
.d4 .door-mark{display:none;}

/* 05 · FOYER — the door has two leaves, and they open. */
.d5 .gate{height:240svh;}
.d5 .leaves{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;perspective:1400px;}
.d5 .leaf{
  width:calc(var(--door-w) / 2);aspect-ratio:5/14;will-change:transform;
  border:2px solid rgba(246,210,122,.85);
  background:linear-gradient(180deg,rgba(255,204,0,.16),rgba(255,208,0,0) 81%);
  box-shadow:0 0 60px -10px rgba(217,168,63,.5);
}
.d5 .leaf.l{border-right:none;border-radius:999px 0 0 0;transform-origin:left center;}
.d5 .leaf.r{border-left:none;border-radius:0 999px 0 0;transform-origin:right center;}
.d5 .leaf::after{content:"";position:absolute;inset:10px;border:1px solid rgba(246,210,122,.25);}
.d5 .door-mark{display:none;}

/* 06 · LANTERN — a light inside the door sweeps, and reveals as it passes. */
.d6 .gate{height:230svh;}
.d6 .door-mark .beamlight{
  position:absolute;left:50%;top:0;bottom:0;width:56%;transform:translateX(-50%);
  background:linear-gradient(90deg,transparent,rgba(255,244,200,.55),transparent);
  filter:blur(10px);will-change:transform;
}
.d6 .sec h2,.d6 .step h3{
  background:linear-gradient(90deg,rgba(245,242,234,.28) 40%,#FFF6D8 50%,rgba(245,242,234,.28) 60%);
  background-size:280% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;
  animation:sweep 7s linear infinite;
}
@keyframes sweep{to{background-position:-280% 0}}

/* 07 · PROCESSION — the chapters walk through the door one at a time. */
.d7 .gate{height:260svh;}
.d7 .proc{position:absolute;inset:0;display:grid;place-items:center;perspective:1000px;}
.d7 .marcher{
  position:absolute;width:min(60vw,520px);text-align:center;will-change:transform,opacity;
  font-family:'Sora',sans-serif;font-weight:800;letter-spacing:-.03em;
  font-size:clamp(20px,3.2vw,40px);line-height:1.1;
}
.d7 .marcher span{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;}

/* 08 · REFLECTION — the door stands on water, and everything has a twin. */
.d8 .gate{height:240svh;}
.d8 .stick{align-items:flex-start;padding-top:14vh;}
.d8 .door-mark{margin-top:0;}
.d8 .mirror{
  position:absolute;left:50%;top:calc(14vh + var(--door-w) * 1.4);transform:translateX(-50%) scaleY(-1);
  width:var(--door-w);aspect-ratio:10/14;opacity:.3;filter:blur(1.5px);
  -webkit-mask-image:linear-gradient(180deg,#000,transparent 70%);
  mask-image:linear-gradient(180deg,#000,transparent 70%);
}
.d8 .mirror .frame{
  position:absolute;inset:0;border-radius:999px 999px 0 0;
  border:2px solid rgba(246,210,122,.7);border-bottom:none;
}
.d8 .waterline{
  position:absolute;left:0;right:0;top:calc(14vh + var(--door-w) * 1.4);height:1px;
  background:linear-gradient(90deg,transparent,rgba(246,210,122,.5),transparent);
}

/* 09 · VAULT — a barrel vault of arches overhead, parallaxing as you pass. */
.d9 .gate{height:240svh;}
.d9 .vaultroof{position:absolute;left:0;right:0;top:0;height:62%;overflow:hidden;perspective:700px;}
.d9 .rib{
  position:absolute;left:50%;transform:translateX(-50%);width:150%;height:120%;
  border-radius:50% 50% 0 0;border:1px solid rgba(246,210,122,.28);border-bottom:none;
  will-change:transform,opacity;
}
.d9 .door-mark{margin-top:12vh;}

/* 10 · IRIS — the door is a shutter, opening one stop at a time. */
.d10 .gate{height:240svh;}
.d10 .iris{position:absolute;inset:0;display:grid;place-items:center;}
.d10 .blade{
  position:absolute;width:92vmin;height:92vmin;transform-origin:50% 50%;will-change:transform;
  border-radius:999px 999px 0 0;border:1px solid rgba(246,210,122,.35);border-bottom:none;
}
.d10 .door-mark .frame{border-width:3px;}

/* 11 · GALLERY — arch-framed plates travel past a fixed viewpoint. */
.d11 .gate{height:270svh;}
.d11 .galrail{position:absolute;inset:0;display:flex;align-items:center;will-change:transform;}
.d11 .plate{
  flex:0 0 auto;width:min(46vw,380px);aspect-ratio:10/13;margin-right:clamp(24px,5vw,80px);
  border-radius:999px 999px 20px 20px;border:1px solid rgba(246,210,122,.4);
  background:linear-gradient(180deg,rgba(255,204,0,.10),rgba(4,4,4,.2) 78%);
  display:flex;align-items:flex-end;padding:26px;
}
.d11 .plate b{
  font-family:'Sora',sans-serif;font-weight:800;font-size:clamp(16px,2vw,22px);
  letter-spacing:-.02em;line-height:1.15;
}
.d11 .door-mark{display:none;}

/* 12 · BEACON — the door pulses, and the page arrives on the beat. */
.d12 .gate{height:230svh;}
.d12 .door-mark .frame{animation:beacon 3.4s ease-in-out infinite;}
@keyframes beacon{
  0%,100%{box-shadow:0 0 40px -14px rgba(217,168,63,.4),inset 0 0 50px -22px rgba(217,168,63,.35)}
  50%{box-shadow:0 0 110px -6px rgba(246,210,122,.8),inset 0 0 90px -14px rgba(246,210,122,.6)}
}
.d12 .ring{
  position:absolute;left:50%;top:60%;transform:translate(-50%,-50%);
  width:var(--door-w);aspect-ratio:10/14;border-radius:999px 999px 0 0;
  border:1px solid rgba(246,210,122,.5);border-bottom:none;
  animation:ripple 3.4s ease-out infinite;pointer-events:none;
}
.d12 .ring:nth-of-type(2){animation-delay:1.13s}
.d12 .ring:nth-of-type(3){animation-delay:2.26s}
@keyframes ripple{
  0%{transform:translate(-50%,-50%) scale(1);opacity:.7}
  100%{transform:translate(-50%,-50%) scale(3.4);opacity:0}
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION ANIMATION VOCABULARY
   Twenty effects. No direction uses the same combination as another, and each
   page's sections rhyme with its own door: Foyer's cards swing on a hinge,
   Iris's clip open from a point, Colonnade's arrive out of depth, Beacon's
   ripple up on its pulse. The mapping lives in renderers.mjs (ANIM).
   Every effect resolves to its finished state under reduced motion.
   ═══════════════════════════════════════════════════════════════════════════ */
[data-anim="rise"]{opacity:0;transform:translateY(30px);transition:opacity .9s var(--ease),transform .9s var(--ease);}
[data-anim="tilt"]{opacity:0;transform:perspective(1200px) rotateX(11deg) translateY(38px);transition:opacity 1s var(--ease),transform 1.05s var(--ease);}
[data-anim="zoom"]{opacity:0;transform:scale(.86);filter:blur(9px);transition:opacity .9s var(--ease),transform 1s var(--ease),filter .9s var(--ease);}
[data-anim="wipe"]{clip-path:inset(0 100% 0 0);transition:clip-path 1.1s cubic-bezier(.76,0,.24,1);}
[data-anim="split"]{clip-path:inset(0 50% 0 50%);opacity:0;transition:clip-path 1.15s cubic-bezier(.76,0,.24,1),opacity .6s ease;}
[data-anim="glowin"]{opacity:0;transform:translateY(24px) scale(.97);filter:brightness(.35);transition:opacity .9s var(--ease),transform 1s var(--ease),filter 1.3s var(--ease);}
[data-anim="slidein"]{opacity:0;transform:translateX(-54px);transition:opacity .85s var(--ease),transform 1s var(--ease);}
[data-anim="slidealt"]{opacity:0;transform:translateX(54px);transition:opacity .85s var(--ease),transform 1s var(--ease);}
[data-anim="slidealt"]:nth-child(even){transform:translateX(-54px);}
[data-anim="flip"]{opacity:0;transform:perspective(1400px) rotateX(-58deg);transform-origin:50% 0;transition:opacity .8s var(--ease),transform 1.1s var(--ease);}
[data-anim="swing"]{opacity:0;transform:perspective(1400px) rotateY(-46deg);transform-origin:0 50%;transition:opacity .8s var(--ease),transform 1.1s var(--ease);}
[data-anim="irisin"]{clip-path:circle(0% at 50% 55%);opacity:0;transition:clip-path 1.2s cubic-bezier(.76,0,.24,1),opacity .5s ease;}
[data-anim="depth"]{opacity:0;transform:perspective(900px) translateZ(-320px) scale(.9);transition:opacity .9s var(--ease),transform 1.15s var(--ease);}
[data-anim="rippleup"]{opacity:0;transform:scale(.78);transition:opacity .8s var(--ease),transform 1.05s cubic-bezier(.34,1.56,.64,1);}
[data-anim="unroll"]{opacity:0;transform:scaleY(.2);transform-origin:50% 0;transition:opacity .7s var(--ease),transform 1s var(--ease);}
[data-anim="blurin"]{opacity:0;filter:blur(16px);transition:opacity 1s var(--ease),filter 1.1s var(--ease);}
[data-anim="maskup"]{clip-path:inset(100% 0 0 0);transition:clip-path 1.05s cubic-bezier(.76,0,.24,1);}
[data-anim="mirrorin"]{opacity:0;transform:scaleY(-1) translateY(26px);transition:opacity .9s var(--ease),transform 1s var(--ease);}
[data-anim="rotin"]{opacity:0;transform:rotate(-9deg) scale(.9);transition:opacity .85s var(--ease),transform 1.05s var(--ease);}
[data-anim="draw"]::before{transform:scaleY(0);transform-origin:50% 100%;transition:transform .85s var(--ease) .1s;}
[data-anim="climb"] .w i{transform:translateY(105%);}

/* The stagger MUST come after the effects. Each effect sets the `transition`
   shorthand, which resets transition-delay to 0 — declaring the delay above
   them at equal specificity meant it was wiped on every element and the whole
   page landed in one flat instant. */
[data-anim]{transition-delay:calc(var(--d,0) * 95ms);}
[data-anim].lit{opacity:1;transform:none;filter:none;clip-path:inset(0 0 0 0);}
[data-anim="irisin"].lit{clip-path:circle(85% at 50% 55%);}
[data-anim="wipe"].lit,[data-anim="split"].lit,[data-anim="maskup"].lit{clip-path:inset(0 0 0 0);}
[data-anim="draw"].lit::before{transform:scaleY(1);}
[data-anim="climb"].lit .w i{transform:none;}

@media(prefers-reduced-motion:reduce){
  [data-anim]{opacity:1!important;transform:none!important;filter:none!important;clip-path:none!important;}
  [data-anim="draw"]::before{transform:none!important;}
  [data-par]{transform:none!important;}
}

/* ═══════════════════════════════════════ UNLOCKING SCROLL AFTER THE MOVE
   Two rules in common.css assume the globe is the page's own fixed backdrop:

     body:has(.globe-wrap){ overflow:hidden }
     body:has(.globe-wrap):not(:has(.globe-intent)) .globe-wrap{
       position:fixed; top:0; left:0; width:100vw; height:100svh; margin:0 }

   Both are correct on /en/buy/, where the globe IS the viewport and the page
   scrolls inside its own containers. Here the globe lives inside the gate, so
   the first froze the document outright and the second tore it back out to
   fixed. Overridden with `body` in the selector so these win on specificity
   ((0,2,2) and (0,3,2)) rather than on stylesheet order. */
html[data-dir] body:has(.globe-wrap){overflow:visible;}
/* the globe hero is the shipped markup in its shipped place — nothing here
   touches its layout, only the document-level scroll lock is lifted */

/* Do NOT set overflow-x on html/body here (a previous pass did, to stop
   page-level horizontal scroll). Per the CSS Overflow spec, overflow-x on
   one axis with the other axis left visible gets force-corrected to
   overflow-y:auto by every browser, EVEN if overflow-y is written out
   explicitly as `visible` — there is no way to write "clip x, leave y
   native" that survives this. The correction turns <body> into its own
   scroll container instead of the page using native root/viewport
   scrolling, which silently breaks position:sticky for every descendant —
   confirmed via a headless probe: .stick's getBoundingClientRect().top was
   tracking scroll 1:1 from the first pixel instead of holding at 0, meaning
   it was never actually sticking at all. This was the root cause of every
   scroll-timing bug reported through this whole thread. If horizontal
   scroll needs preventing again, it must target the specific overflowing
   element directly, never html/body's own overflow-x. */

/* Scrollbar stays functional, just invisible — the visible track/thumb reads
   wrong against the dark #040404 ground (it's tuned for the white site). */
html[data-dir]{scrollbar-width:none;-ms-overflow-style:none;}
html[data-dir]::-webkit-scrollbar,
html[data-dir] body::-webkit-scrollbar{width:0;height:0;background:transparent;}


/* ═════════════════════════════════════ THE CONTENT COMES THROUGH THE DOOR
   No caption in the gate: the door opens and the page arrives through it.
   The body starts small and slightly back, and is scaled up to full size by
   the last stretch of the gate, so it reads as coming out of the doorway
   rather than simply being the next section down. */
[data-emerge]{
  transform-origin:50% 0;will-change:transform,opacity;
  /* the resting state, for the no-JS and reduced-motion paths */
  opacity:1;
  /* Safety net, not the driver: lab.js sets opacity every scroll tick, so
     this only engages once actual scrolling has stopped mid-fade (momentum
     scrolling settling, a trackpad release) — without it the reveal freezes
     at whatever opacity the last scroll tick left it at. Opacity only, and
     short: transform stays scroll-locked (a transitioned transform would lag
     behind the door's own untransitioned scale and visibly desync from it
     during active scrolling). */
  transition:opacity .15s ease;
}

@media(prefers-reduced-motion:reduce){
  [data-emerge]{transform:none!important;opacity:1!important;}
}


/* ═════════════════════════════════════════ DAYLIGHT · PAST THE THRESHOLD
   Class A is dark up TO the door and light after it. The flash at the top of
   the door's arc is the cut: lab.js sets `is-through` at the flash's PEAK,
   where the screen is already white, so the palette turns over underneath it
   and the page is never seen to repaint. It is a toggle, not a latch — scroll
   back up through the door and the dark comes back with you.

   Every value here is the site's own light editorial system: the palette
   styles/tokens.css declares at :root and the other 2,267 routes already
   render. Nothing is a second light theme invented for this page.

   The gold ramp is the one thing that cannot be borrowed verbatim. #F6D27A →
   #D9A83F is built to read as ink on #040404 and all but disappears on
   #ffffff (2.2:1), so the three stops are re-pointed to the DEEP end of the
   same ramp — #8F6612, the ramp's own bottom stop, becomes the text gold, and
   the light stop is demoted to hairline duty. Same ramp, read from the other
   end.

   Scoped to html[data-dir].is-through, which outranks the force-dark block at
   the top of this file on specificity alone ((0,2,x) against (0,1,x)). No
   rule below depends on which order the three stylesheets happen to land in. */

/* Only the surfaces actually on screen at the cut carry a transition, and
   only long enough to cover the flash's own tail. The article needs none: its
   colours all come from custom properties, which do not transition at all —
   and it is still at opacity 0 when the palette flips. */
html[data-dir] body,
html[data-dir] body .site-header,
html[data-dir] body .site-header.is-solid,
html[data-dir] body .search,
html[data-dir] body .site-header.is-solid .lang-btn{
  transition:background-color .32s linear,color .32s linear,border-color .32s linear;
}

html[data-dir].is-through body{background:#ffffff;color:#16171a;}
html[data-dir].is-through,
html[data-dir].is-through .labpage,
html[data-dir].is-through .labpage .d1,
html[data-dir].is-through .art-shell{
  background:#ffffff;color:#16171a;
}
html[data-dir].is-through .labpage .grain{
  opacity:0!important;visibility:hidden;pointer-events:none;
}

/* The chrome, answered rule for rule against the force-dark block above. */
html[data-dir].is-through body .site-header{
  background:#fff;border-bottom-color:#ececef;
  box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;
}
html[data-dir].is-through body .site-header.is-solid{
  background:#fff;border-bottom:1px solid #ececef;
  box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;
}
/* The dark mark — and without the drop-shadow common.css hangs on it for the
   globe hero, which exists to hold the logo off a photographic background and
   on white only smudges it. */
html[data-dir].is-through body .site-header .brand-mark,
html[data-dir].is-through body .site-header.is-solid .brand-mark{
  content:url(/pages-assets/logo-mark.svg);filter:none;
}
html[data-dir].is-through body .site-header .brand,
html[data-dir].is-through body .site-header .area-name,
html[data-dir].is-through body .lang-btn,
html[data-dir].is-through body .search input{color:#16171a;}
html[data-dir].is-through body .search,
html[data-dir].is-through body .site-header.is-solid .search{
  background:#f5f5f6;border-color:#ececef;
}
html[data-dir].is-through body .site-header.is-solid .lang-btn,
html[data-dir].is-through body .site-header.is-solid .lang-btn--solo{
  background:#f6f7f8;border-color:#ececef;color:#16171a;
}
/* The locale code and its chevron are painted white by common.css's own
   globe-intent rule, not by the force-dark block above — the header there is
   transparent over a photographic hero, so white is right for it and wrong
   for us. It is answered here rather than left to inherit from .lang-btn,
   because that rule is (0,4,1) and the inherit never gets a chance. */
html[data-dir].is-through body .site-header.is-solid .lang-code,
html[data-dir].is-through body .site-header.is-solid .lang-arrow{color:#16171a;}

/* The article's ramp. One block re-points the tokens and the whole .art- and
   .b- vocabulary follows, so art-shell.css needs no light-mode twin of any
   rule it already has. */
html[data-dir].is-through .labpage{
  --noir:#ffffff;                  /* the ground, and the card faces standing on it */
  --gold-1-rgb:143,102,18;         /* the ramp's deep stop is the TEXT gold on white */
  --or1:rgb(var(--gold-1-rgb));    /* #8F6612 — 5.1:1 on #ffffff */
  --or2:#9A7211;                   /* labels, numerals, rules */
  --or3:#E3D2A2;                   /* the hairline gold — the light stop, demoted */
  --ink-rgb:22,23,26;
  --blanc:rgb(var(--ink-rgb));
  --vert:#1B8F4D;
  --rouge-rgb:192,60,54;
  --rouge:rgb(var(--rouge-rgb));
  --hair:rgba(22,23,26,.1);
  --grad:linear-gradient(180deg,#C08A1A,#9A7211 52%,#8F6612);
  /* the ghost numeral behind each question. art-shell.css falls back to the
     dark value, so this line is the whole of its daylight half. */
  --ghost:#f2f2f5;
  /* the section + sidenote rules. Ink on paper; art-shell.css falls back to a
     .3-alpha light rule for the dark half. */
  --rule:#16171a;
}

/* Grain is mixed for #040404. On the white article it only greys the page,
   so it stays off after the door. */
html[data-dir].is-through .labpage .grain{
  opacity:0!important;visibility:hidden;pointer-events:none;
}

/* After the door, chrome + article share the Dubai guide measure: 1640px,
   tracks 320 / 760 / 340, area name in the middle column. */
html[data-dir].is-through body:has(.globe-intent) .site-header .area-name {
  display: block;
  color: #16171a;
}
@media (min-width: 1240px) {
  html[data-dir].is-through body:has(.globe-intent) .site-header .bar,
  html[data-dir].is-through body .site-header .bar {
    display: grid;
    grid-template-columns: minmax(240px, 320px) minmax(0, 760px) minmax(280px, 340px);
    gap: clamp(28px, 3.5vw, 60px);
    justify-content: center;
    align-items: center;
    max-width: 1640px;
    margin: 0 auto;
    padding: 0 var(--gutter);
    height: 70px;
  }
  html[data-dir].is-through body:has(.globe-intent) .site-header .brand { flex: none; }
  html[data-dir].is-through body:has(.globe-intent) .site-header .area-name {
    display: block; flex: none; width: 100%; max-width: none;
  }
}

html[data-dir].is-through .labpage {
  font-family: Outfit, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", Arial, sans-serif;
}
html[data-dir].is-through .labpage h1,
html[data-dir].is-through .labpage h2,
html[data-dir].is-through .labpage h3 {
  font-family: Outfit, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", Arial, sans-serif;
}
html[data-dir].is-through .art-sec h2 { color: #16171a; }
html[data-dir].is-through .art-prose p,
html[data-dir].is-through .b-lead { color: #3a3a3f; opacity: 1; }
html[data-dir].is-through .art-lede,
html[data-dir].is-through .art-prose strong { color: #16171a; }
/* The sidenote is no longer gold — art-shell.css sets it in ink, as a ruled
   margin note. It has to leave this list rather than be overridden later: every
   selector here carries html[data-dir].is-through, so (0,3,1) beats the (0,1,1)
   of a plain `.art-note p` no matter what order the stylesheets load in. */
html[data-dir].is-through .b-a,
html[data-dir].is-through .art-transition { color: #c8941e; }
html[data-dir].is-through .art-note-k { color: #16171a; opacity: .42; }
html[data-dir].is-through .b-b { color: #16171a; }
html[data-dir].is-through .b-v { color: #8a8a90; }
html[data-dir].is-through .art-num { display: none; }
html[data-dir].is-through .b-unlisted,
html[data-dir].is-through .b-counterfactual {
  background: #fff; border: 1px solid #ececef; gap: 0;
}
html[data-dir].is-through .b-tension { background: transparent; border: 0; gap: 12px; }
html[data-dir].is-through .b-tension li,
html[data-dir].is-through .b-unlisted > div,
html[data-dir].is-through .b-counterfactual li {
  background: #fff; border-bottom: 1px solid #f3f3f5;
}
html[data-dir].is-through .b-tension li { border: 1px solid #ececef; }
html[data-dir].is-through .b-unlisted > div:last-child,
html[data-dir].is-through .b-counterfactual li:last-child { border-bottom: 0; }
html[data-dir].is-through .site-footer { background: #f5f5f6; border-top-color: #ececef; }
html[data-dir].is-through .art-rail .guide-toc a.active { color: #16171a; }


/* ═════════════════════════════════════════════ VARIANT 5 · GAZETTE
   The skin chosen out of /style-lab/ (six variants; see
   site/public/style-lab/README.md). Shipped the way that README prescribes:
   the skin block, every selector prefixed `html[data-dir].is-through .labpage`
   so it outranks BOTH art-shell.css and the daylight overrides above on
   specificity alone — (0,4,x) against art-shell's (0,1,x) and the block above's
   (0,2,x). No rule here depends on which order the three stylesheets land in.

   A magazine feature: Fraunces carries the questions, the lede opens on a gold
   drop cap, a diamond ornament parts the sections, and the reader's question
   becomes a pull-quote in the margin. Outfit still does all the reading work —
   the serif only performs. Fraunces is requested by Transactional.astro's
   `fonts` prop; without it the whole skin degrades to Georgia and still reads.

   THE SKIN, AND ONLY THE SKIN. The lab HTML embeds a snapshot of art-shell.css
   taken before the always-open situation switch, the sticky sidenote and the
   card aspect-ratio landed, so a few values the lab renders are that older
   base rather than the gazette. Those are deliberately not reproduced — the
   current base keeps them. Three rules are re-pointed at markup that has been
   renamed or restructured since; each is marked below. */

html[data-dir].is-through .labpage{
  /* The lab's own token names, so the skin ports verbatim. --muted is already
     #6b6b6b at common.css's :root and is left alone rather than restated. */
  --serif:"Fraunces","Instrument Serif",Georgia,"Iowan Old Style","Times New Roman",serif;
  --font:Outfit,system-ui,-apple-system,"Segoe UI",Roboto,"Noto Sans",Arial,sans-serif;
  --ink:#16171a; --ink-soft:#3a3a3f; --faint:#8a8a92;
  --gold-deep:#c8941e; --gold-text:#8f6612; --gold-label:#9a7211; --gold-hair:#e3d2a2;
}

/* The ground stays WHITE. The lab's gazette prints on a warm #fffdf7 stock;
   this ships on the daylight block's own #ffffff instead, so the skin is the
   serif, the gold and the rules — not a paper tint. Nothing is overridden here:
   dropping the override is what leaves the five surfaces above at #ffffff.

   Every shape that has to read as a HOLE in a line — the diamond that breaks
   the section hairline, the node on the reveal chain — is filled with the same
   white rather than the lab's cream, or it would sit on the page as a tinted
   disc instead of disappearing into it. */
html[data-dir].is-through .labpage .art-main{counter-reset:sec}
/* ── the section rule is VARIANT 1's too ──────────────────────────────────
   A full-measure ink rule opens every question, 2px on the first. This replaces
   the gazette's centred gold hairline and diamond outright — the two are the
   same piece of furniture and cannot both stand.

   It is a real `border-top` on .art-sec, not a drawn line, which is why the
   padding moves 44px → 26px with it: the border sits at the section's edge
   where the gazette's absolute hairline sat at `top:0` INSIDE it. 26px is also
   what drops the ghost numeral onto the rule the way the reference shows —
   the 44px was only ever there to keep it clear of the diamond, and there is
   no diamond now. */
html[data-dir].is-through .labpage .art-sec{counter-increment:sec;padding-top:26px;
  border-top:1px solid var(--ink);}
html[data-dir].is-through .labpage .art-sec:first-child{border-top-width:2px;}
/* Two ornaments were cancelled here: the gazette's hairline and diamond, and
   art-shell's OWN hairline-and-node pair off `.art-sec + .art-sec`. Only a
   guard against the latter is left, and it is deliberately `::after` ONLY.
   art-shell no longer draws that pair at all — the section's `border-top` is
   the same piece of furniture and replaced it — and `::before` there is now
   the data-block tag, which this skin keeps: written as `.art-sec + .art-sec
   ::before` the cancel would strip the tag off every question but the first,
   which reads as the tag failing rather than as a skin decision. */
html[data-dir].is-through .labpage .art-sec::after,
html[data-dir].is-through .labpage .art-sec + .art-sec::after{content:none;}
/* ── the question heading is VARIANT 1's, not variant 5's ──────────────────
   Everything else on this page is the gazette; the numeral and the question
   itself come from skins/1-ledger.css, measured off /style-lab/1-ledger.html.
   The gazette set a 1.6rem serif numeral beside the question in a 52px indent;
   the ledger instead tucks an oversized ghost numeral behind it and cuts the
   question in the sans at 700. The two cannot both apply — the indent, the
   serif and the numeral's size and position are all replaced here, not layered.

   What is NOT taken from the ledger: its section rule, its `data-block` machine
   tag, and its 26px section padding. The gazette's gold hairline and diamond
   still open each question. Keeping the gazette's 44px padding is also what
   stops the ghost numeral rising out of the section — at the ledger's 26px it
   crosses its own top rule by 4px, which reads as deliberate against a full-
   measure ink rule and as a mistake against a centred diamond. The numeral's
   offset from the question is the ledger's exactly, so the tuck is unchanged. */
html[data-dir].is-through .labpage .art-sec-head{position:relative;padding-top:34px;padding-left:0;}
html[data-dir].is-through .labpage .art-sec-head::before{
  content:counter(sec,decimal-leading-zero);position:absolute;top:-30px;left:-8px;
  font-family:var(--font);font-size:clamp(88px,9vw,126px);font-weight:800;line-height:1;
  letter-spacing:-.06em;color:#f2f2f5;font-feature-settings:normal;
  z-index:0;pointer-events:none;user-select:none;-webkit-user-select:none;}
html[data-dir].is-through .labpage .art-sec h2{
  font-family:var(--font);font-weight:700;font-size:clamp(1.7rem,2.4vw,2.1rem);
  line-height:1.2;letter-spacing:-.034em;max-width:22ch;color:var(--ink);
  position:relative;z-index:1;
  /* Neither lab file resets the h2 margin, so both carry the UA's own .83em and
     that is the rhythm each variant was picked on — air this build's reset takes
     back. In em, so it tracks the clamp down to 1.7rem on a phone. */
  margin:.83em 0;}
/* The brand rule under the question. It is `h2::after` in the skin — part of the
   heading, not of the section — so it comes across with it. */
html[data-dir].is-through .labpage .art-sec h2::after{
  content:"";display:block;width:52px;height:3px;margin-top:20px;background:#ffcc00;}
html[data-dir].is-through .labpage .art-lede{font-size:1.09rem;line-height:1.62;color:var(--ink-soft);margin-top:6px}
html[data-dir].is-through .labpage .art-lede::first-letter{float:left;font-family:var(--serif);font-weight:400;font-size:4.1em; line-height:.78;padding:8px 12px 0 0;color:var(--gold-deep)}
html[data-dir].is-through .labpage .art-by{font-family:var(--serif);font-style:italic;font-size:.95rem;color:var(--muted); padding-top:12px;border-top:1px solid var(--gold-hair);clear:both}
html[data-dir].is-through .labpage .b-lead{font-size:1.12rem;line-height:1.62;color:var(--ink);font-weight:400}
html[data-dir].is-through .labpage .b-lead::before{content:"";display:block;width:38px;height:1px;background:var(--gold-deep);margin-bottom:16px}
html[data-dir].is-through .labpage .guide-toc strong{font-family:var(--serif);font-weight:400;font-size:1.02rem;letter-spacing:.01em; text-transform:none;color:var(--ink);font-style:italic; padding-bottom:12px;border-bottom:1px solid var(--gold-hair)}
html[data-dir].is-through .labpage .toc-pct{font-family:var(--font);font-size:.68rem}
/* ── the rail, matched to what the lab RENDERS rather than to skins/5-gazette.css
   The skin re-cuts the contents list — no left rule, 9px rows, .86rem at weight
   400, the current question left plain. None of that is what the lab shows: the
   restated `.guide-toc` block it ships is (0,3,1) and the skin's rail rules are
   (0,2,1), so in the lab the base wins nearly all of them and the skin only
   lands the dotted separator, the serif numerals and the italic on the current
   question. Ported literally, production came out MORE gazette than the gazette
   — and visibly different from the variant that was signed off.

   So these carry the lab's own computed values. The current question keeps its
   7% brand wash and yellow marker: that is the selected state, not page tint,
   and it is what the reference shows. Everything below is measured, not read
   off the skin file. */
html[data-dir].is-through .labpage .art-rail .guide-toc{font-size:1rem;border-radius:0;}
html[data-dir].is-through .labpage .art-rail-list{gap:0;padding-top:8px;position:static;}
/* common.css hangs a continuous 2px spine off the list and a second 2px bar off
   every link. The lab has neither — the only vertical mark in that gutter is the
   current question's own border-left, which is why it reads as a marker against
   the page instead of a highlight on a track. */
html[data-dir].is-through .labpage .art-rail-list::before,
html[data-dir].is-through .labpage .art-rail-list a::after{content:none;}
html[data-dir].is-through .labpage .art-rail-list a{
  gap:9px;padding:6px 4px 6px 16px;font-size:.88rem;font-weight:500;line-height:1.35;
  color:var(--muted);background:transparent;position:static;
  border-left:2px solid transparent;border-radius:0;
  border-bottom:1px dotted #e6ddc6;}
html[data-dir].is-through .labpage .art-rail-list a::before{
  font-family:var(--serif);font-size:.68rem;font-weight:700;letter-spacing:.04em;color:var(--gold-deep);}
html[data-dir].is-through .labpage .art-rail-list a:hover{
  background:transparent;color:var(--ink);transform:translateX(2px);}
html[data-dir].is-through .labpage .art-rail-list a.active{
  background:rgba(255,204,0,.07);color:var(--ink);font-weight:700;font-style:italic;
  border-left-color:#ffcc00;}
html[data-dir].is-through .labpage .art-rail-list a.active::before{color:var(--ink);}
/* The pull-quote's rule sits on .art-note-in, not .art-note. The lab has no
   sticky inner: there the aside IS the quote, so a border-top on it lands
   directly above the text. Here .art-note is a full-height slot in the
   gutter, so the same border would strand itself at the top of the
   question while the quote scrolled on without it. */
html[data-dir].is-through .labpage .art-note{border-left:0;padding:0;}
html[data-dir].is-through .labpage .art-note-in{border-top:2px solid var(--ink);padding-top:16px;}
html[data-dir].is-through .labpage .art-note-k{font-family:var(--font);font-size:.58rem;letter-spacing:.2em;color:var(--muted)}
html[data-dir].is-through .labpage .art-note p{font-family:var(--serif);font-style:italic;font-size:1.24rem;line-height:1.34;color:var(--ink)}
html[data-dir].is-through .labpage .art-note p::before{content:"“";color:var(--gold-deep);margin-right:2px}
html[data-dir].is-through .labpage .art-note p::after{content:"”";color:var(--gold-deep)}
html[data-dir].is-through .labpage .art-photo img{border-radius:0;border:1px solid #e3dcc8;filter:saturate(.82) contrast(1.05)}
html[data-dir].is-through .labpage .art-photo figcaption{font-family:var(--serif);font-style:italic;font-size:.95rem;line-height:1.5; color:var(--muted);text-align:center;max-width:52ch;margin:16px auto 0}
html[data-dir].is-through .labpage .b-tension{gap:0;border-top:1px solid var(--gold-hair)}
html[data-dir].is-through .labpage .b-tension li{background:transparent;border:0;border-bottom:1px solid #eee6d3;border-radius:0; padding:22px 0;display:grid;grid-template-columns:1fr auto 1fr;gap:0 22px;align-items:start}
html[data-dir].is-through .labpage .b-tension li:hover{background:transparent}
html[data-dir].is-through .labpage .b-a,
html[data-dir].is-through .labpage .b-b{font-family:var(--serif);font-weight:400;font-size:1.24rem;line-height:1.26}
html[data-dir].is-through .labpage .b-a{color:var(--gold-text);text-align:right}
html[data-dir].is-through .labpage .b-b{color:var(--ink)}
html[data-dir].is-through .labpage .b-v{font-family:var(--serif);font-style:italic;font-size:1rem;color:var(--faint);margin:0; align-self:center;position:relative}
html[data-dir].is-through .labpage .b-v::before{content:"";position:absolute;left:50%;top:-22px;bottom:-22px;width:1px;background:#eee6d3}
html[data-dir].is-through .labpage .b-note{grid-column:1/-1;margin-top:16px;font-size:.94rem;line-height:1.7;color:var(--muted); columns:2;column-gap:34px;column-rule:1px solid #f0e9d8}
/* ── the origin rows are VARIANT 6's stops on the line ────────────────────
   Measured off /style-lab/6-route.html. The gazette ruled these rows off flat
   against the page; the route mounts each as a white card with a gold tick
   facing the reading column — the radius is on the RIGHT corners only, so the
   left edge stays a straight rail down the block.

   Colour and layout only, as asked: the route's own hover (translateX(3px) and
   a lift) is deliberately not taken, and art-shell's is cancelled below.

   The gazette's three type rules here are DELETED rather than re-pointed. The
   route skin never touches the label, the two columns or the "so" line, so
   what the reference renders for them is just art-shell's own default — which
   this build already has. Restating them would only be a second copy to drift. */
html[data-dir].is-through .labpage .b-origin{gap:14px;border-top:0;}
html[data-dir].is-through .labpage .b-origin-row{
  background:#fff;border:1px solid #e9e6dd;border-left:3px solid var(--gold-hair);
  border-radius:0 12px 12px 0;padding:20px 22px;}
/* Inert on hover, by restating the resting state — art-shell answers with a
   brand border, a #ffcc0012 wash and an `inset 2px 0 0` bar, and all three have
   to be named or the leftovers show through. border-left-color comes after the
   shorthand on purpose: `border-color` alone would repaint the gold tick too. */
html[data-dir].is-through .labpage .b-origin-row:hover{
  background:#fff;border-color:#e9e6dd;border-left-color:var(--gold-hair);box-shadow:none;}
/* The arrow needs no rule at all. art-shell draws it from `var(--or3)`, which the
   daylight ramp above already points at #E3D2A2 — the same gold-hair the route
   renders. The gazette's override is dropped rather than re-coloured: it used
   the `border-color` shorthand, which painted the two edges art-shell leaves
   unset and turned the head from a chevron into a filled corner. */
/* Same `.labpage p` zeroing as the two section labels below: the skin hangs a
   dotted rule on this line and without art-shell's 16px it draws flush against
   the sentence above it. Their grid parent has gap:0, so nothing else absorbs it. */
/* Only the margin survives from the gazette's version of this line — the dotted
   rule, the italic and the softened ink were all its own, and the route shows
   art-shell's plain hairline instead. The margin has to stay because `.labpage p`
   zeroes art-shell's `margin:16px 0 0` (see the two section labels below). */
html[data-dir].is-through .labpage .b-origin-so{margin-top:16px;}
/* ── the tables are boxed, VARIANT 4's shape in a neutral grey ────────────
   The gazette hung the table off a single 2px ink rule; variant 4 packs it in
   a rounded box instead. The shape is taken from /style-lab/4-daybreak.html —
   1px, 20px radius — but the colour is NOT: daybreak's #f3edda is a warm cream
   and this is the site's own neutral hairline, the same grey the situation
   cards use. Its float shadow and its row hover are both left behind. */
html[data-dir].is-through .labpage .b-table-wrap{
  border:1px solid var(--hair);border-radius:20px;background:transparent;box-shadow:none;}
/* The box needs an inset or the first column and the caption sit ON the border —
   the gazette's cells run to padding-left:0 because there was no left edge to
   clear. Only the two OUTER edges are padded, so the interior column rhythm is
   exactly what it was; daybreak's uniform 22px would have re-spaced every cell. */
html[data-dir].is-through .labpage .b-table th:first-child,
html[data-dir].is-through .labpage .b-table td:first-child{padding-left:22px;}
html[data-dir].is-through .labpage .b-table th:last-child,
html[data-dir].is-through .labpage .b-table td:last-child{padding-right:22px;}
/* padding-bottom was 0, inherited from a caption that used to sit ABOVE an open
   table and had the whole page as its lower margin. Boxed, that band is closed
   by the header rule underneath, so a 0 bottom dropped the line onto it. Even
   top and bottom centres it in its own band. */
html[data-dir].is-through .labpage .b-table caption{font-family:var(--serif);font-style:italic;font-size:1.02rem;letter-spacing:0; text-transform:none;color:var(--ink);padding:14px 22px}
/* Every horizontal rule in the table is the SAME grey as the box — the gazette's
   warm #eee6d3 rows and its gold header rule both read as a second palette once
   there is a neutral border around them. --hair is the token the box uses. */
html[data-dir].is-through .labpage .b-table th,
html[data-dir].is-through .labpage .b-table td{padding:14px 18px 14px 0;border-bottom:1px solid var(--hair)}
html[data-dir].is-through .labpage .b-table thead th{font-family:var(--font);letter-spacing:.14em;border-bottom:1px solid var(--hair);color:var(--ink)}
/* The last row's own rule stacked on the box's bottom border — two 1px lines a
   pixel apart, which reads as one thick, slightly blurred edge. The row gives
   its up; the box keeps its own. */
html[data-dir].is-through .labpage .b-table tbody tr:last-child th,
html[data-dir].is-through .labpage .b-table tbody tr:last-child td{border-bottom:0}
html[data-dir].is-through .labpage .b-table tbody th{font-family:var(--serif);font-weight:400;font-size:1.02rem}
html[data-dir].is-through .labpage .b-table td:last-child{font-variant-numeric:oldstyle-nums tabular-nums;color:var(--gold-text)}
/* Neutral, not the lab's #fffaf0. That tint was warm-on-warm against the cream
   stock and barely there; on white it lands as a cream band under the cursor —
   the one thing the ground was just changed to stop doing. */
/* No row hover. Stated, not deleted: art-shell tints rows on hover with
   `rgba(var(--gold-1-rgb),.035)`, so removing this line would bring a wash back
   rather than take one away.
   (`.b-table-wrap:focus-visible` keeps its outline — that is the keyboard's only
   handle on a table that scrolls sideways on a phone, not a hover effect.) */
html[data-dir].is-through .labpage .b-table tbody tr:hover{background:transparent}
html[data-dir].is-through .labpage .b-table-note{font-style:italic;font-size:.86rem;margin-top:12px;}
/* The FAQ is boxed in the price tables' terms — same 1px neutral hairline, same
   20px radius — rather than hung off the single ink rule it had.

   The inset goes on the CHILDREN, not on .art-faq itself: the rules between
   questions have to run the full width of the box, and padding on the block
   would stop them 22px short at both ends. Same reason the tables carry theirs
   on the cells.

   Bottom padding is 12px against 28px at the top because the last closed
   <summary> already contributes its own 16px — 12 + 16 balances the 28. */
html[data-dir].is-through .labpage .art-faq{
  border:1px solid var(--hair);border-radius:20px;padding:28px 0 12px;}
html[data-dir].is-through .labpage .art-faq-k{padding:0 22px;}
html[data-dir].is-through .labpage .art-faq details p{padding:0 22px;}
/* The last question drops its rule so it cannot stack on the box's own bottom
   edge — one pixel apart reads as a single thick, blurred line. */
html[data-dir].is-through .labpage .art-faq details:last-of-type{border-bottom:0;}
/* The 14px art-shell asks for under both section labels never lands: `.labpage p`
   (this file, the chrome block) zeroes every paragraph margin at (0,1,1) and
   art-shell's `.art-faq-k` / `.art-sources-k` are (0,1,0). Pre-existing, and
   invisible while the labels were 10px all-caps — at 1.02rem italic they sit
   flush on the first row. Restored to what the lab renders. */
html[data-dir].is-through .labpage .art-faq-k{font-family:var(--serif);font-style:italic;font-size:1.02rem;letter-spacing:0; text-transform:none;color:var(--ink);margin-bottom:14px;}
html[data-dir].is-through .labpage .art-faq details{border-bottom:1px solid #eee6d3}
html[data-dir].is-through .labpage .art-faq summary{font-family:var(--serif);font-weight:400;font-size:1.14rem;padding:16px 22px}
html[data-dir].is-through .labpage .art-progress i{background:var(--gold-deep)}
@media(max-width:760px){
html[data-dir].is-through .labpage .b-tension li{grid-template-columns:1fr}
html[data-dir].is-through .labpage .b-a{text-align:left}
html[data-dir].is-through .labpage .b-v::before{display:none}
html[data-dir].is-through .labpage .b-note{columns:1}
}
/* .b-opt and .b-contrast-panel are deliberately OUT of this list — the six
   situations are variant 4's floating cards, and the two-sided comparison is
   variant 6's stop on the line. Both are further down. Everything else in the
   gazette's vocabulary is still a rule rather than a box. */
html[data-dir].is-through .labpage .b-card,
html[data-dir].is-through .labpage .art-fig{background:transparent;border:0;border-top:1px solid var(--gold-hair);border-radius:0;padding:22px 0 0}
html[data-dir].is-through .labpage .b-card:hover{background:transparent;transform:none;border-color:var(--gold-deep)}

/* ── the two-sided comparison is VARIANT 6's stop on the line ─────────────
   Measured off /style-lab/6-route.html#s6, and the same treatment the origin
   rows already carry: a white card boxed in a neutral hairline, with the gold
   tick facing the reading column and the radius on the right corners only.

   The BOX and the TICK only, as asked. The route also re-cuts the heading (its
   own sans at 700 rather than the gazette's serif) and turns the CE QUE ÇA
   CHANGE label gold; neither is taken, so the type in these panels is unchanged.
   Padding comes along because it has to — the gazette ran the copy to
   padding-left:0, and a box needs its content off the edge. */
html[data-dir].is-through .labpage .b-contrast-panel{
  background:#fff;border:1px solid #e9e6dd;border-left:3px solid var(--gold-hair);
  border-radius:0 12px 12px 0;padding:22px;}
/* Inert on hover, matching the situation cards and the origin rows. art-shell
   tints and re-borders on hover; border-left-color is restated after the
   shorthand so the gold tick survives. */
html[data-dir].is-through .labpage .b-contrast-panel:hover{
  background:#fff;border-color:#e9e6dd;border-left-color:var(--gold-hair);
  transform:none;box-shadow:none;}
html[data-dir].is-through .labpage .b-card .b-card-img{width:100%;margin:0 0 18px;border-radius:0;filter:saturate(.8) contrast(1.06)}
html[data-dir].is-through .labpage .b-card h3,
html[data-dir].is-through .labpage .b-contrast-panel h3{font-family:var(--serif);font-weight:400;font-size:1.22rem;line-height:1.24;color:var(--ink);
  /* art-shell tightens these to -.028em for Sora. Fraunces is a Scotch face and
     already sets its own fit; the negative tracking closes the serifs up. The
     lab renders them at normal for the same reason — nothing there re-tracks. */
  letter-spacing:normal;}
/* ── section 14: one card PER PROFILE, 10px apart ─────────────────────────
   This started as the route's own treatment for `.b-counterfactual` — a single
   card wrapping the list, with the profiles as rows divided by #f2efe6 rules.
   It is now one card per profile instead, with the dividing rules gone: the gap
   IS the separation. 10px as asked, rather than the 14px `.b-regret` carries.

   So the card moves OFF the container and ONTO the li. The container keeps
   nothing but the gap — no frame, no tick, no face — or a second border would
   run outside the six and the rules would still show through between them.

   `.b-cf-who` and `.b-cf-chooses` leave the gazette's serif groups rather than
   being overridden: art-shell's own 15.5px/600 and 15.5px/gold ARE what the
   route renders, so the gazette was the thing overriding them. */
html[data-dir].is-through .labpage .b-counterfactual{
  background:transparent;border:0;border-radius:0;padding:0;gap:10px;overflow:visible;}
/* A plain card, not a route "stop": no gold tick, and the radius runs all four
   corners rather than the route's right-hand pair. Border, radius and face are
   the page's ordinary card — the same neutral hairline, 20px and transparent
   face the situation cards in section 2 and the closing steps in section 15
   carry. 22px horizontal is art-shell's own and comes back with the box. */
html[data-dir].is-through .labpage .b-counterfactual li{
  background:transparent;border:1px solid var(--hair);
  border-radius:20px;padding:20px 22px;}

/* ── the unlisted checks are VARIANT 1's index, BOXED ─────────────────────
   Measured off /style-lab/1-ledger.html#s12: gray hairlines between the rows,
   the item title cut in the sans at 700, and the last row's rule dropped so it
   cannot double the frame.

   ONE DELIBERATE DEVIATION, and it is the thing that was asked for: the ledger
   frames this list with an INK rule on the TOP EDGE ONLY. Here it is a closed
   box in the price tables' terms instead — same 1px neutral hairline, same 20px
   radius — so the two "tabled" blocks on the page read as one object rather
   than as a grey box and a black one. The rest of the block is the reference.

   `.b-unlisted` and its dt leave the two gazette groups above rather than being
   overridden, same as the timeline and the numbered steps: art-shell's 16px is
   the reference size, and only the weight, the tracking and the ink need saying. */
html[data-dir].is-through .labpage .b-unlisted{
  background:transparent;border:1px solid var(--hair);border-radius:20px;padding:0;}
/* 22px of horizontal padding is art-shell's own, and it has to come back with
   the box: the ledger runs these rows to `padding:18px 0` because there is no
   left edge to clear. Same reason the price tables needed an inset. */
html[data-dir].is-through .labpage .b-unlisted > div{
  background:transparent;border-bottom:1px solid var(--line);padding:18px 22px;}
html[data-dir].is-through .labpage .b-unlisted > div:last-child{border-bottom:0;}
/* No hover — art-shell tints each row `rgba(gold,.035)` on pointer, which the
   rest of this page no longer does. */
html[data-dir].is-through .labpage .b-unlisted > div:hover{background:transparent}
html[data-dir].is-through .labpage .b-unlisted dt{
  font-family:var(--font);font-size:16px;font-weight:700;letter-spacing:-.02em;color:var(--ink);}
/* ── the six-months-later mistakes are VARIANT 6's stops on the line ──────
   Measured off /style-lab/6-route.html#s13 — and unlike the counterfactual
   block below, this one really IS one card PER ENTRY: art-shell already gives
   `.b-regret` a 14px grid gap, so the six sit apart with their own frames.

   THE TICK IS GOLD, NOT THE ROUTE'S RED. The route singles this block out with
   `border-left:3px solid var(--rouge)` — #c03c36 — because in its palette these
   are the regrets. Here it takes var(--gold-hair), the same 3px #e3d2a2 as the
   origin rows, the Freehold/Leasehold panels and section 14, so every card on
   the page carries one tick colour. That is the one deliberate departure.

   `.b-regret-is` and `.b-regret span` leave the gazette's groups rather than
   being overridden: art-shell's 15.5px/600 and 10px/.16em are what the route
   renders, so only the gold and the 700 on the label need saying. */
html[data-dir].is-through .labpage .b-regret li{
  background:#fff;border:1px solid #e9e6dd;border-left:3px solid var(--gold-hair);
  border-radius:0 12px 12px 0;padding:20px 22px;}
/* Inert on hover — art-shell washes each entry `rgba(rouge,.03)`; restated
   rather than deleted, and border-left-color after the shorthand so the gold
   tick survives. */
html[data-dir].is-through .labpage .b-regret li:hover{
  background:#fff;border-color:#e9e6dd;border-left-color:var(--gold-hair);}
html[data-dir].is-through .labpage .b-regret span{
  color:var(--gold-label);opacity:1;font-weight:700;}
html[data-dir].is-through .labpage .b-chain li::before{background:var(--noir);border-color:var(--gold-deep)}
html[data-dir].is-through .labpage .b-chain-start span{font-family:var(--serif);font-style:italic;color:var(--gold-text)}
html[data-dir].is-through .labpage .b-card dt,
html[data-dir].is-through .labpage .b-contrast-so span{font-family:var(--font);font-size:.58rem;letter-spacing:.2em;opacity:1;color:var(--muted)}

/* ── the ordinary-Tuesday timeline is VARIANT 6's line too ────────────────
   Measured off /style-lab/6-route.html#s10. Same reasoning as the numbered
   steps above: this block already IS a journey, so the route gives it the rail
   treatment — a gold ring on a gold line, with the hour in gold rather than
   grey. `.b-week-p` and `.b-week-t` leave the two gazette groups above for the
   same reason `.b-seq-label` and `.b-seq-actor` did: the route never re-cuts
   them, so art-shell's own 17px/600 and 11px/.1em ARE the reference, and the
   gazette was the thing overriding them.

   The ring's fill is var(--noir), not the route's #faf9f6. That colour is the
   route's own warm page ground; this page is white, and the fill exists to
   punch a hole in the rail — it has to be whatever the page is, or the ring
   reads as a tinted bead. Same call as the chain node and the old diamond. */
html[data-dir].is-through .labpage .b-week li::before{
  width:11px;height:11px;background:var(--noir);border:2px solid var(--gold-deep);}
html[data-dir].is-through .labpage .b-week li::after{width:2px;background:var(--gold-hair)}
html[data-dir].is-through .labpage .b-week-t{color:var(--gold-label);opacity:1;font-weight:700;}

/* ── the numbered steps are VARIANT 6's line ──────────────────────────────
   Measured off /style-lab/6-route.html#s8. The gazette set the step number as a
   plain serif numeral hanging in the margin beside a hairline; the route makes
   it a filled gold disc sitting ON a gold rail — the block already IS a journey,
   so it gets the line treatment properly.

   `.b-seq-label` and `.b-seq-actor` are removed from the two gazette groups
   above rather than overridden here: the route skin never re-cuts the step
   title, so art-shell's own 17px/600 IS the reference, and re-stating it would
   just be a second copy to drift. The actor label does need its own rule — the
   route paints it gold and bold, which art-shell does not. */
html[data-dir].is-through .labpage .b-seq li{padding-left:38px}
/* The disc is a grid box so the numeral centres optically inside it; art-shell
   lays the same ::before out as a plain block, which is why width and height
   were tracking the glyph instead of the circle. left:0 and 22px pair with
   art-shell's `left:11px` on the rail below — 11px is the disc's own centre. */
html[data-dir].is-through .labpage .b-seq li::before{
  display:grid;place-items:center;width:22px;height:22px;left:0;top:-1px;
  border-radius:50%;background:var(--gold-deep);color:#fff;opacity:1;
  font:700 .58rem/1 var(--font);}
html[data-dir].is-through .labpage .b-seq li::after{width:2px;background:var(--gold-hair)}
html[data-dir].is-through .labpage .b-seq-actor{
  color:var(--gold-label);opacity:1;font-weight:700;font-size:10px;letter-spacing:.15em;}
/* .b-opt-title, not `.b-switch label`: the six situations stopped being a
   radio accordion, and the labels went with the inputs. */
/* ── the six situations are VARIANT 4's floating cards ────────────────────
   Measured off /style-lab/4-daybreak.html. The gazette made each situation a
   rule with 22px of air above it; daybreak floats each one as its own rounded
   card. Only .b-opt and its title change — the 12px grid gap, the title's
   16/18/12 padding and divider, and the pane's 14/18/18 already agree, so
   nothing else here needed touching.

   The card face is TRANSPARENT, not #fff, which is what the lab renders: on
   daybreak's warm wash the page shows through and reads as white, and on this
   white ground it is white outright.

   Daybreak's gold-tinted float is deliberately NOT taken — these are the shape
   and the hairline only. `box-shadow:none` is written out rather than left off,
   because art-shell puts a shadow on .b-opt in its hover state and the
   declaration has to exist for the two states to stay identical. */
html[data-dir].is-through .labpage .b-opt{
  background:transparent;border:1px solid rgba(22,23,26,.1);border-radius:20px;padding:0;
  box-shadow:none;}
/* Inert on hover and on focus, by restating the resting state rather than by
   deleting a rule. art-shell answers both with a brand border, a #ffcc0012 wash
   and an `inset 2px 0 0` bar — written for a square card, so on a 20px radius
   it clips at the corners. Drop these two selectors and that comes straight
   back; they are what holds the card still. */
html[data-dir].is-through .labpage .b-opt:hover,
html[data-dir].is-through .labpage .b-opt:focus-within{
  background:transparent;border-color:rgba(22,23,26,.1);box-shadow:none;}
/* art-shell hovers the TITLE too, on a separate rule — `color:var(--or1)`, which
   would leave the one hover effect still running after the card itself went
   inert. Held at the resting ink. */
html[data-dir].is-through .labpage .b-opt:hover .b-opt-title,
html[data-dir].is-through .labpage .b-opt:focus-within .b-opt-title{
  color:var(--ink);opacity:1;}
/* Sans at 700, not the gazette's serif at 400 — this is the one place the
   variant-4 card overrides the gazette's block-heading face. */
html[data-dir].is-through .labpage .b-opt-title{
  font-family:var(--font);font-weight:700;font-size:1rem;line-height:1.65;opacity:1;}
html[data-dir].is-through .labpage .art-sources-k{font-family:var(--serif);font-style:italic;font-size:1.02rem; letter-spacing:0;text-transform:none;color:var(--ink);margin-bottom:14px;}


/* ── section 15: the closing steps as a two-column card grid ──────────────
   art-shell renders this block as one ruled column — `border-left:2px solid
   var(--or2)` with a 24px indent. The rule goes and the six paragraphs become
   cards instead, two across, in the same terms as the situation cards in
   section 2: transparent face, one neutral hairline, 20px radius, no shadow.

   The grid is on the block and the card on its paragraphs, so no markup
   changes — the resolution ships as six sibling <p>, five numbered steps and
   a closing thought, and each simply becomes a cell. Six into two columns is
   three even rows, which is why the closing paragraph is carded too rather
   than left to hang under an orphan fifth step.

   art-shell's `.art-prose p` bottom margin has to go with it: inside a card it
   would push the text off-centre, and the grid gap is the spacing now. */
html[data-dir].is-through .labpage .art-resolution{
  border-left:0;padding-left:0;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;
  /* Every card the same height, not just the pair on each row. `1fr` rows all
     take the tallest card's height and the default `stretch` fills them; the
     earlier `align-items:start` was what let neighbours end at different
     depths. The cost is deliberate: the shortest step now carries whitespace
     so the longest one sets the measure. */
  grid-auto-rows:1fr;}
html[data-dir].is-through .labpage .art-resolution p{
  margin:0;background:transparent;border:1px solid var(--hair);border-radius:20px;padding:20px 22px;}
/* The closing thought is not a step, so it loses the frame — but it keeps its
   cell and its padding, so the text stays aligned with the column above it and
   the grid stays whole rather than opening a hole beside the fifth step.
   Guarded twice: only the LAST paragraph, and only when it carries no bold lead
   — a resolution that is all numbered steps keeps every one of them carded. */
html[data-dir].is-through .labpage .art-resolution p:last-child:not(:has(strong)){
  border:0;border-radius:0;background:transparent;}
/* One column once the pair would be narrower than the 760px column can carry —
   the same breakpoint art-shell uses to unstack the rest of the vocabulary. */
@media(max-width:760px){
  /* One column, and `1fr` rows go with the second column. Matched heights exist
     so neighbours end level; stacked there are no neighbours, and forcing every
     row to the longest step's height would pad each short one for nothing. This
     page's steps happen to wrap to the same depth at 375px, but the next
     article's will not. */
  html[data-dir].is-through .labpage .art-resolution{grid-template-columns:1fr;grid-auto-rows:auto;}
}



/* ═══════════════════════════════════════════════════════════════════════════
   THE HORIZON CLOSE — footer-lab variant C, ported value for value.

   Source: scripts/buy-lab/footer-lab/bold.html, the `.hz` block, on the backup
   branch. Every number below is that file's number: the 150% breakout, the
   50%/120px ellipse, both shadow stops, 96px, 34px, 52px, 18px, the 11px/.3em
   labels, the 14.5px/.5 links, the 12.5px/.3 bottom row.

   BOTH HALVES KEEP THE SITE MEASURE. The close in the sky and the three-column
   grid on the ground are each inside the footer's own `.wrap`, so common.css
   caps them at 1640px from 1240px up and gutters them below — the same measure
   the header and the article use. The ground's tracks are `.footer-grid`'s own,
   so its three columns line up with the light footer's. Nothing here invents a
   width.

   THE FOOTER IS NIGHT IN BOTH OF THIS PAGE'S STATES. It does not follow the
   door: variant C is a black sky over a black planet, and a footer that turned
   white after the door would be a different design. So every rule below is
   stated once with no `.is-through` half — except the background, which has to
   be restated at that specificity to beat the daylight
   `.site-footer{background:#f5f5f6}` rule above.

   Scoped to `.site-footer--hz`, which only Footer.astro's horizon branch emits,
   so the other two presentation classes cannot see any of it.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --hz-* rather than the file's own --or1/--grad: every token in lab.css is
   declared on `.labpage`, and the footer is a SIBLING of .labpage, not a
   descendant. A bare var(--or1) in here resolves to nothing and the whole
   declaration is dropped. Values are the mockup's `.pv` block verbatim. */
html[data-dir] .site-footer--hz,
html[data-dir].is-through .site-footer--hz {
  --hz-or1: #F6D27A;
  --hz-or2: #D9A83F;
  --hz-grad: linear-gradient(180deg, #F6D27A, #D9A83F 52%, #8F6612);
  --hz-blanc: 245, 242, 234;

  position: relative;
  background: #040404;                     /* .pv --noir */
  border-top: 0;
  overflow: hidden;                        /* .hz — the ground breaks out to 150% */
  color: rgb(var(--hz-blanc));
  font-family: 'Figtree', -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
}

/* ── the sky ─────────────────────────────────────────────────────────────
   The mockup's `.hz-sky` is lopsided on purpose (6vh over 13vh, to leave the
   atmosphere room to burn); here the band is symmetrical — 12vh top and bottom —
   so the close sits centred in its own sky. 12vh still clears the ground's glow,
   which reaches 26px up and blurs 90px. Horizontal padding comes from the
   footer's own `.wrap`, so the block measures like the rest of the page. */
html[data-dir] .site-footer--hz .f-sky { position: relative; padding: 12vh 0; }
html[data-dir] .site-footer--hz .f-close { position: relative; text-align: center; }
html[data-dir] .site-footer--hz .f-stars {
  position: absolute; inset: 0; pointer-events: none; opacity: .5;
}
html[data-dir] .site-footer--hz .f-stars i {
  position: absolute; width: 1.5px; height: 1.5px; border-radius: 50%; background: #F5F2EA;
}

/* ── the ground ──────────────────────────────────────────────────────────
   .hz-ground. One elliptical border-radius on a box 150% of the footer's
   width, pulled left by a quarter of itself so its centre still lines up with
   the page's. The overhang is what makes the curve shallow enough to read as a
   planet rather than a bowl — narrow it and you get a bowl. .f-ground-in undoes
   the breakout: 66.66% of 150% is 100%, so the grid inside keeps the site
   measure common.css gives every other `.site-footer .wrap`. */
html[data-dir] .site-footer--hz .f-ground {
  position: relative; width: 150%; margin-left: -25%;
  background: #000;
  border-top: 1px solid rgba(246, 210, 122, .34);
  border-radius: 50% 50% 0 0 / 120px 120px 0 0;
  box-shadow: 0 -26px 90px rgba(217, 168, 63, .16), 0 -2px 0 rgba(246, 210, 122, .06);
  padding: 96px 0 0;
}
html[data-dir] .site-footer--hz .f-ground-in { width: 66.66%; margin: 0 auto; }
/* The ground already carries the mockup's 96px of clearance under the curve;
   `.footer-grid`'s own 52px on top of it would push the columns off the arc. */
html[data-dir] .site-footer--hz .footer-grid { padding-top: 0; padding-bottom: 52px; }

/* ── the mark, on the ground ─────────────────────────────────────────────
   Column one of three. The dark wordmark would disappear into #000, so it is
   swapped the way common.css already swaps it for the globe header — and for
   the same reason that only works because BrandMark renders an <img>:
   `content: url()` replaces the box of a REPLACED element and is silently
   ignored on an inline <svg>. */
html[data-dir] .site-footer--hz .brand-mark {
  content: url(/pages-assets/logo-mark-white.svg);
  /* `.brand--sm` shrinks the mark to 30px for the light footer's tighter column.
     Heading a column of its own on the ground it reads as an afterthought at
     that size, so it goes back to the 40px common.css gives `.brand-mark`
     everywhere else — the site's own full size, not a new one. */
  height: 40px;
}
html[data-dir] .site-footer--hz .f-brand-line {
  margin: 16px 0 6px; font-size: 1.02rem; font-weight: 600; line-height: 1.5;
  color: rgb(var(--hz-blanc));
}
html[data-dir] .site-footer--hz .f-brand-line-sub {
  margin: 0; max-width: 34ch; font-size: .9rem; line-height: 1.65;
  color: rgba(var(--hz-blanc), .5);
}

/* ── the close, standing in the sky ──────────────────────────────────────
   .close-h — the tagline IS the closing headline here: same string, new
   register. Sora 800 is the mockup's display face and is already loaded on this
   page (Layout.astro's fonts prop carries Outfit + Sora + Figtree). */
html[data-dir] .site-footer--hz .f-tagline {
  position: relative; max-width: none; margin: 0 0 18px;
  font-family: 'Sora', -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  font-weight: 800; font-size: clamp(30px, 4.4vw, 56px);
  line-height: 1.06; letter-spacing: -.028em;
  color: #fff;
}
/* .close-p */
html[data-dir] .site-footer--hz .f-tagline-sub {
  position: relative; margin: 0 auto 40px; max-width: 560px;
  font-size: 17px; line-height: 1.65; font-weight: 400;
  color: rgba(var(--hz-blanc), .55);
}
/* The same button the header carries on its right, not the mockup's gradient
   pill. Its size and radius are restated rather than inherited: they live in
   Header.astro's scoped block under `.site-header .actions`, which cannot reach
   the footer. The rest (#f8d86d, the two shadows, the #FFD700 hover) is
   common.css's own .btn/.btn-yellow, and common.css's `.f-cta` 42px/13px is what
   has to be overridden. font-family is stated because this footer sets Figtree
   and the header's button inherits the body's Outfit. */
html[data-dir] .site-footer--hz .f-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 45px; padding: 0 18px; box-sizing: border-box;
  border: 1px solid transparent; border-radius: 15px;
  background: #f8d86d; color: #000;
  font-family: Outfit, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", Arial, sans-serif;
  /* .92rem, not .btn's 14px: that is what the header's button actually computes
     to, and "the same button" has to mean the same type size too. */
  font-size: .92rem; font-weight: 600; line-height: 1; white-space: nowrap;
  box-shadow: 0 6px 16px #f8d86d73, inset 0 0 10px #0000000a;
}
html[data-dir] .site-footer--hz .f-cta:hover { background: #FFD700; color: #000; }

/* ── the link columns ────────────────────────────────────────────────────
   .hz h4 / .hz li a. Widths and tracks are left to `.footer-grid` and
   `.f-links` — this is colour and type only. */
html[data-dir] .site-footer--hz .f-col h4 {
  display: block; margin: 0 0 14px; padding-bottom: 0;
  font-family: 'Sora', -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  font-size: 11px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase;
  color: var(--hz-or2);
}
/* The rule that grows under each heading on hover belongs to the light footer;
   on the ground the gold label is the whole signal. */
html[data-dir] .site-footer--hz .f-col h4::after { display: none; }
html[data-dir] .site-footer--hz .f-col a {
  /* flex, not block, so a label that wraps aligns to the chevron's right edge
     instead of running back under it */
  display: flex; align-items: center; gap: 10px;
  padding: 5px 0; font-size: 14.5px;
  color: rgba(var(--hz-blanc), .5); transition: color .2s;
}
html[data-dir] .site-footer--hz .f-col a:hover {
  color: var(--hz-or1); transform: none;
}
/* common.css dims every OTHER link in the column to .45 while one is hovered —
   `.f-col ul:has(a:hover) a:not(:hover)`, part of a site-wide focus effect it
   shares with the topic cards and chips. On the ground the links are already at
   .5 alpha, so dimming them again reads as the list greying out rather than as
   emphasis. The hovered link going gold is the whole signal. */
html[data-dir] .site-footer--hz .f-col ul:has(a:hover) a:not(:hover) { opacity: 1; }

/* A chevron before every link. This REPLACES the light footer's marker rather
   than restyling it: that one is a gold dot, absolutely positioned at left:-12px
   and faded in on hover — a different idea from a permanent leading arrow — so
   every property it sets has to be unset here, `position` and `opacity`
   included, or the dot's geometry leaks through.

   Drawn from two borders on a rotated box rather than a "›" glyph: weight,
   size and optical centre are then ours and not whatever the font ships. It
   inherits `currentColor`, so it follows the link into gold on hover for free. */
html[data-dir] .site-footer--hz .f-col a::before,
html[data-dir] .site-footer--hz .f-col a:hover::before {
  content: ""; display: block; flex: none;
  position: static; left: auto; top: auto;
  width: 5px; height: 5px; margin: -1px 0 0;
  border: 0; border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor;
  border-radius: 0; background: none; opacity: 1;
  transform: rotate(45deg);
}

/* The explore list's COLUMN COUNT is not set here any more.
   
   What stood here spanned the explore nav across two of `.f-links`' three tracks
   and flowed its twelve topics 6/6 down them, leaving the cities nav as the
   third track — the shape the ground was designed around when there were two
   link groups. There is one group now (Footer.astro merged cities into
   "Explorer Villes"), so that override did the opposite of its purpose: the
   merged nav still matched `:not(.f-col--cities)`, still split 6/6, and the one
   city link landed alone in a third column with no heading over it.
   
   The nav spans the whole row on its own now (`.f-col--explore`), and the split
   lives with the markup in Footer.astro so every footer divides the same way.
   Nothing page-specific is left to say about it. */

/* .hz-bottom */
html[data-dir] .site-footer--hz .footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, .06);
}
html[data-dir] .site-footer--hz .footer-bottom .wrap { padding-top: 18px; padding-bottom: 18px; }
html[data-dir] .site-footer--hz .copy { font-size: 12.5px; color: rgba(var(--hz-blanc), .3); }
html[data-dir] .site-footer--hz .copy a { color: rgba(var(--hz-blanc), .45); font-weight: 400; }
html[data-dir] .site-footer--hz .copy a:hover { color: var(--hz-or1); }
html[data-dir] .site-footer--hz .copy a::after { display: none; }
html[data-dir] .site-footer--hz .copy-sep { color: rgba(var(--hz-blanc), .18); }

/* 120px of arc across a phone is a bowl, not a horizon. */
@media (max-width: 900px) {
  html[data-dir] .site-footer--hz .f-ground {
    border-radius: 50% 50% 0 0 / 56px 56px 0 0; padding-top: 62px;
  }
}
