// appdata.jsx — 互動原型資料層：案件、價目、法規庫、情境範本、.ics 產生器

const PRICE_LIST = [
  { key:'reels',     item:'IG Reels 一則（60秒，非逐格動畫）', price:53000,
    note:'腳本及影片以過稿一次為限，修改以資訊調整為主，不補拍/重拍；以企劃包裝帶入；hashtag 五個以內。' },
  { key:'reels_yt',  item:'IG Reels 一則 ＋ YT 同步上傳', price:60000, note:'內容同上，另含 YouTube 同步上傳。' },
  { key:'story',     item:'IG 限動一則（不過稿、帶導購連結）', price:5000, note:'hashtag 五個以內。' },
  { key:'bot',       item:'設定留言自動回覆機器人', price:6700, note:'不含機器人平台方案購買費用，方案開通費由客戶支付，創作者僅協助設定串接。' },
  { key:'post',      item:'IG 純圖文貼文一篇', price:28000, note:'5–6 張圖，順序以創作者安排為主；hashtag 五個以內。' },
  { key:'post_v',    item:'IG 影片＋圖貼文一篇', price:35000, note:'5–6 張圖及 1 張影片圖，順序以創作者安排為主；hashtag 五個以內。' },
  { key:'ad_w',      item:'IG(Meta) 廣告主＋全媒體素材授權（一週）', price:6000, note:'廣告貼文需創作者確認後使用；可包框再製需確認；可上傳品牌官方自媒體。' },
  { key:'ad_m',      item:'IG(Meta) 廣告主＋全媒體素材授權（一個月）', price:20000, note:'授權範圍同上，效期一個月。' },
  { key:'noncomp',   item:'上線後避開三個月競品', price:27000, note:'競品範圍需於委刊單載明。' },
];

const STAGES = [
  { id:'inquiry', name:'新進洽詢', hint:'廠商來信・風控' },
  { id:'intent',  name:'意願', hint:'合作意願文件' },
  { id:'quote',   name:'報價', hint:'報價信' },
  { id:'contract',name:'合約', hint:'委刊單' },
  { id:'schedule',name:'排程', hint:'溝通・行事曆' },
  { id:'produce', name:'製作中',    hint:'拍攝・上線' },
  { id:'finance', name:'收款・發票', hint:'結案' },
];

// ── 案件目前進度對應的詳情分頁（點進案件時直接跳到該進度）──
function currentTab(c){
  if(!c) return 'mail';
  // 婉拒／未成交：成交後分頁隱藏，停在「報價信」
  if(c.progress==='婉拒' || c.progress==='未成交' || c.willing==='婉拒') return 'quote';
  // 看板階段（stage）為使用者點選的欄位，合約後階段以 stage 為權威
  const stageDefinite = { contract:'io', schedule:'prod', produce:'prod', finance:'prod' };
  if(stageDefinite[c.stage]) return stageDefinite[c.stage];
  // 簽約前（洽談・意願・報價）以 progress 為主
  const byProgress = {
    '意願':'intent', '報價':'quote', '簽約':'io',
    '審稿':'prod', '售後':'prod', '結案':'prod',
  };
  if(byProgress[c.progress]) return byProgress[c.progress];
  // 退而依看板階段
  const byStage = { inquiry:'mail', risk:'risk', intent:'intent', quote:'quote', contract:'io', schedule:'comm', produce:'prod', finance:'prod' };
  return byStage[c.stage] || 'mail';
}

// ── 法規庫：依產品類別套用（使用者指定四項）──
const LAW_LIB = {
  food: [
    { code:'食品安全衛生管理法 §28', t:'食品之標示、宣傳或廣告，不得有不實、誇張或易生誤解之情形，且不得涉及醫療效能。' },
    { code:'公平交易法 §21', t:'事業不得於商品、廣告或其他使公眾得知之方法，為虛偽不實或引人錯誤之表示或表徵。' },
  ],
  cosmetic: [
    { code:'化粧品衛生安全管理法 §10', t:'化粧品之標示、宣傳及廣告，不得有虛偽、誇大或宣稱醫療效能之情事。' },
    { code:'化粧品標示宣傳廣告涉及虛偽誇大或醫療效能認定準則', t:'明列禁用詞句；「換膚、除皺、治療、醫療級、修復受損」等醫療效能用語不得使用。' },
    { code:'公平交易法 §21', t:'不得為虛偽不實或引人錯誤之表示或表徵。' },
  ],
  general: [
    { code:'公平交易法 §21', t:'商品/廣告/標示不得為虛偽不實或引人錯誤之表示或表徵。' },
  ],
};
const AVOID_WORDS = {
  food: ['療效','治療','預防','增強免疫力','醫師推薦','根治','改善過敏','調整體質'],
  cosmetic: ['換膚','除皺','治療','醫療級','修復受損','淡化疤痕','抗敏','藥用'],
  general: ['最佳','第一','唯一','100%','保證有效','無效退費'],
};
const RISK_KIND_LABEL = { food:'食品／保健', cosmetic:'化粧品／保養', general:'一般商品' };

// ── 乙方·果米工作室固定資訊（來自真實委刊單）──
const STUDIO = {
  name:'果米工作室', creator:'國美ゴメ｜5cm小人物の日常',
  invoiceTitle:'果米工作室', taxId:'61557095',
  addr:'臺南市北區育德二路190巷46號',
  contact:'多多', tel:'0956054136', email:'5cmgomei@gmail.com', line:'@942njuhl',
};

// ── 委刊單服務條款（依真實範本）──
const IO_CLAUSES = [
  { h:'一、費用與支付', body:'請於簽約且甲方收受乙方開立之發票後 7 日內支付 50% 訂金；提交初稿後，於收到發票 30 日內支付 50% 尾款。逾期付款按年利率 5% 計算遲延利息。' },
  { h:'二、審稿與驗收', body:'內容企劃：雙方事前溝通方向。初稿提供後，甲方僅得為 1 次修改且不得為實質內容之變更。正式撰稿：僅限 1 次資訊錯誤修正，非因乙方過失而需超過 1 次以上修改，乙方有權收取額外修改費用。默認驗收：初稿或正式稿交付後 7 日內未提出修改，視同驗收合格。' },
  { h:'三、著作權與授權', body:'圖文著作權歸「國美ゴメ｜5cm小人物の日常」所有。未經書面同意，甲方不得重製、改作或於約定平台以外發布。廣告投放須事先告知並標記「#AD」；甲方於對外公開使用或投放前，須將素材及使用方式提供乙方確認，經同意後始得使用。不得發表於有損創作者形象之管道。' },
  { h:'四、違約補償與終止', body:'中途終止：若因可歸責於甲方之事由取消專案，應依進度支付費用（撰寫前 50%、中途 70%、提交後 90%、排程後 100%）。延遲上線：依延遲時間（1小時/1個月/3個月）按比例（30%/50%/100%）支付或扣減廣告費。私自改文：甲方若私自竄改文案或投放廣告，須賠償懲罰性違約金及其餘損害。' },
  { h:'五、形象與誠信擔保', body:'雙方擔保素材合法且不侵害第三方權利，並應維護彼此品牌與創作者形象。違者應負損害賠償責任（含律師費、訴訟費等）。' },
  { h:'六、保密義務', body:'雙方對合作期間知悗之非公開資料負保密義務，不因委刊服務終止而失效。' },
  { h:'七、法源與管轄', body:'本委刊單雙方同意得使用 PDF 檔或商業上可使用之軟體簽訂，確認簽名以電子方式交付。未盡事宜以中華民國法律為準，並以台灣台北地方法院為第一審管轄法院。' },
];

// ── 製作排程里程碑（依真實「工作排程」欄位）──
// color：寫入行事曆的色系——red=國美要交付的重要日期；yellow=區間性製作排程
const PROD_STEPS = [
  { key:'draft',    icon:'📤', label:'提供草圖', kind:'date',  cal:true, color:'red',    cat:'國美工作日' },
  { key:'draftFix', icon:'✎', label:'修改草圖', kind:'range', cal:true, color:'yellow', cat:'區間排程' },
  { key:'script',   icon:'📤', label:'提供腳本', kind:'date',  cal:true, color:'red',    cat:'國美工作日' },
  { key:'scriptFix',icon:'📝', label:'修改腳本', kind:'range', cal:true, color:'yellow', cat:'區間排程' },
  { key:'shoot',    icon:'📷', label:'拍攝日',   kind:'date',  cal:true, color:'red',    cat:'國美工作日' },
  { key:'post',     icon:'📝', label:'後製期',   kind:'range', cal:true, color:'yellow', cat:'區間排程' },
  { key:'deliver',  icon:'📤', label:'提供成品', kind:'date',  cal:true, color:'red',    cat:'國美工作日' },
  { key:'finalFix', icon:'📝', label:'修改成品', kind:'range', cal:true, color:'yellow', cat:'區間排程' },
  { key:'online',   icon:'🥇', label:'上線日',   kind:'date',  cal:true, color:'red',    cat:'國美工作日' },
];

// ── 追蹤表語彙（依真實「案件整理追蹤」欄位）──
// 從案件來源區分
const SOURCES = ['自來信', '開發信'];
const sourceTone = (s)=> s==='開發信'?'source-dev':'source-in';

const CASE_TYPES = ['純業配','團購','稿費+分潤'];
const WILLING = ['有興趣','婉拒'];
const PROGRESS = ['洽談','意願','報價','簽約','審稿','售後'];
const DEAL = ['洽談中','結案','待請款','入帳','未成交'];
const dealTone = (d)=> d==='未成交'?'risk-high': d==='入帳'||d==='結案'?'risk-low':'risk-mid';
const progressFromStage = (s)=> ({inquiry:'洽談',risk:'意願',intent:'意願',quote:'報價',contract:'簽約',schedule:'簽約',produce:'審稿',finance:'售後'})[s]||'洽談';
// 從真實追蹤表的「進度/成交」反推看板 stage（從 Google Sheets 載入舊案件用，僅供初次估計，可在看板手動拖曳調整）
function stageFromCase(row){
  if (row.deal==='結案' || row.deal==='入帳' || row.progress==='售後') return 'finance';
  if (row.io && row.io.signed) return row.prod && (row.prod.shoot||row.prod.online) ? 'produce' : 'schedule';
  const byProgress = { 洽談:'inquiry', 意願:'intent', 報價:'quote', 簽約:'contract', 審稿:'produce', 售後:'finance' };
  return byProgress[row.progress] || 'inquiry';
}

// ── 案件進度（製作流程，與財務分開）──
const PROGRESS_PIPELINE = ['洽談','意願','報價','簽約','審稿','售後','結案','待追蹤'];
const progressTone = (p)=> p==='結案'?'risk-low': ['未成交','婉拒'].includes(p)?'risk-high': p==='待追蹤'?'risk-wait':'neutral';
// ── 財務狀態（訂金 / 尾款，兩者獨立）──
function makePay(c){ return { dep:{ paid:false, date:'' }, bal:{ paid:false, date:'' } }; }
function payLabel(pay){
  if(!pay) return '未收款';
  if(pay.dep.paid && pay.bal.paid) return '已結清';
  if(pay.dep.paid) return '已收訂金';
  return '未收款';
}
function payTone(pay){
  if(!pay) return 'risk-mid';
  if(pay.dep.paid && pay.bal.paid) return 'risk-low';
  return 'risk-mid';
}

// ── 範例案件 ──
const SEED_CASES = [
  {
    id:'PL-2406', stage:'intent', vendor:'淨研生技 PureLab', product:'PureLab 日研益生菌',
    category:'保健食品', riskKind:'food', contact:'林品妍', contactRole:'行銷專員',
    received:'2026/06/09', updated:'20 分鐘前', pinned:true, avatarBg:'var(--clay)',
    budgetHint:'希望控制在 7 萬以內', value:78000,
    email:`多多您好，\n\n我們是淨研生技 PureLab，主打日研益生菌系列。長期關注「國美ゴメ5cm小人物の日常」的內容，覺得很符合我們的品牌調性，想邀請合作。\n\n這次想推廣新品「日研益生菌（300 億 CFU）」，希望有 IG Reels 一則介紹產品、搭配一則限時動態帶導購連結，另想詢問 IG 廣告主授權一個月的方案。\n\n預算希望控制在 7 萬以內，預計 7 月上線。再麻煩您提供報價與合作方式，謝謝！\n\n淨研生技 行銷專員 林品妍`,
    wants:['IG Reels 一則','IG 限動一則（帶導購）','廣告主授權一個月'],
    productLink:'https://purelab.example/probiotics-300',
    risk:'high', riskLabel:'需注意', riskStatus:'done',
    riskFindings:{
      pros:['第三方 SGS 檢驗報告齊全','菌數標示清楚（300 億 CFU）','品牌成立 6 年、無重大客訴'],
      cons:['官網文案出現「改善過敏、增強免疫」等接近療效用語','部分通路評價反映「腹脹」個案'],
      disputes:[{ y:'2023', t:'電商頁宣稱「調整體質、預防感冒」遭民眾檢舉，業者已自行下架文案。' }],
      okAngle:'以「日常保養、補充每日所需」生活化角度切入，搭配 5cm 小人物情境，避免任何功效保證。',
    },
    quote:{ items:['reels','story','ad_m'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'2026/06/25', online:'2026/07/04' },
  },
  {
    id:'NG-2410', stage:'inquiry', vendor:'霓研 NiraGlow', product:'亮采保濕精華液',
    category:'保養品・化粧品', riskKind:'cosmetic', contact:'周庭安', contactRole:'品牌經理',
    received:'2026/06/10', updated:'1 小時前', avatarBg:'oklch(0.66 0.1 320)',
    budgetHint:'未提供', value:null,
    email:`多多您好，\n\n我是霓研 NiraGlow 的品牌經理周庭安。我們即將上市新款「亮采保濕精華液」，主打高效保濕與亮膚。\n\n想邀請國美合作一篇圖文貼文＋一則限動，介紹使用前後的膚況變化。希望能呈現「淡斑、撫平細紋」的效果。\n\n再請提供報價，謝謝！`,
    wants:['IG 純圖文貼文一篇','IG 限動一則'],
    productLink:'https://niraglow.example/serum',
    risk:'mid', riskLabel:'待評估', riskStatus:'idle', riskFindings:null,
    quote:{ items:['post','story'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
  {
    id:'MU-2405', stage:'quote', vendor:'木栖文具 MUSE', product:'木栖桌面收納墊',
    category:'文具・家居', riskKind:'general', contact:'陳冠宇', contactRole:'業務',
    received:'2026/06/05', updated:'1 天前', avatarBg:'var(--gold)',
    budgetHint:'3.5 萬', value:35000,
    email:`多多您好，木栖文具想邀請國美合作一篇「IG 影片＋圖貼文」，介紹我們的桌面收納墊。商品很適合 5cm 小人物的拍攝場景！預算 3.5 萬，再請報價，謝謝。`,
    wants:['IG 影片＋圖貼文一篇'], productLink:'https://muse.example/deskmat',
    risk:'low', riskLabel:'低風險', riskStatus:'done',
    riskFindings:{ pros:['一般家居用品，無功效宣稱疑慮','品牌形象單純'], cons:['注意勿出現誇大耐用度等絕對化用語'], disputes:[], okAngle:'純情境式置入，展示收納與拍攝場景。' },
    quote:{ items:['post_v'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
  {
    id:'GH-2410', stage:'inquiry', vendor:'綠頌 GreenHymn', product:'氣泡蔬果飲',
    category:'食品・飲料', riskKind:'food', contact:'Yuki', contactRole:'行銷',
    received:'2026/06/10', updated:'3 小時前', avatarBg:'var(--sage)',
    budgetHint:'未提供', value:null,
    email:`Hi 多多，綠頌 GreenHymn 新品氣泡蔬果飲想找國美合作，想呈現健康、低負擔的形象。細節想再跟您討論，先問有沒有檔期～`,
    wants:['尚未確認'], productLink:'https://greenhymn.example',
    risk:'mid', riskLabel:'待評估', riskStatus:'idle', riskFindings:null,
    quote:{ items:[], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
  {
    id:'NS-2403', stage:'schedule', vendor:'暖室 Nuanshi', product:'手作香氛蠟燭',
    category:'居家・香氛', riskKind:'general', contact:'吳子涵', contactRole:'創辦人',
    received:'2026/05/28', updated:'昨天', avatarBg:'var(--clay-2)',
    budgetHint:'3.3 萬', value:33000,
    email:`多多您好，暖室手作香氛蠟燭想合作一篇圖文貼文＋一則限動，呈現溫暖居家氛圍。`,
    wants:['IG 純圖文貼文一篇','IG 限動一則'], productLink:'https://nuanshi.example',
    risk:'low', riskLabel:'低風險', riskStatus:'done',
    riskFindings:{ pros:['居家香氛，調性契合'], cons:['注意香氛成分勿宣稱舒緩療效'], disputes:[], okAngle:'氛圍情境置入。' },
    quote:{ items:['post','story'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'2026/06/18', online:'2026/06/27' },
  },
  {
    id:'CT-2401', stage:'produce', vendor:'小宇宙 Cosmo Toys', product:'微縮場景配件組',
    category:'模型・玩具', riskKind:'general', contact:'Leo', contactRole:'PM',
    received:'2026/05/12', updated:'2 天前', avatarBg:'var(--ink-3)',
    budgetHint:'6 萬', value:60000,
    email:`多多您好，Cosmo Toys 微縮場景配件組，想合作 Reels + YT。`,
    wants:['IG Reels 一則 ＋ YT'], productLink:'https://cosmotoys.example',
    risk:'low', riskLabel:'低風險', riskStatus:'done',
    riskFindings:{ pros:['模型玩具，與 5cm 小人物高度契合'], cons:[], disputes:[], okAngle:'完美題材，情境敘事。' },
    prodSeed:{ draft:'2026/06/02', draftFix:'06/03~06/05', script:'2026/06/08', scriptFix:'06/09~06/11', shoot:'2026/06/14', post:'06/15~06/20', deliver:'2026/06/22', finalFix:'06/23~06/25', online:'2026/06/27' },
    quote:{ items:['reels_yt'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'已完成', online:'2026/06/14' },
  },
  {
    id:'TM-2312', stage:'finance', vendor:'田町 Tamachi', product:'純棉中筒襪',
    category:'服飾', riskKind:'general', contact:'高雅婷', contactRole:'行銷',
    received:'2026/04/20', updated:'已結案', avatarBg:'var(--gold-2)',
    budgetHint:'3.5 萬', value:35000,
    email:`多多您好，田町純棉中筒襪，合作一篇影片＋圖貼文。`,
    wants:['IG 影片＋圖貼文一篇'], productLink:'https://tamachi.example',
    risk:'low', riskLabel:'低風險', riskStatus:'done',
    riskFindings:{ pros:['服飾類，無功效疑慮'], cons:[], disputes:[], okAngle:'穿搭情境。' },
    quote:{ items:['post_v'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'已完成', online:'2026/05/02' },
    invoice:{ no:'INV-114-0331', amount:35000, date:'2026/05/10' }, paid:true,
  },
];

// ── 追蹤欄位元資料（類型/意願/進度/成交/備註）──
const TRACK_META = {
  'PL-2406':{ caseType:'純業配', willing:'有興趣', progress:'報價', note:'法規需注意', pay:{dep:{paid:false,date:'', source:'自來信' },bal:{paid:false,date:''}} },
  'NG-2410':{ caseType:'純業配', willing:'有興趣', progress:'洽談', note:'訴求有療效虑', pay:{dep:{paid:false,date:'', source:'自來信' },bal:{paid:false,date:''}} },
  'MU-2405':{ caseType:'純業配', willing:'有興趣', progress:'報價', note:'', pay:{dep:{paid:false,date:'', source:'自來信' },bal:{paid:false,date:''}} },
  'GH-2410':{ caseType:'團購', willing:'有興趣', progress:'洽談', note:'公司討論中', pay:{dep:{paid:false,date:'', source:'自來信' },bal:{paid:false,date:''}} },
  'NS-2403':{ caseType:'純業配', willing:'有興趣', progress:'簽約', note:'', pay:{dep:{paid:true,date:'2026/06/12', source:'自來信' },bal:{paid:false,date:''}} },
  'CT-2401':{ caseType:'純業配', willing:'有興趣', progress:'審稿', note:'已收訂金·製作中', pay:{dep:{paid:true,date:'2026/05/20', source:'自來信' },bal:{paid:false,date:''}} },
  'TM-2312':{ caseType:'純業配', willing:'有興趣', progress:'結案', note:'已結案', pay:{dep:{paid:true,date:'2026/04/28', source:'自來信' },bal:{paid:true,date:'2026/05/10'}} },
};

// ── 來自真實追蹤/排程表的範例廠商（早期洽談）──
const EXTRA_CASES = [
  {
    id:'MJ-2406', stage:'inquiry', vendor:'無印良品 MUJI', product:'生活選品系列',
    category:'居家·生活', riskKind:'general', contact:'無印', contactRole:'行銷窗口',
    received:'2026/05/29', updated:'2 小時前', avatarBg:'var(--ink)',
    budgetHint:'未提供', value:null,
    email:`多多您好，無印良品想逈0國美合作生活選品系列的情境置入，先詢問檔期與報價。`,
    wants:['待確認'], productLink:'https://muji.example',
    risk:'low', riskLabel:'低風險', riskStatus:'idle', riskFindings:null,
    quote:{ items:[], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
  {
    id:'WP-2406', stage:'inquiry', vendor:'惠而浦（聯太公關）', product:'家電新品推廣',
    category:'家電', riskKind:'general', contact:'David', contactRole:'聯太公關',
    received:'2026/06/03', updated:'未開始', avatarBg:'var(--clay-2)',
    budgetHint:'未提供', value:null,
    email:`Hi 多多，我是聯太公關 David，代理惠而浦家電新品專案，想詢問國美的合作方式與檔期，謝謝。`,
    wants:['待確認'], productLink:'https://whirlpool.example',
    risk:'mid', riskLabel:'待評估', riskStatus:'idle', riskFindings:null,
    quote:{ items:[], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
  {
    id:'WW-2405', stage:'intent', vendor:'高雄衛武營國家藝術文化中心', product:'表演季黃推廣',
    category:'藝文·活動', riskKind:'general', contact:'昭雪', contactRole:'行銷',
    received:'2026/05/20', updated:'昨天', avatarBg:'var(--gold-2)',
    budgetHint:'公部預算', value:null,
    email:`多多您好，衡武營新一季表演節目想逈0國美合作推廣，以 5cm 小人物視角介紹場館與表演，請提供報價。`,
    wants:['IG 純圖文貼文一篇'], productLink:'https://weiwuying.example',
    risk:'low', riskLabel:'低風險', riskStatus:'done',
    riskFindings:{ pros:['公立藝文場館，形象正面'], cons:['注意演出資訊、票價描述需準確'], disputes:[], okAngle:'以場館小人物探險情境呈現。' },
    quote:{ items:['post'], situation:'s1', rush:false, groupFee:8000, share:15 },
    schedule:{ shoot:'', online:'' },
  },
];
const REJECTED_CASE = {
  id:'XX-2405', stage:'inquiry', vendor:'某電子菸品牌', product:'加熱菸裝置',
  category:'菸品', riskKind:'general', contact:'業務', contactRole:'業務',
  received:'2026/05/18', updated:'已婉拒', avatarBg:'var(--ink-3)',
  budgetHint:'—', value:null,
  email:`想逈0國美合作加熱菸裝置的置入介紹。`,
  wants:['IG Reels 一則'], productLink:'',
  risk:'high', riskLabel:'需注意', riskStatus:'done',
  riskFindings:{ pros:[], cons:['菸品不得廣告（菸害防制法），與品牌調性不符'], disputes:[], okAngle:'不建議合作。' },
  quote:{ items:[], situation:'s2', rush:false, groupFee:8000, share:15 },
  schedule:{ shoot:'', online:'' },
};
TRACK_META['MJ-2406']={ caseType:'純業配', willing:'有興趣', progress:'洽談', note:'' , source:'開發信' };
TRACK_META['WP-2406']={ caseType:'純業配', willing:'有興趣', progress:'洽談', note:'未開始' , source:'自來信' };
TRACK_META['WW-2405']={ caseType:'純業配', willing:'有興趣', progress:'報價', note:'' , source:'開發信' };
TRACK_META['XX-2405']={ caseType:'純業配', willing:'婉拒', progress:'婉拒', note:'法規不可·婉拒' , source:'自來信' };
SEED_CASES.push(...EXTRA_CASES, REJECTED_CASE);
SEED_CASES.forEach(c=>{ Object.assign(c, TRACK_META[c.id] || { caseType:'純業配', willing:'有興趣', progress:progressFromStage(c.stage), note:'' , source:'自來信' }); });
SEED_CASES.forEach(c=>{ if(!c.pay) c.pay = makePay(c); });

// ── 委刊單 / 溝通表 / 製作排程 預設工廠──
let _ioSeq = 240611;
function ioItemsFromQuote(c){
  return c.quote.items.map(k=>{ const p=PRICE_LIST.find(x=>x.key===k)||{}; return { name:p.item, fee:p.price||0 }; });
}
function makeIO(c){
  return {
    number:'IO-'+(_ioSeq++), date:'',
    // 甲方資訊
    taxId:'', invoiceTitle:c.vendor, addr:'', tel:'', email:'',
    // 可編輯明細
    items: ioItemsFromQuote(c),
    // 付款條件（可雙方異動）
    depPct:50, balPct:50,
    payDep:'簽約且收受乙方開立之發票後 7 日內',
    payBal:'提交初稿並收到發票後 30 日內',
    // 可編輯條款（預帶範本 7 條）
    clauses: IO_CLAUSES.map(cl=>({ h:cl.h, body:cl.body.replace('NT$ 　','NT$ ＿＿ ') })),
    noncompScope: c.quote.items.includes('noncomp')?'同類競品，三個月':'', penalty:'', note:'',
    // 雙方帳號資料
    bankA:{ holder:'', bank:'', code:'', acct:'' },
    bankB:{ holder:'果米工作室', bank:'', code:'', acct:'' },
    signA:'', signB:'', signed:false,
  };
}
function makeComm(c){
  return { selling:'', theme:'', mustSay:'', avoid:'', refLinks:'', materials:'', deliveryAddr:'', sampleNeeded:'是',
    onlineWindow: c.schedule.online||'', special:'', filled:false };
}
function makeProd(c){
  if(c.prodSeed) return { draft:'', draftFix:'', script:'', scriptFix:'', shoot:'', post:'', deliver:'', finalFix:'', online:'', ...c.prodSeed };
  return { draft:'', draftFix:'', script:'', scriptFix:'',
    shoot: /\d{4}/.test(c.schedule.shoot||'')?c.schedule.shoot:'', post:'', deliver:'', finalFix:'',
    online: /\d{4}/.test(c.schedule.online||'')?c.schedule.online:'' };
}

const fmt = (n) => n==null ? '—' : 'NT$ ' + Number(n).toLocaleString('en-US');
const fmtNum = (n) => Number(n||0).toLocaleString('en-US');
const riskTone = (r) => r==='high'?'risk-high':r==='mid'?'risk-mid':'risk-low';
const stageName = (id) => (STAGES.find(s=>s.id===id)||{}).name || id;

// ── .ics 產生（全天事件，支援色系與區間）──
function pad(n){ return String(n).padStart(2,'0'); }
function icsDate(yyyymmdd){ return yyyymmdd.replace(/[^0-9]/g,''); } // 20260625
function nextDay(yyyymmdd){
  const s=icsDate(yyyymmdd); const y=+s.slice(0,4),m=+s.slice(4,6),d=+s.slice(6,8);
  const dt=new Date(y,m-1,d+1);
  return `${dt.getFullYear()}${pad(dt.getMonth()+1)}${pad(dt.getDate())}`;
}
// 將「2026-06-18」、06/18　12026/06/18 歸一化為 YYYYMMDD（缺年份則用 refYear）
function normDate(v, refYear){
  const parts=String(v).trim().split(/[/\-.]/).map(x=>x.trim()).filter(Boolean);
  let y,m,d;
  if(parts.length>=3){ [y,m,d]=parts; }
  else if(parts.length===2){ [m,d]=parts; y=refYear; }
  else return null;
  if(!/^\d+$/.test(y)||!/^\d+$/.test(m)||!/^\d+$/.test(d)) return null;
  return `${y}${pad(+m)}${pad(+d)}`;
}
// 「09/11~09/17」→ {start,end}（YYYYMMDD）
function parseRange(v, refYear){
  const seg=String(v).split(/[~\u2013\u2014\u81f3]/).map(x=>x.trim()).filter(Boolean);
  if(seg.length<2) return null;
  const start=normDate(seg[0], refYear), end=normDate(seg[1], refYear);
  if(!start||!end) return null;
  return { start, end };
}
// 依案件產生製作排程事件（含色系、區間）
function buildProdEvents(c){
  const pr=c.prod||{}; const out=[];
  const refYear=(()=>{
    for(const k of ['online','shoot','deliver','script','draft']){
      const mm=String(pr[k]||'').match(/(\d{4})/); if(mm) return mm[1];
    }
    return String(new Date().getFullYear());
  })();
  PROD_STEPS.forEach(s=>{
    if(!s.cal) return;
    const v=String(pr[s.key]||'').trim(); if(!v) return;
    const summary=`${s.icon}【${s.label}】${c.vendor} · ${c.product}`;
    const desc=`${c.id} ${c.vendor}`;
    if(s.kind==='range'){
      const r=parseRange(v, refYear); if(!r) return;
      out.push({ start:r.start, end:r.end, summary, desc, color:s.color, cat:s.cat, label:s.label, icon:s.icon, kind:'range' });
    } else {
      const d=normDate(v, refYear); if(!d) return;
      out.push({ date:d, summary, desc, color:s.color, cat:s.cat, label:s.label, icon:s.icon, kind:'date' });
    }
  });
  return out;
}
const ICS_COLOR = { red:'tomato', yellow:'khaki' }; // RFC 7986 COLOR（CSS3 色名）
// Google Calendar API event colorId（API 才能真正指定顏色；.ics 匯入會被忽略）
const GCAL_COLOR = {
  red:    { id:'11', name:'Tomato 蕃茄紅', hex:'#D50000' },
  yellow: { id:'5',  name:'Banana 香蕉黃', hex:'#F6BF26' },
};
// 由提供草圖日期自動推算後續排程（差距 gap 天，3~5）
function parseYMD(v){
  const s=String(v).trim().replace(/\//g,'-'); const p=s.split('-').map(Number);
  if(p.length<3 || p.some(isNaN)) return null;
  return new Date(p[0], p[1]-1, p[2]);
}
function addDays(d, n){ const x=new Date(d); x.setDate(x.getDate()+n); return x; }
function fmtYMD(d){ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`; }
function fmtMD(d){ return `${pad(d.getMonth()+1)}/${pad(d.getDate())}`; }
function fmtRangeMD(a,b){ return `${fmtMD(a)}~${fmtMD(b)}`; }
// gap：里程碑之間的間隔天數（3~5）；修改/後製區間長度 = gap
function autoSchedule(draftYMD, gap){
  const d0 = parseYMD(draftYMD); if(!d0) return null;
  const g = Math.min(5, Math.max(3, gap||4));
  const out = { draft: fmtYMD(d0) };
  let s, e;
  s = addDays(d0, 1);        e = addDays(s, g-1);  out.draftFix  = fmtRangeMD(s, e);  // 修改草圖
  let cur = addDays(e, g);   out.script   = fmtYMD(cur);                              // 提供腳本
  s = addDays(cur, 1);       e = addDays(s, g-1);  out.scriptFix = fmtRangeMD(s, e);  // 修改腳本
  cur = addDays(e, g);       out.shoot    = fmtYMD(cur);                              // 拍攝日
  s = addDays(cur, 1);       e = addDays(s, g);    out.post     = fmtRangeMD(s, e);  // 後製期（略長）
  cur = addDays(e, g);       out.deliver  = fmtYMD(cur);                              // 提供成品
  s = addDays(cur, 1);       e = addDays(s, g-1);  out.finalFix = fmtRangeMD(s, e);  // 修改成品
  cur = addDays(e, g);       out.online   = fmtYMD(cur);                              // 上線日
  return out;
}
function buildICS(title, events){
  const stamp = new Date().toISOString().replace(/[-:]/g,'').split('.')[0]+'Z';
  let L = ['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//果米工作室//工作整合器//TW','CALSCALE:GREGORIAN','METHOD:PUBLISH'];
  events.forEach((e,i)=>{
    let start, end;
    if(e.kind==='range' && e.start){ start=icsDate(e.start); end=nextDay(e.end); }
    else { if(!e.date || !/\d{4}/.test(e.date)) return; start=icsDate(e.date); end=nextDay(e.date); }
    L.push('BEGIN:VEVENT',
      `UID:${title}-${i}-${start}@guomi`,
      `DTSTAMP:${stamp}`,
      `DTSTART;VALUE=DATE:${start}`,
      `DTEND;VALUE=DATE:${end}`,
      `SUMMARY:${e.summary}`);
    if(e.cat) L.push(`CATEGORIES:${e.cat}`);
    if(e.color && ICS_COLOR[e.color]) L.push(`COLOR:${ICS_COLOR[e.color]}`);
    L.push(`DESCRIPTION:${(e.desc||'').replace(/\n/g,'\\n')}`,'END:VEVENT');
  });
  L.push('END:VCALENDAR');
  return L.join('\r\n');
}
async function copyText(text, toast, okMsg){
  try{
    if(navigator.clipboard && navigator.clipboard.writeText){
      await navigator.clipboard.writeText(text);
      toast && toast(okMsg||'已複製到剪貼簿'); return true;
    }
    throw new Error('no-api');
  }catch(e){
    try{
      const ta=document.createElement('textarea');
      ta.value=text; ta.style.cssText='position:fixed;top:0;left:0;opacity:0;';
      document.body.appendChild(ta); ta.focus(); ta.select();
      const ok=document.execCommand('copy'); document.body.removeChild(ta);
      toast && toast(ok? (okMsg||'已複製到剪貼簿') : '複製受限，請長按選取內文手動複製');
      return ok;
    }catch(_e){ toast && toast('複製受限，請長按選取內文手動複製'); return false; }
  }
}
function downloadICS(filename, content){
  const blob = new Blob([content], { type:'text/calendar;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a'); a.href=url; a.download=filename; document.body.appendChild(a); a.click();
  setTimeout(()=>{ document.body.removeChild(a); URL.revokeObjectURL(url); }, 200);
}

Object.assign(window, {
  PRICE_LIST, STAGES, LAW_LIB, AVOID_WORDS, RISK_KIND_LABEL, SEED_CASES,
  STUDIO, IO_CLAUSES, PROD_STEPS, CASE_TYPES, WILLING, PROGRESS, DEAL, SOURCES, sourceTone,
  dealTone, progressFromStage, stageFromCase, makeIO, makeComm, makeProd, ioItemsFromQuote,
  PROGRESS_PIPELINE, progressTone, makePay, payLabel, payTone,
  fmt, fmtNum, riskTone, stageName, buildICS, downloadICS, copyText, buildProdEvents, autoSchedule, GCAL_COLOR, currentTab,
});
