// Forms.jsx — Patient forms hub: intake, consent, post-operative instructions
const { useState: useFS } = React;

function buildTrafftUrl(d) {
  const p = new URLSearchParams({ action: 'link' });
  if (d && d.npi)  p.set('npi', d.npi);
  if (d && d.name) p.set('name', d.name);
  return `/api/trafft?${p}`;
}

// Open a hosted form in a new tab via our /i/<slug> redirect — the user
// never sees the underlying provider URL in our links. The redirect is
// resolved server-side by the Pages Function at functions/i/[slug].js.
// When a server-side link-creation endpoint is configured, /api/portal/start
// returns a per-patient pre-filled URL; this path is the fallback.
function openHostedForm(slug, prefill = {}) {
  const url = buildHostedFormUrl(slug, prefill);
  const win = window.open(url, '_blank', 'noopener,noreferrer');
  if (!win) {
    window.location.href = url;
  }
}

function buildHostedFormUrl(slug, prefill = {}) {
  const p = new URLSearchParams(Object.fromEntries(Object.entries(prefill).filter(([,v])=>v)));
  const qs = p.toString();
  return `/i/${encodeURIComponent(slug)}${qs?'?'+qs:''}`;
}

// Backwards-compatible aliases for any callers still using the old names.
const openFormRobin = openHostedForm;
const buildFRUrl = buildHostedFormUrl;

// ─── CATALOG ─────────────────────────────────────────────────────────────────

const FORM_CATS = [
  { id:'all',           label:'All forms'              },
  { id:'new-patient',   label:'New patient'            },
  { id:'return-patient',label:'Return patient'         },
  { id:'consent',       label:'Consent forms'          },
  { id:'post-op',       label:'Post-op instructions'   },
  { id:'other',         label:'Records & other'        },
];

const FORM_CATALOG = [
  // ── NEW PATIENT ────────────────────────────────────────────────────────────
  { id:'new-patient-registration', cat:'new-patient', type:'native', slug:'new-patient-registration',
    title:'New Patient Registration', time:'5 min',
    desc:'Demographics, date of birth, address, emergency contact, and primary insurance. Required before your first visit.' },
  { id:'health-history', cat:'new-patient', type:'native', slug:'health-history',
    title:'Medical & Dental Health History', time:'8 min',
    desc:'Current medications, allergies, systemic conditions, and dental history. ADA-standard. Required at first visit.' },
  { id:'hipaa-acknowledgment', cat:'new-patient', type:'native', slug:'hipaa-acknowledgment',
    title:'HIPAA Privacy Notice Acknowledgment', time:'2 min',
    desc:'Federal requirement acknowledging receipt of the Notice of Privacy Practices (45 CFR §164.520).' },
  { id:'financial-policy', cat:'new-patient', type:'native', slug:'financial-policy',
    title:'Financial Policy & Insurance Authorization', time:'3 min',
    desc:'Practice payment policies, assignment of dental benefits, authorization to bill insurance, and payment plan terms.' },

  // ── RETURN PATIENT ────────────────────────────────────────────────────────
  { id:'health-history-update', cat:'return-patient', type:'native', slug:'health-history-update',
    title:'Health History Update', time:'3 min',
    desc:'Brief update covering any changes to medications, allergies, or medical conditions since your last visit.' },
  { id:'insurance-update', cat:'return-patient', type:'native', slug:'insurance-update',
    title:'Insurance & Demographics Update', time:'2 min',
    desc:'Update address, phone number, emergency contact, or insurance information.' },

  // ── CONSENT FORMS ─────────────────────────────────────────────────────────
  { id:'consent-treatment', cat:'consent', type:'consent', slug:'consent-treatment',
    title:'General Consent to Treatment', time:'3 min',
    desc:'Informed consent for examination, diagnosis, and general dental treatment.',
    risks:['Unexpected findings may require additional treatment','Anesthesia reactions (rare)','Temporary sensitivity or discomfort after procedures'],
    alts:['Delaying treatment (may worsen the condition)','Seeking care at another provider'] },
  { id:'consent-xrays', cat:'consent', type:'consent', slug:'consent-xrays',
    title:'Consent for Radiographs (X-Rays)', time:'2 min',
    desc:'Consent for dental radiographs including bitewings, periapicals, and panoramic images.',
    risks:['Low-dose radiation — equivalent to 1–2 hours of natural background radiation with modern digital sensors'],
    alts:['Refusing x-rays limits diagnostic accuracy and may result in missed pathology'] },
  { id:'consent-nitrous', cat:'consent', type:'consent', slug:'consent-nitrous',
    title:'Consent for Nitrous Oxide (Laughing Gas)', time:'3 min',
    desc:'Informed consent for nitrous oxide/oxygen inhalation analgesia. You may drive afterward. Nasal congestion contraindicates it.',
    risks:['Nausea if dose is too high','Contraindicated in first-trimester pregnancy','MTHFR mutation: discuss with dentist','Claustrophobia with nasal mask'],
    alts:['Oral sedation','IV sedation','No sedation — proceed with local anesthetic only'] },
  { id:'consent-oral-sedation', cat:'consent', type:'consent', slug:'consent-oral-sedation',
    title:'Consent for Oral Sedation', time:'4 min',
    desc:'Consent for oral sedative medication (e.g., triazolam, diazepam). A responsible adult driver is required. Cannot drive or make important decisions for 24 hours.',
    risks:['Residual drowsiness 6–12 hours','Paradoxical excitation (rare)','Respiratory depression at dental doses (very rare)','Dangerous interaction with alcohol'],
    alts:['Nitrous oxide','IV sedation','No sedation'] },
  { id:'consent-iv-sedation', cat:'consent', type:'consent', slug:'consent-iv-sedation',
    title:'Consent for IV / Deep Sedation', time:'5 min',
    desc:'Consent for intravenous sedation or general anesthesia with continuous monitoring. Requires pre-op fasting, a driver, and a companion for 4–6 hours post-procedure.',
    risks:['Nausea and vomiting post-procedure','IV site bruising','Aspiration risk (mitigated by pre-op fasting)','Respiratory or cardiovascular events (rare; monitored throughout)'],
    alts:['Oral sedation','Nitrous oxide','Local anesthetic only'] },
  { id:'consent-extraction', cat:'consent', type:'consent', slug:'consent-extraction',
    title:'Consent for Simple Tooth Extraction', time:'3 min',
    desc:'Informed consent for non-surgical single or multiple tooth removal.',
    risks:['Dry socket (alveolar osteitis) — most common complication, 3–5%','Post-extraction infection','Prolonged bleeding','Adjacent tooth or nerve injury (rare)'],
    alts:['Root canal therapy to retain the tooth','Crown if the tooth is restorable','Continued monitoring if asymptomatic'] },
  { id:'consent-surgical-extraction', cat:'consent', type:'consent', slug:'consent-surgical-extraction',
    title:'Consent for Surgical Extraction / Wisdom Teeth', time:'5 min',
    desc:'Consent for surgical removal of impacted or partially erupted teeth, including wisdom teeth.',
    risks:['Inferior alveolar nerve (IAN) paresthesia or numbness — usually temporary','Dry socket (higher incidence than simple extraction)','Sinus perforation for upper molars','Trismus (limited jaw opening) 1–3 weeks','Post-operative infection'],
    alts:['Active monitoring without extraction if asymptomatic','Coronectomy (planned partial removal to avoid nerve)'] },
  { id:'consent-root-canal', cat:'consent', type:'consent', slug:'consent-root-canal',
    title:'Consent for Root Canal Therapy', time:'4 min',
    desc:'Consent for endodontic treatment. A permanent crown is required after treatment in most posterior teeth.',
    risks:['Post-treatment flare-up (pain, swelling) in 2–5%','Instrument separation within the canal (rare)','Canal perforation (rare)','Re-treatment may be needed (~10% over 10 years)'],
    alts:['Tooth extraction followed by implant or bridge','Continued monitoring if asymptomatic (may worsen)'] },
  { id:'consent-implant', cat:'consent', type:'consent', slug:'consent-implant',
    title:'Consent for Dental Implant Placement', time:'6 min',
    desc:'Full informed consent for implant surgery including bone grafting, osseointegration timeline, and failure considerations.',
    risks:['Implant failure / osseointegration failure (~5–10% lifetime)','Peri-implantitis (gum/bone infection around implant)','Nerve proximity — numbness (pre-op CBCT reviewed)','Sinus perforation for upper posterior sites','Smoking doubles failure risk'],
    alts:['Dental bridge (adjacent teeth prepared)','Partial denture','No tooth replacement'] },
  { id:'consent-bone-graft', cat:'consent', type:'consent', slug:'consent-bone-graft',
    title:'Consent for Bone Grafting', time:'4 min',
    desc:'Consent for socket preservation or ridge augmentation using allograft, xenograft, or autograft material.',
    risks:['Graft rejection or resorption','Collagen membrane exposure','Infection requiring graft removal','Partial graft loss — secondary graft may be needed'],
    alts:['Extraction without grafting (ridge will resorb, compromising future implant)','Delayed implant placement without grafting'] },
  { id:'consent-perio-surgery', cat:'consent', type:'consent', slug:'consent-perio-surgery',
    title:'Consent for Periodontal Surgery', time:'4 min',
    desc:'Consent for osseous (bone) surgery, flap procedures, or LANAP laser periodontal therapy.',
    risks:['Expected gum recession revealing root surfaces','Post-surgical root sensitivity','Infection','Tooth mobility (usually temporary)','Swelling and bruising'],
    alts:['Scaling and root planing (may be insufficient for advanced disease)','Tooth extraction','Continued supportive maintenance without surgery'] },
  { id:'consent-whitening', cat:'consent', type:'consent', slug:'consent-whitening',
    title:'Consent for Teeth Whitening / Bleaching', time:'2 min',
    desc:'Consent for in-office or take-home bleaching treatment. Existing crowns and veneers will not whiten.',
    risks:['Transient tooth sensitivity — most common, resolves 1–4 days','Gum tissue irritation from bleaching gel contact','Existing restorations will not change color and may need replacement to match new shade'],
    alts:['Take-home tray whitening (lower-concentration peroxide, longer treatment)','No whitening'] },
  { id:'consent-crown', cat:'consent', type:'consent', slug:'consent-crown',
    title:'Consent for Crown / Bridge', time:'3 min',
    desc:'Consent for irreversible tooth preparation and porcelain, zirconia, or PFM crown or bridge.',
    risks:['Irreversible tooth reduction','Temporary crown sensitivity or debonding','Pulpitis leading to root canal need (~5%)','Crown fracture over time','Bridge: abutment teeth require preparation'],
    alts:['Inlay/onlay (more conservative preparation)','Extraction and implant','Large composite filling if sufficient tooth structure remains'] },
  { id:'consent-veneers', cat:'consent', type:'consent', slug:'consent-veneers',
    title:'Consent for Porcelain Veneers', time:'4 min',
    desc:'Consent for irreversible enamel reduction and indirect veneer fabrication and bonding.',
    risks:['Irreversible enamel removal (0.3–0.7 mm)','Significant sensitivity during temporary phase','Veneer fracture (avoid biting nails, ice, hard objects)','Color cannot be changed after bonding','Root canal risk (~3%)'],
    alts:['Direct composite veneers (reversible, less durable)','Orthodontic treatment for spacing/alignment','No treatment'] },
  { id:'consent-orthodontics', cat:'consent', type:'consent', slug:'consent-orthodontics',
    title:'Consent for Orthodontic Treatment', time:'5 min',
    desc:'Consent for comprehensive orthodontic treatment with braces or clear aligners.',
    risks:['Root resorption (typically minor; rarely significant)','White spot lesions / decalcification if oral hygiene lapses','Relapse without consistent retainer wear','Treatment may extend beyond original estimate','Aligner or bracket breakage requiring repair'],
    alts:['Limited/partial orthodontic treatment','No treatment'] },
  { id:'consent-minor', cat:'consent', type:'consent', slug:'consent-minor',
    title:'Minor Patient Authorization (Pediatric)', time:'3 min',
    desc:'Parent or legal guardian authorization for dental examination and treatment of a patient under 18 years of age.',
    risks:['See the procedure-specific consent form for your child\'s planned treatment'],
    alts:['Second opinion','Referral to pediatric dentist'] },

  // ── POST-OPERATIVE ────────────────────────────────────────────────────────
  { id:'postop-simple-extraction',   cat:'post-op', type:'post-op', procedure:'simple-extraction',
    title:'After Simple Tooth Extraction',
    desc:'Routine non-surgical removal. Covers clot protection, bleeding control, diet, and dry socket prevention.' },
  { id:'postop-surgical-extraction', cat:'post-op', type:'post-op', procedure:'surgical-extraction',
    title:'After Surgical / Wisdom Tooth Removal',
    desc:'Surgical removal including impacted wisdom teeth. Covers sutures, swelling, trismus, and dry socket.' },
  { id:'postop-root-canal',          cat:'post-op', type:'post-op', procedure:'root-canal',
    title:'After Root Canal Therapy',
    desc:'Post-endodontic care, flare-up signs, temporary crown protection, and crown scheduling.' },
  { id:'postop-crown',               cat:'post-op', type:'post-op', procedure:'crown',
    title:'After Crown or Bridge (Prep & Delivery)',
    desc:'Temporary crown care and permanent crown delivery: bite adjustment, sensitivity, long-term maintenance.' },
  { id:'postop-implant',             cat:'post-op', type:'post-op', procedure:'implant',
    title:'After Dental Implant Surgery',
    desc:'Osseointegration protocol, diet, activity restrictions, sutures, and post-op visit schedule.' },
  { id:'postop-bone-graft',          cat:'post-op', type:'post-op', procedure:'bone-graft',
    title:'After Bone Grafting / Socket Preservation',
    desc:'Protecting the graft membrane, diet, medications, and signs of graft failure.' },
  { id:'postop-perio-surgery',       cat:'post-op', type:'post-op', procedure:'perio-surgery',
    title:'After Periodontal Surgery',
    desc:'Suture care, chlorhexidine rinse protocol, diet, and activity restrictions.' },
  { id:'postop-srp',                 cat:'post-op', type:'post-op', procedure:'srp',
    title:'After Scaling and Root Planing (Deep Cleaning)',
    desc:'Managing sensitivity, prescribed rinse protocol, and follow-up maintenance scheduling.' },
  { id:'postop-filling',             cat:'post-op', type:'post-op', procedure:'filling',
    title:'After Composite Filling Placement',
    desc:'Bite adjustment expectations, sensitivity timeline, diet, and when to call.' },
  { id:'postop-whitening',           cat:'post-op', type:'post-op', procedure:'whitening',
    title:'After Teeth Whitening',
    desc:'White diet first 48 hours, sensitivity management, touch-up timing.' },
  { id:'postop-veneers',             cat:'post-op', type:'post-op', procedure:'veneers',
    title:'After Veneer Preparation & Delivery',
    desc:'Temporary veneer care, final delivery sensitivity, and long-term maintenance.' },
  { id:'postop-aligners',            cat:'post-op', type:'post-op', procedure:'aligners',
    title:'Clear Aligner / Invisalign Start Instructions',
    desc:'Wear protocol, attachments, IPR sensitivity, aligner hygiene, advancing trays.' },
  { id:'postop-nitrous',             cat:'post-op', type:'post-op', procedure:'nitrous',
    title:'After Nitrous Oxide (Laughing Gas)',
    desc:'Short recovery, driving safety, and same-day activity guidelines.' },
  { id:'postop-oral-sedation',       cat:'post-op', type:'post-op', procedure:'oral-sedation',
    title:'After Oral Sedation',
    desc:'Driver requirement, 24-hour activity and decision restrictions.' },
  { id:'postop-iv-sedation',         cat:'post-op', type:'post-op', procedure:'iv-sedation',
    title:'After IV / Deep Sedation',
    desc:'Full recovery protocol: driver, diet, activity, work restrictions, and medication resumption.' },
  { id:'postop-frenectomy',          cat:'post-op', type:'post-op', procedure:'frenectomy',
    title:'After Frenectomy / Lip or Tongue Tie Release',
    desc:'Wound care, stretching exercises, speech, breastfeeding, and healing expectations.' },
  { id:'postop-sinus-lift',          cat:'post-op', type:'post-op', procedure:'sinus-lift',
    title:'After Sinus Lift (Sinus Elevation)',
    desc:'Critical no-blow-nose protocol, decongestant use, activity and flight restrictions.' },
  { id:'postop-apicoectomy',         cat:'post-op', type:'post-op', procedure:'apicoectomy',
    title:'After Apicoectomy (Root-End Surgery)',
    desc:'Ice protocol, suture care, swelling, activity restrictions, and follow-up.' },

  // ── RECORDS & OTHER ───────────────────────────────────────────────────────
  { id:'release-of-records', cat:'other', type:'native', slug:'release-of-records',
    title:'Release of Dental Records', time:'3 min',
    desc:'HIPAA-compliant authorization to release records, x-rays, and treatment notes to another provider.' },
  { id:'second-opinion-request', cat:'other', type:'native', slug:'second-opinion-request',
    title:'Second Opinion Request', time:'4 min',
    desc:'Request a treatment-plan review by another TheDentist.ai recognized provider.' },
  { id:'referral', cat:'other', type:'native', slug:'referral',
    title:'Specialist Referral Form', time:'3 min',
    desc:'Referral to orthodontist, periodontist, endodontist, or oral surgeon.' },
];

// ─── FORM SCHEMAS ─────────────────────────────────────────────────────────────

const US_STATES = [
  'AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA',
  'HI','ID','IL','IN','IA','KS','KY','LA','ME','MD',
  'MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ',
  'NM','NY','NC','ND','OH','OK','OR','PA','RI','SC',
  'SD','TN','TX','UT','VT','VA','WA','WV','WI','WY',
];

const FORM_SCHEMAS = {
  'new-patient-registration': [
    { id:'h1', type:'heading', label:'Personal Information' },
    { id:'first_name', type:'text', label:'First name', required:true, cols:2 },
    { id:'last_name', type:'text', label:'Last name', required:true, cols:2 },
    { id:'dob', type:'date', label:'Date of birth', required:true, cols:2 },
    { id:'email', type:'email', label:'Email address', required:true, cols:2 },
    { id:'phone', type:'tel', label:'Phone number', required:true, cols:2 },
    { id:'h2', type:'heading', label:'Address' },
    { id:'address', type:'text', label:'Street address', required:true },
    { id:'city', type:'text', label:'City', required:true, cols:2 },
    { id:'state', type:'select', label:'State', required:true, cols:2, options:US_STATES },
    { id:'zip', type:'text', label:'ZIP code', required:true, cols:2 },
    { id:'h3', type:'heading', label:'Emergency Contact' },
    { id:'emergency_name', type:'text', label:'Emergency contact name', required:true, cols:2 },
    { id:'emergency_phone', type:'tel', label:'Emergency contact phone', required:true, cols:2 },
    { id:'emergency_relationship', type:'text', label:'Relationship', cols:2 },
    { id:'h4', type:'heading', label:'Insurance' },
    { id:'insurance_carrier', type:'text', label:'Insurance carrier', cols:2 },
    { id:'member_id', type:'text', label:'Member ID', cols:2 },
    { id:'group_number', type:'text', label:'Group number', cols:2 },
    { id:'subscriber_name', type:'text', label:'Subscriber name', cols:2 },
  ],
  'health-history': [
    { id:'h1', type:'heading', label:'Medical Conditions (check all that apply)' },
    { id:'conditions', type:'checkboxgroup', label:'Medical conditions', options:[
      'Heart disease','Diabetes','High blood pressure','Asthma / respiratory',
      'Bleeding disorder','Cancer (current or past)','HIV/AIDS','Kidney disease',
      'Osteoporosis','Thyroid disorder','Stroke','Epilepsy / seizures',
      'Artificial joints / implants','Pacemaker / heart device',
    ]},
    { id:'other_conditions', type:'textarea', label:'Other medical conditions or notes', placeholder:'List any other conditions...' },
    { id:'h2', type:'heading', label:'Medications' },
    { id:'medications', type:'textarea', label:'Current medications', placeholder:'List all current medications, vitamins, and supplements (name + dosage)' },
    { id:'h3', type:'heading', label:'Allergies (check all that apply)' },
    { id:'allergies', type:'checkboxgroup', label:'Allergies', options:[
      'Penicillin / amoxicillin','Aspirin / ibuprofen','Codeine / opioids',
      'Latex','Local anesthetic (e.g. novocaine)','Sulfa drugs','Erythromycin',
    ]},
    { id:'other_allergies', type:'text', label:'Other allergies' },
    { id:'h4', type:'heading', label:'Dental History' },
    { id:'last_dental_visit', type:'date', label:'Approximate date of last dental visit' },
    { id:'dental_concerns', type:'textarea', label:'Current dental concerns', placeholder:'What brings you in today?' },
  ],
  'hipaa-acknowledgment': [
    { id:'info1', type:'info', label:'I acknowledge that I have received a copy of this practice\'s Notice of Privacy Practices, which describes how my health information may be used and disclosed and how I can access this information. (45 CFR §164.520)' },
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'h1', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'financial-policy': [
    { id:'info1', type:'info', label:'This practice requires payment of your estimated patient portion at the time of service. Insurance benefits are assigned directly to the practice. You are responsible for any balance not covered by insurance.' },
    { id:'h1', type:'heading', label:'Assignment of Benefits' },
    { id:'insurance_auth', type:'checkboxgroup', label:'Authorization', options:[
      'I authorize this practice to bill my dental insurance directly',
      'I authorize release of information necessary to process my claim',
    ]},
    { id:'h2', type:'heading', label:'Payment Agreement' },
    { id:'payment_agree', type:'checkboxgroup', label:'Payment agreement', options:[
      'I understand I am responsible for any balance not covered by my insurance',
      'I agree to pay collection costs and attorney fees if my account is referred for collection',
    ]},
    { id:'responsible_party', type:'text', label:'Financially responsible party name', required:true },
    { id:'relationship', type:'select', label:'Relationship to patient', options:['Self','Spouse','Parent/Guardian','Other'] },
    { id:'h3', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'health-history-update': [
    { id:'info1', type:'info', label:'Please indicate any changes since your last visit.' },
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'medications_changed', type:'select', label:'Have your medications changed?', required:true, options:['No','Yes — added/removed','Yes — dosage change'] },
    { id:'medication_notes', type:'textarea', label:'If yes, list changes' },
    { id:'conditions_changed', type:'select', label:'Any new medical diagnoses or conditions?', required:true, options:['No','Yes'] },
    { id:'condition_notes', type:'textarea', label:'If yes, describe' },
    { id:'hospitalizations', type:'textarea', label:'Any hospitalizations or surgeries since last visit?', placeholder:'Leave blank if none' },
    { id:'allergies_changed', type:'select', label:'Any new allergies?', required:true, options:['No','Yes'] },
    { id:'allergy_notes', type:'text', label:'If yes, describe' },
    { id:'h1', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'insurance-update': [
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'h1', type:'heading', label:'Contact Updates (leave blank if unchanged)' },
    { id:'new_address', type:'text', label:'New street address' },
    { id:'new_city', type:'text', label:'City', cols:2 },
    { id:'new_state', type:'select', label:'State', cols:2, options:US_STATES },
    { id:'new_zip', type:'text', label:'ZIP code', cols:2 },
    { id:'new_phone', type:'tel', label:'New phone number' },
    { id:'new_email', type:'email', label:'New email address' },
    { id:'h2', type:'heading', label:'Insurance Updates (leave blank if unchanged)' },
    { id:'insurance_changed', type:'select', label:'Has your insurance changed?', options:['No','Yes — new plan','Yes — same plan new info'] },
    { id:'new_carrier', type:'text', label:'New insurance carrier' },
    { id:'new_member_id', type:'text', label:'New member ID' },
    { id:'new_group_number', type:'text', label:'New group number' },
    { id:'new_subscriber', type:'text', label:'Subscriber name (if not self)' },
    { id:'h3', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'release-of-records': [
    { id:'info1', type:'info', label:'This HIPAA-compliant authorization permits the release of your dental records to the designated provider.' },
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'h1', type:'heading', label:'Release To' },
    { id:'recipient_name', type:'text', label:'Provider or practice name', required:true },
    { id:'recipient_address', type:'text', label:'Provider address' },
    { id:'records_requested', type:'checkboxgroup', label:'Records requested', options:[
      'Full chart / treatment notes','X-rays / radiographs','Periodontal records',
      'Photographs','Referral summary','Insurance EOBs',
    ]},
    { id:'purpose', type:'textarea', label:'Purpose of disclosure', placeholder:'e.g. continuing care, second opinion...' },
    { id:'h2', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'second-opinion-request': [
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'email', type:'email', label:'Email address', required:true },
    { id:'phone', type:'tel', label:'Phone number', required:true },
    { id:'h1', type:'heading', label:'Treatment Plan Details' },
    { id:'current_dentist', type:'text', label:'Current dentist / practice' },
    { id:'treatment_proposed', type:'textarea', label:'Treatment proposed for second opinion', required:true, placeholder:'Describe the treatment plan you received...' },
    { id:'treatment_cost', type:'text', label:'Estimated cost quoted (optional)' },
    { id:'concerns', type:'textarea', label:'Specific concerns or questions', placeholder:'What would you like a second opinion on?' },
    { id:'h2', type:'heading', label:'Signature' },
    { id:'signature', type:'signature', label:'Type your full name as your electronic signature', required:true },
    { id:'sig_date', type:'date', label:'Date', required:true },
  ],
  'referral': [
    { id:'patient_name', type:'text', label:'Patient full name', required:true },
    { id:'dob', type:'date', label:'Date of birth', required:true },
    { id:'phone', type:'tel', label:'Phone number', required:true },
    { id:'h1', type:'heading', label:'Referral Information' },
    { id:'referring_dentist', type:'text', label:'Referring dentist', required:true },
    { id:'specialty', type:'select', label:'Referring to specialty', required:true, options:['Orthodontist','Periodontist','Endodontist','Oral Surgeon','Pediatric Dentist','Prosthodontist','Other'] },
    { id:'reason', type:'textarea', label:'Reason for referral', required:true, placeholder:'Describe the clinical indication...' },
    { id:'urgency', type:'select', label:'Urgency', options:['Routine','Urgent (within 1 week)','Emergency'] },
    { id:'clinical_notes', type:'textarea', label:'Clinical notes for specialist', placeholder:'Relevant history, radiographic findings, prior treatment...' },
  ],
};

// ─── POST-OP INSTRUCTION DATA ─────────────────────────────────────────────────

const POST_OP_DATA = {
  'simple-extraction': {
    title:'After Your Tooth Extraction', subtitle:'Simple (non-surgical) extraction',
    sections:[
      { h:'First 24 hours', items:[
        'Bite firmly on the gauze pad your dentist placed — 30–45 minutes without lifting to check. Replace with a fresh pad if soaked.',
        'Keep your head slightly elevated, even while resting. Lying flat increases bleeding.',
        'Apply ice packs to your cheek: 20 minutes on, 20 minutes off, for the first 6–8 hours.',
        'Do not spit, use straws, or rinse vigorously. These dislodge the blood clot and cause dry socket.',
        'Do not smoke or use any tobacco product — it dramatically increases dry socket risk.',
      ]},
      { h:'Managing bleeding', items:[
        'Some blood-tinged saliva for 24 hours is normal.',
        'Active bleeding: fold a clean gauze pad thick and bite firmly 30 minutes without checking.',
        'Alternative: bite on a moist black tea bag — tannic acid promotes clotting.',
        'Call the office or go to urgent care if heavy bleeding has not slowed after two gauze changes.',
      ]},
      { h:'Pain & swelling', items:[
        'Start ibuprofen (Advil/Motrin) 400–600 mg as soon as numbness wears off — do not wait for pain. Take every 6–8 hours with food.',
        'Alternate ibuprofen with acetaminophen (Tylenol) 500 mg every 6 hours for stronger control.',
        'If a prescription pain medication was given, use it as directed. Do not drive while taking it.',
        'Swelling peaks at 48–72 hours. Use ice first 24 hours, then warm moist heat from day 2 onward.',
      ]},
      { h:'Diet', items:[
        'Soft, cool foods today: yogurt, scrambled eggs, lukewarm soup, mashed potatoes, smoothies (no straw).',
        'Do not eat on the extraction side until numbness has fully worn off.',
        'Avoid hard, crunchy, chewy, or very hot foods and alcohol for 24–48 hours.',
        'Stay well hydrated — water is fine.',
      ]},
      { h:'Oral hygiene', items:[
        'Do not brush the extraction site today.',
        'Gently brush all other teeth as usual.',
        'From tomorrow: rinse gently with warm salt water (½ tsp salt in 8 oz warm water) after meals. Do not force-rinse.',
        'Resume flossing adjacent teeth once comfortable, usually 3–5 days.',
      ]},
      { h:'Call us immediately if', items:[
        'Heavy bleeding not slowing after two gauze changes.',
        'Severe, worsening pain at days 3–5 not controlled by medication — this may be dry socket. It is treatable; call us.',
        'Fever over 101 °F (38.3 °C).',
        'Swelling spreading toward your neck or eye.',
        'Bad taste or foul odor from the socket that is not improving.',
      ]},
    ],
    note:'Dry socket occurs in 3–5% of extractions. It is not an infection — it is loss of the protective blood clot and is treated at the office with medicated packing. Relief is rapid once treated.',
  },

  'surgical-extraction': {
    title:'After Surgical Extraction', subtitle:'Including impacted wisdom tooth removal',
    sections:[
      { h:'First 24 hours', items:[
        'Bite firmly on gauze for 45–60 minutes. Replace as needed. Blood-tinged saliva is normal.',
        'Keep head elevated 30–45 degrees, including during sleep (use an extra pillow).',
        'Ice packs to cheek: 20 min on / 20 min off for the first 24 hours.',
        'Rest completely today. No exercise, bending, heavy lifting, or strenuous activity.',
        'Do not rinse, spit, or use straws. Do not smoke or use tobacco products.',
      ]},
      { h:'Swelling & bruising', items:[
        'Swelling peaks at 48–72 hours and gradually resolves over 5–7 days.',
        'Bruising on the cheek, jaw, or neck is common — it appears day 2–3 and fades over a week.',
        'After the first 24 hours, switch from ice to warm moist heat to help resolve swelling.',
      ]},
      { h:'Pain management', items:[
        'Begin ibuprofen 600 mg every 6–8 hours with food as soon as feeling returns. Do not wait for pain.',
        'Alternate with acetaminophen 500–1,000 mg every 6 hours for better control.',
        'Prescription pain medications: use as directed. Do not drive or operate machinery.',
        'Pain that worsens significantly after day 3 instead of improving is abnormal — call us.',
      ]},
      { h:'Sutures', items:[
        'Dissolvable sutures disappear in 3–7 days. If they feel slightly loose near end of week 1, that is normal.',
        'Non-dissolving sutures require removal at your follow-up appointment (7–10 days).',
        'If sutures come out in the first 2 days, call us for assessment.',
      ]},
      { h:'Jaw stiffness (trismus)', items:[
        'Limited jaw opening and stiffness is normal after wisdom tooth removal.',
        'Beginning day 3–4: gently open and close your jaw several times daily to restore range of motion.',
        'Warm moist heat on the jaw from day 2 helps relax muscle spasm.',
        'Full opening typically returns within 2–3 weeks.',
      ]},
      { h:'Diet', items:[
        'Days 1–3: liquids and very soft foods. Avoid chewing on the surgical side.',
        'Days 3–7: soft foods — scrambled eggs, soft pasta, yogurt, soft fish, smoothies (no straw).',
        'Gradually reintroduce normal foods over 1–2 weeks as comfort allows.',
        'Avoid seeds, nuts, popcorn, and anything that could lodge in the socket.',
        'No alcohol for 48 hours, and never combined with prescription pain medication.',
      ]},
      { h:'Oral hygiene', items:[
        'Do not brush or rinse the surgical sites today.',
        'From tomorrow: gently brush all other teeth. Begin warm salt water rinses 3× daily after meals.',
        'If given an irrigation syringe, use it gently (from day 3 onward) to flush food from sockets.',
      ]},
      { h:'Call us immediately if', items:[
        'Dry socket: severe throbbing pain at days 3–5 not relieved by medication. Call us for medicated packing — relief is rapid.',
        'Fever over 101 °F or chills.',
        'Swelling increasing after day 3 rather than improving.',
        'Persistent numbness or tingling of the lip, chin, or tongue beyond 24–48 hours.',
        'Difficulty swallowing or breathing — go to the ER immediately.',
      ]},
    ],
    note:'Dry socket is more common in lower molar sockets, in smokers, and in women taking oral contraceptives. It is not dangerous and is reliably treated in office.',
  },

  'root-canal': {
    title:'After Root Canal Therapy', subtitle:'Endodontic treatment',
    sections:[
      { h:'What to expect today', items:[
        'The tooth and surrounding area will be numb for 2–4 hours after the procedure.',
        'Do not eat until the numbness has fully worn off — biting on a numb tooth can cause injury.',
        'Mild soreness in and around the tooth is normal for 2–5 days. This is post-procedural inflammation, not a sign of failure.',
        'A temporary filling or crown has been placed. Avoid hard biting on it.',
      ]},
      { h:'Pain management', items:[
        'Ibuprofen 400–600 mg every 6–8 hours with food controls post-endodontic discomfort very effectively.',
        'Alternate with acetaminophen 500–1,000 mg every 6 hours for stronger control.',
        'Pain typically peaks at 24–72 hours and then gradually improves each day.',
        'Complete any prescribed antibiotic course — even if you feel fine.',
      ]},
      { h:'Flare-ups', items:[
        'A "flare-up" — increased pain or swelling in the first 48–72 hours — occurs in 2–5% of cases. It does not mean treatment failed.',
        'Call us if you develop significant swelling, fever, or pain not improving after 3 days of consistent pain medication.',
      ]},
      { h:'Protecting the tooth — critical', items:[
        'Schedule your permanent crown within 2–4 weeks. This is the most important instruction.',
        'Root canal treatment makes the tooth significantly more brittle and prone to fracture.',
        'A tooth with only a temporary filling is at serious risk of fracture that can make it unrestorable.',
        'Avoid chewing hard, crunchy, or chewy foods on that side until the permanent crown is placed.',
        'If the temporary filling comes out, call us to have it replaced — do not leave the tooth unprotected.',
      ]},
      { h:'Call us immediately if', items:[
        'Swelling spreading into the face, gum, or neck.',
        'Fever over 101 °F.',
        'Allergic reaction to any prescribed medication.',
        'Temporary crown falls off or fractures.',
        'Pain worsening (not improving) after day 3–4 despite consistent medication.',
      ]},
    ],
    note:'Root canal success rate is 90–95% at 8–10 years. A crown is required for most posterior teeth within 30 days to prevent fracture.',
  },

  'crown': {
    title:'After Crown or Bridge', subtitle:'Preparation and final delivery',
    sections:[
      { h:'After crown preparation — temporary crown', items:[
        'A temporary crown is protecting your prepared tooth while the permanent crown is fabricated (typically 1–2 weeks).',
        'Avoid sticky foods (caramel, gum, taffy) — they pull temporaries off.',
        'Avoid hard foods (ice, nuts, hard bread crust) on the preparation side.',
        'Sensitivity to cold is normal and expected — the nerve is closer to the surface after preparation.',
        'Brush gently around the temporary. When flossing, pull the floss out sideways — not upward — to avoid dislodging it.',
        'If the temporary comes off: call us for recementation as soon as possible. In a pinch, temporary dental cement (Fixodent) from any drugstore can hold it briefly. Do not leave the prepared tooth exposed.',
      ]},
      { h:'After permanent crown delivery', items:[
        'Cement sets fully within 1–2 hours — avoid sticky foods today.',
        'Mild bite sensitivity or pressure sensitivity for 1–2 weeks is normal.',
        'Cold sensitivity may continue for 2–4 weeks and gradually resolves.',
        'If your bite feels "high" — hitting the crown before your other teeth when closing — call for a quick bite adjustment. Do not leave an uncorrected high bite for more than a few days.',
      ]},
      { h:'Long-term care', items:[
        'Brush and floss the crown daily. The crown-to-gum margin is vulnerable to decay — floss thoroughly.',
        'Avoid habitually chewing ice, pens, or fingernails.',
        'A night guard is recommended if you grind or clench — grinding dramatically shortens crown lifespan.',
        'Crowns typically last 10–20 years with good oral hygiene and regular maintenance.',
      ]},
      { h:'Call us if', items:[
        'Bite still feels significantly high after 1–2 weeks.',
        'Crown fractures, chips, or comes off.',
        'Cold sensitivity is not improving after 4 weeks.',
        'Sensitivity to heat develops — this may indicate the nerve is inflamed and a root canal could be needed.',
        'Gum swelling, pain, or discharge around the crown.',
      ]},
    ],
    note:'Temporary crown sensitivity is normal. Heat sensitivity (distinct from cold) is less common and should be reported promptly.',
  },

  'implant': {
    title:'After Dental Implant Surgery', subtitle:'Implant placement',
    sections:[
      { h:'First 24 hours', items:[
        'Bite firmly on the gauze pad placed by your surgeon for 45–60 minutes.',
        'Blood-tinged saliva for 24–48 hours is normal.',
        'Keep head elevated — even during rest and sleep (use an extra pillow).',
        'Ice packs to cheek: 20 min on / 20 min off for 24 hours.',
        'Do not touch the implant site with your tongue or fingers.',
        'Do not rinse, spit, or use straws today.',
        'Rest completely. No bending, lifting, or exercise.',
      ]},
      { h:'Smoking — critical', items:[
        'Do not smoke. This is the most important modifiable risk factor for implant failure.',
        'Smoking reduces blood supply to healing bone and doubles the implant failure rate.',
        'Even smokeless tobacco and e-cigarettes are harmful during osseointegration.',
        'Ideally: quit permanently. At minimum: abstain for 8 weeks around surgery.',
      ]},
      { h:'Medications', items:[
        'Antibiotic: take the complete prescribed course. Do not stop early.',
        'Chlorhexidine 0.12% rinse (Peridex): begin the morning after surgery, rinse gently twice daily as prescribed.',
        'Ibuprofen 600 mg every 6–8 hours with food for the first 3–5 days manages pain and surgical inflammation.',
        'If your surgeon asked you to avoid NSAIDs: use acetaminophen 500–1,000 mg instead.',
      ]},
      { h:'Diet', items:[
        'Weeks 1–4: soft foods only. Nothing that requires biting pressure through the implant site.',
        'Do not place direct chewing pressure on the implant during osseointegration.',
        'Gradually reintroduce normal foods only after your surgeon confirms integration (typically 3–6 months).',
        'Avoid alcohol for 48 hours, and never combined with prescription medication.',
      ]},
      { h:'Oral hygiene', items:[
        'Day 1: do not brush the implant site.',
        'Day 2 onward: brush all other teeth gently. Use prescribed chlorhexidine rinse.',
        'After week 1: gentle brushing around the implant with a soft brush and very little pressure.',
        'Use floss or interdental brushes around the implant once initial healing is confirmed.',
      ]},
      { h:'Osseointegration period (3–6 months)', items:[
        'The implant is fusing with your jawbone during this period. Protect it from trauma.',
        'The implant should never feel mobile. If you feel movement: call us immediately.',
        'You will be seen at 7–10 days post-op, then periodically until integration is confirmed by x-ray.',
      ]},
      { h:'Call us immediately if', items:[
        'Heavy bleeding not controlled with firm gauze pressure.',
        'The implant feels loose at any point.',
        'Swelling significantly increasing after day 3.',
        'Fever over 101 °F.',
        'Pus or persistent bad taste or odor from the site.',
        'Sutures falling out in the first 3 days.',
      ]},
    ],
    note:'Osseointegration success is approximately 95% at 10 years. Smoking, uncontrolled diabetes, bisphosphonate medications, and inadequate bone volume are the primary risk factors for failure.',
  },

  'bone-graft': {
    title:'After Bone Grafting / Socket Preservation', subtitle:'Allograft, xenograft, or autograft',
    sections:[
      { h:'Critical — protect the graft', items:[
        'Do not probe, push on, or touch the graft site with your tongue or fingers.',
        'Small white graft granules in your mouth during the first few days are normal — rinse gently; do not forcibly remove them.',
        'A collagen membrane or sutures cover the graft. Do not disturb it.',
        'Avoid any pressure, stretching, or trauma over the graft site.',
      ]},
      { h:'First 24 hours', items:[
        'Do not spit, rinse vigorously, or use straws.',
        'Keep head elevated. Rest.',
        'Apply ice packs: 20 min on / 20 min off.',
        'Some blood-tinged saliva is expected.',
      ]},
      { h:'Medications', items:[
        'Complete the full antibiotic course — it is essential for graft protection against infection.',
        'Pain control: acetaminophen 500–1,000 mg every 6 hours is preferred for the first 2 weeks.',
        'Avoid ibuprofen and NSAIDs for the first 2 weeks — they may impair bone formation.',
        'Chlorhexidine 0.12% rinse as prescribed is critical for preventing infection.',
      ]},
      { h:'Diet', items:[
        'Very soft foods for 2–4 weeks — nothing requiring chewing over the graft site.',
        'No hard, crunchy, sharp, or chewy foods.',
        'No seeds, nuts, or foods that could penetrate or displace the membrane.',
        'Avoid temperature extremes. Stay hydrated.',
      ]},
      { h:'Smoking', items:[
        'Do not smoke during graft healing — it is the single most significant modifiable risk factor for graft failure.',
        'Nicotine constricts blood vessels and profoundly reduces healing blood supply.',
      ]},
      { h:'Call us if you notice', items:[
        'Large quantities of graft granules coming out of the socket (minor loss is normal).',
        'Membrane or sutures becoming significantly exposed in the first week.',
        'Fever over 101 °F.',
        'Significant swelling increasing after day 3.',
        'Pus, foul taste, or foul odor from the site.',
      ]},
    ],
    note:'Bone grafts require 3–6 months of healing before implant placement can be evaluated by x-ray or CBCT.',
  },

  'perio-surgery': {
    title:'After Periodontal Surgery', subtitle:'Osseous surgery, flap procedure, or LANAP',
    sections:[
      { h:'First 24 hours', items:[
        'Rest with head elevated. No strenuous exercise or physical exertion.',
        'Ice packs to the face over the treated area: 20 min on / 20 min off.',
        'Do not spit, rinse forcefully, or use straws.',
        'Some bleeding and oozing is expected and should slow within a few hours.',
      ]},
      { h:'Medications & chlorhexidine rinse', items:[
        'Chlorhexidine gluconate 0.12% (Peridex): rinse gently for 30 seconds twice daily — morning and night. Do not swallow.',
        'Use as prescribed for 2–4 weeks. It will stain teeth slightly; this is temporary and polishable at your next cleaning.',
        'Complete any prescribed antibiotic course.',
        'Ibuprofen 400–600 mg or prescribed pain medication as directed for pain and inflammation.',
      ]},
      { h:'Diet', items:[
        'Soft, non-abrasive diet for 1–2 weeks in the treated area.',
        'Avoid hard, crunchy, sharp, or spicy foods.',
        'No alcohol while taking prescription medications.',
        'Stay hydrated.',
      ]},
      { h:'Oral hygiene', items:[
        'Do not brush or floss the treated area until sutures are removed (usually 7–10 days).',
        'Continue normal brushing and flossing in all untreated areas.',
        'After suture removal: resume very gentle brushing with a soft brush over treated areas.',
        'Flossing in treated areas: resume only after clearance from your provider at the follow-up visit.',
      ]},
      { h:'What to expect', items:[
        'Swelling and bruising peak at 48–72 hours and resolve over 5–7 days.',
        'Gum recession after surgery is expected — it reflects removal of diseased tissue and is intended.',
        'Root sensitivity to cold is common and typically decreases over weeks.',
        'Some slight tooth mobility may occur temporarily; this usually resolves.',
      ]},
      { h:'Call us if you notice', items:[
        'Sutures coming out in the first 2 days.',
        'Swelling worsening after day 3 rather than improving.',
        'Fever over 101 °F.',
        'Significant uncontrolled bleeding.',
        'Abscess formation or pus discharge.',
      ]},
    ],
    note:'Post-surgical periodontal maintenance every 3–4 months (not every 6) is essential for long-term results. Returning to annual care intervals after periodontal surgery significantly increases disease recurrence.',
  },

  'srp': {
    title:'After Scaling and Root Planing', subtitle:'Deep cleaning / periodontal therapy',
    sections:[
      { h:'Right after the appointment', items:[
        'Numbness from local anesthetic will last 2–4 hours. Avoid eating on the treated side until it fully wears off.',
        'Some bleeding and soreness in the gums today is normal and expected.',
        'Ibuprofen 400 mg as needed for discomfort.',
      ]},
      { h:'Over the next 1–4 weeks', items:[
        'Root sensitivity to cold is expected and typically improves over 2–4 weeks.',
        'Gums may appear to have receded slightly — this is normal swelling resolving.',
        'Use a desensitizing toothpaste (Sensodyne) if sensitivity is bothersome.',
        'If a prescription-strength fluoride toothpaste was given, use it nightly as directed.',
      ]},
      { h:'Chlorhexidine rinse protocol', items:[
        'Chlorhexidine rinse as prescribed: twice daily for 2 weeks.',
        'Rinse may stain teeth slightly — this is temporary and removed at your next cleaning.',
        'Do not use chlorhexidine at the same time as regular toothpaste — separate by 30 minutes (toothpaste neutralizes the rinse).',
      ]},
      { h:'Oral hygiene', items:[
        'Resume normal brushing and flossing — do not avoid the treated areas.',
        'Gentle but thorough brushing at the gum line is essential for healing.',
        'Use a soft-bristled or electric toothbrush.',
        'Floss daily — this is critical for periodontal health.',
      ]},
      { h:'Follow-up — critical', items:[
        'Your 4–6 week re-evaluation appointment is essential. Please keep it.',
        'This visit assesses healing and determines whether additional treatment (surgery or further SRP) is needed.',
        'After SRP: periodontal maintenance visits every 3–4 months are required — not the standard 6-month interval.',
      ]},
      { h:'Call us if you notice', items:[
        'Severe pain not responding to OTC pain medication.',
        'Gum abscess or significant swelling.',
        'Fever.',
        'Significant bleeding lasting more than 24 hours.',
      ]},
    ],
    note:'SRP improves periodontal pocket depths in most patients. Without consistent maintenance at 3–4 month intervals, disease typically recurs within 3–6 months.',
  },

  'filling': {
    title:'After Composite Filling Placement', subtitle:'White (resin) restoration',
    sections:[
      { h:'Right after the appointment', items:[
        'Composite resin is light-cured and fully set immediately — there is no waiting period for the material.',
        'However, the area is numb: wait until numbness fully wears off (2–4 hours) before eating on the filled side.',
        'Biting a numb area can cause injury without you realizing it.',
      ]},
      { h:'Bite adjustment', items:[
        'The filled tooth may feel slightly "high" when biting — this is common and often settles within 1–2 days.',
        'If your bite feels significantly off, or you consistently hit that tooth first when closing: call for a quick adjustment. It takes 5 minutes.',
        'Do not leave a significantly high bite unadjusted beyond 1–2 days — it causes jaw soreness and worsening sensitivity.',
      ]},
      { h:'Sensitivity', items:[
        'Sensitivity to cold, pressure, or sweets after a filling is normal.',
        'Typically peaks during week 1 and gradually decreases over 2–6 weeks.',
        'Deep fillings near the nerve may be more sensitive and take longer to settle.',
        'Sensitivity to heat (hot liquids) is less common. If it develops, the nerve may be inflamed and a root canal could be indicated — call us.',
      ]},
      { h:'Diet', items:[
        'No special diet restrictions once numbness wears off.',
        'If the area is very sensitive, avoid temperature extremes temporarily.',
      ]},
      { h:'Call us if you notice', items:[
        'Bite still feels high after 2 weeks.',
        'Sensitivity to heat (not just cold).',
        'Sensitivity worsening, not improving, after 4–6 weeks.',
        'Filling feels rough, has a sharp edge, or chips.',
        'Sharp pain when biting directly on the tooth.',
      ]},
    ],
    note:'Composite fillings last 7–10+ years with good oral hygiene. Grinding or clenching (bruxism) significantly reduces longevity — discuss a night guard if this applies.',
  },

  'whitening': {
    title:'After Teeth Whitening', subtitle:'In-office or take-home bleaching',
    sections:[
      { h:'White diet — first 48 hours', items:[
        'Teeth are temporarily more porous immediately after whitening and absorb pigment easily.',
        'Avoid for 48 hours: coffee, tea, red wine, dark juices (grape, cranberry, beet), berries, soy sauce, curry, tomato sauce, dark chocolate, mustard.',
        'Safe foods: water, still or sparkling; chicken, fish, white rice, pasta (no dark sauce), white bread, bananas, apples (peeled), plain yogurt, cauliflower.',
        'No tobacco products — they stain and undermine results.',
      ]},
      { h:'Managing sensitivity', items:[
        'Tooth sensitivity during or after whitening is the most common side effect and is temporary.',
        'Use a desensitizing toothpaste (Sensodyne) twice daily.',
        'Ibuprofen or acetaminophen for discomfort if needed.',
        'Take-home gel users: if sensitivity is severe, skip 1–2 days then resume.',
        'Sensitivity resolves within 24–72 hours for most patients.',
      ]},
      { h:'Take-home tray instructions', items:[
        'Load a small, pea-size amount of gel into each tray compartment — do not overfill.',
        'Seat trays carefully; wipe away any gel that contacts the gum tissue.',
        'Wear time: follow your dentist\'s instructions (typically 30–60 min daytime, or overnight if prescribed for lower-concentration gel).',
        'After each session: rinse mouth and trays thoroughly. Store clean trays dry in the case.',
      ]},
      { h:'Maintaining results', items:[
        'Results typically last 6–18 months depending on dietary habits and oral hygiene.',
        'Touch-up: use trays for 1–2 nights every 6–12 months to maintain the shade.',
        'Crowns, veneers, and composite bonding will not whiten — they may need replacement to match a significantly lighter shade.',
      ]},
    ],
    note:'Whitening products contain hydrogen peroxide or carbamide peroxide. They affect only natural tooth enamel. Exposed dentin and existing restorations do not bleach.',
  },

  'veneers': {
    title:'After Veneer Preparation & Delivery', subtitle:'Porcelain or composite veneers',
    sections:[
      { h:'After veneer preparation — temporary veneers', items:[
        'Your teeth have been prepared (enamel reduced). Temporaries protect them while permanents are fabricated.',
        'Temporary veneers are fragile — avoid sticky foods, hard foods, and biting into anything hard.',
        'Significant cold and pressure sensitivity during the temporary phase is expected.',
        'If a temporary comes off, call us immediately. Keep it in a small bag. In a pinch, dental adhesive (Fixodent) provides temporary hold.',
        'Do not judge the final appearance from the temporaries — the final veneers will look different.',
      ]},
      { h:'After permanent veneer delivery', items:[
        'Permanent veneers are bonded and will not come off with normal function.',
        'Mild bite sensitivity or pressure sensitivity for 1–2 weeks is normal.',
        'Your bite may feel slightly different for 1–2 weeks as you adapt.',
        'If the bite feels significantly off, call for an adjustment.',
      ]},
      { h:'Protecting your veneers', items:[
        'Do not bite fingernails, pens, ice, or hard objects with your veneered teeth.',
        'Wear a custom night guard if you grind or clench — bruxism is the most common cause of veneer fracture.',
        'Use a non-abrasive toothpaste (avoid whitening toothpastes with high abrasive content).',
        'Veneers resist decay, but the margin where veneer meets tooth is vulnerable — floss daily.',
      ]},
      { h:'Long-term care', items:[
        'Porcelain veneers: expected lifespan 10–20 years with good care and night guard use.',
        'Avoid excessive staining beverages; veneer porcelain resists staining well but cement margins can discolor.',
        'Attend regular cleanings. Inform your hygienist that you have veneers — avoid air abrasion or harsh metal instruments on them.',
      ]},
      { h:'Call us if', items:[
        'A veneer fractures, chips, or debonds.',
        'Sensitivity to heat develops.',
        'Bite feels significantly wrong after 2 weeks.',
        'Gum swelling at the veneer margin.',
      ]},
    ],
    note:'Veneer preparation is irreversible. Failure to wear a night guard in bruxers significantly increases fracture risk.',
  },

  'aligners': {
    title:'Clear Aligner / Invisalign Instructions', subtitle:'Starting treatment',
    sections:[
      { h:'Wear protocol — critical', items:[
        'Wear aligners 20–22 hours per day, minimum. Less than this slows or stalls treatment.',
        'Remove aligners only to eat, drink anything other than plain cold water, and to brush and floss.',
        'Even small daily gaps compound — patients who wear consistently finish on time or early.',
      ]},
      { h:'Eating and drinking', items:[
        'Always remove aligners before eating. Always.',
        'Eating with aligners in warps them and stains them permanently.',
        'Remove before all beverages except plain cold or room-temperature water.',
        'Hot beverages (coffee, tea) can warp aligners — always remove them first.',
        'Rinse your mouth before reinserting aligners after meals.',
      ]},
      { h:'Soreness with each new set', items:[
        'Each new aligner set produces pressure and soreness for 1–3 days. This is normal and expected.',
        'The pressure indicates the aligners are working.',
        'Ibuprofen or acetaminophen as needed.',
        'Pro tip: insert new aligners at night so you sleep through the first hours of soreness.',
      ]},
      { h:'Attachments (buttons)', items:[
        'Small tooth-colored resin attachments help aligners grip and move teeth precisely.',
        'You will feel them initially — this is normal and fades quickly.',
        'If an attachment falls off, call us — some are critical. Continue wearing the aligner.',
      ]},
      { h:'Aligner hygiene', items:[
        'Clean aligners morning and night: rinse with lukewarm (not hot) water and brush gently with a soft toothbrush.',
        'Do not use toothpaste on aligners — it scratches and clouds them. Use Retainer Brite, Invisalign cleaning crystals, or a drop of clear dish soap.',
        'Do not soak in mouthwash — it stains them.',
        'Always store in the provided case — not wrapped in napkins or in your pocket.',
      ]},
      { h:'Advancing trays', items:[
        'Change to the next aligner on the schedule your provider gave you (typically every 7–14 days).',
        'Always save every previous aligner set — if a current set breaks or is lost, wear the previous one and call us.',
        'If the current set no longer fits snugly before you are due to advance, call us.',
      ]},
      { h:'IPR (interproximal reduction)', items:[
        'Mild sensitivity for 1–3 days after IPR appointments is normal.',
        'IPR creates micro-spaces between teeth that allow planned tooth movement.',
      ]},
    ],
    note:'Treatment duration depends heavily on wear compliance. Refinement aligners (additional trays to fine-tune the result) are common and expected — they do not indicate treatment failure.',
  },

  'nitrous': {
    title:'After Nitrous Oxide', subtitle:'Laughing gas (nitrous oxide/oxygen)',
    sections:[
      { h:'Recovery', items:[
        'Nitrous oxide is cleared from your system through breathing within 5–10 minutes of receiving pure oxygen at the end of your appointment.',
        'You should feel fully normal within 10–15 minutes of the mask being removed.',
        'Mild light-headedness or brief nausea is possible and self-resolving.',
      ]},
      { h:'Activity', items:[
        'You may drive immediately after your appointment if you feel completely normal.',
        'Normal diet, work, and activity may resume immediately.',
        'No restrictions on decisions, driving, or work — nitrous oxide leaves the system completely and quickly.',
      ]},
      { h:'If you felt nauseated', items:[
        'Remain seated until the feeling fully passes before standing.',
        'Eat a light meal before your next appointment to reduce nausea risk.',
        'Mention nausea to your dentist before future appointments — the dose or flow rate may need adjustment.',
      ]},
    ],
    note:'Unlike oral or IV sedation, nitrous oxide does not impair driving or decision-making after the oxygen flush. It is safe for most adults and children. Contraindicated in MTHFR mutation, B12 deficiency, first-trimester pregnancy, and severe COPD.',
  },

  'oral-sedation': {
    title:'After Oral Sedation', subtitle:'Prescription oral sedative medication',
    sections:[
      { h:'Transportation — non-negotiable', items:[
        'You must be driven home by a responsible adult. You may not drive or travel alone.',
        'Do not drive or operate any vehicle for 24 hours after oral sedation.',
      ]},
      { h:'Today — restrictions', items:[
        'Rest at home today. Light activities only.',
        'No driving, alcohol, other sedatives, or recreational substances for 24 hours.',
        'No important decisions, financial transactions, or signing legal documents today.',
        'No operating power tools, machinery, or cooking over an open flame.',
      ]},
      { h:'Diet', items:[
        'Begin with liquids or soft foods — nausea is possible after oral sedation.',
        'Gradually advance to normal foods as tolerated.',
        'Stay well hydrated.',
      ]},
      { h:'Amnesia — what is normal', items:[
        'It is normal to have limited or no memory of the procedure — this is the intended amnestic effect.',
        'This does not mean anything went wrong.',
        'Your treatment was completed as planned.',
      ]},
      { h:'Drowsiness timeline', items:[
        'Drowsiness may persist 6–12 hours or longer depending on the medication, dose, and your metabolism.',
        'Rest if you feel tired.',
        'Full alertness should return within 12–24 hours.',
      ]},
      { h:'Call us if', items:[
        'Severe confusion or inability to be roused past 12 hours.',
        'Severe or persistent nausea and vomiting.',
        'Allergic reaction: rash, hives, throat swelling, difficulty breathing — call 911 if severe.',
      ]},
    ],
    note:'Common dental oral sedatives include triazolam (Halcion), diazepam (Valium), and lorazepam. Do not take any of these medications outside of dental supervision.',
  },

  'iv-sedation': {
    title:'After IV / Deep Sedation', subtitle:'Intravenous sedation or general anesthesia',
    sections:[
      { h:'Transportation — non-negotiable', items:[
        'You must be driven home and supervised by a responsible adult.',
        'Do not drive or operate any vehicle for 24 hours after IV sedation.',
        'A companion should remain with you for at least 4–6 hours after the procedure.',
      ]},
      { h:'Today — restrictions', items:[
        'Rest today. Light activity only.',
        'No driving, alcohol, sedatives, or important decisions for 24 hours.',
        'No operating machinery, cooking over open flame, or signing legal documents.',
        'Resume normal medications unless explicitly told otherwise by your provider.',
      ]},
      { h:'Nausea and eating', items:[
        'Begin with clear liquids (water, broth, apple juice). Progress to soft foods.',
        'Mild nausea is common and typically resolves within a few hours.',
        'If nausea is severe or you cannot hold liquids down 4+ hours after the procedure, call us.',
      ]},
      { h:'IV site', items:[
        'The IV insertion site (usually inner elbow or back of hand) may be bruised or tender for a few days.',
        'Apply a warm compress 20 minutes several times daily if sore.',
        'Significant swelling, hardness, or spreading redness at the IV site: call us.',
      ]},
      { h:'Recovery timeline', items:[
        'Grogginess typically clears within 4–8 hours.',
        'Full mental clarity returns within 12–24 hours.',
        'Fatigue lasting 24–48 hours after deep sedation is normal.',
      ]},
      { h:'Call us immediately if', items:[
        'Difficulty breathing or chest tightness.',
        'Inability to be roused or extreme grogginess past 12 hours.',
        'Severe nausea or vomiting lasting more than 4 hours.',
        'High fever (over 101 °F) within 24 hours of sedation.',
        'Signs of allergic reaction: rash, hives, throat or tongue swelling — call 911 if breathing is affected.',
      ]},
    ],
    note:'IV sedation in dental offices is conducted under ASA monitoring guidelines with continuous pulse oximetry and blood pressure monitoring. Pre-operative fasting is required — follow your provider\'s specific pre-op instructions.',
  },

  'frenectomy': {
    title:'After Frenectomy', subtitle:'Lip tie or tongue tie (frenulum) release',
    sections:[
      { h:'First 24 hours', items:[
        'Some bleeding is normal — apply gentle gauze pressure for 10–15 minutes.',
        'For labial (lip) frenectomy: ice to the outside of the lip for the first few hours.',
        'Soft foods only today.',
        'Avoid spitting, vigorous rinsing, or straws.',
      ]},
      { h:'Stretching exercises — critical for preventing reattachment', items:[
        'Stretching exercises are typically prescribed beginning 24–48 hours after surgery.',
        'Perform the prescribed stretch 4–6 times daily for 3–4 weeks as instructed.',
        'This is the most important step in ensuring a successful outcome.',
        'Reattachment of the frenulum in a restrictive position is the most common complication and is preventable with consistent stretching.',
        'Your provider will show you exactly how — follow their demonstration precisely.',
      ]},
      { h:'Wound appearance', items:[
        'The wound site may appear white, yellow, or grey — this is normal fibrin (healing tissue), not infection.',
        'Full healing typically occurs in 7–14 days.',
      ]},
      { h:'Breastfeeding (for infant procedures)', items:[
        'Breastfeeding can usually resume within 1–2 hours of the procedure.',
        'Latch may initially feel different — improvement often takes 1–2 weeks as the infant learns new tongue mechanics.',
        'Working with a lactation consultant optimizes feeding outcomes after release.',
      ]},
      { h:'Speech and tongue function', items:[
        'Temporary changes in speech or tongue movement after tongue tie release are common and resolve as healing progresses.',
        'Speech therapy follow-up (if recommended) should begin 4–6 weeks after healing for best results.',
      ]},
      { h:'Call us if', items:[
        'Heavy bleeding not controlled with firm gauze pressure for 15 minutes.',
        'Significant swelling or spreading redness after day 3.',
        'Fever over 101 °F.',
        'Wound appears to be closing with obvious reattachment before day 14.',
      ]},
    ],
    note:'Frenectomy results depend significantly on consistent completion of the prescribed stretching exercises. Skipping stretches is the primary cause of the frenulum reattaching in a restricted position.',
  },

  'sinus-lift': {
    title:'After Sinus Lift (Sinus Elevation)', subtitle:'Internal or lateral window sinus augmentation',
    sections:[
      { h:'CRITICAL — do not blow your nose', items:[
        'DO NOT blow your nose for a minimum of 4 weeks. This is the single most important instruction.',
        'Nose-blowing creates pressure that can dislodge the graft from the sinus or rupture the sinus membrane.',
        'If you need to sneeze: let it out through your MOUTH with your mouth open. Do not suppress a sneeze — it increases pressure more than sneezing openly.',
        'Even a single gentle nose-blow can damage the graft.',
      ]},
      { h:'Nasal and sinus care', items:[
        'Use the prescribed nasal decongestant (spray or oral Sudafed) as directed for the first 1–2 weeks.',
        'Blood-tinged nasal mucus or drainage for the first 24–48 hours is normal.',
        'Sinus congestion, pressure, and stuffiness is expected for 2–4 weeks.',
        'Sleep with your head slightly elevated for the first week.',
      ]},
      { h:'Activity and pressure restrictions', items:[
        'No scuba diving for 4 weeks.',
        'Avoid air travel for 2–4 weeks if possible (altitude creates sinus pressure changes).',
        'No strenuous exercise for 1 week.',
        'Avoid any activity that creates sinus pressure changes (wind instruments, heavy lifting, forceful nose blowing) for 4 weeks.',
      ]},
      { h:'Medications', items:[
        'Complete the full antibiotic course.',
        'Chlorhexidine rinse as prescribed.',
        'Ibuprofen or prescribed pain medication as directed.',
        'Prescribed nasal spray or decongestant: use exactly as directed.',
      ]},
      { h:'Diet and oral care', items:[
        'Soft diet for 1–2 weeks. Avoid hard or crunchy foods.',
        'Do not use straws.',
        'Do not disturb the upper surgical site.',
        'Gentle salt water rinse from the morning after surgery.',
      ]},
      { h:'Call us immediately if', items:[
        'White graft granules appearing through your nostril or in nasal discharge.',
        'Nasal bleeding beyond 48 hours.',
        'Fever over 101 °F.',
        'Sinus pressure or pain significantly increasing after day 5.',
        'Persistent clear fluid from the nose (could indicate membrane issue — call immediately).',
      ]},
    ],
    note:'Sinus lift augmentation requires 4–6 months of graft maturation before implant placement can be evaluated. Sinus membrane perforations, if they occur during surgery, are managed intraoperatively.',
  },

  'apicoectomy': {
    title:'After Apicoectomy', subtitle:'Root-end surgery (periradicular surgery)',
    sections:[
      { h:'First 24 hours', items:[
        'Apply ice packs immediately after returning home: 20 minutes on, 20 minutes off for 6–8 hours.',
        'Keep head elevated.',
        'Rest completely. No vigorous activity or exercise.',
        'Do not spit, rinse forcefully, or use straws.',
      ]},
      { h:'Swelling & bruising', items:[
        'Swelling is normal and often more extensive on the face than expected.',
        'It peaks at 48–72 hours and resolves over 5–7 days.',
        'Bruising (ecchymosis) on the cheek or below the eye is common and harmless — it appears on days 2–3.',
        'After the first 24 hours, switch from ice to warm moist heat to help resolve swelling.',
      ]},
      { h:'Pain management', items:[
        'Pain after apicoectomy is typically less than patients expect.',
        'Ibuprofen 600 mg every 6–8 hours with food is usually very effective.',
        'Alternate with acetaminophen 500–1,000 mg every 6 hours for stronger control.',
        'Take any prescribed medications as directed.',
      ]},
      { h:'Sutures', items:[
        'Sutures are placed and removed at your follow-up appointment in 7–10 days.',
        'Do not probe or pull on sutures with your tongue.',
        'Slight loosening near the end of week 1 is normal.',
      ]},
      { h:'Diet', items:[
        'Soft diet for 1 week. Avoid chewing on the surgical side.',
        'No hard, crunchy, or chewy foods.',
        'Avoid very hot foods and beverages.',
        'Stay well hydrated.',
      ]},
      { h:'Oral hygiene', items:[
        'Do not brush the surgical site until sutures are removed.',
        'Brush and floss all other areas normally.',
        'Gentle warm salt water rinse beginning 24 hours after the procedure, 3× daily.',
      ]},
      { h:'Call us if', items:[
        'Swelling significantly worsening after day 3.',
        'Fever over 101 °F.',
        'Sutures coming out in the first 3 days.',
        'Persistent metallic taste at the site.',
        'Do not smoke — it significantly impairs healing.',
      ]},
    ],
    note:'Apicoectomy success is approximately 85–97% at 5 years. Healing of the periapical lesion is confirmed by x-ray at 6–12 months post-surgery.',
  },
};

// ─── FORMS DIRECTORY ─────────────────────────────────────────────────────────

// ── Bucket-first layout: pick a need, then see only the relevant forms ──────
const BUCKETS = [
  { id:'new-patient',    title:"I'm a new patient",        desc:'Registration, health history, HIPAA, financial — everything for your first visit.', accent:'var(--seal)' },
  { id:'post-op',        title:'I just had a procedure',    desc:'Recovery instructions for 18 procedures. Print or email to yourself.',              accent:'#6B8E23'    },
  { id:'specific',       title:'I have a specific form',    desc:'Consent forms, return-patient updates, records release, referrals.',                accent:'var(--ink-1)'},
];

function FormsDirectory({ go, state, set }) {
  // _catFilter (set by deep links from snapshot / hero chips) selects the bucket
  // up-front. Default view shows the 3 bucket cards.
  const initialBucket = state && (state._catFilter === 'post-op' ? 'post-op'
                              : state._catFilter === 'new-patient' ? 'new-patient'
                              : state._catFilter ? 'specific' : null);
  const [bucket, setBucket] = useFS(initialBucket);
  const [cat, setCat] = useFS((state && state._catFilter) || 'all');
  const [q, setQ] = useFS('');
  const dentist = state && state._selectedDentist;

  // Which forms to show, given the active bucket:
  // - new-patient bucket → only new-patient forms, ordered
  // - post-op bucket → only post-op
  // - specific bucket → everything except new-patient + post-op, with sub-filter + search
  const inBucket = (f) => {
    if (bucket === 'new-patient') return f.cat === 'new-patient';
    if (bucket === 'post-op')     return f.cat === 'post-op';
    if (bucket === 'specific') {
      if (cat === 'all') return f.cat !== 'new-patient' && f.cat !== 'post-op';
      return f.cat === cat;
    }
    return false;
  };

  const filtered = FORM_CATALOG.filter(f => {
    if (!inBucket(f)) return false;
    if (q) {
      const lq = q.toLowerCase();
      return f.title.toLowerCase().includes(lq) || (f.desc||'').toLowerCase().includes(lq);
    }
    return true;
  });

  const prefill = {
    zip: state && state.zip,
    insurance: state && state.insurance,
    lang: state && state.language,
    dentist_npi: dentist && dentist.npi,
    dentist_name: dentist && dentist.name,
  };

  function openForm(f) {
    window.Enc?.openedForm(f);
    if (f.type === 'native') {
      if (set) set(s => ({ ...s, _selectedForm: f }));
      go('form-viewer');
    } else if (f.type === 'consent') {
      if (set) set(s => ({ ...s, _selectedForm: f }));
      go('form-viewer');
    } else if (f.type === 'post-op') {
      if (set) set(s => ({ ...s, _selectedPostOp: f.procedure }));
      go('post-op');
    }
  }

  const ctaLabel = (f) => {
    if (f.type === 'native')  return 'Fill out form →';
    if (f.type === 'consent') return 'View & print →';
    if (f.type === 'post-op') return 'View instructions →';
    return 'Open →';
  };

  return (
    <div className="app">
      <Masthead lang={state && state.lang} setLang={()=>{}} go={go}/>
      <main>
        <div className="container">
          <Breadcrumbs crumbs={[{label:'Home',screen:'landing'},{label:'Patient forms'}]} go={go}/>

          <div style={{padding:'var(--s-2) 0 var(--s-4)'}}>
            <div className="t-eyebrow" style={{marginBottom:6}}>Patient forms</div>
            <h1 className="section-h" style={{margin:0}}>What do you need today?</h1>
            {dentist && (
              <div style={{marginTop:'var(--s-3)',padding:'var(--s-3) var(--s-4)',background:'var(--sage)',color:'var(--paper)',borderRadius:'var(--r-3)',fontSize:14,display:'flex',alignItems:'center',gap:10}}>
                <Icon d={ICONS.pin} size={16}/>
                <span>Pre-filled for <strong>{dentist.name}</strong> · {dentist.practice}</span>
                <button onClick={()=>{ if(set)set(s=>({...s,_selectedDentist:null})); }}
                  style={{marginLeft:'auto',background:'transparent',border:'none',color:'inherit',cursor:'pointer',fontSize:13,opacity:0.8}}>Clear ×</button>
              </div>
            )}
          </div>

          {/* ── Survey CTA — always visible above the bucket grid ── */}
          {!bucket && (
            <div style={{marginBottom:'var(--s-6)',padding:'var(--s-4) var(--s-5)',background:'var(--bone)',borderRadius:'var(--r-4)',border:'1px solid var(--ink-5)',display:'flex',alignItems:'center',justifyContent:'space-between',gap:'var(--s-4)',flexWrap:'wrap'}}>
              <div>
                <div className="t-eyebrow" style={{marginBottom:3}}>Already had your visit?</div>
                <div style={{fontSize:15,fontWeight:500,color:'var(--ink-1)'}}>Tell us how it went — your feedback shapes Verified Performance Scores.</div>
              </div>
              <Button variant="ghost" size="sm"
                style={{color:'var(--seal)',borderColor:'var(--seal)',flexShrink:0}}
                onClick={()=>go('survey')}>Rate my visit →</Button>
            </div>
          )}

          {/* ── Step 1: pick a bucket ── */}
          {!bucket && (
            <div style={{
              display:'grid',
              gridTemplateColumns:'repeat(auto-fit, minmax(260px, 1fr))',
              gap:'var(--s-4)',
              marginBottom:'var(--s-12)',
            }}>
              {BUCKETS.map(b => (
                <button key={b.id} type="button"
                  onClick={()=>{ setBucket(b.id); setCat(b.id === 'specific' ? 'all' : b.id); }}
                  style={{
                    textAlign:'left', padding:'var(--s-6)', background:'var(--paper)',
                    border:'1px solid var(--ink-5)', borderRadius:'var(--r-5)', cursor:'pointer',
                    display:'flex', flexDirection:'column', gap:'var(--s-2)',
                  }}>
                  <h3 style={{margin:0,fontFamily:'var(--font-display)',fontSize:22,fontWeight:500,color:b.accent}}>{b.title}</h3>
                  <p style={{margin:0,fontSize:14,color:'var(--ink-2)',lineHeight:1.55}}>{b.desc}</p>
                  <span style={{marginTop:'auto',paddingTop:8,fontSize:13,fontWeight:500,color:b.accent}}>Continue →</span>
                </button>
              ))}
            </div>
          )}

          {/* ── Step 2: filtered list ── */}
          {bucket && (
            <>
              <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',gap:'var(--s-3)',marginBottom:'var(--s-4)',flexWrap:'wrap'}}>
                <div>
                  <div className="t-eyebrow" style={{marginBottom:4}}>Showing</div>
                  <div style={{fontFamily:'var(--font-display)',fontSize:20,fontWeight:500}}>
                    {BUCKETS.find(b=>b.id===bucket)?.title}
                  </div>
                </div>
                <button type="button"
                  onClick={()=>{ setBucket(null); setQ(''); setCat('all'); if(set)set(s=>{const n={...s};delete n._catFilter;return n;}); }}
                  style={{background:'transparent',border:'none',color:'var(--ink-2)',cursor:'pointer',fontSize:13,textDecoration:'underline'}}>
                  ← Change category
                </button>
              </div>

              {/* Search + sub-filter only for the "specific" bucket */}
              {bucket === 'specific' && (
                <>
                  <form style={{display:'flex',gap:'var(--s-3)',marginBottom:'var(--s-3)'}} onSubmit={(e)=>e.preventDefault()}>
                    <div style={{flex:1,display:'flex',alignItems:'center',gap:8,background:'var(--paper)',border:'1.5px solid var(--ink-4)',borderRadius:'var(--r-3)',padding:'0 var(--s-3)'}}>
                      <Icon d={ICONS.search} size={16}/>
                      <input value={q} onChange={e=>setQ(e.target.value)} placeholder="Search forms…"
                        style={{border:'none',background:'transparent',width:'100%',padding:'10px 0',fontFamily:'var(--font-body)',fontSize:14,outline:'none',color:'var(--ink)'}}/>
                    </div>
                  </form>
                  <div style={{display:'flex',gap:'var(--s-2)',flexWrap:'wrap',marginBottom:'var(--s-5)'}}>
                    {FORM_CATS.filter(c => c.id !== 'new-patient' && c.id !== 'post-op').map(c => (
                      <span key={c.id} className={`pill ${cat===c.id?'pill-active':''}`}
                        style={{cursor:'pointer'}} onClick={()=>setCat(c.id)}
                        role="button" tabIndex={0}
                        onKeyDown={e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();setCat(c.id);}}}
                      >{c.label}</span>
                    ))}
                  </div>
                </>
              )}

              {filtered.length === 0 && (
                <div style={{padding:'var(--s-8)',textAlign:'center',color:'var(--ink-2)'}}>
                  No forms match. <button className="btn btn-sm btn-ghost" onClick={()=>{setCat('all');setQ('');}}>Clear filters</button>
                </div>
              )}

              {/* New-patient bucket: numbered step-by-step list */}
              {bucket === 'new-patient' && filtered.length > 0 && (
                <p style={{margin:'0 0 var(--s-4)',color:'var(--ink-2)',fontSize:14,lineHeight:1.55}}>
                  Complete all four to be ready for your first visit. Total time: about 18 minutes.
                </p>
              )}

              <div style={{display:'grid',gap:'var(--s-3)',marginBottom:'var(--s-12)'}}>
                {filtered.map((f, i) => (
                  <div key={f.id} className="card card-paper"
                    style={{display:'flex',justifyContent:'space-between',alignItems:'center',gap:'var(--s-4)'}}>
                    {bucket === 'new-patient' && (
                      <div aria-hidden="true" style={{
                        flexShrink:0, width:32, height:32, borderRadius:'50%', background:'var(--ink-5)',
                        color:'var(--ink-1)', display:'flex',alignItems:'center',justifyContent:'center',
                        fontFamily:'var(--font-display)', fontWeight:500, fontSize:14,
                      }}>{i+1}</div>
                    )}
                    <div style={{flex:1}}>
                      <div style={{display:'flex',alignItems:'center',gap:'var(--s-2)',marginBottom:4}}>
                        <span className="t-eyebrow">{FORM_CATS.find(c=>c.id===f.cat)?.label}</span>
                        {f.time && <span className="t-meta">· {f.time}</span>}
                        {f.type==='native'    && <span style={{fontSize:11,fontFamily:'var(--font-mono)',padding:'2px 6px',background:'var(--sage)',color:'var(--paper)',borderRadius:4}}>HIPAA secured</span>}
                        {f.type==='post-op'   && <span style={{fontSize:11,fontFamily:'var(--font-mono)',padding:'2px 6px',background:'var(--bone)',color:'var(--ink-2)',borderRadius:4}}>print-friendly</span>}
                      </div>
                      <h3 style={{margin:'0 0 4px',fontFamily:'var(--font-display)',fontSize:17,fontWeight:500}}>{f.title}</h3>
                      <p style={{margin:0,fontSize:14,color:'var(--ink-2)',lineHeight:1.5}}>{f.desc}</p>
                    </div>
                    <Button variant="primary" size="sm" onClick={()=>openForm(f)}>{ctaLabel(f)}</Button>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>
      </main>
      <Footer go={go}/>
    </div>
  );
}

// ─── NATIVE FORM VIEWER ───────────────────────────────────────────────────────

function NativeFormViewer({ f, go, state }) {
  const schema = FORM_SCHEMAS[f.id] || [];

  // Build initial field state
  const initFields = () => {
    const v = {};
    schema.forEach(field => {
      if (field.type === 'heading' || field.type === 'info') return;
      if (field.type === 'checkboxgroup') v[field.id] = [];
      else v[field.id] = '';
    });
    return v;
  };

  const [fields, setFields] = useFS(initFields);
  const [errors, setErrors] = useFS({});
  const [submitted, setSubmitted] = useFS(false);
  const [submitting, setSubmitting] = useFS(false);
  const [submitError, setSubmitError] = useFS(null);

  const setField = (id, val) => {
    setFields(f => ({ ...f, [id]: val }));
    setErrors(e => { const n = {...e}; delete n[id]; return n; });
  };

  const toggleCheckbox = (id, option) => {
    setFields(prev => {
      const arr = prev[id] || [];
      const next = arr.includes(option) ? arr.filter(x => x !== option) : [...arr, option];
      return { ...prev, [id]: next };
    });
  };

  const validate = () => {
    const errs = {};
    schema.forEach(field => {
      if (!field.required) return;
      if (field.type === 'heading' || field.type === 'info') return;
      const val = fields[field.id];
      if (field.type === 'checkboxgroup') {
        if (!val || val.length === 0) errs[field.id] = 'Required';
      } else {
        if (!val || !val.trim()) errs[field.id] = 'Required';
      }
    });
    return errs;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    const errs = validate();
    if (Object.keys(errs).length > 0) {
      setErrors(errs);
      const firstId = Object.keys(errs)[0];
      const el = document.getElementById('field-' + firstId);
      if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' });
      return;
    }
    setSubmitting(true);
    setSubmitError(null);
    try {
      const resp = await fetch('/api/portal/submit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ form_id: f.id, fields }),
      });
      const data = await resp.json().catch(() => ({}));
      if (!resp.ok || data.ok === false) {
        setSubmitError(data.error || `Submit failed (${resp.status}). Please try again.`);
        if (Array.isArray(data.errors)) {
          const fieldErrs = {};
          data.errors.forEach(e => { if (e.field) fieldErrs[e.field] = e.message || 'Invalid'; });
          if (Object.keys(fieldErrs).length) setErrors(fieldErrs);
        }
        setSubmitting(false);
        return;
      }
    } catch (err) {
      setSubmitError('Network error. Check your connection and try again.');
      setSubmitting(false);
      return;
    }
    setSubmitting(false);
    setSubmitted(true);
  };

  const patientName = fields.patient_name || (fields.first_name && fields.last_name ? `${fields.first_name} ${fields.last_name}` : fields.first_name) || '';

  if (submitted) {
    return (
      <div style={{padding:'var(--s-6) 0'}} className="native-form-success">
        <style>{`@media print { .no-print { display:none!important; } body{background:#fff;} .native-form-success .print-summary { display:block!important; } }`}</style>
        <div className="card card-paper no-print" style={{maxWidth:560,margin:'0 auto',textAlign:'center',padding:'var(--s-8)'}}>
          <div style={{marginBottom:'var(--s-3)',display:'flex',justifyContent:'center'}}>
            <span style={{width:52,height:52,borderRadius:'50%',background:'var(--sage)',color:'var(--paper)',display:'flex',alignItems:'center',justifyContent:'center'}}>
              <Icon d={ICONS.check} size={28} stroke={2}/>
            </span>
          </div>
          <h2 style={{fontFamily:'var(--font-display)',fontSize:26,fontWeight:500,margin:'0 0 var(--s-2)'}}>Form submitted</h2>
          {patientName
            ? <p style={{color:'var(--ink-2)',marginBottom:'var(--s-4)'}}>Thank you, {patientName}. We received your {f.title}.</p>
            : <p style={{color:'var(--ink-2)',marginBottom:'var(--s-4)'}}>Your {f.title} has been received.</p>
          }
          <div style={{display:'flex',gap:10,justifyContent:'center',flexWrap:'wrap'}}>
            <Button variant="secondary" onClick={()=>window.print()}>Print this form</Button>
            <Button variant="primary" onClick={()=>go('forms')}>Back to forms</Button>
          </div>
        </div>
        <div className="print-summary" style={{display:'none',maxWidth:680,margin:'var(--s-6) auto',fontFamily:'var(--font-body)',fontSize:14,lineHeight:1.7}}>
          <h2 style={{fontFamily:'var(--font-display)',fontSize:22,marginBottom:'var(--s-4)'}}>{f.title}</h2>
          <p style={{color:'#555',marginBottom:'var(--s-5)'}}>Submitted: {new Date().toLocaleDateString('en-US',{month:'long',day:'numeric',year:'numeric'})}</p>
          {schema.filter(fd => fd.type !== 'heading' && fd.type !== 'info' && fd.type !== 'checkboxgroup').map(fd =>
            fields[fd.id] ? (
              <div key={fd.id} style={{borderBottom:'1px solid #eee',padding:'6px 0',display:'grid',gridTemplateColumns:'200px 1fr',gap:8}}>
                <span style={{fontWeight:600,color:'#333'}}>{fd.label}</span>
                <span>{fields[fd.id]}</span>
              </div>
            ) : null
          )}
          {schema.filter(fd => fd.type === 'checkboxgroup').map(fd =>
            fields[fd.id] && fields[fd.id].length > 0 ? (
              <div key={fd.id} style={{borderBottom:'1px solid #eee',padding:'6px 0'}}>
                <div style={{fontWeight:600,color:'#333',marginBottom:4}}>{fd.label}</div>
                <div>{fields[fd.id].join(', ')}</div>
              </div>
            ) : null
          )}
        </div>
      </div>
    );
  }

  const inputStyle = (id) => ({
    width:'100%', boxSizing:'border-box',
    padding:'10px 12px',
    border: errors[id] ? '1.5px solid #e53e3e' : '1.5px solid var(--ink-5)',
    borderRadius:'var(--r-3)',
    background: errors[id] ? 'rgba(229,62,62,.04)' : 'var(--paper)',
    fontFamily:'var(--font-body)', fontSize:15, color:'var(--ink)',
    outline:'none',
    transition:'border-color .15s, box-shadow .15s',
  });

  const renderField = (field) => {
    if (field.type === 'heading') {
      return (
        <div key={field.id} style={{gridColumn:'1 / -1', borderBottom:'2px solid var(--ink-5)', paddingBottom:'var(--s-2)', marginTop:'var(--s-4)'}}>
          <h2 style={{fontFamily:'var(--font-display)',fontSize:18,fontWeight:500,margin:0,color:'var(--ink)'}}>{field.label}</h2>
        </div>
      );
    }
    if (field.type === 'info') {
      return (
        <div key={field.id} style={{gridColumn:'1 / -1', padding:'var(--s-4)', background:'var(--bone)', borderRadius:'var(--r-3)', borderLeft:'3px solid var(--seal)', fontSize:14, lineHeight:1.65, color:'var(--ink-2)'}}>
          {field.label}
        </div>
      );
    }

    const colSpan = field.cols === 2 ? {} : { gridColumn:'1 / -1' };
    const labelEl = (
      <label htmlFor={'field-' + field.id} style={{display:'block', fontSize:13, fontWeight:500, color:'var(--ink-2)', marginBottom:5}}>
        {field.label}
        {field.required && <span style={{color:'var(--seal)',marginLeft:3}}>*</span>}
      </label>
    );

    if (field.type === 'checkboxgroup') {
      return (
        <div key={field.id} id={'field-' + field.id} style={{gridColumn:'1 / -1'}}>
          {labelEl}
          <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(220px, 1fr))', gap:'var(--s-2)', marginTop:4}}>
            {(field.options||[]).map(opt => (
              <label key={opt} style={{display:'flex', alignItems:'flex-start', gap:8, fontSize:14, cursor:'pointer', lineHeight:1.45}}>
                <input type="checkbox" checked={(fields[field.id]||[]).includes(opt)}
                  onChange={()=>toggleCheckbox(field.id, opt)}
                  style={{marginTop:3, accentColor:'var(--seal)', flexShrink:0}}/>
                {opt}
              </label>
            ))}
          </div>
          {errors[field.id] && <div style={{color:'#e53e3e',fontSize:12,marginTop:4}}>{errors[field.id]}</div>}
        </div>
      );
    }

    let input = null;
    if (field.type === 'textarea') {
      input = (
        <textarea id={'field-' + field.id} rows={4} value={fields[field.id]||''} placeholder={field.placeholder||''}
          onChange={e=>setField(field.id, e.target.value)}
          onFocus={e=>{e.target.style.borderColor='var(--seal)';e.target.style.boxShadow='0 0 0 3px rgba(181,58,58,.1)';}}
          onBlur={e=>{e.target.style.borderColor=errors[field.id]?'#e53e3e':'var(--ink-5)';e.target.style.boxShadow='none';}}
          style={{...inputStyle(field.id), resize:'vertical'}}/>
      );
    } else if (field.type === 'select') {
      input = (
        <select id={'field-' + field.id} value={fields[field.id]||''} onChange={e=>setField(field.id, e.target.value)}
          onFocus={e=>{e.target.style.borderColor='var(--seal)';e.target.style.boxShadow='0 0 0 3px rgba(181,58,58,.1)';}}
          onBlur={e=>{e.target.style.borderColor=errors[field.id]?'#e53e3e':'var(--ink-5)';e.target.style.boxShadow='none';}}
          style={{...inputStyle(field.id), appearance:'none'}}>
          <option value="">— select —</option>
          {(field.options||[]).map(o=><option key={o} value={o}>{o}</option>)}
        </select>
      );
    } else if (field.type === 'signature') {
      input = (
        <input id={'field-' + field.id} type="text" value={fields[field.id]||''} placeholder="Type your full legal name"
          onChange={e=>setField(field.id, e.target.value)}
          onFocus={e=>{e.target.style.borderColor='var(--seal)';e.target.style.boxShadow='0 0 0 3px rgba(181,58,58,.1)';}}
          onBlur={e=>{e.target.style.borderColor=errors[field.id]?'#e53e3e':'var(--ink-5)';e.target.style.boxShadow='none';}}
          style={{...inputStyle(field.id), fontStyle:'italic', fontFamily:'Georgia, serif', fontSize:17}}/>
      );
    } else {
      input = (
        <input id={'field-' + field.id} type={field.type} value={fields[field.id]||''} placeholder={field.placeholder||''}
          onChange={e=>setField(field.id, e.target.value)}
          onFocus={e=>{e.target.style.borderColor='var(--seal)';e.target.style.boxShadow='0 0 0 3px rgba(181,58,58,.1)';}}
          onBlur={e=>{e.target.style.borderColor=errors[field.id]?'#e53e3e':'var(--ink-5)';e.target.style.boxShadow='none';}}
          style={inputStyle(field.id)}/>
      );
    }

    return (
      <div key={field.id} id={'field-' + field.id} style={colSpan}>
        {labelEl}
        {input}
        {errors[field.id] && <div style={{color:'#e53e3e',fontSize:12,marginTop:4}}>{errors[field.id]}</div>}
      </div>
    );
  };

  return (
    <form onSubmit={handleSubmit} noValidate>
      <div style={{marginBottom:'var(--s-4)'}}>
        <div className="t-eyebrow" style={{marginBottom:6}}>Patient intake form</div>
        <h1 style={{fontFamily:'var(--font-display)',fontSize:28,fontWeight:500,margin:'0 0 var(--s-2)'}}>{f.title}</h1>
        {f.time && <p style={{color:'var(--ink-3)',fontSize:14,margin:0}}>Estimated time: {f.time}</p>}
      </div>

      <div style={{
        display:'grid',
        gridTemplateColumns:'repeat(2, 1fr)',
        gap:'var(--s-4)',
        marginBottom:'var(--s-6)',
      }}>
        {schema.map(renderField)}
      </div>

      {submitError && (
        <div role="alert" aria-live="polite" style={{padding:'var(--s-3)',background:'#FFF5F2',border:'1px solid var(--seal)',borderRadius:8,color:'var(--seal)',fontSize:14,marginBottom:'var(--s-3)'}}>
          {submitError}
        </div>
      )}
      <div style={{paddingTop:'var(--s-4)',borderTop:'1px solid var(--ink-5)',display:'flex',gap:10,flexWrap:'wrap',alignItems:'center'}}>
        <button type="submit" disabled={submitting} className="btn btn-primary" style={{minWidth:160}}>
          {submitting ? 'Submitting…' : 'Submit form'}
        </button>
        <Button variant="ghost" onClick={()=>go('forms')}>← All forms</Button>
      </div>

      <div style={{marginTop:'var(--s-4)',fontSize:12,color:'var(--ink-3)',lineHeight:1.5}}>
        Your information is submitted securely over an encrypted connection. Fields marked <span style={{color:'var(--seal)'}}>*</span> are required.
      </div>
    </form>
  );
}

// ─── CONSENT FORM VIEWER ──────────────────────────────────────────────────────

function FormViewer({ go, state, set }) {
  const f = state && state._selectedForm;
  const dentist = state && state._selectedDentist;
  const prefill = {
    zip: state && state.zip,
    insurance: state && state.insurance,
    dentist_npi: dentist && dentist.npi,
    dentist_name: dentist && dentist.name,
  };

  if (!f) {
    return (
      <div className="app">
        <Masthead go={go}/>
        <main><div className="container" style={{padding:'var(--s-12) 0',textAlign:'center'}}>
          <p>No form selected.</p>
          <Button variant="primary" onClick={()=>go('forms')}>Browse all forms</Button>
        </div></main>
        <Footer go={go}/>
      </div>
    );
  }

  // Branch: native forms get NativeFormViewer wrapped in the standard shell
  if (f.type === 'native') {
    return (
      <div className="app">
        <style>{`@media print { .no-print { display:none!important; } body { background:#fff; } .card { box-shadow:none!important; border:1px solid #ddd; } }`}</style>
        <Masthead go={go} className="no-print"/>
        <main>
          <div className="container article" style={{maxWidth:720}}>
            <Breadcrumbs className="no-print" crumbs={[{label:'Home',screen:'landing'},{label:'Patient forms',screen:'forms'},{label:f.title}]} go={go}/>
            <div className="card card-paper" style={{marginTop:'var(--s-4)'}}>
              <NativeFormViewer f={f} go={go} state={state}/>
            </div>
          </div>
        </main>
        <Footer go={go} className="no-print"/>
      </div>
    );
  }

  // Consent forms (existing logic unchanged)
  return (
    <div className="app">
      <style>{`@media print { .no-print { display:none!important; } body { background:#fff; } .card { box-shadow:none!important; border:1px solid #ddd; } }`}</style>
      <Masthead go={go} className="no-print"/>
      <main>
        <div className="container article" style={{maxWidth:680}}>
          <Breadcrumbs className="no-print" crumbs={[{label:'Home',screen:'landing'},{label:'Patient forms',screen:'forms'},{label:f.title}]} go={go}/>

          <div className="card card-paper" style={{marginTop:'var(--s-4)'}}>
            <div className="t-eyebrow" style={{marginBottom:6}}>Informed consent · {new Date().toLocaleDateString('en-US',{month:'long',day:'numeric',year:'numeric'})}</div>
            <h1 style={{fontFamily:'var(--font-display)',fontSize:28,fontWeight:500,margin:'0 0 var(--s-3)'}}>{f.title}</h1>
            <p style={{color:'var(--ink-2)',lineHeight:1.65,marginBottom:'var(--s-6)'}}>{f.desc}</p>

            {f.risks && f.risks.length > 0 && (
              <div style={{marginBottom:'var(--s-5)'}}>
                <h2 style={{fontFamily:'var(--font-display)',fontSize:18,fontWeight:500,margin:'0 0 var(--s-3)'}}>Possible risks and complications</h2>
                <ul style={{margin:0,paddingLeft:'var(--s-5)',display:'grid',gap:'var(--s-2)'}}>
                  {f.risks.map((r,i)=><li key={i} style={{fontSize:15,lineHeight:1.6,color:'var(--ink-1)'}}>{r}</li>)}
                </ul>
              </div>
            )}
            {f.alts && f.alts.length > 0 && (
              <div style={{marginBottom:'var(--s-5)'}}>
                <h2 style={{fontFamily:'var(--font-display)',fontSize:18,fontWeight:500,margin:'0 0 var(--s-3)'}}>Treatment alternatives</h2>
                <ul style={{margin:0,paddingLeft:'var(--s-5)',display:'grid',gap:'var(--s-2)'}}>
                  {f.alts.map((a,i)=><li key={i} style={{fontSize:15,lineHeight:1.6,color:'var(--ink-1)'}}>{a}</li>)}
                </ul>
              </div>
            )}

            <div style={{padding:'var(--s-4)',background:'var(--bone)',borderRadius:'var(--r-3)',marginBottom:'var(--s-6)',fontSize:14,lineHeight:1.6,color:'var(--ink-2)'}}>
              <strong style={{color:'var(--ink-1)'}}>Note:</strong> This summary is for patient education. Your dentist will review this content with you and collect your formal signature at the office. Questions are always welcome before you sign.
            </div>

            <div className="no-print" style={{display:'flex',gap:10,flexWrap:'wrap'}}>
              <Button variant="secondary" onClick={()=>window.print()}>
                <Icon d={ICONS.upload} size={16}/> Print
              </Button>
              <Button variant="ghost" onClick={()=>go('forms')}>← All forms</Button>
            </div>
          </div>

          <Disclosure/>
        </div>
      </main>
      <Footer go={go} className="no-print"/>
    </div>
  );
}

// ─── POST-OP INSTRUCTION VIEWER ───────────────────────────────────────────────

function PostOpViewer({ go, state, set }) {
  const procedure = state && state._selectedPostOp;
  const data = procedure && POST_OP_DATA[procedure];
  const dentist = state && state._selectedDentist;

  React.useEffect(() => { if (data) window.Enc?.viewedPostOp(procedure, data.title); }, [procedure]);

  if (!data) {
    return (
      <div className="app">
        <Masthead go={go}/>
        <main><div className="container" style={{padding:'var(--s-12) 0',textAlign:'center'}}>
          <p>No procedure selected.</p>
          <Button variant="primary" onClick={()=>{ if(set)set(s=>({...s,_catFilter:'post-op'})); go('forms'); }}>Browse post-op instructions</Button>
        </div></main>
        <Footer go={go}/>
      </div>
    );
  }

  const emailSubject = encodeURIComponent(`Post-op instructions: ${data.title}`);
  const shareUrl = `${window.location.origin}/#post-op`;

  return (
    <div className="app">
      <style>{`@media print { .no-print{display:none!important;} nav{display:none!important;} footer{display:none!important;} body{background:#fff;} .card{box-shadow:none!important;border:1px solid #ddd;} .postop-section{break-inside:avoid;} .postop-critical{border:2px solid #B8492C!important;} }`}</style>
      <Masthead go={go} className="no-print"/>
      <main>
        <div className="container article" style={{maxWidth:700}}>
          <div className="no-print">
            <Breadcrumbs crumbs={[{label:'Home',screen:'landing'},{label:'Patient forms',screen:'forms'},{label:data.title}]} go={go}/>
          </div>

          <div style={{padding:'var(--s-2) 0 var(--s-6)'}}>
            <div className="t-eyebrow" style={{marginBottom:6}}>Post-operative instructions</div>
            <h1 style={{fontFamily:'var(--font-display)',fontSize:32,fontWeight:500,margin:'0 0 4px'}}>{data.title}</h1>
            <p style={{color:'var(--ink-2)',fontSize:16,margin:'0 0 var(--s-4)'}}>{data.subtitle}</p>

            {dentist && (
              <div style={{padding:'var(--s-3) var(--s-4)',background:'var(--bone)',borderRadius:'var(--r-3)',fontSize:14,color:'var(--ink-2)',marginBottom:'var(--s-4)'}}>
                Provided by <strong style={{color:'var(--ink-1)'}}>{dentist.name}</strong> · {dentist.practice} · {new Date().toLocaleDateString()}
              </div>
            )}

            <div className="no-print" style={{display:'flex',gap:8,flexWrap:'wrap',marginBottom:'var(--s-6)'}}>
              <Button variant="primary" size="sm" onClick={()=>window.print()}>
                <Icon d={ICONS.upload} size={14}/> Print instructions
              </Button>
              <a href={`mailto:?subject=${emailSubject}&body=Here are my post-op instructions: ${shareUrl}`}
                className="btn btn-sm btn-secondary" style={{textDecoration:'none'}}>
                <Icon d={ICONS.share} size={14}/> Email to myself
              </a>
              <Button variant="ghost" size="sm" onClick={()=>go('forms')}>← All forms</Button>
            </div>
          </div>

          <div style={{display:'grid',gap:'var(--s-4)',marginBottom:'var(--s-8)'}}>
            {data.sections.map((sec, i) => {
              const isCritical = sec.h.toLowerCase().includes('critical');
              return (
                <div key={i} className={`card card-paper postop-section${isCritical?' postop-critical':''}`}
                  style={isCritical ? {borderLeft:'4px solid var(--seal)'} : {}}>
                  <h2 style={{fontFamily:'var(--font-display)',fontSize:19,fontWeight:500,
                    margin:'0 0 var(--s-3)',
                    color: isCritical ? 'var(--seal)' : 'var(--ink)'}}>{sec.h}</h2>
                  <ul style={{margin:0,paddingLeft:'var(--s-5)',display:'grid',gap:'var(--s-2)'}}>
                    {sec.items.map((item,j)=>(
                      <li key={j} style={{fontSize:15,lineHeight:1.65,color:'var(--ink-1)'}}>{item}</li>
                    ))}
                  </ul>
                </div>
              );
            })}
          </div>

          {data.note && (
            <div style={{padding:'var(--s-4)',background:'var(--bone)',borderRadius:'var(--r-3)',marginBottom:'var(--s-6)',fontSize:14,lineHeight:1.65,color:'var(--ink-2)'}}>
              <strong style={{color:'var(--ink-1)',display:'block',marginBottom:4}}>Clinical note</strong>
              {data.note}
            </div>
          )}

          {data.phone_note && (
            <div style={{padding:'var(--s-4)',background:'var(--ink)',color:'var(--paper)',borderRadius:'var(--r-3)',marginBottom:'var(--s-6)',fontSize:14}}>
              <strong>Office contact:</strong> {data.phone_note}
              {dentist && dentist.phone && <span> · {dentist.phone}</span>}
            </div>
          )}

          <div style={{padding:'var(--s-4)',borderTop:'1px solid var(--ink-5)',fontSize:13,color:'var(--ink-3)',lineHeight:1.5}}>
            AI-assisted content generated under California AB 3030 disclosure. These instructions are general guidance and do not constitute medical advice. Your provider's verbal instructions take precedence. If you are experiencing an emergency, call 911 or go to the nearest emergency room.
          </div>
        </div>
      </main>
      <Footer go={go} className="no-print"/>
    </div>
  );
}

Object.assign(window, { FormsDirectory, FormViewer, PostOpViewer, NativeFormViewer, buildTrafftUrl, buildFRUrl, openFormRobin });
