/* ============================================================
   BEDROCK — app shell, descent engine, darkening, navigation
   ============================================================ */
const { useState: U, useEffect: E, useRef: R, useCallback: CB } = React;
const A = window.STRATA_A, B = window.STRATA_B, C = window.STRATA_C;

/* ---------- strata metadata ---------- */
const STRATA = [
  { n: "01", key: "listening",      name: "Listening",         rail: "Listening",      q: "What did we actually hear?",            dark: 0.05, depth: "012 m",   Comp: A.StratumListening },
  { n: "02", key: "framing",        name: "Framing",           rail: "Framing",        q: "What is the real challenge?",           dark: 0.14, depth: "048 m",   Comp: A.StratumFraming },
  { n: "03", key: "envisioning",    name: "Envisioning",       rail: "Envisioning",    q: "What future are we aiming for?",        dark: 0.24, depth: "120 m",   Comp: A.StratumEnvisioning },
  { n: "04", key: "assumptions",    name: "Assumptions",       rail: "Assumptions",    q: "What must be true?",                    dark: 0.40, depth: "300 m",   Comp: B.StratumAssumptions },
  { n: "05", key: "transformation", name: "Transformation",    rail: "Transformation", q: "What is being transformed?",            dark: 0.54, depth: "480 m",   Comp: B.StratumTransformation },
  { n: "06", key: "reference",      name: "Reference Frames",  rail: "Reference",      q: "What models organize the thinking?",    dark: 0.68, depth: "700 m",   Comp: B.StratumReferenceFrames },
  { n: "07", key: "crux",           name: "The Crux",          rail: "Crux",           q: "What single challenge unlocks the rest?", dark: 0.86, depth: "900 m", Comp: C.StratumCrux },
  { n: "08", key: "integration",    name: "Integration",       rail: "Integration",    q: "What has to shift in us?",              dark: 1.00, depth: "bedrock", Comp: C.StratumIntegration },
  { n: "09", key: "narrative",      name: "Strategic Narrative", rail: "Narrative",    q: "What story do we carry up?",            dark: 0.08, depth: "↑ surface", Comp: C.StratumNarrative },
];

/* ---------- color helpers ---------- */
function hex2rgb(h) { const n = parseInt(h.slice(1), 16); return [n >> 16 & 255, n >> 8 & 255, n & 255]; }
function rgb2hex(r) { return "#" + r.map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0")).join(""); }
function lerpHex(a, b, t) { const x = hex2rgb(a), y = hex2rgb(b); return rgb2hex([0, 1, 2].map((i) => x[i] + (y[i] - x[i]) * t)); }
function lighten(h, amt) { return lerpHex(h, "#ffffff", amt); }

/* Contrast-preserving descent.
   d ≤ 0.7  → "light regime": warm paper dims toward taupe, text stays ink.
   d > 0.7  → "dark regime": the floor drops to true dark, text flips to paper.
   The plunge lands exactly at the crux + integration (the dark room). */
const LIGHT_END = "#BDB8AE";
function themeFor(d) {
  if (d <= 0.7) {
    const k = d / 0.7;
    return {
      bg: lerpHex("#F2F0EB", LIGHT_END, k),
      fg: "#0A0A0A",
      fg2: lerpHex("#6B6862", "#3D3B37", k),
      soft: lerpHex("#C8C4BB", "#8E8A82", k),
    };
  }
  const k = (d - 0.7) / 0.3;
  return {
    bg: lerpHex("#1C1B19", "#0A0A0A", k),
    fg: "#F2F0EB",
    fg2: "#9A968E",
    soft: "#34332E",
  };
}

function applyTheme(darkness, signal) {
  const th = themeFor(darkness);
  const root = document.documentElement.style;
  root.setProperty("--stage-bg", th.bg);
  root.setProperty("--stage-fg", th.fg);
  root.setProperty("--stage-fg2", th.fg2);
  root.setProperty("--stage-soft", th.soft);
  root.setProperty("--stage-signal", lerpHex(signal, lighten(signal, 0.18), Math.min(1, darkness)));
  root.setProperty("--stage-shift", String(darkness));
}

/* curve the per-layer darkness by atmosphere mode */
function darknessFor(stratum, atmosphere) {
  if (atmosphere === "editorial") return 0;                       // restraint only
  if (atmosphere === "cartographic") return stratum.dark * 0.22;  // a faint dimming
  return stratum.dark;                                            // full descent
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "atmosphere": "darkening",
  "opening": "masthead",
  "rail": true,
  "stone": "flashlight",
  "signal": "#D64A1F"
}/*EDITMODE-END*/;

/* ---------- entrance / cover ---------- */
function Cover({ variant, onEnter, exiting }) {
  const copy = {
    masthead: {
      eyebrow: <>DARK HORSE WORKS &nbsp;·&nbsp; A SENSEMAKING INSTRUMENT</>,
      sub: "A descent in nine strata, down to the one thing that matters.",
    },
    expedition: {
      eyebrow: <>FIELD SURVEY <span className="sig">№ 001</span> &nbsp;·&nbsp; LOOKING GLASS ROBOTICS</>,
      sub: "A vertical core sample of a frontier problem.",
    },
    void: {
      eyebrow: <>BEGIN IN THE DARK &nbsp;·&nbsp; <span className="sig">●</span> ONE STONE</>,
      sub: "Descend beneath the symptoms, toward what is fundamental.",
    },
  }[variant] || {};
  return (
    <div className={"cover" + (variant === "void" ? " cover--void" : "") + (exiting ? " exit" : "")}>
      <div className="cover-grid" aria-hidden="true" />
      <div className="cover-top">
        <div className="cover-wordmark" aria-label="Dark Horse Works">
          <span className="mono" style={{ fontSize: 12, letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--ash)" }}>Dark&nbsp;Horse&nbsp;Works</span>
        </div>
        <div className="cover-stamp">
          <b>SUBJECT</b><br />Looking Glass Robotics — Project Juvet<br />
          <b>FOUNDER</b><br />Varjoun Sarkissian<br />
          <b>MODE</b><br />Facilitated · shared screen
        </div>
      </div>
      <div className="cover-mid">
        <div className="cover-eyebrow">{copy.eyebrow}</div>
        <h1 className="cover-title">BEDROCK</h1>
        <p className="cover-sub">{copy.sub}</p>
      </div>
      <div className="cover-bottom">
        <p className="cover-desc">
          Nine layers of one strategic conversation, arranged as a descent. We move from what was
          heard, beneath assumptions and mental models, down to the crux — <b>prove one sensory
          loop</b> — and back to the surface carrying a story. Each layer is discovered, not read.
        </p>
        <button className="cover-enter" onClick={onEnter}>Begin the descent &nbsp;↓</button>
      </div>
    </div>
  );
}

/* ---------- strata rail ---------- */
function Rail({ idx, onJump, onHome }) {
  return (
    <nav className="rail" aria-label="strata">
      <button className="rail-head" onClick={onHome} title="back to the surface" style={{ background: "none", border: 0, cursor: "pointer", color: "inherit" }}>
        BEDROCK ↑
      </button>
      <div className="rail-strata">
        {STRATA.map((s, i) => (
          <button key={s.key} className={"rail-stratum" + (i === idx ? " is-active" : "")} onClick={() => onJump(i)} title={s.name}>
            <span className="rail-num">{s.n}</span>
            <span className="rail-tick" />
            <span className="rail-name">{s.rail}</span>
          </button>
        ))}
      </div>
      <div className="rail-foot">descent</div>
    </nav>
  );
}

/* ---------- a single stratum field ---------- */
function Field({ idx }) {
  const s = STRATA[idx];
  const Comp = s.Comp;
  const scrollRef = R(null);
  E(() => { if (scrollRef.current) scrollRef.current.scrollTop = 0; }, [idx]);
  const descending = idx < 7;
  const phaseLabel = idx === 8 ? "RESURFACED" : idx === 7 ? "BEDROCK" : "DESCENT";
  return (
    <div className="field">
      <div className="field-scroll" ref={scrollRef}>
        <div className="stratum field-anim" key={idx}>
          <div className="stratum-coord">
            <span><b>STRATUM {s.n}</b> / 09</span>
            <span className="sig">●</span>
            <span>DEPTH&nbsp; <b>{s.depth}</b></span>
            <span>{descending ? "↓" : "↑"} {phaseLabel}</span>
          </div>
          <p className="stratum-q">{s.q}</p>
          <h1 className="stratum-title">{s.name}</h1>
          <Comp />
        </div>
      </div>
    </div>
  );
}

/* ---------- app ---------- */
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [phase, setPhase] = U(() => (localStorage.getItem("bedrock.phase") === "descent" ? "descent" : "cover"));
  const [idx, setIdx] = U(() => { const i = parseInt(localStorage.getItem("bedrock.idx"), 10); return isNaN(i) ? 0 : Math.max(0, Math.min(8, i)); });
  const [exiting, setExiting] = U(false);

  /* persist */
  E(() => { localStorage.setItem("bedrock.phase", phase); }, [phase]);
  E(() => { localStorage.setItem("bedrock.idx", String(idx)); }, [idx]);

  /* theme follows the active layer (or surface on cover) */
  E(() => {
    const darkness = phase === "cover" ? 0 : darknessFor(STRATA[idx], t.atmosphere);
    applyTheme(darkness, t.signal);
  }, [phase, idx, t.atmosphere, t.signal]);

  /* stone variant + carto flag on <html> */
  E(() => {
    document.documentElement.dataset.stone = t.stone;
    document.documentElement.dataset.carto = t.atmosphere === "cartographic" ? "1" : "0";
  }, [t.stone, t.atmosphere]);

  const enter = () => { setExiting(true); setTimeout(() => { setPhase("descent"); setExiting(false); }, 420); };
  const home = () => { setPhase("cover"); };
  const next = () => setIdx((i) => Math.min(8, i + 1));
  const prev = () => setIdx((i) => Math.max(0, i - 1));
  const jump = (i) => setIdx(i);

  /* keyboard descent control */
  E(() => {
    if (phase !== "descent") return;
    const onKey = (e) => {
      const el = document.activeElement;
      if (el && (el.tagName === "TEXTAREA" || el.tagName === "INPUT" || el.isContentEditable)) return;
      if (e.key === "ArrowRight" || e.key === "ArrowDown" || e.key === " " || e.key === "PageDown") { e.preventDefault(); next(); }
      else if (e.key === "ArrowLeft" || e.key === "ArrowUp" || e.key === "PageUp") { e.preventDefault(); prev(); }
      else if (e.key === "Home") { jump(0); }
      else if (e.key === "End") { jump(8); }
      else if (e.key === "Escape") { home(); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [phase]);

  const progress = ((idx + 1) / 9) * 100;
  const s = STRATA[idx];

  return (
    <>
      <div className="masthead-rule" />
      {phase === "cover" && <Cover variant={t.opening} onEnter={enter} exiting={exiting} />}

      <div className={"stage" + (t.rail ? "" : " no-rail")} style={t.rail ? {} : { gridTemplateColumns: "1fr" }}>
        {t.rail && <Rail idx={idx} onJump={jump} onHome={home} />}
        <Field idx={idx} />
      </div>

      {/* nav controls — always reachable, outside the scroll */}
      {phase === "descent" && (
        <div className="nav" style={t.rail ? { left: "clamp(82px,9vw,132px)" } : { left: 0 }}>
          <button className="nav-btn ghost" onClick={prev} disabled={idx === 0}>← back</button>
          <div className="nav-meta hide-sm">{s.n} · {s.name.toUpperCase()}</div>
          <div className="nav-progress"><span className="fill" style={{ width: progress + "%" }} /></div>
          <div className="nav-meta">{String(idx + 1)} / 9</div>
          {idx < 8
            ? <button className="nav-btn primary" onClick={next}>descend ↓</button>
            : <button className="nav-btn primary" onClick={home}>resurface ↑</button>}
        </div>
      )}

      {/* TWEAKS */}
      <TweaksPanel>
        <TweakSection label="Atmosphere" />
        <TweakRadio label="Descent feel" value={t.atmosphere}
          options={["darkening", "editorial", "cartographic"]}
          onChange={(v) => setTweak("atmosphere", v)} />
        <p className="tweak-hint">darkening: the page sinks into ink · editorial: pure restraint, stays on paper · cartographic: a surveyed, faintly-dimming map</p>

        <TweakSection label="Entrance" />
        <TweakRadio label="Opening" value={t.opening}
          options={["masthead", "expedition", "void"]}
          onChange={(v) => setTweak("opening", v)} />

        <TweakSection label="Navigation" />
        <TweakToggle label="Strata gauge (left rail)" value={t.rail}
          onChange={(v) => setTweak("rail", v)} />

        <TweakSection label="The stone — climax" />
        <TweakRadio label="Treatment" value={t.stone}
          options={["flashlight", "ember", "bare"]}
          onChange={(v) => setTweak("stone", v)} />

        <TweakSection label="Signal" />
        <TweakColor label="Editorial red" value={t.signal}
          options={["#D64A1F", "#E2541F", "#B23A1A", "#C2451E"]}
          onChange={(v) => setTweak("signal", v)} />
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
