/* ════════════════════════════════════════════════════════════════════════
   scent-card.jsx  —  Phinn-Phang 香氣分析・共用視覺系統
   ------------------------------------------------------------------------
   匯出（window）：
     THEMES            兩個 theme（dark / cream）token 物件
     deriveWork(work)  把 work 物件算成畫面需要的資料
     Radar             7 軸 SVG 雷達（theme-aware）
     ScreenView        【螢幕 view】全頁自然網頁流動、響應式
     ExportCard        【下載 view】固定 840×1188 A4，截圖用
     makeSerial        無 serialNumber 時的 fallback 序號
   兩個 view 共用同一份資料與同一套視覺語言；ScreenView 鬆、ExportCard 密。
   ════════════════════════════════════════════════════════════════════════ */
const { useEffect: _useEffect, useRef: _useRef } = React;

/* ── THEMES ──────────────────────────────────────────────────────────────── */
const THEMES = {
  dark: {
    name: 'dark',
    pageBg: 'radial-gradient(125% 90% at 50% 6%, #2a1610 0%, #1a0f0a 50%, #140c08 100%)',
    cardPageBg: 'radial-gradient(125% 90% at 50% 8%, #2a1610 0%, #1a0f0a 52%, #140c08 100%)',
    exportBg: '#160d08',
    ink: '#F2EADD', inkSoft: 'rgba(242,234,221,0.66)', inkFaint: 'rgba(242,234,221,0.34)',
    gold: '#C8965A', goldSoft: 'rgba(200,150,90,0.72)', goldFaint: 'rgba(200,150,90,0.26)',
    coral: '#E8B5A0',
    line: 'rgba(200,150,90,0.22)', hair: 'rgba(200,150,90,0.14)',
    cardBg: 'linear-gradient(158deg, rgba(200,150,90,0.07), rgba(255,250,244,0.012))',
    cardBorder: 'rgba(200,150,90,0.18)',
    chipBorder: 'rgba(200,150,90,0.42)',
    radarGrid: 'rgba(200,150,90,0.16)', radarFill: 'rgba(232,149,122,0.20)', radarStroke: '#E8B5A0',
    barTrack: 'rgba(242,234,221,0.06)',
    logo: 'uploads/logo_dark.png', wmOpacity: 0.05, famMix: null,
    glow: '0 0 70px rgba(220,120,90,0.22)',
    chromeBg: 'rgba(22,13,8,0.72)', chromeBorder: 'rgba(200,150,90,0.22)',
  },
  cream: {
    name: 'cream',
    pageBg: 'radial-gradient(125% 95% at 50% 0%, #FCF9F5 0%, #F5EFE6 55%, #E8DFD0 100%)',
    cardPageBg: 'radial-gradient(125% 95% at 50% 0%, #FCF9F5 0%, #F5EFE6 55%, #E8DFD0 100%)',
    exportBg: '#F5EFE6',
    ink: '#2f2418', inkSoft: 'rgba(47,36,24,0.70)', inkFaint: 'rgba(47,36,24,0.40)',
    gold: '#9a6324', goldSoft: 'rgba(140,90,40,0.80)', goldFaint: 'rgba(140,90,40,0.32)',
    coral: '#bb6346',
    line: 'rgba(120,85,45,0.30)', hair: 'rgba(120,85,45,0.18)',
    cardBg: 'linear-gradient(158deg, rgba(255,252,245,0.55), rgba(220,200,165,0.18))',
    cardBorder: 'rgba(120,85,45,0.24)',
    chipBorder: 'rgba(140,95,45,0.45)',
    radarGrid: 'rgba(120,85,45,0.22)', radarFill: 'rgba(187,99,70,0.18)', radarStroke: '#bb6346',
    barTrack: 'rgba(70,50,30,0.08)',
    logo: 'uploads/logo_light.png', wmOpacity: 0.05, famMix: '#3a2614',
    glow: 'none',
    chromeBg: 'rgba(243,236,220,0.78)', chromeBorder: 'rgba(120,85,45,0.26)',
  },
};

/* hex helpers — darken family colours for the cream paper theme */
function _hex2rgb(h){ h=h.replace('#',''); if(h.length===3)h=h.split('').map(c=>c+c).join(''); const n=parseInt(h,16); return [n>>16&255,n>>8&255,n&255]; }
function _rgb2hex(r,g,b){ return '#'+[r,g,b].map(v=>Math.max(0,Math.min(255,Math.round(v))).toString(16).padStart(2,'0')).join(''); }
function _mix(a,b,t){ const A=_hex2rgb(a),B=_hex2rgb(b); return _rgb2hex(A[0]+(B[0]-A[0])*t,A[1]+(B[1]-A[1])*t,A[2]+(B[2]-A[2])*t); }
function famColor(c,t){ return t.famMix ? _mix(c, t.famMix, 0.30) : c; }

/* ── derive helpers ──────────────────────────────────────────────────────── */
function computeImpressions(radar){
  const v = id => radar.find(d => d.id === id)?.value || 0;
  const cl = n => Math.max(0, Math.min(100, Math.round(n)));
  return [
    { zh: '清新感', value: cl((v('citrus') + v('green') + v('tea')) / 3) },
    { zh: '花香感', value: cl(v('floral')) },
    { zh: '木質感', value: cl((v('woody') + v('mossy') + v('balsam')) / 3) },
    { zh: '甜　感', value: cl((v('fruity') + v('sweety')) / 2) },
    { zh: '溫暖感', value: cl((v('balsam') + v('woody') + v('musk')) / 3) },
    { zh: '神秘感', value: cl((v('oriental') + v('musk')) / 2) },
    { zh: '清爽感', value: cl((v('citrus') + v('green') + v('fresh')) / 3) },
  ];
}

function makeSerial(work){
  const src = (work.id || work.workName || 'pp') + '';
  let h = 0; for (const c of src) h = (h * 31 + c.charCodeAt(0)) >>> 0;
  return String(h % 10000).padStart(4, '0');
}

const _LAYERS = [
  { id: 'top',    zh: '前調', en: 'TOP'   },
  { id: 'middle', zh: '中調', en: 'HEART' },
  { id: 'base',   zh: '後調', en: 'BASE'  },
];

function deriveWork(work){
  const radar    = work.radarData?.length ? work.radarData : PP.computeRadar(work.formula);
  const dims     = computeImpressions(radar);
  const families = PP.computeRadar(work.formula).filter(f => f.value > 0).sort((a, b) => b.value - a.value);
  const total    = work.totalDrops || work.formula.reduce((s, f) => s + (Number(f.drops) || 0), 0);
  const layerData = _LAYERS.map(L => {
    const items = work.formula.filter(f => f.layer === L.id);
    const drops = items.reduce((s, f) => s + (Number(f.drops) || 0), 0);
    return { ...L, items, drops, pct: total ? Math.round(drops / total * 100) : 0 };
  });
  const serial  = (work.serialNumber != null && work.serialNumber !== '')
    ? String(work.serialNumber) : makeSerial(work);
  const tagline = work.tagline || '';
  return { radar, dims, families, layerData, total, serial, tagline };
}

/* 匯出卡調香手記截句：≤85 字直接回；否則截到前 85 字內最後一個句號（含）；
   85 字內無句號 → 前 80 字 + 「…」。保證完整句、不硬切。unicode-safe。 */
function makeExportNote(text){
  const s = (text || '').trim();
  const chars = [...s];
  if (chars.length <= 85) return s;
  const head = chars.slice(0, 85).join('');
  const lastPeriod = head.lastIndexOf('。');
  if (lastPeriod >= 0) return head.slice(0, lastPeriod + 1);
  return chars.slice(0, 80).join('') + '…';
}

/* ── Radar (SVG, theme-aware) ───────────────────────────────────────────────
   size: 視覺尺寸（px maxWidth）。labelGap 控制標籤離環的距離。 */
function Radar({ dims, t, max = 286, labelFs = 13, valFs = 18, S = 320, cx = 160, cy = 158, R = 92 }){
  const n = dims.length, step = (Math.PI * 2) / n, start = -Math.PI / 2;
  // 動態軸 max：放大形狀貼合實際印象值範圍(~0-35)；下限 40 防全小值時爆滿失真，maxDim>40 時用 maxDim 確保最大維不超出環
  const AXIS_MAX = Math.max(40, dims.reduce((m, d) => Math.max(m, d.value), 0));
  const pt = (i, rad) => [cx + Math.cos(start + step * i) * rad, cy + Math.sin(start + step * i) * rad];
  const ringPts = s => dims.map((_, i) => pt(i, R * s).join(',')).join(' ');
  const dataPts = dims.map((d, i) => pt(i, R * Math.min(1, d.value / AXIS_MAX)).join(',')).join(' ');

  return (
    <svg viewBox={`0 0 ${S} ${S}`} style={{ width: '100%', maxWidth: max, display: 'block', margin: '0 auto' }}>
      {[0.25, 0.5, 0.75, 1].map(s => (
        <polygon key={s} points={ringPts(s)} fill="none" stroke={t.radarGrid} strokeWidth="0.8" />
      ))}
      {dims.map((_, i) => { const [x, y] = pt(i, R); return <line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke={t.radarGrid} strokeWidth="0.8" />; })}
      <polygon points={dataPts} fill={t.radarFill} stroke={t.radarStroke} strokeWidth="1.6" strokeLinejoin="round" />
      {dims.map((d, i) => { const [x, y] = pt(i, R * Math.min(1, d.value / AXIS_MAX)); return <circle key={i} cx={x} cy={y} r={d.value > 0 ? 3.4 : 2} fill={d.value > 0 ? t.radarStroke : t.goldFaint} />; })}
      {dims.map((d, i) => {
        const a = start + step * i, lx = cx + Math.cos(a) * (R + 30), ly = cy + Math.sin(a) * (R + 30);
        const cos = Math.cos(a);
        const anchor = cos > 0.30 ? 'start' : cos < -0.30 ? 'end' : 'middle';
        const active = d.value > 0;
        return (
          <g key={i}>
            <text x={lx} y={ly - 4} textAnchor={anchor} fill={active ? t.gold : t.goldFaint}
              style={{ fontFamily: "'Noto Serif TC',serif", fontSize: labelFs, fontWeight: 300, letterSpacing: '.04em' }}>{d.zh}</text>
            <text x={lx} y={ly + 15} textAnchor={anchor} fill={active ? t.coral : t.goldFaint}
              style={{ fontFamily: "'Cormorant Garamond',serif", fontSize: valFs, fontWeight: 500 }}>{d.value}</text>
          </g>
        );
      })}
    </svg>
  );
}

/* ── shared atoms ───────────────────────────────────────────────────────── */
function Label({ en, zh, t, big }){
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginBottom: 14 }}>
      <span style={{ fontFamily: "'IBM Plex Mono',monospace", fontSize: big ? 16 : 11, letterSpacing: '.28em', textTransform: 'uppercase', color: t.goldSoft, whiteSpace: 'nowrap' }}>{en}</span>
      {zh && <span style={{ fontSize: big ? 16 : 11.5, letterSpacing: '.2em', color: t.inkFaint, whiteSpace: 'nowrap' }}>{zh}</span>}
      <span style={{ flex: 1, height: 1, background: `linear-gradient(to right, ${t.line}, transparent)` }} />
    </div>
  );
}
function Chip({ children, t, fs = 12.5 }){
  return <span style={{ padding: '4px 13px', border: `1px solid ${t.chipBorder}`, color: t.gold, fontSize: fs, letterSpacing: '.1em', lineHeight: 1.5, whiteSpace: 'nowrap', borderRadius: 1 }}>{children}</span>;
}

/* ════════════════════════════════════════════════════════════════════════
   PERSONA BAND（SCENT TYPE）— 兩 view 共用，尺寸用 props 調
   ════════════════════════════════════════════════════════════════════════ */
function PersonaBand({ sp, t, big }){
  if (!sp) return null;
  return (
    <div className="sc-band" style={{ display: 'flex', alignItems: 'center', gap: big ? 26 : 18, padding: big ? '22px 30px' : '14px 22px', background: t.cardBg, border: `1px solid ${t.cardBorder}`, borderRadius: 3 }}>
      <div className="sc-band-type" style={{ textAlign: 'center', paddingRight: big ? 26 : 18, borderRight: `1px solid ${t.hair}`, flexShrink: 0 }}>
        <div style={{ fontFamily: "'IBM Plex Mono',monospace", fontSize: big ? 10.5 : 9.5, letterSpacing: '.24em', color: t.goldSoft, marginBottom: 6 }}>SCENT TYPE</div>
        <div style={{ fontFamily: "'Noto Serif TC',serif", fontWeight: 400, fontSize: big ? 28 : 22, letterSpacing: '.08em', color: t.coral, whiteSpace: 'nowrap' }}>{/型人格$/.test(sp.title) ? sp.title : `${sp.title}型人格`}</div>
      </div>
      {Array.isArray(sp.keywords) && (
        <div className="sc-band-chips" style={{ display: 'flex', flexWrap: 'wrap', gap: big ? 10 : 8, flex: 1 }}>
          {sp.keywords.map((k, i) => <Chip key={i} t={t} fs={big ? 14 : 12.5}>{k}</Chip>)}
        </div>
      )}
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════
   RATIO（香調比例）— stacked bar + legend rows
   ════════════════════════════════════════════════════════════════════════ */
function RatioBlock({ families, t, rows = 6, big }){
  return (
    <div>
      <div style={{ display: 'flex', height: big ? 26 : 22, borderRadius: 2, overflow: 'hidden', marginBottom: big ? 20 : 16, border: `1px solid ${t.hair}` }}>
        {families.map(f => (
          <div key={f.id} style={{ width: `${f.value}%`, background: famColor(f.color, t) }} title={`${f.zh} ${f.value}%`} />
        ))}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: big ? 12 : 9 }}>
        {families.slice(0, rows).map(f => (
          <div key={f.id} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 9, height: 9, borderRadius: '50%', background: famColor(f.color, t), flexShrink: 0 }} />
            <span style={{ fontSize: big ? 15 : 13.5, color: t.inkSoft, letterSpacing: '.05em', flexShrink: 0, minWidth: 46 }}>{f.zh}</span>
            <span style={{ flex: 1, height: 3, borderRadius: 2, background: t.barTrack, overflow: 'hidden' }}>
              <span style={{ display: 'block', height: '100%', width: `${f.value}%`, background: famColor(f.color, t), opacity: .75 }} />
            </span>
            <span style={{ fontFamily: "'Cormorant Garamond',serif", fontSize: big ? 19 : 17, color: famColor(f.color, t), minWidth: 32, textAlign: 'right' }}>{f.value}%</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════
   FORMULA（前中後調三欄）
   ════════════════════════════════════════════════════════════════════════ */
// d2: 對齊「香氣卡-D2」模板的放大字級（層調 25 / en 17 / pct 23 / 香精名 23 / 滴數 21 / 滴 18，cols gap 44）。
// 預設 undefined → falsy → 與原 big/small 行為完全相同，ScreenView 既有呼叫不受影響。
function FormulaCols({ layerData, t, big, className, d2 }){
  return (
    <div className={className} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: d2 ? 44 : big ? 28 : 20 }}>
      {layerData.map(L => (
        <div key={L.id}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: d2 ? 16 : big ? 14 : 10, paddingBottom: d2 ? 11 : big ? 9 : 7, borderBottom: `1px solid ${t.hair}` }}>
            <span style={{ fontFamily: "'Noto Serif TC',serif", fontWeight: 600, fontSize: d2 ? 25 : big ? 18 : 16, letterSpacing: '.1em', color: t.ink }}>{L.zh}</span>
            <span style={{ fontFamily: "'Cormorant Garamond',serif", fontStyle: d2 ? 'normal' : undefined, fontSize: d2 ? 17 : big ? 10 : 9.5, letterSpacing: d2 ? '.3em' : '.16em', textTransform: d2 ? 'uppercase' : undefined, color: t.goldSoft }}>{L.en}</span>
            <span style={{ marginLeft: 'auto', fontFamily: d2 ? "'Space Mono','IBM Plex Mono',monospace" : "'Cormorant Garamond',serif", fontSize: d2 ? 23 : big ? 18 : 16, color: t.gold }}>{L.pct}%</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: d2 ? 13 : big ? 10 : 8 }}>
            {L.items.length === 0 && <span style={{ fontSize: 12.5, color: t.inkFaint, letterSpacing: '.05em' }}>—</span>}
            {L.items.map(ing => (
              <div key={ing.id || ing.name} style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
                <span style={{ width: 7, height: 7, borderRadius: '50%', background: famColor(PP.FAMILIES.find(x => x.id === ing.family)?.color || t.gold, t), flexShrink: 0, transform: 'translateY(-1px)' }} />
                <span style={{ fontSize: d2 ? 23 : big ? 15 : 14, color: t.ink, letterSpacing: '.04em' }}>{ing.name}</span>
                <span style={{ marginLeft: 'auto', fontFamily: d2 ? "'Space Mono','IBM Plex Mono',monospace" : "'IBM Plex Mono',monospace", fontSize: d2 ? 21 : big ? 13 : 12, color: t.inkSoft }}>{ing.drops}<span style={{ fontSize: d2 ? 18 : 10, color: t.inkFaint }}> 滴</span></span>
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

/* tri proportion bar above formula */
function TriBar({ layerData, t, h = 6 }){
  return (
    <div style={{ display: 'flex', height: h, borderRadius: h / 2, overflow: 'hidden', marginBottom: 13 }}>
      {layerData.map((L, i) => (
        <div key={L.id} style={{ width: `${L.pct || 0.5}%`, background: t.gold, opacity: 0.3 + i * 0.28 }} />
      ))}
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════
   THREE CARDS（Persona / Emotion / Balance）
   ════════════════════════════════════════════════════════════════════════ */
// Filter out cards where head AND body are both empty/missing. Partial-null
// cards (one of head/body present) stay in place; their empty section just
// renders empty (no placeholder text).
function threeCardData(work){
  const sp = work.scentProfile, ee = work.emotionalEffect, ba = work.balanceAdvice;
  const trim = s => (s || '').trim();
  const entries = [];
  if (sp && (trim(sp.title) || trim(sp.description))) {
    entries.push({ en: 'Persona', zh: '香氣性格', head: sp.title || '', body: sp.description || '' });
  }
  if (ee && (trim(ee.mood) || trim(ee.description))) {
    entries.push({ en: 'Emotion', zh: '情緒陪伴', head: ee.mood ? `這支香氣帶來「${ee.mood}」` : '', body: ee.description || '' });
  }
  if (trim(ba)) {
    entries.push({ en: 'Balance', zh: '配方建議', head: '下次可以這樣調', body: ba });
  }
  return entries;
}
function ThreeCards({ work, cards, t, big, className, bodyFs, bodyLs, headFs, enFs, cardMinH }){
  const data = cards || threeCardData(work);
  if (data.length === 0) return null;
  return (
    <div className={className} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: big ? 22 : 18 }}>
      {data.map((c, i) => (
        <div key={i} style={{ background: t.cardBg, border: `1px solid ${t.cardBorder}`, borderRadius: 3, padding: big ? '22px 22px' : '15px 16px', minHeight: cardMinH, display: 'flex', flexDirection: 'column' }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: big ? 12 : 9 }}>
            <span style={{ fontFamily: "'Cormorant Garamond',serif", fontStyle: 'italic', fontSize: enFs ?? (big ? 17 : 15), letterSpacing: '.06em', color: t.gold }}>{c.en}</span>
            <span style={{ fontSize: 11, letterSpacing: '.16em', color: t.inkFaint }}>{c.zh}</span>
          </div>
          {c.head && <div style={{ fontFamily: "'Noto Serif TC',serif", fontWeight: 400, fontSize: headFs ?? (big ? 16 : 14.5), letterSpacing: '.04em', color: t.coral, lineHeight: 1.5, marginBottom: big ? 10 : 8 }}>{c.head}</div>}
          <p style={{ fontSize: bodyFs ?? (big ? 13.5 : 11.8), color: t.inkSoft, lineHeight: big ? 1.95 : 1.74, letterSpacing: bodyLs ?? '.03em' }}>{c.body}</p>
        </div>
      ))}
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════
   ① SCREEN VIEW — 全頁、自然流動、響應式
   ════════════════════════════════════════════════════════════════════════ */
function ScreenView({ work, t, onShare }){
  const { dims, families, layerData, total, serial, tagline } = deriveWork(work);
  const sp = work.scentProfile;
  const cards = threeCardData(work);

  return (
    <div className="sv-wrap">

      {/* ── Header row ─────────────────────────────────────────── */}
      <div className="sv-headrow">
        <a href="index.html" style={{ display: 'inline-block', lineHeight: 0 }}><img src={t.logo} alt="Phinn-Phang" className="sv-logo" /></a>
        <div style={{ textAlign: 'right', fontFamily: "'IBM Plex Mono',monospace", lineHeight: 1.7 }}>
          <div style={{ fontSize: 13, letterSpacing: '.18em', color: t.gold }}>No. {serial}</div>
          <div style={{ fontSize: 11, letterSpacing: '.14em', color: t.inkFaint }}>{work.courseDate || '—'}</div>
        </div>
      </div>

      {/* ── Hero ───────────────────────────────────────────────── */}
      <header className="sv-hero">
        <div style={{ fontFamily: "'IBM Plex Mono',monospace", fontSize: 11, letterSpacing: '.34em', color: t.goldSoft, marginBottom: 18 }}>YOUR SCENT PROFILE · 香氣分析</div>
        <h1 className="sv-title" style={{ color: t.ink, textShadow: t.glow }}>{work.workName}</h1>
      </header>

      {/* ── SCENT TYPE band ────────────────────────────────────── */}
      {sp && (
        <section className="sv-sec">
          <PersonaBand sp={sp} t={t} big />
        </section>
      )}

      {/* ── Creator's note（全文，與其他 section 同寬）─────────── */}
      {work.aiDescription && (
        <section className="sv-sec">
          <Label en="Creator's Note" zh="調香手記" t={t} />
          <div style={{ position: 'relative', paddingLeft: 4 }}>
            <p style={{ fontFamily: "'Noto Serif TC',serif", fontSize: 18, fontWeight: 300, color: t.inkSoft, lineHeight: 2.2, letterSpacing: '.06em' }}>{work.aiDescription}</p>
          </div>
        </section>
      )}

      {/* ── Impression radar（單獨）─────────────────────────────── */}
      <section className="sv-sec">
        <Label en="Impression" zh="香氣印象圖" t={t} />
        <Radar dims={dims} t={t} max={360} labelFs={14} valFs={20} />
      </section>

      {/* ── 配方 前中後調 ──────────────────────────────────────── */}
      <section className="sv-sec">
        <Label en="The Formula" zh={`配方組成${work.base?.name ? ' · ' + work.base.name : ''} · 共 ${total} 滴`} t={t} />
        <TriBar layerData={layerData} t={t} h={7} />
        <FormulaCols layerData={layerData} t={t} big className="sv-formula" />
      </section>

      {/* ── 三張卡（全 null → 整 row skip，eyebrow 也不畫）──────── */}
      {cards.length > 0 && (
        <section className="sv-sec">
          <Label en="Reading" zh="香氣解讀" t={t} />
          <ThreeCards cards={cards} t={t} big className="sv-cards" bodyFs={18} bodyLs=".06em" headFs={23} enFs={18} />
        </section>
      )}

      {/* ── Composition Ratio（移到最下方）──────────────────────── */}
      {/* 最後一個 sv-sec：清掉 margin-bottom，讓「最後內容→©」間距統一交給 SiteFooter marginTop */}
      <section className="sv-sec" style={{ marginBottom: 0 }}>
        <Label en="Composition Ratio" zh="香調比例" t={t} />
        <RatioBlock families={families} t={t} rows={6} big />
      </section>

      {/* ── 手機操作區（分享 / IG / 回首頁）— footer 上方、僅手機顯示（桌機用頂部 Chrome）── */}
      <div className="sv-foot-actions">
        <button className="sv-fa-btn sv-fa-solid" onClick={()=>onShare && onShare()}>分享</button>
        <a className="sv-fa-btn" href="https://www.instagram.com/phinnphang.__" target="_blank" rel="noopener noreferrer">追蹤 IG</a>
        <a className="sv-fa-btn" href="index.html">回首頁</a>
      </div>

      {/* ── Site footer（components.jsx 共用元件，© 2026 收尾）──── */}
      {window.SiteFooter ? <window.SiteFooter /> : null}
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════
   ② EXPORT CARD — 固定 840×1188 A4，密度高，截圖用
   ════════════════════════════════════════════════════════════════════════ */
function ExportCard({ work, t }){
  const { dims, layerData, total, serial, tagline } = deriveWork(work);
  const sp = work.scentProfile;
  const ee = work.emotionalEffect;
  // 精簡版（exportSummary）優先、完整版 fallback（沒精簡版時用原文，overflow 仍裁但不空白）。
  const es = work.exportSummary || {};
  const note = makeExportNote(es.desc || work.aiDescription || '');
  const personaDesc = es.personaDesc || (sp && sp.description) || '';
  const emotionDesc = es.emotionDesc || (ee && ee.description) || '';

  // 字體（對齊 D2 模板）：Noto Serif TC（內文/標題）、Cormorant（eyebrow/英文）、Space Mono（數字/編號/滴數）。
  const SERIF = "'Noto Serif TC',serif";
  const CORM = "'Cormorant Garamond',serif";
  const MONO = "'Space Mono','IBM Plex Mono',monospace";

  // 香名長度自適應字級。D2 理想值 96px（短中文名衝 96）；長名才逐階降。[...] 正確計 unicode 長度。
  const nm = work.workName || '';
  const nmLen = [...nm].length;
  // 中英分開算字級：中文窄、用原階梯；英文同字數可更大、放寬級距。
  const hasCJK = /[㐀-鿿＀-￯]/.test(nm);
  const nameFs = hasCJK
    ? (nmLen <= 4 ? 96 : nmLen <= 6 ? 76 : nmLen <= 10 ? 56 : nmLen <= 16 ? 40 : 30)
    : (nmLen <= 8 ? 88 : nmLen <= 12 ? 68 : nmLen <= 18 ? 52 : 40);
  const ptype = (sp && sp.title) ? (/型人格$/.test(sp.title) ? sp.title : `${sp.title}型人格`) : '';

  // 卡片底樣（D2：radius 10、border 1px line、padding 32 34）。色票走 theme（保 dark/cream 雙主題）。
  const card = { background: t.cardBg, border: `1px solid ${t.cardBorder}`, borderRadius: 10, overflow: 'hidden' };
  // card-lab eyebrow（D2）：en Cormorant italic 600 24px gold-soft；zh serif 18px .22em muted。
  const cardEyebrow = (en, zh) => (
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 16 }}>
      <span style={{ fontFamily: CORM, fontStyle: 'italic', fontWeight: 600, fontSize: 24, letterSpacing: '.04em', color: t.goldSoft }}>{en}</span>
      <span style={{ fontFamily: SERIF, fontSize: 18, letterSpacing: '.22em', color: t.inkFaint, whiteSpace: 'nowrap' }}>{zh}</span>
    </div>
  );

  // .a4 是 flex column（work.html CSS）。inline 覆寫成 D2 bento：padding 64 72 56、gap 22；
  // 可成長 row 用 flex 比例撐滿 1920，配方卡 flex:'0 0 auto' 貼合內容。各卡 overflow:hidden（批二精簡）。
  return (
    <div className="a4" style={{ background: t.cardPageBg, color: t.ink, padding: '64px 72px 56px', justifyContent: 'flex-start', gap: 22 }}>

      {/* 1. HEADER — logo + No.編號（Space Mono 24 + 42px 金色短線 + 日期），通欄固定高 */}
      <div className="layer" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', flex: '0 0 auto' }}>
        <img src={t.logo} alt="Phinn-Phang" style={{ height: 58, opacity: .92 }} />
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontFamily: MONO, fontSize: 24, letterSpacing: '.18em', color: t.gold }}>No. {serial}</div>
          <div style={{ width: 42, height: 2, background: t.gold, marginLeft: 'auto', marginTop: 9, marginBottom: 9 }} />
          <div style={{ fontFamily: MONO, fontSize: 14, letterSpacing: '.14em', color: t.inkFaint }}>{work.courseDate || '—'}</div>
        </div>
      </div>

      {/* 2. 第一屏：左欄(標題卡 + 人格卡 上下疊) / 右欄(雷達卡 span2，grid stretch → 與左欄等高) */}
      <div className="layer" style={{ display: 'grid', gridTemplateColumns: '0.92fr 1.08fr', gap: 22, flex: '34 1 0' }}>
        {/* 左欄：兩格垂直堆疊 */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
          {/* 左上 標題卡：香名 96 + 標語 27 */}
          <div style={{ ...card, padding: '32px 34px', flex: '1.2 1 0', display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 20 }}>
            <div style={{ fontFamily: MONO, fontSize: 13, letterSpacing: '.3em', color: t.goldSoft }}>YOUR SCENT</div>
            <div>
              {/* 大標題層：香名 —— D2 96px 理想，自適應降階；長度/語言不固定（wordBreak 接住長英文名） */}
              <h1 style={{ fontFamily: SERIF, fontWeight: 600, fontSize: nameFs, letterSpacing: '.06em', lineHeight: 1.04, color: t.ink, textShadow: t.glow, marginBottom: 0, wordBreak: 'break-word' }}>{nm}</h1>
            </div>
          </div>
          {/* 左下 人格卡：Scent Type + 型人格 + tags（還原卡片框；ptype 空則不印標題避免空殼） */}
          {sp && (
            <div style={{ ...card, padding: '32px 34px', flex: '1 1 0', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
              {cardEyebrow('Scent Type', '香氣人格')}
              {ptype && <div style={{ fontFamily: SERIF, fontWeight: 600, fontSize: 42, letterSpacing: '.08em', color: t.coral, lineHeight: 1.2, margin: '14px 0 22px', whiteSpace: 'nowrap' }}>{ptype}</div>}
              {Array.isArray(sp.keywords) && (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, justifyContent: 'flex-start' }}>
                  {sp.keywords.map((k, i) => (
                    <span key={i} style={{ fontFamily: SERIF, fontSize: 22, letterSpacing: '.16em', color: t.coral, border: `1px solid ${t.chipBorder}`, borderRadius: 3, padding: '8px 18px', lineHeight: 1.3, whiteSpace: 'nowrap' }}>{k}</span>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>
        {/* 右欄 雷達卡（grid 預設 align stretch → 撐到與左欄兩格疊起來等高） */}
        <div style={{ ...card, padding: '32px 34px', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
          {cardEyebrow('Impression', '香氣印象')}
          {/* 雷達放大填滿右格：R 加大讓雷達佔更多 viewBox；S/cx/cy 留邊讓維度標籤（R+30）不被裁切。
              全靠 prop 傳值，Radar 本體未改；ScreenView 不傳 → default 不受影響。 */}
          <Radar dims={dims} t={t} max={420} S={400} cx={200} cy={198} R={112} labelFs={21} valFs={23} />
        </div>
      </div>

      {/* 4. 旅程卡 調香手記 — 通欄（可成長；批一完整 aiDescription 可能爆格→裁切，批二精簡） */}
      <div className="layer" style={{ ...card, padding: '32px 34px', flex: '16 1 0', display: 'flex', flexDirection: 'column' }}>
        {cardEyebrow('Journey', '調香手記')}
        <p style={{ fontFamily: SERIF, fontSize: 28, fontWeight: 300, color: t.inkSoft, lineHeight: 1.85, letterSpacing: '.05em' }}>{note}</p>
      </div>

      {/* 5. Persona + Emotion 半卡並排（可成長；persona 標題 rose-bright、emotion 標題 ink） */}
      <div className="layer" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 22, flex: '24 1 0' }}>
        {sp && (
          <div style={{ ...card, padding: '32px 34px', display: 'flex', flexDirection: 'column' }}>
            {cardEyebrow('Persona', '香氣性格')}
            <div style={{ fontFamily: SERIF, fontWeight: 600, fontSize: 42, letterSpacing: '.08em', color: t.coral, lineHeight: 1.3, marginBottom: 18 }}>關於香氣性格</div>
            <p style={{ fontFamily: SERIF, fontWeight: 300, fontSize: 28, color: t.inkSoft, lineHeight: 1.8, letterSpacing: '.03em' }}>{personaDesc}</p>
          </div>
        )}
        {ee && (
          <div style={{ ...card, padding: '32px 34px', display: 'flex', flexDirection: 'column' }}>
            {cardEyebrow('Emotion', '情緒陪伴')}
            {ee.mood && <div style={{ fontFamily: SERIF, fontWeight: 600, fontSize: 42, letterSpacing: '.08em', color: t.coral, lineHeight: 1.3, marginBottom: 18 }}>「{ee.mood}」</div>}
            <p style={{ fontFamily: SERIF, fontWeight: 300, fontSize: 28, color: t.inkSoft, lineHeight: 1.8, letterSpacing: '.03em' }}>{emotionDesc}</p>
          </div>
        )}
      </div>

      {/* 6. 配方卡 — 通欄（flex:0 0 auto 貼合內容）。FormulaCols 用新 d2 prop 放大層調/香精名/滴數 */}
      <div className="layer" style={{ ...card, padding: '32px 34px', flex: '0 0 auto', display: 'flex', flexDirection: 'column' }}>
        {cardEyebrow('The Formula', `配方組成 · ${work.base?.name || ''}${work.base?.name ? ' · ' : ''}共 ${total} 滴`)}
        <TriBar layerData={layerData} t={t} h={8} />
        <FormulaCols layerData={layerData} t={t} big d2 />
      </div>

      {/* FOOTER — © line（固定高；批三再改 IG 引導＋版權，本批保留） */}
      <div className="layer" style={{ paddingTop: 6, textAlign: 'center', fontFamily: "'IBM Plex Mono',monospace", fontSize: 14, letterSpacing: '.26em', color: t.inkFaint, flex: '0 0 auto' }}>
        © 2026 Phinn-Phang. All rights reserved.
      </div>
    </div>
  );
}

/* ── export to window ───────────────────────────────────────────────────── */
Object.assign(window, {
  THEMES, deriveWork, makeSerial, computeImpressions, famColor,
  Radar, Label, Chip, PersonaBand, RatioBlock, FormulaCols, TriBar, ThreeCards,
  ScreenView, ExportCard,
});
