// tasting-card.jsx — BeanScriptor professional tasting form

const METHODS = [
  'Espresso',
  'V60',
  'Kalita',
  'Chemex',
  'Origami',
  'Clever',
  'AeroPress',
  'French Press',
  'Moka Pot',
  'Siphon',
  'Cold Brew',
  'Cupping',
  'Ibrik',
];

const CVA_ATTRS = [
  { key: 'fragrance_aroma', label: 'Fragrance / Aroma' },
  { key: 'flavor',          label: 'Flavor' },
  { key: 'aftertaste',      label: 'Aftertaste' },
  { key: 'acidity',         label: 'Acidity' },
  { key: 'body',            label: 'Body' },
  { key: 'balance',         label: 'Balance' },
  { key: 'sweetness',       label: 'Sweetness' },
  { key: 'uniformity',      label: 'Uniformity' },
  { key: 'clean_cup',       label: 'Clean Cup' },
  { key: 'overall',         label: 'Overall' },
];

function cvaGradeInfo(score) {
  if (score >= 90) return { label: 'Outstanding', color: '#1B5E20', bg: 'rgba(76,175,80,0.12)' };
  if (score >= 85) return { label: 'Excellent',   color: PALETTE.sageDeep, bg: 'rgba(124,154,98,0.14)' };
  if (score >= 80) return { label: 'Very Good',   color: '#7A4A2A', bg: 'rgba(184,121,74,0.14)' };
  if (score >= 75) return { label: 'Good',        color: PALETTE.cocoa,    bg: 'rgba(122,74,54,0.10)' };
  if (score >= 70) return { label: 'Fair',        color: PALETTE.inkMuted, bg: 'rgba(36,23,18,0.06)' };
  return                   { label: 'Below Std.', color: '#B71C1C',        bg: 'rgba(183,28,28,0.08)' };
}

function DefectStepper({ label, sublabel, value, onChange }) {
  const btn = (glyph, action) => (
    <button onClick={action} style={{
      width: 30, height: 30, borderRadius: 999,
      background: PALETTE.crema, border: `0.5px solid ${PALETTE.hairline}`,
      fontSize: 18, lineHeight: 1, cursor: 'pointer', color: PALETTE.espresso,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: '-apple-system, system-ui',
    }}>{glyph}</button>
  );
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div>
        <div style={{ fontSize: 13, fontWeight: 600, color: PALETTE.espresso }}>{label}</div>
        <div style={{ fontSize: 11, color: PALETTE.inkMuted, marginTop: 1 }}>
          {sublabel} · −{value} pt{value !== 1 ? 's' : ''}
        </div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        {btn('−', () => onChange(Math.max(0, value - 1)))}
        <span style={{
          fontSize: 18, fontWeight: 700, color: PALETTE.espresso,
          minWidth: 20, textAlign: 'center', fontFeatureSettings: '"tnum"',
        }}>{value}</span>
        {btn('+', () => onChange(Math.min(5, value + 1)))}
      </div>
    </div>
  );
}

const NOTE_CATEGORIES = [
  { key: 'berries',     label: 'Berries',     emoji: '🍓', items: ['Strawberry', 'Raspberry', 'Blueberry', 'Blackcurrant'] },
  { key: 'stoneFruit',  label: 'Stone fruit', emoji: '🍑', items: ['Peach', 'Apricot', 'Plum', 'Cherry'] },
  { key: 'citrus',      label: 'Citrus',      emoji: '🍋', items: ['Lemon', 'Orange', 'Grapefruit', 'Bergamot'] },
  { key: 'tropical',    label: 'Tropical',    emoji: '🥭', items: ['Mango', 'Pineapple', 'Lychee', 'Passion fruit'] },
  { key: 'syrupy',      label: 'Syrupy',      emoji: '🍯', items: ['Honey', 'Maple', 'Caramel', 'Molasses'] },
  { key: 'choco',       label: 'Cocoa',       emoji: '🍫', items: ['Dark chocolate', 'Milk chocolate', 'Cocoa nib', 'Brownie'] },
  { key: 'spice',       label: 'Spice',       emoji: '🌶', items: ['Cinnamon', 'Cardamom', 'Clove', 'Pepper'] },
  { key: 'floral',      label: 'Floral',      emoji: '🌸', items: ['Jasmine', 'Rose', 'Hibiscus', 'Chamomile'] },
];

function NotePicker({ open, onClose, onPick }) {
  const [cat, setCat] = React.useState(NOTE_CATEGORIES[0].key);
  if (!open) return null;
  const active = NOTE_CATEGORIES.find(c => c.key === cat);
  return ReactDOM.createPortal(
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 10000,
      background: 'rgba(36,23,18,0.45)', backdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'flex-end',
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: '100%',
        background: PALETTE.cream,
        borderTopLeftRadius: 28, borderTopRightRadius: 28,
        padding: '14px 16px 28px',
        boxShadow: '0 -10px 40px rgba(36,23,18,0.25)',
      }}>
        <div style={{ width: 36, height: 4, background: PALETTE.inkSoft, borderRadius: 4,
                      margin: '0 auto 14px' }} />
        <div style={{ fontSize: 16, fontWeight: 700, color: PALETTE.espresso, marginBottom: 12 }}>
          Add tasting note
        </div>
        {/* category tabs */}
        <div style={{ display: 'flex', gap: 6, overflowX: 'auto', paddingBottom: 12, scrollbarWidth: 'none' }}>
          {NOTE_CATEGORIES.map((c) => (
            <Chip key={c.key} active={c.key === cat} icon={c.emoji} onClick={() => setCat(c.key)}>
              {c.label}
            </Chip>
          ))}
        </div>
        {/* items grid */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
          {active.items.map((it) => (
            <button key={it} onClick={() => { onPick(`${active.emoji} ${it}`); onClose(); }} style={{
              padding: '14px 14px',
              borderRadius: 16,
              border: `0.5px solid ${PALETTE.hairline}`,
              background: PALETTE.paper,
              fontSize: 14, fontWeight: 600, color: PALETTE.espresso,
              textAlign: 'left', cursor: 'pointer',
              fontFamily: '-apple-system, system-ui',
            }}>
              <span style={{ fontSize: 18, marginRight: 8 }}>{active.emoji}</span>{it}
            </button>
          ))}
        </div>
      </div>
    </div>,
    document.body
  );
}

function HotColdNotes({ icon, label, hot, cold, onAddHot, onAddCold, onRemoveHot, onRemoveCold }) {
  const Bucket = ({ tone, notes, onAdd, onRemove }) => (
    <div style={{
      flex: 1, padding: 12,
      background: tone === 'hot'
        ? 'linear-gradient(180deg, rgba(232,138,89,0.10), rgba(255,252,246,0.7))'
        : 'linear-gradient(180deg, rgba(89,154,184,0.10), rgba(255,252,246,0.7))',
      border: `0.5px solid ${PALETTE.hairline}`,
      borderRadius: 16,
      minHeight: 92,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8,
                    color: tone === 'hot' ? '#A85626' : '#3A6E89',
                    fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase' }}>
        {tone === 'hot' ? Icon.flame(12) : Icon.snow(12)}
        {tone === 'hot' ? 'Hot' : 'Cold'}
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
        {notes.map((n, i) => (
          <button key={i} onClick={() => onRemove(i)} style={{
            padding: '5px 9px', borderRadius: 999,
            background: PALETTE.paper,
            border: `0.5px solid ${PALETTE.hairline}`,
            fontSize: 12, fontWeight: 500, color: PALETTE.espresso, cursor: 'pointer',
            fontFamily: '-apple-system, system-ui',
          }}>{n}</button>
        ))}
        <button onClick={onAdd} style={{
          padding: '5px 10px', borderRadius: 999,
          background: 'transparent',
          border: `1px dashed ${PALETTE.inkSoft}`,
          fontSize: 12, color: PALETTE.inkMuted, cursor: 'pointer', fontWeight: 500,
          display: 'inline-flex', alignItems: 'center', gap: 4,
          fontFamily: '-apple-system, system-ui',
        }}>+ Add</button>
      </div>
    </div>
  );
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '0 4px 8px' }}>
        <span style={{ color: PALETTE.coffee }}>{icon}</span>
        <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1.4, textTransform: 'uppercase',
                      color: PALETTE.inkMuted }}>{label}</div>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <Bucket tone="hot" notes={hot} onAdd={onAddHot} onRemove={onRemoveHot} />
        <Bucket tone="cold" notes={cold} onAdd={onAddCold} onRemove={onRemoveCold} />
      </div>
    </div>
  );
}

function MethodSelect({ value, onChange }) {
  const [open, setOpen] = React.useState(false);
  const [pos, setPos]   = React.useState({ top: 0, left: 0, width: 180 });
  const btnRef = React.useRef(null);

  const toggle = () => {
    if (btnRef.current) {
      const shell = btnRef.current.parentElement?.parentElement ?? btnRef.current;
      const r = shell.getBoundingClientRect();
      setPos({ top: r.bottom + 6, left: r.left, width: Math.max(r.width, 180) });
    }
    setOpen(o => !o);
  };

  // Close when the page scrolls — pos is stale after any scroll
  React.useEffect(() => {
    if (!open) return;
    const close = () => setOpen(false);
    window.addEventListener('scroll', close, true);
    return () => window.removeEventListener('scroll', close, true);
  }, [open]);

  return (
    <FieldShell label="Brew method" span={2}>
      <button ref={btnRef} onClick={toggle} style={{
        background: 'transparent', border: 'none', outline: 'none', padding: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        width: '100%', fontSize: 16, fontWeight: 600, color: PALETTE.espresso,
        cursor: 'pointer', fontFamily: '-apple-system, system-ui',
      }}>
        <span>{value}</span>
        <span style={{ color: PALETTE.inkMuted, transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
                       transition: 'transform 150ms', display: 'inline-flex' }}>{Icon.chevron(16)}</span>
      </button>
      {open && ReactDOM.createPortal(
        <>
          {/* transparent backdrop — closes menu on outside click */}
          <div onClick={() => setOpen(false)}
               style={{ position: 'fixed', inset: 0, zIndex: 9998 }} />
          <div style={{
            position: 'fixed',
            top: pos.top, left: pos.left, width: pos.width,
            background: PALETTE.paper, borderRadius: 14,
            border: `0.5px solid ${PALETTE.hairline}`,
            boxShadow: '0 12px 32px rgba(36,23,18,0.20)',
            padding: 6, zIndex: 9999,
            maxHeight: 260, overflowY: 'auto',
          }}>
            {METHODS.map((m) => (
              <div key={m} onClick={() => { onChange(m); setOpen(false); }} style={{
                padding: '8px 12px', borderRadius: 10,
                fontSize: 14, fontWeight: 500, color: PALETTE.espresso,
                cursor: 'pointer',
                background: m === value ? PALETTE.crema : 'transparent',
              }}>{m}</div>
            ))}
          </div>
        </>,
        document.body
      )}
    </FieldShell>
  );
}

function TastingCard({ onBack, onSave }) {
  const [coffeeName, setCoffeeName] = React.useState('Gesha · Lot 47');
  const [roaster, setRoaster] = React.useState('April Coffee');
  const [altitude, setAltitude] = React.useState('1850');
  const [dose, setDose] = React.useState('18.0');
  const [yield_, setYield] = React.useState('300');
  const [grind, setGrind] = React.useState('24 clicks');
  const [temp, setTemp] = React.useState('94');
  const [tempUnit, setTempUnit] = React.useState('°C');
  const [time, setTime] = React.useState('3:15');
  const [tds, setTds] = React.useState('1.35');
  const [method, setMethod] = React.useState('V60');

  const [flavors, setFlavors] = React.useState(['fruity', 'floral', 'sweet']);
  const [acidity, setAcidity] = React.useState(7);
  const [body, setBody] = React.useState(5);
  const [balance, setBalance] = React.useState(8);
  const [sweetness, setSweetness] = React.useState(7);

  const [aromaHot, setAromaHot] = React.useState(['🌸 Jasmine', '🍑 Peach']);
  const [aromaCold, setAromaCold] = React.useState(['🍯 Honey']);
  const [tasteHot, setTasteHot] = React.useState(['🍋 Bergamot', '🍑 Apricot']);
  const [tasteCold, setTasteCold] = React.useState(['🍓 Strawberry', '🍯 Maple']);
  const [obs, setObs] = React.useState('Rinsed paper at 96°C. 50g bloom × 30s, then 4 pulses to 300g. Drawdown 2:50.');

  const [cvaEnabled, setCvaEnabled] = React.useState(false);
  const [cvaScores, setCvaScores] = React.useState({
    fragrance_aroma: 8.0, flavor: 8.0, aftertaste: 8.0,
    acidity: 8.0, body: 8.0, balance: 8.0, sweetness: 8.0,
    uniformity: 8.0, clean_cup: 8.0, overall: 8.0,
  });
  const [cvaDefects, setCvaDefects] = React.useState({ taint: 0, fault: 0 });

  const [pickerCtx, setPickerCtx] = React.useState(null);

  const cvaTotal = React.useMemo(() => {
    const sum = Object.values(cvaScores).reduce((a, v) => a + v, 0);
    return Math.max(0, sum - cvaDefects.taint - cvaDefects.fault);
  }, [cvaScores, cvaDefects]);

  const handleSave = () => onSave({
    coffee_name:  coffeeName,
    roaster:      roaster      || null,
    brew_method:  method       || null,
    altitude:     altitude     ? parseInt(altitude)      : null,
    dose:         dose         ? parseFloat(dose)        : null,
    yield_g:      yield_       ? parseFloat(yield_)      : null,
    grind:        grind        || null,
    water_temp:   temp         ? parseInt(temp)          : null,
    temp_unit:    tempUnit,
    brew_time:    time         || null,
    tds:          tds          ? parseFloat(tds)         : null,
    flavors,
    acidity:      cvaEnabled ? null : acidity,
    body:         cvaEnabled ? null : body,
    balance:      cvaEnabled ? null : balance,
    sweetness:    cvaEnabled ? null : sweetness,
    aroma_hot:    aromaHot,
    aroma_cold:   aromaCold,
    taste_hot:    tasteHot,
    taste_cold:   tasteCold,
    observations: obs          || null,
    cva_enabled:          cvaEnabled,
    cva_fragrance_aroma:  cvaEnabled ? cvaScores.fragrance_aroma : null,
    cva_flavor:           cvaEnabled ? cvaScores.flavor           : null,
    cva_aftertaste:       cvaEnabled ? cvaScores.aftertaste       : null,
    cva_acidity:          cvaEnabled ? cvaScores.acidity          : null,
    cva_body:             cvaEnabled ? cvaScores.body             : null,
    cva_balance:          cvaEnabled ? cvaScores.balance          : null,
    cva_sweetness:        cvaEnabled ? cvaScores.sweetness        : null,
    cva_uniformity:       cvaEnabled ? cvaScores.uniformity       : null,
    cva_clean_cup:        cvaEnabled ? cvaScores.clean_cup        : null,
    cva_overall:          cvaEnabled ? cvaScores.overall          : null,
    cva_defects_taint:    cvaEnabled ? cvaDefects.taint           : null,
    cva_defects_fault:    cvaEnabled ? cvaDefects.fault           : null,
    cva_total_score:      cvaEnabled ? cvaTotal                   : null,
  });

  const toggleFlavor = (k) => {
    setFlavors(f => f.includes(k) ? f.filter(x => x !== k) : [...f, k]);
  };

  const openPicker = (target) => setPickerCtx(target);
  const handlePick = (note) => {
    if (!pickerCtx) return;
    const map = {
      'aromaHot': [aromaHot, setAromaHot],
      'aromaCold': [aromaCold, setAromaCold],
      'tasteHot': [tasteHot, setTasteHot],
      'tasteCold': [tasteCold, setTasteCold],
    };
    const [arr, setter] = map[pickerCtx];
    setter([...arr, note]);
  };
  const removeFrom = (target, i) => {
    const map = {
      'aromaHot': [aromaHot, setAromaHot],
      'aromaCold': [aromaCold, setAromaCold],
      'tasteHot': [tasteHot, setTasteHot],
      'tasteCold': [tasteCold, setTasteCold],
    };
    const [arr, setter] = map[target];
    setter(arr.filter((_, idx) => idx !== i));
  };

  // Live brew ratio — recomputes whenever dose or yield changes.
  const ratio = React.useMemo(() => {
    const d = parseFloat(dose);
    const y = parseFloat(yield_);
    if (!d || !y || d <= 0) return null;
    return (y / d).toFixed(2);
  }, [dose, yield_]);
  const ratioLabel = ratio ? `1:${ratio}` : '—';
  const ratioKind =
    !ratio ? 'neutral' :
    parseFloat(ratio) <= 3   ? 'espresso' :
    parseFloat(ratio) <= 8   ? 'concentrated' :
    parseFloat(ratio) <= 14  ? 'short' :
    parseFloat(ratio) <= 18  ? 'classic' :
                               'long';
  const ratioTone = {
    neutral:      { bg: 'rgba(36,23,18,0.06)', fg: PALETTE.inkMuted, lbl: 'enter dose & yield' },
    espresso:     { bg: 'rgba(122,74,54,0.16)', fg: '#5A2F1E',       lbl: 'espresso range' },
    concentrated: { bg: 'rgba(184,121,74,0.18)', fg: '#7A4A2A',      lbl: 'concentrated' },
    short:        { bg: 'rgba(124,154,98,0.16)', fg: '#3F5E2C',      lbl: 'short brew' },
    classic:      { bg: 'rgba(124,154,98,0.22)', fg: '#2E4A1F',      lbl: 'classic filter' },
    long:         { bg: 'rgba(43,124,217,0.14)', fg: '#1F4F8F',      lbl: 'long brew' },
  }[ratioKind];

  return (
    <div style={{
      minHeight: '100%',
      background: `radial-gradient(140% 80% at 50% 0%, ${PALETTE.crema} 0%, ${PALETTE.cream} 50%, ${PALETTE.paper} 100%)`,
      paddingBottom: 80, position: 'relative',
    }}>
      <div style={{ height: 60 }} />

      {/* Top nav */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '4px 16px 12px',
      }}>
        <button onClick={onBack} style={{
          width: 38, height: 38, borderRadius: 999,
          border: `0.5px solid ${PALETTE.hairline}`,
          background: 'rgba(255,252,246,0.7)', backdropFilter: 'blur(10px)',
          color: PALETTE.espresso, cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>{Icon.back(20)}</button>
        <div style={{ fontSize: 13, fontWeight: 600, color: PALETTE.inkMuted, letterSpacing: 0.4 }}>
          Tasting · Draft
        </div>
        <button onClick={handleSave} style={{
          height: 38, padding: '0 16px', borderRadius: 999, border: 'none',
          background: PALETTE.espresso, color: PALETTE.crema,
          fontSize: 13, fontWeight: 700, letterSpacing: 0.2, cursor: 'pointer',
        }}>Save log</button>
      </div>

      {/* Header info */}
      <div style={{ padding: '0 16px 16px' }}>
        <GlassCard padding={14} radius={22}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <TextField label="Coffee name" value={coffeeName} onChange={setCoffeeName} />
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
              <TextField label="Roaster" value={roaster} onChange={setRoaster} />
              <NumField label="Altitude" suffix="masl" mode="int" maxLength={4} value={altitude} onChange={setAltitude} />
            </div>
          </div>
        </GlassCard>
      </div>

      {/* Pro brew section */}
      <SectionLabel style={{ padding: '0 20px 8px' }}>Pro brew</SectionLabel>
      <div style={{ padding: '0 16px 16px' }}>
        <GlassCard padding={12} radius={22}>
          {/* Live ratio readout — auto-updates from Dose & Yield */}
          <div style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            padding: '10px 12px', marginBottom: 10,
            borderRadius: 16, background: ratioTone.bg,
            border: `0.5px solid ${PALETTE.hairline}`,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{
                width: 32, height: 32, borderRadius: 10,
                background: 'rgba(255,252,246,0.7)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                color: ratioTone.fg,
              }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                     strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M3 6h12M3 12h18M3 18h9"/>
                </svg>
              </div>
              <div>
                <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: 1.2,
                              textTransform: 'uppercase', color: PALETTE.inkMuted }}>
                  Brew ratio
                </div>
                <div style={{ fontSize: 11, color: ratioTone.fg, fontWeight: 600, marginTop: 1,
                              textTransform: 'lowercase', fontVariant: 'small-caps', letterSpacing: 0.4 }}>
                  {ratioTone.lbl}
                </div>
              </div>
            </div>
            <div style={{
              fontSize: 22, fontWeight: 700, color: ratioTone.fg,
              fontFeatureSettings: '"tnum"', letterSpacing: -0.5,
            }}>{ratioLabel}</div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
            <NumField label="Dose" suffix="g" maxLength={6} value={dose} onChange={setDose} />
            <NumField label="Yield" suffix="g" maxLength={6} value={yield_} onChange={setYield} />
            {/* Grind is free text by design — "24 clicks", "fine", grinder model etc. */}
            <TextField label="Grind" value={grind} onChange={setGrind} />
            <FieldShell label="Water temp" suffix={tempUnit}>
              <input type="text" inputMode="numeric" maxLength={3} value={temp}
                     onChange={(e) => setTemp(sanitizeNumeric(e.target.value, 'int'))}
                     style={{ background: 'transparent', border: 'none', outline: 'none',
                              fontSize: 18, fontWeight: 600, color: PALETTE.espresso,
                              fontFeatureSettings: '"tnum"', width: 32, padding: 0,
                              fontFamily: '-apple-system, system-ui' }} />
              <button onClick={() => setTempUnit(u => u === '°C' ? '°F' : '°C')} style={{
                marginLeft: 'auto', padding: '2px 7px', borderRadius: 6,
                background: PALETTE.crema, border: 'none',
                fontSize: 10, fontWeight: 700, color: PALETTE.coffee, cursor: 'pointer',
                letterSpacing: 0.4,
              }}>{tempUnit === '°C' ? '→°F' : '→°C'}</button>
            </FieldShell>
            <FieldShell label="Brew time">
              {/* digits + one colon ("3:15"); keeps the default keyboard — numeric keypads have no colon */}
              <input type="text" value={time} maxLength={10}
                     onChange={(e) => {
                       let v = e.target.value.replace(/[^\d:]/g, '');
                       const i = v.indexOf(':');
                       if (i !== -1) v = v.slice(0, i + 1) + v.slice(i + 1).replace(/:/g, '');
                       setTime(v);
                     }}
                     style={{ background: 'transparent', border: 'none', outline: 'none',
                              fontSize: 18, fontWeight: 600, color: PALETTE.espresso,
                              fontFeatureSettings: '"tnum"', width: '100%', padding: 0,
                              fontFamily: '-apple-system, system-ui' }} />
              <span style={{ color: PALETTE.sageDeep, display: 'inline-flex' }}>{Icon.clock(14)}</span>
            </FieldShell>
            <NumField label="TDS" suffix="%" maxLength={5} value={tds} onChange={setTds} />
            <MethodSelect value={method} onChange={setMethod} />
          </div>
        </GlassCard>
      </div>

      {/* Flavor wheel */}
      <SectionLabel kicker="Tap to toggle" style={{ padding: '0 20px 8px' }}>Flavor wheel</SectionLabel>
      <div style={{ padding: '0 16px 16px' }}>
        <GlassCard padding={14} radius={22}>
          <div style={{ display: 'flex', justifyContent: 'center' }}>
            <FlavorWheel active={flavors} onToggle={toggleFlavor} size={290} />
          </div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 10, justifyContent: 'center' }}>
            {flavors.map(k => {
              const f = FLAVORS.find(x => x.key === k);
              return (
                <span key={k} style={{
                  padding: '4px 10px', borderRadius: 999,
                  background: PALETTE.espresso, color: PALETTE.crema,
                  fontSize: 11, fontWeight: 600, letterSpacing: 0.3,
                }}>{f.label}</span>
              );
            })}
            {flavors.length === 0 && (
              <span style={{ fontSize: 12, color: PALETTE.inkSoft }}>none yet — tap a sector</span>
            )}
          </div>
        </GlassCard>
      </div>

      {/* Sensory / CVA toggle */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 20px 8px' }}>
        <SectionLabel>Sensory scales</SectionLabel>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 11, fontWeight: 600, color: PALETTE.inkMuted, letterSpacing: 0.4 }}>SCA CVA</span>
          <div onClick={() => setCvaEnabled(e => !e)} style={{
            width: 44, height: 26, borderRadius: 13,
            background: cvaEnabled ? PALETTE.sageDeep : PALETTE.inkSoft,
            position: 'relative', cursor: 'pointer', transition: 'background 200ms',
            flexShrink: 0,
          }}>
            <div style={{
              position: 'absolute', top: 3, left: cvaEnabled ? 21 : 3,
              width: 20, height: 20, borderRadius: 10,
              background: '#fff',
              boxShadow: '0 1px 3px rgba(0,0,0,0.18)',
              transition: 'left 200ms',
            }} />
          </div>
        </div>
      </div>
      <div style={{ padding: '0 16px 16px' }}>
        {!cvaEnabled ? (
          <GlassCard padding={16} radius={22}>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
              {[
                { label: 'Acidity', val: acidity, set: setAcidity, l: 'Soft', r: 'Bright' },
                { label: 'Body', val: body, set: setBody, l: 'Tea-like', r: 'Syrupy' },
                { label: 'Balance', val: balance, set: setBalance, l: 'Loose', r: 'Resolved' },
                { label: 'Sweetness', val: sweetness, set: setSweetness, l: 'Dry', r: 'Sugary' },
              ].map(s => (
                <div key={s.label}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: PALETTE.espresso }}>{s.label}</div>
                    <div style={{ fontSize: 13, fontWeight: 700, color: PALETTE.coffee, fontFeatureSettings: '"tnum"' }}>
                      {s.val}<span style={{ color: PALETTE.inkSoft, fontWeight: 500 }}> /10</span>
                    </div>
                  </div>
                  <BeanSlider value={s.val} onChange={s.set} min={0} max={10} leftLabel={s.l} rightLabel={s.r} />
                </div>
              ))}
            </div>
          </GlassCard>
        ) : (
          <GlassCard padding={16} radius={22}>
            {/* Score hero */}
            {(() => {
              const g = cvaGradeInfo(cvaTotal);
              return (
                <div style={{
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  padding: '12px 16px', marginBottom: 16,
                  borderRadius: 16, background: g.bg, border: `0.5px solid ${PALETTE.hairline}`,
                }}>
                  <div>
                    <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1.2, textTransform: 'uppercase',
                                  color: PALETTE.inkMuted }}>CVA Total</div>
                    <div style={{ fontSize: 16, fontWeight: 700, color: g.color, marginTop: 2 }}>{g.label}</div>
                  </div>
                  <div style={{ fontSize: 38, fontWeight: 800, color: g.color,
                                fontFeatureSettings: '"tnum"', letterSpacing: -1 }}>
                    {cvaTotal.toFixed(2)}
                  </div>
                </div>
              );
            })()}
            {/* 10 attribute sliders */}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18, marginBottom: 20 }}>
              {CVA_ATTRS.map(({ key, label }) => (
                <div key={key}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: PALETTE.espresso }}>{label}</div>
                    <div style={{ fontSize: 13, fontWeight: 700, color: PALETTE.coffee, fontFeatureSettings: '"tnum"' }}>
                      {cvaScores[key].toFixed(2)}<span style={{ color: PALETTE.inkSoft, fontWeight: 500 }}> /10</span>
                    </div>
                  </div>
                  <BeanSlider
                    value={cvaScores[key]}
                    onChange={(v) => setCvaScores(s => ({ ...s, [key]: v }))}
                    min={6} max={10} step={0.25}
                    ticks={[6, 7, 8, 9, 10]}
                  />
                </div>
              ))}
            </div>
            {/* Defect counters */}
            <div style={{
              borderTop: `0.5px solid ${PALETTE.hairline}`, paddingTop: 16,
              display: 'flex', flexDirection: 'column', gap: 14,
            }}>
              <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1.2, textTransform: 'uppercase',
                            color: PALETTE.inkMuted, marginBottom: 2 }}>Defects</div>
              <DefectStepper
                label="Taint"
                sublabel="-1 pt/cup"
                value={cvaDefects.taint}
                onChange={(v) => setCvaDefects(d => ({ ...d, taint: v }))}
              />
              <DefectStepper
                label="Fault"
                sublabel="-1 pt/cup"
                value={cvaDefects.fault}
                onChange={(v) => setCvaDefects(d => ({ ...d, fault: v }))}
              />
              {(cvaDefects.taint > 0 || cvaDefects.fault > 0) && (
                <div style={{ fontSize: 12, color: '#B71C1C', fontWeight: 600, paddingTop: 2 }}>
                  Penalty: −{cvaDefects.taint + cvaDefects.fault} pts
                </div>
              )}
            </div>
          </GlassCard>
        )}
      </div>

      {/* Hot/Cold descriptors */}
      <SectionLabel style={{ padding: '0 20px 8px' }}>Aromas</SectionLabel>
      <div style={{ padding: '0 16px 14px' }}>
        <HotColdNotes
          icon={Icon.drop(14)} label=""
          hot={aromaHot} cold={aromaCold}
          onAddHot={() => openPicker('aromaHot')}
          onAddCold={() => openPicker('aromaCold')}
          onRemoveHot={(i) => removeFrom('aromaHot', i)}
          onRemoveCold={(i) => removeFrom('aromaCold', i)}
        />
      </div>

      <SectionLabel style={{ padding: '0 20px 8px' }}>Tasting notes</SectionLabel>
      <div style={{ padding: '0 16px 14px' }}>
        <HotColdNotes
          icon={Icon.drop(14)} label=""
          hot={tasteHot} cold={tasteCold}
          onAddHot={() => openPicker('tasteHot')}
          onAddCold={() => openPicker('tasteCold')}
          onRemoveHot={(i) => removeFrom('tasteHot', i)}
          onRemoveCold={(i) => removeFrom('tasteCold', i)}
        />
      </div>

      {/* Notes */}
      <SectionLabel style={{ padding: '0 20px 8px' }}>Brewing observations</SectionLabel>
      <div style={{ padding: '0 16px 28px' }}>
        <div style={{
          background: 'rgba(255,252,246,0.7)',
          border: `0.5px solid ${PALETTE.hairline}`,
          borderRadius: 18, padding: 14,
        }}>
          <textarea value={obs} onChange={(e) => setObs(e.target.value)}
                    rows={4}
                    style={{
                      width: '100%', resize: 'none',
                      background: 'transparent', border: 'none', outline: 'none',
                      fontSize: 14, color: PALETTE.espresso, lineHeight: 1.5,
                      fontFamily: '-apple-system, system-ui',
                    }} />
        </div>
      </div>

      <NotePicker open={!!pickerCtx} onClose={() => setPickerCtx(null)} onPick={handlePick} />
    </div>
  );
}

Object.assign(window, { TastingCard });
