// Scent Alchemist — game logic & main screen
// Globals expected: React, INGREDIENTS, RECIPES, CUSTOMER_TYPES, UPGRADES,
//                   STARTING_STOCK, RESTOCK_BUNDLE, ingredientById, recipeById

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ─────────────────────────────────────────────────────────────
// utilities
// ─────────────────────────────────────────────────────────────
function clamp(v, lo, hi) { return Math.max(lo, Math.min(hi, v)); }
function fmtDrops(n) {
  // Show fractional only when needed (Brass Pipette half-drops); otherwise integer.
  if (n === undefined || n === null) return '0';
  return Math.abs(n - Math.round(n)) < 0.01 ? String(Math.round(n)) : n.toFixed(1);
}
function totalUnits(mix) { return Object.values(mix).reduce((a, b) => a + b, 0); }
function mixturePercents(mix) {
  const t = totalUnits(mix); if (!t) return {};
  const out = {};
  for (const [k, v] of Object.entries(mix)) out[k] = (v / t) * 100;
  return out;
}
function computeAccuracy(mix, recipe) {
  const actualP = mixturePercents(mix);
  const allKeys = new Set([...Object.keys(recipe.ratios), ...Object.keys(actualP)]);
  let dev = 0;
  for (const k of allKeys) dev += Math.abs((actualP[k] || 0) - (recipe.ratios[k] || 0));
  return Math.max(0, Math.round(100 - dev / 2));
}
function tierFor(score) {
  if (score >= 95) return { tier: 'Perfect Blend', payMul: 1.0, tipMul: 1.0, repGain: 3, color: '#2B7A4B', glow: '#7BD49B' };
  if (score >= 85) return { tier: 'Great',         payMul: 1.0, tipMul: 0.6, repGain: 2, color: '#3D6BA8', glow: '#8FB6E0' };
  if (score >= 70) return { tier: 'Acceptable',    payMul: 0.85,tipMul: 0,   repGain: 1, color: '#8A6A2E', glow: '#E8C99D' };
  if (score >= 50) return { tier: 'Weak',          payMul: 0.5, tipMul: 0,   repGain: 0, color: '#A35B3D', glow: '#E8A88A' };
  return                     { tier: 'Failed',     payMul: 0,   tipMul: 0,   repGain: -1, color: '#7A2D2D', glow: '#D49B9B' };
}

// Mix → liquid color (weighted blend)
function mixColor(mix) {
  const t = totalUnits(mix);
  if (!t) return { r: 230, g: 220, b: 200, a: 0 };
  let r = 0, g = 0, b = 0;
  for (const [k, v] of Object.entries(mix)) {
    const ing = ingredientById(k); if (!ing) continue;
    const c = ing.color.replace('#', '');
    const cr = parseInt(c.slice(0, 2), 16), cg = parseInt(c.slice(2, 4), 16), cb = parseInt(c.slice(4, 6), 16);
    r += cr * v; g += cg * v; b += cb * v;
  }
  return { r: r / t, g: g / t, b: b / t, a: clamp(t / 12, 0.1, 1) };
}

// ─────────────────────────────────────────────────────────────
// Customer generation
// ─────────────────────────────────────────────────────────────
function pickCustomer(reputation, day, ownedUpgrades = {}) {
  let pool;
  if (reputation < 5)       pool = ['student', 'student', 'business', 'hasty'];
  else if (reputation < 15) pool = ['student', 'business', 'business', 'hasty', 'influencer'];
  else if (reputation < 30) pool = ['business', 'influencer', 'influencer', 'collector', 'mysterious', 'hasty'];
  else                      pool = ['influencer', 'collector', 'collector', 'mysterious', 'business'];
  // VIP Sofa decoration — boost premium customer appearance rate.
  if (ownedUpgrades.sofa) {
    pool = [...pool, 'influencer', 'collector', 'mysterious'];
  }
  const type = CUSTOMER_TYPES[pool[Math.floor(Math.random() * pool.length)]];

  const eligible = RECIPES.filter(r => !r.locked || reputation >= r.repReq);
  const recipe = eligible[Math.floor(Math.random() * eligible.length)];

  const basePat = 38 + Math.random() * 6;
  const patience = Math.round(basePat * type.patienceMul);
  const pay = Math.round(recipe.base * type.payMul);
  const tip = Math.round(recipe.base * type.tipMul);
  const quote = type.quotes[Math.floor(Math.random() * type.quotes.length)];
  const blindBrief = type.blind ? buildBlindBrief(recipe) : null;

  return {
    id: `c${day}-${Math.random().toString(36).slice(2, 6)}`,
    type, recipe, patience, pay, tip, quote,
    minQuality: type.minQuality,
    blind: !!type.blind,
    blindBrief,
  };
}

// ─────────────────────────────────────────────────────────────
// Persistent default state
// ─────────────────────────────────────────────────────────────
const DEFAULT_STATE = {
  coins: 60,
  reputation: 0,
  day: 1,
  orderNumber: 1,
  stock: { ...STARTING_STOCK },
  ownedUpgrades: {},
  unlockedRecipes: { fresh: true, blue: true, sweet: true, oud: true, wolf: true },
  idleBank: 0,
};

const SAVE_KEY = 'scent-alchemist-save-v1';
function loadGame() {
  try { const s = JSON.parse(localStorage.getItem(SAVE_KEY)); return s ? { ...DEFAULT_STATE, ...s } : { ...DEFAULT_STATE }; }
  catch (e) { return { ...DEFAULT_STATE }; }
}
function saveGame(s) { try { localStorage.setItem(SAVE_KEY, JSON.stringify(s)); } catch (e) {} }

// ─────────────────────────────────────────────────────────────
// HUD bar (top)
// ─────────────────────────────────────────────────────────────
function Hud({ state, lowStock, hardMode, onWarn, onSettings, onMenu }) {
  return (
    <div className="hud">
      {onMenu && (
        <button className="hud-back" title="Main menu" onClick={onMenu} aria-label="Main menu">‹</button>
      )}
      <Pill icon="✦" label={state.coins} hint="coins" tone="coin" />
      <Pill icon="◆" label={state.reputation} hint="rep" tone="rep" />
      <Pill icon="❍" label={`Day ${state.day}${hardMode ? ' · HARD' : ''}`} hint={`#${state.orderNumber}`} tone="day" />
      <button className={`hud-warn ${lowStock ? 'on' : ''}`} title={lowStock ? 'Low stock!' : 'Stock OK'} onClick={onWarn}>
        {lowStock ? '!' : '·'}
      </button>
      <button className="hud-gear" title="Settings" onClick={onSettings} aria-label="Settings">⚙</button>
    </div>
  );
}
function Pill({ icon, label, hint, tone }) {
  return (
    <div className={`pill pill-${tone}`}>
      <span className="pill-ico">{icon}</span>
      <span className="pill-val">{label}</span>
      <span className="pill-hint">{hint}</span>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Customer / order panel
// ─────────────────────────────────────────────────────────────
function CustomerPanel({ customer, timeLeft, totalTime, animState, ownedUpgrades = {} }) {
  if (!customer) {
    return (
      <div className="counter-scene empty">
        <div className="counter-bg"><AntiqueBackdrop /></div>
        <div className="counter-plank" />
        <div className="counter-empty-text">— next customer arriving —</div>
      </div>
    );
  }
  const t = customer.type;
  const pct = clamp(timeLeft / totalTime, 0, 1);
  const danger = pct < 0.33;
  return (
    <div className={`counter-scene anim-${animState}`}>
      {/* Antique apothecary backdrop — painted PNG fills the wall */}
      <div className="counter-bg">
        <AntiqueBackdrop />
      </div>

      {/* Visual decor overlays disabled — backdrop PNG carries the antique theme.
          Decor upgrades remain mechanically active (patience, tips, premium rate, etc.). */}

      {/* Customer body, peeking over the counter */}
      <div className="cust-stage">
        <svg viewBox="0 0 120 120" width="118" height="118" className="cust-figure">
          {/* shoulders/torso */}
          <path d={`M14 120 Q14 76 36 70 L84 70 Q106 76 106 120 Z`} fill={t.shirt} />
          {/* collar / shirt line */}
          <path d={`M48 70 Q60 80 72 70`} stroke="rgba(0,0,0,0.18)" strokeWidth="1.4" fill="none" />
          {/* neck */}
          <rect x="52" y="58" width="16" height="14" rx="3" fill={t.skin} />
          {/* hair back */}
          <ellipse cx="60" cy="36" rx="28" ry="30" fill={t.hair} />
          {/* face */}
          <ellipse cx="60" cy="42" rx="22" ry="24" fill={t.skin} />
          {/* fringe */}
          <path d={`M34 28 Q60 14 86 28 L86 36 Q60 28 34 36 Z`} fill={t.hair} />
          {/* ears */}
          <ellipse cx="38" cy="46" rx="3" ry="5" fill={t.skin} />
          <ellipse cx="82" cy="46" rx="3" ry="5" fill={t.skin} />
          {/* eyes */}
          <ellipse cx="50" cy="46" rx="2" ry={animState==='happy' ? 0.6 : 2.4} fill="#1A1413" />
          <ellipse cx="70" cy="46" rx="2" ry={animState==='happy' ? 0.6 : 2.4} fill="#1A1413" />
          {/* brows — angry tilts inward */}
          {animState === 'angry' ? (
            <>
              <path d="M44 39 L56 42" stroke="#1A1413" strokeWidth="1.8" strokeLinecap="round" />
              <path d="M76 39 L64 42" stroke="#1A1413" strokeWidth="1.8" strokeLinecap="round" />
            </>
          ) : (
            <>
              <path d="M44 40 Q50 38 56 40" stroke="#1A1413" strokeWidth="1.6" strokeLinecap="round" fill="none" />
              <path d="M64 40 Q70 38 76 40" stroke="#1A1413" strokeWidth="1.6" strokeLinecap="round" fill="none" />
            </>
          )}
          {/* mouth — varies by mood */}
          {animState === 'happy' && <path d="M50 56 Q60 64 70 56" stroke="#7A3D3D" strokeWidth="1.8" fill="none" strokeLinecap="round" />}
          {animState === 'sad'   && <path d="M50 58 Q60 52 70 58" stroke="#7A3D3D" strokeWidth="1.8" fill="none" strokeLinecap="round" />}
          {animState === 'angry' && <path d="M50 58 Q60 53 70 58" stroke="#7A3D3D" strokeWidth="1.8" fill="none" strokeLinecap="round" />}
          {(animState === 'idle' || animState === 'enter') &&
            <path d="M52 56 Q60 58 68 56" stroke="#7A3D3D" strokeWidth="1.6" fill="none" strokeLinecap="round" />}
        </svg>

        {/* Speech bubble */}
        <div className="speech">
          <div className="speech-arrow" />
          “{customer.quote}”
        </div>
      </div>

      {/* Counter plank — front edge */}
      <div className="counter-plank">
        <div className="counter-plank-edge" />
      </div>

      {/* Order ticket sits on counter */}
      <div className={`order-ticket ${customer.blind ? 'blind' : ''}`}>
        <div className="ticket-tape" />
        <div className="ticket-meta">
          <span className="cust-type">{t.label}</span>
          <span className="ticket-diff">{'◆'.repeat(customer.recipe.difficulty)}<span className="dim">{'◇'.repeat(4 - customer.recipe.difficulty)}</span></span>
        </div>
        {customer.blind ? (
          <>
            <div className="order-name blind-title">??? <span className="blind-tag">BLIND</span></div>
            <div className="order-brief">"{customer.blindBrief}"</div>
          </>
        ) : (
          <>
            <div className="order-name">{customer.recipe.name}</div>
            <div className="order-tag">{customer.recipe.tagline}</div>
          </>
        )}
        <div className="order-pay">
          <span className="pay-base">✦{customer.pay}</span>
          <span className="pay-plus">+</span>
          <span className="pay-tip">tip ✦{customer.tip}</span>
          <span className="pay-req">≥ {customer.minQuality}%</span>
        </div>
        <PatienceBar pct={pct} danger={danger} />
      </div>
    </div>
  );
}
function PatienceBar({ pct, danger }) {
  return (
    <div className={`pat-bar ${danger ? 'danger' : ''}`}>
      <div className="pat-fill" style={{ width: `${pct * 100}%` }} />
      <div className="pat-ticks">
        {[0.25, 0.5, 0.75].map(t => <div key={t} className="pat-tick" style={{ left: `${t * 100}%` }} />)}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Flask / mixing visualization
// ─────────────────────────────────────────────────────────────
function FlaskView({ mix, target, recipeOpen, lastTap, shake }) {
  const total = totalUnits(mix);
  const c = mixColor(mix);
  const fillCap = 14; // visual cap
  const fillPct = clamp(total / fillCap, 0, 1);
  const fillH = fillPct * 100; // svg height of fill (max 100, sits in y range 100..200)
  const fillY = 200 - fillH;
  const liquidColor = `rgb(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)})`;
  const liquidColorDark = `rgb(${Math.round(c.r * 0.78)}, ${Math.round(c.g * 0.78)}, ${Math.round(c.b * 0.78)})`;

  const percents = mixturePercents(mix);

  return (
    <div className={`flask-wrap ${shake ? 'shake' : ''}`}>
      <svg viewBox="0 0 200 220" width="170" height="200" className="flask-svg" aria-hidden>
        <defs>
          <linearGradient id="glassGrad" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stopColor="#FFFFFF" stopOpacity="0.45" />
            <stop offset="0.5" stopColor="#FFFFFF" stopOpacity="0.05" />
            <stop offset="1" stopColor="#FFFFFF" stopOpacity="0.25" />
          </linearGradient>
          <linearGradient id="liquidGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor={liquidColor} />
            <stop offset="1" stopColor={liquidColorDark} />
          </linearGradient>
          <clipPath id="flaskClip">
            <path d="M75 28 L75 78 L40 188 Q40 200 56 200 L144 200 Q160 200 160 188 L125 78 L125 28 Z" />
          </clipPath>
        </defs>

        {/* cork / stopper */}
        <rect x="78" y="14" width="44" height="16" rx="3" fill="#8B5A3C" stroke="#5A361F" strokeWidth="1.2" />
        <rect x="84" y="6"  width="32" height="12" rx="2" fill="#A37049" stroke="#5A361F" strokeWidth="1.2" />

        {/* glass body */}
        <path d="M75 28 L75 78 L40 188 Q40 200 56 200 L144 200 Q160 200 160 188 L125 78 L125 28 Z"
              fill="#F8F3E7" fillOpacity="0.4" stroke="#7A6A4C" strokeWidth="1.6" />

        {/* single blended liquid, clipped to flask */}
        <g clipPath="url(#flaskClip)">
          {total > 0 && (
            <>
              <rect x="30" y={fillY} width="140" height={fillH + 2} fill="url(#liquidGrad)" />
              {/* meniscus / shimmer line */}
              <ellipse cx="100" cy={fillY + 1} rx="48" ry="2.6" fill="#FFFFFF" opacity="0.35" />
              {/* subtle wave overlay */}
              <path d={`M30 ${fillY + 4} Q60 ${fillY + 1} 100 ${fillY + 4} T170 ${fillY + 4} L170 ${fillY + 14} L30 ${fillY + 14} Z`}
                    fill="#FFFFFF" opacity="0.08" />
            </>
          )}
        </g>

        {/* highlight on glass */}
        <path d="M82 36 L82 78 L52 184" stroke="url(#glassGrad)" strokeWidth="4" fill="none" strokeLinecap="round" />

        {/* measurement ticks — follow the angled glass wall (slope from x=75 at y=78 to x=40 at y=188) */}
        {[0.25, 0.5, 0.75].map(t => {
          const y = 200 - t * 100;
          // left interior wall at this y
          const leftEdge = 75 - ((y - 78) * 35) / 110;
          return (
            <g key={t}>
              <line x1={leftEdge + 2.5} y1={y} x2={leftEdge + 9} y2={y}
                    stroke="#9B8B66" strokeWidth="1" strokeLinecap="round" />
              <text x={leftEdge + 11} y={y + 2.6} fontSize="6" fontFamily="Manrope, sans-serif"
                    fill="#9B8B66" opacity="0.7">{Math.round(t * 100)}</text>
            </g>
          );
        })}

        {/* sparkle particle when adding */}
        {lastTap && (
          <g className="sparkle">
            <circle cx="100" cy={fillY + 4} r="2.6" fill={lastTap.color} />
            <circle cx="92"  cy={fillY + 14} r="1.6" fill={lastTap.color} opacity="0.7" />
            <circle cx="108" cy={fillY + 10} r="1.8" fill={lastTap.color} opacity="0.6" />
          </g>
        )}
      </svg>

      {/* readout */}
      <div className="mix-readout">
        <div className="mix-readout-head">
          <span>current mixture</span>
          <span className="mix-total">{fmtDrops(total)} drops</span>
        </div>
        <div className="mix-rows">
          {INGREDIENTS.filter(i => i.id !== 'bottle').map(ing => {
            const cur = Math.round(percents[ing.id] || 0);
            const tgt = recipeOpen ? (target?.ratios[ing.id] || 0) : null;
            if (cur === 0 && (!tgt || tgt === 0)) return null;
            return (
              <div key={ing.id} className="mix-row">
                <span className="mix-sw" style={{ background: ing.color, borderColor: ing.stroke }} />
                <span className="mix-name">{ing.short}</span>
                <span className="mix-cur">{cur}%</span>
                {tgt !== null && tgt > 0 && (
                  <span className={`mix-tgt ${Math.abs(cur - tgt) <= 3 ? 'good' : ''}`}>/ {tgt}%</span>
                )}
              </div>
            );
          })}
          {total === 0 && <div className="mix-empty">tap an ingredient to start mixing</div>}
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Ingredient bottle buttons
// ─────────────────────────────────────────────────────────────
function IngredientRow({ stock, onTap, bouncing, dim }) {
  // Bottle is the vessel, not an essence — it never appears as a tappable ingredient.
  const essences = INGREDIENTS.filter(i => i.id !== 'bottle');
  return (
    <div className="ing-grid ing-grid-essences">
      {essences.map(ing => {
        const out = stock[ing.id] <= 0;
        const low = stock[ing.id] > 0 && stock[ing.id] <= 3;
        return (
          <button
            key={ing.id}
            className={`ing-btn ${bouncing === ing.id ? 'bounce' : ''} ${out ? 'out' : ''} ${dim ? 'dim' : ''}`}
            onClick={() => !out && onTap(ing.id)}
            disabled={out || dim}
            title={`${ing.name} — ${stock[ing.id]} in stock`}
          >
            <svg viewBox="0 0 40 60" width="32" height="48" className="ing-bottle">
              <rect x="14" y="2" width="12" height="6" rx="1.5" fill="#3D2614" />
              <path d="M11 10 L29 10 L31 18 Q31 22 28 24 L28 52 Q28 56 24 56 L16 56 Q12 56 12 52 L12 24 Q9 22 9 18 Z"
                    fill={ing.color} stroke={ing.stroke} strokeWidth="1.4" />
              <ellipse cx="20" cy="20" rx="6" ry="1.2" fill="#FFFFFF" opacity="0.5" />
              <rect x="14" y="34" width="12" height="12" fill="#F3E8D2" stroke={ing.stroke} strokeWidth="0.8" />
              <text x="20" y="43" fontSize="6" fontFamily="Manrope, sans-serif" textAnchor="middle" fill={ing.stroke} fontWeight="700">{ing.glyph}</text>
            </svg>
            <div className="ing-meta">
              <span className="ing-short">{ing.short}</span>
              <span className={`ing-stock ${out ? 'out' : ''} ${low ? 'low' : ''}`}>×{fmtDrops(stock[ing.id])}</span>
            </div>
          </button>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Antique apothecary backdrop (default shop wall)
// ─────────────────────────────────────────────────────────────
function AntiqueBackdrop() {
  // Painted PNG backdrop — generated externally, placed at assets/backdrop.png.
  // Covers the entire counter-bg area; bottom ~25% (wooden floor) is hidden by counter plank.
  return (
    <img className="bg-cabinet-img"
         src="assets/backdrop.png"
         alt=""
         aria-hidden="true"
         onError={(e) => { e.currentTarget.style.display = 'none'; }} />
  );
}

// Fallback SVG (used if backdrop.png is missing — keeps shop visually intact)
function AntiqueBackdropSVG() {
  const shelfBottles = [
    // shelf 1 (top)
    [{ x: 60, c: '#E89BB4', h: 16, w: 7 }, { x: 73, c: '#F5C242', h: 18, w: 6 }, { x: 86, c: '#5D3A6B', h: 14, w: 8 },
     { x: 100, c: '#8B5A3C', h: 20, w: 6 }, { x: 113, c: '#E8C99D', h: 16, w: 7 }, { x: 127, c: '#A8C5D9', h: 18, w: 6 }],
    // shelf 2 (middle)
    [{ x: 58, c: '#A8C5D9', h: 14, w: 7 }, { x: 71, c: '#8B5A3C', h: 18, w: 6 }, { x: 84, c: '#F5C242', h: 16, w: 8 },
     { x: 98, c: '#E89BB4', h: 20, w: 6 }, { x: 111, c: '#5D3A6B', h: 14, w: 7 }, { x: 125, c: '#E8C99D', h: 18, w: 7 }],
    // shelf 3 (bottom)
    [{ x: 58, c: '#5D3A6B', h: 18, w: 8 }, { x: 73, c: '#E8C99D', h: 14, w: 7 }, { x: 86, c: '#A8C5D9', h: 20, w: 6 },
     { x: 100, c: '#F5C242', h: 14, w: 8 }, { x: 115, c: '#8B5A3C', h: 18, w: 6 }, { x: 128, c: '#E89BB4', h: 16, w: 7 }],
  ];
  const shelfYs = [38, 78, 118]; // top of each shelf in svg space
  return (
    <svg className="bg-cabinet" viewBox="0 0 200 200" preserveAspectRatio="xMidYMid slice">
      <defs>
        <linearGradient id="wallGrad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#C29560" />
          <stop offset="0.6" stopColor="#A57340" />
          <stop offset="1" stopColor="#7A5028" />
        </linearGradient>
        <linearGradient id="wallPanel" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#B0844F" />
          <stop offset="1" stopColor="#7A5028" />
        </linearGradient>
        <linearGradient id="cabFrame" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#5A3318" />
          <stop offset="1" stopColor="#2A1408" />
        </linearGradient>
        <linearGradient id="cabBack" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#3E2410" />
          <stop offset="0.5" stopColor="#52331A" />
          <stop offset="1" stopColor="#341E0C" />
        </linearGradient>
        <linearGradient id="shelfWood" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#7E5328" />
          <stop offset="1" stopColor="#4F3018" />
        </linearGradient>
        <radialGradient id="cabGlow" cx="0.5" cy="0.5" r="0.55">
          <stop offset="0" stopColor="#FFD89B" stopOpacity="0.18"/>
          <stop offset="1" stopColor="#FFD89B" stopOpacity="0"/>
        </radialGradient>
      </defs>

      {/* Wall */}
      <rect x="0" y="0" width="200" height="200" fill="url(#wallGrad)" />

      {/* Wall vertical paneling lines (subtle wood paneling effect) */}
      {[20, 50, 150, 180].map(x => (
        <line key={x} x1={x} y1="0" x2={x} y2="200" stroke="#5A3818" strokeWidth="0.5" opacity="0.35"/>
      ))}

      {/* Crown moulding strip at top */}
      <rect x="0" y="0" width="200" height="10" fill="url(#cabFrame)" />
      <rect x="0" y="10" width="200" height="2" fill="#3E2410" />
      <rect x="0" y="12" width="200" height="1" fill="#7A5028" />

      {/* Wainscot panels along bottom */}
      <rect x="0" y="172" width="200" height="28" fill="url(#wallPanel)" opacity="0.7" />
      <rect x="0" y="170" width="200" height="2" fill="#3E2410" />
      {[26, 60, 94, 140, 174].map(x => (
        <rect key={x} x={x} y="178" width="22" height="18" rx="1.5" fill="none" stroke="#3E2410" strokeWidth="0.6" opacity="0.6"/>
      ))}

      {/* Apothecary cabinet — arched top, centered */}
      {/* Outer frame */}
      <path d="M40 162 L40 50 Q40 18 100 18 Q160 18 160 50 L160 162 Z"
            fill="url(#cabFrame)" />
      {/* Inner panel (back of cabinet) */}
      <path d="M48 156 L48 52 Q48 26 100 26 Q152 26 152 52 L152 156 Z"
            fill="url(#cabBack)" />
      {/* Warm interior glow */}
      <ellipse cx="100" cy="90" rx="56" ry="60" fill="url(#cabGlow)" />

      {/* Shelves (3) */}
      {shelfYs.map(y => (
        <g key={y}>
          <rect x="48" y={y} width="104" height="3" fill="url(#shelfWood)" />
          <rect x="48" y={y + 2.6} width="104" height="0.6" fill="#1B0E04" opacity="0.6" />
        </g>
      ))}

      {/* Bottles on each shelf */}
      {shelfBottles.map((bottles, si) => (
        <g key={si}>
          {bottles.map((b, i) => {
            const y = shelfYs[si];
            const top = y - b.h;
            return (
              <g key={i}>
                {/* cork */}
                <rect x={b.x - b.w/2 + 1} y={top - 3} width={b.w - 2} height="2.4" rx="0.3" fill="#3D2614" />
                {/* neck */}
                <rect x={b.x - b.w/2 + 1.5} y={top - 1} width={b.w - 3} height="2" fill={b.c} stroke="#1B0E04" strokeWidth="0.4" />
                {/* body */}
                <rect x={b.x - b.w/2} y={top + 1} width={b.w} height={b.h - 1} rx="1" fill={b.c}
                      stroke="#1B0E04" strokeWidth="0.5" />
                {/* highlight */}
                <rect x={b.x - b.w/2 + 0.8} y={top + 2.5} width="0.8" height={b.h - 4} fill="#fff" opacity="0.35"/>
                {/* tiny label */}
                <rect x={b.x - b.w/2 + 1.5} y={top + b.h/2} width={b.w - 3} height={Math.min(3, b.h/4)}
                      fill="#F3E8D2" opacity="0.7" />
              </g>
            );
          })}
        </g>
      ))}

      {/* Cabinet top ornamental brass plate */}
      <ellipse cx="100" cy="32" rx="8" ry="4" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.6"/>
      <ellipse cx="100" cy="31" rx="6" ry="2.2" fill="#E8C57A"/>
      <text x="100" y="33.2" textAnchor="middle" fontSize="4" fontFamily="serif" fontWeight="700" fill="#5A3D14">A</text>

      {/* Brass cabinet handles */}
      <line x1="80" y1="160" x2="80" y2="156" stroke="#C89B3C" strokeWidth="1.4" strokeLinecap="round"/>
      <line x1="120" y1="160" x2="120" y2="156" stroke="#C89B3C" strokeWidth="1.4" strokeLinecap="round"/>
      <circle cx="80"  cy="156" r="1.2" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.3"/>
      <circle cx="120" cy="156" r="1.2" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.3"/>

      {/* Framed apothecary label off to the side */}
      <g transform="translate(14 70)">
        <rect x="0" y="0" width="20" height="26" rx="1" fill="#C89B3C" stroke="#3E2410" strokeWidth="0.8"/>
        <rect x="2" y="2" width="16" height="22" fill="#F3E8D2"/>
        <line x1="4" y1="6"  x2="16" y2="6"  stroke="#8E3D52" strokeWidth="0.5"/>
        <line x1="4" y1="10" x2="14" y2="10" stroke="#5A3D14" strokeWidth="0.4"/>
        <line x1="4" y1="13" x2="15" y2="13" stroke="#5A3D14" strokeWidth="0.4"/>
        <line x1="4" y1="16" x2="13" y2="16" stroke="#5A3D14" strokeWidth="0.4"/>
        <line x1="4" y1="19" x2="14" y2="19" stroke="#5A3D14" strokeWidth="0.4"/>
        <line x1="4" y1="22" x2="12" y2="22" stroke="#5A3D14" strokeWidth="0.4"/>
      </g>

      {/* Hanging brass scale on the other side */}
      <g transform="translate(170 60)">
        <line x1="6" y1="0" x2="6" y2="6" stroke="#5A3D14" strokeWidth="0.6"/>
        <line x1="0" y1="6" x2="12" y2="6" stroke="#C89B3C" strokeWidth="0.8"/>
        <line x1="2" y1="6" x2="2" y2="12" stroke="#C89B3C" strokeWidth="0.5"/>
        <line x1="10" y1="6" x2="10" y2="12" stroke="#C89B3C" strokeWidth="0.5"/>
        <ellipse cx="2" cy="13" rx="3" ry="1" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.4"/>
        <ellipse cx="10" cy="13" rx="3" ry="1" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.4"/>
      </g>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Shop decoration overlays
// ─────────────────────────────────────────────────────────────
function NeonSign() {
  // Outlined neon tube with glow + flicker
  return (
    <div className="decor-neon">
      <svg className="decor-neon-svg" viewBox="0 0 120 28">
        <defs>
          <filter id="neonGlow" x="-30%" y="-30%" width="160%" height="160%">
            <feGaussianBlur stdDeviation="1.4" result="blur"/>
            <feMerge>
              <feMergeNode in="blur"/>
              <feMergeNode in="blur"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>
        </defs>
        {/* Tube outline */}
        <text x="60" y="20" textAnchor="middle"
              fontFamily="Cormorant Garamond, serif"
              fontStyle="italic"
              fontWeight="700"
              fontSize="22"
              fill="none"
              stroke="#FF9DD9"
              strokeWidth="0.6"
              filter="url(#neonGlow)">PARFUM</text>
        {/* Inner bright fill */}
        <text x="60" y="20" textAnchor="middle"
              fontFamily="Cormorant Garamond, serif"
              fontStyle="italic"
              fontWeight="700"
              fontSize="22"
              fill="#FFF0F8"
              stroke="#FF66CC"
              strokeWidth="0.3">PARFUM</text>
      </svg>
    </div>
  );
}
function GlassShelf() {
  // Floating display shelf with mini bottles — sits upper-left of the counter scene
  return (
    <svg className="decor-shelf" viewBox="0 0 80 40" aria-hidden>
      <rect x="2" y="22" width="76" height="2" fill="#3d2614" />
      <rect x="2" y="36" width="76" height="2" fill="#3d2614" />
      {/* Upper tier bottles */}
      {[
        { x: 8,  c: '#E89BB4' },
        { x: 20, c: '#F5C242' },
        { x: 32, c: '#5D3A6B' },
        { x: 44, c: '#8B5A3C' },
        { x: 56, c: '#E8C99D' },
        { x: 68, c: '#A8C5D9' },
      ].map((b, i) => (
        <g key={i}>
          <rect x={b.x - 2.5} y={14} width={5} height={8} rx={0.8} fill={b.c} stroke="#3d2614" strokeWidth={0.5} />
          <rect x={b.x - 1.2} y={12.5} width={2.4} height={2} fill="#3d2614" />
        </g>
      ))}
      {/* Lower tier bottles */}
      {[10, 22, 34, 46, 58, 70].map((x, i) => (
        <g key={`l${i}`}>
          <rect x={x - 2.2} y={28} width={4.4} height={8} rx={0.8}
                fill={['#A8C5D9', '#E8C99D', '#8B5A3C', '#5D3A6B', '#F5C242', '#E89BB4'][i]}
                stroke="#3d2614" strokeWidth={0.5} />
          <rect x={x - 1} y={26.8} width={2} height={1.8} fill="#3d2614" />
        </g>
      ))}
    </svg>
  );
}
function VipSofa() {
  // Velvet chesterfield-style sofa with diamond tufting + throw pillows + gold legs
  return (
    <svg className="decor-sofa" viewBox="0 0 100 70" aria-hidden>
      <defs>
        <linearGradient id="velvetGrad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#8B3D62" />
          <stop offset="0.5" stopColor="#6B2F50" />
          <stop offset="1" stopColor="#4A1F38" />
        </linearGradient>
        <linearGradient id="cushionGrad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#9C4670" />
          <stop offset="1" stopColor="#7E3A60" />
        </linearGradient>
      </defs>
      {/* Sofa back with rolled arms */}
      <path d="M4 38 Q4 12 22 12 L78 12 Q96 12 96 38 L96 60 L4 60 Z"
            fill="url(#velvetGrad)" stroke="#3D1A30" strokeWidth="1.2" />
      {/* Rolled arm highlights */}
      <ellipse cx="10" cy="22" rx="6" ry="14" fill="#9C4670" opacity="0.5"/>
      <ellipse cx="90" cy="22" rx="6" ry="14" fill="#9C4670" opacity="0.5"/>
      {/* Diamond tufting on back */}
      {[[22,22],[34,28],[46,22],[58,28],[70,22],[82,28]].map(([cx,cy],i) => (
        <g key={i}>
          <circle cx={cx} cy={cy} r="1.4" fill="#3D1A30" />
          <circle cx={cx} cy={cy} r="0.6" fill="#C89B3C" opacity="0.7"/>
        </g>
      ))}
      {[[28,28],[40,22],[52,28],[64,22],[76,28]].map(([cx,cy],i) => (
        <circle key={i} cx={cx} cy={cy} r="1" fill="#3D1A30" opacity="0.5"/>
      ))}
      {/* Seat cushion */}
      <path d="M14 36 Q14 32 18 32 L82 32 Q86 32 86 36 L86 56 L14 56 Z"
            fill="url(#cushionGrad)" stroke="#3D1A30" strokeWidth="1"/>
      {/* Seat seam */}
      <line x1="50" y1="34" x2="50" y2="56" stroke="#3D1A30" strokeWidth="0.6" opacity="0.6"/>
      {/* Throw pillow left */}
      <g transform="translate(18 30) rotate(-8)">
        <rect x="0" y="0" width="14" height="11" rx="2" fill="#E8C99D" stroke="#3D1A30" strokeWidth="0.6"/>
        <rect x="2" y="2" width="10" height="7" rx="1" fill="#F5DCA2" opacity="0.6"/>
      </g>
      {/* Throw pillow right */}
      <g transform="translate(72 31) rotate(7)">
        <rect x="0" y="0" width="13" height="10" rx="2" fill="#C89B3C" stroke="#3D1A30" strokeWidth="0.6"/>
        <rect x="2" y="2" width="9" height="6" rx="1" fill="#F5DCA2" opacity="0.5"/>
      </g>
      {/* Gold trim along the top */}
      <path d="M4 12 Q4 11 5 11 L95 11 Q96 11 96 12" stroke="#C89B3C" strokeWidth="1.2" fill="none"/>
      <line x1="4" y1="38" x2="96" y2="38" stroke="#C89B3C" strokeWidth="0.6" opacity="0.7"/>
      {/* Brass legs */}
      <rect x="8"  y="60" width="3" height="6" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.4"/>
      <rect x="89" y="60" width="3" height="6" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.4"/>
    </svg>
  );
}
function Register() {
  // Brass cash register with paper receipt curling out of the top
  return (
    <svg className="decor-register" viewBox="0 0 48 44" aria-hidden>
      <defs>
        <linearGradient id="regBody" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#F5DCA2" />
          <stop offset="0.5" stopColor="#D7AB58" />
          <stop offset="1" stopColor="#9C7222" />
        </linearGradient>
        <linearGradient id="regTop" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#E8C57A" />
          <stop offset="1" stopColor="#B5862E" />
        </linearGradient>
      </defs>
      {/* Paper receipt curling up + back */}
      <path d="M22 6 Q26 0 30 4 Q32 6 28 10 L28 16 L22 16 Z"
            fill="#FAF3E3" stroke="#5A3D14" strokeWidth="0.5" />
      <line x1="24" y1="8"  x2="28" y2="8"  stroke="#5A3D14" strokeWidth="0.3"/>
      <line x1="24" y1="11" x2="27" y2="11" stroke="#5A3D14" strokeWidth="0.3"/>
      <line x1="24" y1="14" x2="28" y2="14" stroke="#5A3D14" strokeWidth="0.3"/>

      {/* Top hood */}
      <rect x="6"  y="14" width="36" height="6" rx="1.5" fill="url(#regTop)" stroke="#5A3D14" strokeWidth="0.7"/>

      {/* Display window */}
      <rect x="10" y="8"  width="14" height="8" rx="1" fill="#2A1B14" stroke="#5A3D14" strokeWidth="0.7"/>
      <text x="17" y="14" fontSize="5" fontWeight="800" textAnchor="middle"
            fontFamily="Manrope, sans-serif" fill="#E8C57A">✦</text>

      {/* Main body */}
      <rect x="3"  y="20" width="42" height="20" rx="2" fill="url(#regBody)" stroke="#5A3D14" strokeWidth="1"/>

      {/* Key matrix */}
      <rect x="6"  y="23" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="14" y="23" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="22" y="23" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="30" y="23" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="38" y="23" width="5" height="5" rx="0.6" fill="#C24545"/>
      <rect x="6"  y="30" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="14" y="30" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="22" y="30" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="30" y="30" width="6" height="5" rx="0.6" fill="#3E2410"/>
      <rect x="38" y="30" width="5" height="5" rx="0.6" fill="#5A8A5A"/>

      {/* Drawer line + handle */}
      <line x1="3"  y1="38" x2="45" y2="38" stroke="#5A3D14" strokeWidth="0.8"/>
      <rect x="20" y="37" width="8" height="1.4" rx="0.4" fill="#5A3D14"/>

      {/* Stacked coins beside the register */}
      <ellipse cx="46" cy="42" rx="3" ry="1" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.3"/>
      <ellipse cx="46" cy="40.5" rx="3" ry="1" fill="#E8C57A" stroke="#5A3D14" strokeWidth="0.3"/>
      <ellipse cx="46" cy="39" rx="3" ry="1" fill="#C89B3C" stroke="#5A3D14" strokeWidth="0.3"/>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Floating coin/text rewards
// ─────────────────────────────────────────────────────────────
function Floaters({ items }) {
  return (
    <div className="floaters">
      {items.map(f => (
        <div key={f.id} className={`floater f-${f.kind}`} style={{ left: f.x, top: f.y, color: f.color }}>
          {f.text}
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  computeAccuracy, tierFor, mixColor, mixturePercents, totalUnits,
  pickCustomer, loadGame, saveGame, DEFAULT_STATE,
  Hud, CustomerPanel, FlaskView, IngredientRow, Floaters,
  clamp, fmtDrops,
});
