/* ============================================================
   FRAGILITY — Energy game storyboard, 11 screens
   Bloomberg-terminal × FT interactive aesthetic
   ============================================================ */
const { useState: fU, useMemo: fM } = React;

/* ---------- campaign timeline data ---------- */
const STATIONS = [
  { kind: "mission", year: 2011, n: 1, label: "Nuclear phase-out" },
  { kind: "shock",   year: 2014, severity: "minor",  label: "Crimea Crisis" },
  { kind: "mission", year: 2015, n: 2, label: "Industrial costs" },
  { kind: "mission", year: 2019, n: 3, label: "Emissions deadline" },
  { kind: "shock",   year: 2022, severity: "major",  label: "Russian gas cutoff" },
  { kind: "mission", year: 2024, n: 4, label: "Energy security" },
  { kind: "shock",   year: 2028, severity: "severe", label: "Rhine drought" },
  { kind: "mission", year: 2030, n: 5, label: "Final target" },
];
const YR_MIN = 2010, YR_MAX = 2032;
const pctY = (y) => ((y - YR_MIN) / (YR_MAX - YR_MIN)) * 100;

const SHOCK_TONE = { minor: "#f5c451", major: "#e07c2c", severe: "#c0392b" };

/* ---------- source palette (canonical-ish) ---------- */
const SRC_COLOR = {
  oil:     "#1b1d2a",
  gasRu:   "#9b2c2c",
  gasLng:  "#d97706",
  gasOth:  "#b07321",
  coal:    "#3a3a3a",
  nuclear: "#6d28d9",
  hydro:   "#1e6fbf",
  wind:    "#0e7c66",
  solar:   "#d4a017",
  biomass: "#5b8f2b",
};
const SRC_LABEL = {
  oil: "Oil", gasRu: "Gas · RU pipeline", gasLng: "Gas · LNG",
  gasOth: "Gas · NO/NL", coal: "Coal", nuclear: "Nuclear",
  hydro: "Hydro", wind: "Wind", solar: "Solar", biomass: "Biomass",
};

const SECTORS = [
  { id: "trans",    label: "Transport" },
  { id: "resHeat",  label: "Residential heat" },
  { id: "resElec",  label: "Residential elec" },
  { id: "comm",     label: "Commercial" },
  { id: "indHi",    label: "Industry · hi-heat" },
  { id: "indLo",    label: "Industry · lo-heat" },
  { id: "feed",     label: "Chem feedstock" },
  { id: "agri",     label: "Agriculture" },
];

/* world state per year — illustrative TWh and reliability tone */
const STATE = {
  2011: {
    src: { nuclear: 22, coal: 28, gasRu: 16, gasOth: 4, gasLng: 0, oil: 28, hydro: 2, wind: 4, solar: 2, biomass: 6 },
    sec: { trans: "ok", resHeat: "ok", resElec: "ok", comm: "ok", indHi: "ok", indLo: "ok", feed: "ok", agri: "ok" },
    oil: 95, gas: 72, batt: 12,
    dials: { trans: 92, resHeat: 90, ind: 88, comm: 91 },
    gdp: 1.6, costIdx: 102,
  },
  2013: {
    src: { nuclear: 18, coal: 30, gasRu: 17, gasOth: 4, gasLng: 0, oil: 28, hydro: 2, wind: 6, solar: 4, biomass: 7 },
    sec: { trans: "ok", resHeat: "ok", resElec: "ok", comm: "ok", indHi: "warn", indLo: "ok", feed: "ok", agri: "ok" },
    oil: 95, gas: 68, batt: 14,
    dials: { trans: 92, resHeat: 90, ind: 84, comm: 90 },
    gdp: 0.8, costIdx: 108,
  },
  2014: {
    src: { nuclear: 17, coal: 30, gasRu: 16, gasOth: 5, gasLng: 0, oil: 28, hydro: 2, wind: 7, solar: 5, biomass: 7 },
    sec: { trans: "ok", resHeat: "warn", resElec: "ok", comm: "ok", indHi: "warn", indLo: "ok", feed: "warn", agri: "ok" },
    oil: 95, gas: 55, batt: 14,
    dials: { trans: 91, resHeat: 78, ind: 80, comm: 88 },
    gdp: 1.9, costIdx: 118,
  },
  2015: {
    src: { nuclear: 15, coal: 28, gasRu: 15, gasOth: 6, gasLng: 1, oil: 27, hydro: 2, wind: 10, solar: 6, biomass: 8 },
    sec: { trans: "ok", resHeat: "ok", resElec: "ok", comm: "ok", indHi: "warn", indLo: "warn", feed: "warn", agri: "ok" },
    oil: 95, gas: 68, batt: 18,
    dials: { trans: 92, resHeat: 86, ind: 72, comm: 88 },
    gdp: 1.7, costIdx: 122,
  },
  2019: {
    src: { nuclear: 8, coal: 20, gasRu: 17, gasOth: 7, gasLng: 2, oil: 26, hydro: 2, wind: 17, solar: 10, biomass: 9 },
    sec: { trans: "warn", resHeat: "ok", resElec: "ok", comm: "ok", indHi: "warn", indLo: "ok", feed: "ok", agri: "ok" },
    oil: 95, gas: 78, batt: 32,
    dials: { trans: 84, resHeat: 88, ind: 78, comm: 90 },
    gdp: 1.1, costIdx: 132,
  },
  2022: {
    src: { nuclear: 4, coal: 26, gasRu: 4, gasOth: 12, gasLng: 8, oil: 25, hydro: 2, wind: 19, solar: 12, biomass: 9 },
    sec: { trans: "warn", resHeat: "bad", resElec: "warn", comm: "warn", indHi: "bad", indLo: "warn", feed: "bad", agri: "warn" },
    oil: 80, gas: 22, batt: 38,
    dials: { trans: 78, resHeat: 52, ind: 38, comm: 70 },
    gdp: -0.8, costIdx: 198,
  },
  2024: {
    src: { nuclear: 1, coal: 22, gasRu: 2, gasOth: 14, gasLng: 14, oil: 24, hydro: 2, wind: 22, solar: 14, biomass: 9 },
    sec: { trans: "ok", resHeat: "warn", resElec: "ok", comm: "ok", indHi: "bad", indLo: "warn", feed: "warn", agri: "ok" },
    oil: 80, gas: 45, batt: 52,
    dials: { trans: 88, resHeat: 62, ind: 41, comm: 84 },
    gdp: 1.4, costIdx: 172,
  },
  2028: {
    src: { nuclear: 0, coal: 18, gasRu: 0, gasOth: 14, gasLng: 16, oil: 21, hydro: 1, wind: 27, solar: 20, biomass: 9 },
    sec: { trans: "warn", resHeat: "warn", resElec: "warn", comm: "warn", indHi: "bad", indLo: "warn", feed: "warn", agri: "warn" },
    oil: 78, gas: 60, batt: 64,
    dials: { trans: 72, resHeat: 70, ind: 48, comm: 72 },
    gdp: 0.9, costIdx: 164,
  },
  2032: {
    src: { nuclear: 0, coal: 8, gasRu: 0, gasOth: 12, gasLng: 14, oil: 17, hydro: 2, wind: 34, solar: 28, biomass: 10 },
    sec: { trans: "ok", resHeat: "ok", resElec: "ok", comm: "ok", indHi: "warn", indLo: "ok", feed: "warn", agri: "ok" },
    oil: 80, gas: 75, batt: 78,
    dials: { trans: 90, resHeat: 88, ind: 76, comm: 88 },
    gdp: 1.6, costIdx: 138,
  },
};

const TONE_COLOR = { ok: "#4ea36b", warn: "#d49a2a", bad: "#c0392b", crit: "#a01a1a" };
const TONE_TXT   = { ok: "HEALTHY", warn: "STRAINED", bad: "CRITICAL", crit: "FAILING" };

/* ============================================================
   TIMELINE STRIP (top of every in-game screen, also Screen 2)
   ============================================================ */
function TimelineStrip({ year, big }) {
  return (
    <div className={"frg-tline " + (big ? "is-big" : "")}>
      <div className="frg-tline-axis" />
      <div className="frg-tline-yearmark" style={{ left: `${pctY(year)}%` }}>
        <span className="frg-tline-yearbubble">{year}</span>
      </div>
      {[YR_MIN, 2015, 2020, 2025, YR_MAX].map((y) => (
        <span key={y} className="frg-tline-tick" style={{ left: `${pctY(y)}%` }}>{y}</span>
      ))}
      {STATIONS.map((s, i) => {
        const left = pctY(s.year);
        if (s.kind === "mission") {
          return (
            <span key={i} className={"frg-tline-mission " + (s.year === year ? "is-current" : s.year < year ? "is-past" : "")}
              style={{ left: `${left}%` }} title={`M${s.n} · ${s.year} · ${s.label}`}>
              <span className="frg-tline-circle">M{s.n}</span>
              {big && <span className="frg-tline-label">{s.label}<em>{s.year}</em></span>}
            </span>
          );
        }
        return (
          <span key={i} className={"frg-tline-shock"} style={{ left: `${left}%` }} title={`${s.year} · ${s.label}`}>
            <span className="frg-tline-diamond" style={{ background: SHOCK_TONE[s.severity] }} />
            {big && <span className="frg-tline-label">{s.label}<em>{s.year} · {s.severity}</em></span>}
          </span>
        );
      })}
    </div>
  );
}

/* ============================================================
   TWO-BAR VISUALIZATION
   ============================================================ */
function TwoBars({ state, hover, bandsAuto, shockSrc, shockTargets, narrowThermal }) {
  // build segments
  const srcOrder = ["oil","gasRu","gasLng","gasOth","coal","nuclear","hydro","wind","solar","biomass"];
  const total = srcOrder.reduce((a,k) => a + (state.src[k] || 0), 0) || 1;

  const W = 720, H = 460;
  const padTop = 28, padBot = 24;
  const barH = H - padTop - padBot;
  const barW = 56;
  const xSrc = 240, xUse = 480;

  // source layout
  let y = padTop;
  const srcSegs = srcOrder.map((k) => {
    const v = state.src[k] || 0;
    const h = (v / total) * barH;
    const seg = { id: k, color: SRC_COLOR[k], y, h, v, label: SRC_LABEL[k], cy: y + h/2 };
    y += h;
    return seg;
  }).filter(s => s.h > 0.5);

  // sector layout — equal-ish weights tuned for visual
  const SEC_W = { trans: 18, resHeat: 14, resElec: 10, comm: 10, indHi: 14, indLo: 12, feed: 8, agri: 4 };
  const secTotal = Object.values(SEC_W).reduce((a,b)=>a+b,0);
  let y2 = padTop;
  const secSegs = SECTORS.map((s) => {
    const h = (SEC_W[s.id] / secTotal) * barH;
    const tone = state.sec[s.id] || "ok";
    const seg = { id: s.id, label: s.label, y: y2, h, cy: y2 + h/2, tone };
    y2 += h;
    return seg;
  });

  // dependency map: which sectors each source feeds (simplified)
  const DEPS = {
    oil:     ["trans", "indLo", "feed", "agri"],
    gasRu:   ["resHeat", "indHi", "feed", "comm"],
    gasLng:  ["resHeat", "indHi", "indLo", "comm"],
    gasOth:  ["resHeat", "indHi", "indLo"],
    coal:    ["indHi", "resElec", "comm"],
    nuclear: ["resElec", "comm", "indLo"],
    hydro:   ["resElec", "comm"],
    wind:    ["resElec", "comm", "indLo"],
    solar:   ["resElec", "comm"],
    biomass: ["resHeat", "indLo"],
  };

  // bands to draw
  const bands = [];
  const activeSrc = hover && hover.kind === "src" ? hover.id : null;
  const activeSec = hover && hover.kind === "sec" ? hover.id : null;
  const showAll = !!shockSrc;

  function addBand(srcId, secId, value, opts) {
    const src = srcSegs.find(s => s.id === srcId);
    const sec = secSegs.find(s => s.id === secId);
    if (!src || !sec) return;
    const w = Math.max(2, (value || src.h * 0.25));
    bands.push({ src, sec, w, color: SRC_COLOR[srcId], ...(opts||{}) });
  }

  if (activeSrc) {
    const targets = DEPS[activeSrc] || [];
    targets.forEach((t,i) => addBand(activeSrc, t, srcSegs.find(s=>s.id===activeSrc).h / (targets.length+0.6)));
  } else if (activeSec) {
    Object.keys(DEPS).forEach((s) => {
      if (DEPS[s].includes(activeSec)) {
        const src = srcSegs.find(x=>x.id===s);
        if (src) addBand(s, activeSec, src.h * 0.18);
      }
    });
  } else if (shockSrc && shockTargets) {
    shockTargets.forEach((t,i) => addBand(shockSrc, t, 8, { pulse: true, dashed: true }));
  }

  return (
    <svg className="frg-bars" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      <text x={xSrc + barW/2} y={14} className="frg-bars-coltitle" textAnchor="middle">SOURCES · TWh/yr</text>
      <text x={xUse + barW/2} y={14} className="frg-bars-coltitle" textAnchor="middle">END USE · sectors</text>

      {/* bands */}
      <g className="frg-bars-bands">
        {bands.map((b, i) => {
          const x0 = xSrc + barW, x1 = xUse;
          const y0 = b.src.cy, y1 = b.sec.cy;
          const cx = (x0 + x1) / 2;
          const top = `M ${x0} ${y0 - b.w/2}
                       C ${cx} ${y0 - b.w/2}, ${cx} ${y1 - b.w/2}, ${x1} ${y1 - b.w/2}
                       L ${x1} ${y1 + b.w/2}
                       C ${cx} ${y1 + b.w/2}, ${cx} ${y0 + b.w/2}, ${x0} ${y0 + b.w/2} Z`;
          return (
            <path key={i} d={top}
              fill={b.color}
              fillOpacity={b.pulse ? 0.55 : 0.4}
              className={b.pulse ? "frg-band-pulse" : ""}
              stroke={b.dashed ? b.color : "none"}
              strokeWidth={b.dashed ? 0.5 : 0}
              strokeDasharray={b.dashed ? "3 2" : ""}
            />
          );
        })}
      </g>

      {/* source bar */}
      <g>
        {srcSegs.map((s) => {
          const isShock = shockSrc === s.id;
          const dimmed = activeSrc && activeSrc !== s.id;
          return (
            <g key={s.id} className={"frg-src-seg " + (isShock ? "is-shock " : "") + (dimmed ? "is-dim" : "")}>
              <rect x={xSrc} y={s.y} width={barW} height={s.h} fill={s.color} />
              {isShock && (
                <rect x={xSrc-3} y={s.y} width={barW+6} height={s.h} fill="none" stroke="#ef4444" strokeWidth="1.5" />
              )}
              {/* label outside left */}
              <text x={xSrc - 10} y={s.cy + 3} textAnchor="end" className="frg-bars-label">
                {s.label}
              </text>
              <text x={xSrc - 10} y={s.cy + 16} textAnchor="end" className="frg-bars-sublabel">
                {s.v} TWh
              </text>
              {/* embedded storage indicators */}
              {(s.id === "oil" || s.id === "gasOth" || s.id === "wind") && (
                <g>
                  {s.id === "oil" && (
                    <g>
                      <rect x={xSrc+2} y={s.y + s.h - 5} width={barW-4} height={3} fill="rgba(255,255,255,0.18)" />
                      <rect x={xSrc+2} y={s.y + s.h - 5} width={(barW-4) * (state.oil/100)} height={3} fill="#7bd1a5" />
                      <text x={xSrc + barW + 6} y={s.y + s.h - 1} className="frg-bars-store">{state.oil}d res</text>
                    </g>
                  )}
                  {s.id === "gasOth" && (
                    <g>
                      <rect x={xSrc+2} y={s.cy - 1} width={barW-4} height={3} fill="rgba(255,255,255,0.18)" />
                      <rect x={xSrc+2} y={s.cy - 1} width={(barW-4) * (state.gas/100)} height={3}
                        fill={state.gas < 50 ? "#e07c2c" : "#7bd1a5"} />
                      <text x={xSrc + barW + 6} y={s.cy + 3} className="frg-bars-store">{state.gas}% stor</text>
                    </g>
                  )}
                  {s.id === "wind" && (
                    <g>
                      <rect x={xSrc+2} y={s.cy - 1} width={barW-4} height={3} fill="rgba(255,255,255,0.18)" />
                      <rect x={xSrc+2} y={s.cy - 1} width={(barW-4) * (state.batt/100)} height={3} fill="#7bd1a5" />
                      <text x={xSrc + barW + 6} y={s.cy + 3} className="frg-bars-store">{state.batt}% batt</text>
                    </g>
                  )}
                </g>
              )}
            </g>
          );
        })}
      </g>

      {/* sector bar */}
      <g>
        {secSegs.map((s) => {
          const dimmed = activeSec && activeSec !== s.id;
          return (
            <g key={s.id} className={"frg-sec-seg " + (dimmed ? "is-dim" : "")}>
              <rect x={xUse} y={s.y} width={barW} height={s.h} fill={TONE_COLOR[s.tone]} />
              <text x={xUse + barW + 10} y={s.cy + 3} className="frg-bars-label">{s.label}</text>
              <text x={xUse + barW + 10} y={s.cy + 16} className="frg-bars-sublabel" fill={TONE_COLOR[s.tone]}>
                {TONE_TXT[s.tone]}
              </text>
            </g>
          );
        })}
      </g>

      {/* hover hint */}
      <text x={W/2} y={H - 6} textAnchor="middle" className="frg-bars-hint">
        Hover a segment to reveal source ↔ sector dependencies
      </text>
    </svg>
  );
}

/* ============================================================
   RIGHT RAIL
   ============================================================ */
function Dial({ label, value }) {
  const tone = value >= 80 ? "ok" : value >= 60 ? "warn" : "bad";
  const r = 24, cx = 28, cy = 28;
  const a0 = -120 * Math.PI/180, a1 = 120 * Math.PI/180;
  const cur = a0 + (value/100) * (a1 - a0);
  const arc = (s, e, col, w) => {
    const x0 = cx + r*Math.cos(s), y0 = cy + r*Math.sin(s);
    const x1 = cx + r*Math.cos(e), y1 = cy + r*Math.sin(e);
    const lg = (e - s) > Math.PI ? 1 : 0;
    return <path d={`M${x0} ${y0} A ${r} ${r} 0 ${lg} 1 ${x1} ${y1}`} fill="none" stroke={col} strokeWidth={w} />;
  };
  return (
    <div className="frg-rail-dial">
      <svg width="56" height="44" viewBox="0 0 56 44">
        {arc(a0, a1, "#1e2640", 3.5)}
        {arc(a0, cur, TONE_COLOR[tone], 3.5)}
        <text x="28" y="30" textAnchor="middle" className="frg-dial-num">{value}</text>
      </svg>
      <span className="frg-dial-lbl">{label}</span>
    </div>
  );
}

function MiniSpark({ label, points, accent, val, unit, delta }) {
  const W = 168, H = 32;
  const p = points.map((y,i) => `${(i/(points.length-1))*W},${H - y*H}`).join(" ");
  return (
    <div className="frg-rail-spark">
      <div className="frg-rail-spark-top">
        <span>{label}</span>
        <span><b>{val}</b><i>{unit}</i><em className={delta < 0 ? "dn" : "up"}>{delta > 0 ? "▲" : "▼"} {Math.abs(delta)}</em></span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" width="100%" height={H}>
        <polyline points={p} fill="none" stroke={accent} strokeWidth="1.4" vectorEffect="non-scaling-stroke" />
      </svg>
    </div>
  );
}

function RightRail({ year, state }) {
  const gdpPts  = [0.5,0.55,0.6,0.66,0.62,0.7,0.75,0.78,0.82,0.6,0.7,0.78,0.82,0.85];
  const costPts = [0.3,0.32,0.36,0.4,0.48,0.5,0.52,0.6,0.62,0.92,0.84,0.74,0.7,0.68];
  return (
    <aside className="frg-rail">
      <div className="frg-rail-year">
        <span className="frg-rail-year-lbl">YEAR</span>
        <span className="frg-rail-year-num">{year}</span>
      </div>
      <div className="frg-rail-sec">
        <div className="frg-rail-title">SECTOR RELIABILITY</div>
        <div className="frg-rail-dials">
          <Dial label="Transport"   value={state.dials.trans} />
          <Dial label="Residential" value={state.dials.resHeat} />
          <Dial label="Industrial"  value={state.dials.ind} />
          <Dial label="Commercial"  value={state.dials.comm} />
        </div>
      </div>
      <div className="frg-rail-sec">
        <div className="frg-rail-title">RESERVES</div>
        <div className="frg-rail-bar">
          <div className="frg-rail-bar-row"><span>Oil reserve</span><b>{state.oil}d</b></div>
          <div className="frg-rail-bar-track"><div style={{width: `${state.oil}%`, background: state.oil > 60 ? "#4ea36b" : "#d49a2a"}} /></div>
        </div>
        <div className="frg-rail-bar">
          <div className="frg-rail-bar-row"><span>Gas storage</span><b>{state.gas}%</b><i className="frg-rail-bench" title="seasonal benchmark 70%">·70</i></div>
          <div className="frg-rail-bar-track">
            <div style={{width: `${state.gas}%`, background: state.gas > 60 ? "#4ea36b" : state.gas > 30 ? "#d49a2a" : "#c0392b"}} />
            <span className="frg-rail-bar-bench" style={{left: "70%"}} />
          </div>
        </div>
        <div className="frg-rail-bar">
          <div className="frg-rail-bar-row"><span>Battery/hydro</span><b>{state.batt}%</b></div>
          <div className="frg-rail-bar-track"><div style={{width: `${state.batt}%`, background: "#7bd1a5"}} /></div>
        </div>
      </div>
      <div className="frg-rail-sec">
        <div className="frg-rail-title">MACRO</div>
        <MiniSpark label="GDP index" val={state.gdp} unit="%" delta={state.gdp} accent="#4ea36b" points={gdpPts} />
        <MiniSpark label="Energy cost" val={state.costIdx} unit=" idx" delta={state.costIdx - 100} accent="#d49a2a" points={costPts} />
      </div>
    </aside>
  );
}

/* ============================================================
   CONSTRUCTION QUEUE (collapsible)
   ============================================================ */
function QueueStrip({ openByDefault, items, year }) {
  const [open, setOpen] = fU(!!openByDefault);
  const yMin = 2010, yMax = 2032;
  const colorOf = (k) => ({ lng: "#d97706", wind: "#0e7c66", grid: "#1e293b", nuc: "#6d28d9", solar: "#d4a017", coal: "#3a3a3a" })[k] || "#666";
  return (
    <div className={"frg-queue " + (open ? "is-open" : "")}>
      <button className="frg-queue-toggle" onClick={() => setOpen(o=>!o)}>
        <span className="frg-queue-chev">{open ? "▾" : "▸"}</span>
        <span className="frg-queue-title">CONSTRUCTION QUEUE</span>
        <span className="frg-queue-count">{items.length} projects in flight</span>
      </button>
      {open && (
        <div className="frg-queue-track">
          <div className="frg-queue-axis">
            {[2010,2015,2020,2025,2030].map(y =>
              <span key={y} className="frg-queue-tick" style={{left: `${(y-yMin)/(yMax-yMin)*100}%`}}>{y}</span>
            )}
            <span className="frg-queue-now" style={{left: `${(year-yMin)/(yMax-yMin)*100}%`}}><i>NOW {year}</i></span>
          </div>
          <div className="frg-queue-rows">
            {items.map((it,i) => {
              const l = (it.start-yMin)/(yMax-yMin)*100;
              const w = (it.eta-it.start)/(yMax-yMin)*100;
              const done = Math.min(100, Math.max(0, ((year-it.start)/(it.eta-it.start))*100));
              return (
                <div key={i} className="frg-queue-row">
                  <div className="frg-queue-meta"><span style={{color: colorOf(it.kind)}}>● {it.type}</span></div>
                  <div className="frg-queue-bar-wrap">
                    <div className="frg-queue-bar" style={{left: `${l}%`, width: `${w}%`, borderColor: colorOf(it.kind)}}>
                      <div className="frg-queue-bar-fill" style={{width: `${done}%`, background: colorOf(it.kind)}} />
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

/* ============================================================
   MISSION / SHOCK PANELS
   ============================================================ */
function MissionPanel({ num, year, title, brief, choices, picked: pickedInit, collapsed }) {
  const [picked, setPicked] = fU(pickedInit || "B");
  if (collapsed) {
    return (
      <div className="frg-mission is-collapsed">
        <div className="frg-collapsed-row">
          <span className="frg-mission-num">M·0{num}</span>
          <span className="frg-mission-collapsed-title">{title}</span>
          <span className="frg-mission-collapsed-meta">Decision committed · time progressing</span>
        </div>
      </div>
    );
  }
  return (
    <section className="frg-mission">
      <header className="frg-mission-head">
        <div className="frg-mission-tag">
          <span className="frg-mission-num">M·0{num}</span>
          <span className="frg-mission-tagline">MISSION ACTIVE · TIME PAUSED FOR DECISION</span>
        </div>
        <div className="frg-mission-meta">
          <span><b>YEAR</b> {year}</span>
          <span><b>SELECTED</b> {picked}</span>
        </div>
      </header>
      <div className="frg-mission-body">
        <h1 className="frg-mission-title">{title}</h1>
        <p className="frg-mission-brief">{brief}</p>
        <div className="frg-choice-grid">
          {choices.map((c) => (
            <button key={c.key} className={"frg-choice " + (picked === c.key ? "is-picked" : "")}
              onClick={() => setPicked(c.key)}>
              <div className="frg-choice-head">
                <span className="frg-choice-key">{c.key}</span>
                <span className="frg-choice-tag">{c.tag}</span>
              </div>
              <div className="frg-choice-title">{c.title}</div>
              <div className="frg-choice-lead">{c.lead}</div>
              <div className="frg-choice-foot">
                <span>{c.cost}</span><span className="frg-choice-sep">·</span><span>{c.time}</span>
              </div>
            </button>
          ))}
        </div>
      </div>
      <footer className="frg-mission-foot">
        <span className="frg-mission-foot-meta">SELECTED · <b>{picked}</b></span>
        <button className="frg-mission-submit">Commit decision →</button>
      </footer>
    </section>
  );
}

function ShockPanel({ year, severity, title, brief, choices }) {
  const [picked, setPicked] = fU("A");
  return (
    <section className={"frg-shock is-" + severity}>
      <header className="frg-shock-head">
        <div className="frg-shock-tag">
          <span className="frg-shock-glyph">◆</span>
          <span className="frg-shock-label">SHOCK · {severity.toUpperCase()} · {year}</span>
        </div>
        <div className="frg-shock-meta">EMERGENCY RESPONSE REQUIRED</div>
      </header>
      <div className="frg-mission-body">
        <h1 className="frg-mission-title">{title}</h1>
        <p className="frg-mission-brief">{brief}</p>
        <div className="frg-choice-grid">
          {choices.map((c) => (
            <button key={c.key} className={"frg-choice frg-choice-shock " + (picked === c.key ? "is-picked" : "")}
              onClick={() => setPicked(c.key)}>
              <div className="frg-choice-head">
                <span className="frg-choice-key">{c.key}</span>
                <span className="frg-choice-tag">{c.tag || ""}</span>
              </div>
              <div className="frg-choice-title">{c.title}</div>
              <div className="frg-choice-lead">{c.lead}</div>
            </button>
          ))}
        </div>
      </div>
      <footer className="frg-mission-foot">
        <span className="frg-mission-foot-meta">SELECTED · <b>{picked}</b></span>
        <button className="frg-mission-submit is-urgent">Commit response →</button>
      </footer>
    </section>
  );
}

/* ============================================================
   DASHBOARD FRAME (shared chrome — screens 3-10)
   ============================================================ */
function DashboardFrame({ year, panel, queue, hover, shockSrc, shockTargets, narrowThermal, newsFlash, transitionTicker }) {
  const state = STATE[year] || STATE[2024];
  return (
    <div className="frg-root">
      <div className="frg-topbar">
        <div className="frg-topbar-brand">
          <span className="frg-topbar-dot" />
          <span className="frg-topbar-name">FRAGILITY</span>
          <span className="frg-topbar-sep">/</span>
          <span className="frg-topbar-camp">Energiewende Stress Test · 2010–2032</span>
        </div>
        <div className="frg-topbar-status">{transitionTicker ? <span>⏵ TIME ADVANCING · {transitionTicker}</span> : <span>⏸ {panel?.kind === "shock" ? "SHOCK · PAUSED" : "PAUSED"}</span>}</div>
      </div>
      <TimelineStrip year={year} />
      {panel}
      <div className="frg-stage">
        <div className="frg-stage-main">
          {newsFlash && <div className="frg-news-flash"><b>NEWS · {newsFlash.year}</b> {newsFlash.body}</div>}
          <TwoBars state={state} hover={hover} shockSrc={shockSrc} shockTargets={shockTargets} narrowThermal={narrowThermal} />
          {queue}
        </div>
        <RightRail year={year} state={state} />
      </div>
    </div>
  );
}

/* ============================================================
   SCREEN 1 — Home
   ============================================================ */
function ScreenHome() {
  return (
    <div className="frg-root frg-home">
      <header className="frg-home-top">
        <span className="frg-topbar-dot" />
        <span className="frg-topbar-name">FRAGILITY</span>
      </header>
      <main className="frg-home-main">
        <h1 className="frg-home-title">Energy systems<br/>under pressure.</h1>
        <p className="frg-home-tag">An interactive simulation of energy fragility.</p>
        <button className="frg-home-cta">Start new campaign →</button>

        <div className="frg-home-libtitle">CAMPAIGN LIBRARY</div>
        <div className="frg-home-grid">
          <article className="frg-home-card frg-home-card-active">
            <header className="frg-home-card-head">
              <span className="frg-home-card-flag">DE</span>
              <span className="frg-home-card-era">2010 → 2032</span>
              <span className="frg-home-card-diff">DIFFICULTY · 4/5</span>
            </header>
            <h3 className="frg-home-card-title">The Energiewende Stress Test</h3>
            <p className="frg-home-card-lead">
              Steer Germany through the nuclear phase-out, two gas shocks, and a climate-era
              drought. Choose how to build resilience over 22 years of decisions.
            </p>
            <div className="frg-home-card-meta">
              <span>5 missions</span><i>·</i><span>3 shocks</span><i>·</i><span>~40 min</span>
            </div>
          </article>
          <article className="frg-home-card frg-home-card-empty">
            <div className="frg-home-empty-glyph">+</div>
            <div className="frg-home-empty-lbl">More campaigns coming</div>
            <div className="frg-home-empty-sub">UK · 2008–2030<br/>Japan · post-Fukushima<br/>India · 2020–2045</div>
          </article>
        </div>
      </main>
      <footer className="frg-home-foot">
        <div>
          <a href="#">About</a><span>·</span><a href="#">Methodology</a><span>·</span><a href="#">Learn more</a>
        </div>
        <div className="frg-home-foot-meta">FRAGILITY · v 0.4 · data sourced from IEA, BMWK, AGEB</div>
      </footer>
    </div>
  );
}

/* ============================================================
   SCREEN 2 — Campaign overview
   ============================================================ */
function ScreenOverview() {
  return (
    <div className="frg-root frg-over">
      <header className="frg-over-head">
        <div className="frg-over-tag">CAMPAIGN · DE · 22 YEARS</div>
        <h1 className="frg-over-title">The Energiewende Stress Test</h1>
        <p className="frg-over-narr">
          In 2010, Germany sets out to phase out nuclear power, decarbonize its industry, and rewire
          its grid. Three shocks lie ahead — a diplomatic crisis, a pipeline cutoff, and a climate
          emergency. The decisions you commit early will reshape what's possible in the 2020s.
        </p>
      </header>

      <div className="frg-over-tline-wrap">
        <TimelineStrip year={2010} big />
      </div>

      <section className="frg-over-learn">
        <div className="frg-over-learn-title">WHAT YOU'LL LEARN</div>
        <div className="frg-over-learn-grid">
          <div><b>Source dependencies</b><p>How a single import route can underpin half of industrial heat.</p></div>
          <div><b>Sector vulnerabilities</b><p>Why chemical feedstock, residential heat, and steel each break differently.</p></div>
          <div><b>Lead-time tradeoffs</b><p>Why some answers take 12 months and others 12 years to deliver capacity.</p></div>
          <div><b>Path dependency</b><p>How a 2011 decision quietly determines the menu of options available in 2024.</p></div>
        </div>
      </section>

      <footer className="frg-over-foot">
        <div className="frg-over-foot-meta">5 missions · 3 telegraphed shocks · time tick 2.5s/year</div>
        <button className="frg-mission-submit">Begin campaign →</button>
      </footer>
    </div>
  );
}

/* ============================================================
   SCREEN BUILDERS for missions / shocks
   ============================================================ */
const M1 = {
  num: 1, year: 2011,
  title: "Decommission 8 reactors by 2022 while keeping the lights on.",
  brief: "Post-Fukushima, the Bundestag has voted to phase out 8 reactors by 2022. Choose how to replace 12 GW of baseload without losing reliability — and without overshooting emissions targets.",
  choices: [
    { key:"A", tag:"Gas bridge",  title:"Gas plants + imports", lead:"Build CCGT capacity; sign long-term Russian + Norwegian gas.", cost:"€14B", time:"3–5 years" },
    { key:"B", tag:"Renewables",  title:"Wind + solar + grid",  lead:"Tender 8 GW offshore wind, scale rooftop solar, expand HVDC.",   cost:"€38B", time:"6–9 years" },
    { key:"C", tag:"Coal life-ext", title:"Retrofit coal fleet", lead:"Extend lignite and hard-coal plants; defer retirements.",         cost:"€8B",  time:"2–3 years" },
    { key:"D", tag:"Mixed",       title:"Phased mix",            lead:"Balanced gas + renewables + national efficiency mandate.",      cost:"€24B", time:"4–7 years" },
  ],
  picked: "A",
};

const S1 = {
  year: 2014, severity: "minor",
  title: "Russian annexation of Crimea — gas markets tighten.",
  brief: "Spot gas prices spike 30%; storage drawdown accelerates ahead of winter. The crisis is not, yet, existential — but it is the first reminder that 40% of pipeline gas runs through one geography.",
  choices: [
    { key:"A", title:"Expand strategic gas storage", lead:"Top up reserves; +14 days of cover by Q4.", tag:"Hedge" },
    { key:"B", title:"Pass spike through to consumers", lead:"No new spend; absorb political cost.", tag:"Market" },
    { key:"C", title:"Diversify supply contracts now", lead:"Norway + NL long-term; small new LNG pilot.", tag:"Diversify" },
  ],
};

const M2 = {
  num: 2, year: 2015,
  title: "Stop industrial competitiveness from cracking.",
  brief: "Industrial energy costs are 38% above the EU average. Chemicals and steel are warning about relocation. Defend competitiveness without abandoning the transition.",
  choices: [
    { key:"A", tag:"Tax relief",  title:"Industrial elec tax exemption", lead:"Carve-out for energy-intensive sectors; €6B/yr budget cost.", cost:"€6B/yr", time:"immediate" },
    { key:"B", tag:"Domestic gas",title:"Push for shale exploration",    lead:"Lift moratorium in 2 Länder; political backlash certain.",     cost:"€2B",    time:"4–6 years" },
    { key:"C", tag:"H₂ pilot",    title:"Early hydrogen programs",       lead:"Co-fund 4 industrial pilot sites; long-term bet.",              cost:"€4B",    time:"5–10 years" },
    { key:"D", tag:"EU",          title:"Deepen EU energy market",       lead:"Couple price zones; cross-border capacity auctions.",          cost:"€1B",    time:"slow" },
  ],
  picked: "A",
};

const M3 = {
  num: 3, year: 2019,
  title: "Cut emissions 40% by 2025 — the trajectory falls short by 12 pp.",
  brief: "Treaty deadlines are approaching; current policy mix is not enough. Pick the dominant lever for the next half-decade.",
  choices: [
    { key:"A", tag:"Coal exit",  title:"Accelerated coal phase-out",  lead:"Bring exit forward to 2030; transition fund for regions.",        cost:"€20B", time:"5–7 years" },
    { key:"B", tag:"Heat",       title:"National heat-pump rollout",  lead:"Subsidy + tradesperson training; electrification accelerates.",   cost:"€18B", time:"5–8 years" },
    { key:"C", tag:"Transport",  title:"EV mandate + chargers",        lead:"2030 sales mandate; €12B charging build-out.",                   cost:"€12B", time:"long" },
    { key:"D", tag:"Carbon",     title:"Tighten ETS price floor",     lead:"Carbon price floor; market-driven pace, less direct control.",   cost:"—",    time:"market" },
  ],
  picked: "B",
};

const S2 = {
  year: 2022, severity: "major",
  title: "Russian pipeline gas cut off mid-year.",
  brief: "Heating, power generation, and chemical-industry feedstock are hit simultaneously. Forecasters now expect industrial output to drop 6–8% peak-to-trough. Storage sits at 22% with winter four months away.",
  choices: [
    { key:"A", title:"Ration industrial use", lead:"Protect residential heat; allocate cuts via auction.", tag:"Ration" },
    { key:"B", title:"Mandate temperature limits", lead:"19°C public buildings; efficiency campaign.", tag:"Demand" },
    { key:"C", title:"Emergency LNG charters", lead:"Spot-market charters at +€8B; sign 18-month deals.", tag:"Supply" },
    { key:"D", title:"Reactivate coal capacity", lead:"Pull mothballed lignite back online for 24 months.", tag:"Coal" },
  ],
};

const M4 = {
  num: 4, year: 2024,
  title: "Rebuild energy security in 5 years.",
  brief: "Russian pipeline gas is gone. Industrial output dropped 6.4% peak-to-trough; chemical feedstock supply still 32% below 2010. Residential reliability is recovering but gas storage sits below the seasonal benchmark. Choose your primary strategic posture.",
  choices: [
    { key:"A", tag:"Supply security", title:"LNG terminal expansion", lead:"4 floating + 2 fixed LNG terminals; 15-yr Qatari & US contracts.", cost:"€18B", time:"18–30 mo" },
    { key:"B", tag:"Decarbonized",    title:"Renewables + green H₂",  lead:"Double offshore tender; 10 GW electrolyser pipeline; NL/NO corridor.", cost:"€42B", time:"5–8 yr" },
    { key:"C", tag:"Baseload",        title:"Nuclear restart",        lead:"Reverse 2023 shutdowns; restart Isar-2 + Neckarwestheim-2.",          cost:"€6B",  time:"12–18 mo" },
    { key:"D", tag:"Diplomatic",      title:"Diversified imports",    lead:"NO +20%, Algeria via Italy, Azerbaijan via TAP, US LNG framework.",   cost:"€4B",  time:"2–4 yr" },
  ],
  picked: "B",
};

const S3 = {
  year: 2028, severity: "severe",
  title: "Rhine drought + heatwave hits the grid backbone.",
  brief: "Low river levels disrupt thermal plant cooling and halt fuel barge transport. A concurrent heatwave drives cooling demand 18% above forecast. The event is now expected to last 3–5 weeks.",
  choices: [
    { key:"A", title:"Curtail industrial customers", lead:"Preserve grid stability; protect residential.", tag:"Curtail" },
    { key:"B", title:"Dispatch every reserve", lead:"Accept very high marginal cost; burn through batteries.", tag:"Dispatch" },
    { key:"C", title:"Rolling blackouts by sector", lead:"Pre-scheduled, communicated 24h ahead.", tag:"Blackout" },
    { key:"D", title:"Emergency imports", lead:"FR + NL + DK; depends on neighbours' capacity.", tag:"Imports" },
  ],
};

/* canned construction queues */
const QUEUE_2013 = [
  { type:"Wind · onshore",    start:2011, eta:2014, kind:"wind" },
  { type:"Gas CCGT",          start:2012, eta:2015, kind:"grid" },
  { type:"Nuclear decom.",    start:2011, eta:2013, kind:"nuc" },
  { type:"Solar PV (DE-S)",   start:2013, eta:2016, kind:"solar" },
];
const QUEUE_2024 = [
  { type:"LNG terminal",      start:2023, eta:2026, kind:"lng" },
  { type:"Offshore wind",     start:2022, eta:2025, kind:"wind" },
  { type:"Offshore wind",     start:2023, eta:2026, kind:"wind" },
  { type:"HVDC corridor",     start:2021, eta:2027, kind:"grid" },
  { type:"Nuclear decom.",    start:2023, eta:2024, kind:"nuc" },
];

/* ============================================================
   SCREEN 11 — Recap
   ============================================================ */
function ScreenRecap() {
  const state = STATE[2032];
  // radar — 5 axes, player vs historical
  const axes = [
    { k:"Reliability",     player: 78, hist: 70 },
    { k:"Affordability",   player: 62, hist: 48 },
    { k:"Growth",          player: 72, hist: 64 },
    { k:"Emissions",       player: 82, hist: 64 },
    { k:"Independence",    player: 68, hist: 42 },
  ];
  const cx = 160, cy = 160, R = 120;
  const ptsFor = (vals) => vals.map((v,i) => {
    const a = -Math.PI/2 + (i * 2*Math.PI / axes.length);
    const r = (v/100) * R;
    return `${cx + r*Math.cos(a)},${cy + r*Math.sin(a)}`;
  }).join(" ");

  return (
    <div className="frg-root frg-recap">
      <div className="frg-topbar">
        <div className="frg-topbar-brand">
          <span className="frg-topbar-dot" />
          <span className="frg-topbar-name">FRAGILITY</span>
          <span className="frg-topbar-sep">/</span>
          <span className="frg-topbar-camp">Campaign complete · 2010–2032</span>
        </div>
        <div className="frg-topbar-status"><span>✓ FINAL SCORE</span></div>
      </div>
      <TimelineStrip year={2032} />

      <header className="frg-recap-head">
        <h1 className="frg-recap-title">Your Germany, 2032.</h1>
        <p className="frg-recap-sub">
          You ran a renewables-led, gas-hedged transition. Storage is rebuilt; industry is wobbly but
          intact; emissions cleared the 2025 treaty line by 4 percentage points.
        </p>
      </header>

      <div className="frg-recap-grid">
        <section className="frg-recap-card">
          <div className="frg-recap-card-title">COMPOSITE OUTCOME · YOU VS HISTORICAL</div>
          <svg width="320" height="320" viewBox="0 0 320 320">
            {[0.25, 0.5, 0.75, 1].map((r,i) => (
              <polygon key={i}
                points={axes.map((_,j) => {
                  const a = -Math.PI/2 + (j * 2*Math.PI / axes.length);
                  return `${cx + R*r*Math.cos(a)},${cy + R*r*Math.sin(a)}`;
                }).join(" ")}
                fill="none" stroke="#22304a" strokeWidth="0.5" />
            ))}
            {axes.map((ax,i) => {
              const a = -Math.PI/2 + (i * 2*Math.PI / axes.length);
              return <line key={i} x1={cx} y1={cy} x2={cx + R*Math.cos(a)} y2={cy + R*Math.sin(a)} stroke="#22304a" strokeWidth="0.5" />;
            })}
            <polygon points={ptsFor(axes.map(a=>a.hist))} fill="#5b6470" fillOpacity="0.3" stroke="#9aa3b0" strokeWidth="1" />
            <polygon points={ptsFor(axes.map(a=>a.player))} fill="#3f6e78" fillOpacity="0.35" stroke="#5e93a0" strokeWidth="1.5" />
            {axes.map((ax,i) => {
              const a = -Math.PI/2 + (i * 2*Math.PI / axes.length);
              return (
                <g key={i}>
                  <text x={cx + (R+18)*Math.cos(a)} y={cy + (R+18)*Math.sin(a)} textAnchor="middle" className="frg-radar-label">{ax.k}</text>
                  <text x={cx + (R+34)*Math.cos(a)} y={cy + (R+34)*Math.sin(a) + 2} textAnchor="middle" className="frg-radar-val">{ax.player}<tspan className="frg-radar-hist"> · h {ax.hist}</tspan></text>
                </g>
              );
            })}
          </svg>
          <div className="frg-recap-legend">
            <span><i style={{background:"#5e93a0"}} /> Your run</span>
            <span><i style={{background:"#9aa3b0"}} /> Historical DE</span>
          </div>
        </section>

        <section className="frg-recap-card">
          <div className="frg-recap-card-title">2032 SYSTEM COMPOSITION</div>
          <TwoBars state={state} />
        </section>
      </div>

      <section className="frg-recap-counter">
        <div className="frg-recap-card-title">COUNTERFACTUAL HIGHLIGHTS</div>
        <ul className="frg-recap-cf">
          <li>
            <b>2011 · Gas bridge → Renewables push</b>
            <p>If you'd picked the renewables build-out instead of CCGT capacity, the 2022 cutoff would have been 40% less damaging — but industrial costs would have run 18% higher through 2015–2019.</p>
          </li>
          <li>
            <b>2019 · Heat pumps over coal exit</b>
            <p>Heat-pump rollout cleared the 2025 emissions line. Picking accelerated coal exit instead would have cleared 2025 too — but left an extra 18 TWh of winter gas demand exposed in 2022.</p>
          </li>
          <li>
            <b>2024 · Renewables + H₂ over LNG expansion</b>
            <p>Locked in lower long-run costs and independence; pays back in 2028 when the drought hits and you don't need to ration LNG cargoes. Cost trajectory diverges from historical DE after 2026.</p>
          </li>
        </ul>
      </section>

      <section className="frg-recap-scoreboard">
        <div className="frg-recap-card-title">LEADERBOARD</div>
        <ol className="frg-recap-lb">
          <li><span>1.</span><b>j.okafor</b><i>818</i><em>Renewables + diplomatic</em></li>
          <li className="is-you"><span>2.</span><b>YOU</b><i>764</i><em>Renewables + H₂ · gas hedge</em></li>
          <li><span>3.</span><b>m.weber</b><i>752</i><em>Coal exit · diversified imports</em></li>
          <li><span>4.</span><b>Historical DE</b><i>614</i><em>Real-world outcome</em></li>
          <li><span>5.</span><b>r.singh</b><i>588</i><em>Nuclear restart</em></li>
        </ol>
      </section>

      <footer className="frg-recap-cta">
        <button className="frg-mission-submit">Start a new campaign →</button>
        <button className="frg-cta-secondary">Replay with different choices</button>
      </footer>
    </div>
  );
}

/* ============================================================
   ROOT — wraps the 11 artboards in a DesignCanvas
   ============================================================ */
function FragilityView() {
  const DC = window.DesignCanvas, DCSection = window.DCSection, DCArtboard = window.DCArtboard;
  if (!DC) {
    return <div style={{padding: 40, fontFamily: "monospace"}}>Loading canvas…</div>;
  }
  const screens = [
    { id:"home",     label:"01 · Home",                  w: 1280, h: 800,  el: <ScreenHome /> },
    { id:"overview", label:"02 · Campaign overview",     w: 1280, h: 760,  el: <ScreenOverview /> },
    { id:"m1",       label:"03 · Mission 1 · 2011",      w: 1280, h: 1180, el:
      <DashboardFrame year={2011}
        panel={<MissionPanel {...M1} />}
        queue={<QueueStrip items={QUEUE_2013.slice(0,2)} year={2011} />}
      /> },
    { id:"trans",    label:"04 · Time passing · 2013",   w: 1280, h: 1000, el:
      <DashboardFrame year={2013}
        transitionTicker="tick 2013"
        panel={<MissionPanel {...M1} collapsed />}
        queue={<QueueStrip items={QUEUE_2013} year={2013} openByDefault />}
        newsFlash={{ year: 2013, body: "First decommissioned reactor offline · 1.4 GW lost · gas spot +12%" }}
      /> },
    { id:"s1",       label:"05 · Shock 1 · Crimea 2014", w: 1280, h: 1080, el:
      <DashboardFrame year={2014}
        panel={<ShockPanel {...S1} />}
        queue={<QueueStrip items={QUEUE_2013} year={2014} />}
        shockSrc="gasRu" shockTargets={["resHeat","indHi"]}
      /> },
    { id:"m2",       label:"06 · Mission 2 · 2015",      w: 1280, h: 1180, el:
      <DashboardFrame year={2015}
        panel={<MissionPanel {...M2} />}
        queue={<QueueStrip items={QUEUE_2013.slice(1)} year={2015} />}
      /> },
    { id:"m3",       label:"07 · Mission 3 · 2019",      w: 1280, h: 1180, el:
      <DashboardFrame year={2019}
        panel={<MissionPanel {...M3} />}
        queue={<QueueStrip items={[
          { type:"Offshore wind", start:2017, eta:2020, kind:"wind" },
          { type:"Solar PV", start:2018, eta:2021, kind:"solar" },
          { type:"Coal retire", start:2019, eta:2022, kind:"coal" },
        ]} year={2019} />}
      /> },
    { id:"s2",       label:"08 · Shock 2 · Gas cutoff 2022", w: 1280, h: 1100, el:
      <DashboardFrame year={2022}
        panel={<ShockPanel {...S2} />}
        queue={<QueueStrip items={[
          { type:"LNG terminal · floating", start:2022, eta:2023, kind:"lng" },
          { type:"Offshore wind", start:2020, eta:2024, kind:"wind" },
        ]} year={2022} openByDefault />}
        shockSrc="gasRu" shockTargets={["resHeat","indHi","feed"]}
      /> },
    { id:"m4",       label:"09 · Mission 4 · 2024",      w: 1280, h: 1220, el:
      <DashboardFrame year={2024}
        panel={<MissionPanel {...M4} />}
        queue={<QueueStrip items={QUEUE_2024} year={2024} openByDefault />}
        hover={{ kind: "src", id: "gasLng" }}
      /> },
    { id:"s3",       label:"10 · Shock 3 · Rhine 2028",  w: 1280, h: 1100, el:
      <DashboardFrame year={2028}
        panel={<ShockPanel {...S3} />}
        queue={<QueueStrip items={[
          { type:"HVDC corridor", start:2025, eta:2029, kind:"grid" },
          { type:"Battery park",  start:2027, eta:2029, kind:"wind" },
        ]} year={2028} />}
        shockSrc="hydro" shockTargets={["resElec","comm","trans"]}
        newsFlash={{ year: 2028, body: "Cooling demand +18% above forecast · barge traffic on Rhine halted" }}
      /> },
    { id:"recap",    label:"11 · End of campaign · 2032", w: 1280, h: 1340, el:
      <ScreenRecap /> },
  ];

  return (
    <DC title="Fragility · campaign storyboard" subtitle="Eleven screens covering the full Germany 2010–2032 run">
      <DCSection id="story" title="Player journey">
        {screens.map((s) => (
          <DCArtboard key={s.id} id={s.id} label={s.label} width={s.w} height={s.h}>
            {s.el}
          </DCArtboard>
        ))}
      </DCSection>
    </DC>
  );
}

window.FragilityView = FragilityView;
