/* StrataSnap prototype — council side. Babel/JSX.
   Queue, TicketDetail (two-lane composer + state machine), NewTicket. */

const PEOPLE = ['Dana Lee', 'Alex Morgan', 'Property manager', 'Preferred plumber'];

function TabBar({ active, go }) {
  const tabs = [['dashboard', 'Today', 'home'], ['queue', 'Issues', 'ssInbox'], ['setup', 'Setup', 'shieldCheck'], ['posters', 'Posters', 'ssPoster'], ['settings', 'Settings', 'cog']];
  return (
    <nav className="tabbar">
      {tabs.map(([k, lbl, ic]) =>
      <a key={k} className={active === k ? 'on' : ''} onClick={() => go(k)}><Icon name={ic} size={22} /> {lbl}</a>
      )}
    </nav>);

}

function CouncilDashboard({ tickets, setup, go, onOpen, toast }) {
  const SS = window.SS;
  const readiness = SS.setupProgress(setup);
  const open = (t) => SS.isOpenTicket(t);
  const counts = {
    open: tickets.filter(open).length,
    urgent: tickets.filter((t) => open(t) && t.priority === 'High').length,
    review: tickets.filter((t) => t.status === 'Needs review' || t.status === 'New').length,
    resolved: tickets.filter((t) => t.status === 'Resolved').length
  };
  const attention = tickets.filter(open).sort((a, b) => (b.priority === 'High') - (a.priority === 'High') || new Date(a.createdAt) - new Date(b.createdAt)).slice(0, 3);
  const stats = SS.locationStats(tickets).filter((s) => s.count > 0);
  const recent = tickets.slice().sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))[0];
  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>Harbour View Strata</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Today’s building issues</h1>
      </div>
      <div className="scroll">
        <div className="cd-stats">
          <div className="cd-stat"><span className="cd-stat-ic"><Icon name="list" size={16} /></span><b>{counts.open}</b><span>Open</span></div>
          <div className="cd-stat urgent"><span className="cd-stat-ic"><Icon name="alert" size={16} /></span><b>{counts.urgent}</b><span>Urgent</span></div>
          <div className="cd-stat"><span className="cd-stat-ic" style={{ color: 'var(--st-violet)' }}><span className="dot" style={{ width: 9, height: 9, borderRadius: 9, background: 'var(--st-violet)', display: 'block' }} /></span><b>{counts.review}</b><span>In review</span></div>
          <div className="cd-stat"><span className="cd-stat-ic" style={{ color: 'var(--st-green)' }}><Icon name="check" size={16} /></span><b>{counts.resolved}</b><span>Resolved</span></div>
        </div>

        <button className="setup-nudge" onClick={() => go('setup')}>
          <span className="setup-nudge-ic"><Icon name={readiness.launchReady ? 'check' : 'shieldCheck'} size={22} /></span>
          <span className="setup-nudge-main">
            <span className="setup-nudge-k">{readiness.launchReady ? 'Building setup is ready' : 'Finish building setup'}</span>
            <span className="setup-nudge-v">{readiness.next ? 'Next: ' + readiness.next.label : 'QR intake, notices, and test scan are configured.'}</span>
          </span>
          <span className="setup-ring" aria-label={readiness.percent + ' percent ready'}>{readiness.percent}%</span>
        </button>

        <div className="cd-sec"><h2>Needs attention today</h2><button className="linkbtn" onClick={() => go('queue')}>View inbox</button></div>
        <div className="cd-list">
          {attention.map((t) =>
          <button className="cd-card" key={t.id} onClick={() => onOpen(t.id)}>
              <span className="cd-thumb ph"><Icon name={SS.catIcon(t.category)} size={20} /></span>
              <div className="cd-card-main">
                <div className="cd-card-t">{t.summary}</div>
                <div className="cd-card-m"><Icon name="pin" size={12} /> {t.locationName.replace(' – Elevator Lobby', '')} · {SS.ageLabel(t)}</div>
              </div>
              <div className="cd-card-side">{t.priority === 'High' ? <span className="stt is-urgent"><span className="dot" />Urgent</span> : <StatusDot status={t.status} short />}{t.assignee ? <Avatar name={t.assignee} /> : null}</div>
            </button>
          )}
        </div>

        <div className="cd-mapcard">
          <div className="cd-mapcard-head"><span>Building overview</span><button className="linkbtn" onClick={() => go('map')}>Open map →</button></div>
          <div className="rev-map" style={{ aspectRatio: '16/9', marginTop: 12 }}>
            <img className="rev-map-img" src="art/floor-map.png" alt="" onError={(e) => {e.target.closest('.rev-map').classList.add('noimg');}} />
            {stats.slice(0, 3).map((s, i) =>
            <span key={s.loc.id} className={'cd-mappin tone-' + s.tone} style={{ left: s.loc.x * 100 + '%', top: s.loc.y * 100 + '%' }}>{s.count}</span>
            )}
          </div>
        </div>

        <div className="cd-sec"><h2>Recent activity</h2><button className="linkbtn" onClick={() => go('updates')}>View all</button></div>
        <div className="feed" style={{ padding: '0 16px 18px' }}>
          {SS.feed(tickets, 5).map((it, i) => {
            const e = it.e;
            const tg = e.kind === 'update' ? { cls: 'pub', icon: 'eye', label: 'Update to reporter' } :
            e.kind === 'note' ? { cls: 'priv', icon: 'lock', label: 'Private note' } :
            e.kind === 'submitted' ? { cls: 'new', icon: 'plus', label: 'New report' } :
            { cls: 'status', icon: 'chevronR', label: 'Status change' };
            return (
              <button className="feed-item" key={i} onClick={() => onOpen(it.ticketId)}>
                <span className={'feed-mk ' + tg.cls}><Icon name={tg.icon} size={14} /></span>
                <div className="feed-body">
                  <div className="feed-top"><span className="feed-tag">{tg.label}</span><span className="feed-when">{SS.whenLabel(e.at)}</span></div>
                  <div className="feed-text">{e.body}</div>
                  <div className="feed-ref"><span className="id-mono">{it.ticketId}</span> · {it.summary}</div>
                </div>
              </button>);

          })}
        </div>
      </div>
      <TabBar active="dashboard" go={go} />
      {toast && <Toast>{toast}</Toast>}
    </div>);

}

function BuildingLogoPreview({ setup, compact }) {
  return (
    <div className={'setup-logo-preview' + (compact ? ' compact' : '')}>
      {setup.logoUrl ? <img src={setup.logoUrl} alt={setup.buildingName + ' logo'} /> : <Logo tone="dark" size={compact ? 20 : 24} />}
    </div>
  );
}

function readLogoFile(file, onDone, onError) {
  if (!file) return;
  if (!/^image\/(png|jpeg)$/.test(file.type)) {
    onError && onError('Use a PNG or JPG logo for now.');
    return;
  }
  if (file.size > 5000000) {
    onError && onError('Logo file is too large. Use a file under 5 MB.');
    return;
  }
  const reader = new FileReader();
  reader.onload = () => {
    const url = String(reader.result || '');
    const img = new Image();
    img.onload = () => {
      if ((img.width * img.height) > 16000000) {
        onError && onError('Logo image dimensions are too large. Use a smaller image.');
        return;
      }
      const max = 480;
      const scale = Math.min(1, max / Math.max(img.width, img.height));
      const canvas = document.createElement('canvas');
      canvas.width = Math.max(1, Math.round(img.width * scale));
      canvas.height = Math.max(1, Math.round(img.height * scale));
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      const output = canvas.toDataURL(file.type === 'image/jpeg' ? 'image/jpeg' : 'image/png', 0.86);
      if (output.length > 650000) {
        onError && onError('Logo preview is still too large. Try a simpler PNG or JPG.');
        return;
      }
      try {
        localStorage.setItem('__stratasnap_logo_probe', output);
        localStorage.removeItem('__stratasnap_logo_probe');
      } catch (e) {
        onError && onError('Browser storage is full. Remove other prototype data before uploading a logo.');
        return;
      }
      onDone(output);
    };
    img.onerror = () => onError && onError('Could not process that logo image.');
    img.src = url;
  };
  reader.onerror = () => onError && onError('Could not read that logo file.');
  reader.readAsDataURL(file);
}

function BuildingSetupMobile({ setup, patchSetup, go, toast, setToast, startAtFirst }) {
  const SS = window.SS;
  const readiness = SS.setupProgress(setup);
  const nextToStep = { profile: 'profile', routing: 'routing', emergency: 'emergency', brand: 'brand', locations: 'locations', qr: 'posters', scan: 'test', notify: 'test' };
  const flowSteps = [
    { id: 'profile', label: 'Building', eyebrow: 'Step 1 of 7', question: 'What building is this for?', desc: 'Set the council-facing name, address, lot count, and operating mode first.', required: true, icon: 'building', decision: 'Council confirms the legal or familiar building name residents will recognize.', impact: 'This name appears on posters, status pages, and the council dashboard.' },
    { id: 'routing', label: 'Routing', eyebrow: 'Step 2 of 7', question: 'Who should receive new reports?', desc: 'Every report needs one accountable inbox before residents start scanning.', required: true, icon: 'send', decision: 'Council chooses the shared email or manager inbox that will receive new reports.', impact: 'Residents get a clear handoff instead of another scattered message thread.' },
    { id: 'emergency', label: 'Emergency', eyebrow: 'Step 3 of 7', question: 'What should residents do if it is urgent?', desc: 'Urgent leaks, access failures, and safety issues should not enter a normal queue first.', required: true, icon: 'alert', decision: 'Council records the emergency line or manager instructions residents should see first.', impact: 'Residents are directed to the right urgent path before submitting a standard report.' },
    { id: 'brand', label: 'Brand', eyebrow: 'Step 4 of 7', question: 'What should the app and posters look like?', desc: 'Choose an app accent preset, then add a building or management logo if needed.', required: false, icon: 'ssPoster', decision: 'Council picks the approved accent and decides whether printed materials should carry local building branding.', impact: 'Residents can trust that the QR poster and status page belong to their building.' },
    { id: 'locations', label: 'Locations', eyebrow: 'Step 5 of 7', question: 'Where should residents be able to scan?', desc: 'Start with common-property areas where issue locations often get described vaguely.', required: true, icon: 'pin', decision: 'Council chooses the first pilot locations for QR posters.', impact: 'Reports arrive with a known place attached, so triage starts faster.' },
    { id: 'posters', label: 'Posters', eyebrow: 'Step 6 of 7', question: 'Do these QR poster IDs look right?', desc: 'Each active location gets a public QR code and a private setup check.', required: true, icon: 'qr', decision: 'Council checks that each poster label maps to the right physical area.', impact: 'Residents scan the right code and the issue lands on the right map location.' },
    { id: 'test', label: 'Launch test', eyebrow: 'Step 7 of 7', question: 'Can this building launch safely?', desc: 'Test the scan and notification path before printing or placing posters.', required: true, icon: 'shieldCheck', decision: 'Council confirms the end-to-end flow works before residents see it.', impact: 'The first real resident report has a tested route from scan to council inbox.' },
  ];
  const initialStep = (startAtFirst || !setup.activated) ? 'profile' : (nextToStep[readiness.next ? readiness.next.id : 'profile'] || 'profile');
  const [stepId, setStepId] = React.useState(initialStep);
  const set = (patch) => patchSetup((s) => ({ ...s, ...patch }));
  const themes = SS.APP_THEMES || [];
  const updateLoc = (id, patch) => patchSetup((s) => ({
    ...s,
    locations: s.locations.map((l) => l.id === id ? { ...l, ...patch } : l),
  }));
  const activeLocations = setup.locations.filter((l) => l.active);
  const testedLocations = activeLocations.filter((l) => l.tested);
  const validEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(setup.routingEmail || '').trim());
  const stepIndex = Math.max(0, flowSteps.findIndex((s) => s.id === stepId));
  const currentStep = flowSteps[stepIndex] || flowSteps[0];
  const goStep = (id) => setStepId(id);
  const stepDone = {
    profile: !!(setup.buildingName && setup.address && setup.lots),
    routing: validEmail,
    emergency: !!setup.emergencyContact,
    brand: !!setup.appTheme || !!setup.logoUrl,
    locations: activeLocations.length >= 5,
    posters: activeLocations.length > 0 && activeLocations.every((l) => l.qrId),
    test: readiness.launchReady,
  };
  const testAll = () => {
    patchSetup((s) => ({ ...s, locations: s.locations.map((l) => ({ ...l, tested: true })), testScanPassed: true }));
    setToast('Test scan passed for active QR locations');
  };
  const sendNotification = () => {
    set({ notificationTested: true });
    setToast('Notification test sent to the routing email');
  };
  const activate = () => {
    if (!SS.setupProgress(setup).launchReady) {
      setToast('Finish the required setup steps before launch');
      return;
    }
    set({ activated: true });
    setToast('Building intake is marked ready');
  };
  const canContinue = () => {
    if (stepId === 'profile') return !!(setup.buildingName && setup.address && setup.lots);
    if (stepId === 'routing') return validEmail;
    if (stepId === 'emergency') return !!setup.emergencyContact;
    if (stepId === 'locations') return activeLocations.length >= 5;
    if (stepId === 'posters') return activeLocations.length > 0;
    return true;
  };
  const nextStep = () => {
    if (!canContinue()) {
      const messages = {
        profile: 'Add the building name, address, and number of lots.',
        routing: 'Add a valid routing email before continuing.',
        emergency: 'Add emergency instructions before continuing.',
        locations: 'Choose at least five reporting locations for the pilot.',
        posters: 'Turn on at least one reporting location first.',
      };
      setToast(messages[stepId] || 'Complete this step before continuing');
      return;
    }
    setStepId(flowSteps[Math.min(flowSteps.length - 1, stepIndex + 1)].id);
  };
  const previousStep = () => setStepId(flowSteps[Math.max(0, stepIndex - 1)].id);
  const skipOptional = () => setStepId(flowSteps[Math.min(flowSteps.length - 1, stepIndex + 1)].id);
  const StepFooter = () => (
    <div className="setup-flow-footer">
      <button className="btn btn-out btn-sm" disabled={stepIndex === 0} onClick={previousStep}>Back</button>
      {!currentStep.required && <button className="btn btn-ghost btn-sm" onClick={skipOptional}>Skip</button>}
      {stepIndex < flowSteps.length - 1 ?
        <button className="btn btn-acc btn-sm" onClick={nextStep}>Continue to {flowSteps[Math.min(flowSteps.length - 1, stepIndex + 1)].label.toLowerCase()}</button> :
        <button className="btn btn-acc btn-sm" disabled={!readiness.launchReady} onClick={activate}><Icon name="check" size={16} /> {setup.activated ? 'Activated' : 'Launch'}</button>}
    </div>
  );
  const StepGuidance = () => (
    <div className="setup-guidance">
      <div><span>Council decision</span><b>{currentStep.decision}</b></div>
      <div><span>Resident impact</span><b>{currentStep.impact}</b></div>
    </div>
  );
  const renderStep = () => {
    if (stepId === 'profile') return (
      <React.Fragment>
        <Field label="Building name"><input className="inp" value={setup.buildingName} onChange={(e) => set({ buildingName: e.target.value })} /></Field>
        <Field label="Address"><input className="inp" value={setup.address} onChange={(e) => set({ address: e.target.value })} /></Field>
        <div className="setup-grid2">
          <Field label="Lots"><input className="inp" type="number" min="1" value={setup.lots} onChange={(e) => set({ lots: Number(e.target.value || 0) })} /></Field>
          <Field label="Mode"><select className="inp" value={setup.managerMode} onChange={(e) => set({ managerMode: e.target.value })}><option>Council only</option><option>Council + property manager</option><option>Property manager led</option></select></Field>
        </div>
        <StepGuidance />
      </React.Fragment>
    );
    if (stepId === 'routing') return (
      <React.Fragment>
        <Field label="Routing email"><input className="inp" type="email" aria-invalid={!validEmail} value={setup.routingEmail} onChange={(e) => set({ routingEmail: e.target.value })} /></Field>
        {!validEmail && <div className="setup-inline-error">Use a valid email so test notifications can be sent.</div>}
        <div className="setup-choice-stack" aria-label="Management mode">
          {['Council only', 'Council + property manager', 'Property manager led'].map((mode) => (
            <button key={mode} className={'setup-choice' + (setup.managerMode === mode ? ' on' : '')} onClick={() => set({ managerMode: mode })}>
              <span>{mode}</span>
              <Icon name={setup.managerMode === mode ? 'check' : 'chevronR'} size={16} />
            </button>
          ))}
        </div>
        <StepGuidance />
      </React.Fragment>
    );
    if (stepId === 'emergency') return (
      <React.Fragment>
        <Field label="Emergency contact shown before reports"><input className="inp" value={setup.emergencyContact} onChange={(e) => set({ emergencyContact: e.target.value })} /></Field>
        <Note variant="warn" icon="alert" title="Resident safety copy">Emergency issues should direct residents to 911, the building emergency line, or the property manager emergency line before they submit a normal StrataSnap report.</Note>
        <StepGuidance />
      </React.Fragment>
    );
    if (stepId === 'brand') return (
      <React.Fragment>
        <div className="setup-theme-grid" aria-label="App accent">
          {themes.map((theme) => (
            <button key={theme.key} className={'setup-theme-choice' + (setup.appTheme === theme.key ? ' on' : '')} aria-pressed={setup.appTheme === theme.key} onClick={() => set({ appTheme: theme.key })}>
              <span className="setup-theme-swatch" style={{ background: theme.acc }} />
              <span><b>{theme.label}</b><small>App buttons and resident status pages</small></span>
              <Icon name={setup.appTheme === theme.key ? 'check' : 'chevronR'} size={16} />
            </button>
          ))}
        </div>
        <div className="setup-logo-row">
          <BuildingLogoPreview setup={setup} compact />
          <div>
            <label className="btn btn-out btn-sm setup-upload">Upload logo<input type="file" accept="image/png,image/jpeg" onChange={(e) => readLogoFile(e.target.files[0], (url) => { set({ logoUrl: url }); setToast('Logo uploaded'); }, setToast)} /></label>
            {setup.logoUrl && <button className="linkbtn" onClick={() => set({ logoUrl: '' })}>Remove logo</button>}
          </div>
        </div>
        <Note icon="info">A logo is optional. If you skip this, StrataSnap will use the default wordmark on setup previews and posters.</Note>
        <StepGuidance />
      </React.Fragment>
    );
    if (stepId === 'locations') return (
      <React.Fragment>
        <div className="setup-locations">
          {setup.locations.map((l) => (
            <button key={l.id} className={'setup-loc' + (l.active ? ' active' : '')} aria-pressed={l.active} onClick={() => updateLoc(l.id, { active: !l.active })}>
              <span><b>{l.name}</b><small>{l.floor} · {l.area}</small></span>
              <span className="setup-loc-state">{l.active ? 'Active' : 'Off'}</span>
            </button>
          ))}
        </div>
        <div className="setup-inline-status">{activeLocations.length} active locations. Choose at least five for the first pilot.</div>
        <StepGuidance />
      </React.Fragment>
    );
    if (stepId === 'posters') return (
      <React.Fragment>
        <div className="setup-qr-list">
          {activeLocations.map((l) => {
            const scanUrl = SS.qrScanUrl(setup, l);
            return (
              <div key={l.id} className="setup-qr-row">
                <span className="setup-mini-qr"><QRGraphic value={scanUrl} size={44} quiet={0} /></span>
                <span><b>{l.name}</b><small>{scanUrl.replace(/^https?:\/\//, '')}</small></span>
                <a className="btn btn-out btn-sm" href={scanUrl} target="_blank" rel="noreferrer">Open</a>
                <button className="btn btn-out btn-sm" onClick={() => { updateLoc(l.id, { tested: true, lastScanTestedAt: new Date().toISOString() }); setToast(l.name + ' scan tested'); }}>Test</button>
              </div>
            );
          })}
        </div>
        {!activeLocations.length && <div className="setup-inline-error">No active locations yet. Go back and choose reporting locations.</div>}
        <StepGuidance />
      </React.Fragment>
    );
    return (
      <React.Fragment>
        <div className="setup-actions">
          <Btn variant="out" onClick={testAll}><Icon name="qr" size={17} /> Run test scan</Btn>
          <Btn variant="out" onClick={sendNotification}><Icon name="send" size={17} /> Send notification test</Btn>
        </div>
        <div className="setup-review">
          <span className={readiness.tasks.find((t) => t.id === 'scan').done ? 'done' : ''}>{testedLocations.length}/{activeLocations.length} locations tested</span>
          <span className={readiness.tasks.find((t) => t.id === 'notify').done ? 'done' : ''}>Notification test {setup.notificationTested ? 'sent' : 'not sent'}</span>
          <span className={readiness.launchReady ? 'done' : ''}>{readiness.launchReady ? 'Ready to launch' : 'Launch blocked'}</span>
        </div>
        <StepGuidance />
      </React.Fragment>
    );
  };

  return (
    <div className="screen cd setup-screen">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>{setup.buildingName}</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Building setup</h1>
      </div>
      <div className="scroll">
        <div className="setup-hero">
          <div className="setup-hero-art"><img src="art/checklist.png" alt="" aria-hidden="true" /></div>
          <div className="setup-hero-copy">
            <span className="setup-eyebrow">Launch readiness</span>
            <h2>{setup.activated ? 'Ready to launch QR intake' : currentStep.label + ' setup'}</h2>
            <p>{setup.activated ? 'Residents can scan posters and reports will land in the issue inbox.' : 'Build the intake path in the same order council will approve it: building, routing, safety, locations, posters, then launch tests.'}</p>
          </div>
          <div className="setup-progress">
            <span>{readiness.percent}%</span>
            <i><b style={{ width: readiness.percent + '%' }} /></i>
          </div>
        </div>

        <div className="setup-checklist">
          {flowSteps.map((t, i) => <button key={t.id} className={(stepDone[t.id] ? 'done ' : '') + (stepId === t.id ? 'on' : '')} onClick={() => goStep(t.id)}><Icon name={stepDone[t.id] ? 'check' : stepId === t.id ? t.icon : 'clock'} size={13} />{i + 1}. {t.label}</button>)}
        </div>

        <div className="pad setup-pad">
          <section className="setup-flow-card" aria-labelledby="setup-flow-question">
            <span className="setup-flow-eyebrow">{currentStep.eyebrow}</span>
            <h2 id="setup-flow-question">{currentStep.question}</h2>
            <p>{currentStep.desc}</p>
            <div className="setup-flow-body">{renderStep()}</div>
          </section>
        </div>
      </div>
      <div className="setup-bottom-actions"><StepFooter /></div>
      <TabBar active="setup" go={go} />
      {toast && <Toast>{toast}</Toast>}
    </div>
  );
}

function Queue({ tickets, onOpen, onNew, go, toast }) {
  const SS = window.SS;
  const [view, setView] = React.useState('All');
  const open = (t) => SS.isOpenTicket(t);
  const isUrgent = (t) => open(t) && t.priority === 'High';
  const CHIPS = [['All', null], ['Urgent', 'var(--st-urgent)'], ['New', 'var(--st-blue)'], ['In review', 'var(--st-violet)'], ['Waiting', 'var(--st-amber)'], ['Resolved', 'var(--st-green)']];
  const match = (t) => {
    if (view === 'All') return true;
    if (view === 'Urgent') return isUrgent(t);
    if (view === 'New') return t.status === 'New';
    if (view === 'In review') return t.status === 'Needs review';
    if (view === 'Waiting') return t.status.startsWith('Waiting') || t.status === 'Scheduled';
    if (view === 'Resolved') return t.status === 'Resolved';
    return true;
  };
  const list = tickets.filter(match).slice().sort((a, b) => isUrgent(b) - isUrgent(a) || new Date(b.createdAt) - new Date(a.createdAt));

  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>Harbour View Strata</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <div className="cd-title-row">
          <h1 className="cd-title">Issue inbox</h1>
          <button className="cd-head-action" onClick={onNew}><Icon name="plus" size={15} /> Add issue</button>
        </div>
      </div>
      <div className="ib-chips">
        {CHIPS.map(([v, dot]) =>
        <button key={v} className={'ib-chip' + (view === v ? ' on' : '')} onClick={() => setView(v)}>
            {dot && <span className="ib-chip-dot" style={{ background: dot }} />}{v}
          </button>
        )}
      </div>
      <div className="ib-search">
        <span className="ib-searchbox"><Icon name="search" size={16} /><input placeholder="Search issues…" /></span>
        <button className="ib-sort"><Icon name="list" size={15} /> Sort</button>
      </div>
      <div className="scroll">
        <div className="qlist">
          {list.map((t, i) =>
          <button className="ibk" key={t.id} onClick={() => onOpen(t.id)}>
              <span className="ibk-thumb">
                <span className="ibk-blue"><Icon name={SS.catIcon(t.category)} size={20} /></span>
                <span className={'ibk-num tone-' + (isUrgent(t) ? 'red' : t.status === 'Resolved' ? 'green' : 'blue')}>{i + 1}</span>
              </span>
              <div className="ibk-main">
                <div className="ibk-t">{t.summary}</div>
                <div className="ibk-loc"><Icon name="pin" size={12} /> {t.locationName.replace(' – Elevator Lobby', '')}</div>
                <div className="ibk-meta">{SS.ageLabel(t)} · Reported by {t.reporterName}</div>
              </div>
              <div className="ibk-side">
                {isUrgent(t) ? <span className="stt is-urgent"><span className="dot" />Urgent</span> : <StatusDot status={t.status} short />}
                {t.assignee ? <Avatar name={t.assignee} /> : null}
              </div>
            </button>
          )}
          {list.length === 0 && <div style={{ textAlign: 'center', color: 'var(--ink-400)', padding: '40px 0', fontSize: 15 }}>Nothing here right now.</div>}
        </div>
      </div>
      <TabBar active="queue" go={go} />
      {toast && <Toast>{toast}</Toast>}
    </div>);

}

function TicketDetail({ ticket, onBack, patchTicket, addEvents, toast, setToast, go, pilotApi, refreshFromApi }) {
  const SS = window.SS;
  const [sheet, setSheet] = React.useState(null);
  const [showContact, setShowContact] = React.useState(false);

  if (!ticket) return null;

  const setStatus = (to) => patchTicket(ticket.id, (t) => ({ ...t, status: to }));
  const setField = (patch) => patchTicket(ticket.id, (t) => ({ ...t, ...patch }));
  const syncApiEvent = (event, status) => {
    if (!pilotApi) return;
    pilotApi.addEvent(ticket.id, { ...event, status }).then(() => refreshFromApi && refreshFromApi()).catch((err) => setToast('Saved locally; API event failed: ' + err.message));
  };
  function markResolved() {
    addEvents(ticket.id, [{ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'update', visibility: 'reporter-visible', body: 'This issue has been resolved.', author: 'Dana Lee' }, { id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'status-change', body: ticket.status + ' → Resolved' }]);
    syncApiEvent({ kind: 'update', visibility: 'reporter-visible', body: 'This issue has been resolved.' }, 'Resolved');
    setStatus('Resolved');setToast('Marked resolved · reporter notified (mock)');
  }

  function postUpdate(body) {
    addEvents(ticket.id, [{ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'update', visibility: 'reporter-visible', body, author: 'Dana Lee' }]);
    syncApiEvent({ kind: 'update', visibility: 'reporter-visible', body });
    setSheet(null);setToast('Update posted · reporter notified (mock)');
  }
  function saveNote(body) {
    addEvents(ticket.id, [{ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'note', visibility: 'private', body, author: 'Dana Lee' }]);
    syncApiEvent({ kind: 'note', visibility: 'private', body });
    setSheet(null);setToast('Private note saved · council only');
  }
  function applyTransition(tr, body) {
    const label = (s) => SS.statusActionLabel ? SS.statusActionLabel(s) : ((SS.STATUS[s] || {}).short || s);
    const evs = [];
    if (body && tr.lane === 'reporter-visible') evs.push({ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'update', visibility: 'reporter-visible', body, author: 'Dana Lee' });else
    if (body) evs.push({ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'note', visibility: 'private', body, author: 'Dana Lee' });
    evs.push({ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'status-change', body: `${label(ticket.status)} → ${label(tr.to)}` });
    addEvents(ticket.id, evs);
    syncApiEvent({ kind: body && tr.lane === 'reporter-visible' ? 'update' : 'note', visibility: tr.lane || 'private', body: body || `${label(ticket.status)} → ${label(tr.to)}` }, tr.to);
    setStatus(tr.to);
    setSheet(null);setToast('Status changed to ' + label(tr.to));
  }

  const transitions = SS.TRANSITIONS[ticket.status] || [];
  const isUrgent = ticket.priority === 'High' && SS.isOpenTicket(ticket);
  const reportedEv = ticket.timeline.find((e) => e.kind === 'submitted');
  const reporterUpdates = ticket.timeline.filter((e) => e.kind === 'update' && e.visibility === 'reporter-visible').length;
  const privateNotes = ticket.timeline.filter((e) => e.kind === 'note' && e.visibility === 'private').length;
  const sourceLabel = ticket.source === 'qr' ? 'QR poster' : ticket.source === 'email' ? 'Email' : ticket.source === 'phone' ? 'Phone' : 'Manual entry';

  return (
    <div className="screen cd">
      <StatusBar />
      <div className="nav">
        <button className="iconbtn" onClick={onBack}><Icon name="back" size={18} /></button>
        <span className="t" style={{ flex: '1 1 auto', textAlign: 'center' }}>Issue details</span>
        {isUrgent ? <span className="stt is-urgent" style={{ flex: '0 0 auto' }}><span className="dot" />Urgent</span> : <span style={{ flex: '0 0 auto' }}><StatusDot status={ticket.status} short /></span>}
      </div>

      <div className="scroll">
        <div className="pad">
          <div className="idt-card">
            <span className="idt-photo ph"><CatIcon id={ticket.category} size={28} /></span>
            <div className="idt-main">
              <div className="idt-title">{ticket.summary}</div>
              <div className="idt-loc">{ticket.locationName}</div>
              <div className="idt-meta"><span><Icon name="clock" size={13} /> {SS.ageLabel(ticket)}</span><span className="idt-id"><Icon name="qr" size={12} /> {ticket.id}</span></div>
            </div>
          </div>
          <div className="case-stamp" aria-label="Case source and record summary">
            <div className="case-stamp-item"><span className="case-stamp-k">Source</span><b className="case-stamp-v">{sourceLabel}</b></div>
            <div className="case-stamp-item"><span className="case-stamp-k">Poster</span><b className="case-stamp-v">{ticket.source === 'qr' ? SS.posterCode(ticket.locationId) : '—'}</b></div>
            <div className="case-stamp-item"><span className="case-stamp-k">Updates</span><b className="case-stamp-v">{reporterUpdates}</b></div>
            <div className="case-stamp-item"><span className="case-stamp-k">Notes</span><b className="case-stamp-v">{privateNotes}</b></div>
          </div>
          {reportedEv && <p className="idt-desc">{reportedEv.body}</p>}

          {/* two-lane composer — the trust mechanic (kept, unmistakable) */}
          <div className="sec-label">Respond</div>
          <div className="lane-actions">
            <button className="lane-btn pub" onClick={() => setSheet({ type: 'update' })}>
              <span className="ic"><Icon name="ssUpdate" size={20} /></span>
              <span><span className="tt">Send reporter update</span><span className="ds">Visible on the reporter status page</span></span>
              <Icon name="chevronR" size={18} className="chev" />
            </button>
            <button className="lane-btn priv" onClick={() => setSheet({ type: 'note' })}>
              <span className="ic"><Icon name="ssPrivate" size={20} /></span>
              <span><span className="tt">Private council note</span><span className="ds">For records and council review only</span></span>
              <Icon name="chevronR" size={18} className="chev" />
            </button>
          </div>

          {/* next-step controls */}
          <div className="sec-label">Next steps</div>
          <div className="panel">
            <button className="prow" onClick={() => setSheet({ type: 'status' })}>
              <span className="prow-ic"><Icon name="alert" size={17} /></span><span className="k" style={{ width: 'auto', flex: '1 1 auto' }}>Status</span><span className="v" style={{ flex: '0 0 auto' }}><StatusDot status={ticket.status} /></span><Icon name="chevronR" size={15} className="chev" />
            </button>
            <button className="prow" onClick={() => setSheet({ type: 'assignee' })}>
              <span className="prow-ic"><Icon name="user" size={17} /></span><span className="k" style={{ width: 'auto', flex: '1 1 auto' }}>Assigned to</span><span className="v" style={{ flex: '0 0 auto' }}>{ticket.assignee || <span style={{ color: 'var(--ink-400)' }}>Unassigned</span>}</span><Icon name="chevronR" size={15} className="chev" />
            </button>
            <button className="prow" onClick={() => setSheet({ type: 'responsibility' })}>
              <span className="prow-ic"><Icon name="scale" size={17} /></span><span className="k" style={{ width: 'auto', flex: '1 1 auto' }}>Who owns this?</span><span className="v" style={{ flex: '0 0 auto', fontWeight: 400, fontSize: 14 }}>{ticket.responsibility || <span style={{ color: 'var(--ink-400)' }}>Unclear</span>}</span><Icon name="chevronR" size={15} className="chev" />
            </button>
            <div className="prow" style={{ cursor: 'default' }}>
              <span className="prow-ic"><CatIcon id={ticket.category} size={17} /></span><span className="k" style={{ width: 'auto', flex: '1 1 auto' }}>Category</span><span className="v" style={{ flex: '0 0 auto', fontWeight: 400, fontSize: 14 }}>{SS.catLabel(ticket.category)}</span>
            </div>
          </div>

          {/* reporter contact — admin only */}
          <div className="sec-label">Reporter <span style={{ color: 'var(--ink-300)', fontWeight: 500 }}>· council only</span></div>
          {showContact ?
          <div className="panel">
              <div className="prow" style={{ cursor: 'default' }}><span className="k">Name</span><span className="v" style={{ fontWeight: 400 }}>{ticket.reporterName}</span></div>
              <div className="prow" style={{ cursor: 'default' }}><span className="k">Email</span><span className="v" style={{ fontWeight: 400 }}>{ticket.reporterEmail || '—'}</span></div>
              <div className="prow" style={{ cursor: 'default' }}><span className="k">Phone</span><span className="v" style={{ fontWeight: 400 }}>{ticket.reporterPhone || '—'}</span></div>
              <div className="prow" style={{ cursor: 'default' }}><span className="k">Unit</span><span className="v" style={{ fontWeight: 400 }}>{ticket.unit || '—'}</span></div>
              <button className="prow" onClick={() => setShowContact(false)}><span className="k">Contact</span><span className="v" style={{ fontWeight: 400, color: 'var(--ink-500)' }}>Hide details</span><Icon name="lock" size={15} className="chev" /></button>
            </div> :

          <button className="panel" onClick={() => setShowContact(true)} style={{ width: '100%', display: 'block', textAlign: 'left', cursor: 'pointer' }}>
              <div className="prow"><span className="prow-ic"><Icon name="eye" size={16} /></span><span className="v" style={{ fontWeight: 500, flex: '1 1 auto' }}>Show reporter contact</span><Icon name="chevronR" size={16} className="chev" /></div>
            </button>
          }

          {ticket.photos && ticket.photos.length > 0 &&
          <React.Fragment>
              <div className="sec-label">Photos <span style={{ color: 'var(--ink-300)', fontWeight: 500 }}>· council only</span></div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                {ticket.photos.map((p, i) => <IssuePhoto key={i} seed={p} i={i} className="photo-ph-img" alt={'Resident photo ' + (i + 1)} />)}
              </div>
            </React.Fragment>
          }
          {ticket.voiceNotes && ticket.voiceNotes.length > 0 &&
          <React.Fragment>
              <div className="sec-label">Voice notes <span style={{ color: 'var(--ink-300)', fontWeight: 500 }}>· council only</span></div>
              <div className="voice-list detail">
                {ticket.voiceNotes.map((v, i) => (
                  <div className="voice-item" key={v.id || i}>
                    <Icon name="mic" size={16} />
                    <span>Voice note {i + 1} · {Math.round((v.durationMs || 0) / 1000)}s</span>
                    <audio src={v.url} controls />
                  </div>
                ))}
              </div>
            </React.Fragment>
          }

          <div className="sec-label">Activity log</div>
          <div className="timeline">
            {ticket.timeline.slice().reverse().map((e) => <TimelineRow key={e.id} e={e} />)}
          </div>
          <div className="poweredby" style={{ marginTop: 14 }}>Powered by <b>Strata Match</b></div>
        </div>
      </div>

      <div className="footer">
        <div className="row">
          <Btn variant="out" onClick={() => setSheet({ type: 'update' })}><Icon name="message" size={17} /> Send update</Btn>
          <Btn variant="acc" onClick={markResolved} disabled={ticket.status === 'Resolved'}><Icon name="check" size={17} /> {ticket.status === 'Resolved' ? 'Resolved' : 'Mark resolved'}</Btn>
        </div>
        <HomeInd />
      </div>

      {sheet && sheet.type === 'update' &&
      <UpdateComposer ticket={ticket} onClose={() => setSheet(null)} onPost={postUpdate} />
      }
      {sheet && sheet.type === 'note' &&
      <NoteComposer onClose={() => setSheet(null)} onSave={saveNote} />
      }
      {sheet && sheet.type === 'status' &&
      <StatusSheet ticket={ticket} transitions={transitions} onClose={() => setSheet(null)} onPick={(tr) => setSheet({ type: 'transition', tr })} />
      }
      {sheet && sheet.type === 'transition' &&
      <TransitionComposer tr={sheet.tr} onClose={() => setSheet(null)} onApply={applyTransition} />
      }
      {sheet && sheet.type === 'assignee' &&
      <PickSheet title="Assigned to" options={[...PEOPLE, 'Unassigned']} current={ticket.assignee || 'Unassigned'}
      onClose={() => setSheet(null)} onPick={(v) => {setField({ assignee: v === 'Unassigned' ? null : v });setSheet(null);setToast('Assigned to ' + v);}} />
      }
      {sheet && sheet.type === 'responsibility' &&
      <PickSheet title="Who owns this issue?" subtitle="Internal record only. Use Not common property when the report should not become strata repair work." options={SS.RESPONSIBILITY} current={ticket.responsibility}
      onClose={() => setSheet(null)} onPick={(v) => {setField({ responsibility: v });setSheet(null);setToast('Handling decision saved');}} />
      }
      {toast && <Toast>{toast}</Toast>}
    </div>);

}

function TimelineRow({ e }) {
  const SS = window.SS;
  const cls = { submitted: 'm-submitted', 'status-change': 'm-status', update: 'm-update', note: 'm-note' }[e.kind] || '';
  return (
    <div className={'te ' + cls}>
      <span className="marker" />
      {e.kind === 'update' && <span className="lane-tag pub"><Icon name="eye" size={11} /> Reporter saw this</span>}
      {e.kind === 'note' && <span className="lane-tag priv"><Icon name="lock" size={11} /> Private</span>}
      <div className="when">{SS.whenLabel(e.at)}</div>
      <div className="body" style={e.kind === 'status-change' ? { fontWeight: 600, color: 'var(--ink-700)' } : null}>{e.body}</div>
      {e.author && e.kind !== 'status-change' && <div className="who">{e.author}</div>}
    </div>);

}

// ── composers ──────────────────────────────────────────────────
function UpdateComposer({ ticket, onClose, onPost }) {
  const [body, setBody] = React.useState('');
  const [stage, setStage] = React.useState('compose');
  const SS = window.SS;
  return (
    <Sheet title={stage === 'compose' ? 'Send reporter update' : 'Preview reporter update'} onClose={onClose}
    footer={stage === 'compose' ?
    <Btn variant="acc" disabled={!body.trim()} onClick={() => setStage('preview')}>Preview <Icon name="chevronR" size={16} /></Btn> :
    <React.Fragment><Btn variant="out" onClick={() => setStage('compose')}>Edit</Btn><Btn variant="acc" onClick={() => onPost(body.trim())}>Post to reporter</Btn></React.Fragment>}>
      <div className="lane-banner pub">
        <span className="ic"><Icon name="eye" size={18} /></span>
        <div><span className="tt">Visible to the reporter</span><span className="ds">Posts to their status page and sends an update notice.</span></div>
      </div>
      {stage === 'compose' ?
      <textarea className="inp" autoFocus placeholder="e.g. We’ve booked a plumber for Friday morning." value={body} onChange={(e) => setBody(e.target.value)} style={{ minHeight: 130 }} /> :

      <div>
          <div style={{ fontSize: 13, color: 'var(--ink-500)', marginBottom: 8 }}>This is exactly what the reporter sees:</div>
          <div className="update-card" style={{ marginTop: 0 }}>
            <div className="lbl"><Icon name="eye" size={13} /> Update from council</div>
            <div className="body">{body}</div>
            <div className="when">just now · Dana Lee</div>
          </div>
        </div>
      }
    </Sheet>);

}

function NoteComposer({ onClose, onSave }) {
  const [body, setBody] = React.useState('');
  return (
    <Sheet title="Private council note" onClose={onClose}
    footer={<Btn variant="dark" disabled={!body.trim()} onClick={() => onSave(body.trim())}>Save note</Btn>}>
      <div className="lane-banner priv">
        <span className="ic"><Icon name="lock" size={18} /></span>
        <div><span className="tt">Council and manager only</span><span className="ds">Saved to the record, but not shown on the reporter status page.</span></div>
      </div>
      <textarea className="inp" autoFocus placeholder="e.g. Check if the unit above had a renovation that caused this." value={body} onChange={(e) => setBody(e.target.value)} style={{ minHeight: 130 }} />
    </Sheet>);

}

function StatusSheet({ ticket, transitions, onClose, onPick }) {
  const label = (s) => window.SS.statusActionLabel ? window.SS.statusActionLabel(s) : ((window.SS.STATUS[s] || {}).short || s);
  return (
    <Sheet title="Change status" onClose={onClose}>
      <div style={{ fontSize: 14, color: 'var(--ink-500)', marginBottom: 14 }}>Currently <StatusDot status={ticket.status} />. Choose what happens next.</div>
      <div className="group" style={{ marginTop: 0 }}>
        {transitions.map((tr) =>
        <button className="opt" key={tr.to} onClick={() => onPick(tr)}>
            <span className="well"><span className={'dot ' + (window.SS.STATUS[tr.to] || {}).dot} style={{ width: 11, height: 11, borderRadius: '50%' }} /></span>
            <span className="lbl">{label(tr.to)}<span className="desc">{tr.requires || 'No extra details needed'}</span></span>
            <Icon name="chevronR" size={16} className="chev" />
          </button>
        )}
      </div>
    </Sheet>);

}

function TransitionComposer({ tr, onClose, onApply }) {
  const [body, setBody] = React.useState('');
  const need = !!tr.requires;
  const reporterLane = tr.lane === 'reporter-visible';
  const label = (s) => window.SS.statusActionLabel ? window.SS.statusActionLabel(s) : ((window.SS.STATUS[s] || {}).short || s);
  return (
    <Sheet title={'Move to ' + label(tr.to)} onClose={onClose}
    footer={<Btn variant="acc" disabled={need && !body.trim()} onClick={() => onApply(tr, body.trim())}>Confirm · {label(tr.to)}</Btn>}>
      {need &&
      <div className={'lane-banner ' + (reporterLane ? 'pub' : 'priv')}>
          <span className="ic"><Icon name={reporterLane ? 'eye' : 'lock'} size={18} /></span>
          <div><span className="tt">{reporterLane ? 'Visible to the reporter' : 'Council and manager only'}</span><span className="ds">{reporterLane ? 'Added to their status page' : 'Saved internally, not sent to the reporter'}</span></div>
        </div>
      }
      {need ?
      <Field label={tr.requires}><textarea className="inp" autoFocus value={body} onChange={(e) => setBody(e.target.value)} placeholder="Add the required detail…" /></Field> :
      <Note icon="info">No extra details are needed for this change.</Note>}
    </Sheet>);

}

function PickSheet({ title, subtitle, options, current, onClose, onPick }) {
  return (
    <Sheet title={title} onClose={onClose}>
      {subtitle && <div style={{ fontSize: 13, color: 'var(--ink-500)', marginBottom: 12 }}>{subtitle}</div>}
      <div className="group" style={{ marginTop: 0 }}>
        {options.map((o) =>
        <button className={'opt' + (o === current ? ' sel' : '')} key={o} onClick={() => onPick(o)}>
            <span className="lbl">{o}</span>
            <Icon name="chevronR" size={16} className="chev" />
            <Icon name="check" size={20} className="check" />
          </button>
        )}
      </div>
    </Sheet>);

}

// ── council-created ticket ─────────────────────────────────────
function NewTicket({ onBack, onCreate }) {
  const SS = window.SS;
  const [d, setD] = React.useState({ source: 'phone', locationId: 'lobby', category: null, summary: '', name: '', email: '', phone: '', unit: '' });
  const set = (p) => setD((x) => ({ ...x, ...p }));
  const [sheet, setSheet] = React.useState(null);
  const sources = ['email', 'phone', 'text', 'in person', 'council observation'];
  const loc = SS.LOCATIONS.find((l) => l.id === d.locationId);
  const canCreate = d.category && d.summary.trim();

  return (
    <div className="screen">
      <StatusBar />
      <div className="nav"><button className="iconbtn" onClick={onBack}><Icon name="back" size={18} /></button><span className="t">Add issue</span></div>
      <div className="scroll">
        <div className="pad">
          <h1 className="h-title">Log an issue</h1>
          <p className="h-sub">For issues that came in by phone, email, or that you spotted yourself.</p>

          <Field label="How did it come in?">
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {sources.map((s) =>
              <button key={s} onClick={() => set({ source: s })}
              className="chip" style={d.source === s ? { background: 'var(--acc)', color: '#fff', borderColor: 'var(--acc)', textTransform: 'capitalize' } : { textTransform: 'capitalize', cursor: 'pointer' }}>{s}</button>
              )}
            </div>
          </Field>

          <Field label="Location">
            <button className="inp" style={{ textAlign: 'left', display: 'flex', alignItems: 'center', cursor: 'pointer' }} onClick={() => setSheet('loc')}>
              <span className="flex1">{loc.name}</span><Icon name="down" size={16} style={{ color: 'var(--ink-400)' }} />
            </button>
          </Field>

          <Field label="Category">
            <button className="inp" style={{ textAlign: 'left', display: 'flex', alignItems: 'center', cursor: 'pointer', color: d.category ? 'var(--ink-900)' : 'var(--ink-300)' }} onClick={() => setSheet('cat')}>
              <span className="flex1">{d.category ? SS.catLabel(d.category) : 'Choose a category'}</span><Icon name="down" size={16} style={{ color: 'var(--ink-400)' }} />
            </button>
          </Field>

          <Field label="Summary">
            <input className="inp" placeholder="Short description of the issue" value={d.summary} onChange={(e) => set({ summary: e.target.value })} />
          </Field>

          <div className="sec-label">Reporter <span style={{ color: 'var(--ink-300)', fontWeight: 500 }}>· optional</span></div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <input className="inp" placeholder="Name" value={d.name} onChange={(e) => set({ name: e.target.value })} />
            <input className="inp" placeholder="Unit" value={d.unit} onChange={(e) => set({ unit: e.target.value })} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 12 }}>
            <input className="inp" placeholder="Email" value={d.email} onChange={(e) => set({ email: e.target.value })} />
            <input className="inp" placeholder="Phone" value={d.phone} onChange={(e) => set({ phone: e.target.value })} />
          </div>
          {(d.name || d.email || d.phone) && <Note icon="lock">Contact details you enter are stored on the issue for council only.</Note>}
        </div>
      </div>
      <div className="footer">
        <Btn variant="acc" disabled={!canCreate} onClick={() => onCreate({ ...d, locationName: loc.name })}>Add issue</Btn>
        <HomeInd />
      </div>

      {sheet === 'loc' && <PickSheet title="Location" options={SS.LOCATIONS.map((l) => l.name)} current={loc.name}
      onClose={() => setSheet(null)} onPick={(name) => {set({ locationId: SS.LOCATIONS.find((l) => l.name === name).id });setSheet(null);}} />}
      {sheet === 'cat' && <PickSheet title="Category" options={SS.CATEGORIES.map((c) => c.label)} current={d.category ? SS.catLabel(d.category) : null}
      onClose={() => setSheet(null)} onPick={(label) => {set({ category: SS.CATEGORIES.find((c) => c.label === label).id });setSheet(null);}} />}
    </div>);

}

Object.assign(window, { Queue, TicketDetail, NewTicket, CouncilDashboard, BuildingSetupMobile, BuildingMapMobile });

// ── QR posters ─────────────────────────────────────────────────
function Posters({ setup, onBack, onOpen, go }) {
  const SS = window.SS;
  const posterLocations = SS.setupLocations(setup, { activeOnly: true });
  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>{setup.buildingName}</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Poster network</h1>
      </div>
      <div className="scroll">
        <div className="pad">
          <p className="h-sub">One code per location. Print a poster and place it where residents will see the problem.</p>
          <div className="group" style={{ marginTop: 16 }}>
            {posterLocations.map((l) =>
            <button className="opt" key={l.id} onClick={() => onOpen(l.id)}>
                <span className="well" style={{ background: 'var(--page)', border: '1px solid var(--line2)', padding: 4 }}><QRGraphic value={SS.qrScanUrl(setup, l)} size={30} quiet={0} /></span>
                <span className="lbl">{l.name}<span className="desc">{l.area} · code active</span></span>
                <Icon name="chevronR" size={16} className="chev" />
              </button>
            )}
          </div>
          <Note icon="info">Codes are pre-set for this building. Reprinting a poster keeps the same code, so old stickers keep working.</Note>
        </div>
      </div>
      <TabBar active="posters" go={go} />
    </div>);

}

function BuildingMapMobile({ tickets, onOpen, go }) {
  const SS = window.SS;
  const LEVELS = [['Level 1', 'Ground'], ['Level 2', 'Residential'], ['Parkade', 'P2']];
  const [lvl, setLvl] = React.useState('Parkade');
  const open = (t) => SS.isOpenTicket(t);
  const stats = SS.locationStats(tickets).filter((s) => s.count > 0);
  const onLevel = tickets.filter(open);
  const c = {
    urgent: onLevel.filter((t) => t.priority === 'High').length,
    waiting: onLevel.filter((t) => t.status.startsWith('Waiting') || t.status === 'Scheduled').length,
    review: onLevel.filter((t) => t.status === 'Needs review' || t.status === 'New').length,
    resolved: tickets.filter((t) => t.status === 'Resolved').length
  };
  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>Harbour View Strata</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Building map</h1>
      </div>
      <div className="scroll">
        <div className="bm-levels">
          {LEVELS.map(([l]) => <button key={l} className={'bm-level' + (lvl === l ? ' on' : '')} onClick={() => setLvl(l)}>{l}</button>)}
        </div>
        <div className="rev-map" style={{ aspectRatio: '1/1', margin: '0 16px', borderRadius: 'var(--ios-radius)' }}>
          <img className="rev-map-img" src="art/floor-map.png" alt="" onError={(e) => {e.target.closest('.rev-map').classList.add('noimg');}} />
          {stats.map((s) =>
          <button key={s.loc.id} className={'cd-mappin tone-' + s.tone} style={{ left: s.loc.x * 100 + '%', top: s.loc.y * 100 + '%', cursor: 'pointer' }} onClick={() => s.open[0] && onOpen(s.open[0].id)}>{s.count}</button>
          )}
        </div>
        <div className="bm-legend">
          <span><span className="ml-dot" style={{ background: 'var(--st-urgent)' }} /> Urgent</span>
          <span><span className="ml-dot" style={{ background: 'var(--st-amber)' }} /> Waiting</span>
          <span><span className="ml-dot" style={{ background: 'var(--st-violet)' }} /> In review</span>
          <span><span className="ml-dot" style={{ background: 'var(--st-green)' }} /> Resolved</span>
        </div>
        <div className="bm-openrow"><span><b>{onLevel.length} open</b> on this level</span><button className="linkbtn" onClick={() => go('queue')}>View all →</button></div>
        <div className="bm-stats">
          <div className="bm-stat"><Icon name="alert" size={15} style={{ color: 'var(--st-urgent)' }} /><b>{c.urgent}</b><span>Urgent</span></div>
          <div className="bm-stat"><span className="ml-dot" style={{ background: 'var(--st-amber)' }} /><b>{c.waiting}</b><span>Waiting</span></div>
          <div className="bm-stat"><span className="ml-dot" style={{ background: 'var(--st-violet)' }} /><b>{c.review}</b><span>In review</span></div>
          <div className="bm-stat"><Icon name="check" size={15} style={{ color: 'var(--st-green)' }} /><b>{c.resolved}</b><span>Resolved</span></div>
        </div>
      </div>
      <TabBar active="dashboard" go={go} />
    </div>);

}

function Updates({ tickets, onOpen, go }) {
  const SS = window.SS;
  const items = SS.feed(tickets, 24);
  const tag = (e) => {
    if (e.kind === 'update') return { cls: 'pub', icon: 'eye', label: 'Update to reporter' };
    if (e.kind === 'note') return { cls: 'priv', icon: 'lock', label: 'Private note' };
    if (e.kind === 'submitted') return { cls: 'new', icon: 'plus', label: 'New report' };
    return { cls: 'status', icon: 'chevronR', label: 'Status change' };
  };
  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('settings')}><Icon name="building" size={17} /><span>Harbour View Strata</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Recent activity</h1>
      </div>
      <div className="scroll">
        <div className="feed">
          {items.map((it, i) => {
            const tg = tag(it.e);
            return (
              <button className="feed-item" key={i} onClick={() => onOpen(it.ticketId)}>
                <span className={'feed-mk ' + tg.cls}><Icon name={tg.icon} size={14} /></span>
                <div className="feed-body">
                  <div className="feed-top"><span className="feed-tag">{tg.label}</span><span className="feed-when">{SS.whenLabel(it.e.at)}</span></div>
                  <div className="feed-text">{it.e.body}</div>
                  <div className="feed-ref"><span className="id-mono">{it.ticketId}</span> · {it.summary}</div>
                </div>
              </button>);

          })}
        </div>
      </div>
      <TabBar active="dashboard" go={go} />
    </div>);

}

function PosterDetail({ setup, locationId, onBack, setToast, toast }) {
  const SS = window.SS;
  const loc = SS.setupLocationById(setup, locationId) || SS.setupLocations(setup, { activeOnly: true })[0] || SS.LOCATIONS[0];
  const scanUrl = SS.qrScanUrl(setup, loc);
  const printPoster = () => {
    window.print();
    setToast('Print dialog opened for ' + loc.name);
  };
  return (
    <div className="screen">
      <StatusBar />
      <div className="nav">
        <button className="iconbtn" onClick={onBack}><Icon name="back" size={18} /></button>
        <span className="t">Poster</span>
        <button className="iconbtn" style={{ marginLeft: 'auto' }} onClick={printPoster}><Icon name="printer" size={18} /></button>
      </div>
      <div className="scroll">
        <div className="pad">
          {/* the printable poster artifact */}
          <div className="poster">
            <div className="poster-eyebrow">{setup.buildingName || 'Harbour View Strata'}</div>
            <h2 className="poster-title">See something that needs fixing?</h2>
            <p className="poster-sub">Scan this code to report a maintenance issue to your council. Takes about a minute — no account needed.</p>
            <div className="poster-qr"><QRGraphic value={scanUrl} size={188} /></div>
            <div className="poster-loc"><Icon name="pin" size={15} /> {loc.name}</div>
            <div className="poster-foot">{scanUrl.replace(/^https?:\/\//, '')}</div>
            <div className="poster-foot">StrataSnap · Powered by <b>Strata Match</b></div>
          </div>
          <a className="btn btn-out" href={scanUrl} target="_blank" rel="noreferrer" style={{ marginTop: 18 }}><Icon name="qr" size={18} /> Open test scan</a>
          <Btn variant="acc" style={{ marginTop: 10 }} onClick={printPoster}><Icon name="printer" size={18} /> Print poster</Btn>
          <Btn variant="out" style={{ marginTop: 10 }} onClick={onBack}>Back to posters</Btn>
        </div>
      </div>
      {toast && <Toast icon="download">{toast}</Toast>}
    </div>);

}

Object.assign(window, { Posters, PosterDetail, Updates });

// ── council magic-link sign-in (mock) ──────────────────────────
function CouncilLogin({ onAuthed }) {
  const [email, setEmail] = React.useState('dana.lee@harbourview.ca');
  const [pw, setPw] = React.useState('');
  const [show, setShow] = React.useState(false);
  return (
    <div className="screen signin">
      <StatusBar />
      <div className="scroll">
        <div className="si-hero">
          <div className="si-clouds" aria-hidden="true">
            <span className="si-cloud c1"></span><span className="si-cloud c2"></span><span className="si-cloud c3"></span>
          </div>
          <svg className="si-birds" width="78" height="30" viewBox="0 0 78 30" fill="none" stroke="rgba(30,80,200,.45)" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true">
            <path d="M4 16 q5 -6 10 0 q5 -6 10 0" /><path d="M44 9 q4.5 -5 9 0 q4.5 -5 9 0" /><path d="M30 24 q4 -4.5 8 0 q4 -4.5 8 0" />
          </svg>
          <img className="si-skyline" src="art/condo-cluster.png" alt="" aria-hidden="true" onError={(e) => {e.target.style.display = 'none';}} />
          <div className="si-scrim" aria-hidden="true"></div>
          <div className="si-top">
            <div className="si-logo"><Logo tone="dark" size={30} /></div>
            <h1 className="si-h1">Building issues,<br />clearly tracked.</h1>
            <p className="si-sub">QR reporting, council updates, and clean issue records for strata communities.</p>
          </div>
        </div>

        <div className="si-card">
          <div className="si-card-head">
            <h2>Sign in to StrataSnap</h2>
            <p>Access your building issue inbox and council records.</p>
          </div>
          <div className="si-field">
            <Icon name="message" size={18} />
            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email address" autoComplete="email" />
          </div>
          <Btn variant="acc" onClick={() => onAuthed(email)}>Email me a sign-in link <Icon name="send" size={17} /></Btn>
          <div className="si-or"><span>OR</span></div>
          <button className="si-google" onClick={() => onAuthed(email)}>
            <span className="g-mark" aria-hidden="true">G</span> Continue with Google
          </button>
          <button className="si-google" style={{ marginTop: 10 }} onClick={() => onAuthed(email)}>
            <span className="ms-mark" aria-hidden="true"><svg width="15" height="15" viewBox="0 0 16 16"><rect width="7" height="7" fill="#F25022" /><rect x="9" width="7" height="7" fill="#7FBA00" /><rect y="9" width="7" height="7" fill="#00A4EF" /><rect x="9" y="9" width="7" height="7" fill="#FFB900" /></svg></span> Continue with Microsoft
          </button>
          <div className="si-cardlinks"><button className="linkbtn" onClick={() => onAuthed(email)}>Forgot password?</button><span className="si-div" /><button className="linkbtn" onClick={() => onAuthed(email)}>Request access</button></div>
        </div>

        <button className="si-resident" onClick={onAuthed}>Trying to report an issue? <span>Track a report →</span></button>

        <div className="si-features">
          <div className="si-feat"><span className="si-feat-ic"><Icon name="ssInbox" size={20} /></span>Issue inbox</div>
          <div className="si-feat"><span className="si-feat-ic"><Icon name="ssPoster" size={20} /></span>QR posters</div>
          <div className="si-feat"><span className="si-feat-ic"><Icon name="ssCase" size={20} /></span>Case files</div>
          <div className="si-feat"><span className="si-feat-ic"><Icon name="shieldCheck" size={20} /></span>Private access</div>
        </div>
        <div className="si-foot">
          <Icon name="lock" size={14} />
          <div>Secure. Trusted. Built for Strata communities.<br /><span>StrataSnap is a product by <b>StrataMatch</b>.</span></div>
        </div>
        <HomeInd />
      </div>
    </div>);

}

Object.assign(window, { CouncilLogin });

function CouncilSettings({ setup, onBack, go, onSignOut }) {
  const [notif, setNotif] = React.useState({ newReports: true, replies: true, weekly: false });
  const tog = (k) => setNotif((n) => ({ ...n, [k]: !n[k] }));
  const activeLocations = (setup && setup.locations ? setup.locations : []).filter((l) => l.active);
  const locationPreview = activeLocations.slice(0, 3).map((l) => l.name).join(', ');
  const Row = ({ k, label, desc }) =>
  <button className="set-row" onClick={() => tog(k)}>
      <span className="set-row-t"><span className="set-label">{label}</span><span className="set-desc">{desc}</span></span>
      <span className={'switch' + (notif[k] ? ' on' : '')}><span className="knob" /></span>
    </button>;

  return (
    <div className="screen cd">
      <StatusBar />
      <div className="cd-head">
        <div className="cd-bar"><Logo tone="dark" size={26} /><button className="rh-bell" aria-label="Notifications"><Icon name="message" size={20} /><span className="rh-dot" /></button></div>
        <button className="cd-bldg" onClick={() => go('dashboard')}><Icon name="building" size={17} /><span>{setup.buildingName}</span><Icon name="down" size={16} style={{ marginLeft: 'auto', color: 'var(--ink-400)' }} /></button>
        <h1 className="cd-title">Settings</h1>
      </div>
      <div className="scroll">
        <div className="pad">
          <div className="set-section">Building</div>
          <div className="group">
            <div className="opt" style={{ cursor: 'default' }}><span className="well"><Icon name="building" size={18} /></span><span className="lbl">{setup.buildingName}<span className="desc">{setup.lots} lots · {setup.city || 'Vancouver, BC'}</span></span></div>
            <div className="opt" style={{ cursor: 'default' }}><span className="well"><Icon name="pin" size={18} /></span><span className="lbl">{activeLocations.length} reporting locations<span className="desc">{locationPreview || 'No active locations yet'}…</span></span></div>
          </div>

          <div className="set-section">Council members</div>
          <div className="group">
            <div className="opt" style={{ cursor: 'default' }}><span className="av" style={{ width: 34, height: 34 }}>DL</span><span className="lbl">Dana Lee<span className="desc">Council chair · you</span></span></div>
            <div className="opt" style={{ cursor: 'default' }}><span className="av" style={{ width: 34, height: 34 }}>AM</span><span className="lbl">Alex Morgan<span className="desc">Member</span></span></div>
            <button className="opt"><span className="well"><Icon name="plus" size={18} /></span><span className="lbl" style={{ color: 'var(--acc-text)' }}>Invite a member</span><Icon name="chevronR" size={16} className="chev" /></button>
          </div>

          <div className="set-section">Notifications</div>
          <div className="group set-toggles">
            <Row k="newReports" label="New reports" desc="When a resident submits an issue" />
            <Row k="replies" label="Reporter replies" desc="When a resident responds to an update" />
            <Row k="weekly" label="Weekly digest" desc="A Monday summary of open issues" />
          </div>

          <button className="btn btn-out" style={{ marginTop: 18 }} onClick={onSignOut}>Sign out</button>
          <div className="poweredby" style={{ marginTop: 16 }}>StrataSnap · Powered by <b>Strata Match</b></div>
        </div>
      </div>
      <TabBar active="settings" go={go} />
    </div>);

}

Object.assign(window, { CouncilSettings });
