/* ============================================================
   Prototype stage kit (MySubaru)

   The three Subaru cases embed the same interactive prototypes the interview
   deck used. This file holds the shared shells so every case presents them
   the same way: a phone at the deck's proportions, a wide desktop embed that
   scales to its column, and a caption that carries the deck's own label.

   The animation is driven from subaru-demos.js, which finds a stage by the
   data-demo id written here. Those ids are the deck's slide ids on purpose:
   s39-1 is the first prototype on deck slide 39, so the two stay traceable.
   ============================================================ */
(function () {
  const EMB = "assets/subaru/embeds/";
  /* Embeds sit behind an hour-long cache on the host; the version query
     retires stale copies whenever the embed files themselves change. */
  const EMB_V = "?v=bare2";
  function embSrc(src) {
    return EMB + src + (src.indexOf("?") === -1 ? EMB_V : "");
  }

  function FullLink(props) {
    return (
      <a href={EMB + props.src} target="_blank" rel="noopener noreferrer"
        style={{ color: "var(--accent)", textDecoration: "none", whiteSpace: "nowrap", fontSize: 12.5 }}>
        Open full screen
      </a>
    );
  }

  /* The device and its caption are separate pieces so a row can seat them
     differently: under the phone in a gallery of several, beside the pair
     when there are exactly two. */
  function Slot(props) {
    return (
      <div className="pp-slot" data-demo={props.demo}>
        <iframe title={props.title} data-src={embSrc(props.src)} scrolling="no" loading="lazy" />
      </div>
    );
  }
  function Cap(props) {
    return (
      <div className="pp-cap">
        <div className="pp-lab">
          {props.badge ? <b>{props.badge}</b> : null}
          <span className="pp-live"><i />{props.status || "live"}</span>
        </div>
        {props.note ? <p className="pp-note">{props.note}</p> : null}
        <FullLink src={props.src} />
      </div>
    );
  }

  /* One phone prototype. Passing `demo` hands it to the deck's scenario of
     that id, which walks the interface on its own; hovering gives control
     back to the reader. Omitting `demo` leaves it purely explorable. */
  function Phone(props) {
    return (
      <div className="pp-col">
        <div className="pp-halo">
          <Slot {...props} />
        </div>
        <Cap {...props} />
      </div>
    );
  }

  /* A row of prototypes. Exactly two phones become a duo: the pair sits
     together and both descriptions move to a shared column at its side,
     so the row's width is spent on reading rather than on empty margin.
     `compare` turns a longer row into a swipeable strip on a narrow
     screen so an A/B set stays side by side rather than stacking. */
  function Row(props) {
    const kids = React.Children.toArray(props.children);
    if (kids.length === 2 && !props.stack) {
      return (
        <div className="pp-stage">
          <div className="pp-duo">
            {kids.map(function (k, i) {
              return (
                <div key={"s" + i} className="pp-halo">
                  <Slot {...k.props} />
                </div>
              );
            })}
            <div className="pp-duo-caps">
              {kids.map(function (k, i) { return <Cap key={"c" + i} {...k.props} />; })}
            </div>
          </div>
        </div>
      );
    }
    const cls = "pp-stage-row" + (props.compare ? " is-compare" : "") + (props.tight ? " is-tight" : "");
    return (
      <div className="pp-stage">
        <div className={cls}>{props.children}</div>
      </div>
    );
  }

  /* A single phone with its own stage wrapper, for when there is only one. */
  function Solo(props) {
    return (
      <div className="pp-stage">
        <div className="pp-stage-row">
          <Phone {...props} />
        </div>
      </div>
    );
  }

  /* A fixed-width desktop embed, scaled to fit its column by the driver. */
  function Wide(props) {
    return (
      <figure style={{ margin: 0, display: "flex", flexDirection: "column", gap: 12 }}>
        <div className="pp-wide" data-w={props.w} data-h={props.h} data-hook={props.hook || undefined}>
          <iframe title={props.title} data-src={embSrc(props.src)}
            scrolling={props.scroll ? "auto" : "no"} loading="lazy" />
        </div>
        {props.note ? (
          <figcaption className="pp-cap" style={{ width: "100%" }}>
            <div className="pp-lab">
              {props.badge ? <b>{props.badge}</b> : null}
              <span className="pp-live"><i />{props.status || "live"}</span>
            </div>
            <p className="pp-note">{props.note}</p>
            <FullLink src={props.src} />
          </figcaption>
        ) : null}
      </figure>
    );
  }

  /* ---------- native diagrams ----------
     Drawn in the portfolio's own vocabulary rather than embedded as slide
     exports, so they stay legible at any width and in both modes. Each one
     carries a caption that says what the reader is looking at. ---------- */

  function Dia(props) {
    return (
      <figure style={{ margin: 0, display: "flex", flexDirection: "column", gap: 13 }}>
        <div className="pf-glass pf-glass--thick" style={{ padding: "clamp(18px, 2vw, 30px)" }}>
          {props.children}
        </div>
        <figcaption className="nmc-ev" style={{ borderTop: 0, paddingTop: 0, marginTop: 0 }}>{props.caption}</figcaption>
      </figure>
    );
  }

  /* Term frequency from the blank-module study. Weight sets the type size,
     so the shape of the answer is visible before any of it is read. */
  function TermCloud(props) {
    return (
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(260px, 1fr))", gap: "clamp(20px, 2.4vw, 38px)" }}>
        {props.groups.map(function (g) {
          return (
            <div key={g.module} style={{ display: "flex", flexDirection: "column", gap: 16, minWidth: 0 }}>
              <div style={{
                border: "1px dashed var(--pf-border)", borderRadius: 12,
                padding: "26px 18px", textAlign: "center",
                fontSize: 13, letterSpacing: "0.08em", textTransform: "uppercase",
                color: "var(--label-tertiary)", background: "var(--fill-quaternary)",
              }}>
                {g.module}
                <div style={{ marginTop: 8, fontSize: 11.5, letterSpacing: 0, textTransform: "none" }}>
                  left blank on purpose
                </div>
              </div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: "10px 14px", alignItems: "baseline" }}>
                {g.terms.map(function (t) {
                  return (
                    <span key={t[0]} style={{
                      fontSize: 13 + t[1] * 7,
                      fontWeight: t[1] > 2 ? 400 : 300,
                      lineHeight: 1.1,
                      color: t[1] > 2 ? "var(--label-primary)" : t[1] > 1 ? "var(--label-secondary)" : "var(--label-tertiary)",
                    }}>{t[0]}</span>
                  );
                })}
              </div>
              <div className="nmc-ev">{g.read}</div>
            </div>
          );
        })}
      </div>
    );
  }

  /* Breadth against depth, priced in reachable items per tap. */
  function ReachDiagram(props) {
    const max = 64;
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
        {props.rows.map(function (r) {
          return (
            <div key={r.label} style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <div className="nmc-stat"><span>{r.label}</span><b>{r.items} items</b></div>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <div className="nmc-bar" style={{ flex: 1 }} aria-hidden="true">
                  <i style={{ width: Math.round((r.items / max) * 100) + "%", opacity: r.dim ? 0.45 : 1 }} />
                </div>
                <span style={{ fontSize: 11.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--label-tertiary)", whiteSpace: "nowrap" }}>
                  {r.taps}
                </span>
              </div>
              <p style={{ margin: 0, fontSize: 13, lineHeight: 1.55, color: "var(--label-secondary)" }}>{r.note}</p>
            </div>
          );
        })}
      </div>
    );
  }

  /* Two reading orders of the same thing, as ranked lists. `labels` renames
     the columns when the comparison is not chronological. */
  function OrderFlip(props) {
    const labels = props.labels || ["Before", "After"];
    return (
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: "clamp(18px, 2.2vw, 34px)" }}>
        {[[labels[0], props.before, true], [labels[1], props.after, false]].map(function (p) {
          return (
            <div key={p[0]} style={{ display: "flex", flexDirection: "column", gap: 12, minWidth: 0 }}>
              <div className="nmc-idx" style={{ color: p[2] ? "var(--label-tertiary)" : "var(--accent)" }}>{p[0]}</div>
              <ol style={{ margin: 0, padding: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 8 }}>
                {p[1].map(function (item, n) {
                  return (
                    <li key={item} style={{
                      display: "flex", gap: 12, alignItems: "baseline",
                      padding: "12px 14px", borderRadius: 10,
                      border: "1px solid var(--pf-hairline)",
                      background: n === 0 ? "var(--fill-tertiary)" : "transparent",
                      opacity: p[2] ? 0.78 : 1,
                    }}>
                      <span style={{ fontSize: 11, fontVariantNumeric: "tabular-nums", color: "var(--label-tertiary)", minWidth: 14 }}>{n + 1}</span>
                      <span style={{ fontSize: 13.5, lineHeight: 1.45, color: n === 0 ? "var(--label-primary)" : "var(--label-secondary)" }}>{item}</span>
                    </li>
                  );
                })}
              </ol>
            </div>
          );
        })}
      </div>
    );
  }

  /* The command vocabulary, named in full. */
  function ChipSet(props) {
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        {props.groups.map(function (g) {
          return (
            <div key={g.label} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              <div className="nmc-idx">{g.label}</div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                {g.items.map(function (it) {
                  const near = g.thumb && g.thumb.indexOf(it) !== -1;
                  return (
                    <span key={it} style={{
                      padding: "8px 14px", borderRadius: 999, fontSize: 12.5,
                      border: "1px solid " + (near ? "var(--accent)" : "var(--pf-hairline)"),
                      color: near ? "var(--accent)" : "var(--label-secondary)",
                      background: near ? "var(--fill-tertiary)" : "transparent",
                    }}>{it}</span>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  /* One primitive composed two ways. */
  function Composition(props) {
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        <div className="pf-glass" style={{ padding: "16px 18px", display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
          <div className="nmc-idx" style={{ margin: 0 }}>{props.primitive}</div>
          <p style={{ margin: 0, fontSize: 13, color: "var(--label-secondary)", flex: "1 1 240px" }}>{props.primitiveNote}</p>
        </div>
        <div className="nmc-grid">
          {props.compositions.map(function (c) {
            return (
              <div key={c.label} className="pf-glass nmc-card">
                <div className="nmc-idx">{c.label}</div>
                <p>{c.note}</p>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  /* The recognition instrument, including the options that were not real. */
  function Instrument(props) {
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        <div className="nmc-blk"><b>The prompt</b>{props.prompt}</div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: 16 }}>
          {[["On the screen", props.real, true], ["Not on the screen", props.decoys, false]].map(function (c) {
            return (
              <div key={c[0]} style={{ display: "flex", flexDirection: "column", gap: 12, minWidth: 0 }}>
                <div className="nmc-idx" style={{ color: c[2] ? "var(--accent)" : "var(--label-tertiary)" }}>{c[0]}</div>
                <ul style={{ margin: 0, padding: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 7 }}>
                  {c[1].map(function (it) {
                    return (
                      <li key={it} style={{
                        display: "flex", gap: 10, alignItems: "baseline",
                        fontSize: 13.5, lineHeight: 1.45,
                        color: c[2] ? "var(--label-secondary)" : "var(--label-tertiary)",
                      }}>
                        <span aria-hidden="true" style={{ color: c[2] ? "var(--accent)" : "var(--label-tertiary)", fontSize: 11 }}>
                          {c[2] ? "●" : "○"}
                        </span>
                        <span style={{ textDecoration: c[2] ? "none" : "line-through", textDecorationColor: "var(--pf-border)" }}>{it}</span>
                      </li>
                    );
                  })}
                </ul>
              </div>
            );
          })}
        </div>
        <div className="nmc-ev">{props.note}</div>
      </div>
    );
  }


  window.PPKit = {
    Phone: Phone, Row: Row, Solo: Solo, Wide: Wide, EMB: EMB,
    Dia: Dia, TermCloud: TermCloud, ReachDiagram: ReachDiagram, OrderFlip: OrderFlip,
    ChipSet: ChipSet, Composition: Composition, Instrument: Instrument,
  };
})();
