/* ==========================================================================
   QuietQuality — motion.css
   Presentation layer for the scroll-driven motion engine (motion.js).
   Dependency-free. Reads brand tokens from :root defined in site.css.
   Every effect degrades to a static, safe state under prefers-reduced-motion
   and under body[data-motion="calm"].
   ========================================================================== */

/* --- Enable position:sticky inside .page --------------------------------
   site.css sets `.page { overflow-x: hidden }`, which forces overflow-y to
   compute to `auto` and turns .page into a scroll container — that silently
   breaks position:sticky for descendants (the runner and zoom scenes rely on
   it). `overflow-x: clip` prevents the same horizontal overflow WITHOUT
   establishing a scroll container, so sticky keeps working. */
.page {
  overflow-x: clip;
}

/* --- Split headings (line-mask reveal) ---------------------------------- */
.qq-line {
  display: block;
  overflow: hidden;
}

.qq-line-inner {
  display: block;
  transform: translateY(110%);
  transition: transform 0.95s cubic-bezier(0.19, 0.9, 0.22, 1);
}

.qq-line.is-in .qq-line-inner {
  transform: translateY(0);
}

/* --- Magnetic buttons ---------------------------------------------------- */
.qq-magnetic {
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* --- Scene will-change (added only while a scene is active) -------------- */
.qq-active {
  will-change: transform;
}

/* --- Marquee ------------------------------------------------------------- */
.qq-marquee {
  display: flex;
  width: 100%;
  overflow: hidden;
}

.qq-marquee-track {
  display: flex;
  flex: 0 0 auto;
  width: max-content;
  will-change: transform;
  animation: qq-marquee-move var(--qq-marquee-dur, 28s) linear infinite;
}

.qq-marquee[data-reverse] .qq-marquee-track {
  animation-direction: reverse;
}

.qq-marquee:hover .qq-marquee-track {
  animation-play-state: paused;
}

@keyframes qq-marquee-move {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

/* --- Panel (rounded panel resolving its corners on entry) --------------- */
[data-panel] {
  will-change: transform, border-radius;
}

/* --- Sticky runner ------------------------------------------------------- */
[data-runner] {
  position: relative;
}

/* --- Video scenes -------------------------------------------------------- */
[data-video-scene] {
  position: relative;
  overflow: hidden;
}

[data-video-scene] video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

[data-video-scene="zoom"] video {
  transform-origin: center center;
  will-change: transform, opacity;
}

.qq-video-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.7s ease;
  pointer-events: none;
}

[data-video-scene].is-full .qq-video-overlay {
  opacity: 1;
}

/* --- HUD layer (auto-injected) ------------------------------------------ */
.qq-hud {
  position: fixed;
  inset: 0;
  z-index: 120;
  pointer-events: none;
}

.qq-hud-progress {
  position: absolute;
  top: 12vh;
  bottom: 12vh;
  right: 18px;
  width: 1px;
  background: var(--hairline, #d9d1c3);
  overflow: hidden;
}

.qq-hud-progress-fill {
  position: absolute;
  inset: 0 0 auto 0;
  height: 100%;
  background: var(--metal, #c6b58b);
  transform: scaleY(0);
  transform-origin: top center;
}

/* Top-right, just under the fixed 76px header. Right-aligned two-line readout
   that clears the header nav / CTA and the gold progress line (right: 18px). */
.qq-hud-meta {
  position: absolute;
  top: 90px;
  right: 28px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  /* Paper chip: keeps the fixed readout legible when it passes over the black
     media frames / final-cta (HUD no longer uses mix-blend). */
  padding: 5px 9px;
  background: rgba(255, 253, 248, 0.85);
  border: 1px solid var(--hairline, #d9d1c3);
  font-family: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace;
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-align: right;
  color: var(--qq-olive-600, #667057);
  text-transform: uppercase;
}

/* --- Custom cursor (auto-injected on fine pointers) --------------------- */
.qq-has-cursor {
  cursor: none;
}

.qq-has-cursor a,
.qq-has-cursor button,
.qq-has-cursor [data-magnetic] {
  cursor: none;
}

.qq-has-cursor input,
.qq-has-cursor textarea,
.qq-has-cursor select,
.qq-has-cursor [contenteditable="true"] {
  cursor: auto;
}

.qq-cursor-dot,
.qq-cursor-ring {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  pointer-events: none;
  border-radius: 999px;
}

.qq-cursor-dot {
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--qq-ink-900, #151716);
}

.qq-cursor-ring {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid var(--qq-olive-600, #667057);
  font-family: ui-monospace, "SFMono-Regular", "Menlo", monospace;
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--qq-olive-600, #667057);
  transition:
    width 0.25s ease,
    height 0.25s ease,
    margin 0.25s ease,
    opacity 0.25s ease,
    background-color 0.25s ease;
}

.qq-cursor-ring.is-active {
  width: 64px;
  height: 64px;
  margin: -32px 0 0 -32px;
  background: rgba(66, 74, 58, 0.08);
}

.qq-cursor-hidden .qq-cursor-dot,
.qq-cursor-hidden .qq-cursor-ring {
  opacity: 0;
}

@media (max-width: 620px) {
  /* Keep the readout, tucked below the 66px mobile header so it never overlaps
     the hamburger toggle. */
  .qq-hud-meta {
    top: 74px;
    right: 16px;
    font-size: 10px;
  }
}

/* --- Reduced motion: neutralise every autonomous animation -------------- */
@media (prefers-reduced-motion: reduce) {
  .qq-line-inner {
    transform: translateY(0);
    transition: none;
  }

  .qq-magnetic {
    transition: none;
  }

  .qq-marquee-track {
    animation: none;
  }

  .qq-cursor-dot,
  .qq-cursor-ring {
    display: none;
  }
}

/* ==========================================================================
   ===== INDEX SCENES =====
   Flagship home-page scenes composed on top of the shared engine. These read
   the engine's runner progress (--p), video-scene .is-full and split .qq-line
   hooks. Everything degrades to a static, legible state under reduced motion
   (the --p-driven "fade out on scroll" effects are gated behind
   prefers-reduced-motion: no-preference so the pinned state stays visible).
   ========================================================================== */

/* --- Shared: keep reveal from transforming a sticky ancestor ------------
   .section-pad is auto-revealed (translateY), which would create a containing
   block and disturb the sticky children inside runner scenes. Sections that
   host a sticky stage opt out of the transform but keep their place. */
.qq-has-sticky.reveal,
.qq-has-sticky.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* --- HERO: pinned stage (>=1081px) ------------------------------------
   The hero content is pinned to one screen (fold containment) while the runner
   drives --p, so the heading disperses in place and hands directly to the
   marquee — there is no empty canvas tail to scroll past. The canvas lives
   inside the pinned stage so it stays put while the copy lifts away. */
.home-hero {
  overflow: clip; /* clip (not hidden) keeps the sticky stage pinning */
}

.qq-hero-stage {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: center;
  /* Top pad ≈ bottom pad + header(76px) so the flex-centred content reads as
     vertically centred in the area *below* the fixed header — no bottom blank. */
  padding: clamp(92px, 11vh, 116px) 0 clamp(20px, 3.5vh, 44px);
  overflow: hidden;
}

/* Paper hero (v3): the canvas now draws faint ink/olive lines on paper and the
   copy is ink, so the legibility wash is a soft paper veil (not a dark one) that
   keeps the left column crisp over the line-field. */
.qq-hero-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(244, 240, 231, 0.72) 0%, rgba(244, 240, 231, 0.34) 48%, rgba(244, 240, 231, 0) 100%);
}

/* Fold-fit: drop the authored 920px min-height + 122px padding and tighten the
   vertical rhythm with viewport-scaled gaps so it fits shorter screens too. */
.home-hero .hero-inner {
  min-height: 0;
  padding-top: 0;
  padding-bottom: 0;
}
.home-hero .eyebrow {
  margin-bottom: clamp(16px, 2.2vh, 30px);
}
.home-hero .hero-copy {
  margin-top: clamp(16px, 2.6vh, 34px);
}
.home-hero .hero-actions {
  margin-top: clamp(20px, 3vh, 40px);
}
.home-hero .hero-stats {
  margin-top: clamp(22px, 3.4vh, 52px);
}

/* Stat cards: one line each (incl. the wide "3〜6ヶ月") so all three are the same
   height at every viewport. */
.home-hero .stat {
  min-height: 0;
  padding: clamp(14px, 2vh, 22px) 16px;
}
.home-hero .stat strong {
  white-space: nowrap;
  font-size: clamp(26px, 2.9vw, 40px);
}

/* FOUR PILLARS panel: fit its own content (no stretched dead space, no rows
   over-spread on tall screens) and centre it so the panel's vertical midpoint
   lines up with the left column's. The kicker's big dead gap is gone; the four
   rows keep a natural, mildly viewport-scaled gap. */
.home-hero .hero-panel {
  align-self: center;
  min-height: 0;
  height: auto;
  display: flex;
  flex-direction: column;
  padding: clamp(26px, 3vh, 34px);
}
.home-hero .panel-kicker {
  margin-bottom: clamp(20px, 2.6vh, 34px);
}
.home-hero .layer-stack {
  gap: clamp(14px, 1.8vh, 28px);
}

/* --- HERO v3: portrait + FOUR PILLARS "document" + acid badge (DM cover) ----
   The right visual column is align-self:stretch, so it mirrors the (already
   fold-tuned) left column's height. The portrait fills that height and the
   overlays — FOUR PILLARS document card, acid circle badge, vertical-rl label —
   are absolutely placed inside it, so the fold stays governed by the left
   column and the portrait never pushes content below the first screen. */
.home-hero .hero-visual {
  position: relative;
  align-self: stretch;
  display: flex;
  min-height: clamp(340px, 50vh, 640px);
  padding-right: clamp(20px, 2.2vw, 40px);
}

/* Portrait frame: paper-200 ground, sand hairline, metal 1px inner frame; angle
   0 (radius 0). The <img> swap point fills the same box (object-fit:cover). */
.hero-portrait {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  background: var(--qq-paper-200);
  border: 1px solid var(--qq-sand-300);
  box-shadow: var(--shadow-soft);
}

.hero-portrait-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* (v3.2) Bias the crop toward the top so the model's face is never cut when
     the frame is shorter than the portrait (most visible at 390×844). On
     desktop, where the crop is horizontal, the vertical value is a no-op. */
  object-position: 50% 12%;
}

.hero-portrait::after {
  content: "";
  position: absolute;
  inset: 12px;
  z-index: 2;
  border: 1px solid var(--metal-line);
  pointer-events: none;
}

.hero-portrait-ph {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 20px;
  text-align: center;
  background:
    repeating-linear-gradient(-45deg, rgba(102, 112, 87, 0.05) 0 14px, transparent 14px 28px),
    var(--qq-paper-200);
}

.hero-portrait-ph-label {
  font-family: var(--font-label);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  color: var(--qq-olive-600);
}

.hero-portrait-ph-note {
  max-width: 100%;
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--qq-olive-300);
  word-break: break-all;
}

.hero-portrait-tag {
  position: absolute;
  top: 18px;
  left: 18px;
  z-index: 3;
  margin: 0;
  font-family: var(--font-label);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--metal);
}

/* Vertical-rl short serif label on the paper gutter beside the photo (DM 縦組み). */
.hero-vertical {
  position: absolute;
  top: clamp(16px, 5vh, 62px);
  right: 0;
  z-index: 3;
  margin: 0;
  writing-mode: vertical-rl;
  font-family: var(--font-serif);
  font-size: clamp(13px, 1.2vw, 17px);
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.16em;
  color: var(--qq-olive-800);
}

/* FOUR PILLARS as an overlapping paper "document" card on the portrait's lower
   band (the DM's held acrylic schematics). Solid paper-0 so it reads over any
   future photo. */
.home-hero .hero-visual .hero-panel {
  position: absolute;
  left: clamp(0px, 0.6vw, 8px);
  right: clamp(24px, 3vw, 48px);
  bottom: clamp(12px, 2.6vh, 30px);
  align-self: auto;
  display: block;
  min-height: 0;
  height: auto;
  padding: clamp(15px, 1.9vh, 22px) clamp(15px, 1.5vw, 22px);
  /* (v3.4) Genuinely translucent paper so the portrait's silhouette reads
     clearly THROUGH the card. Lowered from 0.8 (which composited with the inner
     rows to an effective ~0.92 opaque) to 0.52, blur softened to 6px. */
  background: rgba(255, 253, 248, 0.52);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid var(--qq-sand-300);
  box-shadow: var(--shadow-float);
  z-index: 2;
}

.home-hero .hero-visual .hero-panel::before {
  inset: 8px;
}

/* DM acid line across the "documents" (short tick at the card's top edge). */
.home-hero .hero-visual .hero-panel::after {
  content: "";
  position: absolute;
  top: 0;
  left: clamp(15px, 1.5vw, 22px);
  width: clamp(46px, 22%, 92px);
  height: 3px;
  background: var(--acid);
}

.home-hero .hero-visual .panel-kicker {
  margin: 0 0 clamp(9px, 1.3vh, 15px);
}

.home-hero .hero-visual .layer-stack {
  gap: clamp(6px, 0.9vh, 11px);
}

.home-hero .hero-visual .layer,
.home-hero .hero-visual .layer:nth-child(2),
.home-hero .hero-visual .layer:nth-child(3) {
  transform: none;
  min-height: 0;
  padding: clamp(7px, 1vh, 11px) 13px;
}

/* (v3.4) Inner rows kept clearly translucent (dropped from ~0.6) so the panel +
   row stack no longer composites toward opaque — the model's silhouette stays
   visible under the text. Labels are darkened (olive-800 / ink-900) to hold
   legibility over the lighter card. */
.home-hero .hero-visual .layer {
  background: rgba(244, 240, 231, 0.32);
}
.home-hero .hero-visual .layer:nth-child(2) {
  background: rgba(233, 227, 216, 0.38);
}
.home-hero .hero-visual .layer:nth-child(3) {
  background: rgba(244, 240, 231, 0.32);
}

.home-hero .hero-visual .layer b {
  font-size: 10px;
  line-height: 1.35;
  letter-spacing: 0.09em;
  color: var(--qq-olive-800);
}

.home-hero .hero-visual .layer span {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.42;
  color: var(--qq-ink-900);
  font-weight: 700;
}

/* (v3.1) The acid circle badge ("DM限定 / 45分無料招待") was a DM-only campaign
   offer and is not shown on the public site — its hero markup and styles are
   removed. */

/* Phone/tablet: the visual stacks under the copy — portrait gets an explicit
   height, the document card flows below it, and the vertical gutter label is
   dropped. */
@media (max-width: 1080px) {
  .home-hero .hero-visual {
    align-self: auto;
    display: block;
    min-height: 0;
    padding-right: 0;
    margin-top: clamp(28px, 6vw, 44px);
  }
  .hero-portrait {
    /* (v3.2) Taller mobile frame so the face + part of the held plans read. */
    height: clamp(360px, 90vw, 480px);
  }
  .home-hero .hero-visual .hero-panel {
    position: static;
    inset: auto;
    margin-top: 16px;
  }
  .hero-vertical {
    display: none;
  }
}

/* On tablet/phone the FOUR PILLARS panel stacks under the copy, so the hero is
   taller than one screen: fall back to a natural (unpinned) hero whose runner
   is never taller than its content (no tail), keeping the --p dispersal. */
@media (max-width: 1080px) {
  .home-hero {
    overflow: hidden;
  }
  .home-hero[data-runner] {
    min-height: 100vh !important;
  }
  .qq-hero-stage {
    position: static;
    z-index: auto;
    height: auto;
    display: block;
    padding: 0;
    overflow: visible;
  }
  .home-hero .hero-inner {
    padding: 126px 0 64px;
  }
}

/* Fold-fit for short viewports (the user's ~1312×820 laptop): compress the
   heading and gaps so the centred content — stats and the FOUR PILLARS panel —
   still fits one screen. Content stays vertically centred (no top-align, no
   bottom blank). Desktop pinned hero only (>=1081px). */
@media (min-width: 1081px) and (max-height: 940px) {
  .home-hero h1 {
    font-size: clamp(46px, 7.2vh, 92px);
    line-height: 1.06;
  }
  .home-hero .hero-copy {
    font-size: clamp(15px, 2.4vh, 21px);
    line-height: 1.75;
    margin-top: clamp(16px, 2.8vh, 34px);
  }
  .home-hero .eyebrow {
    margin-bottom: clamp(14px, 2.4vh, 30px);
  }
  .home-hero .hero-actions {
    margin-top: clamp(20px, 3.2vh, 44px);
  }
  .home-hero .hero-stats {
    margin-top: clamp(24px, 4vh, 62px);
  }
}

/* Tall viewports (≥1000px high, e.g. 2000×1358): open up the vertical rhythm and
   let the panel grow so the centred content fills the height — the black band
   below the stats stays within ~15% of the viewport. Below 1000px the 900/982
   balance and the ≤940 fold-fit are untouched. */
@media (min-width: 1081px) and (min-height: 1000px) {
  .home-hero .eyebrow {
    margin-bottom: clamp(28px, 3.6vh, 60px);
  }
  .home-hero .hero-copy {
    margin-top: clamp(30px, 4vh, 66px);
  }
  .home-hero .hero-actions {
    margin-top: clamp(34px, 4.8vh, 82px);
  }
  .home-hero .hero-stats {
    margin-top: clamp(40px, 5.8vh, 112px);
  }
  .home-hero .layer-stack {
    gap: clamp(24px, 3.4vh, 52px);
  }
}

/* --- HERO: content holds through the scroll-away (no early dispersal) -------
   v3.2 root-cause fix: the heading / copy / stats stay fully visible while the
   pinned stage scrolls away. Previously a --d-driven opacity+dispersal emptied
   the hero (opacity→0, lines flung up) within the short pin window, then the
   stage still had ~100vh of travel before the marquee arrived — so most of the
   screen was a text-less line-field canvas. Now the content never fades; the
   marquee physically rises to cover it, and every frame shows hero text OR the
   marquee. Only a light upward settle remains on the heading lines. --d retired.
   Gated to no-preference so reduced motion keeps the hero static. */
@media (prefers-reduced-motion: no-preference) {
  .home-hero h1 .qq-line {
    will-change: transform;
    transform: translateY(calc(var(--p, 0) * -8px));
  }
  .home-hero h1 .qq-line:nth-child(2) {
    transform: translateY(calc(var(--p, 0) * -12px));
  }
  .home-hero h1 .qq-line:nth-child(3) {
    transform: translateY(calc(var(--p, 0) * -16px));
  }
  .home-hero h1 .qq-line:nth-child(4) {
    transform: translateY(calc(var(--p, 0) * -20px));
  }
  /* Scroll cue: lit at rest, fades out as soon as the hero starts moving. */
  .home-hero .scroll-note {
    opacity: clamp(0, (0.72 - var(--p, 0)) / 0.16, 1);
    animation: qq-scroll-bob 1.7s ease-in-out infinite;
  }
}

/* Laid out horizontally (arrow stacked over the word) rather than as the base
   vertical label, so the "↓" reliably points down instead of being rotated by
   the vertical writing mode. Applies in every motion mode; the --p fade and bob
   above are gated to no-preference. */
.home-hero .scroll-note {
  bottom: 13vh;
  writing-mode: horizontal-tb;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  z-index: 3;
  color: var(--qq-olive-600, #667057);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-indent: 0.24em;
}

.home-hero .scroll-note .scroll-arrow {
  font-size: 16px;
  line-height: 1;
  letter-spacing: 0;
  text-indent: 0;
}

@keyframes qq-scroll-bob {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(7px);
  }
}

/* --- Marquee band (gold outline lettering) ------------------------------ */
.qq-index-marquee {
  align-items: center;
  padding: clamp(16px, 3vw, 30px) 0;
  background: var(--qq-paper-100, #f4f0e7);
  border-top: 1px solid var(--hairline, #d9d1c3);
  border-bottom: 1px solid var(--hairline, #d9d1c3);
}

.qq-index-marquee span {
  display: inline-block;
  padding: 0 0.5em;
  font-family: var(--font-editorial, "Cormorant Garamond", Georgia, serif);
  font-size: clamp(30px, 6vw, 74px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: transparent;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 1px var(--qq-sand-300, #d9d1c3);
}

.qq-index-marquee .qq-marquee-sep {
  color: var(--qq-metal-400, #c6b58b);
  -webkit-text-fill-color: var(--qq-metal-400, #c6b58b);
  -webkit-text-stroke-width: 0;
}

/* Index CTA labels never wrap mid-phrase (they flex-wrap to a new line whole if
   space runs out). Scoped to index-only sections. */
.home-hero .button,
[data-hud-label="CONSULT"] .hero-actions .button,
.qq-final .button {
  white-space: nowrap;
}

/* --- Video cinematic scenes (differentiated: uncover / letterbox) --------
   The clip plays full-bleed the whole time; there is never a hidden/blank
   phase. initCine (motion.js) locks the frame to the viewport top during entry,
   so the previous section (.qq-cover-above) slides up and reveals it. Scene 1
   (uncover) shows the full frame; scene 2 (letterbox) reveals a 32vh centre band
   that opens to full. Copy rises on --p. Reduced motion / no-JS: full & static. */
.qq-cine {
  position: relative;
  z-index: 0; /* sit below .qq-cover-above so the previous section reveals it */
  background: var(--black);
}

.qq-cine-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: visible; /* the frame is lifted above this box during entry */
}

.qq-cine-frame {
  position: absolute;
  inset: 0;
  overflow: hidden; /* clips the (scaled/letterboxed) video to the frame */
  will-change: transform;
}

.qq-cine-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The previous section is lifted above the cine frame so that, as it scrolls
   off, it uncovers the fixed video underneath (parallax reveal). */
.qq-cover-above {
  position: relative;
  z-index: 1;
}

/* §9 額縁: a metal 1px inner frame + a Helvetica FOOTAGE label so each black clip
   reads as a DM "photo block". The frame rides the sticky (viewport-pinned) box,
   above the parallax-translated video frame and below the copy. */
.qq-cine-sticky::before {
  content: "";
  position: absolute;
  inset: clamp(14px, 2.6vw, 32px);
  z-index: 3;
  border: 1px solid var(--metal-line);
  pointer-events: none;
}

/* Bottom-left so it clears the fixed header (the pinned cine's top rides under
   it) and the centred copy. */
.qq-cine-tag {
  position: absolute;
  bottom: clamp(22px, 3.6vw, 46px);
  left: clamp(22px, 3.6vw, 46px);
  z-index: 3;
  font-family: var(--font-label);
  font-size: clamp(9px, 1vw, 11px);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--metal);
}

.qq-cine-copy {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 var(--gutter);
  text-align: center;
  pointer-events: none;
}

.qq-cine-copy::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(circle at center, rgba(5, 6, 7, 0.42), rgba(5, 6, 7, 0.72));
  opacity: clamp(0, (var(--p, 0) - 0.45) / 0.2, 1);
}

.qq-cine-lead {
  margin: 0;
  max-width: min(920px, 88vw);
  font-size: clamp(30px, 6.4vw, 82px);
  line-height: 1.16;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: var(--cream);
}

.qq-cine-sub {
  margin: clamp(14px, 2vw, 24px) 0 0;
  max-width: min(760px, 84vw);
  font-size: clamp(15px, 2.1vw, 22px);
  line-height: 1.7;
  font-weight: 700;
  color: var(--gold-soft);
}

.qq-cine-mask {
  display: block;
  overflow: hidden;
}

.qq-cine-mask > span {
  display: inline-block;
  transform: translateY(0);
}

@media (prefers-reduced-motion: no-preference) {
  /* Copy rises on --p; base (above) stays shown for reduced motion / no-JS.
     Uncover reveals its copy earlier (full frame from entry); letterbox waits
     until the band has essentially opened. */
  .qq-cine-uncover .qq-cine-lead .qq-cine-mask > span {
    transform: translateY(calc((1 - clamp(0, (var(--p, 0) - 0.3) / 0.24, 1)) * 118%));
  }
  .qq-cine-uncover .qq-cine-sub .qq-cine-mask > span {
    transform: translateY(calc((1 - clamp(0, (var(--p, 0) - 0.42) / 0.24, 1)) * 118%));
  }
  .qq-cine-letterbox .qq-cine-lead .qq-cine-mask > span {
    transform: translateY(calc((1 - clamp(0, (var(--p, 0) - 0.62) / 0.22, 1)) * 118%));
  }
  .qq-cine-letterbox .qq-cine-sub .qq-cine-mask > span {
    transform: translateY(calc((1 - clamp(0, (var(--p, 0) - 0.74) / 0.2, 1)) * 118%));
  }
}

/* --- CONCEPT: gold-lines loop behind the visual panel ------------------- */
.qq-concept-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}

.qq-concept-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.concept-visual::before,
.concept-visual::after {
  z-index: 2;
}

/* --- SERVICE: sticky horizontal track ----------------------------------- */
.qq-htrack-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(20px, 3vh, 40px);
  padding: clamp(92px, 12vh, 122px) 0 clamp(26px, 5vh, 46px);
  overflow: hidden;
}

.qq-htrack-head {
  flex: 0 0 auto;
}

.qq-htrack-head .split-head {
  margin-bottom: 0;
}

.qq-htrack-viewport {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.qq-htrack {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  gap: 16px;
  padding: 0 var(--gutter);
  will-change: transform;
}

.qq-htrack .service-card {
  flex: 0 0 auto;
  width: min(80vw, 420px);
  min-height: clamp(300px, 42vh, 380px);
}

.qq-htrack-dots {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  gap: 10px;
}

.qq-htrack-dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: rgba(66, 74, 58, 0.22);
  transition:
    background 0.3s ease,
    transform 0.3s ease;
}

.qq-htrack-dot.is-on {
  background: var(--qq-ink-900, #151716);
  transform: scale(1.3);
}

/* Static (reduced-motion) fallback: normal wrapping grid, no pin, no slide */
.qq-htrack-static .qq-htrack-stage {
  position: static;
  height: auto;
  display: block;
  padding: 0;
  overflow: visible;
}

.qq-htrack-static .qq-htrack-viewport {
  overflow: visible;
  margin-top: clamp(30px, 5vw, 48px);
}

.qq-htrack-static .qq-htrack {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  width: auto;
  padding: 0;
  transform: none;
}

.qq-htrack-static .qq-htrack .service-card {
  width: auto;
  min-height: auto;
}

.qq-htrack-static .qq-htrack-dots {
  display: none;
}

/* --- METHOD: 3-layer build with a drawing connector -------------------- */
.method-runner {
  position: relative;
}

/* (v3.3) Pin retired. The runner/sticky pinning left geometric dead space above
   and inside the box that no padding tweak could remove (3rd report), so the
   stage is now plain flow and the box fits its content. */
.method-sticky {
  position: static;
  height: auto;
  display: block;
  padding: 0;
}

/* (v3.3) Box height = its content + a calm inner padding; no viewport-height
   floor, so there are no flat bands top/bottom inside the frame. */
.method-diagram {
  width: 100%;
  min-height: 0;
  display: block;
  padding: clamp(32px, 3.4vw, 44px);
}

/* (v3.2) Tighten the METHOD section frame itself — smaller section padding and
   heading→box gap — on the index #method section and the method.html LAYERS
   section, so the section stops feeling stretched around the pinned box. */
#method.section-pad,
[data-hud-label="LAYERS"].section-pad {
  padding-block: clamp(52px, 6.5vw, 96px);
}

#method .split-head {
  margin-bottom: clamp(20px, 2.6vw, 32px);
}

.method-line {
  position: relative;
}

.method-connector {
  position: absolute;
  left: 24px;
  top: 6%;
  width: 4px;
  height: 88%;
  overflow: visible;
  pointer-events: none;
}

.method-connector path {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2;
  /* (v3.3) Static full line — the pin (and its --p draw) is gone; the connector
     is a plain vertical rule linking the three rows. */
  stroke-dasharray: none;
  stroke-dashoffset: 0;
}

/* (v3.3) The 3 rows now build with the shared IO reveal/stagger (data-stagger on
   .method-line) — each row fades/rises in top→down on scroll arrival, instead of
   being scrubbed by --p. Under reduced motion the base .reveal rule shows all
   three (opacity:1). No method-specific --p rules remain. */

/* --- MILESTONE: outlined giant phase numbers --------------------------- */
.qq-milestone .phase-number {
  color: transparent;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 2px var(--gold);
  font-size: clamp(70px, 11vw, 148px);
  line-height: 0.86;
  letter-spacing: -0.02em;
}

/* --- CASE: gentle image zoom on hover ---------------------------------- */
.qq-case-grid .case-card {
  overflow: hidden;
}

.qq-case-grid .case-image {
  transition: transform 0.7s cubic-bezier(0.19, 0.9, 0.22, 1);
}

.qq-case-grid .case-card:hover .case-image {
  transform: scale(1.06);
}

/* --- FINAL CTA: full-height, particles behind ------------------------- */
.qq-final {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
}

.qq-final-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.qq-final-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.5;
}

.qq-final-shade {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(circle at 78% 20%, rgba(198, 181, 139, 0.16), transparent 42%),
    linear-gradient(90deg, rgba(21, 23, 22, 0.94), rgba(21, 23, 22, 0.66));
}

.qq-final .cta-grid {
  position: relative;
  z-index: 2;
}

.qq-final h2 {
  font-size: clamp(40px, 7.2vw, 96px);
  line-height: 1.08;
}

/* --- Mobile: shorten runner scroll distance (effects preserved) --------
   (Hero is handled by the <=1080px block above: min-height:100vh, unpinned.) */
@media (max-width: 620px) {
  /* (v3.4) Mobile cine: the WHOLE section collapses to ~55svh — media and its
     black ground shrink together, with no full-height stage and no letterbox
     masks (the v3.3 100vh-stage + top/bottom black bands are removed). The
     runner's inline min-height (data-runner=170 → 170vh) is overridden here, so
     the scrub can never advance (runnerHeight − innerHeight ≤ 0 ⇒ --p pinned at
     0); every scrub-driven element is therefore forced to its static FINAL
     state below. The loop video still autoplays via its IntersectionObserver.
     Desktop (>620px) is completely unchanged. */
  .qq-cine[data-runner] {
    min-height: 55svh !important;
  }
  .qq-cine-sticky {
    position: static;
    height: 55svh;
  }
  /* Drop the v3.3 letterbox bars entirely — no black above/below the media. */
  .qq-cine-sticky::after {
    display: none;
  }
  /* Frame: no parallax viewport-lock, no letterbox clip — full-bleed inside the
     55svh box (overrides the JS inline transform / clip-path). */
  .qq-cine-frame {
    transform: none !important;
    clip-path: none !important;
  }
  .qq-cine-frame video {
    transform: none !important;
  }
  /* Copy: pin the line masks open and the legibility shade on, so the full copy
     reads over the still (but playing) video. */
  .qq-cine-mask > span {
    transform: none !important;
  }
  .qq-cine-copy::before {
    opacity: 1 !important;
  }
  .qq-cine-lead {
    font-size: clamp(26px, 8.2vw, 40px);
    line-height: 1.18;
  }
  .qq-cine-sub {
    margin-top: 10px;
    font-size: 14px;
    line-height: 1.62;
  }
  #service[data-runner] {
    min-height: 180vh !important;
  }
}

@media (max-width: 620px) {
  .qq-htrack-stage {
    justify-content: flex-start;
    gap: 18px;
    padding-top: 92px;
  }
  .qq-htrack .service-card {
    width: 78vw;
    min-height: auto;
  }
  .qq-index-marquee span {
    font-size: clamp(26px, 9vw, 44px);
  }

  /* Fold-fit: keep the three stats as a compact single row so their bottom sits
     within the first screen at 390×844, and tighten the copy/CTA rhythm. */
  .home-hero .hero-inner {
    padding: 108px 0 56px;
  }
  .home-hero .hero-copy {
    font-size: 15px;
    line-height: 1.7;
    margin-top: clamp(12px, 2vh, 22px);
  }
  .home-hero .hero-actions {
    margin-top: clamp(12px, 2vh, 22px);
  }
  .home-hero .hero-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: clamp(14px, 2.2vh, 26px);
  }
  .home-hero .stat {
    min-height: 0;
    padding: 12px 10px;
  }
  .home-hero .stat strong {
    font-size: clamp(19px, 5.6vw, 28px);
    white-space: nowrap;
  }
  .home-hero .stat span {
    margin-top: 6px;
    font-size: 10px;
    line-height: 1.4;
  }
}

/* --- Reduced motion: pin scene copy to its resolved, legible state ------ */
@media (prefers-reduced-motion: reduce) {
  .qq-case-grid .case-image {
    transition: none;
  }
  .qq-case-grid .case-card:hover .case-image {
    transform: none;
  }
}
