/* ==========================================================================
   what-i-build.css — Stacked scroll-reveal type section
   Reference: minhpham.design "What I Do" — dual-layer clip mask reveal
   Pairs with: JS scrub clip animation in Plan 04
   ========================================================================== */

/* === Section container ===
   Sized to 100vh on desktop because Plan-04 GSAP pins this section for the
   duration of the clip reveal. overflow: hidden clips the parallax props at
   the section boundary so they cannot leak into adjacent sections. */
.what-i-build {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;   /* constant small-viewport height — no address-bar reflow jitter */
  padding: var(--space-4xl) 10vw;
  --wib-copy-start: max(10vw, calc((100vw - var(--content-max)) / 2 + var(--space-sm)));
  --wib-copy-adjust: 80px;
  overflow: hidden;
  background: var(--color-bg);
}

/* === Section label — matches .about-label / .wib-label pattern === */
.wib-label {
  position: absolute;
  top: var(--space-xl);                     /* 32px from top */
  left: calc(var(--wib-copy-start) + var(--wib-copy-adjust));
  font-family: var(--font-mono);
  /* minhpham section labels (.body-text uppercase) are 0.875rem (14px) — was 11px. */
  font-size: 14px;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-muted);
  z-index: 2;
}

/* === Stacked-line container ===
   Vertically centered inside the pinned 100vh section. flex column with no
   gap so massive type can sit tightly stacked (line-height controls spacing). */
.wib-stack {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  min-height: calc(100vh - 2 * var(--space-4xl));
  gap: 0;
  width: calc(100% + 20vw);
  margin-left: -10vw;
}

/* === Single line wrapper — holds dark + light layers stacked at same position === */
.wib-line {
  position: relative;
  display: block;
  width: 100%;
  font-family: var(--font-display);
  font-size: clamp(48px, 8vw, 132px);    /* minhpham "What I Do" scale (~8.1vw / 113px @ 1396) — was 6.5vw/110px, too small */
  font-weight: 600;
  line-height: 0.84;                      /* minhpham's tight stacking (95px lh on 113px type = 0.84) */
  letter-spacing: var(--wib-track, -0.04em);   /* per-line tracking — set by the control block below */
  word-spacing: var(--wib-word-space, normal); /* per-line word gap — set by the control block below */
  text-transform: uppercase;
  white-space: nowrap;                    /* lines must not wrap mid-word */
  padding-left: calc(var(--wib-copy-start) + var(--wib-copy-adjust));
  border-top: 1px solid rgba(var(--color-text-rgb), 0.1);
  overflow: hidden;
  isolation: isolate;
}

.wib-line:last-child {
  border-bottom: 1px solid rgba(var(--color-text-rgb), 0.1);
}

/* === Per-word units (AI SYSTEMS line) ===
   "AI" and "SYSTEMS" are wrapped in .wib-w so each word's tracking and the gap
   between them can be set independently. Each word falls back to the line
   tracking when its own var is unset. --wib-sys-gap is the visible space
   between AI and SYSTEMS (replaces the old &emsp;). */
.wib-w { display: inline; }
.wib-w[data-w="ai"]  { letter-spacing: var(--wib-ai-track,  var(--wib-track, -0.02em)); }
.wib-w[data-w="sys"] {
  letter-spacing: var(--wib-sys-track, var(--wib-track, -0.02em));
  margin-left: var(--wib-sys-gap, 0.4em);
}

/* ╔══════════════════════════════════════════════════════════════════════╗
   ║  TITLE SPACING CONTROL BLOCK — adjust one number, refresh, eyeball.   ║
   ║  Positive letter-spacing = looser, negative = tighter.                ║
   ╚══════════════════════════════════════════════════════════════════════╝ */

/* Title 1 — FINTECH */
.wib-stack .wib-line:nth-child(1) { --wib-track: -0.04em; }

/* Title 2 — PIPELINES */
.wib-stack .wib-line:nth-child(2) { --wib-track: -0.04em; }

/* Title 3 — BACKEND */
.wib-stack .wib-line:nth-child(3) { --wib-track: -0.04em; }

/* Title 4 — AI SYSTEMS (per word) */
.wib-stack .wib-line:nth-child(4) {
  --wib-ai-track:  -0.04em;   /* "AI" tracking            */
  --wib-sys-track: -0.04em;   /* "SYSTEMS" tracking       */
  --wib-sys-gap:    0.4em;    /* gap between AI & SYSTEMS  */
}

/* === Dark layer — always visible, blends into bg ===
   Color is intentionally close to --color-bg so the line is barely
   perceptible at rest. The light layer above does the visual work. */
.wib-line-dark {
  display: block;
  width: fit-content;
  color: var(--color-reveal-base);
  position: relative;
  z-index: 1;
}

/* === Accent layer — orange band that expands from center on hover ===
   Starts collapsed at vertical midpoint (inset 50% top + 50% bottom = invisible).
   JS animates both insets to 0% on mouseenter (expand outward from center). */
.wib-line-accent {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  display: block;
  color: var(--color-bg);
  background-color: var(--color-accent);
  padding-left: inherit;
  z-index: 3;
  clip-path: inset(50% 0 50% 0);
  will-change: clip-path;
  pointer-events: none;
}

/* === Reveal phrase — minhpham's right-side hover caption ===
   minhpham reveals a small body-text line on the right of each band when it
   opens (their op-0 col-3, ~12.9px Nunito Sans). Here it lives inside .wib-line
   and is clipped open in lockstep with the band: the JS clip set includes
   .wib-line-phrase, so paintAccent() drives the same inset() on it. Dark text on
   the orange band, normal case + wrapping (the line itself is uppercase nowrap
   giant type, so every inherited type property has to be reset). It sits at the
   content's right edge (right: 10vw == the section's right padding). */
.wib-line-phrase {
  position: absolute;
  top: 50%;
  right: 10vw;
  transform: translateY(-50%);
  width: min(34ch, 30vw);
  font-family: var(--font-body);
  font-size: clamp(12px, 0.95vw, 15px);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  white-space: normal;
  text-align: left;
  color: var(--color-bg);
  clip-path: inset(50% 0 50% 0);   /* closed by default; JS opens it with the band */
  will-change: clip-path;
  z-index: 4;                       /* above the band's own word text */
  pointer-events: none;
}

/* Touch / no-hover: the band reveal is hover-driven, so hide the phrase too. */
@media (pointer: coarse) {
  .wib-line-phrase { display: none; }
}

/* === Light layer — clip-revealed by Plan-04 ScrollTrigger scrub ===
   Default state: fully clipped (inset 0 0 100% 0 = invisible).
   Plan-04 JS animates inset's bottom value from 100% → 0% as you scroll. */
.wib-line-light {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  display: block;
  color: var(--color-text);
  padding-left: inherit;                  /* inherits staircase padding-left from .wib-line so both layers align */
  z-index: 2;
  clip-path: inset(0 100% 0 0);           /* fully clipped at rest — right inset 100% → 0% = left-to-right horizontal reveal */
  will-change: clip-path;                 /* permanent: this element is continuously scrubbed during the pin */
  pointer-events: none;
}

/* === Parallax props — left + right edge decorations, desktop only ===
   Empty divs (Plan 01 markup) — placeholder backgrounds until user supplies real assets.
   Plan-04 JS tweens y-position on these for parallax. */
/* === Flush left start — all lines share the same left edge ===
   Previously each line stepped right by a few px (a subtle staircase), which
   read as accidental misalignment rather than an intentional cascade. All
   lines now start at the same x via the base .wib-line padding-left. */

.wib-prop {
  position: absolute;
  width: min(26vw, 420px);
  height: 60vh;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  will-change: transform;
  background: transparent;
  opacity: 0.72;
}

.wib-prop-left {
  left: -3vw;
  top: 9vh;
}

.wib-prop-right {
  right: -4vw;
  top: 46vh;
}

/* No 3D on touch devices — controller-model.js skips WebGL init on coarse pointers, so hide the
   (now empty) prop box on touch tablets 769–1024 where the ≤768 rule below doesn't reach. */
@media (pointer: coarse) { .wib-prop { display: none; } }

/* Three.js canvas must fill the wib-prop container */
[data-controller-model] canvas {
  display: block;
  width: 100%;
  height: 100%;
}

:root.theme-light .wib-prop::before {
  background:
    radial-gradient(circle at 50% 45%, rgba(10, 31, 122, 0.18), transparent 48%),
    radial-gradient(circle at 50% 58%, rgba(210, 193, 168, 0.28), transparent 58%);
}

/* === Dual-mode scoping — scoped to .what-i-build (NEVER bare [data-*]) ===
   Mirrors the .about and .skills patterns from Phase 2. */
.what-i-build [data-professional] { display: block; }
.what-i-build [data-honest]       { display: none; }

body.mode-honest .what-i-build [data-professional] { display: none; }
body.mode-honest .what-i-build [data-honest]       { display: block; }

/* === Reduced-motion belt-and-braces ===
   When user prefers reduced motion, Plan-04 JS short-circuits and never sets up
   the pin or scrub. CSS shows the light layer fully (no clip) so content is
   readable without animation. Props are hidden because they only make sense
   with parallax. */
@media (prefers-reduced-motion: reduce) {
  .wib-line-light {
    clip-path: none !important;
    position: relative;                    /* take it out of absolute stacking so layout collapses correctly */
    color: var(--color-text);
  }
  .wib-line-dark {
    display: none;                          /* with light layer fully revealed, dark layer is redundant */
  }
  .wib-prop {
    display: none;
  }
}

/* === Mobile (≤768px) — no pin (Plan-04 matchMedia guards desktop only) ===
   Light layer fully visible; props hidden; type scaled down. */
@media (max-width: 768px) {
  .what-i-build {
    min-height: auto;                       /* no longer pinned, no need for full viewport */
    padding: var(--space-3xl) var(--space-md); /* 64px vertical, 16px horizontal */
    overflow: visible;                      /* props are hidden on mobile, so the only
                                               reason for overflow:hidden is gone — let the
                                               hold-reveal flood grow past the short base
                                               section without clipping the honest list. */
  }
  .wib-stack {
    min-height: auto;
    gap: var(--space-sm);                   /* small breathing room between lines on mobile */
    width: 100%;
    margin-left: 0;
  }
  .wib-line {
    font-size: clamp(48px, 14vw, 96px);
    line-height: 1.0;
    white-space: normal;                    /* allow wrap on small screens — tight nowrap looks bad here */
    padding-left: 0 !important;             /* reset staircase offsets — desktop-only layout feature */
  }
  .what-i-build .wib-line-light {
    position: relative;                     /* take out of absolute stacking */
    clip-path: none;                        /* no scroll-reveal on mobile */
    color: var(--color-text);
  }
  .what-i-build .wib-line-dark {
    display: none;                          /* specificity matches dual-mode rule (0,2,0) so this wins */
  }
  .wib-prop {
    display: none;                          /* desktop only per D-06 */
  }
  .wib-label {
    top: var(--space-md);
    left: var(--space-md);
  }
}

/* === Small handset (≤480px) — CLAUDE.md responsiveness contract ===
   At 14vw the 768px clamp floor of 48px would still be applied; at 480px-wide
   that's roughly 67px — still aggressive on a 4.5" handset. Drop the floor and
   the upper clamp tighter so 5 stacked lines never overflow horizontally and
   the section fits inside a portrait phone viewport. */
@media (max-width: 480px) {
  .what-i-build {
    padding: var(--space-2xl) var(--space-sm); /* 64px vertical, 8px horizontal — minimal side gutter */
  }
  .wib-line {
    font-size: clamp(36px, 12vw, 64px);     /* tighter floor + lower ceiling for narrow viewports */
  }
  .wib-stack {
    gap: var(--space-xs);                   /* even tighter line spacing at this size */
  }
}

/* === Mobile hold-reveal flood (touch only) ================================
   The honest version of the stack, dark on accent, revealed by the circular
   mask the hold button drives (the mask wiring lives in main.css alongside the
   hero/about/timeline lenses). Desktop keeps the per-line hover bands, so this
   overlay is display:none above 1024px. */
.wib-lens { display: none; }

@media (max-width: 1024px) {
  .wib-lens {
    display: block;
    position: absolute;
    /* Section-box flood (inset:0). JS reveals the whole region together, so the
       hero/about/wib section-box floods tile the viewport with no overlap — wib's
       flood no longer paints over the hero + about honest text above it. */
    inset: 0;
    background: var(--color-accent);
    z-index: 5;
    pointer-events: none;
  }
  .wib-lens-inner {
    /* fills the section box, same padding as the section, so the centred
       description list overlaps the centred title stack. */
    position: absolute;
    inset: 0;
    padding: var(--space-3xl) var(--space-md);
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .wib-lens-label {
    /* mirror the base .wib-label (absolute top-left) so it takes no flow space and
       the description rows centre exactly like the title stack. */
    position: absolute;
    top: var(--space-md);
    left: var(--space-md);
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(var(--color-lens-text-rgb), 0.6);
  }
  /* Each description sits in a row the SAME height as its giant base title (and
     the same row gap), so the honest one-liners OVERLAP the titles instead of
     running taller. The sentence is vertically centred on its title's row. */
  .wib-lens-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);                  /* == .wib-stack gap */
  }
  .wib-lens-line {
    display: flex;
    align-items: center;
    min-height: clamp(48px, 14vw, 96px);   /* == .wib-line title height */
    font-family: var(--font-body);
    font-size: clamp(13px, 3.4vw, 16px);
    font-weight: 600;
    line-height: 1.22;
    letter-spacing: -0.005em;
    color: var(--color-bg);
    /* Recreate the base title dividers on the flood rows (the opaque .wib-lens
       covers the .wib-line border-tops), so each honest one-liner reads as bound
       to its title. Tint of --color-bg (the flood text colour) so it adapts per
       theme: dark rules on the orange flood, light rules on the blue flood. */
    border-top: 1px solid rgba(var(--color-bg-rgb), 0.28);
  }
  .wib-lens-list .wib-lens-line:last-child {
    border-bottom: 1px solid rgba(var(--color-bg-rgb), 0.28);  /* mirror .wib-line:last-child */
  }
  @media (max-width: 480px) {
    .wib-lens-inner { padding: var(--space-2xl) var(--space-sm); }
    .wib-lens-label { top: var(--space-md); left: var(--space-md); }
    .wib-lens-list { gap: var(--space-xs); }            /* == .wib-stack gap ≤480 */
    .wib-lens-line {
      min-height: clamp(36px, 12vw, 64px);              /* == .wib-line ≤480 */
      font-size: clamp(12px, 3.2vw, 14px);
    }
  }
}

body.mode-honest .wib-lens { display: none; }
:root.theme-light .wib-lens { background: var(--color-loader-accent); }
@media (prefers-reduced-motion: reduce) { .wib-lens { display: none; } }
