/* LUXVISION — Landing page specific layout (page-level, not shared tokens) */

.lv-toast {
  position: absolute;
  left: 50%;
  bottom: 2.5rem;
  transform: translateX(-50%);
  z-index: 20;
  padding: 0.7rem 1.3rem;
  border-radius: var(--lv-radius-pill);
  background: rgba(18, 18, 24, 0.92);
  border: 1px solid var(--lv-border-strong);
  color: var(--lv-ink);
  font-size: 0.85rem;
  opacity: 0;
  pointer-events: none;
}

/* Hero is position:fixed, so reserve its height in normal flow */
.lv-hero-spacer { height: 100dvh; }

/* ---- Hero handoff: the brand line, revealed on the way off the ring ----

   Opaque and z-indexed above the fixed hero, so it wipes the carousel as it
   rises rather than sitting transparently on top of it. That opacity is the
   feature, not a detail: the brief was that this copy must stop covering the
   product, and a transparent panel in the spacer would have reproduced the
   overlap exactly.

   Full viewport height because the line needs to be alone. Given a third of a
   screen it reads as a caption to whatever is above it; given the whole
   screen it reads as a statement, which is what a headline shared with the
   film intro has to be.

   The words themselves arrive via .lv-split-reveal - masked and slid up in
   sequence at 40% visibility - so the reveal is tied to the reader crossing
   the panel rather than to a scroll distance that would differ on every
   display. */
.lv-hero-handoff {
  position: relative;
  z-index: 10;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  background: var(--lv-bg);
  /* Sits directly beneath the hero and directly above Our Promise, both of
     which are near-black. A hairline of lift at the top edge keeps the panel
     from reading as one continuous void across three sections. */
  background-image: radial-gradient(
    120% 70% at 50% 0%,
    rgba(149, 101, 237, 0.07) 0%,
    transparent 62%
  );
}

.lv-hero-handoff-inner {
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
}

/* ── THE FLAG BEHIND THE BRAND STATEMENT ───────────────────────────────────
   14 September 2026. Joel: "a greyscale Canadian flag slowly waving in the
   breeze ... behind the 'Precision in Every Pixel' section."

   ⚠️ This block is `background: var(--lv-bg)` and OPAQUE ON PURPOSE — it is
   what wipes the fixed hero carousel as it rises past. Dropping a video in
   behind the copy must not break that, so the clip lives in its own layer
   INSIDE the section rather than replacing the background, and the section
   keeps its own solid fill underneath.

   ⛔ The greyscale is baked into the file, not applied with a CSS filter.
   `filter: grayscale(1)` on a playing video re-filters every composited frame,
   and this one plays behind the page's first heading — the worst place to
   spend frame budget. */
.lv-flag-bed { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
.lv-flag-still,
.lv-flag-clip {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Low, because it sits behind the page's h1. It is atmosphere, not subject:
     if it competes with the headline it has failed. */
  opacity: 0.17;
  transform: scale(1.04);
}
.lv-flag-clip { z-index: 1; }

/* Darkest in the middle, where the copy is. The corners keep a little more of
   the fabric so the movement is still visible at the edges of vision. */
.lv-flag-scrim {
  position: absolute; inset: 0; z-index: 2;
  background:
    radial-gradient(72% 58% at 50% 50%, rgba(5,7,10,0.92), rgba(5,7,10,0.55) 70%, rgba(5,7,10,0.3)),
    linear-gradient(to bottom, var(--lv-bg), transparent 26%, transparent 74%, var(--lv-bg));
}
.lv-hero-handoff-inner { position: relative; z-index: 3; }

/* ── THE TWO LILAC LINES AROUND THE HEADLINE ──────────────────────────────
   Joel, 14 September 2026: "move the Proudly designed and manufactured in
   Canada text to above the Precision in every pixel text, make it bold and our
   Lilac colour. We can remove the Canadian engineered... to below the Precision
   in every pixel text and keep it the Lilac colour."

   ⚠️ `var(--lv-lilac)` directly, NOT `var(--lv-accent)`. The landing page's
   accent is the sitewide Cornflower; Lilac is the PROLUX accent and only
   appears on PROLUX pages. Joel asked for Lilac here specifically, so it is
   named rather than inherited — otherwise it would silently turn blue the next
   time this block is reused on a page with a different theme.

   Contrast checked: #a380f2 on #05070a is 6.65:1, which clears WCAG AA for
   body text, not just for large text. It is the first line on the block and it
   sits over the flag layer, so that mattered. */
.lv-canada-line {
  margin: 0 0 1.1rem;
  font-family: var(--lv-font-body);
  font-weight: 700;
  font-size: clamp(0.84rem, 1.35vw, 1rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lv-lilac);
}

/* ⛔ .lv-brand-sub IS GONE. "Canadian-engineered LED display systems" sat
   beneath the headline in lilac; Joel removed it 14 Sept 2026.

   The rule went with it rather than being left behind. A style with no element
   is not harmless: the next person to read this file has to work out whether
   it is dead or whether the markup is broken, and a check that asserts "two
   lilac lines name the token" keeps passing on a stylesheet describing one
   line that exists and one that does not. */

@media (prefers-reduced-motion: reduce) {
  .lv-flag-clip { display: none; }
  .lv-flag-still { transform: none; }
}

/* Centred and larger here than it was in the corner of the hero. In the
   carousel this line was set against 16ch to keep it out of the product's
   way; with a panel to itself that constraint is gone, and the measure can
   open up to something a headline actually wants. */
.lv-hero-handoff .lv-hero-headline {
  max-width: 24ch;
  font-size: clamp(2.1rem, 5vw, 4.2rem);
  line-height: 1.05;
  margin-top: 0;
}

.lv-reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.8s var(--lv-ease), transform 0.8s var(--lv-ease); }
.lv-reveal.is-in { opacity: 1; transform: translateY(0); }

/* ---- Customer logo marquee ----

   A continuous belt rather than a static grid. A grid of eight logos has to
   be read; a belt is understood at a glance and keeps working when the list
   grows to thirty, which a grid does not.

   Seamless because the track is duplicated in the markup and travels exactly
   -50%: at the halfway point copy two sits precisely where copy one started,
   so the reset lands on an identical frame. This is why both copies must stay
   in step - drop a logo from one and the belt visibly jumps once per cycle. */
.lv-logos { overflow: hidden; }

.lv-logo-marquee {
  position: relative;
  margin-top: 1.75rem;
  overflow: hidden;
  /* Fades the belt out at both ends instead of letting logos hit a hard edge.
     Without it the marquee reads as a clipped div; with it, as something
     passing through the page. */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
}

.lv-logo-track {
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 5vw, 5rem);
  width: max-content;
  animation: lv-logo-belt 42s linear infinite;
}

/* Slow. 42s for a full cycle is deliberately below the speed at which the eye
   starts tracking individual items - the belt should register as ambient
   movement that rewards a glance, not as a carousel demanding one. */
@keyframes lv-logo-belt {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Pause on hover so a name someone recognises can actually be read. Hovering
   a moving list and being unable to stop it is a small, specific frustration
   that this costs one line to avoid. */
.lv-logo-marquee:hover .lv-logo-track { animation-play-state: paused; }

/*
  Logos arrive in whatever colours their owners use, and a row of eight
  competing brand palettes pulls harder than anything else on the page - which
  is exactly backwards, since this section is evidence, not the argument.

  So they are held monochrome and dimmed, and come up to full strength on
  hover. The treatment also rescues a row of mismatched source files: eight
  logos at eight different weights and colours look like a clip-art bin, and
  one flat ink makes them look curated.

  `filter` is on the item rather than the track so a future <img> logo and
  these text placeholders take the same treatment with no extra rule.
*/
.lv-logo-item {
  flex: 0 0 auto;
  font-family: var(--lv-font-display);
  font-weight: 600;
  font-size: clamp(1rem, 1.5vw, 1.4rem);
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--lv-ink-muted);
  opacity: 0.55;
  filter: grayscale(1);
  transition: opacity 0.4s var(--lv-ease), color 0.4s var(--lv-ease);
}
.lv-logo-item:hover { opacity: 1; color: var(--lv-ink); }

/* When real files land they drop straight in as <img> inside .lv-logo-item
   and inherit the height, the greyscale and the hover lift. */
.lv-logo-item img {
  height: clamp(1.6rem, 2.6vw, 2.4rem);
  width: auto;
  display: block;
}

/* Reduced motion: the belt stops and becomes a wrapping row. It must not
   simply freeze mid-travel, or half the logos sit permanently off-screen
   behind the mask - the content has to survive the animation being removed. */
@media (prefers-reduced-motion: reduce) {
  .lv-logo-track {
    animation: none;
    flex-wrap: wrap;
    width: 100%;
    justify-content: center;
    row-gap: 1.5rem;
  }
  .lv-logo-marquee { -webkit-mask-image: none; mask-image: none; }
  /* The duplicate copy is decoration once nothing is moving. */
  .lv-logo-item[aria-hidden="true"] { display: none; }
}

/* ---- Warranty ----

   Last section before the footer. Given a slightly lifted ground so it reads
   as a distinct closing statement rather than as one more scroll beat — this
   is the page's final argument and it should feel like the room going quiet,
   not like another card. */
.lv-warranty {
  position: relative;
  /* ⚠️ Found by the stacking check, not by eye. `position: relative` with
     z-index auto paints BELOW `.lv-hero`'s z-index 5 — this section has been
     under the fixed ring since it was written, and only looked right because
     the ring is transparent by the time you scroll here. */
  z-index: 10;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(149, 101, 237, 0.06) 0%, transparent 60%),
    var(--lv-bg-raised);
  border-top: 1px solid var(--lv-border);
}

.lv-warranty-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.5vw, 2.25rem);
  margin-top: clamp(2rem, 5vh, 3.5rem);
}

.lv-warranty-card {
  padding: clamp(1.5rem, 2.5vw, 2.25rem);
  border: 1px solid var(--lv-border);
  border-radius: var(--lv-radius-lg);
  background: rgba(255, 255, 255, 0.015);
}

/* The counters here run to values of wildly different magnitude — 7, 5 and
   100,000 — so they are NOT given a shared size. Sized as one, the seven-year
   figure would be set to survive a six-digit number and end up looking
   incidental, when it is the most important number in the section. */
.lv-warranty-card .lv-feature-stat {
  font-size: clamp(2rem, 3.6vw, 3.2rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.lv-warranty-card .lv-h3 { margin-top: 0.75rem; }

/* The clause gets its own block and a rule down the accent side. It is the
   one piece of copy on this page quoted verbatim from a legal document, and
   it should look like a quotation rather than like more marketing. */
.lv-warranty-clause {
  margin-top: clamp(2.5rem, 6vh, 4rem);
  padding-left: clamp(1.25rem, 2.5vw, 2rem);
  border-left: 2px solid var(--lv-accent);
}

.lv-warranty-clause blockquote {
  margin: 0;
  font-style: normal; /* it is a quotation, not an aside — italics would make
                         a legal term read as emphasis */
  line-height: 1.35;
}

.lv-warranty .lv-cta-row { margin-top: clamp(2rem, 4vh, 3rem); }

@media (max-width: 900px) {
  .lv-warranty-grid { grid-template-columns: 1fr; }
}

/* ---- Brand statement ---- */
.lv-brand-statement { position: relative; z-index: 10; background: var(--lv-bg); }
.lv-brand-bg { position: absolute; inset: 0; overflow: hidden; }
.lv-brand-bg img { width: 100%; height: 100%; object-fit: cover; opacity: 0.4; filter: saturate(0.6) contrast(1.1); }
.lv-brand-bg-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, var(--lv-bg) 0%, rgba(11,11,16,0.55) 40%, var(--lv-bg) 100%); }
.lv-brand-statement .lv-wrap { position: relative; }

/* ---- Canadian-made beat ---- */
.lv-canadian-beat { background: var(--lv-bg-raised); z-index: 10; position: relative; }
.lv-canadian-inner { display: grid; grid-template-columns: 0.85fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.lv-canadian-media .lv-img-frame { aspect-ratio: 4/5; }
@media (max-width: 860px) { .lv-canadian-inner { grid-template-columns: 1fr; } }

/* ---- CEO video ---- */
.lv-ceo-video { background: var(--lv-bg); z-index: 10; position: relative; }
.lv-ceo-video-frame {
  position: relative;
  max-width: 920px;
  margin: 0 auto;
  border-radius: var(--lv-radius-lg);
  overflow: hidden;
  aspect-ratio: 16/9;
  background: var(--lv-bg-raised);
}
.lv-ceo-video-frame video { width: 100%; height: 100%; object-fit: cover; }
.lv-ceo-captions {
  position: absolute; left: 1.25rem; right: 1.25rem; bottom: 1.25rem;
  background: rgba(11,11,16,0.75); padding: 0.6rem 0.9rem; border-radius: var(--lv-radius-sm);
  font-size: 0.85rem; color: var(--lv-ink);
}
.lv-ceo-video.is-unmuted .lv-ceo-video-frame [data-unmute] { display: none; }

/* ---- About us ---- */
.lv-about { background: var(--lv-bg-raised); z-index: 10; position: relative; }
.lv-team-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; margin-top: 2.5rem; margin-bottom: 1.5rem; }
.lv-team-photo { aspect-ratio: 1; border-radius: var(--lv-radius-md); background: linear-gradient(150deg, var(--lv-bg-raised-2), #232330); margin-bottom: 0.9rem; }
@media (max-width: 760px) { .lv-team-grid { grid-template-columns: repeat(2, 1fr); } }

/* ---- Footer ---- */

/* ⚠️ The footer rules moved to shared/base.css on 14 Sept 2026. The SAME
   footer markup sits on all seven pages, but only the landing page loads
   this file, so on the six product pages it had no styling at all: no
   grid, no border, no padding, just a stack of paragraphs. Found because
   Joel sent a screenshot of the footer and it prompted a look at the
   other pages. */

/* ── BUILT HERE ────────────────────────────────────────────────────────────
   14 September 2026.

   ── WHY THE GREYSCALE IS IN THE FILES AND NOT IN CSS ─────────────────────
   `filter: grayscale(1)` on a playing video re-filters every composited frame,
   and on a moving still it re-filters every frame the parallax touches. Both
   are baked at export. The grade is deliberate rather than a flat desaturate:
   a shop under fluorescent light goes muddy, so the floor is lifted, the mids
   deepened, and a trace of the brand blue left in the shadows.
   ───────────────────────────────────────────────────────────────────────── */
/* ⚠️ z-index 10, NOT z-index auto. `position: relative` alone is not enough to
   clear `.lv-hero`, which is fixed at z-index 5: a positioned element with
   z-index auto paints BELOW one with a positive z-index. This section only
   looked right because the hero is opacity 0 by the time you reach it — it was
   under the ring the whole way down. Same latent fault the Philosophy section
   shipped with. */
.lv-madehere { position: relative; z-index: 10; padding: 0; isolation: isolate; }
/* ⚠️ 420vh WAS RIGHT FOR FOUR STOPS AND WRONG FOR SIX.

   The dial turns between dockEnd (0.34) and turnEnd (0.92) of this track, so
   the scroll each stop gets is:

       (track - 100vh) * 0.58 / (stops - 1)

   At 420vh with four stops that was 62vh per stop. Adding the HD-X cabinet and
   the NEMA crossfade took it to 37vh without anything looking broken: the wheel
   simply spun faster and each picture got under two thirds of a screen before
   the next one arrived. Nothing errors when a section is paced wrong, which is
   why there is now a check on the arithmetic rather than on this number.

       580vh, six stops  ->  56vh each. */
.lv-madehere-track { position: relative; height: 580vh; }
.lv-madehere-stage {
  position: sticky; top: 0;
  height: 100vh; overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  align-content: center;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  /* ⚠️ THE TOP PADDING IS THE NAV KEEP-OUT, NOT A ROUND NUMBER. This stage is
     pinned, so `align-content: center` parks the copy in the same place for the
     whole section — a collision with the fixed brand mark is permanent here,
     not a moment in passing. Reserving the band centres the content in what is
     left below it. box-sizing is border-box site-wide, so the 100vh still
     describes the pinned height. */
  padding: var(--lv-nav-keepout) clamp(1.25rem, 5vw, 5rem) 0;
  --dock: 0;                    /* 0 = the clip fills the frame, 1 = docked right */
}

/* The copy arrives WITH the dock, not after it. Joel: "this radial swipe should
   appear at the same time as the text on the left hand side."

   ⚠️ Not a `.lv-reveal`. A reveal fires once on enter and never again; this has
   to track the dock in BOTH directions, so scrolling back up puts the copy away
   again and the clip gets its full frame back. */
.lv-madehere-copy {
  grid-column: 1; position: relative; z-index: 3;
  opacity: var(--dock);
  transform: translateY(calc((1 - var(--dock)) * 26px));
}

/* ── THE DIAL ──────────────────────────────────────────────────────────────
   Four stops on an arc. The whole dial is one fixed-size box that is SCALED
   and MOVED by transform to dock; the items inside are placed on the arc by
   transform too.

   ⚠️ Nothing here animates width, height, top or left. Those relayout the
   section on every frame of the scroll and force the video to rescale its own
   decode. Transforms are composited and the layout never changes. */
.lv-dial {
  position: absolute; top: 50%; left: 50%;
  width: min(62rem, 78vw);
  aspect-ratio: 16 / 10;
  transform-origin: 50% 50%;
  will-change: transform;
  z-index: 2;
}
.lv-dial-item {
  position: absolute; inset: 0; margin: 0;
  border-radius: 16px; overflow: hidden;
  border: 1px solid var(--lv-border);
  background: var(--lv-bg);
  box-shadow: 0 40px 90px -36px rgba(0,0,0,0.95);
  transform-origin: 50% 50%;
  will-change: transform, opacity;
  backface-visibility: hidden;
}
.lv-dial-item img,
.lv-dial-item video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.lv-dial-item video { z-index: 1; opacity: 0; transition: opacity .45s ease; }
/* The clip only fades up once its stop is at the front. Off to the side it is
   a thumbnail nobody is reading, and the still is enough. */
.lv-dial-item.is-front video { opacity: 1; }

.lv-dial-item figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 3rem 1.1rem 1rem;
  display: grid; gap: 0.2rem;
  font: 500 0.68rem/1.3 ui-monospace, monospace;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--lv-ink-muted);
  background: linear-gradient(to top, rgba(5,7,10,0.9), transparent);
  opacity: 0; transition: opacity .4s ease;
}
.lv-dial-item.is-front figcaption { opacity: 1; }
.lv-dial-item figcaption b {
  color: var(--lv-ink); font-weight: 600; letter-spacing: 0.18em;
}

@media (max-width: 880px) {
  .lv-madehere-track { height: 340vh; }
  .lv-madehere-stage { grid-template-columns: 1fr; align-content: start;
                       padding-top: clamp(3.5rem, 10vh, 6rem); }
  .lv-madehere-copy { grid-column: 1; }
  .lv-dial { width: 88vw; }
}

/* ── reduced motion, and no JavaScript ────────────────────────────────────
   Both get the four stops as a plain stacked list: no pin, no arc, no clips.
   The section is complete and legible with nothing running, which is the test
   that matters — a decorative layer must never be able to hide content. */
.lv-madehere-stage:not(.is-docking) { --dock: 1; }
.lv-madehere-stage:not(.is-docking) .lv-dial { position: static; width: auto;
  aspect-ratio: auto; display: grid; gap: 1rem; transform: none; }
.lv-madehere-stage:not(.is-docking) .lv-dial-item { position: static;
  aspect-ratio: 16 / 10; transform: none; opacity: 1; }
.lv-madehere-stage:not(.is-docking) .lv-dial-item figcaption,
.lv-madehere-stage:not(.is-docking) .lv-dial-item video { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .lv-madehere-track { height: auto; }
  .lv-madehere-stage { position: static; height: auto; overflow: visible;
    --dock: 1; grid-template-columns: 1fr; padding-top: 4rem; padding-bottom: 4rem; }
  .lv-dial { position: static; width: auto; aspect-ratio: auto;
    display: grid; gap: 1rem; transform: none !important; margin-top: 2.5rem; }
  .lv-dial-item { position: static; aspect-ratio: 16 / 10;
    transform: none !important; opacity: 1 !important; }
  .lv-dial-item video { display: none; }
  .lv-dial-item figcaption { opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE LUXVISION PHILOSOPHY

   Added 14 Sept 2026, directly under "Precision in Every Pixel".

   ⚠️ IMAGE LEFT, COPY RIGHT — the mirror of the manufacturing section below,
   which runs copy-left. Two consecutive sections with the copy on the same
   side read as one long column with pictures beside it. Alternating is what
   makes them two sections rather than one.
   ═══════════════════════════════════════════════════════════════════════════ */
.lv-philosophy-grid {
  display: grid;
  grid-template-columns: 1.04fr 0.96fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

/* ⚠️ NO FRAME, NO RADIUS, NO SHADOW — AND THAT IS THE WHOLE POINT.

   The photograph's own edges are graded to #0b0b10, the page's background, so
   it dissolves into the section instead of sitting in a box on top of it. A
   border-radius or a card behind it would draw the hard edge back in and undo
   the grade, which is the one treatment decision Joel made himself. */
/* ⚠️ position + z-index, and NO background.

   `.lv-hero` is position:fixed at z-index 5. A static section cannot sit above
   a positioned one, so without this the whole section paints UNDER the ring —
   invisible until the hero fades, and in the wrong stacking order the entire
   time. Every other landing section does the same thing (.lv-brand-statement,
   .lv-warranty); this one was added without it.

   ⛔ The background stays absent on purpose: the photograph's edges are graded
   to the page's own #0b0b10 and a background here would put a hard rectangle
   back around it. A check in _DEV/test-console.js fails if one appears. */
.lv-philosophy { position: relative; z-index: 10; }

.lv-philosophy-shot { margin: 0; }
.lv-philosophy-shot img {
  display: block;
  width: 100%;
  height: auto;
  /* The fade already darkens the rim; this only stops a hairline seam where
     the JPEG's outermost pixel row meets the section on a non-sRGB display. */
  background: var(--lv-bg);
}

/* Reading measure is set per-paragraph in the markup (max-width in ch, as the
   manufacturing section does) so the two blocks stay visibly related. */
.lv-philosophy-copy { max-width: 46ch; }

@media (max-width: 900px) {
  /* ⚠️ COPY FIRST ON A PHONE. The grid puts the picture first in source order
     because that is the desktop reading order, but on a narrow screen a
     full-width photograph above the heading pushes the argument below the
     fold — the visitor scrolls past a group shot to find out what section
     they are in. `order` moves the copy up without touching the markup. */
  .lv-philosophy-grid { grid-template-columns: 1fr; gap: 2rem; }
  .lv-philosophy-copy { order: -1; max-width: none; }
  .lv-philosophy-copy p { max-width: 54ch !important; }
}


/* ⚠️ FIVE PARAGRAPHS IN A PINNED 100vh STAGE IS AT THE LIMIT, and the
   local-economy paragraph added on 14 Sept is what took it there. On a 900px
   viewport the copy ran within 40px of the bottom; anything shorter and
   `overflow: hidden` silently clips the last line — no error, no scrollbar,
   just a sentence that ends early.

   So the type tightens on short viewports rather than the copy being cut. If a
   sixth paragraph ever goes in, this stops being enough and the section needs
   to stop being pinned. */
@media (max-height: 920px) {
  .lv-madehere-copy .lv-body-lg { font-size: 0.95rem; line-height: 1.5; }
  .lv-madehere-copy .lv-body-lg + .lv-body-lg { margin-top: 0.7rem !important; }
  .lv-madehere-copy .lv-h2 { font-size: clamp(1.7rem, 3.4vw, 2.4rem); }
}
@media (max-height: 780px) {
  .lv-madehere-copy .lv-body-lg { font-size: 0.88rem; line-height: 1.45; }
  .lv-madehere-copy .lv-body-lg + .lv-body-lg { margin-top: 0.55rem !important; }
}

/* The plate caption. Quiet enough that it reads as a credit rather than as
   copy — it is naming a photograph, not making an argument, and the four
   paragraphs beside it are the argument. */
.lv-philosophy-shot figcaption {
  margin-top: 0.9rem;
  text-align: center;
  font-family: var(--lv-font-body);
  font-size: 0.72rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--lv-ink-faint);
}

/* The second frame of a crossfading dial stop, stacked exactly on the first.
   ⚠️ No transition. Its opacity is set every frame from the scroll position, so
   a CSS transition would add a second, slower animation chasing the first and
   the dissolve would lag the wheel it is supposed to be locked to. */
/* 🔴 THIS BLOCK USED TO OPEN WITH
          and it made the whole stop invisible. Joel: "the NEMA images aren't visible
   on the landing page I can see the spot where they should sit but they are
   invisible."

   `.lv-dial-item` is ALREADY `position: absolute; inset: 0` — that is how every
   stop is placed on the arc. Overriding it to relative pulled this one out of
   that layout, and since all of its children are absolute it collapsed to zero
   height and drew nothing. The empty space Joel could see was the stop's slot
   on the wheel, still being transformed, with nothing left in it.

   ⚠️ The override was never needed. An absolutely positioned parent is already
   a containing block for absolute children. I wrote rules for this component
   without reading the rules it already had, and every line below that is not
   `opacity` was doing the same: `.lv-dial-item img` sets position, inset, size
   and object-fit for both frames already. What is genuinely new here is one
   property. */
.lv-dial-item .lv-dial-fade { opacity: 0; pointer-events: none; }
/* Reduced motion gets the stops as a plain stacked list and nothing animates,
   so the second frame would sit on top of the first at whatever opacity the
   script last wrote. It is simply not shown. */
@media (prefers-reduced-motion: reduce) {
  .lv-dial-item .lv-dial-fade { display: none; }
}

/* The warranty sub-line. Sits under the headline, lighter and smaller, so the
   two read as one thought in two beats rather than as two headlines competing.

   ⚠️ It is a SEPARATE element from the h2 on purpose. `lv-split-reveal` rebuilds
   whatever it is on from textContent, so a second line inside the h2 would be
   flattened into the first the moment the animation ran. */
.lv-warranty-sub {
  margin: 0.55rem 0 0;
  max-width: 40ch;      /* breaks after "repair,", which is the right place */
  font-family: var(--lv-font-display);
  font-weight: 500;
  font-size: clamp(1.02rem, 1.8vw, 1.35rem);
  line-height: 1.3;
  color: var(--lv-ink-muted);
}

/* The location stamp, now UNDER the manufacturing headline rather than above
   it. A dateline: it says where, not what, so it belongs after the statement
   it qualifies rather than in the chapter position.

   ⚠️ Deliberately NOT cornflower. The section label above it is, and two
   accent-coloured lines either side of a headline would fight each other and
   neither would lead. Same reasoning as the two lilac lines on the brand
   statement, recorded there in 2026. */
.lv-stamp {
  display: block;
  margin-top: 0.85rem;
  max-width: 40ch;
  font-family: var(--lv-font-body);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--lv-ink-faint);
}

/* ── THE CLAUSE AND THE FOOTAGE THAT PROVES IT ─────────────────────────────
   Copy left, loop right. The film is square because it was cut for LinkedIn,
   and a square sitting beside a column of text is a better shape than a wide
   crop that would have thrown away the top and bottom of every kick. */
.lv-warranty-clause {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}
.lv-clause-film { margin: 0; }
.lv-clause-film video {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 16px;
  border: 1px solid var(--lv-border);
  background: var(--lv-bg);
}
.lv-clause-film figcaption {
  margin-top: 0.7rem;
  text-align: center;
  font-family: var(--lv-font-body);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  color: var(--lv-ink-faint);
}
/* Joel, 15 September 2026: "We should Add ** Chair impacts not covered under
   warranty."

   ⚠️ IT IS SET AS A JOKE, NOT AS A DISCLAIMER, because that is what it is. In
   the caption's own 0.13em uppercase it would read as a real exclusion sitting
   directly under a warranty claim, which is the opposite of funny and the kind
   of thing a customer screenshots. Lighter, sentence case, and clearly a second
   voice: an aside about the chair in the video, not a term of the Agreement.

   ⚠️ An explicit font-size, not `small`'s default. `small` computes to 0.8em of
   0.68rem, which is 0.54rem — below the point where the letterspacing above it
   stops being legible on a laptop. */
.lv-clause-film figcaption small {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  opacity: 0.68;
}
@media (max-width: 900px) {
  /* ⚠️ COPY FIRST. The clause is the point; the film is the evidence for it,
     and evidence arriving before the claim is just a video. */
  .lv-warranty-clause { grid-template-columns: 1fr; gap: 1.75rem; }
  .lv-clause-film { order: 2; }
  .lv-clause-copy { order: 1; }
}
