/* ============================================================
   nomi: case chapters, laid out natively in the portfolio's
   design language. The case is organized around the social-self
   thesis: identity as reusable product memory rather than
   repeated prompting. Opening states the thesis; Research runs
   from the identity-reconstruction problem to the RedNote wedge;
   Ideation shows the too-broad first system; Testing appends the
   validation results to the recorded reels from nomi.jsx;
   Iterations argues each revision; the only embedded piece is
   the working prototype via assets/nomi-rednote-flow-v4.html
   ?embed=proto; Outcome moves from preference to retention.
   Registers into window.CASE_PANELS["nomi"].
   ============================================================ */
(function () {
  const { useState, useRef } = React;
  const K = window.CSKit;
  const SectionHead = K.SectionHead;

  /* ---------- tiny shared bits ---------- */
  function Orb(props) {
    const s = props.s || 26;
    return <span aria-hidden="true" style={{ width: s, height: s, minWidth: s, borderRadius: "50%", display: "inline-block", background: "radial-gradient(circle at 32% 28%, #8fd9ff 0%, #4a55c8 48%, #302c9a 100%)" }} />;
  }
  function Chain(props) {
    return (
      <div className="nmc-chain">
        {props.nodes.map(function (n, i) {
          return (
            <React.Fragment key={i}>
              {i > 0 ? <span className="nmc-arr">&rarr;</span> : null}
              <div className={"nmc-node" + (n.cut ? " cut" : "")}>{n.t}{n.s ? <small>{n.s}</small> : null}</div>
            </React.Fragment>
          );
        })}
      </div>
    );
  }
  function H3Block(props) {
    return (
      <div>
        <h3 className="pf-h3" style={{ margin: "0 0 10px" }}>{props.title}</h3>
        {props.sub ? <p className="nmc-sub">{props.sub}</p> : null}
      </div>
    );
  }
  function Dot(props) {
    return (
      <button className="nmc-dot" style={props.st} aria-pressed={props.on ? "true" : "false"}
        aria-label={"Annotation " + props.n} onClick={props.onClick}>{props.n}</button>
    );
  }
  function Notes(props) {
    return (
      <div className="nmc-notes">
        {props.items.map(function (n, i) {
          const on = props.open === i;
          return (
            <button key={i} className={"nmc-note" + (on ? " on" : "")} onClick={function () { props.set(on ? -1 : i); }}>
              <div className="nmc-nidx">{n.k}</div>
              <h5>{n.t}</h5>
              <p>{n.p}</p>
            </button>
          );
        })}
      </div>
    );
  }
  function MiniBtn(props) {
    return <span style={{ display: "inline-block", borderRadius: 999, padding: "5px 14px", fontSize: 10.5, background: props.ghost ? "transparent" : "var(--accent)", color: props.ghost ? "var(--label-secondary)" : "#fff", border: props.ghost ? "1px solid var(--pf-border)" : "1px solid transparent" }}>{props.children}</span>;
  }

  /* ============================================================
     OPENING: the social-self thesis
     ============================================================ */
  function MetaCard(props) {
    return (
      <div className="pf-glass" style={{ gridColumn: "span 3", padding: "clamp(22px, 2vw, 30px)" }}>
        <div className="pf-eyebrow" style={{ marginBottom: 12 }}>{props.label}</div>
        <div className="pf-h3" style={{ fontSize: 18 }}>{props.value}</div>
      </div>
    );
  }
  function OpeningPanel(props) {
    const c = props.case;
    return (
      <div className="nmc" style={{ gap: 40 }}>
        <div style={{ maxWidth: 860 }}>
          <h2 className="pf-h2" style={{ margin: 0, fontSize: "clamp(24px, 2.6vw, 36px)" }}>What if AI remembered which version of you was creating?</h2>
          <p className="pf-lead" style={{ margin: "18px 0 0", maxWidth: 820 }}>
            Generative AI can write quickly, but it often collapses the person behind the prompt into one generic
            voice. Nomi explores a different model: users shape one reusable social-self, a contextual version of
            themselves, and create through it, so identity becomes part of the product rather than another
            instruction they have to rewrite every time.
          </p>
          <p className="pf-body" style={{ margin: "14px 0 0", maxWidth: 820, fontSize: 15.5, lineHeight: 1.7, color: "var(--label-secondary)" }}>
            I designed Nomi as the smallest test of that idea. Across two controlled studies with 32 participants,
            I compared direct generation against generation through a social-self, then used the evidence to narrow
            the product, redesign the interaction model, and launch a RedNote-first production MVP under ZeyaAI.
          </p>
          {c.live ? (
            <a href={c.live} target="_blank" rel="noopener noreferrer" className="pf-btn pf-btn--primary gv-lift"
              style={{ display: "inline-flex", marginTop: 26, textDecoration: "none" }}>
              <span className="gv-ping" aria-hidden="true" style={{ width: 8, height: 8, borderRadius: "50%", background: "currentColor" }} />
              Live &middot; {c.live.replace(/^https?:\/\//, "")}
              <i data-lucide="arrow-up-right" style={{ width: 16, height: 16, opacity: 0.8 }} />
            </a>
          ) : null}
        </div>

        <div className="pf-glass nmc-map">
          <div className="pf-eyebrow" style={{ marginBottom: 14 }}>Generic AI</div>
          <Chain nodes={[
            { t: "Idea" },
            { t: "Prompt reconstructs identity", s: "every single session" },
            { t: "Model" },
            { t: "Output", s: "competent, interchangeable" },
          ]} />
          <div className="pf-eyebrow" style={{ margin: "18px 0 14px", color: "var(--accent)" }}>Nomi</div>
          <div className="nmc-chain">
            <div className="nmc-node">Idea</div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">Saved social-self<small>persistent, user-shaped</small></div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">Current context</div>
            <span className="nmc-arr">&rarr;</span>
            <div className="nmc-node">Model</div>
            <span className="nmc-arr">&rarr;</span>
            <div className="nmc-node">Output<small>recognizably yours</small></div>
          </div>
          <div className="nmc-loop">Nomi moves identity from repeated prompting into reusable product memory.</div>
        </div>

        <div className="nmc-grid">
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Evidence 01</div>
            <h4>32 participants, two controlled studies</h4>
            <p>Both rounds ran the same within-participant comparison: direct generation against generation through a social-self, on the same idea.</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Evidence 02</div>
            <h4>Intended-self fit, 50% to 69%</h4>
            <p>The core metric moved 19 percentage points between rounds, after the product was narrowed to one platform and one lighter social-self setup. Several variables changed together, so Testing carries the causal reading.</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Evidence 03</div>
            <h4>Live production MVP</h4>
            <p>Launched and instrumented under ZeyaAI, RedNote-first, with an activation funnel counting the behaviors the studies could only ask about.</p>
          </div>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <div className="nmc-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(min(440px, 100%), 1fr))" }}>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">What a social-self is</div>
            <h4>A contextual version of the real user</h4>
            <p>
              People do not show up as one universal self. The version of a person that appears in professional
              contexts, personal storytelling, creative work, or different communities can be intentionally
              different while still being authentic. A social-self captures one of those versions: intentionally
              shaped by the user, persistent enough to reuse, specific enough to influence generation, and
              flexible enough to evolve.
            </p>
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 14 }}>
              {["user-shaped", "contextual", "persistent", "steers generation", "evolves"].map(function (t) {
                return <span key={t} className="nmc-chip">{t}</span>;
              })}
            </div>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">What it is not</div>
            <h4>Not a persona, not a filter, not a preset</h4>
            <p>
              A social-self is not a fictional persona, a role-play character, a cosmetic tone filter, a collection
              of personality facts, or a brand-voice preset. Every self is the same real person, expressed for a
              particular context.
            </p>
            <div className="nmc-ev">
              The question underneath the whole case: what if identity were something the product remembered and
              applied, instead of something the user had to repeatedly reconstruct inside prompts?
            </div>
          </div>
        </div>

        <div className="pf-bento" style={{ gridAutoRows: "auto" }}>
          <MetaCard label="Role" value={c.role} />
          <MetaCard label="Platform" value={c.platform} />
          <MetaCard label="Year" value={c.year} />
          <MetaCard label="Organization" value={c.org} />
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
          {c.tags.map(function (t) { return <span key={t} className="pf-chip">{t}</span>; })}
        </div>
      </div>
    );
  }

  /* ============================================================
     RESEARCH
     ============================================================ */
  const FINDINGS = [
    "Titles carry a hard limit of about 20 characters and lead with value: a number, a mistake avoided, a comparison, a hidden gem. The title and cover together decide the click in a two-column feed, so the hook is a design constraint, not a style choice.",
    "Creator guides and growth communities converge on the same engagement hierarchy: comments, shares, and follows appear to count far more than likes, and saves signal lasting value. The exact weights are unverifiable from outside the platform, so I treated the ranking rather than any specific numbers as the design input: notes that earn saves and comments travel beyond their first traffic pool, and the first hours after posting matter most.",
    "Save-earning notes share an anatomy: a personal hook, a numbered utility list, a reason to save for later, and a question that invites comments. Creator guides put the balance at roughly a 60/40 split of practical value to personal narrative, and the high-performing notes I read sit near that ratio, so I treated it as a starting proportion rather than a rule.",
    "RedNote doubles as a search engine. Creator guides agree on the mechanics here, and the high-performing notes I read follow them: keywords belong in the title and first lines, and 5 to 8 tags mix broad and niche terms. This is why the product surfaces tag view counts and keyword-aware titles instead of leaving them to chance.",
  ];
  const STUDIES = [
    {
      cover: "cover: badge and morning light at Apple Park",
      title: "my day as an Apple intern in the Bay",
      body: "6:40am. Caltrain, cold brew, rehearsing my standup update in my head.\nwhat nobody tells you about interning here:\n1. the campus is a circle and you will get lost in a circle\n2. lunch is subsidized, the cafe matcha is not a secret anymore\n3. your badge opens fewer doors than your questions do\n4. design reviews are quiet. the silence is the feedback\nask me anything about the recruiting timeline, I kept every email.\nsave this for your application season.",
      tags: "#applestudentintern #bayarealife #techinternship #dayinmylife",
      tech: ["day-in-the-life hook", "numbered list", "save CTA", "comment invitation"],
    },
    {
      cover: "cover: tasting flight on a wooden tray, Uji storefront",
      title: "5 matcha stores in Japan worth the flight",
      body: "I planned a whole trip around matcha and regret nothing.\n1. Nakamura Tokichi, Uji. the fresh mochi arrives still warm\n2. Ippodo, Kyoto. buy the koicha, thank me later\n3. Tsujiri Honten, Gion. the parfait is a structural achievement\n4. Suzukien, Tokyo. gelato in seven intensities, take level six\n5. Saryo Tsujiri. warabi mochi that ends arguments\nqueue times and what to order first are in the last image.\nsave this before your Japan trip disappears into a screenshot folder.",
      tags: "#japantravel #matcha #kyotofood #mochi",
      tech: ["number hook", "personally tested", "reference detail", "save CTA"],
    },
    {
      cover: "cover: suite window facing the Matterhorn",
      title: "8 Swiss resorts where the view does the work",
      body: "I compared 23 resorts so you only have to choose from 8.\n1. The Cambrian, Adelboden. the pool photo is real\n2. Riffelalp, Zermatt. Matterhorn from the outdoor spa\n3. Burgenstock, Lake Lucerne. the funicular is the check-in\n4. Villa Honegg. yes, the one from the video\n5. The Chedi Andermatt. a cheese tower taller than me\n6. The Omnia, Zermatt. cliff elevator, quiet rooms\n7. The Alpina Gstaad. quiet money, loud mountains\n8. Le Grand Bellevue. a wellness circuit worth a full day\nrates drop hard in shoulder season, late September is the move.\nwhich one is your type? comment your pick.",
      tags: "#switzerland #luxurytravel #alpineresorts #travelguide",
      tech: ["curation credibility", "comparison list", "insider tip", "comment prompt"],
    },
  ];
  function ResearchPanel() {
    return (
      <div className="nmc" style={{ gap: 36 }}>
        <SectionHead kicker="Research" title="The problem was not content generation. It was identity reconstruction."
          lead="Most general-purpose AI starts each task with either a blank prompt or one broad representation of the user. In practice, people repeatedly specify the same things: how personal to be, who they are speaking to, how polished they want to sound, what version of themselves belongs in this context. I treated that repetition as a product problem rather than a prompting problem." />
        <div className="pf-glass nmc-map">
          <div className="pf-eyebrow" style={{ marginBottom: 14 }}>Every session today</div>
          <Chain nodes={[
            { t: "Idea" },
            { t: "Re-explain tone" },
            { t: "Re-explain audience" },
            { t: "Re-explain desired impression" },
            { t: "Generate" },
          ]} />
          <div className="pf-eyebrow" style={{ margin: "18px 0 14px", color: "var(--accent)" }}>The Nomi hypothesis</div>
          <div className="nmc-chain">
            <div className="nmc-node">Saved social-self</div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">New idea</div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">Current context</div>
            <span className="nmc-arr">&rarr;</span>
            <div className="nmc-node">Generate</div>
          </div>
          <div className="nmc-loop">The risky assumption was whether users would value a persistent identity layer enough to reuse it.</div>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="I reduced the larger vision to one falsifiable question"
          sub="The broader ZeyaAI idea could eventually support multiple contextual selves, but testing that entire system would mix too many assumptions together. I reduced it to one atomic question: does creating through one lightweight social-self produce more useful content than generating directly from the same idea?" />
        <div className="pf-glass nmc-map">
          <Chain nodes={[
            { t: "One participant" },
            { t: "Same idea" },
            { t: "Two paths", s: "direct vs social-self generation" },
            { t: "Forced comparison", s: "fit, postability, editing" },
          ]} />
          <div className="nmc-loop">This within-participant comparison is the spine of both testing rounds that follow.</div>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="Validation told me identity mattered. Production required choosing where it mattered most."
          sub="Round 1 showed that platform breadth diluted the signal. Round 2 narrowed the study to Instagram and strengthened intended-self fit from 50% to 69%, which suggested the social-self worked better when identity was grounded in a specific social context rather than treated as a universal writing profile. For production, I chose RedNote as the wedge: its creator economy already centers recognizable personal IP, informational utility, saves, searchability, and platform-specific publishing conventions. That made it a strong environment for testing whether a social-self could become an ongoing creator asset rather than a one-session prompt." />
        <div className="nmc-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(min(440px, 100%), 1fr))" }}>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Instagram</div>
            <h4>The controlled validation context</h4>
            <p>One familiar platform, chosen to isolate the social-self variable. It answered whether the identity layer creates value at all, under study conditions.</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">RedNote</div>
            <h4>The production wedge</h4>
            <p>A creator ecosystem where recognizable personal IP, saves, and search behavior matter strongly. It asks the harder question: does a social-self become an asset a creator keeps?</p>
          </div>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="How high-engagement RedNote notes are written"
          sub="With the wedge chosen, I studied the platform's content economy before designing generation: what the platform rewards, how top notes are structured, and why. Four findings shaped the product directly, and I wrote format studies to internalize the craft before asking a model to reproduce it." />
        <div className="nmc-grid">
          {FINDINGS.map(function (f, i) {
            return (
              <div key={i} className="pf-glass nmc-card">
                <div className="nmc-idx">Finding 0{i + 1}</div>
                <p>{f}</p>
              </div>
            );
          })}
        </div>
        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="Format studies" sub="Three notes I wrote to the platform's conventions, one per register the product generates. Each label names the technique the note demonstrates." />
        <div className="nmc-grid">
          {STUDIES.map(function (s, i) {
            return (
              <div key={i} className="pf-glass nmc-card" style={{ gap: 10 }}>
                <div className="nmc-cover">{s.cover}</div>
                <h4 style={{ margin: 0 }}>{s.title}</h4>
                <p className="nmc-pre" style={{ fontSize: 12.5 }}>{s.body}</p>
                <p style={{ fontSize: 11.5, color: "var(--label-tertiary)" }}>{s.tags}</p>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap", paddingTop: 10, borderTop: "1px dashed var(--pf-border)" }}>
                  {s.tech.map(function (t) { return <span key={t} className="nmc-chip">{t}</span>; })}
                </div>
              </div>
            );
          })}
        </div>
        <p className="nmc-sub">What this means for Nomi: generation has to target the whole anatomy (hook title, list body, save line, comment prompt, tag mix). The guidance layer I call the recipe carries the platform knowledge, publish timing and tag selection, so the user's self can carry the voice.</p>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="The architectural decision: identity and platform expertise are not the same thing"
          sub="The research produced one structural rule that everything downstream obeys. The user should own how they show up; Nomi should absorb the platform mechanics. The social-self carries identity, and the recipe carries RedNote knowledge." />
        <div className="nmc-evrow">
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">The social-self owns</div>
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 4 }}>
              {["voice", "perspective", "energy", "closeness", "identity continuity"].map(function (t) {
                return <span key={t} className="nmc-chip" style={{ borderColor: "color-mix(in srgb, var(--accent) 40%, transparent)" }}>{t}</span>;
              })}
            </div>
          </div>
          <div className="ar" aria-hidden="true">+</div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">The recipe owns</div>
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 4 }}>
              {["hook structure", "note anatomy", "save mechanics", "comment invitation", "tags", "platform conventions"].map(function (t) {
                return <span key={t} className="nmc-chip">{t}</span>;
              })}
            </div>
          </div>
        </div>
        <div className="pf-glass nmc-map">
          <div className="nmc-chain">
            <div className="nmc-node">Social-self<small>who is writing</small></div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">Recipe<small>how the platform works</small></div>
            <span className="nmc-arr">+</span>
            <div className="nmc-node">Idea<small>what today's note is about</small></div>
            <span className="nmc-arr">&rarr;</span>
            <div className="nmc-node">Output<small>platform-native, recognizably yours</small></div>
          </div>
        </div>
      </div>
    );
  }

  /* ============================================================
     IDEATION
     ============================================================ */
  function IdeationPanel() {
    return (
      <div className="nmc" style={{ gap: 28 }}>
        <SectionHead kicker="Ideation" title="I initially designed the system before proving its atomic value"
          lead="My first concept assumed that richer AI personalization required collecting more information about the user. I designed one identity profile that could power three jobs at once: social content, professional networking messages, and profile representation." />
        <div className="pf-glass nmc-map">
          <div className="pf-eyebrow" style={{ marginBottom: 14 }}>The original architecture: one profile, three jobs</div>
          <div className="nmc-chain">
            <div className="nmc-node">Identity profile<small>one onboarding system</small></div>
            <span className="nmc-arr">&rarr;</span>
            <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
              <div className="nmc-node">Create<small>social content</small></div>
              <div className="nmc-node">Connect<small>networking communication</small></div>
              <div className="nmc-node">Appear<small>profile representation</small></div>
            </div>
          </div>
          <p className="nmc-sub" style={{ marginTop: 14, fontSize: 13.5 }}>The architecture made conceptual sense, but from a product perspective it was premature: three jobs shared one onboarding system before any one behavior had been validated.</p>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="The original wireframe flow"
          sub="The first wireframes cast Nomi wide: a mode select across three jobs, a profile builder that collected personal facts, a separate context page, and a generation screen with a detail editor. The flow below is the starting point this case study revises; the per-screen references appear in Iterations next to what replaced them." />
        <div className="pf-glass nmc-map">
          <div className="pf-eyebrow" style={{ marginBottom: 14 }}>Original flow, eight screens and three modes</div>
          <Chain nodes={[
            { t: "Mode select", s: "3 paths", cut: true },
            { t: "Profile picture generation", cut: true },
            { t: "Profile builder", s: "personal facts" },
            { t: "Context drop", s: "separate page" },
            { t: "Generate 3 cards" },
            { t: "Detail and edit" },
            { t: "Networking messages", s: "parallel path", cut: true },
          ]} />
          <p className="nmc-sub" style={{ marginTop: 14, fontSize: 13.5 }}>Two setup pages ran before any value appeared, three ambitions shared one product, and content extraction arrived after identity was already fixed, where it could not reduce setup cost. Testing made each of these costs measurable.</p>
        </div>
        <div className="nmc-blk"><b>What the original flow exposed</b>
          My first wrong assumption was that better personalization required more user data. The profile collected
          facts such as interests and personality signals, but those facts were not necessarily useful for producing
          the intended voice. Worse, users encountered multiple setup steps before seeing any value. Testing changed
          the direction from collect more about the person to let the person intentionally shape the version of
          themselves that matters here. That distinction, shaping over collecting, became the strongest AI product
          design lesson in this case.
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="Three questions the wireframes could not answer"
          sub="Each one maps to a measurement in the rounds that follow: the first as a direct comparison, the second as a magnitude, the third as a demand signal." />
        <div className="nmc-grid">
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">01</div>
            <p>Does a social-self actually improve the result compared with direct generation?</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">02</div>
            <p>How little identity input can produce a meaningful difference?</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">03</div>
            <p>If one social-self works, will users want to save it, reuse it, or eventually create another?</p>
          </div>
        </div>
        <p className="nmc-sub">Testing answers these next.</p>
      </div>
    );
  }

  /* ============================================================
     TESTING: results + insights (appended after the reels)
     ============================================================ */
  const ROUNDS = [
    {
      t: "Round 1 · any platform",
      p: "Tested whether a shaped self matters at all. Demand for saving and reusing a self was the strongest signal; platform breadth diluted output quality.",
      stats: [["intended-self fit", "50%"], ["more likely to post", "56%"], ["open to saving the self", "81%"], ["would choose the workflow again", "63%"]],
    },
    {
      t: "Round 2 · instagram only",
      p: "Same comparison, one platform, lighter setup. The three core output metrics improved. Time to a usable result did not move, and save intent dipped.",
      stats: [["intended-self fit", "69%"], ["more likely to post", "63%"], ["less editing required", "56%"], ["faster to usable result", "44%"]],
    },
  ];
  const DECISIONS = [
    { k: "D1", t: "RedNote content is the only mode", p: "I cut networking messages and profile appearance. Round 1 showed that breadth across contexts diluted every signal, and only content creation was ever validated.", ev: "The self object stays platform-agnostic underneath, so other modes can return in Nyla without rework." },
    { k: "D2", t: "One self, with a visible entry to Nyla", p: "Nomi is a one-self trial. The home screen shows the saved self plus a locked card for a second one that opens a waitlist prompt. Wanting another self becomes a counted event instead of a survey answer.", ev: "75% said they wanted another self; this converts stated intent into observable demand." },
    { k: "D3", t: "Three seed sources replace the bio form", p: "A self starts from the user's own posts, from a creator they admire, or from a RedNote archetype, then three dials and one identity line. The original form collected facts the model could not use as voice.", ev: "Round 2 improved by lightening setup; seeding from real posts removes prompt writing entirely." },
    { k: "D4", t: "A live voice preview during setup", p: "A sample note re-renders on every adjustment while shaping the self. The user hears the self before generating anything, so setup produces value instead of asking for faith.", ev: "Aimed directly at the flat 44% speed metric." },
    { k: "D5", t: "Platform anatomy, user covers, and the recipe", p: "Drafts are structured as real notes: hook title, list body, save line, tags chosen by the research findings. Covers are uploaded, never generated. Nomi's guidance layer, the recipe, appears only at service moments.", ev: "The combined Round 2 refinement (narrower scope, lighter setup, platform-native output) lifted intended-self fit 19 points; no single variable can claim that gain alone, and the recipe carries the platform knowledge." },
  ];
  function ResultsBlock() {
    return (
      <div className="nmc" style={{ gap: 32 }}>
        <SectionHead kicker="The numbers" title="Two validation rounds, 32 participants"
          lead="Both rounds used a within-participant comparison: the same person, the same topic, direct generation against social-self generation, then forced choices on fit, postability, and editing burden, plus save and reuse intent." />
        <div className="nmc-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))" }}>
          {ROUNDS.map(function (r, i) {
            return (
              <div key={i} className="pf-glass nmc-card">
                <div className="nmc-idx">{r.t}</div>
                <p>{r.p}</p>
                <div style={{ marginTop: 18, display: "grid", gap: 13 }}>
                  {r.stats.map(function (s) {
                    return (
                      <div key={s[0]}>
                        <div className="nmc-stat"><span>{s[0]}</span><b>{s[1]}</b></div>
                        <div className="nmc-bar" aria-hidden="true"><i style={{ width: s[1] }} /></div>
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })}
        </div>
        <p className="nmc-sub">On causality: Round 2 changed several variables at once (platform scope, onboarding weight, social-self setup, and prompt behavior), so the 19 point rise in intended-self fit belongs to the combined refinement, not to any single change. And the negative evidence stayed honest: speed held at 44%, and stated save intent softened from roughly 81% to 75%. Round 2 improved immediate output value more clearly than repeat-use confidence, which is exactly the question production has to answer.</p>
      </div>
    );
  }
  function InsightsBlock() {
    return (
      <div className="nmc" style={{ gap: 32 }}>
        <SectionHead kicker="Insights" title="What the numbers meant, and the five decisions they produced"
          lead="The two rounds strengthened the core hypothesis without proving it, and they localized two unresolved product problems. Setup feels like work before it shows value: the speed metric stayed flat at 44% while everything else improved. And persistence is stated but not felt: 75 to 81 percent said they would save and branch a self, yet nothing in the product made that saved self visible or rewarding. Each decision below attacks one of the two, inside a RedNote-only frame chosen for its creator-identity economy, its US-entry timing, and its mechanical parallels to the Instagram evidence." />
        <div className="nmc-grid">
          {DECISIONS.map(function (d) {
            return (
              <div key={d.k} className="pf-glass nmc-card">
                <div className="nmc-idx">{d.k}</div>
                <h4>{d.t}</h4>
                <p>{d.p}</p>
                <div className="nmc-ev">{d.ev}</div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  /* ============================================================
     ITERATIONS
     ============================================================ */
  const RULES = [
    { k: "Rule 1", t: "Where prompt pills belong", p: "I add pills where intent is known but phrasing is not: topics, reference creators, warm starts, refine scopes, trait words. Recognition replaces recall, which attacks the prompt-skill prerequisite from my research notes and the flat 44 percent speed metric, and every tap lands in analytics as a countable choice where free text cannot.", ev: "The one input pills never replace is the note idea itself. The topic is the single thing the system cannot know for the user." },
    { k: "Rule 2", t: "Why five variations became three", p: "In the interim build, three of five variations opened with the same sentence, so choosing meant proofreading. Round 1 had already shown that people respond to versions of a self, not shuffles of one text. Three drafts in three registers make the choice about identity, fit on screen without scrolling, and turn each keep or discard into a clean per-register preference signal.", ev: "Fewer, more distinct options is also what the forced-choice study design itself relied on." },
    { k: "Rule 3", t: "Where input lives, and where it is removed", p: "Input sits where its consequence is visible, and nowhere else. The note idea sits beside generation, refine sits under the drafts it rewrites, identity controls sit beside the live voice check. Where the consequence is invisible the input is removed, which is why profile editing left the compose path and two setup pages became one box.", ev: "Every page before value is attrition surface in my drop-off metric. Merging input with its preview turns prompting into steering." },
  ];
  const RES = [
    { k: "01 · scope", t: "Whether networking and appearance modes belong in the MVP", q: "My wireframes carried three parallel modes, but only content creation was ever validated by the research.", d: "Both extra modes are out of the MVP. The self object stays platform-agnostic underneath so a networking self can exist in Nyla without rework.", tr: "I lose the chance to discover networking demand accidentally in round 3. I accept that, because accidental discovery on unvalidated surfaces is what muddied Round 1." },
    { k: "02 · the bio form", t: "What the personal-facts form was reaching for", q: "The original profile builder collected MBTI, favorite flavors, and interests. Reviewing it, I recognized the real intent: giving users a blogger to look to as a starting point for becoming one.", d: "That intent became a first-class feature. A creator you admire is one of three seed sources. The system extracts the reference's register only, meaning rhythm, structure, and energy, never name or story.", tr: "Aspiration seeding solves the cold start for users with no posts, but risks sound-alike voices. Guardrails: register-only extraction, a mandatory identity line, and the reference stays private to the user." },
    { k: "03 · covers", t: "How a cover-led platform works in a text-first MVP", q: "RedNote discovery is driven by covers, but both research rounds deliberately excluded image generation so it would not confound the voice comparison.", d: "Users upload their own cover to preview it in the feed; otherwise the draft shows a written cover concept with an upload control. The product does not generate images.", tr: "Uploading is a manual step and depends on the user having a photo. I track the upload rate: if it stays low, the feed preview loses power, and that is the signal to revisit generation after the voice loop is proven." },
    { k: "04 · language", t: "Default language for US-entry creators", q: "The product faces US-entry creators, so I had to choose between English, Chinese, and a bilingual toggle.", d: "English is the only body language in the MVP. Tags remain mixed English and Chinese because that is how discovery works on the US feed and it costs the user nothing.", tr: "A simpler product and a cleaner round 3 cohort, at the price of excluding bilingual creators. If recruiting surfaces them in numbers, the toggle returns; the generation layer already supports it." },
    { k: "05 · one self", t: "How many selves the trial allows", q: "Multiple selves are the Nyla vision, but an MVP that ships them would be testing management before proving the value of one.", d: "Nomi allows one self. The home screen keeps a visible locked card for a second; opening it states the limit and links to the Nyla waitlist. The compose screen repeats the same entry in passing.", tr: "Round 3 never observes real multi-self behavior, which Nyla ultimately needs proven. In exchange, every waitlist click is a counted, attributable demand signal, and the MVP stays honest about what it is. A smaller true measurement beats a larger fake one." },
    { k: "06 · triage", t: "What the accept and reject stack was for", q: "My original detail screen had a card stack with accept and reject marks. The intent was draft triage: letting users select and make choices.", d: "Keep and discard buttons on every draft. Same choice, three practical gains: all drafts stay visible during the choice, the controls are keyboard accessible, and each click lands in analytics as a per-register preference.", tr: "Buttons are less tactile than swiping. On a future mobile build, swipe returns as a gesture over the same keep and discard model; the data schema does not change." },
    { k: "07 · monetization", t: "Where the subscription signal lives in a free study", q: "My metrics notes listed subscription conversion, but a paywall inside a 16-person study loop would contaminate every completion metric.", d: "The loop stays free. Willingness is measured twice, never as a gate: the Nyla waitlist clicks, and one post-study question asked at a concrete moment, whether the user would pay to keep Rain.", tr: "Stated willingness is weaker evidence than a real conversion. I take the honest weaker signal now; pricing gets its own test when Nyla exists." },
    { k: "08 · the recipe", t: "Whose voice the product itself speaks in", q: "My early wireframes had the assistant commenting between steps. The concept underneath: users define explicit selves and own them; Nomi has no explicit self of its own, but it has an implicit one, the native recipe that boosts engagement. The selling points are management and the perks of that recipe.", d: "The recipe became the product term. It appears exactly where it serves: warm starts on Compose, publish timing and tag rationale in Studio, always labeled and visually distinct, never as conversation between the user and their draft.", tr: "An ambient guidance layer demos less flashily than a talking assistant. But a narrator would make the tool the author, and the evidence says the value is the user's own self, elevated. The recipe earns visibility through measured tap-through, not personality." },
  ];

  /* voice-check matrices for the Shape wireframe (energy+structure → title, energy+closeness+structure → body) */
  const VC_TITLES = { "00": "a quiet bakery note", "01": "the bakery list, kept short", "10": "drop everything, new bakery", "11": "3 things to order at this bakery" };
  const VC_BODIES = {
    "000": "found a small bakery on a side street.\nthe morning loaf, still warm. the coffee, honest.\nkeeping this one for slow days.",
    "001": "the short version:\n1. go before 9\n2. order the morning loaf\n3. skip the pastry case, take the plain one\nsave for your next slow morning.",
    "010": "wandered in by accident and stayed an hour.\nwarm bread, a corner seat, nowhere to be.\nthe kind of morning I keep trying to build.",
    "011": "my bakery morning, in order:\n8am, first batch out\nthe corner seat by the window\nthe loaf that made me text three people\nworth planning a morning around.",
    "100": "ok everyone needs to hear about this bakery\nthe loaf comes out at 8 and it does not survive till 9\nI am not exaggerating, run",
    "101": "the verdict is in:\n1. morning loaf, perfect\n2. sesame roll, strong second\n3. the famous croissant, skip it\nfight me in the comments",
    "110": "this bakery broke me a little\nwarm bread at 8am and the owner remembered my order\nthis is my whole personality now",
    "111": "tested the full pastry case so you do not have to:\n1. morning loaf, a ten\n2. sesame roll, a nine\n3. croissant, overhyped\nfull notes below, save this",
  };

  /* chevron pager for the four screens: same pattern as the Testing rounds */
  const SCREEN_META = [
    { t: "01 Shelf: the home screen holds the saved self", r: "replaces the mode select home and the accounts list" },
    { t: "02 Shape: seeding, dials, and a live preview on one screen", r: "replaces the profile builder and the separate extraction step" },
    { t: "03 Compose: context and intent merge into one input", r: "replaces the context page and the separate create page" },
    { t: "04 Studio: drafts in feed context, edits that teach the self", r: "replaces the generation cards and the separate detail and edit screen" },
  ];
  function ScreenSwitcher(props) {
    const m = SCREEN_META[props.idx];
    return (
      <div className="nmc-switch">
        <button onClick={function () { props.set((props.idx + 3) % 4); }} className="pf-btn gv-lift" aria-label="Previous screen" style={{ padding: 14, flex: "none" }}>
          <i data-lucide="chevron-left" style={{ width: 18, height: 18 }} />
        </button>
        <div className="nmc-swmid">
          <div className="pf-eyebrow" style={{ marginBottom: 6, color: "var(--accent)" }}>Screen {props.idx + 1} of 4</div>
          <h3 className="pf-h3" style={{ margin: 0 }}>{m.t}</h3>
          <div style={{ fontSize: 12.5, color: "var(--label-tertiary)", marginTop: 4 }}>{m.r}</div>
        </div>
        <button onClick={function () { props.set((props.idx + 1) % 4); }} className="pf-btn gv-lift" aria-label="Next screen" style={{ padding: 14, flex: "none" }}>
          <i data-lucide="chevron-right" style={{ width: 18, height: 18 }} />
        </button>
      </div>
    );
  }
  function Compare(props) {
    return (
      <div className="nmc-compare">
        <div>
          <div className="nmc-olabel">{props.label}</div>
          <div className="nmc-oframe">{props.children}</div>
        </div>
        <div className="pf-glass nmc-card nmc-changes">
          <div className="nmc-idx">What I changed</div>
          <ul>{props.changes.map(function (c, i) { return <li key={i}>{c}</li>; })}</ul>
        </div>
      </div>
    );
  }

  /* --- screen 01: shelf --- */
  function ShelfScreen() {
    const [open, setOpen] = useState(-1);
    const notesRef = useRef(null);
    function flip(i) {
      const opening = open !== i;
      setOpen(opening ? i : -1);
      if (opening) setTimeout(function () { if (notesRef.current) notesRef.current.scrollIntoView({ block: "nearest", behavior: "smooth" }); }, 60);
    }
    const notes = [
      { k: "1 · Persistence first", t: "The saved self is the home screen", p: "Saving and reusing was the strongest signal in both rounds, so I made it the architecture rather than a feature. The card leads with a line in the self's voice because people recognize a voice faster than they read metadata." },
      { k: "2 · The Nyla entry", t: "A locked card that states the limit honestly", p: "One self in Nomi, by design. The card explains the limit and links to the Nyla waitlist. Each click is a measured unit of multi-self demand, and doubles as a willingness signal for the business model." },
      { k: "3 · Publishing stays manual", t: "Recent notes record copy events, not posts", p: "The MVP posts nothing. A note's life ends here as copied to RedNote, which is a proxy I can count honestly without account integration." },
    ];
    return (
      <div className="nmc" style={{ gap: 18 }}>
        <Compare label="Original: mode select home" changes={[
          "Removed the mode choice. The validated job, RedNote content, is the whole product.",
          "Replaced the empty landing with the saved self, so the product's memory is the first thing a returning user sees.",
          "Added a locked second-self card that opens a Nyla waitlist prompt, converting branch intent into counted clicks.",
        ]}>
          <div className="ttl">nomi</div>
          <div style={{ display: "flex", gap: 8, margin: "auto 0", justifyContent: "center" }}>
            <div className="nmc-obtn sel" style={{ flex: 1 }}>RedNote Content</div>
            <div className="nmc-obtn" style={{ flex: 1 }}>Networking Message</div>
            <div className="nmc-obtn" style={{ flex: 1 }}>Profile Appearance</div>
          </div>
          <div style={{ display: "flex", justifyContent: "flex-end" }}><span className="nmc-obtn cta">Continue</span></div>
        </Compare>
        <div className="nmc-hint">Click a numbered dot on the wireframe, or a card below, to open its annotation.</div>
        <div className="nmc-frame">
          <div className="nmc-fz">
            <div className="nmc-logo">nomi</div>
            <div style={{ marginTop: "3.4%", fontSize: 13, color: "var(--label-primary)" }}>Choose a self to write with</div>
            <div style={{ fontSize: 9.5, color: "var(--label-secondary)", maxWidth: "52ch" }}>A self is your saved RedNote voice. It remembers how you sound, so every note starts from you.</div>
            <div className="nmc-rowshelf" style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "2.4%", margin: "auto 0", marginTop: "2.4%" }}>
              <div className="nmc-pcard" style={{ position: "relative", padding: "5% 5.5%", display: "flex", flexDirection: "column", gap: 6 }}>
                <Dot n={1} st={{ top: -9, left: -9 }} on={open === 0} onClick={function () { flip(0); }} />
                <Orb />
                <div style={{ fontWeight: 500, fontSize: 13 }}>Rain</div>
                <div style={{ fontSize: 10, color: "var(--label-secondary)", fontStyle: "italic", lineHeight: 1.5 }}>"Uji at first light, warm mochi in hand. everything since has been an audition."</div>
                <div style={{ fontSize: 9, color: "var(--label-tertiary)", marginTop: "auto", paddingTop: 8 }}>12 notes in, drafts start closer to done.<br />Every note you keep teaches Rain more of you.</div>
                <div style={{ alignSelf: "flex-start", marginTop: 6 }}><MiniBtn>Write with Rain</MiniBtn></div>
              </div>
              <div style={{ position: "relative", border: "1.5px dashed var(--pf-border)", borderRadius: 10, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 7, color: "var(--label-secondary)", fontSize: 11, textAlign: "center", padding: "6%" }}>
                <Dot n={2} st={{ top: -9, right: -9 }} on={open === 1} onClick={function () { flip(1); }} />
                <span className="nmc-chip" style={{ fontSize: 8.5, letterSpacing: "0.1em", textTransform: "uppercase" }}>locked</span>
                <div>New self</div>
                <div style={{ fontSize: 9, lineHeight: 1.5 }}>Nomi is a one-self trial.<br />Nyla holds as many selves as you need.</div>
                <span style={{ fontSize: 9, color: "var(--accent)", textDecoration: "underline" }}>join the Nyla waitlist</span>
              </div>
              <div className="nmc-gcard" style={{ position: "relative", padding: "5% 5.5%", display: "flex", flexDirection: "column", gap: 7 }}>
                <Dot n={3} st={{ top: -9, right: -9 }} on={open === 2} onClick={function () { flip(2); }} />
                <div style={{ fontSize: 8.5, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--label-tertiary)" }}>Recent notes</div>
                <div className="nmc-lbox">5 matcha stores in Japan worth the flight<span style={{ display: "block", fontSize: 8, color: "var(--label-tertiary)" }}>copied to RedNote · 2d ago</span></div>
                <div className="nmc-lbox">a slow morning in Uji before the crowds<span style={{ display: "block", fontSize: 8, color: "var(--label-tertiary)" }}>kept as draft · 5d ago</span></div>
              </div>
            </div>
            <div style={{ marginTop: "auto", display: "flex", justifyContent: "flex-end" }}><MiniBtn ghost>Reshape Rain</MiniBtn></div>
          </div>
        </div>
        <div ref={notesRef}><Notes items={notes} open={open} set={setOpen} /></div>
      </div>
    );
  }

  /* --- screen 02: shape --- */
  function ShapeScreen() {
    const [open, setOpen] = useState(-1);
    const notesRef = useRef(null);
    function flip(i) {
      const opening = open !== i;
      setOpen(opening ? i : -1);
      if (opening) setTimeout(function () { if (notesRef.current) notesRef.current.scrollIntoView({ block: "nearest", behavior: "smooth" }); }, 60);
    }
    const [e, setE] = useState(72);
    const [c, setC] = useState(68);
    const [p, setP] = useState(28);
    function bk(v) { return v >= 50 ? "1" : "0"; }
    const title = VC_TITLES[bk(e) + bk(p)];
    const body = VC_BODIES[bk(e) + bk(c) + bk(p)];
    const notes = [
      { k: "1 · Two directions", t: "Where I am, and where I want to be", p: "The seed resolved into an identity question rather than a data source. Where I am holds the voice the user already has, from any platform, pasted or as screenshots. Where I want to be holds inspirations: anything that pulls them forward, with the register borrowed and the identity left alone. The old archetypes dissolved into category options inside both, so aspiration is expressed by category, not by template." },
      { k: "2 · Sliders plus words", t: "Spectrum controls for the dimensions, the user's words for the language", p: "I tried replacing the sliders with binary word pairs and reversed it: pairs collapsed the spectrum users actually feel. The final control is both layers. Sliders carry the three dimensions, and a trait field carries the user's own words, which testing showed is how people describe a version of themselves. One identity line remains as the ownership ritual." },
      { k: "3 · The voice check", t: "The preview re-voices labeled examples, never your content", p: "The live sample is an example note on a neutral topic, labeled as such, with more examples one tap away. Judging the voice on neutral content isolates the one variable this screen controls, keeps shaping from sliding into composing, and still removes the prompt-skill prerequisite: users steer against visible output. Because the example is not theirs, the save action carries the weight, so it anchors the whole screen." },
    ];
    function DialRow(props) {
      return (
        <div>
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 9.5, color: "var(--label-primary)", marginBottom: 3 }}><span>{props.l}</span></div>
          <input type="range" min="0" max="100" value={props.v} onChange={function (ev) { props.set(+ev.target.value); }} aria-label={props.l} style={{ width: "100%", accentColor: "var(--accent)", height: 18, margin: 0 }} />
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 8.5, color: "var(--label-tertiary)" }}><span>{props.lo}</span><span>{props.hi}</span></div>
        </div>
      );
    }
    return (
      <div className="nmc" style={{ gap: 18 }}>
        <Compare label="Original: profile builder" changes={[
          "Replaced personal facts with voice controls. The facts described a person; they did not control how output sounds.",
          "Moved extraction upstream: a self now starts from the user's own posts, a creator they admire, or an archetype.",
          "Added a live sample note that re-renders as the dials move, so nobody sets up a voice blind.",
          "Held everything to one screen with a 90 second budget. The original spread setup across two pages.",
        ]}>
          <div style={{ display: "flex", gap: 8, flex: 1 }}>
            <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 6 }}>
              <div className="nmc-ocard" style={{ textAlign: "center" }}>Rain<br /><span style={{ fontSize: 7.5, color: "#6e6c7a" }}>avatar</span></div>
              <div className="nmc-ocard" style={{ flex: 1 }}>Intro: INFJ Gemini. I am an introvert who enjoys me time. I write diaries and love to collect shells. My favorite ice cream flavors are blueberries, hazelnut.</div>
            </div>
            <div style={{ flex: 1.2, display: "flex", flexDirection: "column", gap: 6 }}>
              <div><span className="nmc-otag">Gen AI</span><span className="nmc-otag">Digital Assets</span><span className="nmc-otag">Crypto</span><span className="nmc-otag">Conversation</span></div>
              <div className="nmc-ocard" style={{ flex: 1 }}>What I wish to be:</div>
              <div style={{ display: "flex", gap: 6, flex: 1 }}><div className="nmc-ocard" style={{ flex: 1 }}>Who I like:</div><div className="nmc-ocard" style={{ flex: 1 }}>Social platforms I use:</div></div>
            </div>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}><span className="nmc-obtn">Save this profile</span><span className="nmc-obtn cta">Continue</span></div>
        </Compare>
        <div className="nmc-hint">Click a numbered dot on the wireframe, or a card below, to open its annotation.</div>
        <div className="nmc-frame">
          <div className="nmc-fz">
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <div className="nmc-logo">nomi</div>
              <span style={{ fontSize: 9, color: "var(--label-tertiary)" }}>step 1 of 1 · about 90 seconds</span>
            </div>
            <div className="nmc-row3" style={{ display: "grid", gridTemplateColumns: "1.05fr 1fr 1.15fr", gap: "2.2%", flex: 1, minHeight: 0, marginTop: "2%" }}>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, minHeight: 0 }}>
                <div style={{ fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--label-tertiary)" }}>Seed</div>
                <div className="nmc-pcard" style={{ position: "relative", flex: 1, padding: "6% 7%", display: "flex", flexDirection: "column", gap: 6 }}>
                  <Dot n={1} st={{ top: -9, left: -9 }} on={open === 0} onClick={function () { flip(0); }} />
                  <div className="nmc-lbox" style={{ borderColor: "var(--accent)", boxShadow: "0 0 0 1px var(--accent)" }}>
                    <span style={{ fontSize: 10, fontWeight: 500, color: "var(--label-primary)", display: "block" }}>Where I am</span>
                    <span style={{ fontSize: 8.5 }}>The voice you have today. RedNote posts work best, but any writing counts: captions, blogs, notes, screenshots.</span>
                  </div>
                  <div className="nmc-lbox">
                    <span style={{ fontSize: 10, fontWeight: 500, color: "var(--label-primary)", display: "block" }}>Where I want to be</span>
                    <span style={{ fontSize: 8.5 }}>Inspirations: upload anything that pulls you forward. Nomi borrows the register, never the identity.</span>
                  </div>
                  <div className="nmc-lbox">
                    <span style={{ fontSize: 10, fontWeight: 500, color: "var(--label-primary)", display: "block" }}>Categories, in both</span>
                    <span><span className="nmc-lpill">food</span><span className="nmc-lpill">travel</span><span className="nmc-lpill">honest reviews</span><span className="nmc-lpill">slow living</span></span>
                  </div>
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, minHeight: 0 }}>
                <div style={{ fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--label-tertiary)" }}>Tune</div>
                <div className="nmc-pcard" style={{ position: "relative", flex: 1, padding: "7% 9%", display: "flex", flexDirection: "column", gap: 10, justifyContent: "center" }}>
                  <Dot n={2} st={{ top: -9, right: -9 }} on={open === 1} onClick={function () { flip(1); }} />
                  <DialRow l="Energy" v={e} set={setE} lo="quiet" hi="high energy" />
                  <DialRow l="Closeness" v={c} set={setC} lo="useful for readers" hi="diary close" />
                  <DialRow l="Structure" v={p} set={setP} lo="off the cuff" hi="structured" />
                  <div className="nmc-lbox">Your own words: warm, picky, detail-driven. Add or remove traits.</div>
                  <div className="nmc-lbox">Anything else that defines you: whatever the options above did not cover.</div>
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, minHeight: 0 }}>
                <div style={{ fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--label-tertiary)" }}>Hear it</div>
                <div style={{ position: "relative", flex: 1, background: "color-mix(in srgb, var(--accent) 8%, transparent)", border: "1px solid color-mix(in srgb, var(--accent) 30%, transparent)", borderRadius: 10, padding: "5% 6%", display: "flex", flexDirection: "column", gap: 8 }}>
                  <Dot n={3} st={{ top: -9, right: -9 }} on={open === 2} onClick={function () { flip(2); }} />
                  <div style={{ fontSize: 8.5, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--accent)" }}>voice check · an example, not your content</div>
                  <div className="nmc-pcard" style={{ padding: "9px 11px", flex: 1, display: "flex", flexDirection: "column", gap: 5 }}>
                    <div style={{ fontSize: 11.5, fontWeight: 500, lineHeight: 1.35 }}>{title}</div>
                    <div className="nmc-pre" style={{ fontSize: 9.5, lineHeight: 1.55, color: "var(--label-secondary)" }}>{body}</div>
                    <div style={{ fontSize: 8.5, color: "var(--label-tertiary)", marginTop: "auto" }}>#bakery #morningfind</div>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 8 }}>
                    <span style={{ fontSize: 8.5, color: "var(--label-secondary)" }}>a sample topic, so the voice is judged before it touches your notes</span>
                    <MiniBtn>Save Rain</MiniBtn>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div ref={notesRef}><Notes items={notes} open={open} set={setOpen} /></div>
      </div>
    );
  }

  /* --- screen 03: compose --- */
  function ComposeScreen() {
    const [open, setOpen] = useState(-1);
    const notesRef = useRef(null);
    function flip(i) {
      const opening = open !== i;
      setOpen(opening ? i : -1);
      if (opening) setTimeout(function () { if (notesRef.current) notesRef.current.scrollIntoView({ block: "nearest", behavior: "smooth" }); }, 60);
    }
    const notes = [
      { k: "1 · Self as context", t: "The chip introduces the self and opens Shape", p: "Returning users reach this screen in two clicks. The chip carries the self's name and its traits, so anyone can tell at a glance who is writing, and tapping it goes straight to Shape for reshaping. The Nyla door stays on the shelf, where the demand count lives." },
      { k: "2 · One input", t: "Fewer pages before value", p: "My drop-off metric made the argument: every page before generation is attrition surface. Per-note context stays per note; only what the user explicitly teaches persists to the self." },
      { k: "3 · Warm starts", t: "The recipe suggests, the user decides", p: "These are labeled as recipe suggestions and measured by tap-through. Nomi's guidance layer serves; it does not narrate." },
    ];
    return (
      <div className="nmc" style={{ gap: 18 }}>
        <Compare label="Original: context page, then a create page" changes={[
          "Merged the context drop and the creation prompt into one input. To a creator they are the same sentence.",
          "Reduced the self to a switchable chip. Identity editing does not belong on the path to writing a note.",
          "Removed the accounts list; multi-account management belongs to Nyla, not this trial.",
          "Added warm starts: a series continuation, one trending pull, an unfinished draft.",
        ]}>
          <div className="nmc-ogrey" style={{ display: "flex", gap: 8, alignItems: "center", justifyContent: "space-between" }}>
            <span>Rain · INFJ Gemini. I am an introvert…</span><span className="nmc-obtn" style={{ fontSize: 8 }}>Update Looks</span>
          </div>
          <div style={{ fontSize: 9.5, margin: "8px 0 6px", color: "#dddce4" }}>Give me some context of what you are creating today:</div>
          <div style={{ display: "flex", gap: 8, flex: 1 }}>
            <div className="nmc-ogrey" style={{ flex: 0.6, display: "flex", alignItems: "center", justifyContent: "center" }}>Drop here</div>
            <div className="nmc-ocard" style={{ flex: 1.4 }}>Give me anything. Input a link to your most recent work, a paper you wrote, a conversation, books you have read, transcripts from conferences.</div>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}><span style={{ fontSize: 7.5, color: "#8b8995", textDecoration: "underline" }}>Accounts I manage</span><span className="nmc-obtn cta">Continue</span></div>
        </Compare>
        <div className="nmc-hint">Click a numbered dot on the wireframe, or a card below, to open its annotation.</div>
        <div className="nmc-frame">
          <div className="nmc-fz">
            <div className="nmc-logo">nomi</div>
            <div className="nmc-composewrap">
              <div style={{ position: "relative", display: "flex", alignItems: "center", gap: 8, alignSelf: "flex-start", background: "var(--fill-secondary)", border: "1px solid var(--pf-border)", borderRadius: 999, padding: "5px 12px 5px 6px" }}>
                <Dot n={1} st={{ top: -9, right: -9 }} on={open === 0} onClick={function () { flip(0); }} />
                <Orb s={18} />
                <span style={{ fontSize: 10, color: "var(--label-primary)" }}>Rain</span>
                <span style={{ fontSize: 9, color: "var(--label-tertiary)", borderLeft: "1px solid var(--pf-border)", paddingLeft: 8 }}>warm · high energy · honest</span>
                <span style={{ fontSize: 9, color: "var(--label-tertiary)", borderLeft: "1px solid var(--pf-border)", paddingLeft: 8 }}>tap to reshape</span>
              </div>
              <div style={{ fontSize: 14, color: "var(--label-primary)" }}>What is the note about today?</div>
              <div className="nmc-pcard" style={{ position: "relative", padding: "16px 18px", minHeight: "34%", display: "flex", flexDirection: "column" }}>
                <Dot n={2} st={{ top: -9, right: -9 }} on={open === 1} onClick={function () { flip(1); }} />
                <div style={{ fontSize: 12, color: "var(--label-tertiary)" }}>Type it, paste it, or drop it: an idea, a link, a photo set, a transcript. Rain reads anything. Output is English by default.</div>
                <div style={{ marginTop: "auto", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <div style={{ display: "flex", gap: 6 }}>
                    <span style={{ fontSize: 8.5, border: "1px dashed var(--pf-border)", borderRadius: 6, padding: "3px 8px", color: "var(--label-secondary)" }}>add file</span>
                    <span style={{ fontSize: 8.5, border: "1px dashed var(--pf-border)", borderRadius: 6, padding: "3px 8px", color: "var(--label-secondary)" }}>add link</span>
                  </div>
                  <MiniBtn>Generate 3 notes</MiniBtn>
                </div>
              </div>
              <div style={{ position: "relative", display: "flex", gap: 6, flexWrap: "wrap" }}>
                <Dot n={3} st={{ top: -9, left: -9 }} on={open === 2} onClick={function () { flip(2); }} />
                <span className="nmc-lpill">continue: Japan matcha series, part 2</span>
                <span className="nmc-lpill">recipe: trending in your niche, Kyoto autumn</span>
                <span className="nmc-lpill">resume: saved draft from Tuesday</span>
              </div>
            </div>
          </div>
        </div>
        <div ref={notesRef}><Notes items={notes} open={open} set={setOpen} /></div>
      </div>
    );
  }

  /* --- screen 04: studio --- */
  function StudioScreen() {
    const [open, setOpen] = useState(-1);
    const notesRef = useRef(null);
    function flip(i) {
      const opening = open !== i;
      setOpen(opening ? i : -1);
      if (opening) setTimeout(function () { if (notesRef.current) notesRef.current.scrollIntoView({ block: "nearest", behavior: "smooth" }); }, 60);
    }
    const notes = [
      { k: "1 · Page preview", t: "The panel simulates your own page, not a generic feed", p: "Seeing the note inside your page is the sharpest version of the question my study asked: is this me, here? Users can upload a screenshot of their current RedNote page to simulate the full grid, and a drafts box holds every unposted note as cards, so several can be placed, dragged into order, and previewed together, with the current one highlighted. Cells follow RedNote's real card anatomy: 3:4 cover, two-line title, author row." },
      { k: "2 · Note anatomy", t: "Three registers, covers by upload", p: "The drafts are a guide, a review, and a diary entry, which forces a real choice. Covers are user photographs, never generated; the concept line describes the shot until one is uploaded." },
      { k: "3 · Triage and refinement", t: "Keep, discard, and three scoped rewrites", p: "The tone, word choice, and attitude scopes come from my original board notes. Keep and discard preserve the triage intent of my swipe stack with every draft visible and each click legible in analytics." },
      { k: "4 · Visible learning", t: "Edits teach the self only when the user says so", p: "The teach control is the second learning moment after seeding. It converts editing labor into compounding value, and it keeps consent explicit: triage clicks are choices, not training data." },
    ];
    const drafts = [
      { sel: true, cover: "upload cover · concept: tasting flight, Uji storefront", t: "5 matcha stores in Japan worth the flight", b: "I planned a whole trip around matcha and regret nothing. queue times and what to order first below.", g: "#japantravel 2.1M · #matcha 1.4M" },
      { cover: "upload cover · concept: twelve desserts, scored flat lay", t: "I tried 12 matcha desserts in Kyoto", b: "criteria: grind, sweetness honesty, texture, price. number 4 will start fights. scores below.", g: "#kyotofood 860K · #matchareview 640K" },
      { cover: "upload cover · concept: empty street, first light, one cup", t: "a slow morning in Uji before the crowds", b: "no list today. one street before the shops opened, one warm mochi, one small routine.", g: "#slowtravel 920K · #diary 3.4M" },
    ];
    return (
      <div className="nmc" style={{ gap: 18 }}>
        <Compare label="Original: generation cards, then a detail screen" changes={[
          "Merged generation and editing into one screen and promoted the feed preview to a fixed panel.",
          "Made the three drafts three distinct registers of the note rather than three variations of one text.",
          "Replaced the swipe stack with keep and discard buttons; the job was triage and buttons do it with all drafts visible.",
          "Replaced the image toggle with a cover upload; the product does not generate images.",
          "Routed all learning through a visible teach control; nothing trains silently.",
        ]}>
          <div style={{ display: "flex", gap: 8, flex: 1 }}>
            <div style={{ flex: 1.4, display: "flex", flexDirection: "column", gap: 6 }}>
              <div style={{ display: "flex", gap: 6, flex: 1 }}><div className="nmc-ocard" style={{ flex: 1 }}></div><div className="nmc-ocard" style={{ flex: 1 }}></div><div className="nmc-ocard" style={{ flex: 1 }}></div></div>
              <div className="nmc-ogrey">What changes would you like to make? · Texts / Image toggle</div>
              <div className="nmc-ogrey" style={{ display: "flex", gap: 10, justifyContent: "center" }}>check mark · card stack · cross mark</div>
            </div>
            <div style={{ flex: 0.7, display: "flex", flexDirection: "column", gap: 4 }}>
              <div className="nmc-ogrey" style={{ fontSize: 7.5 }}>#PredictiveAI · 1M views</div>
              <div className="nmc-ogrey" style={{ fontSize: 7.5 }}>#GenerativeAI · 3.1M views</div>
              <div className="nmc-ogrey" style={{ fontSize: 7.5 }}>#BigData · 900K views</div>
              <div className="nmc-ogrey" style={{ fontSize: 7.5, flex: 1 }}>This post performs best at noon on workdays.</div>
            </div>
          </div>
        </Compare>
        <div className="nmc-hint">Click a numbered dot on the wireframe, or a card below, to open its annotation.</div>
        <div className="nmc-frame">
          <div className="nmc-fz">
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <div className="nmc-logo">nomi</div><span style={{ fontSize: 9, color: "var(--label-tertiary)" }}>Rain · 3 drafts · English</span>
            </div>
            <div className="nmc-rowstudio" style={{ display: "grid", gridTemplateColumns: "0.8fr 2.2fr", gap: "2.2%", alignItems: "start", marginTop: "1.6%" }}>
              <div className="nmc-gcard" style={{ position: "relative", padding: "4% 5%", display: "flex", flexDirection: "column", gap: 6, minHeight: 0 }}>
                <Dot n={1} st={{ top: -9, left: -9 }} on={open === 0} onClick={function () { flip(0); }} />
                <div style={{ fontSize: 8, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--label-tertiary)" }}>Your RedNote page preview · drafts box</div>
                <div style={{ fontSize: 8, color: "var(--label-tertiary)" }}>your RedNote page, simulated from a screenshot</div>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 5 }}>
                  <div style={{ background: "var(--fill-secondary)", borderRadius: 5, aspectRatio: "3 / 4" }}></div>
                  <div className="nmc-pcard" style={{ outline: "2px solid var(--accent)", display: "flex", alignItems: "flex-end", padding: 5, borderRadius: 5, aspectRatio: "3 / 4" }}><span style={{ fontSize: 8.5, fontWeight: 500, lineHeight: 1.3 }}>5 matcha stores in Japan worth the flight</span></div>
                  <div style={{ background: "var(--fill-secondary)", borderRadius: 5, aspectRatio: "3 / 4" }}></div>
                  <div style={{ background: "var(--fill-secondary)", borderRadius: 5, aspectRatio: "3 / 4" }}></div>
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                <div className="nmc-row3" style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
                  {drafts.map(function (d, i) {
                    return (
                      <div key={i} className="nmc-pcard" style={{ position: "relative", padding: "4.5% 5%", display: "flex", flexDirection: "column", gap: 5, minHeight: 0, outline: d.sel ? "2.5px solid var(--accent)" : "none" }}>
                        {i === 0 ? <Dot n={2} st={{ top: -9, right: -9 }} on={open === 1} onClick={function () { flip(1); }} /> : null}
                        <div style={{ fontSize: 8, color: "var(--label-tertiary)", border: "1px dashed var(--pf-border)", borderRadius: 5, padding: "3px 6px" }}><u style={{ color: "var(--accent)" }}>{d.cover.split(" · ")[0]}</u> · {d.cover.split(" · ")[1]}</div>
                        <div style={{ fontSize: 10.5, fontWeight: 500, lineHeight: 1.3, color: "var(--label-primary)" }}>{d.t}</div>
                        <div style={{ fontSize: 8.5, lineHeight: 1.5, color: "var(--label-secondary)", overflow: "hidden" }}>{d.b}</div>
                        <div style={{ marginTop: "auto", fontSize: 8, color: "var(--label-tertiary)" }}>{d.g}</div>
                        <div style={{ display: "flex", gap: 5 }}>
                          <span style={{ fontSize: 8, borderRadius: 999, padding: "2px 8px", background: "color-mix(in srgb, #4caf7d 16%, transparent)", color: "var(--label-primary)", border: "1px solid color-mix(in srgb, #4caf7d 40%, transparent)" }}>keep</span>
                          <span style={{ fontSize: 8, borderRadius: 999, padding: "2px 8px", background: "transparent", color: "var(--label-secondary)", border: "1px solid var(--pf-border)" }}>discard</span>
                        </div>
                      </div>
                    );
                  })}
                </div>
                <div className="nmc-gcard" style={{ position: "relative", padding: "2% 2.4%", display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                  <Dot n={3} st={{ top: -9, left: -9 }} on={open === 2} onClick={function () { flip(2); }} />
                  <span style={{ fontSize: 9.5, color: "var(--label-primary)" }}>Refine:</span>
                  <span className="nmc-lpill">tone</span><span className="nmc-lpill">word choice</span>
                  <span className="nmc-lpill" style={{ borderColor: "var(--accent)", color: "var(--accent)" }}>attitude</span>
                  <span className="nmc-lpill">shorter</span>
                  <span style={{ position: "relative", marginLeft: "auto", display: "flex", alignItems: "center", gap: 6, fontSize: 8.5, color: "var(--accent)" }}>
                    <Dot n={4} st={{ top: -14, right: -10 }} on={open === 3} onClick={function () { flip(3); }} />
                    <span style={{ width: 22, height: 12, borderRadius: 999, background: "var(--accent)", position: "relative", display: "inline-block" }}><span style={{ position: "absolute", right: 1.5, top: 1.5, width: 9, height: 9, borderRadius: "50%", background: "#fff" }} /></span>
                    teach Rain from my edits
                  </span>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
                  <span style={{ display: "inline-flex", alignItems: "center", gap: 7, border: "1px solid color-mix(in srgb, var(--accent) 30%, transparent)", background: "color-mix(in srgb, var(--accent) 8%, transparent)", borderRadius: 8, padding: "5px 10px", fontSize: 9, color: "var(--accent)" }}>recipe: notes like this perform best Thursday to Sunday, 12 to 2pm PT</span>
                  <span style={{ display: "inline-flex", gap: 8 }}><MiniBtn ghost>Download</MiniBtn><MiniBtn>Copy to clipboard</MiniBtn></span>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div ref={notesRef}><Notes items={notes} open={open} set={setOpen} /></div>
      </div>
    );
  }

  function IterationsPanel() {
    const [screen, setScreen] = useState(0);
    return (
      <div className="nmc" style={{ gap: 40 }}>
        <SectionHead kicker="Iterations" title="From eight screens to four, with each revision argued"
          lead="I translated each research signal into a product constraint. Every major revision below answers a measured failure, a behavioral signal, or an explicit trade-off." />
        <div className="pf-glass nmc-map">
          <div className="pf-eyebrow" style={{ marginBottom: 14, color: "var(--accent)" }}>Revised flow</div>
          <Chain nodes={[
            { t: "01 Shelf", s: "the saved self" },
            { t: "02 Shape", s: "first run only, under 90s" },
            { t: "03 Compose", s: "one input" },
            { t: "04 Studio", s: "drafts, triage, copy out" },
          ]} />
          <div className="nmc-loop">Returning users skip 02. Accepted edits in 04 teach the self. The locked card on 01 counts Nyla demand.</div>
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="Three input decisions I standardized across builds"
          sub="Across versions of Nomi, the same three input questions kept getting re-answered: by me, and by the AI pair tools I built with. The interim build below shows both patterns mid-evolution, redrawn in light mode. I turned the answers into rules and applied them everywhere." />
        <div className="nmc-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))", gap: 18 }}>
          <div>
            <div className="nmc-olabel">Interim build: profile as a form, pills arriving</div>
            <div className="nmc-mock">
              <div className="mt">Your creative profile</div>
              <div style={{ fontSize: 8.5, margin: "2px 0 8px" }}>This is how Nomi learns to sound like you. Fill in as much as you like.</div>
              <div style={{ marginBottom: 6 }}><span className="nmc-lpill">Gen AI</span><span className="nmc-lpill">Digital Assets</span><span className="nmc-lpill">Crypto</span><span className="nmc-lpill">Predictive AI</span><span className="nmc-lpill">Conversation</span><span className="nmc-lpill dim">add topic</span></div>
              <div className="nmc-lbox" style={{ marginBottom: 6 }}>INFJ Gemini. I am an introvert who enjoys me time. I write diaries and love to collect shells.</div>
              <div style={{ display: "flex", gap: 6, flex: 1 }}>
                <div className="nmc-lbox" style={{ flex: 1 }}>Who I like<br /><span className="nmc-lpill">Paul Graham</span><span className="nmc-lpill">Andrej Karpathy</span><span className="nmc-lpill">Li Jin</span></div>
                <div className="nmc-lbox" style={{ flex: 1 }}>Platforms I use<br /><span className="nmc-lpill">RedNote</span><span className="nmc-lpill dim">LinkedIn</span><span className="nmc-lpill dim">Instagram</span></div>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8 }}><MiniBtn ghost>Save profile</MiniBtn><MiniBtn>Continue</MiniBtn></div>
            </div>
          </div>
          <div>
            <div className="nmc-olabel">Interim build: five variations, prompt on the same screen</div>
            <div className="nmc-mock">
              <div style={{ fontSize: 7.5, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--label-tertiary)", marginBottom: 5 }}>Variations</div>
              <div className="nmc-varrow">
                <div className="nmc-lvar"><div className="lc" /><div className="lb"><b>Marginal Benefits of AI in Prod</b>AI product design delivers significant marginal benefits by accelerating iterative processes.</div></div>
                <div className="nmc-lvar"><div className="lc" /><div className="lb"><b>Big Data Modeling in Predictiv</b>AI product design delivers significant marginal benefits by accelerating iterative processes.</div></div>
                <div className="nmc-lvar"><div className="lc" /><div className="lb"><b>Big Data Modeling in Human In</b>AI product design delivers significant marginal benefits by accelerating iterative processes.</div></div>
                <div className="nmc-lvar"><div className="lc" /><div className="lb"><b>AI Automation in Design Cycles</b>How AI automation is streamlining the iterative cycles of product design.</div></div>
                <div className="nmc-lvar"><div className="lc" /><div className="lb"><b>The Front-End Reliance of AI</b>A deep look at why AI concepts depend so heavily on front-end human interactions.</div></div>
              </div>
              <div className="nmc-lbox" style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
                <span className="nmc-lpill">Predictive AI</span><span className="nmc-lpill">AI Visualization</span>
                <span style={{ flex: 1, minWidth: 120 }}>I want to create a series of notes that investigate the marginal benefits of AI in product design.</span>
                <MiniBtn>Proceed</MiniBtn>
              </div>
            </div>
          </div>
        </div>
        <div className="nmc-grid">
          {RULES.map(function (r) {
            return (
              <div key={r.k} className="pf-glass nmc-card">
                <div className="nmc-idx">{r.k}</div>
                <h4>{r.t}</h4>
                <p>{r.p}</p>
                <div className="nmc-ev">{r.ev}</div>
              </div>
            );
          })}
        </div>

        <hr className="pf-rule" style={{ margin: 0 }} />
        <ScreenSwitcher idx={screen} set={setScreen} />
        {screen === 0 ? <ShelfScreen /> : null}
        {screen === 1 ? <ShapeScreen /> : null}
        {screen === 2 ? <ComposeScreen /> : null}
        {screen === 3 ? <StudioScreen /> : null}

        <hr className="pf-rule" style={{ margin: 0 }} />
        <H3Block title="Eight design questions I raised and resolved"
          sub="Reviewing the original wireframes against the research produced eight open questions. I resolved each with a decision and priced it as a trade-off." />
        <div className="nmc-qgrid">
          {RES.map(function (r) {
            return (
              <div key={r.k} className="pf-glass nmc-card">
                <div className="nmc-idx">{r.k}</div>
                <h4>{r.t}</h4>
                <div className="nmc-blk"><b>Question</b>{r.q}</div>
                <div className="nmc-blk dec"><b>Decision</b>{r.d}</div>
                <div className="nmc-blk trade"><b>Trade-off</b>{r.tr}</div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  /* ============================================================
     PROTOTYPE: the one embedded piece, framed quietly
     ============================================================ */
  function PrototypePanel() {
    function sync(ifr) {
      try {
        const doc = ifr.contentDocument;
        if (!doc) return;
        const fit = function () {
          try {
            /* body.scrollHeight hugs the prototype itself; documentElement
               never shrinks below the iframe viewport. */
            const h = doc.body.scrollHeight;
            if (h) ifr.style.height = Math.ceil(h) + "px";
          } catch (e) {}
        };
        fit();
        setTimeout(fit, 200);
        setTimeout(fit, 700);
        if (window.ResizeObserver && doc.body) new ResizeObserver(fit).observe(doc.body);
        if (ifr.contentWindow) ifr.contentWindow.addEventListener("resize", fit);
        window.addEventListener("resize", fit);
        /* keep the prototype's theme in step with the site's; its own
           moon button can still override until the site next changes */
        const applyTheme = function () {
          try {
            const t = document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
            ifr.style.colorScheme = t;
            if (ifr.contentWindow && ifr.contentWindow.__setNomiTheme) ifr.contentWindow.__setNomiTheme(t);
          } catch (e) {}
        };
        applyTheme();
        new MutationObserver(applyTheme).observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
      } catch (e) {}
    }
    return (
      <div className="nmc" style={{ gap: 28 }}>
        <SectionHead kicker="Prototype" title="Interactive prototype of the four screens"
          lead="The revised four-screen prototype turns the research decisions into one system: choose a saved social-self, reshape it when needed, compose one idea, then triage and refine platform-native drafts in Studio. Try it: reshape Rain, hear the voice preview re-render as you tune, compose, compare the three drafts, refine, and teach the self from your edits. Use the arrows or the step pills in the top bar to move between screens." />
        <iframe title="nomi interactive prototype" src="assets/nomi-rednote-flow-v4.html?embed=proto" scrolling="no"
          onLoad={function (e) { sync(e.target); }}
          style={{ display: "block", width: "100%", height: 980, border: 0, borderRadius: 18, background: "transparent" }} />
        <p className="nmc-sub" style={{ fontSize: 13, color: "var(--label-tertiary)" }}>Prototype boundaries: generation is canned to one sample idea, a Japan matcha and mochi trip, so the step is believable without a model behind it; the voice check re-voices labeled example topics and never user content; refine controls swap written variants; custom refines are acknowledged but not applied; uploads never leave the page, including the RedNote page screenshot the Studio preview simulates from; the avatar recolors are placeholders until the final five colors arrive; and the waitlist link counts a click and goes nowhere. Navigation, renaming, the look preview and confirm, seeding from where you are and where you want to be, triage, the drafts box with drag ordering, the teach control, copy, and download are real.</p>
      </div>
    );
  }

  /* ============================================================
     OUTCOME
     ============================================================ */
  const FUNNEL = [
    ["Self created", "time to save and seed source chosen; covers the extraction-completion metric and the unresolved setup-speed gap"],
    ["First generation", "completion rate and keep or discard per register; covers generation completion and drop-off"],
    ["Cover uploaded", "upload rate per kept draft; decides whether cover generation ever earns a place"],
    ["Note copied out", "copy events per session, the honest proxy for posting"],
    ["Return with the same self", "second session within 7 days; the willingness-to-return metric that decides Nyla"],
    ["Self taught", "teach acceptances per session; makes persistence measurable rather than stated"],
    ["Nyla entry clicked", "locked-card opens and waitlist joins; branch intent becomes counted demand and a willingness signal"],
  ];
  const WEEK1 = [
    { k: "Week one", t: "800+ unique visitors", p: "Acquired through Instagram and Facebook ads in the first week live, against a product that had existed for less than a month. That is enough acquisition and production exposure to start observing behavior, but one week of paid traffic establishes none of the things that matter next: retention, social-self reuse, or product-market fit. The funnel below exists to measure exactly those." },
    { k: "How they arrived", t: "87% mobile in-app browsers", p: "Most visitors never saw a desktop or even a real mobile browser: they arrived inside Instagram's own webview. That one number reset the design priorities on the spot." },
    { k: "Shipping under load", t: "3 deploy cycles, zero downtime", p: "The landing rebuild and the full mobile overhaul shipped while the ad campaign was still running, without taking the product down once." },
  ];
  function OutcomePanel() {
    return (
      <div className="nmc" style={{ gap: 32 }}>
        <SectionHead kicker="Outcome" title="Launched solo, then iterated under live traffic"
          lead="Launching changed the question again. The prototype studies measured preference under controlled conditions; production now lets me measure whether creators voluntarily register, complete the social-self loop, return, and reuse it, without being asked to participate in a study. I moved Nomi from controlled preference testing into a measurable production system." />
        <p className="nmc-sub" style={{ marginTop: -8 }}>nomi shipped as a bilingual (中/EN) single-page app: a serverless API on Vercel and Redis, Google OAuth sign-in, GPT-powered generation with live web research, and an image-extraction pipeline that turns profile screenshots into editable post layouts. Shipping bilingual reversed the MVP's English-only body copy, a decision I revisited before launch once the product was facing real creators rather than a study cohort. Designed, built, and launched solo in under a month, then put in front of paid traffic.</p>

        <div className="nmc-grid">
          {WEEK1.map(function (c) {
            return (
              <div key={c.k} className="pf-glass nmc-card">
                <div className="nmc-idx">{c.k}</div>
                <h4>{c.t}</h4>
                <p>{c.p}</p>
              </div>
            );
          })}
        </div>

        <div className="nmc-blk"><b>The number that forced a redesign</b>
          The analytics were built from scratch for the launch: an event funnel, session accounting, and prompt
          logging across three tables, with per-day cohorts and second-resolution dwell tracking. They earned their
          keep immediately. Median dwell on the landing page was one second: people were arriving, glancing, and
          leaving before the product said anything. I treated that as a research finding rather than a traffic
          problem, rebuilt the landing page around what the first screen has to say, and overhauled the mobile
          experience the in-app-browser number demanded: 44px touch targets, iOS zoom elimination, and CJK-aware
          typography for the bilingual audience.
        </div>

        <SectionHead kicker="Instrumented" title="The activation funnel, now counted in production"
          lead="The funnel below maps each metric from my research notes onto a mechanism in the flow, and the launch instrumentation counts every stage per day. The two decisive numbers are return-with-the-same-self, which tests whether persistence became real, and Nyla entry clicks, which test whether one self creates demand for many." />
        <div className="nmc-funnel">
          {FUNNEL.map(function (f) {
            return <div key={f[0]} className="nmc-fstep"><div className="fn">{f[0]}</div><div className="fm">{f[1]}</div></div>;
          })}
        </div>
        <hr className="pf-rule" style={{ margin: 0 }} />
        <SectionHead kicker="What comes next" title="The next proof is repeated behavior"
          lead="The research established that a social-self can improve intended-self fit. Production now has to prove that the object becomes valuable over time. The measures: activation, Day-30 retention, social-self reuse, publish-ready posts per retained creator, and demand for a second social-self." />
        <div className="nmc-grid">
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Definition 01</div>
            <h4>Activated creator</h4>
            <p>A registered creator who shapes or selects a social-self, generates through it, and saves or copies at least one publish-ready result.</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Definition 02</div>
            <h4>Day-30 retained creator</h4>
            <p>An activated creator who returns around Day 30 and completes another meaningful creation flow.</p>
          </div>
          <div className="pf-glass nmc-card">
            <div className="nmc-idx">Definition 03</div>
            <h4>Social-self reuse</h4>
            <p>The same saved social-self is used in multiple creation sessions. This is the number that decides whether identity became product memory.</p>
          </div>
        </div>
        <p className="nmc-sub">If returning sessions and waitlist demand hold up, the next build is Nyla: the same self object, multiplied and managed. If they do not, the one-self loop still stands as a validated creator tool, and the research record shows exactly where the thesis stopped.</p>
        <div className="pf-glass nmc-map">
          <Chain nodes={[
            { t: "Controlled preference", s: "two rounds, 32 participants" },
            { t: "Repeated use", s: "production, now measuring" },
            { t: "Persistent social-self", s: "reuse across sessions" },
            { t: "Multi-self demand", s: "counted waitlist clicks" },
            { t: "Nyla", s: "the system that follows" },
          ]} />
          <div className="nmc-loop">Each arrow must be earned by evidence before the next build begins.</div>
        </div>
      </div>
    );
  }

  /* ---------- register ---------- */
  window.CASE_PANELS = window.CASE_PANELS || {};
  const reg = window.CASE_PANELS["nomi"] = window.CASE_PANELS["nomi"] || {};

  reg.Opening = OpeningPanel;
  reg.Research = ResearchPanel;
  reg.Ideation = IdeationPanel;
  reg.Iterations = IterationsPanel;
  reg.Prototype = PrototypePanel;
  reg.Outcome = OutcomePanel;

  const PrevTesting = reg.Testing;
  reg.Testing = function (props) {
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 56 }}>
        {PrevTesting ? React.createElement(PrevTesting, { case: props.case }) : null}
        <hr className="pf-rule" style={{ margin: 0 }} />
        <ResultsBlock />
        <hr className="pf-rule" style={{ margin: 0 }} />
        <InsightsBlock />
      </div>
    );
  };
})();
