/* Screens for the MissBetty v1 responsive application. Direction A look-and-feel.
   All screens render responsively using Tailwind breakpoints. */

const { useState, useEffect, useMemo } = React;

// Mobile/desktop split aligned with ResponsiveTodayShell's `lg:` sidebar breakpoint (1024px).
// JS hook is used only for component props that take a number (svg sizes, positions);
// everything else uses Tailwind `lg:` classes.
function useIsMobile(maxPx = 1023) {
  const get = () =>
    typeof window !== 'undefined' && window.matchMedia
      ? window.matchMedia(`(max-width: ${maxPx}px)`).matches
      : false;
  const [mob, setMob] = useState(get);
  useEffect(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    const mq = window.matchMedia(`(max-width: ${maxPx}px)`);
    const cb = (e) => setMob(e.matches);
    mq.addEventListener ? mq.addEventListener('change', cb) : mq.addListener(cb);
    return () => {
      mq.removeEventListener ? mq.removeEventListener('change', cb) : mq.removeListener(cb);
    };
  }, [maxPx]);
  return mob;
}

/* ---------- shared bits ---------- */

const Btn = ({ children, onClick, variant = 'primary', disabled, className = '', size = 'md' }) => {
  const sizes = { sm: 'px-3 py-1.5 text-[13px]', md: 'px-4 py-2.5 text-sm', lg: 'px-5 py-3 text-[15px]' };
  const variants = {
    primary: 'bg-[#3D2B3C] text-[#F8F2E7] hover:bg-[#2c1f2c]',
    secondary: 'bg-white text-[#3D2B3C] border border-[#3D2B3C]/20 hover:bg-[#3D2B3C]/5',
    coral: 'bg-[#F4A88E] text-[#3D2B3C] hover:bg-[#f29472]',
    plum: 'bg-[#3D2B3C] text-[#F8F2E7] hover:bg-[#2c1f2c]',
    ghost: 'text-[#3D2B3C] hover:bg-[#3D2B3C]/8',
  };
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`rounded-full font-medium transition disabled:opacity-40 disabled:cursor-not-allowed ${sizes[size]} ${variants[variant]} ${className}`}
    >
      {children}
    </button>
  );
};

const Eyebrow = ({ children, className = '' }) => (
  <div className={`uppercase tracking-[0.18em] text-[10px] font-semibold text-[#5A4459] ${className}`}>{children}</div>
);

/* ---------- 0. Welcome ---------- */

function WelcomeScreen({ onBegin }) {
  const compact = useIsMobile(640);
  return (
    <div className="min-h-screen flex flex-col items-center justify-center text-center px-4 sm:px-6 py-10 relative">
      <div className="mb-6">
        <MascotLarge size={compact ? 200 : 260} mouth="half-smile" />
      </div>
      <h1 className="ff-serif text-[#3D2B3C] leading-[1.1] text-3xl sm:text-4xl" style={{ fontWeight: 380 }}>
        Hi, I'm <span className="ff-serif" style={{ fontStyle: 'italic', fontWeight: 350 }}>MissBetty</span>.
      </h1>
      <p className="ff-serif text-[#3D2B3C] mt-2 max-w-[28ch] text-lg sm:text-xl" style={{ fontWeight: 380 }}>
        Something hard has happened. Take a breath — I'll lead.
      </p>
      <div className="mt-7 flex flex-col gap-2 w-full max-w-[320px]">
        <Btn onClick={onBegin} size="lg" className="w-full">Show me what's next</Btn>
        <Btn variant="ghost" size="md">Sign in</Btn>
      </div>
      <div className="absolute bottom-4 left-0 right-0 text-[11px] text-[#5A4459]/70">
        Take your time. Nothing is on a clock here.
      </div>
    </div>
  );
}

/* ---------- 1. Intake ---------- */

// v1 spec: branching tree, not a flat form. Order = severity (worst-case first).
// Order: relationship → when → state of death → will → (executor|informal_lead) → inmotion → helpers? → paperwork?
const INTAKE_QUESTIONS = [
  {
    id: 'relationship',
    title: 'Who did you lose?',
    sub: "There's no good way to ask this. I'll keep it brief.",
    kind: 'options',
    // worst-case ordering: child first
    options: ['My child', 'My spouse or partner', 'My parent', 'My sibling', 'My grandparent', 'Another close relative (in-law, aunt or uncle, cousin)', 'A close friend', 'Someone else'],
    mascot: true,
  },
  {
    id: 'when',
    title: 'When did they die?',
    sub: 'Roughly is fine. The exact date can come later.',
    kind: 'date-options',
    options: ['Today or yesterday', 'This week', 'This month', 'Earlier — I\'m catching up'],
  },
  {
    id: 'state_death',
    title: 'Where did the death occur?',
    sub: "Paperwork is state-specific. If they were traveling, use where it actually happened.",
    kind: 'location',
    // first location input — no smart suggestions, no permission prompts. Clean typeahead picker.
    // International toggle swaps US states for ISO countries.
  },
  {
    id: 'will',
    title: 'Is there a will, or anything written down?',
    sub: "A note on a fridge counts. Not knowing is also an answer.",
    kind: 'options',
    // uncertainty-first ordering
    options: ["I don't know yet", 'Nothing that I know of', "Something written, not formal", 'Yes, a formal will'],
  },
  {
    id: 'executor',
    title: 'Do you know who the executor is?',
    sub: 'The person legally responsible. Often, but not always, the coordinator.',
    kind: 'options',
    options: ["Don't know yet", "Yes, but I don't have contact info", "Yes — that's me", 'Yes — someone else in the family'],
    skipIf: (a) => a.will !== 'Yes, a formal will' && a.will !== 'Something written, not formal',
  },
  {
    id: 'informal_lead',
    title: 'Has the family agreed informally on who\'s handling things?',
    sub: "Without a will, it usually falls to whoever steps up. That's a different question than 'executor.'",
    kind: 'options',
    options: ['Not yet', "Yes — that's me", 'Yes — someone else in the family'],
    skipIf: (a) => a.will !== 'Nothing that I know of',
  },
  {
    id: 'inmotion',
    title: "What's already in motion?",
    sub: 'Pick everything that\'s underway — even if you\'re not sure it\'s done right.',
    kind: 'multi',
    exclusiveOption: "No — we're just starting",
    options: [
      'No — we\'re just starting',
      'Funeral home is contacted',
      'Death certificates ordered',
      'Attorney involved',
      'Employer told',
      'Bank told',
    ],
  },
  {
    // Question (i) — religious/cultural traditions. Optional, prominent skip.
    // Spec rule: "Function, Not Identity" — we ask about timing + practices, not belief.
    // Time-sensitive picks (Jewish, Islamic, Hindu, Sikh) elevate funeral-home + travel tasks
    // to Right Now and set tradition_time_sensitive: true on the family seed.
    id: 'tradition',
    title: 'Are there religious or cultural traditions to follow?',
    sub: "Many traditions (Jewish, Islamic, Hindu, Sikh, and others) require burial or cremation within a specific window, or have specific rituals. If that applies, I'll prioritize the right tasks. If not, this question is safe to skip.",
    kind: 'tradition',
  },
  {
    id: 'inner_circle',
    title: "Who's in your inner circle?",
    sub: "These are the people closest to them who already know what's happened. You can invite them later to help, if they want to. Skipping is fine — names can come back to you over the next few days.",
    kind: 'inner_circle',
  },
  {
    id: 'paperwork',
    title: 'How are you with paperwork?',
    sub: 'No wrong answer. This shapes how much I do beside you.',
    kind: 'options',
    mascot: true,
    options: ["I'm overwhelmed", "I don't know yet", "I'd rather have help", "I'll handle it"],
    // inferable when user is confident about will + executor
    skipIf: (a) => (a.will === 'Yes, a formal will' && (a.executor === "Yes — that's me" || a.executor === 'Yes — someone else in the family')),
  },
];

// returns the visible ordered list of questions given current answers
const visibleQuestions = (answers) => INTAKE_QUESTIONS.filter((q) => !q.skipIf || !q.skipIf(answers));

/* US states + DC + 5 territories */
const US_STATES = [
  'Alabama','Alaska','Arizona','Arkansas','California','Colorado','Connecticut','Delaware',
  'District of Columbia','Florida','Georgia','Hawaii','Idaho','Illinois','Indiana','Iowa',
  'Kansas','Kentucky','Louisiana','Maine','Maryland','Massachusetts','Michigan','Minnesota',
  'Mississippi','Missouri','Montana','Nebraska','Nevada','New Hampshire','New Jersey','New Mexico',
  'New York','North Carolina','North Dakota','Ohio','Oklahoma','Oregon','Pennsylvania','Rhode Island',
  'South Carolina','South Dakota','Tennessee','Texas','Utah','Vermont','Virginia','Washington',
  'West Virginia','Wisconsin','Wyoming',
  'Puerto Rico','Guam','U.S. Virgin Islands','American Samoa','Northern Mariana Islands',
];

const COUNTRIES = [
  'Australia','Austria','Belgium','Brazil','Canada','China','Denmark','Egypt','France','Germany',
  'Greece','Hong Kong','India','Indonesia','Ireland','Israel','Italy','Japan','Mexico','Netherlands',
  'New Zealand','Nigeria','Norway','Philippines','Poland','Portugal','Singapore','South Africa',
  'South Korea','Spain','Sweden','Switzerland','Taiwan','Thailand','Turkey','United Arab Emirates',
  'United Kingdom','Vietnam','Other',
];

/* Clean typeahead — no smart suggestions, no permission prompts.
   Beneath the typeahead: a quick-selector grid of every option, filterable by typing. */
function LocationPicker({ value, onChange }) {
  // value: { scope: 'us' | 'intl', place: string }
  const v = value || { scope: 'us', place: '' };
  const [query, setQuery] = useState(v.place || '');
  const list = v.scope === 'us' ? US_STATES : COUNTRIES;
  const matches = query
    ? list.filter((s) => s.toLowerCase().includes(query.toLowerCase()))
    : list;
  const swapScope = () => {
    const next = v.scope === 'us' ? 'intl' : 'us';
    onChange({ scope: next, place: '' });
    setQuery('');
  };
  return (
    <div>
      <div className="relative">
        <input
          type="text"
          value={query}
          onChange={(e) => { setQuery(e.target.value); onChange({ scope: v.scope, place: '' }); }}
          placeholder={v.scope === 'us' ? 'Type a state…' : 'Type a country…'}
          className="w-full rounded-2xl border border-[#3D2B3C]/15 bg-white px-4 py-3 text-[#3D2B3C] text-[14px] focus:outline-none focus:border-[#3D2B3C]"
        />
      </div>
      {(query || !v.place) && (
        <div className="mt-2 rounded-xl border border-[#3D2B3C]/10 bg-white overflow-hidden max-h-[260px] overflow-y-auto">
          {matches.length === 0 ? (
            <div className="px-4 py-3 text-[13px] text-[#5A4459] italic ff-serif">No matches.</div>
          ) : matches.map((s, i) => (
            <button
              key={s}
              onClick={() => { onChange({ scope: v.scope, place: s }); setQuery(s); }}
              className={`w-full text-left px-4 py-2.5 text-[13px] text-[#3D2B3C] hover:bg-[#F8F2E7] ${i !== matches.length - 1 ? 'border-b border-[#3D2B3C]/6' : ''} ${v.place === s ? 'bg-[#F8F2E7]' : ''}`}>
              {s}
            </button>
          ))}
        </div>
      )}
      {v.place && !query && (
        <div className="mt-2 rounded-xl bg-[#3D2B3C] text-[#F8F2E7] px-4 py-3 text-[14px] flex items-center justify-between">
          <span>{v.place}</span>
          <button onClick={() => { onChange({ scope: v.scope, place: '' }); setQuery(''); }} className="text-[#F8F2E7]/70 text-[12px] hover:text-[#F8F2E7]">change</button>
        </div>
      )}
      <button onClick={swapScope} className="text-[12px] text-[#5A4459] hover:text-[#3D2B3C] mt-3 underline decoration-dotted underline-offset-2">
        {v.scope === 'us' ? 'Outside the US?' : '← Back to US states'}
      </button>
      {v.scope === 'intl' && v.place && (
        <div className="mt-3 rounded-xl bg-[#F8F2E7] border border-[#3D2B3C]/10 px-4 py-3 text-[12px] text-[#5A4459] leading-relaxed">
          <span className="ff-serif italic text-[#3D2B3C]">A note for international:</span> the workflow is different abroad. I'll surface the embassy step (Consular Report of Death, DS-2060) and what we have so far — for the rest, the US embassy in {v.place} is the authoritative source. I'll be honest about what I don't know.
        </div>
      )}
    </div>
  );
}

function ResidenceSelector({ answers, value, onChange }) {
  // value shape: { same: bool, place: string, scope: 'us'|'intl' }
  const sd = answers.state_death || { scope: 'us', place: '' };
  const sdPlace = sd.place || '';
  const v = value || (sdPlace ? { same: true, place: sdPlace, scope: sd.scope } : null);
  const same = v?.same ?? true;
  return (
    <div>
      <button
        onClick={() => onChange({ same: true, place: sdPlace, scope: sd.scope })}
        className={`w-full text-left rounded-2xl border px-4 py-3 mb-2 transition ${
          same
            ? 'border-[#3D2B3C] bg-[#3D2B3C] text-[#F8F2E7]'
            : 'border-[#3D2B3C]/15 bg-white text-[#3D2B3C] hover:border-[#3D2B3C]/40'
        }`}
      >
        <div className="text-[14px]">Same as where they died{sdPlace ? ` — ${sdPlace}` : ''}</div>
        <div className={`text-[12px] mt-0.5 ${same ? 'text-[#F8F2E7]/70' : 'text-[#5A4459]'}`}>Most common.</div>
      </button>
      <div className="text-[11px] uppercase tracking-[.18em] text-[#5A4459] mt-3 mb-2">Or, somewhere else</div>
      <LocationPicker
        value={!same ? { scope: v?.scope || 'us', place: v?.place || '' } : { scope: 'us', place: '' }}
        onChange={(loc) => onChange({ same: false, scope: loc.scope, place: loc.place })}
      />
    </div>
  );
}

/* Inner Circle list-builder — final intake step.
   Per spec: name + relationship-to-deceased only. NO contact info. Skipping is valid.
   Entries seed Contact records with notification_status: known-aware. */
const INNER_CIRCLE_RELATIONS = [
  'Their child',
  'Their spouse or partner',
  'Their parent',
  'Their sibling',
  'Their grandchild',
  'Their grandparent',
  'Another close relative',
  'A close friend',
  'Someone else',
];

function InnerCirclePicker({ value, onChange }) {
  const entries = Array.isArray(value) ? value : [];
  const [draftName, setDraftName] = useState('');
  const [draftRel, setDraftRel] = useState('');
  const [adding, setAdding] = useState(entries.length === 0);

  const commit = () => {
    if (!draftName.trim() || !draftRel) return;
    onChange([...entries, { name: draftName.trim(), relation: draftRel }]);
    setDraftName('');
    setDraftRel('');
    setAdding(false);
  };

  const remove = (i) => onChange(entries.filter((_, idx) => idx !== i));

  return (
    <div>
      {entries.length > 0 && (
        <div className="space-y-1.5 mb-3">
          {entries.map((e, i) => (
            <div key={i} className="rounded-2xl bg-white border border-[#3D2B3C]/15 px-4 py-3 flex items-center gap-3">
              <span className="w-7 h-7 rounded-full bg-[#3D2B3C]/8 text-[#3D2B3C] text-[12px] flex items-center justify-center" style={{ fontWeight: 500 }}>
                {e.name[0]?.toUpperCase()}
              </span>
              <div className="flex-1 min-w-0">
                <div className="text-[14px] text-[#3D2B3C]" style={{ fontWeight: 500 }}>{e.name}</div>
                <div className="text-[11px] text-[#5A4459]">{e.relation}</div>
              </div>
              <button onClick={() => remove(i)} className="text-[#5A4459] hover:text-[#3D2B3C] text-[12px]">remove</button>
            </div>
          ))}
        </div>
      )}

      {adding ? (
        <div className="rounded-2xl bg-white border border-[#3D2B3C]/15 p-4">
          <label className="text-[10px] uppercase tracking-[.18em] text-[#5A4459]">Their name</label>
          <input
            type="text"
            value={draftName}
            onChange={(e) => setDraftName(e.target.value)}
            placeholder="First name is enough"
            className="w-full mt-1.5 rounded-xl border border-[#3D2B3C]/15 bg-white px-3 py-2.5 text-[14px] text-[#3D2B3C] focus:outline-none focus:border-[#3D2B3C]"
          />
          <label className="block text-[10px] uppercase tracking-[.18em] text-[#5A4459] mt-3">Relationship to them</label>
          <select
            value={draftRel}
            onChange={(e) => setDraftRel(e.target.value)}
            className="w-full mt-1.5 rounded-xl border border-[#3D2B3C]/15 bg-white px-3 py-2.5 text-[14px] text-[#3D2B3C] focus:outline-none focus:border-[#3D2B3C]"
          >
            <option value="">Pick one…</option>
            {INNER_CIRCLE_RELATIONS.map((r) => <option key={r} value={r}>{r}</option>)}
          </select>
          <div className="flex items-center gap-2 mt-4">
            <Btn onClick={commit} disabled={!draftName.trim() || !draftRel} size="sm" variant="primary">Add to list</Btn>
            {entries.length > 0 && (
              <Btn onClick={() => { setAdding(false); setDraftName(''); setDraftRel(''); }} size="sm" variant="ghost">Cancel</Btn>
            )}
          </div>
          <div className="text-[11px] text-[#5A4459]/80 mt-3 leading-relaxed">
            Just a name and how they're related. No phone, no email — those come later, only if you want to invite them.
          </div>
        </div>
      ) : (
        <button
          onClick={() => setAdding(true)}
          className="w-full rounded-2xl border border-dashed border-[#3D2B3C]/30 bg-white/40 px-4 py-3 text-[#3D2B3C] hover:border-[#3D2B3C]/60 hover:bg-white transition flex items-center justify-center gap-2 text-[14px]"
        >
          <span className="text-[16px]">+</span> Add a relative
        </button>
      )}

      <div className="text-[11px] text-[#5A4459]/80 mt-3 leading-relaxed text-center">
        {entries.length === 0
          ? 'Skipping is fine — names can come back to you over the next few days.'
          : `${entries.length} ${entries.length === 1 ? 'person' : 'people'} on your inner circle list.`}
      </div>
    </div>
  );
}

/* Tradition picker — question (i).
   Value shape:
     null
     | { share: 'skip' }
     | { share: 'yes', traditionId: string, custom?: string }
   Time-sensitive picks (jewish/islamic/hindu/sikh) drive downstream task prioritization
   via a derived `tradition_time_sensitive` flag computed at intake-complete. */
const TRADITION_OPTIONS = [
  { id: 'jewish',   label: 'Jewish',                    note: 'typically burial within 24–48 hours',  timeSensitive: true },
  { id: 'islamic',  label: 'Islamic',                   note: 'within 24 hours',                       timeSensitive: true },
  { id: 'hindu',    label: 'Hindu',                     note: 'same day or within 24 hours',           timeSensitive: true },
  { id: 'sikh',     label: 'Sikh',                      note: 'within 3 days',                         timeSensitive: true },
  { id: 'catholic', label: 'Catholic / other Christian', note: 'not usually time-constrained',         timeSensitive: false },
  { id: 'buddhist', label: 'Buddhist',                  note: 'varies',                                timeSensitive: false },
  { id: 'other',    label: 'Another tradition',         note: 'tell me a bit',                         timeSensitive: null, custom: true },
  { id: 'unsure',   label: 'Not sure yet — let me come back to this',                                  timeSensitive: null },
];

function TraditionPicker({ value, onChange, onAutoAdvance }) {
  const v = value || null;
  const share = v?.share || null;
  const traditionId = v?.share === 'yes' ? v.traditionId : null;
  const custom = v?.share === 'yes' ? (v.custom || '') : '';
  const selected = TRADITION_OPTIONS.find((o) => o.id === traditionId);

  if (!share) {
    return (
      <div className="grid grid-cols-1 gap-2">
        <button
          onClick={() => onChange({ share: 'yes', traditionId: null })}
          className="text-left rounded-2xl border border-[#3D2B3C]/15 bg-white hover:border-[#3D2B3C]/40 text-[#3D2B3C] px-4 py-3 transition"
        >
          <div className="text-[14px]" style={{ fontWeight: 500 }}>Yes — let me share</div>
          <div className="text-[12px] text-[#5A4459] mt-0.5">I'll show options with typical timeframes.</div>
        </button>
        <button
          onClick={() => { onChange({ share: 'skip' }); onAutoAdvance && onAutoAdvance(); }}
          className="text-left rounded-2xl border border-[#3D2B3C]/15 bg-white hover:border-[#3D2B3C]/40 text-[#3D2B3C] px-4 py-3 transition"
        >
          <div className="text-[14px]" style={{ fontWeight: 500 }}>No / not sure / skip</div>
          <div className="text-[12px] text-[#5A4459] mt-0.5">Totally fine — we'll keep going.</div>
        </button>
      </div>
    );
  }

  return (
    <div>
      <div className="grid grid-cols-1 gap-2">
        {TRADITION_OPTIONS.map((opt) => {
          const sel = traditionId === opt.id;
          return (
            <button
              key={opt.id}
              onClick={() => onChange({ share: 'yes', traditionId: opt.id, custom: opt.custom ? custom : undefined })}
              className={`text-left rounded-2xl border px-4 py-3 transition ${
                sel
                  ? 'border-[#3D2B3C] bg-[#3D2B3C] text-[#F8F2E7]'
                  : 'border-[#3D2B3C]/15 bg-white hover:border-[#3D2B3C]/40 text-[#3D2B3C]'
              }`}
            >
              <div className="text-[14px]" style={{ fontWeight: 500 }}>{opt.label}</div>
              {opt.note && (
                <div className={`text-[12px] mt-0.5 ${sel ? 'text-[#F8F2E7]/75' : 'text-[#5A4459]'}`}>
                  {opt.note}
                </div>
              )}
            </button>
          );
        })}
      </div>

      {selected?.custom && (
        <div className="mt-3">
          <label className="text-[10px] uppercase tracking-[.18em] text-[#5A4459]">Tell me a bit (optional)</label>
          <input
            type="text"
            value={custom}
            onChange={(e) => onChange({ share: 'yes', traditionId, custom: e.target.value })}
            placeholder="e.g. Bahá'í — burial within 1 hour's travel, no embalming"
            className="w-full mt-1.5 rounded-xl border border-[#3D2B3C]/15 bg-white px-3 py-2.5 text-[14px] text-[#3D2B3C] focus:outline-none focus:border-[#3D2B3C]"
          />
          <div className="text-[11px] text-[#5A4459]/80 mt-1.5 leading-relaxed">
            If there's a timing window, I'll prioritize accordingly. If not, this just tags relevant tasks.
          </div>
        </div>
      )}

      {selected?.timeSensitive === true && (
        <div className="mt-4 rounded-xl bg-[#F8F2E7] border border-[#3D2B3C]/10 px-4 py-3 text-[12px] text-[#5A4459] leading-relaxed">
          <span className="ff-serif italic text-[#3D2B3C]">Noted.</span> I'll move "find a funeral home that supports {selected.label}" to <span className="ff-serif italic">Right Now</span>, and flag anything travel-blocking as time-critical.
        </div>
      )}

      <button
        onClick={() => onChange(null)}
        className="text-[12px] text-[#5A4459] hover:text-[#3D2B3C] mt-4 underline decoration-dotted underline-offset-2"
      >
        ← actually, skip this question
      </button>
    </div>
  );
}

function IntakeScreen({ index, answers, setAnswer, onNext, onBack, onComplete }) {
  // branching: derive the active question list from current answers
  const visible = visibleQuestions(answers);
  const total = visible.length;
  const safeIdx = Math.min(index, total - 1);
  const q = visible[safeIdx];
  const value = answers[q.id];

  const canAdvance =
    q.kind === 'multi' ? Array.isArray(value) && value.length > 0 :
    q.kind === 'residence' ? !!value :
    q.kind === 'location' ? !!(value && value.place) :
    q.kind === 'inner_circle' ? true : // skipping is valid; an empty list is a real answer
    q.kind === 'tradition' ? (value?.share === 'skip' || (value?.share === 'yes' && !!value?.traditionId)) :
    !!value;

  const handleNext = () => {
    if (safeIdx === total - 1) onComplete();
    else onNext();
  };

  const toggleMulti = (opt) => {
    const cur = Array.isArray(value) ? value : [];
    // exclusive option (e.g. “No — we're just starting”, “No one yet”) clears all other picks
    const exclusive = q.exclusiveOption || "No — we're just starting";
    if (opt === exclusive) {
      setAnswer(q.id, cur.includes(opt) ? [] : [opt]);
      return;
    }
    const without = cur.filter((x) => x !== exclusive);
    setAnswer(q.id, without.includes(opt) ? without.filter((x) => x !== opt) : [...without, opt]);
  };

  return (
    <div className="min-h-screen flex flex-col px-4 sm:px-6 pt-6 max-w-2xl mx-auto">
      {/* progress */}
      <div className="flex items-center gap-3 mb-4">
        <button
          onClick={onBack}
          disabled={index === 0}
          className="text-[#5A4459] disabled:opacity-30 hover:text-[#3D2B3C] text-sm flex items-center gap-1"
        >
          <span>←</span> back
        </button>
        <div className="flex-1 h-[3px] rounded-full bg-[#3D2B3C]/10 overflow-hidden">
          <div
            className="h-full bg-[#3D2B3C] transition-all"
            style={{ width: `${((safeIdx + 1) / total) * 100}%` }}
          />
        </div>
        <div className="ff-mono text-[11px] text-[#5A4459]">
          {String(safeIdx + 1).padStart(2, '0')} / {String(total).padStart(2, '0')}
        </div>
      </div>

      {/* question */}
      <div className="flex-1 flex flex-col">
        <div className="mt-2 mb-1">
          {q.mascot && (
            <div className="mb-3">
              <MascotGlyph size={32} />
            </div>
          )}
          <h2
            className="ff-serif text-2xl sm:text-3xl text-[#3D2B3C] leading-[1.1]"
            style={{ fontWeight: 400 }}
          >
            {q.title}
          </h2>
          <p className="text-[#5A4459] mt-2 text-[14px] leading-relaxed max-w-[42ch]">{q.sub}</p>
        </div>

        {/* answer surface */}
        <div className="mt-5 flex-1">
          {(q.kind === 'options' || q.kind === 'date-options') && (
            <div className="grid grid-cols-1 gap-2">
              {q.options.map((opt) => {
                const sel = value === opt;
                return (
                  <button
                    key={opt}
                    onClick={() => setAnswer(q.id, opt)}
                    className={`text-left rounded-2xl border px-4 py-3 transition ${
                      sel
                        ? 'border-[#3D2B3C] bg-[#3D2B3C] text-[#F8F2E7]'
                        : 'border-[#3D2B3C]/15 bg-white hover:border-[#3D2B3C]/40 text-[#3D2B3C]'
                    }`}
                  >
                    <div className="text-[14px]">{opt}</div>
                  </button>
                );
              })}
            </div>
          )}

          {q.kind === 'multi' && (
            <div className="grid grid-cols-1 gap-2">
              {q.options.map((opt) => {
                const arr = Array.isArray(value) ? value : [];
                const sel = arr.includes(opt);
                return (
                  <button
                    key={opt}
                    onClick={() => toggleMulti(opt)}
                    className={`text-left rounded-2xl border px-4 py-3 flex items-center gap-3 transition ${
                      sel
                        ? 'border-[#3D2B3C] bg-[#3D2B3C]/[.04] text-[#3D2B3C]'
                        : 'border-[#3D2B3C]/15 bg-white hover:border-[#3D2B3C]/40 text-[#3D2B3C]'
                    }`}
                  >
                    <span
                      className={`w-4 h-4 rounded border-2 flex items-center justify-center ${
                        sel ? 'border-[#3D2B3C] bg-[#3D2B3C]' : 'border-[#3D2B3C]/30'
                      }`}
                    >
                      {sel && (
                        <svg viewBox="0 0 12 12" width="10" height="10">
                          <path d="M2 6 L 5 9 L 10 3" stroke="#F8F2E7" strokeWidth="2" fill="none" strokeLinecap="round" />
                        </svg>
                      )}
                    </span>
                    <div className="text-[14px]">{opt}</div>
                  </button>
                );
              })}
            </div>
          )}

          {q.kind === 'location' && (
            <LocationPicker value={value} onChange={(v) => setAnswer(q.id, v)} />
          )}

          {q.kind === 'inner_circle' && (
            <InnerCirclePicker value={value} onChange={(v) => setAnswer(q.id, v)} />
          )}

          {q.kind === 'tradition' && (
            <TraditionPicker
              value={value}
              onChange={(v) => setAnswer(q.id, v)}
              onAutoAdvance={handleNext}
            />
          )}

          {q.kind === 'residence' && (
            <ResidenceSelector
              answers={answers}
              value={value}
              onChange={(v) => setAnswer(q.id, v)}
            />
          )}
        </div>

        {/* footer — sticks to viewport bottom so Next stays reachable
            even when the answer area (e.g. the 50-state picker) is long */}
        <div className="sticky bottom-0 pt-5 pb-6 -mx-4 sm:-mx-6 px-4 sm:px-6 flex items-center justify-between bg-gradient-to-t from-[#F8F2E7] via-[#F8F2E7] to-[#F8F2E7]/0 z-10">
          <button onClick={handleNext} className="text-[#5A4459] text-[13px] hover:text-[#3D2B3C]">
            Skip this one
          </button>
          <Btn onClick={handleNext} disabled={!canAdvance} size="lg">
            {index === total - 1 ? "Show me what's next" : 'Next'} <span className="ml-1">→</span>
          </Btn>
        </div>
      </div>
    </div>
  );
}

/* ---------- 2. Generating ---------- */

function GeneratingScreen({ onDone }) {
  const compact = useIsMobile(640);
  const lines = [
    'Reading through your answers…',
    'Pulling the right starting points…',
    'Sequencing what waits and what doesn\'t…',
    'Almost there.',
  ];
  const [i, setI] = useState(0);
  useEffect(() => {
    const t = setInterval(() => setI((x) => Math.min(x + 1, lines.length - 1)), 850);
    const finish = setTimeout(onDone, 3600);
    return () => { clearInterval(t); clearTimeout(finish); };
  }, []);
  return (
    <div className="min-h-screen flex flex-col items-center justify-center text-center px-4 sm:px-6">
      <MascotLarge size={compact ? 180 : 220} mouth="thinking" />
      <div
        className="ff-serif text-xl sm:text-2xl text-[#3D2B3C] mt-5 transition-opacity"
        style={{ fontWeight: 380, fontStyle: 'italic' }}
      >
        {lines[i]}
      </div>
      <div className="mt-6 flex gap-1.5">
        {lines.map((_, idx) => (
          <span
            key={idx}
            className="w-1.5 h-1.5 rounded-full transition"
            style={{ background: idx <= i ? '#F4A88E' : '#3D2B3C22' }}
          />
        ))}
      </div>
    </div>
  );
}

/* ---------- 3. Today screen ---------- */

const TASK_LIBRARY = [
  { id: 'family', n: 1, title: 'Notify key family members', est: '20 min', bucket: 'now', who: 'Sarah', open: true },
  { id: 'certs', n: 2, title: 'Order death certificates', est: '25 min', bucket: 'now', who: 'Sarah', open: true },
  { id: 'funeral', n: 3, title: 'Funeral & memorial logistics', est: 'this week', bucket: 'now', who: 'Sarah' },
  { id: 'ssa', n: 4, title: 'Social Security & benefits', est: '30 min', bucket: 'week' },
  { id: 'lifeins', n: 5, title: 'Life insurance claims', est: '45 min', bucket: 'week' },
  { id: 'employer', n: 6, title: "Notify the employer", est: '15 min', bucket: 'week', open: true },
  { id: 'banks', n: 7, title: 'Bank account next steps', est: '40 min', bucket: 'week' },
  { id: 'will', n: 8, title: 'Will & probate orientation', est: '20 min', bucket: 'week' },
  { id: 'subs', n: 9, title: 'Subscription & account cancellation', est: 'ongoing', bucket: 'month' },
  { id: 'digital', n: 10, title: 'Digital accounts & passwords', est: 'ongoing', bucket: 'month' },
  { id: 'utilities', n: 11, title: 'Utility & housing next steps', est: '30 min', bucket: 'month' },
  { id: 'tax', n: 12, title: 'Tax filing basics for the deceased', est: '1 hr', bucket: 'later' },
  { id: 'debts', n: 13, title: 'Handling debts and creditors', est: 'varies', bucket: 'later' },
  { id: 'pets', n: 14, title: 'Pet & dependent care logistics', est: '20 min', bucket: 'later' },
  { id: 'ssaplus', n: 15, title: 'Expanded Social Security & benefits', est: '30 min', bucket: 'later' },
];

function TaskRow({ task, onOpen, family }) {
  const assignee = task.assigneeId ? family.find((f) => f.id === task.assigneeId) : null;
  return (
    <button
      onClick={() => task.open && onOpen(task.id)}
      className={`w-full text-left rounded-2xl border px-4 py-3 flex items-start gap-3 transition group ${
        task.done
          ? 'bg-[#3D2B3C]/[.04] border-[#3D2B3C]/10'
          : 'bg-white border-[#3D2B3C]/12 hover:border-[#3D2B3C]/35'
      }`}
    >
      <div
        className={`mt-0.5 w-5 h-5 rounded-full border-2 flex-shrink-0 flex items-center justify-center ${
          task.done ? 'bg-[#3D2B3C] border-[#3D2B3C]' : 'border-[#3D2B3C]/25'
        }`}
      >
        {task.done && (
          <svg viewBox="0 0 12 12" width="10" height="10">
            <path d="M2 6 L 5 9 L 10 3" stroke="#F8F2E7" strokeWidth="2" fill="none" strokeLinecap="round" />
          </svg>
        )}
      </div>
      <div className="flex-1 min-w-0">
        <div className="flex items-baseline gap-2">
          <span className="ff-mono text-[10px] text-[#5A4459]">§ {String(task.n).padStart(2, '0')}</span>
          <span className={`text-[14px] ${task.done ? 'line-through text-[#5A4459]' : 'text-[#3D2B3C]'} truncate`}>
            {task.title}
          </span>
        </div>
        <div className="flex items-center gap-2 mt-1 text-[11px] text-[#5A4459]">
          <span>{task.est}</span>
          {assignee && (
            <>
              <span>·</span>
              <span className="flex items-center gap-1">
                <span className="w-3.5 h-3.5 rounded-full" style={{ background: assignee.color }} />
                {assignee.firstName}
              </span>
            </>
          )}
          {!assignee && !task.done && <span className="text-[#5A4459]/60">· unassigned</span>}
        </div>
      </div>
      {task.open && (
        <span className="hidden lg:inline text-[#5A4459] text-[18px] opacity-0 group-hover:opacity-100 transition">→</span>
      )}
    </button>
  );
}

/* ---------- Companion pill — click to open a "what do you need right now?" panel ----------
   Three options per spec:
     1. Help, I'm feeling overwhelmed  → guided breath
     2. I need to talk to someone      → escalation cards
     3. I have a question              → ask-Betty input
*/
const PILL_GRADIENT_BG = [
  'radial-gradient(120% 220% at 100% 50%, rgba(184,164,201,0.32) 0%, rgba(184,164,201,0) 60%)',
  'radial-gradient(140% 220% at 0% 50%, rgba(244,168,142,0.22) 0%, rgba(244,168,142,0) 65%)',
  'linear-gradient(90deg, #FBF4E8 0%, #F6EDDE 50%, #F1E7DB 100%)',
].join(', ');
const PANEL_GRADIENT_BG = [
  'radial-gradient(80% 60% at 100% 0%, rgba(184,164,201,0.30) 0%, rgba(184,164,201,0) 70%)',
  'radial-gradient(80% 60% at 0% 100%, rgba(244,168,142,0.22) 0%, rgba(244,168,142,0) 70%)',
  'linear-gradient(155deg, #FBF4E8 0%, #F6EDDE 55%, #F1E7DB 100%)',
].join(', ');

function CompanionPill({ hidden }) {
  const compact = useIsMobile();
  // 'closed' | 'menu' | 'breath' | 'talk' | 'ask'
  const [view, setView] = useState('closed');
  const open = view !== 'closed';

  const close = () => setView('closed');

  return (
    <>
      {/* dim backdrop when open */}
      {open && (
        <div
          onClick={close}
          className="absolute inset-0 z-20 transition-opacity"
          style={{ background: 'rgba(61,43,60,0.18)', backdropFilter: 'blur(2px)' }}
        />
      )}

      {/* the expanded panel — emerges above the pill, anchored bottom-right */}
      <div
        className="absolute z-30 pointer-events-none"
        style={{
          right: compact ? 14 : 22,
          bottom: compact ? 14 : 22,
          opacity: open ? 1 : 0,
          transform: open ? 'translateY(0) scale(1)' : 'translateY(12px) scale(0.96)',
          transformOrigin: 'bottom right',
          transition: 'opacity 320ms cubic-bezier(.4,0,.2,1), transform 320ms cubic-bezier(.4,0,.2,1)',
        }}
      >
        {open && (
          <div
            className="rounded-[26px] border border-[#3D2B3C]/12 shadow-[0_28px_60px_-18px_rgba(61,43,60,0.4)] relative overflow-hidden pointer-events-auto"
            style={{
              width: compact ? 300 : 340,
              maxWidth: 'calc(100vw - 28px)',
              backgroundImage: PANEL_GRADIENT_BG,
            }}
          >
            <button
              onClick={close}
              className="absolute top-3 right-3 w-7 h-7 rounded-full flex items-center justify-center text-[#5A4459] hover:text-[#3D2B3C] hover:bg-[#3D2B3C]/8 text-[16px] z-10"
              aria-label="Close"
            >
              ×
            </button>

            {view === 'menu' && <CompanionMenu onPick={setView} />}
            {view === 'breath' && <CompanionBreath onBack={() => setView('menu')} onDone={close} />}
            {view === 'talk' && <CompanionTalk onBack={() => setView('menu')} />}
            {view === 'ask' && <CompanionAsk onBack={() => setView('menu')} />}
          </div>
        )}
      </div>

      {/* the pill itself — hides while panel is open */}
      <div
        className="absolute z-40 pointer-events-auto"
        style={{
          right: compact ? 14 : 22,
          bottom: compact ? 14 : 22,
          opacity: hidden || open ? 0 : 1,
          transform: hidden ? 'translateY(14px) scale(0.94)' : open ? 'scale(0.92)' : 'translateY(0) scale(1)',
          transformOrigin: 'bottom right',
          pointerEvents: hidden || open ? 'none' : 'auto',
          transition: 'opacity 380ms cubic-bezier(.4,0,.2,1), transform 380ms cubic-bezier(.4,0,.2,1)',
        }}
      >
        <button
          onClick={() => setView('menu')}
          className="flex items-center gap-3 rounded-full backdrop-blur-md border border-[#3D2B3C]/10 shadow-[0_12px_32px_-12px_rgba(61,43,60,0.32)] pl-1.5 pr-4 py-1.5 hover:shadow-[0_18px_38px_-12px_rgba(61,43,60,0.38)] transition-shadow relative overflow-hidden"
          style={{ backgroundImage: PILL_GRADIENT_BG }}
        >
          <div className="shrink-0">
            <MascotCard size={compact ? 44 : 50} />
          </div>
          <p
            className="ff-serif text-[#3D2B3C] leading-tight text-left"
            style={{ fontSize: compact ? 13 : 14, fontWeight: 400, fontStyle: 'italic', maxWidth: 200 }}
          >
            I&rsquo;m here. One step at a time.
          </p>
        </button>
      </div>
    </>
  );
}

function CompanionMenu({ onPick }) {
  const opts = [
    {
      id: 'breath',
      title: "Help — I'm feeling overwhelmed",
      sub: "Let's slow down together for a minute.",
      dot: '#F4A88E',
    },
    {
      id: 'talk',
      title: 'I need to talk to someone',
      sub: 'A person, not me. I can point you.',
      dot: '#B8A4C9',
    },
    {
      id: 'ask',
      title: 'I have a question',
      sub: 'Anything. The dumb ones too.',
      dot: '#9CA88C',
    },
  ];
  return (
    <div className="p-5 pt-6">
      <div className="flex items-center gap-3 mb-4">
        <MascotCard size={44} />
        <div>
          <div className="ff-serif text-[#3D2B3C] leading-tight" style={{ fontSize: 17, fontWeight: 450 }}>
            What do you need right now?
          </div>
          <div className="text-[#5A4459] text-[11px] mt-0.5">
            No wrong answer.
          </div>
        </div>
      </div>
      <div className="space-y-2">
        {opts.map((o) => (
          <button
            key={o.id}
            onClick={() => onPick(o.id)}
            className="w-full text-left rounded-2xl bg-white/70 hover:bg-white border border-[#3D2B3C]/10 hover:border-[#3D2B3C]/30 px-4 py-3 transition flex items-start gap-3"
          >
            <span className="mt-1.5 w-2 h-2 rounded-full flex-shrink-0" style={{ background: o.dot }} />
            <div className="flex-1 min-w-0">
              <div className="text-[#3D2B3C] text-[14px] leading-snug" style={{ fontWeight: 500 }}>{o.title}</div>
              <div className="text-[#5A4459] text-[12px] leading-relaxed mt-0.5 ff-serif" style={{ fontStyle: 'italic' }}>{o.sub}</div>
            </div>
          </button>
        ))}
      </div>
    </div>
  );
}

function CompanionBreath({ onBack, onDone }) {
  // 4-7-8 inspired but gentler: in 4s, hold 2s, out 6s — three rounds.
  const cycle = 12000;
  const [t, setT] = useState(0);
  const [round, setRound] = useState(1);
  useEffect(() => {
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const elapsed = now - start;
      const r = Math.floor(elapsed / cycle) + 1;
      if (r > 3) { onDone(); return; }
      setRound(r);
      setT((elapsed % cycle) / cycle);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  // phase: 0–0.33 inhale, 0.33–0.5 hold, 0.5–1 exhale
  const phase = t < 0.33 ? 'in' : t < 0.5 ? 'hold' : 'out';
  const scale =
    phase === 'in' ? 0.8 + (t / 0.33) * 0.4 :
    phase === 'hold' ? 1.2 :
    1.2 - ((t - 0.5) / 0.5) * 0.4;
  const label = phase === 'in' ? 'Breathe in…' : phase === 'hold' ? 'Hold.' : 'And out.';

  return (
    <div className="p-6 pt-7 text-center">
      <button onClick={onBack} className="absolute top-3 left-3 text-[#5A4459] hover:text-[#3D2B3C] text-[12px] flex items-center gap-1">
        <span>←</span> back
      </button>
      <div className="text-[10px] uppercase tracking-[.18em] text-[#5A4459] mb-4">
        round {round} of 3
      </div>
      <div className="relative h-[160px] flex items-center justify-center">
        {/* halo ring */}
        <div
          className="absolute rounded-full"
          style={{
            width: 160, height: 160,
            background: 'radial-gradient(circle, rgba(244,168,142,0.35) 0%, rgba(244,168,142,0) 70%)',
            transform: `scale(${scale})`,
            transition: 'transform 60ms linear',
          }}
        />
        <div
          style={{
            transform: `scale(${scale})`,
            transition: 'transform 60ms linear',
          }}
        >
          <MascotCard size={84} />
        </div>
      </div>
      <div
        className="ff-serif text-[#3D2B3C] mt-3"
        style={{ fontSize: 20, fontWeight: 400, fontStyle: 'italic' }}
      >
        {label}
      </div>
      <div className="text-[#5A4459] text-[12px] mt-2 leading-relaxed">
        The list will be here when you come back.
      </div>
      <button
        onClick={onDone}
        className="mt-5 text-[12px] text-[#5A4459] hover:text-[#3D2B3C] underline decoration-dotted underline-offset-2"
      >
        I'm okay, close this
      </button>
    </div>
  );
}

function CompanionTalk({ onBack }) {
  const cards = [
    {
      tag: 'right now',
      title: '988 — Suicide & Crisis Lifeline',
      sub: 'Free, 24/7. Call or text 988. Grief counselors trained for loss.',
      tint: '#F4A88E',
    },
    {
      tag: 'this week',
      title: 'A grief counselor',
      sub: "I'll surface a few in your state when you're ready. No appointment needed today.",
      tint: '#B8A4C9',
    },
    {
      tag: 'someone you know',
      title: 'Call Sarah, or a friend',
      sub: 'The person you would have called before any of this. They want to hear from you.',
      tint: '#9CA88C',
    },
  ];
  return (
    <div className="p-5 pt-6">
      <button onClick={onBack} className="absolute top-3 left-3 text-[#5A4459] hover:text-[#3D2B3C] text-[12px] flex items-center gap-1">
        <span>←</span> back
      </button>
      <div className="text-center mb-4 mt-1">
        <MascotCard size={38} />
        <div className="ff-serif text-[#3D2B3C] mt-2" style={{ fontSize: 17, fontWeight: 450 }}>
          A person, not me.
        </div>
        <div className="text-[#5A4459] text-[12px] mt-1 ff-serif" style={{ fontStyle: 'italic' }}>
          Pick whatever feels closest to right.
        </div>
      </div>
      <div className="space-y-2">
        {cards.map((c) => (
          <button
            key={c.title}
            className="w-full text-left rounded-2xl bg-white/80 hover:bg-white border border-[#3D2B3C]/10 hover:border-[#3D2B3C]/30 px-4 py-3 transition"
          >
            <div className="flex items-center gap-2 mb-1">
              <span className="w-1.5 h-1.5 rounded-full" style={{ background: c.tint }} />
              <span className="text-[9px] uppercase tracking-[.18em] text-[#5A4459]">{c.tag}</span>
            </div>
            <div className="text-[#3D2B3C] text-[13.5px]" style={{ fontWeight: 500 }}>{c.title}</div>
            <div className="text-[#5A4459] text-[12px] leading-relaxed mt-0.5">{c.sub}</div>
          </button>
        ))}
      </div>
    </div>
  );
}

function CompanionAsk({ onBack }) {
  const [q, setQ] = useState('');
  const [phase, setPhase] = useState('idle'); // idle | thinking | answer
  const suggestions = [
    'How many death certificates?',
    'What if there\'s no will?',
    "Can I do this tomorrow?",
  ];
  const ask = (text) => {
    setQ(text);
    setPhase('thinking');
    setTimeout(() => setPhase('answer'), 1100);
  };
  return (
    <div className="p-5 pt-6">
      <button onClick={onBack} className="absolute top-3 left-3 text-[#5A4459] hover:text-[#3D2B3C] text-[12px] flex items-center gap-1">
        <span>←</span> back
      </button>
      <div className="flex items-center gap-3 mb-4 mt-1">
        <MascotCard size={40} />
        <div>
          <div className="ff-serif text-[#3D2B3C] leading-tight" style={{ fontSize: 16, fontWeight: 450 }}>
            Ask me anything.
          </div>
          <div className="text-[#5A4459] text-[11px] mt-0.5 ff-serif" style={{ fontStyle: 'italic' }}>
            The dumb ones too.
          </div>
        </div>
      </div>

      {phase === 'idle' && (
        <>
          <div className="rounded-2xl bg-white/80 border border-[#3D2B3C]/10 p-1">
            <input
              type="text"
              value={q}
              onChange={(e) => setQ(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter' && q.trim()) ask(q.trim()); }}
              placeholder="Type a question…"
              className="w-full bg-transparent px-3 py-2 text-[13px] text-[#3D2B3C] focus:outline-none"
            />
          </div>
          <div className="text-[10px] uppercase tracking-[.18em] text-[#5A4459] mt-3 mb-1.5">
            or try one
          </div>
          <div className="space-y-1.5">
            {suggestions.map((s) => (
              <button
                key={s}
                onClick={() => ask(s)}
                className="w-full text-left rounded-xl bg-white/60 hover:bg-white border border-[#3D2B3C]/10 hover:border-[#3D2B3C]/30 px-3 py-2 text-[12.5px] text-[#3D2B3C] transition ff-serif"
                style={{ fontStyle: 'italic' }}
              >
                {s}
              </button>
            ))}
          </div>
        </>
      )}

      {phase === 'thinking' && (
        <div className="text-center py-6">
          <div className="ff-serif text-[#3D2B3C] mb-3" style={{ fontSize: 14, fontStyle: 'italic' }}>
            "{q}"
          </div>
          <div className="flex justify-center gap-1.5">
            {[0, 1, 2].map((i) => (
              <span
                key={i}
                className="w-1.5 h-1.5 rounded-full bg-[#5A4459]"
                style={{ animation: `mb-breath 1.1s ease-in-out ${i * 0.2}s infinite` }}
              />
            ))}
          </div>
          <div className="text-[11px] text-[#5A4459] mt-3 ff-serif" style={{ fontStyle: 'italic' }}>
            thinking…
          </div>
        </div>
      )}

      {phase === 'answer' && (
        <div>
          <div className="text-[11px] text-[#5A4459] mb-1.5">you asked</div>
          <div className="rounded-xl bg-white/60 border border-[#3D2B3C]/10 px-3 py-2 text-[12.5px] text-[#3D2B3C] ff-serif italic mb-3">
            {q}
          </div>
          <div className="rounded-2xl bg-white border border-[#3D2B3C]/12 p-3.5">
            <div className="flex items-start gap-2.5">
              <MascotGlyph size={22} />
              <p className="text-[#3D2B3C] text-[13px] leading-relaxed flex-1">
                I'll have a real answer for you here in v1.5 — for now, imagine a short, warm,
                accurate reply with a link to the most relevant task page.
              </p>
            </div>
          </div>
          <button
            onClick={() => { setQ(''); setPhase('idle'); }}
            className="mt-3 text-[12px] text-[#5A4459] hover:text-[#3D2B3C] underline decoration-dotted underline-offset-2"
          >
            Ask another
          </button>
        </div>
      )}
    </div>
  );
}

function TodayScreen({ tasks, family, onOpenTask, onInvite, singleDay, introBreath, onIntroDone }) {
  const compact = useIsMobile();
  const [expanded, setExpanded] = useState(!singleDay);
  // re-collapse when the rule turns on
  useEffect(() => { if (singleDay) setExpanded(false); else setExpanded(true); }, [singleDay]);

  // intro breath sequence: full-screen mascot saying the line, then morph upward into the grounding card.
  // 'enter' (fade in) → 'hold' (breathe) → 'depart' (translate up + fade) → 'done'
  const [breathPhase, setBreathPhase] = useState(introBreath ? 'enter' : 'done');
  useEffect(() => {
    if (!introBreath) return;
    const t1 = setTimeout(() => setBreathPhase('hold'), 60);
    const t2 = setTimeout(() => setBreathPhase('depart'), 4600);
    const t3 = setTimeout(() => { setBreathPhase('done'); onIntroDone && onIntroDone(); }, 6300);
    return () => { clearTimeout(t1); clearTimeout(t2); clearTimeout(t3); };
  }, []);

  const now = tasks.filter((t) => t.bucket === 'now' && !t.done);
  const week = tasks.filter((t) => t.bucket === 'week');
  const month = tasks.filter((t) => t.bucket === 'month');
  const later = tasks.filter((t) => t.bucket === 'later');
  const done = tasks.filter((t) => t.done).length;

  // The single-day rule: surface ONE task, not a calendar.
  const singular = now[0];
  const todayClear = !singular;

  return (
    <div className="h-full overflow-y-auto relative">
      {/* greeting — small, time-of-day, never a calendar dump */}
      <div className="px-6 pt-7 pb-4">
        <Eyebrow>Tuesday morning · for Sarah</Eyebrow>
      </div>

      {/* THE ONE THING (or the clear-day acknowledgement) */}
      <div className="px-6 mt-2">
        {!todayClear ? (
          <>
            <div className="flex items-center gap-2 mb-3">
              <span className="w-2 h-2 rounded-full bg-[#F4A88E]" />
              <Eyebrow>One thing for today</Eyebrow>
            </div>
            <SingularTaskCard task={singular} onOpen={onOpenTask} family={family} />
          </>
        ) : (
          <div className="rounded-2xl border border-[#3D2B3C]/15 bg-white px-5 py-6">
            <div
              className="ff-serif text-[#3D2B3C] text-[22px] lg:text-[26px]"
              style={{ fontWeight: 400 }}
            >
              Today's clear.
            </div>
            <div className="text-[#5A4459] text-[14px] leading-relaxed mt-1.5">
              When you're ready, here's what's coming up.
            </div>
          </div>
        )}
      </div>

      {/* THE DISCLOSURE — opt-in to see beyond today */}
      {!expanded && (
        <div className="px-6 mt-5">
          <button
            onClick={() => setExpanded(true)}
            className="w-full text-left rounded-2xl border border-dashed border-[#3D2B3C]/25 px-4 py-3 text-[#5A4459] hover:border-[#3D2B3C]/50 hover:text-[#3D2B3C] transition flex items-center justify-between"
          >
            <span className="text-[13px] ff-serif" style={{ fontStyle: 'italic', fontWeight: 380 }}>
              See what's coming, when you're ready.
            </span>
            <span className="text-[#5A4459] text-[16px]">↓</span>
          </button>
          <div className="text-[11px] text-[#5A4459]/70 mt-2 leading-relaxed">
            {tasks.length - 1} more on your list. They'll wait.
          </div>
        </div>
      )}

      {/* INVITE NUDGE — coordinator is a tracker, family claims tasks.
          On desktop this lives in the sidebar beneath the Family section instead. */}
      <div className="lg:hidden px-6 mt-6">
        <div className="rounded-2xl bg-white border border-[#3D2B3C]/12 p-4">
          <div className="flex items-start gap-3">
            <MascotGlyph size={28} />
            <div className="flex-1">
              <div className="text-[#3D2B3C] text-[14px] leading-snug" style={{ fontWeight: 500 }}>
                You don't have to assign anything.
              </div>
              <div className="text-[#5A4459] text-[13px] leading-relaxed mt-1">
                When the family joins, they'll see the same list and claim what they can do. I'll quietly nudge the rest.
              </div>
              <div className="mt-3">
                <Btn onClick={onInvite} variant="coral" size="sm">Invite the family</Btn>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* EXPANDED — only when the user asks for it */}
      {expanded && (
        <>
          <div className="px-6 mt-8">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <span className="w-2 h-2 rounded-full bg-[#B8A4C9]" />
                <Eyebrow>Right now · today</Eyebrow>
              </div>
              <span className="ff-mono text-[10px] text-[#5A4459]">{now.length} unclaimed</span>
            </div>
            <div className="space-y-2">
              {now.map((t) => <TaskRow key={t.id} task={t} onOpen={onOpenTask} family={family} />)}
            </div>
          </div>

          <div className="px-6 mt-7">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <span className="w-2 h-2 rounded-full bg-[#3D2B3C]/40" />
                <Eyebrow>This week</Eyebrow>
              </div>
              <span className="ff-mono text-[10px] text-[#5A4459]">{week.length} items</span>
            </div>
            <div className="space-y-2">
              {week.map((t) => <TaskRow key={t.id} task={t} onOpen={onOpenTask} family={family} />)}
            </div>
          </div>

          <div className="px-6 mt-7">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <span className="w-2 h-2 rounded-full bg-[#3D2B3C]/30" />
                <Eyebrow>This month</Eyebrow>
              </div>
              <span className="ff-mono text-[10px] text-[#5A4459]">{month.length} items</span>
            </div>
            <div className="space-y-2">
              {month.map((t) => <TaskRow key={t.id} task={t} onOpen={onOpenTask} family={family} />)}
            </div>
          </div>

          <div className="px-6 mt-7 mb-4">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <span className="w-2 h-2 rounded-full bg-[#3D2B3C]/20" />
                <Eyebrow>Later · weeks from now</Eyebrow>
              </div>
              <span className="ff-mono text-[10px] text-[#5A4459]">{later.length} items</span>
            </div>
            <div className="space-y-2">
              {later.map((t) => <TaskRow key={t.id} task={t} onOpen={onOpenTask} family={family} />)}
            </div>
          </div>

          <div className="px-6 mt-2 mb-6">
            <button
              onClick={() => setExpanded(false)}
              className="text-[12px] text-[#5A4459] hover:text-[#3D2B3C] flex items-center gap-1"
            >
              <span>↑</span> Show only today
            </button>
          </div>
        </>
      )}

      <div className="px-6 pb-8 pt-4 border-t border-[#3D2B3C]/10 flex items-center justify-between mt-4">
        <div className="text-[11px] text-[#5A4459]">
          {done} of {tasks.length} done · paced for you, not against you
        </div>
        <button className="text-[11px] text-[#5A4459] hover:text-[#3D2B3C]">Help &amp; boundaries</button>
      </div>

      {/* AMBIENT MASCOT — floating bottom-right companion. Persistent after intro. */}
      <CompanionPill hidden={breathPhase === 'enter' || breathPhase === 'hold'} />

      {/* INTRO BREATH OVERLAY — first arrival only. Mascot says the line, user breathes,
          then morphs down into the floating bottom-right companion. */}
      {breathPhase !== 'done' && (
        <div
          className="absolute inset-0 z-30 pointer-events-none"
          style={{
            background: 'radial-gradient(ellipse at 50% 45%, #FBF6EC 0%, #F4ECDB 70%, #EFE5D0 100%)',
            opacity: breathPhase === 'enter' ? 0 : breathPhase === 'depart' ? 0 : 1,
            transition: breathPhase === 'depart'
              ? 'opacity 1500ms cubic-bezier(.4,0,.2,1)'
              : 'opacity 700ms ease-out',
          }}
        >
          <div
            className="absolute text-center"
            style={{
              right: breathPhase === 'depart' ? (compact ? 14 : 22) : '50%',
              bottom: breathPhase === 'depart' ? (compact ? 14 : 22) : '50%',
              transform: breathPhase === 'depart'
                ? 'translate(0, 0) scale(0.22)'
                : breathPhase === 'enter'
                  ? 'translate(50%, 50%) scale(0.97)'
                  : 'translate(50%, 50%) scale(1)',
              transformOrigin: 'bottom right',
              opacity: breathPhase === 'enter' ? 0 : 1,
              maxWidth: 460,
              width: '88%',
              transition: breathPhase === 'depart'
                ? 'right 1500ms cubic-bezier(.4,0,.2,1), bottom 1500ms cubic-bezier(.4,0,.2,1), transform 1500ms cubic-bezier(.4,0,.2,1), opacity 1400ms cubic-bezier(.4,0,.2,1) 100ms'
                : 'transform 800ms cubic-bezier(.4,0,.2,1), opacity 700ms ease-out',
            }}
          >
            <div className="mb-breath flex justify-center">
              <MascotLarge size={compact ? 180 : 220} mouth="flat" />
            </div>
            <p
              className="ff-serif text-[#3D2B3C] mt-7 leading-[1.32] text-[21px] lg:text-[26px]"
              style={{ fontWeight: 400, textWrap: 'balance' }}
            >
              Take a breath. Let&rsquo;s just take it one step at a time. We&rsquo;ll be here the whole way.
            </p>
          </div>
        </div>
      )}
    </div>
  );
}

function SingularTaskCard({ task, onOpen, family }) {
  const assignee = task.assigneeId ? family.find((f) => f.id === task.assigneeId) : null;
  return (
    <button
      onClick={() => task.open && onOpen(task.id)}
      className="w-full text-left rounded-[22px] bg-white border border-[#3D2B3C]/15 p-5 hover:border-[#3D2B3C]/40 transition group block"
    >
      <div className="flex items-start gap-2 mb-2">
        <span className="ff-mono text-[10px] text-[#5A4459]">§ {String(task.n).padStart(2, '0')}</span>
        <span className="text-[10px] uppercase tracking-[.18em] text-[#5A4459]">{task.est}</span>
      </div>
      <div
        className="ff-serif text-[#3D2B3C] leading-[1.1] text-[24px] lg:text-[28px]"
        style={{ fontWeight: 400 }}
      >
        {task.title}
      </div>
      <div className="text-[#5A4459] text-[13px] leading-relaxed mt-2 max-w-[44ch]">
        {task.id === 'certs' && "About forty of them. Not because anyone wants forty — because every account closure asks for one of its own."}
        {task.id === 'family' && "The closest people first. Quick calls, not perfect ones."}
        {task.id === 'funeral' && "What's already in motion, what isn't yet, and what only you can decide."}
      </div>
      <div className="flex items-center justify-between mt-4">
        <div className="text-[12px] text-[#5A4459]">
          {assignee ? (
            <span className="flex items-center gap-1.5">
              <span className="w-3.5 h-3.5 rounded-full" style={{ background: assignee.color }} />
              {assignee.firstName} is on it
            </span>
          ) : (
            <span className="text-[#5A4459]/80">Open — anyone can claim it</span>
          )}
        </div>
        <span className="text-[#3D2B3C] text-[13px] flex items-center gap-1 group-hover:gap-2 transition-all">
          Begin <span>→</span>
        </span>
      </div>
    </button>
  );
}

/* ---------- 4. Task detail (Death Certificates) ---------- */

const TASK_CONTENT = {
  certs: {
    n: 2,
    title: 'Order death certificates',
    sub: 'Yes, you really do need around forty of them. No, I don\'t know why either.',
    why:
      'Almost every account closure, pension claim, and title transfer wants an official certified copy. Photocopies aren\'t accepted. The funeral home usually orders the first batch — most families discover within two weeks they need more.',
    need: ['The deceased\'s full legal name', "Date and county of death", 'Your relationship to them', "A credit card", "A mailing address"],
    steps: [
      { h: 'Confirm what the funeral home already ordered.', b: 'Most order 10 by default. Ask them what their count was — Karen can call if you\'d rather.' },
      { h: 'Order another 30–35 from the county Vital Records office.', b: 'In California it\'s the County Recorder. Online order, $26 each, mailed in 2–3 weeks.' },
      { h: 'Use a single mailing address — yours.', b: 'You\'ll be the one handing them out. Store them in a single labelled folder.' },
      { h: 'Keep the receipt.', b: 'Estate-deductible. Slot it into the documents list once the count clears.' },
    ],
    confusion: [
      { q: 'Do I need certified copies, or are PDFs okay?', a: 'Certified, raised-seal, paper. Some banks accept faxed certifieds; almost none accept PDF.' },
      { q: 'Will I really need 40?', a: 'Median is 35. People with multiple bank accounts, multiple insurance policies, or a house in their name push past 40.' },
      { q: 'What if I order too many?', a: 'You can\'t. They don\'t expire and you\'ll find more places that want one.' },
    ],
    helpWhen: 'If something on the death certificate is wrong — name spelled wrong, wrong cause of death, wrong date — that\'s a separate process called amendment. I\'ll walk you through it.',
  },
  employer: {
    n: 6,
    title: "Notify the employer",
    sub: 'One call, one email, one form. They\'ve done this before.',
    why:
      "The employer holds the last paycheck, unused vacation, life insurance through work, the 401(k), and sometimes a small bereavement payment. Most companies have a person whose job this is, and they will not be surprised by your call.",
    need: ['The deceased\'s employer and HR contact (or main phone)', "Their employee ID or last four of SSN", "A death certificate (most accept emailed PDFs initially)"],
    steps: [
      { h: 'Call the HR / benefits line first.', b: 'Tell them what happened. Ask what their bereavement process looks like and who your point of contact will be.' },
      { h: 'Ask specifically about: final paycheck, unused PTO, employer life insurance, 401(k), and COBRA.', b: 'These are the five things every survivor should know about. Most HR teams will walk you through them.' },
      { h: 'Send the death certificate when they ask.', b: 'Almost always email-first, mail later. Save what you send and to whom.' },
      { h: 'Get the contact in writing.', b: 'A name and a direct email. You will need them again in three weeks.' },
    ],
    confusion: [
      { q: 'What if they were self-employed?', a: 'Different track — we\'ll route this through the business closure path instead. Mark this not applicable when you\'re ready.' },
      { q: 'What about coworkers?', a: 'That\'s yours to decide. Some employers handle the announcement; some leave it to family. Ask.' },
    ],
    helpWhen: 'If the employer pushes back on releasing benefits, that\'s an attorney call. I keep a short list of estate attorneys who do these calls cheaply.',
  },
};

function TaskDetailScreen({ taskId, task, family, onBack, onMarkDone, onAssign }) {
  const c = TASK_CONTENT[taskId];
  if (!c) return null;
  const assignee = task.assigneeId ? family.find((f) => f.id === task.assigneeId) : null;

  return (
    <div className="h-full overflow-y-auto">
      <div className="px-6 pt-5 pb-4 flex items-center justify-between border-b border-[#3D2B3C]/10 sticky top-0 bg-[#F8F2E7]/95 backdrop-blur-sm z-10">
        <button onClick={onBack} className="text-[#5A4459] text-sm flex items-center gap-1.5 hover:text-[#3D2B3C]">
          <span>←</span> Today
        </button>
        <div className="flex items-center gap-2">
          <span className="ff-mono text-[10px] text-[#5A4459]">§ {String(c.n).padStart(2, '0')}</span>
        </div>
      </div>

      <div className="px-6 pt-6 pb-2">
        <Eyebrow>Task · do this slowly</Eyebrow>
        <h1
          className="ff-serif text-[#3D2B3C] leading-[1.05] mt-2 text-[28px] lg:text-[36px]"
          style={{ fontWeight: 400 }}
        >
          {c.title}
        </h1>
        <p className="ff-serif text-[#3D2B3C] mt-2 max-w-[42ch] text-[16px] lg:text-[18px]" style={{ fontWeight: 380, fontStyle: 'italic' }}>
          {c.sub}
        </p>
      </div>

      {/* assignment + actions */}
      <div className="px-6 pt-5 flex flex-wrap items-center gap-2">
        <Btn onClick={onMarkDone} variant={task.done ? 'secondary' : 'primary'} size="md">
          {task.done ? '✓ Done' : 'Mark done'}
        </Btn>
        <Btn variant="secondary" size="md" className="hidden lg:inline-flex">Mark not applicable</Btn>
        <div className="ml-auto">
          <select
            value={task.assigneeId || ''}
            onChange={(e) => onAssign(taskId, e.target.value || null)}
            className="rounded-full border border-[#3D2B3C]/20 bg-white px-3 py-2 text-[13px] text-[#3D2B3C] focus:outline-none focus:border-[#3D2B3C]"
          >
            <option value="">Unassigned</option>
            {family.map((f) => <option key={f.id} value={f.id}>{f.firstName} ({f.relation})</option>)}
          </select>
        </div>
      </div>

      <div className="px-6 mt-7">
        <Eyebrow className="mb-2">Why this matters</Eyebrow>
        <p className="text-[#3D2B3C] text-[15px] leading-relaxed">{c.why}</p>
      </div>

      <div className="px-6 mt-7">
        <Eyebrow className="mb-2">What you'll need</Eyebrow>
        <ul className="space-y-1.5">
          {c.need.map((n, i) => (
            <li key={i} className="flex items-start gap-2 text-[#3D2B3C] text-[14px]">
              <span className="mt-2 w-1 h-1 rounded-full bg-[#3D2B3C]/40 flex-shrink-0" />
              <span>{n}</span>
            </li>
          ))}
        </ul>
      </div>

      <div className="px-6 mt-7">
        <Eyebrow className="mb-3">Steps</Eyebrow>
        <ol className="space-y-3">
          {c.steps.map((s, i) => (
            <li key={i} className="flex items-start gap-3">
              <span className="ff-mono text-[12px] text-[#5A4459] mt-0.5">{String(i + 1).padStart(2, '0')}</span>
              <div>
                <div className="ff-serif text-[#3D2B3C] text-[17px] leading-snug" style={{ fontWeight: 450 }}>
                  {s.h}
                </div>
                <div className="text-[#5A4459] text-[13px] leading-relaxed mt-1">{s.b}</div>
              </div>
            </li>
          ))}
        </ol>
      </div>

      <div className="px-6 mt-7">
        <Eyebrow className="mb-3">Common confusion</Eyebrow>
        <div className="space-y-3">
          {c.confusion.map((cc, i) => (
            <div key={i} className="rounded-2xl bg-white border border-[#3D2B3C]/10 p-4">
              <div className="text-[#3D2B3C] text-[14px]" style={{ fontWeight: 500 }}>{cc.q}</div>
              <div className="text-[#5A4459] text-[13px] leading-relaxed mt-1">{cc.a}</div>
            </div>
          ))}
        </div>
      </div>

      {/* mascot escalation card */}
      <div className="px-6 mt-7 mb-8">
        <div className="rounded-2xl bg-[#3D2B3C]/[.04] border border-[#3D2B3C]/15 p-4">
          <div className="flex items-start gap-3">
            <MascotCard size={44} />
            <div className="flex-1">
              <Eyebrow className="mb-1">When to get help</Eyebrow>
              <div className="text-[#3D2B3C] text-[14px] leading-relaxed">{c.helpWhen}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  Btn,
  Eyebrow,
  WelcomeScreen,
  IntakeScreen,
  GeneratingScreen,
  TodayScreen,
  TaskDetailScreen,
  INTAKE_QUESTIONS,
  TASK_LIBRARY,
  TASK_CONTENT,
  visibleQuestions,
  INNER_CIRCLE_RELATIONS,
  useIsMobile,
});
