// Coastal Cruise — soft seafoam + deep navy, breezy serif, wave accents
// One iOS app, full state, persists packing + tab to localStorage.

const C = {
  // soft seafoam → cream gradient body, with deep navy ink
  bg:    '#EAF1EE',
  paper: '#FFFFFF',
  ink:   '#0F2A3F',
  ink2:  '#3D5A6C',
  muted: '#7A8E99',
  hair:  '#D8E2DC',
  // primary water blue; warm sand accent
  sea:   '#3F6A82',
  seaDk: '#234357',
  sand:  '#E8C9A0',
  coral: '#D26E5E',
  green: '#4F8A7A',
  red:   '#B94A3C',
  serif: '"Cormorant Garamond", "Cormorant", "Playfair Display", Georgia, serif',
  sans:  '-apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif',
};

// ── Wave SVG (animated subtle horizontal drift) ────────────────────────
function CoastalWave({ height = 28, color = C.sea, opacity = 0.18, speed = 18 }) {
  const id = React.useId();
  return (
    <svg width="100%" height={height} viewBox="0 0 800 28" preserveAspectRatio="none"
         style={{ display: 'block' }}>
      <defs>
        <path id={id} d="M0 14 Q 100 0 200 14 T 400 14 T 600 14 T 800 14 V28 H0 Z" />
      </defs>
      <use href={`#${id}`} fill={color} fillOpacity={opacity}>
        <animateTransform attributeName="transform" type="translate"
          values="0 0; -200 0; 0 0" dur={`${speed}s`} repeatCount="indefinite"/>
      </use>
      <use href={`#${id}`} fill={color} fillOpacity={opacity * 0.6} y="3">
        <animateTransform attributeName="transform" type="translate"
          values="0 0; 200 0; 0 0" dur={`${speed*1.4}s`} repeatCount="indefinite"/>
      </use>
    </svg>
  );
}

function CoastalCompass({ size = 14, color = C.muted }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
      <circle cx="12" cy="12" r="10" stroke={color} strokeWidth="1.2" />
      <path d="M12 4v3M12 17v3M4 12h3M17 12h3" stroke={color} strokeWidth="1.2" strokeLinecap="round"/>
      <path d="M12 8l3 7-3-2-3 2 3-7z" fill={color} />
    </svg>
  );
}

function CoastalShip({ size = 16, color = C.sea }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
      <path d="M3 16h18l-2 4H5l-2-4z" fill={color}/>
      <rect x="6" y="9" width="12" height="5" fill={color} opacity=".7"/>
      <rect x="9" y="4" width="2" height="5" fill={color}/>
      <path d="M11 4h5l-1 3h-4V4z" fill={color}/>
    </svg>
  );
}

// ── Helpers ────────────────────────────────────────────────────────────
function CoastalChip({ children, color = C.sea, light, style }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '2px 8px', borderRadius: 999,
      fontFamily: C.sans, fontSize: 10.5, fontWeight: 600,
      letterSpacing: 0.4, textTransform: 'uppercase',
      color: light ? color : '#fff',
      background: light ? `${color}1A` : color,
      ...style,
    }}>{children}</span>
  );
}

function CoastalCountdown({ label, dateIso, color }) {
  const days = window.daysUntil(dateIso);
  const text = days < 0 ? 'In progress' : days === 0 ? 'Today' : `${days} days`;
  return (
    <div style={{
      flex: 1, padding: '14px 14px 16px',
      borderRadius: 14, background: '#fff',
      border: `1px solid ${C.hair}`,
      position: 'relative', overflow: 'hidden',
    }}>
      <div style={{ position: 'absolute', top: 0, left: 0, right: 0 }}>
        <CoastalWave height={18} color={color} opacity={0.16} speed={22}/>
      </div>
      <div style={{ paddingTop: 6 }}>
        <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                      letterSpacing: 1.2, textTransform: 'uppercase',
                      color: C.muted, marginBottom: 6 }}>{label}</div>
        <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                      fontSize: 30, fontWeight: 500, lineHeight: 1, color }}>
          {days >= 0 ? days : '·'}
        </div>
        <div style={{ fontFamily: C.sans, fontSize: 11, color: C.ink2,
                      marginTop: 4 }}>{text}</div>
      </div>
    </div>
  );
}

// ── HOME / TODAY ───────────────────────────────────────────────────────
function CoastalToday({ leg }) {
  const T = window.TRIP;
  const cruiseDays = window.daysUntil(T.legs.cruise.start);
  const gradDays   = window.daysUntil(T.legs.grad.start);
  return (
    <div style={{ padding: '4px 18px 24px' }}>
      {/* hero */}
      <div style={{ position: 'relative', marginTop: 4, marginBottom: 22 }}>
        <div style={{ fontFamily: C.sans, fontSize: 11, fontWeight: 600,
                      letterSpacing: 1.6, textTransform: 'uppercase',
                      color: C.sea }}>
          Summer 2026
        </div>
        <div style={{ fontFamily: C.serif, fontWeight: 500, fontSize: 36,
                      lineHeight: 1.05, color: C.ink, marginTop: 4,
                      letterSpacing: -0.3 }}>
          Two weeks at <em style={{ color: C.sea }}>sea</em> &<br/>
          <em style={{ color: C.coral }}>shore</em>.
        </div>
        <div style={{ fontFamily: C.sans, fontSize: 13, color: C.ink2,
                      marginTop: 8, lineHeight: 1.5 }}>
          Logan, Bonich & Baby Kai · May 10 – 23
        </div>
      </div>

      {/* countdown row */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 20 }}>
        <CoastalCountdown label="Cruise sets sail" dateIso={T.legs.cruise.start} color={C.sea}/>
        <CoastalCountdown label="JHU Graduation"  dateIso={T.legs.grad.start} color={C.coral}/>
      </div>

      {/* "What's next" card */}
      <div style={{ background: C.ink, color: '#fff', borderRadius: 16,
                    padding: '18px 18px 20px', position: 'relative',
                    overflow: 'hidden' }}>
        <div style={{ position: 'absolute', top: 0, left: 0, right: 0 }}>
          <CoastalWave color="#fff" opacity={0.08} height={24}/>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between',
                      alignItems: 'flex-start', position: 'relative' }}>
          <div>
            <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                          letterSpacing: 1.4, opacity: 0.6,
                          textTransform: 'uppercase' }}>Setting sail</div>
            <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                          fontSize: 28, marginTop: 4, lineHeight: 1.1 }}>
              Quantum of the Seas
            </div>
            <div style={{ fontFamily: C.sans, fontSize: 12, opacity: 0.7,
                          marginTop: 6 }}>
              4 nights · Catalina + Ensenada<br/>
              Dep. Port of LA · May 11
            </div>
          </div>
          <CoastalShip size={36} color={C.sand}/>
        </div>
        <div style={{ borderTop: '1px solid rgba(255,255,255,0.15)',
                      marginTop: 16, paddingTop: 12,
                      display: 'flex', justifyContent: 'space-between' }}>
          <div>
            <div style={{ fontSize: 9, opacity: 0.55, letterSpacing: 1, textTransform: 'uppercase' }}>Stateroom</div>
            <div style={{ fontFamily: C.serif, fontSize: 16, marginTop: 2 }}>Interior · ZI GTY</div>
          </div>
          <div>
            <div style={{ fontSize: 9, opacity: 0.55, letterSpacing: 1, textTransform: 'uppercase' }}>Reservation</div>
            <div style={{ fontFamily: C.serif, fontSize: 16, marginTop: 2 }}>#366640</div>
          </div>
        </div>
      </div>

      {/* highlights */}
      <div style={{ marginTop: 22 }}>
        <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                      letterSpacing: 1.4, color: C.muted,
                      textTransform: 'uppercase', marginBottom: 10 }}>
          Highlights of the trip
        </div>
        {[
          { icon: '⚓︎', t: 'Catalina Island', d: 'May 12 · 7AM – 6PM' },
          { icon: '✦',  t: 'Ensenada port day', d: 'May 13 · use Costco Visa' },
          { icon: '🎓', t: "Bonich's JHU graduation", d: 'May 18 · Homewood Field' },
          { icon: '✺',  t: 'Family in Williamsburg', d: 'May 19 – 22' },
        ].map((h, i) => (
          <div key={i} style={{
            display: 'flex', alignItems: 'center', gap: 12,
            padding: '12px 0',
            borderTop: i === 0 ? `1px solid ${C.hair}` : 'none',
            borderBottom: `1px solid ${C.hair}`,
          }}>
            <div style={{ width: 32, height: 32, borderRadius: 10,
                          background: `${C.sea}10`, display: 'grid',
                          placeItems: 'center', fontSize: 16,
                          color: C.sea, fontFamily: C.serif }}>{h.icon}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: C.serif, fontSize: 17, fontWeight: 500, color: C.ink }}>
                {h.t}
              </div>
              <div style={{ fontFamily: C.sans, fontSize: 11.5, color: C.muted, marginTop: 1 }}>
                {h.d}
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── TIMELINE ───────────────────────────────────────────────────────────
function CoastalTimeline({ leg, onPickDay }) {
  const T = window.TRIP;
  const days = T.days.filter(d => leg === 'all' || d.leg === leg);
  return (
    <div style={{ padding: '4px 18px 30px' }}>
      <div style={{ position: 'relative', paddingLeft: 22 }}>
        {/* vertical rope */}
        <div style={{ position: 'absolute', left: 8, top: 8, bottom: 8,
                      width: 2, background: `linear-gradient(${C.sea}33, ${C.coral}55)` }}/>
        {days.map((d, i) => {
          const dotColor = d.leg === 'cruise' ? C.sea : C.coral;
          const status = d.status;
          return (
            <button key={d.date}
              onClick={() => onPickDay(T.days.indexOf(d))}
              style={{
                position: 'relative', display: 'block',
                width: '100%', textAlign: 'left',
                padding: '10px 0 10px 16px', marginLeft: -6,
                background: 'transparent', border: 'none',
                cursor: 'pointer', fontFamily: C.sans,
              }}>
              {/* dot */}
              <div style={{
                position: 'absolute', left: 1, top: 18,
                width: 14, height: 14, borderRadius: 14,
                background: '#fff', border: `2px solid ${dotColor}`,
                display: 'grid', placeItems: 'center',
              }}>
                {d.flag && <span style={{ fontSize: 10, color: dotColor }}>★</span>}
              </div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
                <div style={{ fontFamily: C.serif, fontSize: 22, fontStyle: 'italic',
                              color: dotColor, lineHeight: 1, minWidth: 50 }}>
                  {window.formatDate(d.date)}
                </div>
                <div style={{ fontSize: 10, color: C.muted, letterSpacing: 1,
                              textTransform: 'uppercase', fontWeight: 600 }}>
                  {d.dow}
                </div>
                <div style={{ flex: 1 }}/>
                {status === 'paid'   && <CoastalChip color={C.green} light>Paid</CoastalChip>}
                {status === 'book'   && <CoastalChip color={C.coral}>Book now</CoastalChip>}
                {status === 'partial'&& <CoastalChip color={C.sand}>Partial</CoastalChip>}
                {status === 'rest'   && <CoastalChip color={C.sea} light>Rest</CoastalChip>}
                {status === 'family' && <CoastalChip color={C.coral} light>Family</CoastalChip>}
              </div>
              <div style={{ fontFamily: C.serif, fontSize: 18, color: C.ink,
                            marginTop: 4, fontWeight: 500 }}>{d.title}</div>
              <div style={{ fontSize: 12, color: C.ink2, marginTop: 2 }}>{d.sub}</div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── DAY DETAIL SHEET ───────────────────────────────────────────────────
function CoastalDaySheet({ day, onClose }) {
  if (!day) return null;
  const dotColor = day.leg === 'cruise' ? C.sea : C.coral;
  const [allNotes, setAllNotes] = window.tripSync.useShared('notes', {});
  const note = allNotes[day.date] || '';
  const setNote = (v) => setAllNotes(prev => ({ ...prev, [day.date]: v }));
  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 80,
      background: 'rgba(15,42,63,0.4)',
      display: 'flex', alignItems: 'flex-end',
    }} onClick={onClose}>
      <div onClick={(e) => e.stopPropagation()}
           style={{
             background: '#fff', width: '100%', borderRadius: '22px 22px 0 0',
             padding: '8px 0 38px', maxHeight: '80%', overflow: 'auto',
             animation: 'coastalSheet 280ms cubic-bezier(.2,.8,.3,1)',
             position: 'relative',
           }}>
        <div style={{ width: 36, height: 4, borderRadius: 2,
                      background: C.hair, margin: '6px auto 14px' }}/>
        <div style={{ padding: '0 22px' }}>
          <CoastalChip color={dotColor}>{day.leg === 'cruise' ? 'The Cruise' : 'Graduation'}</CoastalChip>
          <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                        fontSize: 32, color: dotColor, marginTop: 8, lineHeight: 1 }}>
            {window.formatDate(day.date, { long: true })}
          </div>
          <div style={{ fontFamily: C.serif, fontSize: 22, color: C.ink,
                        marginTop: 6, fontWeight: 500 }}>{day.title}</div>
          <div style={{ fontFamily: C.sans, fontSize: 13, color: C.ink2,
                        marginTop: 4 }}>{day.sub}</div>

          <div style={{ display: 'flex', gap: 10, marginTop: 16,
                        paddingTop: 14, borderTop: `1px solid ${C.hair}` }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 10, color: C.muted, letterSpacing: 1,
                            textTransform: 'uppercase', fontWeight: 600 }}>Where</div>
              <div style={{ fontFamily: C.serif, fontSize: 16, color: C.ink, marginTop: 2 }}>
                {day.where}
              </div>
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 10, color: C.muted, letterSpacing: 1,
                            textTransform: 'uppercase', fontWeight: 600 }}>Cost</div>
              <div style={{ fontFamily: C.serif, fontSize: 16, color: C.ink, marginTop: 2 }}>
                {day.cost > 0 ? `$${day.cost.toLocaleString()}` : '—'}
              </div>
            </div>
          </div>

          <ul style={{ listStyle: 'none', padding: 0, margin: '18px 0 0' }}>
            {day.details.map((d, i) => (
              <li key={i} style={{
                position: 'relative', paddingLeft: 18,
                fontFamily: C.sans, fontSize: 13.5, color: C.ink2,
                lineHeight: 1.55, marginBottom: 8,
              }}>
                <span style={{ position: 'absolute', left: 0, top: 8,
                               width: 6, height: 6, borderRadius: 3,
                               background: dotColor }}/>
                {d}
              </li>
            ))}
          </ul>

          {/* Notes / journal */}
          <div style={{ marginTop: 22, paddingTop: 16, borderTop: `1px solid ${C.hair}` }}>
            <div style={{ fontSize: 10, color: C.muted, letterSpacing: 1.4,
                          textTransform: 'uppercase', fontWeight: 700, marginBottom: 8 }}>
              Journal · shared
            </div>
            <textarea value={note} onChange={(e) => setNote(e.target.value)}
              placeholder="What happened today… (auto-syncs between phones)"
              style={{
                width: '100%', minHeight: 110, padding: 12, resize: 'vertical',
                fontFamily: C.serif, fontSize: 16, lineHeight: 1.5,
                color: C.ink, background: '#FAF7F2',
                border: `1px solid ${C.hair}`, borderRadius: 12,
                outline: 'none',
              }}/>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── BUDGET ─────────────────────────────────────────────────────────────
function CoastalBudget({ leg }) {
  const T = window.TRIP;
  const showCruise = leg !== 'grad';
  const showGrad   = leg !== 'cruise';
  const totalEst  = (showCruise ? T.legs.cruise.estimated : 0) + (showGrad ? T.legs.grad.estimated : 0);
  const totalPaid = (showCruise ? T.legs.cruise.paid : 0) + (showGrad ? T.legs.grad.paid : 0);
  const variance = totalEst - totalPaid;
  return (
    <div style={{ padding: '4px 18px 30px' }}>
      <div style={{ background: C.ink, color: '#fff', borderRadius: 18,
                    padding: 18, marginBottom: 18, position: 'relative',
                    overflow: 'hidden' }}>
        <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0 }}>
          <CoastalWave color={C.sea} opacity={0.4} height={32}/>
        </div>
        <div style={{ position: 'relative' }}>
          <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                        letterSpacing: 1.4, opacity: 0.6,
                        textTransform: 'uppercase' }}>Total spent</div>
          <div style={{ fontFamily: C.serif, fontSize: 44, marginTop: 4,
                        lineHeight: 1, fontWeight: 500 }}>
            ${totalPaid.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}
          </div>
          <div style={{ fontFamily: C.sans, fontSize: 12, opacity: 0.7, marginTop: 6 }}>
            of ${totalEst.toFixed(2)} estimated · 
            <span style={{ color: variance < 0 ? '#FFB199' : '#A8DDC8', marginLeft: 4 }}>
              {variance < 0 ? '−' : '+'}${Math.abs(variance).toFixed(2)} {variance < 0 ? 'over' : 'remaining'}
            </span>
          </div>
        </div>
      </div>

      {/* by leg */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 20 }}>
        {showCruise && (
          <CoastalLegCard title="The Cruise" est={T.legs.cruise.estimated}
            paid={T.legs.cruise.paid} color={C.sea}/>
        )}
        {showGrad && (
          <CoastalLegCard title="Graduation" est={T.legs.grad.estimated}
            paid={T.legs.grad.paid} color={C.coral}/>
        )}
      </div>

      {/* by category */}
      <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                    letterSpacing: 1.4, color: C.muted,
                    textTransform: 'uppercase', marginBottom: 8 }}>
        By category
      </div>
      <div style={{ background: '#fff', borderRadius: 14,
                    border: `1px solid ${C.hair}`, overflow: 'hidden' }}>
        {T.budget.categories.map((c, i) => {
          const total = (showCruise ? c.cruise : 0) + (showGrad ? c.grad : 0);
          if (total === 0) return null;
          const max = Math.max(...T.budget.categories.map(x => x.cruise + x.grad));
          const pct = total / max;
          return (
            <div key={c.key} style={{
              padding: '12px 14px',
              borderBottom: i < T.budget.categories.length - 1 ? `1px solid ${C.hair}` : 'none',
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between',
                            fontFamily: C.sans, marginBottom: 6 }}>
                <div style={{ fontSize: 13, color: C.ink, fontWeight: 500 }}>{c.label}</div>
                <div style={{ fontSize: 13, color: C.ink2, fontVariantNumeric: 'tabular-nums' }}>
                  ${total.toFixed(0)}
                </div>
              </div>
              <div style={{ height: 4, background: C.hair, borderRadius: 2, overflow: 'hidden' }}>
                <div style={{
                  height: '100%', width: `${pct * 100}%`,
                  background: `linear-gradient(90deg, ${C.sea}, ${C.coral})`,
                }}/>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function CoastalLegCard({ title, est, paid, color }) {
  const v = est - paid;
  return (
    <div style={{ flex: 1, background: '#fff', borderRadius: 14,
                  border: `1px solid ${C.hair}`, padding: '12px 14px 14px',
                  position: 'relative', overflow: 'hidden' }}>
      <div style={{ width: 8, height: 8, borderRadius: 4, background: color,
                    position: 'absolute', top: 14, right: 14 }}/>
      <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                    letterSpacing: 1.2, color: C.muted,
                    textTransform: 'uppercase' }}>{title}</div>
      <div style={{ fontFamily: C.serif, fontSize: 22, color, marginTop: 4,
                    fontWeight: 500, fontStyle: 'italic' }}>
        ${paid.toFixed(0)}
      </div>
      <div style={{ fontFamily: C.sans, fontSize: 11, color: C.muted, marginTop: 2 }}>
        {v >= 0 ? `$${v.toFixed(0)} under` : `$${Math.abs(v).toFixed(0)} over`} est.
      </div>
    </div>
  );
}

// ── PACKING ────────────────────────────────────────────────────────────
function CoastalPacking() {
  const T = window.TRIP;
  const cats = Object.keys(T.packing);
  const [active, setActive] = React.useState(cats[0]);
  const [packed, setPacked] = window.tripSync.useShared('packed', {});
  // Per-category list overrides. Once a category is touched (add/edit/delete),
  // its full list is shadowed here and replaces T.packing[cat] for everyone.
  const [itemsMap, setItemsMap] = window.tripSync.useShared('items', {});
  const [editing, setEditing] = React.useState(null);  // item being edited
  const [editValue, setEditValue] = React.useState('');
  const [adding, setAdding] = React.useState(false);
  const [addValue, setAddValue] = React.useState('');

  const items = (itemsMap && itemsMap[active]) || T.packing[active];
  const done  = items.filter(i => packed[i]).length;

  const writeList = (newList) => {
    setItemsMap(m => ({ ...(m || {}), [active]: newList }));
  };
  const toggle = (item) => setPacked(p => ({ ...p, [item]: !p[item] }));
  const addItem = (name) => {
    const v = (name || '').trim();
    if (!v || items.includes(v)) return;
    writeList([...items, v]);
  };
  const removeItem = (name) => {
    writeList(items.filter(i => i !== name));
    setPacked(p => { const n = { ...p }; delete n[name]; return n; });
  };
  const renameItem = (oldName, newName) => {
    const v = (newName || '').trim();
    if (!v || v === oldName || items.includes(v)) return;
    writeList(items.map(i => (i === oldName ? v : i)));
    setPacked(p => {
      const n = { ...p };
      if (n[oldName] !== undefined) { n[v] = n[oldName]; delete n[oldName]; }
      return n;
    });
  };

  const startEdit = (it) => { setEditing(it); setEditValue(it); };
  const cancelEdit = () => { setEditing(null); setEditValue(''); };
  const saveEdit = () => { if (editing) renameItem(editing, editValue); cancelEdit(); };

  const inputStyle = {
    flex: 1, minWidth: 0, fontFamily: C.sans, fontSize: 14,
    padding: '8px 10px', border: `1px solid ${C.hair}`, borderRadius: 8,
    color: C.ink, background: '#fff', outline: 'none',
  };
  const pillBtn = (color, bg) => ({
    border: 'none', background: bg || 'transparent', color,
    fontFamily: C.sans, fontSize: 12, fontWeight: 700,
    padding: '6px 10px', borderRadius: 6, cursor: 'pointer',
  });

  return (
    <div style={{ padding: '0 0 30px' }}>
      <div style={{ padding: '0 18px 12px' }}>
        <div style={{ display: 'flex', gap: 6, overflow: 'auto', paddingBottom: 4 }}>
          {cats.map(c => (
            <button key={c} onClick={() => setActive(c)} style={{
              background: active === c ? C.ink : '#fff',
              color: active === c ? '#fff' : C.ink2,
              fontFamily: C.sans, fontSize: 12, fontWeight: 600,
              padding: '6px 12px', borderRadius: 999,
              border: `1px solid ${active === c ? C.ink : C.hair}`,
              cursor: 'pointer', whiteSpace: 'nowrap',
            }}>{c}</button>
          ))}
        </div>
      </div>

      <div style={{ padding: '0 18px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between',
                      alignItems: 'baseline', marginBottom: 6 }}>
          <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                        fontSize: 24, color: C.ink, fontWeight: 500 }}>{active}</div>
          <div style={{ fontFamily: C.sans, fontSize: 12, color: C.muted,
                        fontVariantNumeric: 'tabular-nums' }}>
            {done} / {items.length} packed
          </div>
        </div>
        <div style={{ height: 4, background: C.hair, borderRadius: 2,
                      overflow: 'hidden', marginBottom: 14 }}>
          <div style={{ width: `${items.length ? done/items.length*100 : 0}%`,
                        height: '100%', background: C.sea,
                        transition: 'width 250ms' }}/>
        </div>

        <div style={{ background: '#fff', borderRadius: 14,
                      border: `1px solid ${C.hair}`, overflow: 'hidden' }}>
          {items.map((it, i) => {
            const on = !!packed[it];
            const isEditing = editing === it;
            const isLast = i === items.length - 1;
            const rowBorder = isLast && !adding ? 'none' : `1px solid ${C.hair}`;

            if (isEditing) {
              return (
                <div key={it} style={{
                  display: 'flex', alignItems: 'center', gap: 6,
                  padding: '8px 10px', background: C.bg, borderBottom: rowBorder,
                }}>
                  <input autoFocus value={editValue}
                    onChange={(e) => setEditValue(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter') saveEdit();
                      if (e.key === 'Escape') cancelEdit();
                    }}
                    style={inputStyle}/>
                  <button onClick={saveEdit} style={pillBtn('#fff', C.sea)}>Save</button>
                  <button onClick={() => { removeItem(it); cancelEdit(); }}
                    style={pillBtn('#fff', C.red)}>Delete</button>
                  <button onClick={cancelEdit} style={pillBtn(C.muted)}>×</button>
                </div>
              );
            }

            return (
              <div key={it} style={{
                display: 'flex', alignItems: 'stretch',
                borderBottom: rowBorder,
              }}>
                <button onClick={() => toggle(it)} style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  flex: 1, padding: '12px 14px', textAlign: 'left',
                  background: 'transparent', border: 'none', cursor: 'pointer',
                }}>
                  <div style={{
                    width: 20, height: 20, borderRadius: 10,
                    border: `1.5px solid ${on ? C.sea : C.hair}`,
                    background: on ? C.sea : '#fff', flexShrink: 0,
                    display: 'grid', placeItems: 'center',
                  }}>
                    {on && <svg width="11" height="11" viewBox="0 0 11 11"><path d="M2 5.5L4.5 8L9 3" stroke="#fff" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>}
                  </div>
                  <div style={{
                    flex: 1, fontFamily: C.sans, fontSize: 14,
                    color: on ? C.muted : C.ink,
                    textDecoration: on ? 'line-through' : 'none',
                  }}>{it}</div>
                </button>
                <button onClick={() => startEdit(it)}
                  aria-label={`Edit ${it}`}
                  style={{
                    border: 'none', background: 'transparent', cursor: 'pointer',
                    padding: '0 14px', color: C.muted,
                    display: 'flex', alignItems: 'center',
                  }}>
                  <svg width="15" height="15" viewBox="0 0 24 24" fill="none">
                    <path d="M3 17.25V21h3.75l11-11-3.75-3.75-11 11zM20.71 7.04a1 1 0 0 0 0-1.41l-2.34-2.34a1 1 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" fill="currentColor"/>
                  </svg>
                </button>
              </div>
            );
          })}

          {adding ? (
            <div style={{
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '8px 10px', background: C.bg,
              borderTop: items.length ? `1px solid ${C.hair}` : 'none',
            }}>
              <input autoFocus value={addValue}
                placeholder={`Add to ${active}…`}
                onChange={(e) => setAddValue(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') { addItem(addValue); setAddValue(''); }
                  if (e.key === 'Escape') { setAdding(false); setAddValue(''); }
                }}
                style={inputStyle}/>
              <button onClick={() => { addItem(addValue); setAddValue(''); }}
                style={pillBtn('#fff', C.sea)}>Add</button>
              <button onClick={() => { setAdding(false); setAddValue(''); }}
                style={pillBtn(C.muted)}>Done</button>
            </div>
          ) : (
            <button onClick={() => setAdding(true)} style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              width: '100%', padding: '12px 14px', background: 'transparent',
              border: 'none', borderTop: items.length ? `1px solid ${C.hair}` : 'none',
              fontFamily: C.sans, fontSize: 13, fontWeight: 600,
              color: C.sea, cursor: 'pointer',
            }}>
              <span style={{ fontSize: 18, lineHeight: 1, marginTop: -2 }}>+</span>
              Add item
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

// ── MAP ────────────────────────────────────────────────────────────────
// Stops with hand-calibrated pixel positions on north-america.webp (512×512).
// (Using a linear lat/lng projection didn't match the stylized map's
// non-uniform scaling, so each city is pinned by eye to its actual location.)
const COASTAL_STOPS = [
  { id: 'pvu', name: 'Provo',        sub: 'May 10 · home',           px: 194, py: 292, leg: 'both',   anchor: 'right', dx: 10, dy: -10 },
  { id: 'lax', name: 'Los Angeles',  sub: 'May 10–11 · embark',      px: 161, py: 322, leg: 'cruise', anchor: 'left',  dx: -10, dy: -4 },
  { id: 'cat', name: 'Catalina I.',  sub: 'May 12 · port day',       px: 149, py: 334, leg: 'cruise', anchor: 'left',  dx: -10, dy: 18 },
  { id: 'ens', name: 'Ensenada',     sub: 'May 13 · margaritas',     px: 165, py: 344, leg: 'cruise', anchor: 'left',  dx: -10, dy: 38 },
  { id: 'bwi', name: 'Baltimore',    sub: 'May 17–18 · graduation',  px: 354, py: 296, leg: 'grad',   anchor: 'right', dx: 10, dy: -8 },
  { id: 'wms', name: 'Williamsburg', sub: 'May 19–22 · family time', px: 352, py: 312, leg: 'grad',   anchor: 'right', dx: 10, dy: 14 },
];

// Path of travel, in order
const COASTAL_ROUTE = ['pvu','lax','cat','ens','lax','bwi','wms','pvu'];

function CoastalMap({ leg }) {
  const visible = (s) => leg === 'all' || s.leg === leg || s.leg === 'both';
  const stopsById = Object.fromEntries(COASTAL_STOPS.map(s => [s.id, s]));
  const pathPts = COASTAL_ROUTE
    .map(id => stopsById[id])
    .filter(visible)
    .map(s => [s.px, s.py]);

  return (
    <div style={{ padding: '4px 18px 30px' }}>
      <div style={{ background: '#fff', borderRadius: 18,
                    border: `1px solid ${C.hair}`,
                    padding: '14px 14px 18px', position: 'relative',
                    overflow: 'hidden' }}>
        <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                      fontSize: 22, color: C.ink, fontWeight: 500 }}>
          The route
        </div>
        <div style={{ fontFamily: C.sans, fontSize: 12, color: C.muted, marginTop: 2 }}>
          {leg === 'cruise' ? 'Provo → LA → Catalina → Ensenada → home'
           : leg === 'grad' ? 'Provo → Baltimore → Williamsburg → home'
           : 'Coast to coast, with a side of Mexico'}
        </div>

        <svg viewBox="40 80 460 380" style={{ width: '100%', display: 'block', marginTop: 8 }}>
          <defs>
            <filter id="cstSoft" x="-10%" y="-10%" width="120%" height="120%">
              <feGaussianBlur stdDeviation="0.4"/>
            </filter>
          </defs>

          {/* base map image — read src from a hidden <img> so the bundler can inline it */}
          <image href={(document.getElementById('map-img-src') || {}).src || 'north-america.webp'}
                 x="0" y="0" width="512" height="512"
                 opacity="0.55" style={{ mixBlendMode: 'multiply' }}/>

          {/* dashed route */}
          {pathPts.length > 1 && (
            <path d={pathPts.map((p, i) => (i === 0 ? `M${p[0]} ${p[1]}` : `L${p[0]} ${p[1]}`)).join(' ')}
                  fill="none" stroke={C.ink} strokeWidth="1.6"
                  strokeDasharray="3 3" strokeLinecap="round" opacity="0.85"/>
          )}

          {/* stops */}
          {COASTAL_STOPS.filter(visible).map((s) => {
            const x = s.px, y = s.py;
            const c = s.leg === 'cruise' ? C.sea
                    : s.leg === 'grad'   ? C.coral
                    : C.ink;
            const align = s.anchor === 'left' ? 'end' : 'start';
            return (
              <g key={s.id}>
                {/* outer halo */}
                <circle cx={x} cy={y} r="9" fill={c} opacity="0.15"/>
                <circle cx={x} cy={y} r="4.5" fill="#fff" stroke={c} strokeWidth="1.8"/>
                <circle cx={x} cy={y} r="1.6" fill={c}/>
                {/* label */}
                <text x={x + s.dx} y={y + s.dy} textAnchor={align}
                      fontFamily='"Cormorant Garamond", Georgia, serif'
                      fontStyle="italic" fontSize="13" fontWeight="600"
                      fill={C.ink}>
                  {s.name}
                </text>
                <text x={x + s.dx} y={y + s.dy + 10} textAnchor={align}
                      fontFamily='-apple-system, system-ui, sans-serif'
                      fontSize="7.5" fontWeight="600" letterSpacing="0.6"
                      fill={C.muted}>
                  {s.sub.toUpperCase()}
                </text>
              </g>
            );
          })}

          {/* compass rose, top right */}
          <g transform="translate(465, 110)" opacity="0.55">
            <circle r="13" fill="none" stroke={C.ink} strokeWidth="0.6"/>
            <path d="M0 -10 L2 0 L0 10 L-2 0 Z" fill={C.ink}/>
            <path d="M-10 0 L0 -2 L10 0 L0 2 Z" fill={C.ink} opacity="0.5"/>
            <text y="-15" textAnchor="middle" fontFamily="serif" fontSize="6.5"
                  fontStyle="italic" fill={C.ink}>N</text>
          </g>
        </svg>

        {/* legend */}
        <div style={{ display: 'flex', gap: 16, marginTop: 10,
                      fontFamily: C.sans, fontSize: 11, color: C.ink2 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 8, height: 8, borderRadius: 4, background: C.sea }}/>
            Cruise leg
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 8, height: 8, borderRadius: 4, background: C.coral }}/>
            Graduation leg
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 8, height: 8, borderRadius: 4, background: C.ink }}/>
            Home
          </div>
        </div>
      </div>

      {/* travel hacks */}
      <div style={{ marginTop: 18 }}>
        <div style={{ fontFamily: C.sans, fontSize: 10, fontWeight: 700,
                      letterSpacing: 1.4, color: C.muted,
                      textTransform: 'uppercase', marginBottom: 8 }}>
          Tips for the road
        </div>
        {window.TRIP.hacks.map((h, i) => (
          <div key={i} style={{
            display: 'flex', gap: 12, padding: '10px 0',
            borderTop: i === 0 ? `1px solid ${C.hair}` : 'none',
            borderBottom: `1px solid ${C.hair}`,
          }}>
            <div style={{ fontFamily: C.serif, fontSize: 11,
                          fontStyle: 'italic', color: C.coral,
                          minWidth: 50, paddingTop: 1 }}>{h.kicker}</div>
            <div style={{ fontFamily: C.sans, fontSize: 13, color: C.ink2,
                          lineHeight: 1.45 }}>{h.text}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── HEADER + LEG TOGGLE ────────────────────────────────────────────────
function CoastalHeader({ leg, setLeg, showLegToggle = true }) {
  const T = window.TRIP;
  const tabs = [
    { id: 'all', label: 'Full Trip' },
    { id: 'cruise', label: 'Cruise' },
    { id: 'grad', label: 'Grad' },
  ];
  return (
    <div style={{ padding: showLegToggle ? '52px 16px 8px' : '52px 16px 12px',
                  background: C.bg }}>
      <div style={{ display: 'flex', justifyContent: 'space-between',
                    alignItems: 'center', marginBottom: showLegToggle ? 12 : 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <CoastalCompass size={18} color={C.sea}/>
          <div style={{ fontFamily: C.serif, fontStyle: 'italic',
                        fontSize: 18, color: C.ink, fontWeight: 500 }}>
            Singletons at Sea
          </div>
        </div>
        <div style={{ width: 32, height: 32, borderRadius: 16,
                      background: '#fff', border: `1px solid ${C.hair}`,
                      display: 'grid', placeItems: 'center',
                      fontFamily: C.serif, fontWeight: 600,
                      fontSize: 13, color: C.sea }}>L+B</div>
      </div>

      {showLegToggle && (
        <div style={{ display: 'flex', background: '#fff',
                      borderRadius: 999, padding: 3,
                      border: `1px solid ${C.hair}` }}>
          {tabs.map(t => (
            <button key={t.id} onClick={() => setLeg(t.id)} style={{
              flex: 1, padding: '7px 4px',
              background: leg === t.id ? C.ink : 'transparent',
              color: leg === t.id ? '#fff' : C.ink2,
              border: 'none', borderRadius: 999,
              fontFamily: C.sans, fontSize: 12.5, fontWeight: 600,
              cursor: 'pointer', transition: 'all 200ms',
            }}>{t.label}</button>
          ))}
        </div>
      )}
    </div>
  );
}

// ── BOTTOM TAB BAR ─────────────────────────────────────────────────────
function CoastalTabBar({ tab, setTab }) {
  const tabs = [
    { id: 'today',    label: 'Today',    icon: <path d="M4 10l8-6 8 6v9a2 2 0 0 1-2 2h-3v-6h-6v6H6a2 2 0 0 1-2-2v-9z"/> },
    { id: 'timeline', label: 'Trip',     icon: <><circle cx="6" cy="7" r="2"/><circle cx="6" cy="17" r="2"/><path d="M6 9v6"/><path d="M10 7h10M10 17h10"/></> },
    { id: 'budget',   label: 'Budget',   icon: <><circle cx="12" cy="12" r="9"/><path d="M9 9h6M9 12h6M12 6v12"/></> },
    { id: 'pack',     label: 'Pack',     icon: <><path d="M5 7h14v13a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V7z"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"/></> },
    { id: 'map',      label: 'Map',      icon: <><path d="M3 6l6-2 6 2 6-2v14l-6 2-6-2-6 2V6z"/><path d="M9 4v14M15 6v14"/></> },
  ];
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 70,
      paddingTop: 6, paddingBottom: 28,
      background: 'rgba(255,255,255,0.92)',
      backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)',
      borderTop: `0.5px solid ${C.hair}`,
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-around' }}>
        {tabs.map(t => {
          const on = tab === t.id;
          return (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              border: 'none', background: 'transparent', cursor: 'pointer',
              padding: '6px 4px 4px', display: 'flex', flexDirection: 'column',
              alignItems: 'center', gap: 2, fontFamily: C.sans,
              color: on ? C.sea : C.muted,
            }}>
              <svg width="22" height="22" viewBox="0 0 24 24"
                   fill="none" stroke="currentColor" strokeWidth="1.5"
                   strokeLinecap="round" strokeLinejoin="round">
                {t.icon}
              </svg>
              <div style={{ fontSize: 9.5, fontWeight: on ? 700 : 500,
                            letterSpacing: 0.2 }}>{t.label}</div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── ROOT APP ───────────────────────────────────────────────────────────
function CoastalApp() {
  const T = window.TRIP;
  // Tab + leg are local-only (per-device UI state, not synced)
  const [tab, setTab]   = React.useState(() => localStorage.getItem('coastal:tab') || 'today');
  const [leg, setLeg]   = React.useState(() => localStorage.getItem('coastal:leg') || 'all');
  const [openDay, setOpenDay] = React.useState(null);
  React.useEffect(() => { try { localStorage.setItem('coastal:tab', tab); } catch{} }, [tab]);
  React.useEffect(() => { try { localStorage.setItem('coastal:leg', leg); } catch{} }, [leg]);
  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column',
                  background: C.bg, position: 'relative' }}>
      <style>{`
        @keyframes coastalSheet { from { transform: translateY(100%); } to { transform: translateY(0); } }
      `}</style>
      <CoastalHeader leg={leg} setLeg={setLeg}
        showLegToggle={tab !== 'today' && tab !== 'pack'}/>
      <div style={{ flex: 1, overflow: 'auto', overflowX: 'hidden', paddingBottom: 76 }}>
        {tab === 'today'    && <CoastalToday    leg={leg}/>}
        {tab === 'timeline' && <CoastalTimeline leg={leg} onPickDay={(i) => setOpenDay(i)}/>}
        {tab === 'budget'   && <CoastalBudget   leg={leg}/>}
        {tab === 'pack'     && <CoastalPacking/>}
        {tab === 'map'      && <CoastalMap      leg={leg}/>}
      </div>
      <CoastalTabBar tab={tab} setTab={setTab}/>
      <CoastalDaySheet day={openDay !== null ? T.days[openDay] : null} onClose={() => setOpenDay(null)}/>
    </div>
  );
}

window.CoastalApp = CoastalApp;
