/* ====================================================================
   LN Flooring - article layout ("Immersive spread")
   Loaded AFTER each article's inline <style>, so it overrides it without
   touching 37 files of duplicated CSS.

   Pairs with js/article-spread.js (right-hand card, contents progress)
   and js/fluid.js (the background field).
   ==================================================================== */

/* ====================================================================
   D — IMMERSIVE SPREAD   (B's header + C's spread)

   B gives the article one big photographic moment at the top; C gives
   it a working three-zone body. The join is the only real design
   problem: C's rails are position:fixed at top:7.5rem, so on their own
   they would sit ON TOP of B's full-bleed hero from the first frame -
   a table of contents laid over a photograph, which is both ugly and
   unreadable.

   So the rails are held back until the reader passes the hero, then
   fade in. The hero gets a clean uninterrupted moment; the furniture
   arrives when there is text to navigate. Handled in d-combined.js.
   ==================================================================== */

/* ====================================================================
   1. THE HEADER  (from B)
   Full-bleed WITHOUT 100vw: 100vw counts the scrollbar and overhangs
   the document by exactly its width (measured 8px at 1440), causing
   real horizontal scroll. <main> is already exactly clientWidth, so
   breaking out against it is edge-to-edge and scrollbar-safe.
   ==================================================================== */

main { position: relative; }
.post-wrap { position: static; }   /* band resolves against <main> */

@media (min-width: 900px) {
  .post-wrap { padding-top: 0; }

  .post-breadcrumb, .post-cat, .post-title, .post-meta { position: relative; z-index: 3; }

  .post-wrap::before {
    content: "";
    position: absolute; top: 0; left: 0; right: 0; width: auto;
    height: var(--lnhero, 640px);
    background: var(--dark, #0F0D0B);
    z-index: 0;
  }

  .post-hero-img {
    position: absolute !important;
    /* width:100%, not auto+right:0 — for an absolutely positioned
       REPLACED element width:auto means the image's INTRINSIC width and
       the right offset is ignored (it rendered at its natural size). */
    top: 0; left: 0; right: auto; width: 100%;
    height: var(--lnhero, 640px);
    max-width: none; border-radius: 0; border: 0;
    object-fit: cover; margin: 0; z-index: 1;
    filter: saturate(0.95) brightness(0.72);

    /* The hard line at the top of the band was the PHOTO's own edge, not
       the field/plate boundary — the image began at full opacity on row
       one. Masking its top third lets it emerge out of the dark instead
       of arriving, which is what actually reads as a fade-in. */
    -webkit-mask-image: linear-gradient(to bottom,
      rgba(0,0,0,0) 0%, rgba(0,0,0,0.10) 7%, rgba(0,0,0,0.30) 14%,
      rgba(0,0,0,0.55) 22%, rgba(0,0,0,0.78) 30%, rgba(0,0,0,0.93) 37%,
      rgba(0,0,0,1) 44%);
    mask-image: linear-gradient(to bottom,
      rgba(0,0,0,0) 0%, rgba(0,0,0,0.10) 7%, rgba(0,0,0,0.30) 14%,
      rgba(0,0,0,0.55) 22%, rgba(0,0,0,0.78) 30%, rgba(0,0,0,0.93) 37%,
      rgba(0,0,0,1) 44%);
  }

  .post-wrap::after {
    content: "";
    position: absolute; top: 0; left: 0; right: 0; width: auto;
    height: var(--lnhero, 640px);
    z-index: 2; pointer-events: none;
    background: linear-gradient(to top,
      rgba(10,9,7,0.97) 0%, rgba(10,9,7,0.88) 26%,
      rgba(10,9,7,0.42) 58%, rgba(10,9,7,0.30) 100%);
  }

  .post-breadcrumb { padding-top: 2.5rem; margin-top: calc(var(--lnhero, 640px) - 440px); }

  .post-title {
    font-size: clamp(2.2rem, 3.6vw, 3.4rem);
    line-height: 1.09; letter-spacing: -0.026em;
    text-wrap: balance; max-width: 21ch;
    text-shadow: 0 2px 30px rgba(0,0,0,0.6);
    margin-bottom: 1.35rem;
  }
  .post-meta { margin-bottom: 4rem; border-bottom: 0; padding-bottom: 0; }

  .post-body { position: relative; z-index: 3; }
}

/* ====================================================================
   2. THE SPREAD  (from C)
   ==================================================================== */

@media (min-width: 1480px) {
  .post-wrap {
    max-width: 1400px;
    padding-left: 300px;
    padding-right: 340px;
  }

  /* left: contents, anchored to the article not the viewport */
  body .post-toc-rail {
    top: 7.5rem; bottom: auto; transform: none;
    left: calc(50% - 700px);
    width: 240px;
    max-height: calc(100vh - 11rem);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(184,132,10,0.3) transparent;
  }

  /* right: the standing card */
  .ln-aside {
    position: fixed;
    top: 7.5rem;
    left: calc(50% + 448px);
    width: 252px;
    z-index: 40;
    display: flex; flex-direction: column; gap: 1rem;
    max-height: calc(100vh - 11rem);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(184,132,10,0.3) transparent;
  }
}

/* --- the join: hold the rails back until the hero is behind us ------ */
/* Both rails start hidden and are revealed by adding .is-reading to
   <body> (d-combined.js). visibility, not just opacity, so they are
   not focusable while invisible.                                     */
@media (min-width: 1480px) {
  body .post-toc-rail,
  .ln-aside {
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity .5s cubic-bezier(.22,1,.36,1),
                transform .5s cubic-bezier(.22,1,.36,1),
                visibility 0s .5s;
  }
  body.is-reading .post-toc-rail,
  body.is-reading .ln-aside {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: opacity .5s cubic-bezier(.22,1,.36,1),
                transform .5s cubic-bezier(.22,1,.36,1),
                visibility 0s 0s;
  }
}
@media (prefers-reduced-motion: reduce) {
  body .post-toc-rail, .ln-aside { transform: none !important; transition: none !important; }
}

/* --- reading type ---------------------------------------------------- */
.post-body { font-size: 1.06rem; line-height: 1.83; color: rgba(245,240,232,0.88); }
.post-body > p { max-width: 68ch; margin-bottom: 1.5rem; text-wrap: pretty; }
.post-body > h2 {
  margin-top: 3.3rem; margin-bottom: 1rem;
  font-size: clamp(1.42rem, 2.1vw, 1.9rem);
  letter-spacing: -0.015em; text-wrap: balance;
}
.post-body > h3 { margin-top: 2.25rem; margin-bottom: 0.75rem; }
.post-body > ul, .post-body > ol { max-width: 66ch; }
.post-body a { text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* --- the aside cards (from C) ---------------------------------------- */
.ln-aside { display: none; }
@media (min-width: 1480px) { .ln-aside { display: flex; } }

.ln-card {
  border: 1px solid rgba(200,169,110,0.18);
  border-radius: 14px;
  background: rgba(28, 24, 20, 0.6);
  padding: 1.15rem 1.25rem 1.3rem;
}
.ln-card__label {
  font-family: var(--font-mono, monospace);
  font-size: 0.6rem; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--gold2, #D4A018); display: block; margin-bottom: 0.7rem;
}
.ln-card__title {
  font-family: var(--font-serif, serif);
  font-size: 1.02rem; font-weight: 400; line-height: 1.3;
  color: var(--ivory); margin-bottom: 0.5rem;
}
.ln-card__text { font-size: 0.82rem; line-height: 1.6; color: var(--greige); margin-bottom: 1rem; }
.ln-wa {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 11px 16px; border-radius: 100px;
  background: var(--gold, #B8840A); color: #1A0F00;
  font-weight: 600; font-size: 0.83rem;
  transition: background .3s, transform .3s;
}
.ln-wa:hover { background: var(--gold2, #D4A018); transform: translateY(-2px); }
.ln-wa:focus-visible { outline: 2px solid var(--gold2); outline-offset: 3px; }
.ln-facts { display: flex; flex-direction: column; gap: 0.55rem; }
.ln-fact {
  display: flex; justify-content: space-between; gap: 0.75rem;
  font-size: 0.76rem; line-height: 1.45;
  padding-bottom: 0.55rem; border-bottom: 1px solid rgba(245,240,232,0.07);
}
.ln-fact:last-child { border-bottom: 0; padding-bottom: 0; }
.ln-fact__k { color: rgba(160,144,128,0.85); white-space: nowrap; }
.ln-fact__v { color: var(--ivory); text-align: right; }
@media (prefers-reduced-motion: reduce) { .ln-wa:hover { transform: none; } }

/* --- fallbacks ------------------------------------------------------- */
@media (min-width: 1100px) and (max-width: 1479px) {
  .post-wrap { max-width: 1010px; padding-left: 288px; padding-right: 24px; }
  body .post-toc-rail {
    top: 7.5rem; bottom: auto; transform: none;
    left: calc(50% - 505px); width: 232px;
    max-height: calc(100vh - 11rem); overflow-y: auto;
  }
}
@media (max-width: 1099px) { .post-wrap { max-width: 780px; } }
@media (max-width: 899px)  { .post-hero-img { height: 300px; } }

/* ====================================================================
   3. THE FLUID, AS A PAGE BACKGROUND
   Not a header effect this time - a fixed layer BEHIND the whole
   document. The article sits on an opaque plate, so the field is only
   ever seen in the deliberate gaps above and below it. Text never
   competes with it.

   The top gap already existed, but by accident: .post-breadcrumb has a
   200px top margin which COLLAPSES out through .post-wrap and <main>,
   dragging <main> itself down and exposing the body behind it. That is
   too fragile to build on, so the collapse is contained and the band is
   re-created on purpose.
   ==================================================================== */

body { display: flow-root; }          /* stop main margin escaping body */
.post-wrap { display: flow-root; }    /* contain the breadcrumb margin  */

.ln-fluid {
  position: fixed; inset: 0;
  z-index: 0;
  width: 100%; height: 100%;
  display: block; pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s cubic-bezier(.22,1,.36,1);
}
/* held well back — this is a backdrop, not a feature. At full strength
   it reads as a gold banner competing with the hero photograph. */
.ln-fluid.on { opacity: 0.42; }

/* the always-there default, in case WebGL never starts */
.ln-fluid-bed {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(90% 60% at 82% 2%,  rgba(212,160,24,0.10) 0%, rgba(212,160,24,0) 60%),
    radial-gradient(80% 55% at 20% 99%, rgba(110,69,8,0.13)  0%, rgba(110,69,8,0)  66%);
}

/* content rides above the field */
main, .footer, .post-toc-rail, .ln-aside,
.chat-bubble, .chat-panel, .wa-float { position: relative; z-index: 1; }
.post-toc-rail, .ln-aside, .chat-bubble, .chat-panel, .wa-float { position: fixed; z-index: 40; }

/* the plate: opaque so body copy never sits on moving colour */
main { background: var(--dark, #0F0D0B); }

/* the two reveal bands */
@media (min-width: 900px) {
  main   { margin-top: clamp(170px, 22vh, 280px); }
  .footer { margin-top: clamp(170px, 22vh, 280px); position: relative; z-index: 1; background: var(--dark3, #0A0907); }
}
@media (max-width: 899px) {
  main   { margin-top: 90px; }
  .footer { margin-top: 90px; background: var(--dark3, #0A0907); }
}

/* ====================================================================
   4. CONTENTS PROGRESS
   The rail already marks the ACTIVE section; this adds how far through
   the article you are, as a filling line down the left of the list.
   --toc-progress is written by d-combined.js (0..1).
   ==================================================================== */

body .post-toc-rail { position: fixed; }

/* The bar belongs to the LIST, not the rail. Spanning the whole rail
   drew it straight through the "I" of "IN THIS GUIDE". The <ol> already
   carries the 1px track border, so the fill sits exactly on it. */
body .post-toc-rail ol { position: relative; }
body .post-toc-rail ol::before {
  content: "";
  position: absolute;
  left: -1px; top: 0; bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, var(--gold3, #6E4508), var(--gold2, #D4A018));
  transform: scaleY(var(--toc-progress, 0));
  transform-origin: top center;
  transition: transform .14s linear;
  border-radius: 2px;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  body .post-toc-rail ol::before { transition: none; }
}

/* ====================================================================
   5. SOFT EDGES ON THE BANDS
   The field met the content plate on a hard horizontal line. These
   fade the two together at both ends so the backdrop reads as one
   continuous surface the page is floating on.
   ==================================================================== */

main::before,
main::after,
.footer::before {
  content: "";
  position: absolute; left: 0; right: 0;
  height: clamp(200px, 24vh, 330px);
  pointer-events: none;
  z-index: 0;
}

/* Eased stops, not a plain two-stop ramp. A linear fade between
   transparent and solid still reads as an edge because the eye picks
   up the constant slope; the extra stops approximate an ease-in so the
   field dissolves into the plate instead of meeting it. */
main::before {
  top: calc(-1 * clamp(200px, 24vh, 330px));
  background: linear-gradient(to bottom,
    rgba(15,13,11,0) 0%, rgba(15,13,11,0.06) 18%, rgba(15,13,11,0.20) 34%,
    rgba(15,13,11,0.42) 50%, rgba(15,13,11,0.68) 66%, rgba(15,13,11,0.88) 82%,
    rgba(15,13,11,0.97) 92%, var(--dark, #0F0D0B) 100%);
}
main::after {
  bottom: calc(-1 * clamp(200px, 24vh, 330px));
  background: linear-gradient(to top,
    rgba(15,13,11,0) 0%, rgba(15,13,11,0.06) 18%, rgba(15,13,11,0.20) 34%,
    rgba(15,13,11,0.42) 50%, rgba(15,13,11,0.68) 66%, rgba(15,13,11,0.88) 82%,
    rgba(15,13,11,0.97) 92%, var(--dark, #0F0D0B) 100%);
}
.footer { position: relative; }
.footer::before {
  top: calc(-1 * clamp(200px, 24vh, 330px));
  background: linear-gradient(to bottom,
    rgba(10,9,7,0) 0%, rgba(10,9,7,0.06) 18%, rgba(10,9,7,0.20) 34%,
    rgba(10,9,7,0.42) 50%, rgba(10,9,7,0.68) 66%, rgba(10,9,7,0.88) 82%,
    rgba(10,9,7,0.97) 92%, var(--dark3, #0A0907) 100%);
}

/* The rail's own section marker: post-toc.js gives the active link a
   2px gold border-left, which sits in exactly the same 2px column as
   the progress fill — two indicators stacked on one line. The colour
   is dropped, the 2px is KEPT so nothing shifts sideways when the
   active item changes. The gold link text still says where you are. */
body .post-toc-rail a.is-current,
body .post-toc-rail a[aria-current] { border-left-color: transparent; }
