/* Section shell — transparent, sits on the global .site-bg canvas */
.assembly {
  position: relative;
  background: transparent;
  font-family: var(--font-body);
}

.assembly__track {
  position: relative;
  height: 340vh;
}

.assembly__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  align-items: center;
}

/* Mobile-only duplicate intro (see the HTML comment above it) — never
   shown on desktop/tablet-landscape, where the original in-stage copy
   below still carries this text. */
.assembly__intro-mobile {
  display: none;
}

@media (max-width: 1023px) {
  .assembly__track {
    height: 260vh;
  }

  .assembly__intro-mobile {
    display: block;
    padding: calc(var(--section-padding) * 1.4) var(--section-padding) 0;
  }

  .assembly__intro-mobile .assembly__title,
  .assembly__intro-mobile .assembly__subtitle {
    max-width: none;
  }

  .assembly__content-intro {
    display: none;
  }
}

@media (max-width: 599px) {
  .assembly__track {
    height: 230vh;
  }
}

/* Layout */
.assembly__container {
  position: relative;
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--section-padding);
  display: grid;
  grid-template-columns: .82fr 1.18fr;
  gap: 36px;
  align-items: center;
  z-index: 3;
}

@media (max-width: 1199px) {
  .assembly__container {
    gap: 20px;
  }
}

/* Sticky stage becomes a compact single column: readout on top (per
   the owner's mobile spec — current step first, scene underneath),
   pinned near the top of the safe zone rather than vertically centered
   in the full 100dvh stage (centering a short readout+scene block in
   a tall stage was the source of the "huge empty gap after the
   intro" complaint — the gap was real, just above the readout, not
   below it). Scene is flex:1 so it claims essentially all height the
   readout doesn't need, instead of a fixed short box floating in the
   middle of extra space. */
@media (max-width: 1023px) {
  .assembly__container {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 16px;
    height: 100%;
    padding: calc(var(--header-height) + 12px) var(--section-padding) 10px;
  }

  .assembly__content {
    order: 1;
    flex-shrink: 0;
  }

  .assembly__scene {
    order: 2;
    flex: 1;
    min-height: 0;
  }
}

/* Left column */
.assembly__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.08;
  letter-spacing: var(--ls-heading);
  margin: 22px 0 0;
  color: var(--color-text-primary-strong);
  max-width: 520px;
  text-wrap: balance;
}

.assembly__title span {
  color: var(--color-accent);
}

.assembly__subtitle {
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  line-height: 1.6;
  color: var(--color-text-muted);
  margin: 20px 0 0;
  max-width: 480px;
}

.assembly__panel {
  margin-top: 34px;
  padding-top: 26px;
  border-top: 1px solid var(--color-border-soft);
}

.assembly__panel-head {
  display: flex;
  align-items: baseline;
  gap: 15px;
}

.assembly__panel-code {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 34px;
  color: var(--color-accent);
  line-height: 1;
  min-width: 52px;
}

.assembly__panel-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
  color: var(--color-text-primary);
}

.assembly__panel-en {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--color-text-dim-3);
  margin-top: 4px;
}

.assembly__panel-desc {
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--color-text-dim-5);
  margin: 16px 0 0;
  min-height: 92px;
  max-width: 448px;
}

@media (max-width: 1023px) {
  /* Compact readout: this sits pinned near the top of the sticky stage
     for the whole scroll story, so it's sized to stay recognizably
     stable (per-frame text swaps, not a layout that jumps around) while
     leaving as much height as possible to the scene below it. */
  .assembly__panel {
    margin-top: 0;
    padding-top: 12px;
    text-align: center;
  }

  .assembly__panel-head {
    justify-content: center;
    gap: 10px;
  }

  .assembly__panel-code {
    font-size: 24px;
    min-width: 36px;
  }

  .assembly__panel-name {
    font-size: 15px;
  }

  .assembly__panel-en {
    font-size: 9px;
  }

  .assembly__panel-desc {
    min-height: 0;
    max-width: 420px;
    margin: 6px auto 0;
    font-size: 12.5px;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }

  .assembly__progress {
    justify-content: center;
    margin-top: 8px;
  }

  .assembly__final {
    max-width: 420px;
    margin: 10px auto 0;
    padding-top: 10px;
    font-size: 13px;
    text-align: center;
  }
}

.assembly__progress {
  display: flex;
  gap: 7px;
  margin-top: 6px;
}

.assembly__progress-dot {
  width: 26px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .14);
  transition: background .45s ease, box-shadow .45s ease;
}

.assembly__progress-dot.is-passed {
  background: rgba(200, 255, 46, .55);
}

.assembly__progress-dot.is-active {
  background: var(--color-accent);
  box-shadow: 0 0 12px rgba(200, 255, 46, .7);
}

.assembly__final {
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--color-text-primary);
  max-width: 448px;
  margin: 22px 0 0;
  padding-top: 22px;
  border-top: 1px solid var(--color-border-soft);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .6s ease, transform .6s var(--ease-rise);
}

.assembly__final.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Right column — 2.5D scene */
.assembly__scene {
  position: relative;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 1600px;
}

/* Below 1024px, .assembly__core's 580x620 layer stack (and its chips'
   translate3d coordinates, all computed in JS in that same coordinate
   space) is scaled down as one unit via the scene wrapper — JS only
   ever writes to .assembly__core's own transform (rotateX/rotateY per
   scroll frame), so the scale has to live one level up to avoid being
   clobbered every frame.

   The scene itself is flex:1 (see .assembly__container above) so it
   claims essentially all height the compact readout above doesn't
   need — these scale values are picked so the main/frontmost layer
   card (380px wide in the 580x620 core) reads at roughly 75-88% of a
   typical viewport width in each range, while staying tall enough to
   still fit within the stage's own overflow:hidden bounds on typical
   phone heights (checked visually, not just computed) — a little
   clipping at the scene's own edges is fine (same allowance as the
   Portfolio orbit), the page itself must never gain horizontal
   overflow, and .assembly__stage's overflow:hidden already guards
   that regardless. */
@media (max-width: 1023px) {
  /* The actual fix for the "huge gap between readout and scene"
     complaint: .assembly__scene's unconditional base rule above
     (align-items: center) floats the 3D core in the middle of
     whatever leftover height the flex:1 box (see .assembly__container
     mobile rule) ends up with — which, once the readout is short and
     pinned to the top, is most of the viewport, so centering means
     half of it sits above the visible cascade as pure padding.
     flex-start anchors the core's layout box to the scene's own top;
     transform-origin: top shrinks it toward that same top edge
     instead of its center, so scaling down doesn't reopen the gap it
     was just meant to close. This has to live here (after the
     unconditional rule, not in the earlier .assembly__container mobile
     block) for the same source-order reason documented across this
     file: later same-specificity rules win regardless of which one
     sits in a media query. */
  .assembly__scene {
    align-items: flex-start;
    transform: scale(.86);
    transform-origin: top center;
  }
}

@media (max-width: 767px) {
  .assembly__scene {
    transform: scale(.82);
  }
}

@media (max-width: 599px) {
  .assembly__scene {
    transform: scale(.78);
  }
}

@media (max-width: 389px) {
  .assembly__scene {
    transform: scale(.68);
  }
}

.assembly__core {
  position: relative;
  width: 580px;
  height: 620px;
  transform-style: preserve-3d;
  transform: rotateX(14deg) rotateY(-8deg);
}

/* This — not the scene's own align-items — turns out to be the real
   source of the "huge gap" complaint. Every .assembly__layer/.chip is
   anchored at `top: 50%` of THIS element's own height (620px), so even
   with the core's box now starting right under the readout (see
   .assembly__scene's flex-start above), the cascade's anchor point
   still sits a fixed 310px (620/2) down into it — on mobile that reads
   as dead space, because there's no matching content up there to make
   310px feel proportionate the way it does inside the desktop's full
   two-column layout. JS never touches this height (only
   core.style.transform, for rotateX/rotateY), so it's safe to change
   per breakpoint like everything else here — shrinking it moves every
   layer/chip's 50% anchor up in lockstep, without touching their
   individual translate3d offsets or JS at all. */
@media (max-width: 1023px) {
  .assembly__core {
    height: 260px;
  }
}

@media (max-width: 599px) {
  .assembly__core {
    height: 220px;
  }
}

@media (min-width: 1920px) {
  .assembly__scene {
    transform: scale(1.12);
  }
}

@media (min-width: 2560px) {
  .assembly__scene {
    transform: scale(1.35);
  }
}

.assembly__scan {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 500px;
  height: 2px;
  transform: translate(-50%, -50%);
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--color-accent), transparent);
  box-shadow: 0 0 22px 3px rgba(200, 255, 46, .6);
  z-index: 60;
  animation: lutScanGlow 1.4s ease-in-out infinite;
}

@keyframes lutScanGlow {
  0%, 100% { opacity: .6; }
  50% { opacity: 1; }
}

.assembly__layers {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.assembly__layer {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 380px;
  height: 150px;
  will-change: transform, opacity;
}

.assembly__layer-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, .035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .035) 1px, transparent 1px);
  background-size: 22px 22px;
  pointer-events: none;
}

.assembly__layer-head {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 15px 5px;
}

.assembly__layer-title {
  display: flex;
  align-items: center;
  gap: 9px;
}

.assembly__layer-code {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 11px;
  color: var(--color-accent);
  letter-spacing: .04em;
}

.assembly__layer-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13px;
  color: var(--color-text-primary);
}

.assembly__layer-en {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .14em;
  color: var(--color-text-dim-3);
}

.assembly__layer-body {
  position: relative;
  padding: 6px 15px 0;
}

/* Layer 01 — Market Scan: mini bar-chart + text lines */
.assembly__layer--scan .assembly__layer-body {
  display: flex;
  gap: 13px;
  align-items: flex-end;
  height: 78px;
}

.assembly__layer--scan .bar-chart {
  height: 52px;
}

.assembly__layer--scan .assembly__lines {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

/* Layer 02 — Meaning Layer: text lines + accent cta bar */
.assembly__layer--meaning .assembly__layer-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 8px;
}

/* Layer 03 — Conversion Route: structural blocks */
.assembly__layer--route .assembly__layer-body {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding-top: 8px;
}

.assembly__layer--route .route-block--header {
  height: 12px;
}

.assembly__layer--route .assembly__route-row {
  display: flex;
  gap: 7px;
  height: 33px;
}

.assembly__layer--route .assembly__route-row .route-block {
  flex: 1;
}

/* Layer 04 — Visual System: swatches + type sample + grid */
.assembly__layer--visual .assembly__layer-body {
  display: flex;
  align-items: center;
  gap: 13px;
  padding-top: 11px;
}

.assembly__swatches {
  display: flex;
  gap: 6px;
}

.assembly__swatch {
  width: 20px;
  height: 20px;
  border-radius: 5px;
}

.assembly__swatch--accent { background: var(--color-accent); }
.assembly__swatch--dark { background: #1c1e1a; border: 1px solid var(--color-border-strong); }
.assembly__swatch--light { background: #e6e6e0; }

.assembly__type-sample {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 20px;
  color: var(--color-text-primary);
}

.assembly__mini-grid {
  flex: 1;
  height: 36px;
  border-radius: 5px;
  background-image:
    linear-gradient(rgba(255, 255, 255, .1) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .1) 1px, transparent 1px);
  background-size: 11px 11px;
  border: 1px solid var(--color-border-soft);
}

/* Layer 05 — Motion Interface: cursor path + toggle */
.assembly__layer--motion .assembly__layer-body {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-top: 10px;
}

.assembly__cursor-path {
  position: relative;
  width: 70px;
  height: 42px;
}

.assembly__cursor-path .ui-bar {
  position: absolute;
  left: 0;
}

.assembly__cursor-arrow {
  position: absolute;
  right: 4px;
  bottom: 0;
  width: 0;
  height: 0;
  border-left: 8px solid var(--color-accent);
  border-bottom: 12px solid transparent;
  transform: rotate(-20deg);
}

/* Layer 06 — Launch Core: form fields + submit row */
.assembly__layer--launch .assembly__layer-body {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding-top: 7px;
}

.assembly__submit-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.assembly__submit-row .ui-bar {
  flex: 1;
  height: 20px;
  border-radius: 5px;
}

/* Chips */
.assembly__chip {
  left: 50%;
  top: 50%;
  z-index: 40;
  will-change: transform, opacity;
}

/* Completion state — a compact single-row status console, not a card.
   The "meaning" conclusion (headline + caption) already lives in the
   left .assembly__panel OK-block; this module's only job is to report
   SYSTEM STATUS, so it stays to one line and never repeats that text. */
.assembly__complete {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 258px, 0);
  opacity: 0;
  transition: opacity .6s ease, transform .6s var(--ease-rise);
  pointer-events: none;
  z-index: 80;
  width: 100%;
  max-width: 560px;
}

.assembly__complete.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 242px, 0);
}

/* Mobile: this module lives inside .assembly__core, which is what the
   scene-level transform:scale() above shrinks as one unit with
   everything else — left alone, its on-screen size would shrink right
   along with the scaled-down layer cascade and end up too small/timid
   for what's meant to be the payoff moment (the reported "completion
   module looks too small/uncertain" complaint). Appending scale(K) at
   the END of its own transform list (composition order: the innermost/
   rightmost function applies to the element's own box first) counters
   exactly the ancestor scene's shrink for THIS element's rendered
   size, while the preceding translate3d offset — evaluated after, in
   the scene's already-scaled space — still lands in the same relative
   spot near the bottom of the scaled scene. Combined with a real
   viewport-relative width (not the desktop 560px cap), this renders at
   a fixed, comfortable on-screen size regardless of how small the
   scale tier shrinks the surrounding scene. */
@media (max-width: 1023px) {
  .assembly__complete {
    width: min(90vw, 460px);
    max-width: none;
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 258px, 0) scale(1.163);
  }

  .assembly__complete.is-visible {
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 242px, 0) scale(1.163);
  }

  .assembly__complete-card {
    padding: 14px 18px;
  }
}

@media (max-width: 767px) {
  .assembly__complete {
    width: min(92vw, 420px);
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 258px, 0) scale(1.22);
  }

  .assembly__complete.is-visible {
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 242px, 0) scale(1.22);
  }
}

@media (max-width: 599px) {
  .assembly__complete {
    width: min(92vw, 380px);
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 258px, 0) scale(1.282);
  }

  .assembly__complete.is-visible {
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 242px, 0) scale(1.282);
  }

  .assembly__complete-card {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 14px 16px;
  }

  .assembly__complete-divider {
    display: none;
  }

  .assembly__complete-status {
    flex-wrap: wrap;
    white-space: normal;
  }
}

@media (max-width: 389px) {
  .assembly__complete {
    width: min(92vw, 340px);
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 258px, 0) scale(1.47);
  }

  .assembly__complete.is-visible {
    transform: translate(-50%, -50%) translateZ(170px) translate3d(0, 242px, 0) scale(1.47);
  }
}

.assembly__complete-card {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
  padding: 13px 22px;
  border-color: rgba(200, 255, 46, .26);
  box-shadow: var(--shadow-lifted), inset 0 1px 0 rgba(255, 255, 255, .06), 0 0 28px rgba(200, 255, 46, .1);
}

.assembly__complete-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  white-space: nowrap;
}

.assembly__complete-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: 0 0 10px var(--color-accent);
  flex-shrink: 0;
  animation: lutPulse 1.8s ease-in-out infinite;
}

.assembly__complete-primary {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .02em;
  color: var(--color-accent);
}

.assembly__complete-tech {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .12em;
  color: rgba(200, 255, 46, .5);
}

.assembly__complete-divider {
  width: 1px;
  height: 20px;
  background: var(--color-border-soft);
  flex-shrink: 0;
}

.assembly__complete-status {
  gap: 16px;
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* Reduced motion fallback — static, readable, no scroll-jacking */
@media (prefers-reduced-motion: reduce) {
  .assembly__track {
    height: auto;
  }

  .assembly__stage {
    position: relative;
    height: auto;
    padding: calc(var(--section-padding) * 1.5) 0;
  }

  .assembly__container {
    display: block;
  }

  .assembly__panel,
  .assembly__progress {
    display: none;
  }

  .assembly__final {
    opacity: 1;
    transform: none;
    max-width: 640px;
  }

  .assembly__scene {
    height: auto;
    perspective: none;
    transform: none;
  }

  .assembly__intro-mobile {
    display: none;
  }

  .assembly__content-intro {
    display: block;
  }

  .assembly__core {
    width: 100%;
    height: auto;
    transform: none;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
  }

  .assembly__scan,
  .assembly__chip {
    display: none;
  }

  .assembly__layers {
    position: static;
    display: contents;
  }

  .assembly__layer {
    position: static;
    width: auto;
    height: auto;
    min-height: 168px;
    transform: none !important;
    opacity: 1 !important;
    box-shadow: var(--shadow-elevated) !important;
    border-color: var(--color-border-soft) !important;
  }

  .assembly__layer-desc {
    display: block !important;
  }

  .assembly__complete {
    position: static;
    transform: none;
    opacity: 1;
    margin-top: 32px;
    grid-column: 1 / -1;
  }
}

.assembly__layer-desc {
  display: none;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-dim-5);
  padding: 0 15px 14px;
}
