/* ===========================================================================
   mock-db.jsx — ARGT MOCK DATA LAYER   ◆◆◆ FOLD SEAM ◆◆◆
   ---------------------------------------------------------------------------
   This is the ONLY place the dashboards read/write "server" data. No page
   hard-codes its own domain data anymore — every interactive surface calls:

       const [val, setVal] = window.useDB("collection")   // React hook, persists
       window.ARGT_DB.get("collection")                    // read current value
       window.ARGT_DB.set("collection", v|fn)              // write + notify + persist
       window.ARGT_DB.update("collection", fn)             // functional write

   ─────────────────────────────────────────────────────────────────────────
   HOW TO FOLD INTO THE LIVE APP
   ─────────────────────────────────────────────────────────────────────────
   • Each top-level key in SEED is a "collection" and maps 1:1 to a live
     endpoint, e.g.  creatorProfile  →  GET/PATCH /api/me/creator-profile.
   • The SEED object IS the response-shape contract. Replace the bodies of
     DB.get / DB.set / DB.update with real fetch() calls; keep the same keys
     and shapes and the UI needs zero changes.
   • Persistence here is localStorage ('argt-db-v1', versioned). In prod the
     server is the source of truth; drop the persist()/load() calls.
   • Nothing here is real PII or real algorithm detail — safe demo fixtures only.
   =========================================================================== */
(function () {
  "use strict";
  const LS_KEY = "argt-db-v1";
  const VERSION = 5;

  // ----- SEED FIXTURES (response-shape contracts; swap for server data) -----
  const SEED = {
    // ---------- CREATOR ----------
    creatorProfile: {
      stageName: "Maya Cole",
      city: "Tampa, FL",
      genre: "Soul",
      yearsActive: "6",
      bio: "Soul with a live-band heartbeat. Songs about leaving and coming back.",
      website: "mayacole.com",
      instagram: "@mayacolemusic",
      spotify: "spotify.com/artist/mayacole",
      youtube: "youtube.com/@mayacole",
    },
    auditionSubmission: {
      trackA: "",
      trackB: "",
      trackBio: "",
      setLength: "45 minutes",
      bandSize: "4",
      ridersUrl: "",
      submitted: false,
      submittedAt: null,
    },
    creatorProducts: [
      { id: "p1", name: "Tour tee · charcoal", price: "$28", detail: "S–XXL · 124 in stock", glyph: "👕", active: true },
      { id: "p2", name: "Single · vinyl 7\"", price: "$18", detail: "limited 500", glyph: "💿", active: true },
      { id: "p3", name: "Sticker pack", price: "$6", detail: "set of 4", glyph: "✦", active: true },
      { id: "p4", name: "Bundle · tee + vinyl", price: "$40", detail: "save $6", glyph: "📦", active: false },
    ],
    creatorMedia: [
      { id: "m1", type: "VIDEO", label: "Live at The Orpheum" },
      { id: "m2", type: "PHOTO", label: "Press shot 01" },
      { id: "m3", type: "AUDIO", label: "Garden State (master)" },
      { id: "m4", type: "PHOTO", label: "Backstage 02" },
      { id: "m5", type: "VIDEO", label: "Studio session" },
      { id: "m6", type: "AUDIO", label: "Acoustic demo" },
    ],
    creatorOpportunities: [
      { id: "o1", title: "Main Stage · Sat early slot", org: "ARGT Programming", fee: "$1,200", status: "open" },
      { id: "o2", title: "Halo Beauty brand collab reel", org: "Halo Beauty", fee: "$2,500", status: "open" },
      { id: "o3", title: "Pavilion acoustic session", org: "ARGT Programming", fee: "$600", status: "applied" },
      { id: "o4", title: "Clean Earth benefit single", org: "Clean Earth Initiative", fee: "Royalty split", status: "open" },
    ],
    creatorOrders: [
      { id: "ord1", item: "Tour tee · charcoal ×2", who: "S. Reilly", total: "$56", status: "approved" },
      { id: "ord2", item: "Vinyl 7\" ×1", who: "J. Wynn", total: "$18", status: "pending" },
      { id: "ord3", item: "Bundle ×1", who: "D. Kerr", total: "$40", status: "pending" },
    ],

    // ---------- FAN ----------
    fanReferral: { code: "KAM26", redeems: 12 },

    // ---------- SPONSOR ----------
    sponsorActivation: {
      zone: "Pavilion · gaming + lounge",
      goal: "Brand lift + sampling to Gen-Z fans",
      kpis: "50k impressions · 4k samples · 1.5k emails",
      hospitality: "12 VIP passes · 4 plus-ones",
      notes: "",
      confirmed: true,
    },
    sponsorDeliverables: [
      { id: "d1", label: "Logo on main-stage LED loop", status: "approved" },
      { id: "d2", label: "Pavilion footprint (20×20)", status: "approved" },
      { id: "d3", label: "Email feature (1 of 4 sends)", status: "pending" },
      { id: "d4", label: "Post-event recap deck", status: "draft" },
    ],

    // ---------- CREW ----------
    crewAssignments: [
      { id: "a1", title: "Stage lighting · Saturday 10 AM – 11 PM", pay: "$680 · 13h · OT after 8", status: "open" },
      { id: "a2", title: "Hospitality coverage · Sunday 12 PM – 8 PM", pay: "$420 · 8h", status: "open" },
      { id: "a3", title: "Crew call sheet brief · pre-festival", pay: "Wed Sep 17 · $200", status: "accepted" },
    ],

    // ---------- VETERANS ----------
    vetRecognition: { honorees: "", speaker: "", logistics: "" },

    // ---------- LOCAL BUSINESS ----------
    localOffer: {
      pct: "15%",
      starts: "Sep 17",
      ends: "Sep 21",
      terms: "One per wristband. Not combinable with other offers.",
      redemption: "Show QR at POS",
      published: false,
    },
    localCreative: {
      tagline: "Festival fuel, two blocks away.",
      description: "Show your ARGT wristband for 15% off any order all weekend.",
      logo: null,
      hero: null,
    },

    // ---------- PRESS ----------
    pressInterviews: [
      { id: "i1", subject: "Maya Cole (artist)", when: "Fri Sep 18 · 2:00 PM", status: "open" },
      { id: "i2", subject: "Festival founders", when: "Press week · by appt", status: "open" },
      { id: "i3", subject: "Clean Earth lead", when: "Sat Sep 19 · 11:00 AM", status: "requested" },
    ],

    // =====================================================================
    // LAUNCH COMMAND CENTER  (folds /launch/* + /admin/launch/*)
    // Each key = one live endpoint; the shape IS the response contract.
    // =====================================================================

    // ---------- TODAY / This Week  (GET /api/launch/this-week) ----------
    // tMinusWeek: integer weeks before the Sep 18 gate. status drives the board.
    launchTasks: [
      { id: "t1",  title: "Lock headliner contracts (3 of 5 signed)", engine: "content",  owner: "Casey",  tMinusWeek: 16, due: "Jun 5",  status: "blocked", kpi: "5 headliners", risk: "high" },
      { id: "t2",  title: "Founders-phase ticket cascade go-live", engine: "tickets",  owner: "Kam",   tMinusWeek: 16, due: "Jun 1",  status: "doing",   kpi: "Phase 1 live", risk: "high" },
      { id: "t3",  title: "Approve sponsor activation footprints", engine: "sponsors", owner: "Taylor", tMinusWeek: 16, due: "Jun 3",  status: "doing",   kpi: "8 of 12", risk: "med" },
      { id: "t4",  title: "Publish week-of social calendar", engine: "social",   owner: "Jordan", tMinusWeek: 16, due: "May 31", status: "todo",    kpi: "21 posts", risk: "low" },
      { id: "t5",  title: "Vendor village compliance audit", engine: "day-of",   owner: "Morgan", tMinusWeek: 15, due: "Jun 9",  status: "todo",    kpi: "40 vendors", risk: "med" },
      { id: "t6",  title: "Email sequence: ticket phase 1 announce", engine: "digital",  owner: "Jordan", tMinusWeek: 16, due: "Jun 1",  status: "doing",   kpi: "24k list", risk: "low" },
      { id: "t7",  title: "Confirm 5-stage power + rigging plan", engine: "day-of",   owner: "Morgan", tMinusWeek: 14, due: "Jun 16", status: "todo",    kpi: "5 stages", risk: "med" },
      { id: "t8",  title: "Clean Earth 10% pledge page QA", engine: "digital",  owner: "Jordan", tMinusWeek: 16, due: "Jun 2",  status: "done",    kpi: "Live", risk: "low" },
    ],

    // ---------- ENGINES  (GET /api/launch/engines) ----------
    // The festival's six operating engines. status: healthy|attention|paused.
    // NOTE: progress / status / openTasks are LIVE-DERIVED from launchTasks in
    // the UI (see engineLive() in launch-app.jsx) — the seed values below are
    // only a fallback/contract shape. In prod the server computes these rollups.
    launchEngines: [
      { key: "social",   label: "Social",   status: "healthy",   owner: "Jordan", progress: 72, openTasks: 4,  note: "Week-of calendar in review.", target: "2.5M reach",     enabled: true },
      { key: "digital",  label: "Digital",  status: "healthy",   owner: "Jordan", progress: 64, openTasks: 6,  note: "Email + site on track.", target: "24k list · site live", enabled: true },
      { key: "sponsors", label: "Sponsors", status: "attention", owner: "Taylor", progress: 58, openTasks: 9,  note: "4 activation footprints unconfirmed.", target: "$950k booked", enabled: true },
      { key: "tickets",  label: "Tickets",  status: "attention", owner: "Kam",    progress: 41, openTasks: 7,  note: "Founders phase go-live pending.", target: "10k sold",   enabled: true },
      { key: "content",  label: "Content",  status: "attention", owner: "Casey",  progress: 49, openTasks: 11, note: "2 headliner contracts outstanding.", target: "75+ artists", enabled: true },
      { key: "day-of",   label: "Day-Of",   status: "paused",    owner: "Morgan", progress: 23, openTasks: 14, note: "Opens after lineup locks.", target: "Show ready",   enabled: false },
    ],

    // ---------- INBOX / What changed  (GET /api/launch/inbox) ----------
    launchInbox: [
      { id: "n1", kind: "payment",   summary: "Halo Beauty sponsor deposit cleared ($12,000)", priority: "normal", entityKind: "sponsor",  entityId: "halo",   at: "12m",  readAt: null },
      { id: "n2", kind: "status",    summary: "Maya Cole moved Confirmed → Advanced",          priority: "normal", entityKind: "artist",   entityId: "maya",   at: "48m",  readAt: null },
      { id: "n3", kind: "flag",      summary: "Vendor V-22 missing certificate of insurance",  priority: "high",   entityKind: "vendor",   entityId: "v22",    at: "2h",   readAt: null },
      { id: "n4", kind: "applicant", summary: "9 new crew applications (lighting, audio)",      priority: "low",    entityKind: "crew",     entityId: "batch",  at: "3h",   readAt: "seen" },
      { id: "n5", kind: "status",    summary: "Founders phase sold 41% of allocation",          priority: "normal", entityKind: "tickets",  entityId: "phase1", at: "5h",   readAt: "seen" },
      { id: "n6", kind: "flag",      summary: "Block stage rigging quote over budget by $4.2k", priority: "high",   entityKind: "budget",    entityId: "rig",    at: "1d",   readAt: "seen" },
    ],

    // ---------- PIPELINES  (GET /api/launch/pipeline?audience=) ----------
    // One flat collection; audience + stage partition it into the right board.
    pipelineStages: ["Inquiry", "Review", "Confirmed", "Advanced"],
    pipelineItems: [
      // artist
      { id: "a-1", audience: "artist",  name: "Maya Cole",        stage: "Advanced",  owner: "Casey",  value: "Main · Sat",  meta: "Soul · Tampa",   updatedAt: "48m" },
      { id: "a-2", audience: "artist",  name: "Pillar Funk",      stage: "Confirmed", owner: "Casey",  value: "Frequency",   meta: "Funk · Miami",   updatedAt: "1d" },
      { id: "a-3", audience: "artist",  name: "Cane River",       stage: "Confirmed", owner: "Casey",  value: "Main · Sun",  meta: "Country · Tampa",updatedAt: "2d" },
      { id: "a-4", audience: "artist",  name: "The Anchors",      stage: "Review",    owner: "Casey",  value: "Headliner?",  meta: "Rock · Orlando", updatedAt: "3h" },
      { id: "a-5", audience: "artist",  name: "Quad Aux",         stage: "Inquiry",   owner: "Casey",  value: "—",           meta: "Hip-Hop · Jax",  updatedAt: "5h" },
      // sponsor
      { id: "s-1", audience: "sponsor", name: "Halo Beauty",      stage: "Advanced",  owner: "Taylor", value: "$24,000",     meta: "Brand Partner",  updatedAt: "12m" },
      { id: "s-2", audience: "sponsor", name: "Drift Beverages",  stage: "Confirmed", owner: "Taylor", value: "$40,000",     meta: "Presenting",     updatedAt: "1d" },
      { id: "s-3", audience: "sponsor", name: "Northwave Tech",   stage: "Review",    owner: "Taylor", value: "$18,000",     meta: "Brand Partner",  updatedAt: "6h" },
      { id: "s-4", audience: "sponsor", name: "Treasure Coast CU",stage: "Inquiry",   owner: "Taylor", value: "—",           meta: "Cultural",       updatedAt: "2d" },
      // vendor
      { id: "v-1", audience: "vendor",  name: "Smoke & Sear BBQ", stage: "Confirmed", owner: "Morgan", value: "V-08",        meta: "Food",           updatedAt: "1d" },
      { id: "v-2", audience: "vendor",  name: "Coastal Threads",  stage: "Confirmed", owner: "Morgan", value: "V-14",        meta: "Apparel",        updatedAt: "2d" },
      { id: "v-3", audience: "vendor",  name: "Neon Ink Tattoo",  stage: "Review",    owner: "Morgan", value: "—",           meta: "Experience",     updatedAt: "4h" },
      { id: "v-4", audience: "vendor",  name: "Glass & Grain",    stage: "Inquiry",   owner: "Morgan", value: "—",           meta: "Retail",         updatedAt: "1d" },
      // crew
      { id: "c-1", audience: "crew",    name: "A. Rivera",        stage: "Confirmed", owner: "Morgan", value: "Lighting",    meta: "ETCP cert",      updatedAt: "3h" },
      { id: "c-2", audience: "crew",    name: "J. Okafor",        stage: "Review",    owner: "Morgan", value: "Audio",       meta: "12 yrs",         updatedAt: "5h" },
      { id: "c-3", audience: "crew",    name: "9 new applicants", stage: "Inquiry",   owner: "Morgan", value: "Batch",       meta: "Mixed roles",    updatedAt: "3h" },
      // partner
      { id: "p-1", audience: "partner", name: "Clean Earth Initiative", stage: "Advanced",  owner: "Kam", value: "10% pledge", meta: "Cause",       updatedAt: "1d" },
      { id: "p-2", audience: "partner", name: "City of Fort Pierce",    stage: "Confirmed", owner: "Kam", value: "Permits",    meta: "Civic",       updatedAt: "2d" },
      { id: "p-3", audience: "partner", name: "Treasure Coast Vets",    stage: "Review",    owner: "Kam", value: "Wellness",   meta: "Nonprofit",   updatedAt: "1d" },
    ],

    // ---------- TALENT ADVANCE  (GET /api/launch/talent-advance) ----------
    talentAdvance: [
      { id: "ta1", artist: "Maya Cole",   stage: "Main",      setTime: "Sat 8:00 PM", fee: "$6,000", travel: "booked",   hospitality: "done",    techNeeds: "received", contract: "signed",   status: "ready" },
      { id: "ta2", artist: "Pillar Funk", stage: "Frequency", setTime: "Fri 9:30 PM", fee: "$4,200", travel: "pending",  hospitality: "pending", techNeeds: "received", contract: "signed",   status: "in-progress" },
      { id: "ta3", artist: "Cane River",  stage: "Main",      setTime: "Sun 6:00 PM", fee: "$3,800", travel: "n/a",      hospitality: "done",    techNeeds: "pending",  contract: "out",      status: "in-progress" },
      { id: "ta4", artist: "The Anchors", stage: "Main",      setTime: "Sat 10:00 PM",fee: "$9,500", travel: "pending",  hospitality: "pending", techNeeds: "pending",  contract: "drafting", status: "at-risk" },
    ],

    // ---------- MARKETING ----------
    // CommsCalendarPost{scheduledAt, channel, body, status} — GET /api/launch/comms
    commsCalendar: [
      { id: "cc1", scheduledAt: "May 31", channel: "Instagram", title: "Phase 1 tickets teaser",        status: "approved",  owner: "Jordan" },
      { id: "cc2", scheduledAt: "Jun 1",  channel: "Email",     title: "Founders phase on sale",         status: "approved",  owner: "Jordan" },
      { id: "cc3", scheduledAt: "Jun 2",  channel: "TikTok",    title: "Lineup hint reel",               status: "draft",     owner: "Jordan" },
      { id: "cc4", scheduledAt: "Jun 4",  channel: "Instagram", title: "Sponsor spotlight: Drift",       status: "scheduled", owner: "Taylor" },
      { id: "cc5", scheduledAt: "Jun 6",  channel: "Email",     title: "Vendor village preview",         status: "draft",     owner: "Jordan" },
      { id: "cc6", scheduledAt: "Jun 9",  channel: "Press",     title: "Maya Cole headliner exclusive",  status: "draft",     owner: "Casey" },
    ],
    // ContentStudioAsset{title, type, stage, owner, due} — GET /api/launch/content-studio
    contentStudio: [
      { id: "a1", title: "Phase 1 ticket key art",     type: "Graphic", stage: "published",   owner: "Jordan", due: "May 28" },
      { id: "a2", title: "Lineup teaser reel",         type: "Video",   stage: "approved",    owner: "Jordan", due: "Jun 2" },
      { id: "a3", title: "Sponsor sizzle: Drift",      type: "Video",   stage: "in-progress", owner: "Taylor", due: "Jun 5" },
      { id: "a4", title: "Vendor village map graphic", type: "Graphic", stage: "in-progress", owner: "Morgan", due: "Jun 7" },
      { id: "a5", title: "Clean Earth impact card",    type: "Graphic", stage: "brief",       owner: "Jordan", due: "Jun 10" },
      { id: "a6", title: "Weekend recap template",     type: "Deck",    stage: "brief",       owner: "Casey",  due: "Jun 14" },
    ],
    // Planners — emailSequences + outreach (community/press) folded together.
    emailSequences: [
      { id: "e1", name: "Founders phase on-sale", audience: "Full list · 24k",  sends: 3, status: "active",    nextSend: "Jun 1" },
      { id: "e2", name: "Abandoned checkout",     audience: "Cart · auto",      sends: 2, status: "active",    nextSend: "rolling" },
      { id: "e3", name: "Vendor village recruit", audience: "Local biz · 1.2k", sends: 4, status: "scheduled", nextSend: "Jun 6" },
      { id: "e4", name: "Volunteer call",         audience: "Treasure Coast",   sends: 2, status: "draft",     nextSend: "—" },
    ],
    outreach: [
      { id: "o1", kind: "Press",     contact: "Billboard FL desk",     status: "replied",    owner: "Casey",  note: "Wants headliner exclusive" },
      { id: "o2", kind: "Press",     contact: "TC Palm features",      status: "sent",       owner: "Casey",  note: "Local angle pitch" },
      { id: "o3", kind: "Community", contact: "Fort Pierce Main St.",  status: "confirmed",  owner: "Kam",    note: "Storefront wristband promo" },
      { id: "o4", kind: "Community", contact: "St. Lucie schools",     status: "sent",       owner: "Kam",    note: "Student volunteer drive" },
    ],
    // Public surfaces QA + claims checker — GET /api/launch/public-surfaces
    publicSurfaces: [
      { id: "ps1", page: "Homepage",   url: "/",          status: "live", claim: "10% of every ticket to Clean Earth", mapsTo: "Clean Earth page", owner: "Jordan" },
      { id: "ps2", page: "Tickets",    url: "/tickets",   status: "live", claim: "5 stages, 75+ artists",              mapsTo: "Lineup",           owner: "Jordan" },
      { id: "ps3", page: "Lineup",     url: "/lineup",    status: "qa",   claim: "Full schedule live",                 mapsTo: "Schedule page",    owner: "Casey" },
      { id: "ps4", page: "Auditions",  url: "/auditions", status: "live", claim: "Vote with credits",                  mapsTo: "Fan dashboard",    owner: "Jordan" },
      { id: "ps5", page: "Partners",   url: "/partners",  status: "qa",   claim: "Activation tiers",                   mapsTo: "Sponsor intake",   owner: "Taylor" },
      { id: "ps6", page: "Vendors",    url: "/vendors",   status: "draft",claim: "Apply for a booth",                  mapsTo: "Vendor intake",    owner: "Morgan" },
    ],

    // ---------- FINANCE  (GET /api/launch/budget) ----------
    // amounts in cents. kind: revenue|cost.
    budgetCategories: [
      { id: "b1", kind: "revenue", label: "Ticket sales",        targetCents:  6000000, currentCents:  700000 },
      { id: "b2", kind: "revenue", label: "Sponsorships",        targetCents:  3000000, currentCents:  600000 },
      { id: "b3", kind: "revenue", label: "Vendor fees",         targetCents:  1000000, currentCents:  200000 },
      { id: "b4", kind: "cost",    label: "Talent + production",  targetCents: 120000000, currentCents: 71500000 },
      { id: "b5", kind: "cost",    label: "Venue + infrastructure",targetCents: 64000000, currentCents: 38000000 },
      { id: "b6", kind: "cost",    label: "Marketing",            targetCents: 42000000, currentCents: 24800000 },
      { id: "b7", kind: "cost",    label: "Staffing + crew",      targetCents: 36000000, currentCents: 14200000 },
    ],
    budgetInvoices: [
      { id: "i1", kind: "receivable", counterparty: "Drift Beverages",  category: "Sponsorships", amountCents: 4000000, dueDate: "Jun 15", status: "pending" },
      { id: "i2", kind: "receivable", counterparty: "Halo Beauty",      category: "Sponsorships", amountCents: 1200000, dueDate: "Paid",   status: "paid" },
      { id: "i3", kind: "receivable", counterparty: "Northwave Tech",   category: "Sponsorships", amountCents: 1800000, dueDate: "Jul 1",  status: "draft" },
      { id: "i4", kind: "payable",    counterparty: "Apex Staging",     category: "Venue + infrastructure", amountCents: 2850000, dueDate: "Jun 20", status: "pending" },
      { id: "i5", kind: "payable",    counterparty: "The Anchors (dep.)",category: "Talent + production",   amountCents: 4750000, dueDate: "Jun 10", status: "pending" },
      { id: "i6", kind: "payable",    counterparty: "Coastal Power Co.", category: "Venue + infrastructure", amountCents:  920000, dueDate: "Paid",   status: "paid" },
    ],

    // ---------- ON-SITE (mobile-first) ----------
    dayOfStages: [
      { id: "st1", stage: "Main",      status: "live",    current: "Maya Cole",  next: "Cane River",  nextAt: "9:00 PM", headcount: 4200 },
      { id: "st2", stage: "Frequency", status: "live",    current: "Pillar Funk",next: "Quad Aux",    nextAt: "9:30 PM", headcount: 1800 },
      { id: "st3", stage: "Runway",    status: "changeover", current: "—",       next: "Sable Hours", nextAt: "8:45 PM", headcount: 900 },
      { id: "st4", stage: "Lounge",    status: "live",    current: "DJ Vetiver", next: "Bluedrift",   nextAt: "10:00 PM",headcount: 600 },
      { id: "st5", stage: "Block",     status: "hold",    current: "—",          next: "Cypher set",  nextAt: "TBD",     headcount: 0 },
    ],
    crewCallSheets: [
      { id: "cs1", shift: "Stage lighting · Main",  callTime: "Sat 10:00 AM", location: "Main backstage", contact: "A. Rivera · 555-0142", day: "Sat" },
      { id: "cs2", shift: "Hospitality · Green room",callTime: "Sat 12:00 PM", location: "Pavilion tent",  contact: "Casey · 555-0188",     day: "Sat" },
      { id: "cs3", shift: "Gate + wristband",       callTime: "Fri 2:00 PM",  location: "Main entrance",  contact: "Morgan · 555-0170",    day: "Fri" },
      { id: "cs4", shift: "Audio · Frequency",      callTime: "Sun 11:00 AM", location: "Frequency FOH",  contact: "J. Okafor · 555-0155", day: "Sun" },
    ],
    incidents: [
      { id: "inc1", kind: "Medical", stage: "Main",     severity: "P2", status: "resolved", at: "7:42 PM", notes: "Heat exhaustion, treated on-site." },
      { id: "inc2", kind: "Crowd",   stage: "Frequency",severity: "P3", status: "open",     at: "8:15 PM", notes: "Density at rail, added staff." },
      { id: "inc3", kind: "Vendor",  stage: "Village",  severity: "P3", status: "open",     at: "8:31 PM", notes: "Power trip at row C." },
    ],
    weather: [
      { id: "w1", day: "Fri Sep 18", forecast: "Clear",            temp: "84°", wind: "8 mph",  precip: "5%",  trigger: "none" },
      { id: "w2", day: "Sat Sep 19", forecast: "PM thunderstorms", temp: "87°", wind: "14 mph", precip: "60%", trigger: "Lightning hold plan armed" },
      { id: "w3", day: "Sun Sep 20", forecast: "Partly cloudy",    temp: "85°", wind: "10 mph", precip: "20%", trigger: "none" },
    ],
    ticketPhases: [
      { id: "tp1", phase: "Founders",  status: "live",     sold: 41, allocation: 1000, goLive: "Live",   price: "$149" },
      { id: "tp2", phase: "Phase 1",   status: "ready",    sold: 0,  allocation: 3000, goLive: "Jun 15", price: "$179" },
      { id: "tp3", phase: "Phase 2",   status: "pending",  sold: 0,  allocation: 4000, goLive: "Jul 20", price: "$219" },
      { id: "tp4", phase: "Gate",      status: "pending",  sold: 0,  allocation: 2000, goLive: "Sep 18", price: "$260" },
    ],
    venueZones: [
      { id: "z1", label: "Main Stage",     type: "stage",   x: 22, y: 34 },
      { id: "z2", label: "Frequency",      type: "stage",   x: 58, y: 28 },
      { id: "z3", label: "Runway",         type: "stage",   x: 78, y: 48 },
      { id: "z4", label: "Lounge",         type: "stage",   x: 40, y: 62 },
      { id: "z5", label: "Block",          type: "stage",   x: 66, y: 72 },
      { id: "z6", label: "Vendor Village", type: "vendor",  x: 30, y: 48 },
      { id: "z7", label: "Wellness Zone",  type: "wellness",x: 50, y: 80 },
      { id: "z8", label: "Command",        type: "command", x: 12, y: 16 },
    ],

    // ---------- WORKSPACE ----------
    // NOTE: each teammate's `open` count is LIVE-DERIVED from launchTasks
    // (owner match, status != done) in TeamRoster — seed `open` is fallback only.
    launchTeam: [
      { id: 1, name: "Kam Sandberg",  role: "Festival Director",   load: "high",   color: "#C49800", open: 9 },
      { id: 2, name: "Jordan Lee",    role: "Marketing Lead",      load: "high",   color: "#B5006A", open: 12 },
      { id: 3, name: "Taylor Brooks", role: "Sponsor Coordinator", load: "med",    color: "#007A8A", open: 9 },
      { id: 4, name: "Morgan Diaz",   role: "Production Manager",   load: "high",   color: "#4C1285", open: 14 },
      { id: 5, name: "Casey Nguyen",  role: "Artist Relations",    load: "med",    color: "#00A8BC", open: 11 },
    ],
    checklists: [
      { id: "ch1", label: "Confirm all 5 stage power plans",     owner: "Morgan", due: "Jun 16", cadence: "once",   done: false },
      { id: "ch2", label: "Sponsor assets received + approved",  owner: "Taylor", due: "Jun 12", cadence: "once",   done: false },
      { id: "ch3", label: "Weekly social calendar published",    owner: "Jordan", due: "Mondays",cadence: "weekly", done: true },
      { id: "ch4", label: "Ticket phase readiness review",       owner: "Kam",    due: "Fridays",cadence: "weekly", done: false },
      { id: "ch5", label: "Vendor COI + permits on file",        owner: "Morgan", due: "Jun 20", cadence: "once",   done: false },
      { id: "ch6", label: "Artist travel + hospitality locked",  owner: "Casey",  due: "Aug 15", cadence: "once",   done: false },
    ],
    launchFiles: [
      { id: "f1", type: "folder", name: "Sponsor contracts",  parentId: null, items: 12, sizeBytes: 0,        updatedAt: "1d" },
      { id: "f2", type: "folder", name: "Stage plots",        parentId: null, items: 5,  sizeBytes: 0,        updatedAt: "2d" },
      { id: "f3", type: "folder", name: "Brand + creative",   parentId: null, items: 38, sizeBytes: 0,        updatedAt: "4h" },
      { id: "f4", type: "file",   name: "Run of show v3.pdf", parentId: null, items: 0,  sizeBytes: 2400000,  updatedAt: "3h", mime: "pdf" },
      { id: "f5", type: "file",   name: "Site map FINAL.pdf", parentId: null, items: 0,  sizeBytes: 8800000,  updatedAt: "1d", mime: "pdf" },
      { id: "f6", type: "file",   name: "Budget master.xlsx", parentId: null, items: 0,  sizeBytes: 540000,   updatedAt: "6h", mime: "xlsx" },
    ],
    // 20-week production timeline (Timeline + Dependency view toggle)
    timeline: [
      { week: "T-16", label: "Lineup + ticket phase 1", engine: "content",  status: "doing",   milestones: ["Headliners signed", "Phase 1 on-sale"] },
      { week: "T-14", label: "Sponsor activations lock", engine: "sponsors", status: "todo",    milestones: ["Footprints approved", "Assets due"] },
      { week: "T-10", label: "Production design freeze",  engine: "day-of",   status: "todo",    milestones: ["Stage plots", "Power plan"] },
      { week: "T-6",  label: "Phase 2 + vendor village",  engine: "tickets",  status: "todo",    milestones: ["Phase 2 on-sale", "Vendors confirmed"] },
      { week: "T-2",  label: "Crew + call sheets",        engine: "day-of",   status: "todo",    milestones: ["Crew booked", "Call sheets out"] },
      { week: "T-0",  label: "Festival weekend",          engine: "day-of",   status: "todo",    milestones: ["Sep 18-20", "Gates open"] },
    ],
    recap: {
      published: false,
      metrics: { attendance: 0, ticketRevenueCents: 0, sponsorRecapsSent: 0, cleanEarthCents: 0 },
      highlights: [],
    },

    // ---------- PROJECT-MANAGER SYNC  (GET /api/launch/pm-integrations) ----------
    // Two-way connectors. Each connector maps LCC surfaces (engines / tasks /
    // pipelines / timeline) onto that platform's NATIVE hierarchy. `mapping`
    // values are chosen from `containers`. direction: push|pull|two-way.
    // frequency: realtime|15m|hourly|manual. conflict: lcc|platform|recent.
    pmIntegrations: [
      { id: "clickup", name: "ClickUp", key: "clickup", color: "#7B68EE", hierarchy: "Space · Folder · List · Task",
        connected: true, account: "ARGT Workspace", who: "kam@argt.com",
        direction: "two-way", frequency: "realtime", conflict: "recent", lastSync: "2 min ago",
        scope: { tasks: true, engines: true, pipelines: true, timeline: false },
        containers: ["Space", "Folder", "List", "Task", "Status", "Gantt view", "Custom Field"],
        mapping: { root: "Space", engines: "Folder", tasks: "List", pipelines: "Status", timeline: "Gantt view" },
        log: [
          { at: "2 min ago",  dir: "in",  text: "Pulled 3 task updates from ClickUp" },
          { at: "18 min ago", dir: "out", text: "Pushed 'Lock headliner contracts' status → ClickUp" },
          { at: "1 h ago",    dir: "out", text: "Created Folder 'Sponsors' in ARGT 2026 Space" },
        ] },
      { id: "asana", name: "Asana", key: "asana", color: "#F06A6A", hierarchy: "Project · Section · Task",
        connected: true, account: "ARGT 2026", who: "ops@argt.com",
        direction: "two-way", frequency: "15m", conflict: "lcc", lastSync: "12 min ago",
        scope: { tasks: true, engines: true, pipelines: false, timeline: true },
        containers: ["Team", "Project", "Section", "Task", "Board column", "Timeline view", "Custom Field"],
        mapping: { root: "Project", engines: "Section", tasks: "Task", pipelines: "Board column", timeline: "Timeline view" },
        log: [
          { at: "12 min ago", dir: "out", text: "Synced 8 tasks into Asana sections" },
          { at: "40 min ago", dir: "in",  text: "Pulled due-date change on 'Founders cascade'" },
        ] },
      { id: "trello", name: "Trello", key: "trello", color: "#0079BF", hierarchy: "Board · List · Card",
        connected: true, account: "ARGT Launch", who: "kam@argt.com",
        direction: "two-way", frequency: "realtime", conflict: "recent", lastSync: "just now",
        scope: { tasks: true, engines: true, pipelines: true, timeline: false },
        containers: ["Board", "List", "Card", "Label", "Checklist", "Calendar Power-Up"],
        mapping: { root: "Board", engines: "Label", tasks: "Card", pipelines: "List", timeline: "Calendar Power-Up" },
        log: [
          { at: "just now",   dir: "out", text: "Moved 'Approve sponsor footprints' → Confirmed list" },
          { at: "25 min ago", dir: "in",  text: "Pulled new card from Artists pipeline board" },
        ] },
      { id: "basecamp", name: "Basecamp", key: "basecamp", color: "#2E9E5B", hierarchy: "Project · To-do list · To-do",
        connected: false, account: "", who: "",
        direction: "two-way", frequency: "hourly", conflict: "platform", lastSync: "—",
        scope: { tasks: true, engines: true, pipelines: false, timeline: true },
        containers: ["Project", "To-do list", "To-do", "Card Table", "Column", "Schedule"],
        mapping: { root: "Project", engines: "To-do list", tasks: "To-do", pipelines: "Card Table", timeline: "Schedule" },
        log: [] },
    ],

    // ---------- PM RECONCILIATION QUEUE  (GET /api/launch/pm-reconcile) ----------
    // Divergences a two-way sync can't auto-resolve, surfaced for admin review.
    // type: conflict (edited both sides) | inbound (new in tool) | outbound
    // (not pushed) | deleted (removed in tool) | unmapped (no engine match).
    // `fields` lists diverging values for conflicts; others carry `summary`.
    pmReconcile: [
      { id: "rc1", platform: "clickup", type: "conflict", taskTitle: "Lock headliner contracts", engine: "content",
        fields: [ { label: "Status", lcc: "Blocked", ext: "In progress" }, { label: "Due", lcc: "Jun 5", ext: "Jun 8" } ], detected: "4 min ago" },
      { id: "rc2", platform: "asana", type: "conflict", taskTitle: "Approve sponsor activation footprints", engine: "sponsors",
        fields: [ { label: "Owner", lcc: "Taylor", ext: "Jordan" }, { label: "Status", lcc: "In progress", ext: "Done" } ], detected: "15 min ago" },
      { id: "rc3", platform: "trello", type: "inbound", taskTitle: "Design Frequency stage backdrop", engine: "content",
        summary: "New card added to the Content list in Trello", detected: "22 min ago" },
      { id: "rc4", platform: "clickup", type: "outbound", taskTitle: "Confirm 5-stage power + rigging plan", engine: "day-of",
        summary: "Created in LCC, not yet pushed to ClickUp", detected: "31 min ago" },
      { id: "rc5", platform: "trello", type: "deleted", taskTitle: "Publish week-of social calendar", engine: "social",
        summary: "Card archived in Trello but still active in LCC", detected: "1 h ago" },
      { id: "rc6", platform: "asana", type: "unmapped", taskTitle: "Photographer call sheet", engine: null,
        summary: "Pulled from Asana with no matching engine", detected: "1 h ago" },
    ],

    // ---------- LAUNCH SETTINGS  (GET /api/launch/settings) ----------
    launchSettings: {
      festival: {
        name: "ARGT 2026",
        tagline: "Three days. Five stages. One coast.",
        startDate: "2026-09-18", endDate: "2026-09-20", gatesOpen: "13:00",
        venue: "Harbour Pointe", address: "Fort Pierce, FL",
        capacity: "10,000", artists: "75+",
        presentedBy: "The Private Plane",
        beneficiary: "Clean Earth Initiative", pledgePct: 10,
        stageNames: ["Main", "Frequency", "Runway", "Lounge", "Block"],
      },
      branding: { accent: "magenta", theme: "Obsidian", logo: null },
      alerting: {
        channels: { Email: true, SMS: true, Slack: true, Push: false },
        events: { "Engine status change": true, "New high-priority flag": true, "Payment cleared": true, "Daily digest": true, "Incident P1/P2": true },
        digestTime: "8:00 AM",
        escalation: { P1: "Call + SMS", P2: "SMS", P3: "In-app" },
      },
      integrations: [
        { id: "ig1", name: "Stripe",    purpose: "Payments + payouts", status: "connected", detail: "acct_ARGT2026 · live mode" },
        { id: "ig2", name: "Mailgun",   purpose: "Email sequences",    status: "connected", detail: "send@argt.com · 24k contacts" },
        { id: "ig3", name: "Twilio",    purpose: "Day-of SMS + radio",  status: "connected", detail: "+1 772 555 0100" },
        { id: "ig4", name: "Cloudinary",purpose: "Media library",      status: "connected", detail: "42 GB stored" },
        { id: "ig5", name: "Slack",     purpose: "Incident alerts",    status: "action",    detail: "#argt-ops · reauth needed" },
        { id: "ig6", name: "Google Drive", purpose: "File workspace",  status: "off",       detail: "Not connected" },
      ],
      roles: [
        { id: "r1", name: "Kam Sandberg",  access: "Owner",  scope: "All engines" },
        { id: "r2", name: "Jordan Lee",    access: "Admin",  scope: "Marketing, Digital" },
        { id: "r3", name: "Taylor Brooks", access: "Editor", scope: "Sponsors, Finance" },
        { id: "r4", name: "Morgan Diaz",   access: "Editor", scope: "On-Site, Vendors" },
        { id: "r5", name: "Casey Nguyen",  access: "Editor", scope: "Content, Talent" },
      ],
      storage: { usedGb: 42, totalGb: 200, retentionDays: 365 },
    },

    // ---------- ACCESS CONTROL  (GET /api/launch/access) ----------
    // Who can open which destination. Settings (festival config, invites,
    // roles, integrations) is restricted to superadmin/assigned roles.
    // In the fold this is enforced server-side; the UI hides what you can't open.
    launchAccess: {
      currentRole: "Owner",           // demo control; real value comes from the session
      roles: ["Owner", "Admin", "Operator"],
      // sidebar destinations each role may open
      access: {
        Owner:    ["today", "pipelines", "marketing", "finance", "onsite", "workspace", "settings"],
        Admin:    ["today", "pipelines", "marketing", "finance", "onsite", "workspace", "settings"],
        Operator: ["today", "pipelines", "marketing", "finance", "onsite", "workspace"],
      },
      invites: [
        { id: "inv1", email: "alex@argt.com",  role: "Editor", status: "pending", sent: "2d" },
        { id: "inv2", email: "robin@argt.com", role: "Viewer", status: "pending", sent: "5d" },
      ],
    },

    // ---------- UNIVERSAL ----------
    settingsProfile: { displayName: "Kam Sandberg", email: "kam@example.com", phone: "" },
    settingsNotifications: {
      "Email — status changes": true,
      "Email — weekly digest": true,
      "SMS — urgent only": false,
      "Push — festival weekend": true,
    },

    // ---------- DOWNLOAD / FILE-ACTION LEDGER ----------
    // Tracks "downloaded / added to wallet / opened" actions so file-style
    // buttons give real feedback instead of being inert. In prod these map to
    // signed-URL fetches / wallet-pass generation.
    fileActions: {},
  };

  // ----- store internals -----
  const clone = (o) => JSON.parse(JSON.stringify(o));
  let state = load();
  const subs = new Set();

  function load() {
    try {
      const raw = JSON.parse(localStorage.getItem(LS_KEY) || "null");
      if (raw && raw.__v === VERSION && raw.data) {
        // merge seed → stored so new collections appear after an update
        return Object.assign(clone(SEED), raw.data);
      }
    } catch (e) {}
    return clone(SEED);
  }
  function persist() {
    try { localStorage.setItem(LS_KEY, JSON.stringify({ __v: VERSION, data: state })); } catch (e) {}
  }

  const DB = {
    get(coll) { return state[coll]; },
    set(coll, v) {
      const next = typeof v === "function" ? v(state[coll]) : v;
      state = Object.assign({}, state, { [coll]: next });
      persist();
      subs.forEach((fn) => fn());
      return next;
    },
    update(coll, fn) { return DB.set(coll, fn(state[coll])); },
    subscribe(fn) { subs.add(fn); return () => subs.delete(fn); },
    reset() { state = clone(SEED); persist(); subs.forEach((fn) => fn()); },
    seed: SEED,
  };
  window.ARGT_DB = DB;

  // ----- argtPing: lightweight global toast for file / calendar / external
  // actions that are live-only in the mock (download, add-to-wallet, open-in-
  // maps, message-production, request-changes). In the fold these handlers
  // call the real signed-URL / wallet / messaging endpoints. -----
  window.argtPing = function argtPing(msg, coll) {
    if (coll) { try { DB.update("fileActions", (m) => Object.assign({}, m, { [coll]: Date.now() })); } catch (e) {} }
    try {
      const el = document.createElement("div");
      el.setAttribute("role", "status");
      el.style.cssText = "position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(8px);z-index:600;display:flex;align-items:center;gap:10px;padding:12px 18px;border-radius:999px;background:#3a2e60;border:1px solid #d82884;box-shadow:0 16px 40px rgba(0,0,0,.5);color:#f8f6ff;font:600 13.5px/1.3 'DM Sans',system-ui,sans-serif;max-width:calc(100vw - 32px);opacity:0;transition:opacity .18s,transform .18s;";
      const dot = document.createElement("span");
      dot.textContent = "✓";
      dot.style.cssText = "width:22px;height:22px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;background:#d82884;color:#fff;font-size:12px;";
      el.appendChild(dot); el.appendChild(document.createTextNode(msg));
      document.body.appendChild(el);
      requestAnimationFrame(() => { el.style.opacity = "1"; el.style.transform = "translateX(-50%) translateY(0)"; });
      setTimeout(() => { el.style.opacity = "0"; setTimeout(() => el.remove(), 220); }, 2600);
    } catch (e) {}
  };

  // ----- React binding: subscribe + re-render + persist -----
  window.useDB = function useDB(coll) {
    const [, force] = React.useReducer((x) => x + 1, 0);
    React.useEffect(() => DB.subscribe(force), []);
    const setValue = React.useCallback((v) => DB.set(coll, v), [coll]);
    return [DB.get(coll), setValue];
  };
})();
