
/* ---- src/shared.jsx ---- */
/* ============================================================
   SHARED — primitives + small helpers
   ============================================================ */

const C = window.CONTENT;

/* Render an HTML string safely (used for leadHTML, identity, etc.
   Content is author-controlled — not user input — so this is safe.) */
function HTML({ html, as: Tag = "span", ...rest }) {
  return <Tag {...rest} dangerouslySetInnerHTML={{ __html: html }} />;
}

/* Placeholder image — soft corner ticks, italic caption below */
function Placeholder({ tag = "fig.", code = "00", label = "asset", caption = "", aspect = "4 / 5", mark, tone = "neutral", style }) {
  const bg = {
    neutral: { strip: "rgba(24,21,19,0.05)", base: "var(--bg-2)" },
    moss:    { strip: "rgba(63,78,62,0.16)",  base: "rgba(63,78,62,0.10)" },
    terra:   { strip: "rgba(156,63,34,0.16)", base: "rgba(156,63,34,0.08)" },
    paper:   { strip: "rgba(24,21,19,0.06)",  base: "var(--paper)" },
    dark:    { strip: "rgba(236,229,212,0.06)", base: "rgba(236,229,212,0.04)" },
  }[tone] || { strip: "rgba(24,21,19,0.05)", base: "var(--bg-2)" };

  return (
    <div className="ph-wrap" style={style}>
      <div
        className="ph"
        style={{
          aspectRatio: aspect,
          background: `repeating-linear-gradient(135deg, transparent 0 14px, ${bg.strip} 14px 15px), ${bg.base}`,
        }}
      >
        <span className="ph-tr" />
        <span className="ph-bl" />
        {mark ? <span className="ph-x">{mark}</span> : null}
      </div>
      <div className="ph-caption">
        <span>
          <span style={{ fontStyle:"italic", color:"var(--terra)" }}>{tag}</span>
          <span style={{ color:"var(--rule)", margin:"0 8px" }}>/</span>
          <span style={{ fontFamily:"var(--mono)", fontStyle:"normal", fontSize:11, letterSpacing:"0.14em", color:"var(--ink-2)" }}>{code}</span>
          <span style={{ color:"var(--rule)", margin:"0 8px" }}>·</span>
          <span>{label}</span>
        </span>
        {caption ? <span>{caption}</span> : null}
      </div>
    </div>
  );
}

/* Editorial colophon (footer of each section) */
function Colophon({ ix, title, scale, note }) {
  return (
    <div className="colophon">
      <span className="ix">{ix}</span>
      <span style={{ color:"var(--ink)", fontStyle:"normal", fontFamily:"var(--serif)", fontSize:17, letterSpacing:"-0.01em" }}>
        <em>{title}</em>
      </span>
      {scale ? <><span className="sep">·</span><span>{scale}</span></> : null}
      {note  ? <><span className="sep">·</span><span>{note}</span></> : null}
    </div>
  );
}

/* Section header — simple, editorial */
function SectionHead({ num, kicker, right }) {
  return (
    <div className="section-head" style={{
      display:"flex", justifyContent:"space-between", alignItems:"baseline",
      paddingBottom:14, marginBottom: 64,
      borderBottom:"1px solid var(--ink)",
      position:"relative",
    }}>
      <span style={{
        position:"absolute", left:0, bottom:-7,
        width:72, height:7,
        borderLeft:"1px solid var(--ink)",
        borderRight:"1px solid var(--ink)",
        borderBottom:"1px solid var(--ink)",
        opacity:.5,
      }} />
      <div className="caption">
        <span style={{ fontFamily:"var(--mono)", fontStyle:"normal", fontSize:11, letterSpacing:"0.18em", color:"var(--ink)" }}>
          {num}
        </span>
        <span style={{ color:"var(--rule)", margin:"0 12px" }}>/</span>
        <em>{kicker}</em>
      </div>
      <div className="caption">{right}</div>
    </div>
  );
}

Object.assign(window, { C, HTML, Placeholder, Colophon, SectionHead });


/* ---- src/sections-a.jsx ---- */
/* ============================================================
   SECTIONS A — Cover · Speaker · Narrative
   All copy comes from window.CONTENT (see content.js).
   ============================================================ */

/* ---------------------------- 01 — COVER ---------------------------- */
function CoverSection() {
  const d = C.cover;
  return (
    <section id="cover" style={{ paddingTop: 56 }}>
      <div className="shell">

        {/* slim project meta */}
        <div style={{
          display:"flex", justifyContent:"space-between", alignItems:"baseline",
          borderBottom:"1px solid var(--ink)", paddingBottom:16, marginBottom:80,
        }}>
          <div className="caption">
            <span style={{ fontFamily:"var(--mono)", fontStyle:"normal", fontSize:11, letterSpacing:"0.18em", color:"var(--ink)" }}>
              {d.sheet}
            </span>
            <span style={{ color:"var(--rule)", margin:"0 14px" }}>/</span>
            <em>cover sheet</em>
          </div>
          <div className="caption"><em>{C.project.event}</em></div>
        </div>

        {/* Hero */}
        <div style={{
          display:"grid",
          gridTemplateColumns:"minmax(0, 1.45fr) minmax(0, 1fr)",
          gap: 56, alignItems:"start", position:"relative",
        }} className="cover-grid">

          <div style={{ minWidth:0, position:"relative" }}>
            <div style={{
              fontFamily:"var(--serif)", fontStyle:"italic",
              fontSize:18, color:"var(--mute)", marginBottom:20,
            }}>
              <span style={{ color:"var(--terra)" }}>i.</span>&nbsp; {d.eyebrow}
            </div>
            <h1 className="h-display balance">
              {d.title.l1}<br />
              <span style={{ display:"inline-block", paddingLeft:"4vw" }}>{d.title.l2}</span><br />
              <span className="italic key">{d.title.l3}</span>
            </h1>
          </div>

          <div style={{ position:"relative", marginTop:"3vw", minWidth:0 }} className="cover-image">
            <Placeholder
              tag={d.portrait.tag} code={d.portrait.code} label={d.portrait.label}
              caption={d.portrait.caption} aspect="3 / 4" mark={d.portrait.mark}
            />
          </div>
        </div>

        {/* Lead paragraph */}
        <div style={{
          display:"grid",
          gridTemplateColumns:"minmax(0, 0.4fr) minmax(0, 1fr) minmax(0, 0.5fr)",
          marginTop: 96, gap: 36,
        }} className="cover-lead">
          <div></div>
          <HTML as="p" className="h-lead" style={{ margin:0 }} html={d.leadHTML} />
          <div className="caption" style={{ alignSelf:"end" }}><em>{d.duration}</em></div>
        </div>

        {/* Indexed lingkup bahasan */}
        <div style={{ marginTop: 140 }}>
          <div style={{
            display:"flex", justifyContent:"space-between", alignItems:"baseline",
            borderTop:"1px solid var(--ink)", paddingTop:14, marginBottom:8,
          }}>
            <div className="caption"><em>{d.indexLabel}</em></div>
            <div className="caption"><em>{d.indexRight}</em></div>
          </div>
          {d.indexItems.map((it) => {
            const color = it.accent === "terra" ? "var(--terra)" :
                          it.accent === "moss"  ? "var(--moss)"  :
                          it.accent === "gold"  ? "var(--gold)"  : "var(--mute)";
            return (
              <div key={it.n} style={{
                display:"grid", gridTemplateColumns:"60px 1.2fr 2fr",
                gap:24, padding:"20px 0",
                borderTop:"1px solid var(--rule-soft)",
                alignItems:"baseline",
              }}>
                <span className="serif italic" style={{ fontSize:22, color }}>{it.n}</span>
                <span className="serif" style={{ fontSize:32, letterSpacing:"-0.018em" }}>{it.t}</span>
                <span className="serif italic" style={{ fontSize:18, color:"var(--ink-3)" }}>{it.d}</span>
              </div>
            );
          })}
        </div>

        <div style={{
          marginTop:72,
          display:"grid",
          gridTemplateColumns:"repeat(4, 1fr)",
          gap:0,
          borderTop:"1px solid var(--ink)",
          borderBottom:"1px solid var(--ink)",
        }} className="cover-spec">
          {[
            ["format", "16:9 landscape"],
            ["ratio", "1920 × 1080"],
            ["tempo", "10 menit"],
            ["mode", "PDF / print-ready"],
          ].map(([k, v]) => (
            <div key={k} style={{
              padding:"14px 18px",
              borderRight:"1px solid var(--rule-soft)",
              minHeight:68,
            }}>
              <div className="spec">{k}</div>
              <div className="serif italic" style={{ marginTop:8, fontSize:19, color:"var(--ink-2)" }}>{v}</div>
            </div>
          ))}
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Cover" scale="Tema dan kerangka" note="Sheet of 08" />
      </div>

      <style>{`
        @media (max-width: 900px) {
          #cover .cover-grid { grid-template-columns: 1fr !important; }
          #cover .cover-image { margin-left: 0 !important; margin-top: 40px !important; }
          #cover .cover-lead { grid-template-columns: 1fr !important; }
          #cover .cover-spec { grid-template-columns: repeat(2, 1fr) !important; }
        }
        @media (max-width: 560px) {
          #cover .cover-spec { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </section>
  );
}

/* ---------------------------- 02 — SPEAKER ---------------------------- */
function SpeakerProfile() {
  const d = C.speaker;
  return (
    <section id="speaker">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right={d.right} />

        <div style={{
          display:"grid",
          gridTemplateColumns:"minmax(0, 1fr) minmax(0, 0.7fr)",
          gap: 56, alignItems:"start",
        }} className="speaker-masthead">

          <div>
            <div className="caption" style={{ marginBottom:18 }}><em>{d.nameLabel}</em></div>
            <h2 className="h-section" style={{ marginTop:0 }}>
              <span style={{ color:"var(--mute)" }}>{d.name.prefix}</span><br />
              {d.name.first}<br />
              <span className="italic">{d.name.last}</span>
              <span style={{ color:"var(--mute)" }}> {d.name.suffix}</span>
            </h2>

            <HTML as="p" className="h-lead" style={{ maxWidth:600, marginTop:48 }} html={d.identity} />
          </div>

          <div>
            {d.portraits[0] && (
              <Placeholder
                tag={d.portraits[0].tag} code={d.portraits[0].code}
                label={d.portraits[0].label} caption={d.portraits[0].caption}
                aspect={d.portraits[0].aspect} tone={d.portraits[0].tone}
              />
            )}
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:18, marginTop:64 }}>
              {d.portraits.slice(1, 3).map((p, i) => (
                <Placeholder key={i}
                  tag={p.tag} code={p.code} label={p.label}
                  caption={p.caption} aspect={p.aspect} tone={p.tone}
                />
              ))}
            </div>
          </div>
        </div>

        <div style={{ marginTop:120 }}>
          <div style={{
            display:"flex", justifyContent:"space-between", alignItems:"baseline",
            borderTop:"1px solid var(--ink)", paddingTop:14,
          }}>
            <div className="caption"><em>{d.practiceLabel}</em></div>
            <div className="caption"><em>{d.practiceRight}</em></div>
          </div>
          {d.practiceItems.map((it) => (
            <div key={it.n} style={{
              display:"grid", gridTemplateColumns:"72px 1.1fr 1.6fr",
              gap:32, padding:"22px 0",
              borderTop:"1px solid var(--rule-soft)",
              alignItems:"baseline",
            }}>
              <span className="serif italic" style={{ fontSize:22, color:"var(--terra)" }}>{it.n}</span>
              <span className="serif" style={{ fontSize:30, letterSpacing:"-0.018em" }}>{it.t}</span>
              <span className="serif italic" style={{ fontSize:17, color:"var(--ink-3)" }}>{it.d}</span>
            </div>
          ))}
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Speaker" scale="Identitas narasumber" />
      </div>

      <style>{`
        @media (max-width: 900px) {
          #speaker .speaker-masthead { grid-template-columns: 1fr !important; gap: 48px; }
        }
      `}</style>
    </section>
  );
}

/* ---------------------------- 03 — NARRATIVE ---------------------------- */
function NarrativeFlow() {
  const d = C.narrative;
  return (
    <section id="narrative">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right={d.right} />

        <div className="col-12" style={{ alignItems:"end", marginBottom: 96 }}>
          <div style={{ gridColumn:"span 8" }}>
            <h2 className="h-section balance">
              {d.title.l1}<br/>
              {d.title.l2_pre}<span className="italic key">{d.title.l2_emph}</span>
            </h2>
          </div>
          <div style={{ gridColumn:"span 4" }}>
            <HTML as="p" className="body-lg" style={{ margin:0 }} html={d.leadHTML} />
          </div>
        </div>

        {/* Phase legend */}
        <div style={{
          display:"flex", flexWrap:"wrap", gap:32,
          borderTop:"1px solid var(--rule)", paddingTop:14, marginBottom:48,
        }}>
          {Object.entries(d.phases).map(([k, v]) => (
            <div key={k} style={{
              display:"inline-flex", alignItems:"center", gap:10,
              fontFamily:"var(--serif)", fontStyle:"italic", fontSize:14, color:"var(--ink-3)",
            }}>
              <span style={{ width:9, height:9, borderRadius:"50%", background:v.dot }} />
              {v.label}
            </div>
          ))}
        </div>

        <SpineElevation steps={d.steps} phases={d.phases} />

        {/* Mobile list */}
        <details style={{ borderTop:"1px solid var(--rule)", marginTop:36 }} className="spine-mobile">
          <summary className="caption" style={{ padding:"14px 0" }}><em>↓ open full sequence (mobile)</em></summary>
          <ol style={{ listStyle:"none", padding:0, margin:0 }}>
            {d.steps.map(s => {
              const tone = d.phases[s.phase];
              return (
                <li key={s.n} style={{
                  display:"grid", gridTemplateColumns:"50px 1fr 1.4fr",
                  gap:16, padding:"14px 0", borderTop:"1px solid var(--rule-soft)",
                  alignItems:"baseline",
                }}>
                  <span className="serif italic" style={{fontSize:17, color: tone.dot}}>{s.n}.</span>
                  <span className="serif" style={{fontSize:24, letterSpacing:"-0.01em"}}>{s.t}</span>
                  <span className="caption">{tone.label}</span>
                </li>
              );
            })}
          </ol>
        </details>

        <Colophon ix={d.sheet + " / 08"} title="Narrative" scale="Spine · 12 tahap" note="Read left → right" />
      </div>
    </section>
  );
}

function SpineElevation({ steps, phases }) {
  const W = 1440, H = 320;
  const m = { l: 20, r: 20, t: 80, b: 70 };
  const innerW = W - m.l - m.r;
  const baseY = H - m.b;
  const headY = m.t;
  const stepX = (i) => m.l + (innerW * (i + 0.5) / steps.length);

  return (
    <div style={{ position:"relative" }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width:"100%", height:"auto", display:"block" }} aria-label="Narrative spine — elevation">
        <line x1={m.l} y1={baseY} x2={W-m.r} y2={baseY} stroke="var(--ink)" strokeWidth="1" />
        {steps.map((s, i) => {
          const x = stepX(i);
          return <line key={"v"+i} x1={x} y1={headY-20} x2={x} y2={baseY-1}
            stroke="var(--rule-soft)" strokeWidth="0.5" />;
        })}

        {steps.map((s, i) => {
          const x = stepX(i);
          const tone = phases[s.phase];
          const isOutcome = s.phase === "outcome";
          const dotY = headY + 8;
          return (
            <g key={s.n}>
              {isOutcome
                ? <rect x={x-12} y={dotY-12} width="24" height="24" fill={tone.dot} stroke={tone.dot} strokeWidth="1" />
                : <circle cx={x} cy={dotY} r="5" fill={tone.dot} />}
              <text x={x} y={dotY - 22} textAnchor="middle"
                fontFamily="var(--serif)" fontStyle="italic"
                fontSize={isOutcome ? "18" : "14"}
                fill={isOutcome ? tone.dot : "var(--mute)"}>{s.n}.</text>
              <text x={x} y={baseY + 26} textAnchor="middle"
                fontFamily="var(--serif)"
                fontSize={isOutcome ? 22 : 16}
                fontStyle={isOutcome ? "italic" : "normal"}
                fill={isOutcome ? tone.dot : "var(--ink)"}
                letterSpacing="-0.012em">{s.t}</text>
            </g>
          );
        })}

        <text x={stepX(steps.length-1)} y={headY - 50} textAnchor="middle"
          fontFamily="var(--serif)" fontStyle="italic"
          fontSize="14" fill="var(--terra)">↘ outcome</text>

        <line x1={m.l} y1={headY-26} x2={W-m.r} y2={headY-26} stroke="var(--rule)" strokeWidth="0.6" />
        <text x={m.l} y={headY-32}
          fontFamily="var(--serif)" fontStyle="italic"
          fontSize="14" fill="var(--mute)">{steps[0].t.toLowerCase()}</text>
        <text x={W-m.r} y={headY-32} textAnchor="end"
          fontFamily="var(--serif)" fontStyle="italic"
          fontSize="14" fill="var(--mute)">{steps[steps.length-1].t.toLowerCase()}</text>
      </svg>
    </div>
  );
}

Object.assign(window, { CoverSection, SpeakerProfile, NarrativeFlow });


/* ---- src/sections-b.jsx ---- */
/* ============================================================
   SECTIONS B — Ecosystem · Deck
   All copy comes from window.CONTENT (see content.js).
   ============================================================ */

const TONE_COLOR = {
  terra:"var(--terra)", moss:"var(--moss)", gold:"var(--gold)",
  ink:"var(--ink)", "terra-d":"var(--terra-d)",
};

/* ---------------------------- 04 — ECOSYSTEM ---------------------------- */
function EcosystemMap() {
  const d = C.ecosystem;
  return (
    <section id="ecosystem">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right={d.right} />

        <div style={{ marginBottom: 80 }}>
          <h2 className="serif balance" style={{
            margin:0,
            fontSize:"clamp(40px, 5.6vw, 88px)",
            lineHeight:0.96, letterSpacing:"-0.024em",
          }}>
            {d.title.l1} <span className="italic key">{d.title.l2_emph}</span>
          </h2>
          <p className="serif italic balance" style={{
            margin:"24px 0 0",
            fontSize:"clamp(20px, 2.3vw, 30px)",
            lineHeight:1.32, color:"var(--ink-3)",
            maxWidth: 820,
          }}>
            {d.lead}
          </p>
        </div>

        <EcosystemPlan nodes={d.nodes} outcome={d.outcome} />

        {/* Register */}
        <div style={{ marginTop:80 }}>
          <div style={{
            display:"flex", justifyContent:"space-between", alignItems:"baseline",
            borderTop:"1px solid var(--ink)", paddingTop:14,
          }}>
            <div className="caption"><em>register · simpul</em></div>
            <div className="caption"><em>{d.nodes.length} entries</em></div>
          </div>
          {d.nodes.map((n, i) => (
            <div key={n.id} style={{
              display:"grid",
              gridTemplateColumns:"60px 1.3fr 2fr 1.4fr",
              gap:24, padding:"24px 0",
              borderTop:"1px solid var(--rule-soft)",
              alignItems:"baseline",
            }} className="eco-row">
              <span className="serif italic" style={{ fontSize:22, color: TONE_COLOR[n.tone] }}>
                {String(i+1).padStart(2,"0")}.
              </span>
              <span className="serif" style={{ fontSize:30, letterSpacing:"-0.018em" }}>{n.label}</span>
              <span className="serif italic" style={{ fontSize:17, color:"var(--ink-3)" }}>{n.role}</span>
              <span style={{ fontFamily:"var(--mono)", fontSize:10.5, letterSpacing:"0.06em", color:"var(--mute)" }}>
                ↗ {n.domain}
              </span>
            </div>
          ))}
        </div>

        <div style={{
          marginTop:96, paddingTop:64,
          borderTop:"1px solid var(--ink)",
          textAlign:"center",
        }}>
          <div className="caption" style={{ marginBottom:22 }}><em>{d.outcome.kicker}</em></div>
          <div className="serif italic" style={{
            fontSize:"clamp(48px, 7vw, 108px)",
            lineHeight:0.98, color:"var(--ink)",
            letterSpacing:"-0.026em",
          }}>
            {d.outcome.title}
          </div>
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Ecosystem" scale="Peta praktik · conceptual" />
      </div>

      <style>{`
        @media (max-width: 760px) {
          #ecosystem .eco-row { grid-template-columns: 50px 1fr !important; }
          #ecosystem .eco-row > :nth-child(3),
          #ecosystem .eco-row > :nth-child(4) { grid-column: 2 !important; padding-top: 6px; }
        }
      `}</style>
    </section>
  );
}

function EcosystemPlan({ nodes, outcome }) {
  const W = 1320, H = 700;
  const cx = W/2, cy = H/2 + 6;
  const R1 = 230;
  const R2 = 120;
  const positions = [
    { x: cx,             y: cy - R1        },
    { x: cx + R1*0.95,   y: cy - R1*0.31   },
    { x: cx + R1*0.59,   y: cy + R1*0.81   },
    { x: cx - R1*0.59,   y: cy + R1*0.81   },
    { x: cx - R1*0.95,   y: cy - R1*0.31   },
  ];

  return (
    <div style={{ position:"relative" }}>
      <div className="north-mark" aria-hidden="true">N</div>
      <div style={{
        display:"flex", justifyContent:"space-between", alignItems:"baseline",
        borderTop:"1px solid var(--rule)", paddingTop:14, marginBottom:24,
      }}>
        <div className="caption"><em>fig. 04 · peta ekosistem</em></div>
        <div className="caption"><em>plan view · not to scale</em></div>
      </div>

      <svg viewBox={`0 0 ${W} ${H}`} style={{ width:"100%", height:"auto", display:"block" }} aria-label="Ecosystem plan view">
        <circle cx={cx} cy={cy} r={R1+50} fill="none" stroke="var(--rule-soft)" strokeWidth="0.5" strokeDasharray="1 6" />
        <circle cx={cx} cy={cy} r={R1+10} fill="none" stroke="var(--rule)" strokeWidth="0.6" />
        <circle cx={cx} cy={cy} r={R2+60} fill="none" stroke="var(--rule-soft)" strokeWidth="0.5" strokeDasharray="1 6" />

        {positions.map((p, i) => {
          if (!nodes[i]) return null;
          const dx = cx - p.x, dy = cy - p.y;
          const len = Math.hypot(dx, dy);
          const ux = dx/len, uy = dy/len;
          const x2 = cx - ux * (R2+6);
          const y2 = cy - uy * (R2+6);
          const x1 = p.x + ux * 12;
          const y1 = p.y + uy * 12;
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2}
            stroke="var(--ink)" strokeWidth="0.6" />;
        })}

        <circle cx={cx} cy={cy} r={R2} fill="var(--ink)" />
        <circle cx={cx} cy={cy} r={R2-14} fill="none" stroke="var(--cream)" strokeWidth="0.6" />
        <text x={cx} y={cy - 16} textAnchor="middle"
          fontFamily="var(--serif)" fontStyle="italic"
          fontSize="14" fill="#B7AC97">outcome</text>
        <text x={cx} y={cy + 18} textAnchor="middle"
          fontFamily="var(--serif)" fontSize="34" letterSpacing="-0.02em"
          fill="var(--cream)">{outcome.discTitle}</text>
        <text x={cx} y={cy + 44} textAnchor="middle"
          fontFamily="var(--serif)" fontStyle="italic"
          fontSize="13" fill="#B7AC97">{outcome.discCaption}</text>

        {nodes.map((n, i) => {
          const p = positions[i];
          if (!p) return null;
          const color = TONE_COLOR[n.tone] || "var(--ink)";
          const dx = p.x - cx, dy = p.y - cy;
          const isLeft  = dx < -10;
          const isRight = dx >  10;
          const anchor  = isLeft ? "end" : isRight ? "start" : "middle";
          const tx = p.x + (isLeft ? -28 : isRight ? 28 : 0);
          const ty = p.y + (dy < -10 ? -32 : 38);
          return (
            <g key={n.id}>
              <circle cx={p.x} cy={p.y} r="10" fill={color} />
              <text x={tx} y={ty} textAnchor={anchor}
                fontFamily="var(--serif)" fontStyle="italic"
                fontSize="15" fill={color}>{n.id.toLowerCase()}.</text>
              <text x={tx} y={ty + 26} textAnchor={anchor}
                fontFamily="var(--serif)" fontSize="26" letterSpacing="-0.018em"
                fill="var(--ink)">{n.label.replace("Jiwa Karya ","")}</text>
              <text x={tx} y={ty + 46} textAnchor={anchor}
                fontFamily="var(--serif)" fontStyle="italic"
                fontSize="14" fill="var(--ink-3)">{n.role}</text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

/* ---------------------------- 05 — DECK ---------------------------- */
function DeckSection() {
  const d = C.deck;
  return (
    <section id="deck">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right={`${d.slides.length} slides · 16:9`} />

        <div style={{ marginBottom: 80 }}>
          <h2 className="h-section balance">
            <span className="italic">{d.title.l1_emph}</span>{d.title.l1_post}<br/>
            {d.title.l2_pre}<span className="italic key">{d.title.l2_emph}</span>
          </h2>
          <p className="h-lead" style={{ maxWidth: 680, marginTop: 24 }}>{d.lead}</p>
        </div>

        <div style={{
          display:"grid",
          gridTemplateColumns:"repeat(3, 1fr)",
          gap: 36,
        }} className="deck-grid">
          {d.slides.map(s => <SlidePreview key={s.n} slide={s} total={d.slides.length} />)}
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Deck" scale="Slide template · 16:9" />

        <style>{`
          @media (max-width: 900px) {
            #deck .deck-grid { grid-template-columns: repeat(2, 1fr) !important; gap: 24px; }
          }
          @media (max-width: 560px) {
            #deck .deck-grid { grid-template-columns: 1fr !important; }
          }
        `}</style>
      </div>
    </section>
  );
}

function SlidePreview({ slide, total }) {
  return (
    <figure style={{ margin:0 }}>
      <div className="arch-grid" style={{
        aspectRatio:"16 / 9",
        position:"relative", overflow:"hidden",
        padding:"22px 22px 16px",
        display:"flex", flexDirection:"column", justifyContent:"space-between",
      }}>
        <span style={{
          position:"absolute",
          left:16,
          top:"50%",
          width:34,
          borderTop:"1px solid rgba(24,21,19,0.26)",
          transform:"translateY(-50%)",
        }} />
        <span style={{
          position:"absolute",
          right:16,
          top:"50%",
          width:34,
          borderTop:"1px solid rgba(24,21,19,0.26)",
          transform:"translateY(-50%)",
        }} />
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline" }}>
          <span className="serif italic" style={{ fontSize:14, color:"var(--terra)" }}>
            slide · {slide.n}
          </span>
          <span className="serif italic" style={{ fontSize:13, color:"var(--mute)" }}>{slide.layout}</span>
        </div>

        <SlideLayoutPreview slide={slide} />

        <div style={{
          fontFamily:"var(--serif)", fontStyle:"italic", fontSize:12,
          color:"var(--mute)",
          borderTop:"1px solid var(--rule-soft)", paddingTop:8, marginTop:6,
          display:"flex", justifyContent:"space-between",
        }}>
          <span>Teguh Budiana · IAI Bali</span>
          <span>{slide.n} / {total}</span>
        </div>
      </div>

      <figcaption style={{
        marginTop:14, display:"grid", gridTemplateColumns:"32px 1fr",
        gap:12, alignItems:"baseline",
      }}>
        <span className="serif italic" style={{ fontSize:15, color:"var(--terra)" }}>{slide.n}.</span>
        <span className="serif italic" style={{ fontSize:14.5, color:"var(--ink-3)" }}>{slide.note}</span>
      </figcaption>
    </figure>
  );
}

function SlideLayoutPreview({ slide }) {
  switch (slide.layout) {
    case "title": {
      const words = slide.title.split(" ");
      const main = words.slice(0, -2).join(" ");
      const tail = words.slice(-2).join(" ");
      return (
        <div style={{ flex:1, display:"flex", alignItems:"center" }}>
          <div className="serif balance" style={{
            fontSize:"clamp(20px, 2.5vw, 32px)",
            lineHeight:1.0, letterSpacing:"-0.02em",
          }}>
            {main}{" "}<span style={{ fontStyle:"italic", color:"var(--terra)" }}>{tail}</span>
          </div>
        </div>
      );
    }
    case "split":
      return (
        <div style={{ flex:1, display:"grid", gridTemplateColumns:"1fr 1fr", gap:14 }}>
          <div style={{ display:"flex", alignItems:"end" }}>
            <div className="serif balance" style={{ fontSize:"clamp(16px, 1.9vw, 22px)", lineHeight:1.02, letterSpacing:"-0.015em" }}>
              {slide.title}
            </div>
          </div>
          <div style={{
            background:"repeating-linear-gradient(135deg, transparent 0 9px, rgba(24,21,19,0.06) 9px 10px), var(--bg-2)",
            position:"relative",
          }}>
            <span style={{ position:"absolute", left:0, top:0, width:10, height:10,
              borderTop:"1px solid var(--ink)", borderLeft:"1px solid var(--ink)" }}/>
            <span style={{ position:"absolute", right:0, bottom:0, width:10, height:10,
              borderBottom:"1px solid var(--ink)", borderRight:"1px solid var(--ink)" }}/>
          </div>
        </div>
      );
    case "image":
      return (
        <div style={{ flex:1, display:"grid", gridTemplateRows:"1fr auto", gap:10 }}>
          <div style={{
            background:"repeating-linear-gradient(135deg, transparent 0 9px, rgba(156,63,34,0.14) 9px 10px), rgba(156,63,34,0.07)",
            position:"relative",
          }}>
            <span style={{ position:"absolute", left:8, top:8,
              fontFamily:"var(--serif)", fontStyle:"italic", fontSize:11, color:"var(--terra)",
            }}>full-bleed</span>
            <span style={{ position:"absolute", left:0, top:0, width:10, height:10,
              borderTop:"1px solid var(--ink)", borderLeft:"1px solid var(--ink)" }}/>
            <span style={{ position:"absolute", right:0, bottom:0, width:10, height:10,
              borderBottom:"1px solid var(--ink)", borderRight:"1px solid var(--ink)" }}/>
          </div>
          <div className="serif balance" style={{ fontSize:"clamp(15px, 1.7vw, 21px)", lineHeight:1.04, letterSpacing:"-0.015em" }}>
            {slide.title}
          </div>
        </div>
      );
    case "diagram":
      return (
        <div style={{ flex:1, display:"grid", gridTemplateColumns:"5fr 7fr", gap:14 }}>
          <div style={{ display:"flex", alignItems:"end" }}>
            <div className="serif balance" style={{ fontSize:"clamp(15px, 1.7vw, 21px)", lineHeight:1.04, letterSpacing:"-0.015em" }}>
              {slide.title}
            </div>
          </div>
          <div style={{ display:"grid", placeItems:"center" }}>
            <svg viewBox="0 0 140 70" style={{ width:"94%", height:"auto" }}>
              <line x1="12" y1="38" x2="128" y2="38" stroke="var(--ink)" strokeWidth="0.5" />
              {[16,50,80,114].map((x,i) => (
                <g key={x}>
                  <circle cx={x} cy="38" r="4" fill={i===2 ? "var(--terra)" : "var(--ink)"} />
                  <text x={x} y={i===2?22:54} textAnchor="middle"
                    fontFamily="var(--serif)" fontStyle="italic"
                    fontSize="6" fill={i===2?"var(--terra)":"var(--mute)"}>0{i+1}.</text>
                </g>
              ))}
            </svg>
          </div>
        </div>
      );
    case "quote":
      return (
        <div style={{ flex:1, display:"flex", alignItems:"center" }}>
          <div className="serif italic balance" style={{
            fontSize:"clamp(15px, 1.9vw, 22px)",
            lineHeight:1.18, color:"var(--ink-2)",
          }}>
            <span style={{color:"var(--terra)"}}>“</span>
            {slide.title}
            <span style={{color:"var(--terra)"}}>”</span>
          </div>
        </div>
      );
    default:
      return null;
  }
}

Object.assign(window, { EcosystemMap, DeckSection });


/* ---- src/sections-c.jsx ---- */
/* ============================================================
   SECTIONS C — Manifesto (dark) · Bio · Assets
   All copy comes from window.CONTENT (see content.js).
   ============================================================ */

/* ---------------------------- 06 — MANIFESTO ---------------------------- */
function QuoteSection() {
  const d = C.manifesto;
  return (
    <section id="manifesto" className="dark">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right={`${d.quotes.length} kalimat`} />

        <div style={{ marginBottom: 96 }}>
          <h2 className="h-section balance" style={{ color:"var(--cream)" }}>
            {d.title.l1}<br/>
            <span className="italic key">{d.title.l2_emph}</span>
          </h2>
        </div>

        <div style={{ display:"grid", gap: 96 }}>
          {d.quotes.map((q, i) => {
            const align = i % 2 === 0 ? "left" : "right";
            return (
              <figure key={i} style={{
                margin:0,
                textAlign: align,
                paddingLeft: align === "right" ? "16%" : 0,
                paddingRight: align === "left"  ? "16%" : 0,
              }} className="quote-figure">
                <blockquote className="serif italic balance" style={{
                  margin:0,
                  fontSize:"clamp(36px, 5.4vw, 88px)",
                  lineHeight:1.04,
                  letterSpacing:"-0.024em",
                  color:"var(--cream)",
                }}>
                  <span className="key" style={{ fontStyle:"normal" }}>“</span>
                  {q}
                  <span className="key" style={{ fontStyle:"normal" }}>”</span>
                </blockquote>
                <figcaption className="serif italic" style={{
                  marginTop:18, fontSize:15, color:"#9C927F",
                }}>
                  <span style={{ color:"#E59A77", marginRight:8 }}>{String(i+1).padStart(2,"0")}.</span>
                  signature · #{i+1}
                </figcaption>
              </figure>
            );
          })}
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Manifesto" scale="Signature lines · pull-quote" />
      </div>

      <style>{`
        @media (max-width: 760px) {
          #manifesto .quote-figure { padding-left: 0 !important; padding-right: 0 !important; text-align: left !important; }
        }
      `}</style>
    </section>
  );
}

/* ---------------------------- 07 — BIO ---------------------------- */
function BioSection() {
  const d = C.bio;
  return (
    <section id="bio">
      <div className="shell">
        <SectionHead num={d.sheet} kicker={d.kicker} right="04 versi · placeholder editorial" />

        <div style={{ marginBottom: 96 }}>
          <h2 className="h-section balance">
            {d.title.l1}<br/>
            <span className="italic">{d.title.l2_emph}</span>
          </h2>
          <p className="h-lead" style={{ maxWidth: 720, marginTop: 24 }}>{d.lead}</p>
        </div>

        <div className="bio-trio" style={{
          display:"grid", gridTemplateColumns:"repeat(3, 1fr)", gap:48,
        }}>
          <BioPanel data={d.short} />
          <BioPanel data={d.medium} />
          <BioPanel data={d.moderator} italic />
        </div>

        <BioLong data={d.long} />

        <Colophon ix={d.sheet + " / 08"} title="Bio" scale="Empat versi · satu suara" />
      </div>

      <style>{`
        @media (max-width: 900px) {
          #bio .bio-trio { grid-template-columns: 1fr !important; gap: 56px; }
          #bio .bio-long { grid-template-columns: 1fr !important; gap: 32px; }
        }
      `}</style>
    </section>
  );
}

function BioPanel({ data, italic }) {
  return (
    <div style={{ position:"relative" }}>
      <div style={{
        borderTop:"1px solid var(--ink)", paddingTop:14,
        display:"flex", justifyContent:"space-between", alignItems:"baseline",
        marginBottom:22,
      }}>
        <div className="caption">
          <span className="serif italic" style={{ color:"var(--terra)", fontSize:18, marginRight:10 }}>{data.ix}</span>
          <em>{data.label}</em>
        </div>
      </div>
      <div className="caption" style={{ marginBottom:18, fontSize:12.5 }}><em>{data.spec}</em></div>
      <p className="serif" style={{
        margin:0,
        fontSize:16.5, lineHeight:1.55,
        color:"var(--ink-2)",
        fontStyle: italic ? "italic" : "normal",
      }}>
        {data.body}
      </p>
    </div>
  );
}

function BioLong({ data }) {
  // Replace literal "\n" in the title-emph with line breaks
  const emphLines = (data.title.l2_emph || "").split("\n");
  return (
    <article style={{ marginTop: 120 }}>
      <div style={{
        display:"flex", justifyContent:"space-between", alignItems:"baseline",
        borderTop:"1px solid var(--ink)", paddingTop:14, marginBottom:48,
      }}>
        <div className="caption">
          <span className="serif italic" style={{ color:"var(--terra)", fontSize:18, marginRight:14 }}>{data.ix}</span>
          <em>{data.label}</em>
        </div>
        <div className="caption"><em>{data.spec}</em></div>
      </div>

      <div className="bio-long" style={{
        display:"grid", gridTemplateColumns:"minmax(0, 1.2fr) minmax(0, 1.8fr)", gap: 64,
        alignItems:"start",
      }}>
        <h3 className="serif" style={{
          margin:0,
          fontSize:"clamp(34px, 4.8vw, 72px)",
          lineHeight:0.95, letterSpacing:"-0.022em",
        }}>
          {data.title.l1}<br/>
          {data.title.l2_pre}
          <span className="italic key">
            {emphLines.map((ln, i) => (
              <React.Fragment key={i}>
                {i > 0 && <br/>}
                {ln}
              </React.Fragment>
            ))}
          </span>
        </h3>
        <div>
          {data.paragraphs.map((p, i) => (
            <HTML key={i} as="p" className="serif" html={p} style={{
              fontSize:18, lineHeight:1.62, color:"var(--ink-2)",
              margin: 0, marginTop: i === 0 ? 0 : 0,
              textIndent:"1.6em",
            }} />
          ))}
        </div>
      </div>
    </article>
  );
}

/* ---------------------------- 08 — ASSETS ---------------------------- */
const STATUS_TONE = {
  todo:  { color:"var(--terra)", label:"to do"  },
  draft: { color:"var(--gold)",  label:"draft"  },
  ready: { color:"var(--moss)",  label:"ready"  },
};

function AssetChecklist() {
  const d = C.assets;
  const counts = d.items.reduce((acc, a) => { acc[a.status] = (acc[a.status]||0)+1; return acc; }, {});
  return (
    <section id="assets">
      <div className="shell">
        <SectionHead
          num={d.sheet}
          kicker={d.kicker}
          right={`${d.items.length} items · ${counts.todo||0} to do · ${counts.draft||0} draft`}
        />

        <div style={{ marginBottom: 80 }}>
          <h2 className="h-section balance">
            {d.title.l1}<br/>
            <span className="italic key">{d.title.l2_emph}</span>
          </h2>
        </div>

        <div style={{
          display:"grid", gridTemplateColumns:"minmax(0, 1.6fr) minmax(0, 1fr)",
          gap: 64,
        }} className="assets-grid">

          <div>
            <div style={{
              display:"flex", justifyContent:"space-between", alignItems:"baseline",
              borderTop:"1px solid var(--ink)", paddingTop:14,
            }}>
              <div className="caption"><em>register · visual assets</em></div>
              <div className="caption"><em>{d.items.length} entries</em></div>
            </div>
            {d.items.map((a) => {
              const st = STATUS_TONE[a.status] || STATUS_TONE.todo;
              return (
                <div key={a.id} style={{
                  display:"grid", gridTemplateColumns:"54px 1fr auto",
                  gap:24, padding:"22px 0",
                  borderTop:"1px solid var(--rule-soft)",
                  alignItems:"baseline",
                }} className="asset-row">
                  <span className="serif italic" style={{ fontSize:18, color:"var(--terra)" }}>{a.id}</span>
                  <div>
                    <div className="serif" style={{ fontSize:24, letterSpacing:"-0.014em" }}>{a.title}</div>
                    <div className="serif italic" style={{ fontSize:14.5, color:"var(--ink-3)", marginTop:4 }}>
                      {a.notes}
                    </div>
                    <div className="caption" style={{ marginTop:8, fontSize:12.5 }}>
                      <em>{a.fmt} · {a.aspect}</em>
                    </div>
                  </div>
                  <span className="serif italic" style={{
                    fontSize:15, color: st.color, whiteSpace:"nowrap",
                    display:"inline-flex", alignItems:"center", gap:8,
                  }}>
                    <span style={{ width:8, height:8, borderRadius:"50%", background: st.color }}/>
                    {st.label}
                  </span>
                </div>
              );
            })}
          </div>

          <aside>
            <div style={{
              display:"flex", justifyContent:"space-between", alignItems:"baseline",
              borderTop:"1px solid var(--terra)", paddingTop:14,
            }}>
              <div className="caption" style={{ color:"var(--terra)" }}><em>{d.safetyLabel}</em></div>
            </div>
            <ul style={{ listStyle:"none", padding:0, margin:0 }}>
              {d.safetyNever.map(item => (
                <li key={item} style={{
                  display:"grid", gridTemplateColumns:"24px 1fr", gap:12,
                  padding:"14px 0", borderTop:"1px solid var(--rule-soft)",
                  alignItems:"baseline",
                }}>
                  <span className="serif italic" style={{ color:"var(--terra)", fontSize:18 }}>✕</span>
                  <span className="serif" style={{ fontSize:17, color:"var(--ink-2)", lineHeight:1.4 }}>{item}</span>
                </li>
              ))}
            </ul>

            <div style={{ marginTop:36, paddingTop:24, borderTop:"1px solid var(--ink)" }}>
              <div className="caption" style={{ color:"var(--moss)", marginBottom:14 }}>
                <em>{d.pmaLabel}</em>
              </div>
              <p className="serif italic" style={{
                margin:0, fontSize:18, lineHeight:1.45, color:"var(--ink-2)",
                letterSpacing:"-0.005em",
              }}>
                <span className="key" style={{ fontStyle:"normal" }}>“</span>
                {d.pmaFraming}
                <span className="key" style={{ fontStyle:"normal" }}>”</span>
              </p>
            </div>
          </aside>
        </div>

        <Colophon ix={d.sheet + " / 08"} title="Assets" scale="Checklist · safety panel" />
      </div>

      <style>{`
        @media (max-width: 900px) {
          #assets .assets-grid { grid-template-columns: 1fr !important; gap: 48px; }
        }
        @media (max-width: 560px) {
          #assets .asset-row { grid-template-columns: 40px 1fr !important; }
          #assets .asset-row > :last-child { grid-column: 2 !important; }
        }
      `}</style>
    </section>
  );
}

Object.assign(window, { QuoteSection, BioSection, AssetChecklist });


/* ---- src/app.jsx ---- */
/* ============================================================
   APP — Final 8-slide presentation renderer
   ============================================================ */

function App() {
  const slides = C.deck.slides || [];
  return (
    <React.Fragment>
      {slides.map((slide, index) => (
        <FinalPresentationSlide
          key={slide.id || slide.n}
          slide={slide}
          index={index}
          total={slides.length}
        />
      ))}
    </React.Fragment>
  );
}

function FinalPresentationSlide({ slide, index, total }) {
  const dark = Boolean(slide.dark);
  return (
    <section
      id={slide.id}
      className={`final-slide final-slide-${slide.layout || "split"}${dark ? " dark" : ""}`}
    >
      <div className="shell">
        <SectionHead
          num={`SLIDE ${slide.n}`}
          kicker={slide.kicker}
          right={`${slide.timing} · ${slide.meta}`}
        />

        <div className="final-grid">
          <div className="final-copy">
            <div className="caption final-eyebrow">
              <em>{C.project.event}</em>
            </div>

            <h1 className="final-title serif balance">
              {slide.title}
            </h1>

            {slide.subtitle ? (
              <p className="final-subtitle serif italic balance">
                {slide.subtitle}
              </p>
            ) : null}

            {slide.body ? (
              <p className="final-body">
                {slide.body}
              </p>
            ) : null}

            {slide.bullets && slide.bullets.length ? (
              <ul className="final-bullets">
                {slide.bullets.map((item, i) => (
                  <li key={item}>
                    <span className="serif italic">{String(i + 1).padStart(2, "0")}.</span>
                    <span>{item}</span>
                  </li>
                ))}
              </ul>
            ) : null}
          </div>

          <div className="final-visual">
            {slide.layout === "quote" ? (
              <FinalQuote slide={slide} />
            ) : slide.layout === "diagram" ? (
              <FinalDiagram slide={slide} />
            ) : (
              <FinalVisualPlaceholder slide={slide} />
            )}
          </div>
        </div>

        <div className="final-keyline">
          <span className="caption"><em>key line</em></span>
          <p className="serif italic balance">{slide.keyLine}</p>
        </div>

        <div className="final-transition">
          <span className="caption"><em>transition</em></span>
          <p>{slide.transition}</p>
        </div>

        <Colophon
          ix={`${slide.n} / ${String(total).padStart(2, "0")}`}
          title={slide.kicker}
          scale="16:9 landscape"
          note={C.project.version}
        />
      </div>
    </section>
  );
}

function FinalVisualPlaceholder({ slide }) {
  const v = slide.visual || {};
  return (
    <div>
      <Placeholder
        tag={v.tag}
        code={v.code}
        label={v.label}
        caption={v.caption}
        aspect={v.aspect || "16 / 9"}
        tone={v.tone || "neutral"}
        mark={v.mark}
      />
      <div className="final-visual-note serif italic">
        Visual final dapat diganti dengan foto public-safe sesuai brief aset.
      </div>
    </div>
  );
}

function FinalDiagram({ slide }) {
  const items = slide.bullets || [];
  return (
    <div className="final-diagram">
      <div className="north-mark" aria-hidden="true">N</div>
      <div className="caption final-diagram-caption">
        <em>{slide.visual?.label || "diagram"}</em>
      </div>
      <div className="final-diagram-stack">
        {items.map((item, i) => (
          <React.Fragment key={item}>
            <div className="final-diagram-node">
              <span className="serif italic">{String(i + 1).padStart(2, "0")}</span>
              <strong>{item}</strong>
            </div>
            {i < items.length - 1 ? <div className="final-diagram-arrow">↓</div> : null}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

function FinalQuote({ slide }) {
  return (
    <figure className="final-quote">
      <blockquote className="serif italic balance">
        <span>“</span>
        {slide.body}
        <span>”</span>
      </blockquote>
      <figcaption className="caption">
        <em>{slide.keyLine}</em>
      </figcaption>
    </figure>
  );
}

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