// MedBridge — desktop-first web variant.
// Same tokens, same screens, different chrome:
//   - Persistent left sidebar nav (role-based) replaces bottom tabs.
//   - Top bar with search + persona pill.
//   - Split-pane layouts where they help on desktop:
//       Discover  → filter rail + results grid (2-up cards)
//       Chats     → thread list + active conversation (Slack-style)
//       Listings  → table-style row list with inline applicant counts
//   - Single-column screens (Listing detail, News, Profile, New-listing
//     wizard, Onboarding, Apply success) are reused from the mobile build,
//     centered in a max-width column. They were already responsive enough.

const { useState: useSD, useEffect: useED } = React;

// ─────────────────────────────────────────────────────────────
// Browser frame — mock window chrome so the desktop preview is
// recognisable as a web app rather than just a big phone screen.
// ─────────────────────────────────────────────────────────────
function BrowserFrame({ width, height, url = 'https://medbridge.at/app', children }) {
  return (
    <div style={{
      width, height, background: '#E7EAF0', borderRadius: 12, overflow: 'hidden',
      boxShadow: '0 1px 0 rgba(255,255,255,.4) inset, 0 24px 60px rgba(15,27,45,.18)',
      display: 'flex', flexDirection: 'column',
      fontFamily: MB.font,
    }}>
      {/* window titlebar */}
      <div style={{
        height: 36, display: 'flex', alignItems: 'center', gap: 12,
        padding: '0 14px', background: '#DDE1E8',
        borderBottom: '1px solid rgba(15,27,45,0.08)',
      }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#FF5F57' }} />
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#FEBC2E' }} />
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#28C840' }} />
        </div>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{
            background: '#F4F6FA', border: '1px solid rgba(15,27,45,0.08)',
            borderRadius: 8, padding: '4px 14px', minWidth: 360,
            fontSize: 12, color: MB.ink.tertiary, textAlign: 'center',
            display: 'inline-flex', alignItems: 'center', gap: 8, justifyContent: 'center',
          }}>
            <Icon name="shield" size={12} color={MB.success[600]} />
            <span style={{ fontVariantNumeric: 'tabular-nums' }}>{url}</span>
          </div>
        </div>
        <div style={{ width: 60 }} />
      </div>
      <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>{children}</div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Sidebar — role-based nav. Logo, nav items, persona footer.
// ─────────────────────────────────────────────────────────────
function DesktopSidebar({ persona, active, onChange, unread, onNewListing }) {
  const isHost = !!persona.canHost;
  const items = [
    { id: 'home', icon: 'home', label: 'Start' },
    isHost
      ? { id: 'listings', icon: 'briefcase', label: 'Meine Inserate' }
      : { id: 'discover', icon: 'search', label: 'Suchen' },
    { id: 'news', icon: 'news', label: 'News' },
    { id: 'chats', icon: 'message', label: 'Nachrichten', badge: unread },
    { id: 'calendar', icon: 'calendar', label: 'Kalender' },
    { id: 'profile', icon: 'user', label: 'Profil' },
  ];
  return (
    <aside style={{
      width: 240, flex: 'none', display: 'flex', flexDirection: 'column',
      background: '#0F1B2D', color: '#fff', minHeight: 0,
    }}>
      {/* Brand */}
      <div style={{ padding: '20px 18px 16px', display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{
          width: 32, height: 32, borderRadius: 8, background: MB.brand[600],
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <Icon name="stethoscope" size={18} color="#fff" />
        </span>
        <div>
          <div style={{ fontFamily: MB.font, fontSize: 16, fontWeight: 700, letterSpacing: -0.2 }}>MedBridge</div>
          <div style={{ fontFamily: MB.font, fontSize: 11, color: 'rgba(255,255,255,0.5)', fontWeight: 500 }}>Beta · de-AT</div>
        </div>
      </div>

      {/* Primary CTA for hosts */}
      {isHost && (
        <div style={{ padding: '4px 14px 12px' }}>
          <button onClick={onNewListing} style={{
            width: '100%', height: 40, border: 0, borderRadius: 10,
            background: MB.brand[600], color: '#fff', cursor: 'pointer',
            fontFamily: MB.font, fontSize: 14, fontWeight: 600,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
            letterSpacing: -0.1,
          }}>
            <Icon name="plus" size={16} color="#fff" />
            Neues Inserat
          </button>
        </div>
      )}

      {/* Nav */}
      <nav style={{ flex: 1, overflow: 'auto', padding: '4px 10px', display: 'flex', flexDirection: 'column', gap: 2 }}>
        {items.map(it => {
          const isA = active === it.id;
          return (
            <button key={it.id} onClick={() => onChange(it.id)} style={{
              border: 0, cursor: 'pointer', textAlign: 'left',
              background: isA ? 'rgba(255,255,255,0.10)' : 'transparent',
              color: isA ? '#fff' : 'rgba(255,255,255,0.72)',
              padding: '10px 12px', borderRadius: 8,
              display: 'flex', alignItems: 'center', gap: 12,
              fontFamily: MB.font, fontSize: 14, fontWeight: 600,
              transition: 'background 120ms ease-out',
            }}>
              <Icon name={it.icon} size={18} color="currentColor" stroke={isA ? 2 : 1.6} />
              <span style={{ flex: 1 }}>{it.label}</span>
              {it.badge > 0 && (
                <span style={{
                  minWidth: 20, height: 20, padding: '0 6px', borderRadius: 999,
                  background: MB.danger[600], color: '#fff', fontSize: 11, fontWeight: 700,
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  fontVariantNumeric: 'tabular-nums',
                }}>{it.badge}</span>
              )}
            </button>
          );
        })}
      </nav>

      {/* Persona footer */}
      <div style={{
        padding: '12px 14px 16px', borderTop: '1px solid rgba(255,255,255,0.08)',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <Avatar name={persona.name} size={36} verified />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: MB.font, fontSize: 13, fontWeight: 700, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{persona.name}</div>
          <div style={{ fontFamily: MB.font, fontSize: 11, color: 'rgba(255,255,255,0.55)' }}>{MB.career[persona.stage]?.short || persona.stage}</div>
        </div>
        <Icon name="settings" size={16} color="rgba(255,255,255,0.55)" />
      </div>
    </aside>
  );
}

// ─────────────────────────────────────────────────────────────
// Topbar — title + search + bell. Lightweight.
// ─────────────────────────────────────────────────────────────
function DesktopTopbar({ title, subtitle, action }) {
  return (
    <header style={{
      height: 64, flex: 'none', display: 'flex', alignItems: 'center', gap: 16,
      padding: '0 24px', background: MB.surface.raised,
      borderBottom: `1px solid ${MB.line.hair}`,
    }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: MB.font, fontSize: 18, fontWeight: 700, color: MB.ink.primary, letterSpacing: -0.2 }}>{title}</div>
        {subtitle && <div style={{ fontFamily: MB.font, fontSize: 13, color: MB.ink.tertiary, marginTop: 2 }}>{subtitle}</div>}
      </div>
      <div style={{ width: 320 }}>
        <Input leading={<Icon name="search" size={16} />} placeholder="Suchen — Praxis, Region, Person …" />
      </div>
      {action}
      <span style={{
        width: 40, height: 40, borderRadius: 999, background: MB.surface.canvas,
        border: `1px solid ${MB.line.hair}`,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', position: 'relative',
      }}>
        <Icon name="bell" size={18} color={MB.ink.secondary} />
        <span style={{ position: 'absolute', top: 9, right: 10, width: 8, height: 8, borderRadius: 999, background: MB.danger[600], border: '2px solid #fff' }} />
      </span>
    </header>
  );
}

// ─────────────────────────────────────────────────────────────
// Desktop Home — 2-column dashboard.
// Left: action tiles, bookings, host's own listings.
// Right: recommendations, news teaser, mini calendar.
// ─────────────────────────────────────────────────────────────
function DesktopHome({ persona, onOpenListing, onOpenApplicants, onNewListing, onOpenCalendar }) {
  const isKPJ = persona.stage === 'KPJ';
  const canHost = persona.canHost;
  const recos = isKPJ
    ? SAMPLE.ausbildungen.slice(0, 3)
    : [SAMPLE.vertretungen[0], SAMPLE.ausbildungen[0], SAMPLE.vertretungen[2]];

  const actions = [];
  if (canHost) {
    actions.push({ type: 'Vertretung', side: 'offer', label: 'Vertretung anbieten', sub: 'Praxis abdecken lassen', icon: 'plus' });
    if (persona.hasBefugnis) actions.push({ type: 'Ausbildung', side: 'offer', label: 'Ausbildungsstelle anbieten', sub: 'KPJ · Lehrpraxis', icon: 'plus' });
  } else {
    if (!isKPJ) actions.push({ type: 'Vertretung', side: 'search', label: 'Vertretung suchen', sub: 'Termine · Region', icon: 'search' });
    actions.push({ type: 'Ausbildung', side: 'search', label: isKPJ ? 'KPJ-Stelle finden' : 'Ausbildung finden', sub: 'Lehrpraxis · KPJ', icon: 'search' });
  }

  return (
    <div style={{ padding: '24px 28px', display: 'grid', gridTemplateColumns: 'minmax(0,2fr) minmax(280px,1fr)', gap: 28, alignItems: 'start' }}>
      {/* LEFT column */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 28, minWidth: 0 }}>

        {/* Greeting */}
        <div>
          <div style={{ fontFamily: MB.font, fontSize: 14, color: MB.ink.tertiary, fontWeight: 500 }}>Guten Tag,</div>
          <div style={{ fontFamily: MB.font, fontSize: 28, fontWeight: 700, color: MB.ink.primary, letterSpacing: -0.4, marginTop: 2 }}>{persona.name}</div>
        </div>

        {/* Action tiles */}
        <div>
          <DesktopSectionTitle>Was möchten Sie tun?</DesktopSectionTitle>
          <div style={{ display: 'grid', gridTemplateColumns: `repeat(${actions.length}, minmax(0, 1fr))`, gap: 12, marginTop: 12 }}>
            {actions.map((a, i) => (
              <BigActionTile key={i} {...a}
                onClick={() => {
                  if (a.side === 'offer') onNewListing && onNewListing(a.type);
                  else onOpenListing && onOpenListing(null, a.type);
                }} />
            ))}
          </div>
        </div>

        {/* Today & upcoming */}
        <div>
          <DesktopSectionTitle action="Kalender ›" onActionClick={onOpenCalendar}>Heute & demnächst</DesktopSectionTitle>
          <div style={{ marginTop: 12 }}>
            {canHost && (
              <BookingCard booking={{
                type: 'Vertretung', role: 'host',
                title: 'Dr. M. Berger vertritt Ihre Praxis',
                dateRange: 'Mo 18. — Fr 29. Aug 2026', location: '1080 Wien', status: 'Bestätigt',
              }} />
            )}
            {!canHost && !isKPJ && (
              <BookingCard booking={{
                type: 'Vertretung', role: 'searcher',
                title: 'Vertretung Praxis Dr. Wallner',
                dateRange: 'Di 9. — Fr 12. Sep 2026', location: '1180 Wien', status: 'Heute',
              }} />
            )}
            {isKPJ && (
              <BookingCard booking={{
                type: 'Ausbildung', role: 'searcher',
                title: 'KPJ-Tertial AM · Praxis Hofer',
                dateRange: 'Okt 2026 — Jän 2027', location: '1080 Wien', status: 'Bestätigt',
              }} />
            )}
          </div>
        </div>

        {/* Host listings */}
        {canHost && (
          <div>
            <DesktopSectionTitle action="Alle verwalten ›">Ihre offenen Inserate</DesktopSectionTitle>
            <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
              <div onClick={() => onOpenApplicants && onOpenApplicants(SAMPLE.ausbildungen[0].id)} style={{ cursor: 'pointer' }}>
                <ListingCardAusbildung listing={SAMPLE.ausbildungen[0]} density="expanded" />
                <ApplicantsHint count={4} fresh={2} tone="ausbildung" />
              </div>
            </div>
          </div>
        )}
      </div>

      {/* RIGHT column */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 24, minWidth: 0 }}>

        {/* Recommendations */}
        <DesktopCard title="Empfehlungen" action="Alle ›">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {recos.map(l => {
              const ineligible = isKPJ && l.type === 'Vertretung';
              return (
                <div key={l.id} onClick={() => !ineligible && onOpenListing && onOpenListing(l.id)} style={{ cursor: ineligible ? 'default' : 'pointer' }}>
                  <ListingCard listing={l} density="compact"
                    greyed={ineligible}
                    greyReason={ineligible ? 'Für Assistenzärzte und Niedergelassene' : undefined} />
                </div>
              );
            })}
          </div>
        </DesktopCard>

        {/* News teaser */}
        <DesktopCard title="Aus der Ärztekammer" action="News ›">
          <NewsCard item={SAMPLE.news.find(n => n.kind === 'editorial')} compact />
        </DesktopCard>

        {/* Mini calendar */}
        <DesktopCard title="Diese Woche">
          <div style={{ background: MB.surface.canvas, border: `1px solid ${MB.line.hair}`, borderRadius: 12, padding: 14 }}>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 6, fontFamily: MB.font, fontSize: 11, color: MB.ink.tertiary, fontWeight: 600, marginBottom: 6 }}>
              {['Mo','Di','Mi','Do','Fr','Sa','So'].map((d,i) => (
                <div key={d} style={{ textAlign: 'center' }}>
                  <div>{d}</div>
                  <div style={{ marginTop: 4, fontSize: 14, color: MB.ink.primary, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{11+i}</div>
                </div>
              ))}
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 6, marginTop: 6 }}>
              {[null,null,'V','V',null,null,null].map((c,i) => (
                <div key={i} style={{ height: 22, borderRadius: 6, background: c === 'V' ? MB.vertretung[100] : 'transparent', border: c === 'V' ? `1px solid ${MB.vertretung[600]}` : 'none' }} />
              ))}
              {[null,null,null,null,'A','A','A'].map((c,i) => (
                <div key={'b'+i} style={{ height: 22, borderRadius: 6, background: c === 'A' ? MB.ausbildung[100] : 'transparent', border: c === 'A' ? `1px solid ${MB.ausbildung[600]}` : 'none' }} />
              ))}
            </div>
            <div style={{ marginTop: 12, display: 'flex', gap: 14, fontFamily: MB.font, fontSize: 12, color: MB.ink.secondary }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 10, borderRadius: 3, background: MB.vertretung[600] }} />Vertretung</span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 10, borderRadius: 3, background: MB.ausbildung[600] }} />Ausbildung</span>
            </div>
          </div>
        </DesktopCard>
      </div>
    </div>
  );
}

function DesktopSectionTitle({ children, action, onActionClick }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
      <h3 style={{ fontFamily: MB.font, fontSize: 16, fontWeight: 700, color: MB.ink.primary, margin: 0, letterSpacing: -0.2 }}>{children}</h3>
      {action && <span onClick={onActionClick} style={{ fontFamily: MB.font, fontSize: 13, fontWeight: 600, color: MB.brand[600], cursor: 'pointer' }}>{action}</span>}
    </div>
  );
}

function DesktopCard({ title, action, children }) {
  return (
    <div style={{ background: MB.surface.raised, border: `1px solid ${MB.line.hair}`, borderRadius: 14, padding: 18, boxShadow: MB.shadow.card }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 14 }}>
        <h3 style={{ fontFamily: MB.font, fontSize: 15, fontWeight: 700, color: MB.ink.primary, margin: 0, letterSpacing: -0.1 }}>{title}</h3>
        {action && <span style={{ fontFamily: MB.font, fontSize: 13, fontWeight: 600, color: MB.brand[600], cursor: 'pointer' }}>{action}</span>}
      </div>
      {children}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Desktop Discover — filter rail (left) + results grid (right).
// ─────────────────────────────────────────────────────────────
function DesktopDiscover({ persona, onOpen }) {
  const [filter, setFilter] = useSD(['Vertretung','Ausbildung']);
  const [region, setRegion] = useSD('Alle');
  const isKPJ = persona.stage === 'KPJ';
  const regions = ['Alle','Wien','NÖ','OÖ','Stmk','Sbg','Tirol','Ktn','Bgl','Vbg'];
  const fachOptions = Object.keys(MB.specialty).filter(k => k !== 'default').slice(0, 8);

  const all = [...SAMPLE.vertretungen, ...SAMPLE.ausbildungen]
    .filter(l => filter.includes(l.type))
    .sort((a,b) => (a.urgent ? -1 : 1));

  const toggle = (v) => setFilter(f => f.includes(v) ? f.filter(x => x !== v) : [...f, v]);

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '280px minmax(0, 1fr)', height: '100%', minHeight: 0 }}>
      {/* Filter rail */}
      <aside style={{ background: MB.surface.raised, borderRight: `1px solid ${MB.line.hair}`, padding: 20, overflow: 'auto' }}>
        <h3 style={{ fontFamily: MB.font, fontSize: 14, fontWeight: 700, color: MB.ink.primary, margin: '0 0 12px', letterSpacing: 0.4, textTransform: 'uppercase' }}>Angebotstyp</h3>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          <span onClick={() => toggle('Vertretung')} style={{ cursor: 'pointer' }}>
            <Chip tone="vertretung" strong={filter.includes('Vertretung')} size="lg" leading={<Icon name="stethoscope" size={14} />}>Vertretung</Chip>
          </span>
          <span onClick={() => toggle('Ausbildung')} style={{ cursor: 'pointer' }}>
            <Chip tone="ausbildung" strong={filter.includes('Ausbildung')} size="lg" leading={<Icon name="graduation" size={14} />}>Ausbildungsstelle</Chip>
          </span>
        </div>

        <h3 style={{ fontFamily: MB.font, fontSize: 12, fontWeight: 700, color: MB.ink.tertiary, margin: '20px 0 8px', letterSpacing: 0.4, textTransform: 'uppercase' }}>Bundesland</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {regions.map(r => (
            <span key={r} onClick={() => setRegion(r)} style={{ cursor: 'pointer' }}>
              <Chip tone={r === region ? 'brand' : 'neutral'} strong={r === region} size="sm">{r}</Chip>
            </span>
          ))}
        </div>

        <h3 style={{ fontFamily: MB.font, fontSize: 12, fontWeight: 700, color: MB.ink.tertiary, margin: '20px 0 8px', letterSpacing: 0.4, textTransform: 'uppercase' }}>Fach</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {fachOptions.map(s => <Chip key={s} tone="neutral" size="sm">{s}</Chip>)}
        </div>

        <h3 style={{ fontFamily: MB.font, fontSize: 12, fontWeight: 700, color: MB.ink.tertiary, margin: '20px 0 8px', letterSpacing: 0.4, textTransform: 'uppercase' }}>Zeitraum</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {['Aug 2026','Sep 2026','Q4 2026','2027'].map(z => <Chip key={z} tone="neutral" size="sm">{z}</Chip>)}
        </div>

        <div style={{ marginTop: 24 }}>
          <Button kind="primary" full size="md">Suche speichern</Button>
        </div>
      </aside>

      {/* Results */}
      <div style={{ padding: '20px 24px 32px', overflow: 'auto', minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 16 }}>
          <div style={{ fontFamily: MB.font, fontSize: 14, color: MB.ink.secondary }}>
            <strong style={{ color: MB.ink.primary, fontWeight: 700, fontSize: 16, fontVariantNumeric: 'tabular-nums' }}>{all.length}</strong> Ergebnisse
            {region !== 'Alle' && <> · {region}</>}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontFamily: MB.font, fontSize: 13, color: MB.ink.secondary }}>
            <Icon name="sort" size={14} color={MB.ink.tertiary} />
            <span>Sortieren: Dringend zuerst</span>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 14 }}>
          {all.map(l => {
            const ineligible = isKPJ && l.type === 'Vertretung';
            return (
              <div key={l.id} onClick={() => !ineligible && onOpen && onOpen(l.id)} style={{ cursor: ineligible ? 'default' : 'pointer' }}>
                <ListingCard listing={l} density="expanded"
                  greyed={ineligible}
                  greyReason={ineligible ? `Für Assistenzärzte und Niedergelassene — Ihr Status: ${MB.career[persona.stage]?.short || persona.stage}` : undefined} />
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Desktop Chats — combined thread list + active chat.
// ─────────────────────────────────────────────────────────────
function DesktopChats({ onOpenCall }) {
  const threads = SAMPLE.threads || [];
  const [active, setActive] = useSD(threads[0]);
  const allListings = [...SAMPLE.vertretungen, ...SAMPLE.ausbildungen];
  const listingForActive = active && (allListings.find(x => x.title.startsWith(active.listing.title.split(' · ')[0])) || allListings[0]);
  const c = active && active.type === 'Vertretung' ? MB.vertretung : MB.ausbildung;

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '320px minmax(0,1fr)', height: '100%', minHeight: 0 }}>
      {/* Thread list */}
      <aside style={{ background: MB.surface.raised, borderRight: `1px solid ${MB.line.hair}`, overflow: 'auto', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '16px 18px 12px', borderBottom: `1px solid ${MB.line.hair}` }}>
          <div style={{ fontFamily: MB.font, fontSize: 18, fontWeight: 700, color: MB.ink.primary, letterSpacing: -0.2 }}>Nachrichten</div>
          <div style={{ marginTop: 8 }}>
            <Input leading={<Icon name="search" size={16} />} placeholder="Konversation suchen …" />
          </div>
        </div>
        <div style={{ flex: 1, overflow: 'auto' }}>
          {threads.map(t => {
            const isA = active && active.id === t.id;
            const tc = t.type === 'Vertretung' ? MB.vertretung : MB.ausbildung;
            return (
              <div key={t.id} onClick={() => setActive(t)} style={{
                cursor: 'pointer', display: 'flex', gap: 12, padding: '14px 18px',
                borderBottom: `1px solid ${MB.line.hair}`,
                background: isA ? tc[50] : (t.unread > 0 ? tc[50] : 'transparent'),
                borderLeft: isA ? `3px solid ${tc[600]}` : '3px solid transparent',
              }}>
                <Avatar name={t.partner.name} size={40} verified={t.partner.verified} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'baseline' }}>
                    <span style={{ fontFamily: MB.font, fontSize: 14, fontWeight: t.unread > 0 ? 700 : 600, color: MB.ink.primary, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.partner.name}</span>
                    <span style={{ fontFamily: MB.font, fontSize: 11, color: t.unread > 0 ? tc[700] : MB.ink.tertiary, fontWeight: t.unread > 0 ? 700 : 500, flex: 'none' }}>{t.time}</span>
                  </div>
                  <div style={{ marginTop: 2, fontFamily: MB.font, fontSize: 11, color: tc[700], fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.listing.title}</div>
                  <div style={{ marginTop: 3, display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span style={{ fontFamily: MB.font, fontSize: 12, color: t.unread > 0 ? MB.ink.primary : MB.ink.secondary, fontWeight: t.unread > 0 ? 600 : 400, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: 1, minWidth: 0 }}>{t.last}</span>
                    {t.unread > 0 && (
                      <span style={{ minWidth: 18, height: 18, borderRadius: 999, padding: '0 5px', background: tc[600], color: '#fff', fontFamily: MB.font, fontSize: 10, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>{t.unread}</span>
                    )}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </aside>

      {/* Active conversation */}
      <div style={{ display: 'flex', flexDirection: 'column', minHeight: 0, background: MB.surface.canvas }}>
        {/* Conversation header */}
        {active && (
          <div style={{ padding: '14px 24px', borderBottom: `1px solid ${MB.line.hair}`, background: MB.surface.raised, display: 'flex', alignItems: 'center', gap: 14 }}>
            <Avatar name={active.partner.name} size={40} verified={active.partner.verified} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: MB.font, fontSize: 15, fontWeight: 700, color: MB.ink.primary }}>{active.partner.name}</div>
              <div style={{ fontFamily: MB.font, fontSize: 12, color: c[700], fontWeight: 600 }}>{active.listing.title}</div>
            </div>
            <Button kind="soft" size="sm" tone={c} leading={<Icon name="phone" size={14} />}
              onClick={() => onOpenCall && onOpenCall({ name: active.partner.name, stage: active.partner.stage }, listingForActive)}>Anrufen</Button>
            <Button kind="secondary" size="sm">Inserat öffnen</Button>
          </div>
        )}

        {/* Messages — reuse the mobile body inline */}
        <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: 24 }}>
          <DesktopChatBody listing={listingForActive} partner={active && active.partner} />
        </div>
      </div>
    </div>
  );
}

// Minimal chat body — bubbles + a structured offer card mid-thread + composer.
function DesktopChatBody({ listing, partner }) {
  if (!listing) return null;
  const tone = listing.type === 'Vertretung' ? MB.vertretung : MB.ausbildung;
  const Bubble = ({ from, children }) => (
    <div style={{ display: 'flex', justifyContent: from === 'me' ? 'flex-end' : 'flex-start', marginBottom: 10 }}>
      <div style={{
        maxWidth: 540, padding: '10px 14px', borderRadius: 16,
        background: from === 'me' ? MB.brand[600] : MB.surface.raised,
        color: from === 'me' ? '#fff' : MB.ink.primary,
        border: from === 'me' ? 'none' : `1px solid ${MB.line.hair}`,
        fontFamily: MB.font, fontSize: 14, lineHeight: 1.5,
        boxShadow: from === 'me' ? 'none' : MB.shadow.card,
      }}>{children}</div>
    </div>
  );
  return (
    <div style={{ maxWidth: 880, margin: '0 auto' }}>
      <Bubble from="them">Guten Tag {partner && partner.name.split(' ').pop()},{'\n'}danke für Ihre Bewerbung — passt 9 Uhr Start?</Bubble>
      <Bubble from="me">Sehr gerne, 9 Uhr passt. Habe noch eine Frage zur Patientensoftware.</Bubble>

      {/* Structured offer card */}
      <div style={{
        margin: '18px auto', maxWidth: 560,
        background: MB.surface.raised, border: `1px solid ${tone[100]}`,
        borderLeft: `4px solid ${tone[600]}`, borderRadius: 12, padding: 16,
        boxShadow: MB.shadow.card,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
          <TypePill type={listing.type} size="sm" />
          <Chip tone="success" size="sm">Angebot v2</Chip>
        </div>
        <div style={{ fontFamily: MB.font, fontSize: 16, fontWeight: 700, color: MB.ink.primary, marginBottom: 8, letterSpacing: -0.1 }}>{listing.title}</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 14, fontFamily: MB.font, fontSize: 13, color: MB.ink.secondary, fontVariantNumeric: 'tabular-nums' }}>
          <div><Icon name="calendar" size={13} color={MB.ink.tertiary} /> {listing.dateRange || `${listing.rotation} · ${listing.start}`}</div>
          <div><Icon name="pin" size={13} color={MB.ink.tertiary} /> {listing.location}</div>
          <div><Icon name="euro" size={13} color={MB.ink.tertiary} /> {listing.rate || listing.stipendium}</div>
          <div><Icon name="clock" size={13} color={MB.ink.tertiary} /> 9:00 – 18:00</div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <Button kind="primary" tone={tone} size="md">Annehmen</Button>
          <Button kind="secondary" size="md">Gegenvorschlag</Button>
          <Button kind="ghost" size="md">Ablehnen</Button>
        </div>
      </div>

      <Bubble from="me">Angebot v2 angepasst — 9 Uhr Start passt.</Bubble>

      {/* Composer */}
      <div style={{ marginTop: 24, display: 'flex', gap: 10, alignItems: 'center', padding: 12, background: MB.surface.raised, border: `1px solid ${MB.line.hair}`, borderRadius: 12 }}>
        <Input placeholder="Nachricht schreiben …" />
        <Button kind="primary" size="md" leading={<Icon name="send" size={14} color="#fff" />}>Senden</Button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Desktop Host listings — table-style row list.
// ─────────────────────────────────────────────────────────────
function DesktopHostListings({ persona, onOpenApplicants, onNewListing }) {
  const own = persona.hasBefugnis
    ? [SAMPLE.ausbildungen[0], SAMPLE.vertretungen[0]]
    : [SAMPLE.vertretungen[0]];
  return (
    <div style={{ padding: '24px 28px', overflow: 'auto' }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 16 }}>
        <div>
          <div style={{ fontFamily: MB.font, fontSize: 22, fontWeight: 700, color: MB.ink.primary, letterSpacing: -0.3 }}>Meine Inserate</div>
          <div style={{ fontFamily: MB.font, fontSize: 14, color: MB.ink.tertiary, marginTop: 4 }}>{own.length} aktiv · 6 Bewerbungen offen</div>
        </div>
        <Button kind="primary" size="md" leading={<Icon name="plus" size={14} color="#fff" />} onClick={onNewListing}>Neues Inserat</Button>
      </div>

      <div style={{ background: MB.surface.raised, border: `1px solid ${MB.line.hair}`, borderRadius: 14, overflow: 'hidden', boxShadow: MB.shadow.card }}>
        {/* table head */}
        <div style={{
          display: 'grid', gridTemplateColumns: '120px minmax(0,2fr) 180px 140px 120px 100px',
          gap: 16, padding: '12px 20px', background: MB.surface.canvas2,
          fontFamily: MB.font, fontSize: 11, fontWeight: 700, letterSpacing: 0.4,
          textTransform: 'uppercase', color: MB.ink.tertiary,
          borderBottom: `1px solid ${MB.line.hair}`,
        }}>
          <span>Typ</span><span>Titel</span><span>Zeitraum</span><span>Region</span><span>Bewerbungen</span><span>Status</span>
        </div>
        {own.map((l, i) => {
          const isV = l.type === 'Vertretung';
          const tone = isV ? MB.vertretung : MB.ausbildung;
          return (
            <div key={l.id} onClick={() => onOpenApplicants && onOpenApplicants(l.id)} style={{
              display: 'grid', gridTemplateColumns: '120px minmax(0,2fr) 180px 140px 120px 100px',
              gap: 16, padding: '16px 20px', cursor: 'pointer',
              alignItems: 'center',
              borderBottom: i === own.length - 1 ? 'none' : `1px solid ${MB.line.hair}`,
            }}>
              <TypePill type={l.type} subtype={l.subtype} size="sm" />
              <div style={{ minWidth: 0 }}>
                <div style={{ fontFamily: MB.font, fontSize: 14, fontWeight: 700, color: MB.ink.primary, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{l.title}</div>
                <div style={{ fontFamily: MB.font, fontSize: 12, color: MB.ink.tertiary }}>{l.specialty || l.sonderfach || ''}</div>
              </div>
              <div style={{ fontFamily: MB.font, fontSize: 13, color: MB.ink.secondary, fontVariantNumeric: 'tabular-nums' }}>{l.dateRange || `${l.rotation} · ${l.start}`}</div>
              <div style={{ fontFamily: MB.font, fontSize: 13, color: MB.ink.secondary }}>{l.location}</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ width: 28, height: 28, borderRadius: 999, background: tone[100], color: tone[700], display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontFamily: MB.font, fontSize: 12, fontWeight: 700 }}>{i === 0 ? 4 : 2}</span>
                <span style={{ fontFamily: MB.font, fontSize: 12, color: tone[700], fontWeight: 600 }}>{i === 0 ? '2 neu' : '0 neu'}</span>
              </div>
              <Chip tone="success" size="sm">Aktiv</Chip>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Centered wrapper for single-column screens (Profile, News,
// ListingDetail, NewListing wizard, ApplySuccess, Onboarding).
// ─────────────────────────────────────────────────────────────
function DesktopCenteredFrame({ maxWidth = 780, children, background }) {
  return (
    <div style={{ background: background || MB.surface.canvas, height: '100%', overflow: 'auto' }}>
      <div style={{ maxWidth, margin: '0 auto', padding: '24px 24px 48px' }}>{children}</div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// DesktopApp — the routing layer. Mirrors Prototype in app.jsx
// but renders with the sidebar shell.
// ─────────────────────────────────────────────────────────────
function DesktopApp({ persona, showOnboarding, onFinishOnboarding, initialTab = 'home' }) {
  const isHost = !!persona.canHost;
  const [tab, setTab] = useSD(initialTab);
  const [route, setRoute] = useSD({ name: 'tab' });
  // Publish current inner screen for CommentLayer.
  useED(() => {
    const inner = showOnboarding ? 'onboarding'
      : route.name !== 'tab'
        ? `${route.name}${route.listing ? '-' + route.listing.id : ''}${route.booking ? '-' + route.booking.id : ''}`
        : `tab-${tab}`;
    const screen = `desktop/${persona.key}/${inner}`;
    window.__mb_active_screen = screen;
    window.dispatchEvent(new CustomEvent('mb-active-screen', { detail: screen }));
  }, [persona.key, tab, route, showOnboarding]);

  if (showOnboarding) {
    return (
      <div style={{ position: 'absolute', inset: 0, background: MB.surface.canvas, overflow: 'auto' }}>
        <DesktopCenteredFrame maxWidth={560}>
          <Onboarding initialStage={persona.stage} onFinish={onFinishOnboarding} />
        </DesktopCenteredFrame>
      </div>
    );
  }

  const allListings = [...SAMPLE.vertretungen, ...SAMPLE.ausbildungen];
  const unread = (SAMPLE.threads || []).reduce((s, t) => s + (t.unread || 0), 0);
  const isKPJ = persona.stage === 'KPJ';
  const eligibleFor = (l) => !(isKPJ && l.type === 'Vertretung');

  const openListing = (id, filterType) => {
    if (!id) { setRoute({ name: 'tab' }); setTab('discover'); return; }
    const l = allListings.find(x => x.id === id);
    setRoute({ name: 'detail', listing: l });
  };
  const openApplicants = (id) => {
    const l = allListings.find(x => x.id === id);
    setRoute({ name: 'applicants', listing: l });
  };

  // Determine current screen's title/subtitle for the topbar.
  let title = 'Start';
  let subtitle = null;
  if (route.name === 'detail')       { title = route.listing.title;  subtitle = route.listing.location; }
  else if (route.name === 'applied') { title = 'Bewerbung gesendet'; }
  else if (route.name === 'new')     { title = 'Neues Inserat erstellen'; }
  else if (route.name === 'applicants') { title = 'Bewerbungen'; subtitle = route.listing.title; }
  else if (route.name === 'call')    { title = 'Anruf'; }
  else if (route.name === 'practice'){ title = 'Praxisprofil'; subtitle = route.practice && route.practice.address; }
  else if (route.name === 'booking') { title = 'Buchung'; subtitle = route.booking && route.booking.dateRange; }
  else if (route.name === 'honorar') { title = 'Honorarnote erstellen'; }
  else if (route.name === 'honorarList') { title = 'Honorarnoten'; }
  else if (route.name === 'paywall') { title = 'MedBridge Pro'; }
  else if (route.name === 'savedSearches') { title = 'Gespeicherte Suchen'; }
  else if (route.name === 'settings') { title = 'Einstellungen'; }
  else if (route.name === 'verification') { title = 'Verifizierung'; }
  else if (tab === 'home')           { title = 'Start'; subtitle = MB.career[persona.stage]?.label || ''; }
  else if (tab === 'discover')       { title = 'Suchen'; subtitle = 'Vertretungen & Ausbildungsstellen'; }
  else if (tab === 'listings')       { title = 'Meine Inserate'; }
  else if (tab === 'news')           { title = 'News & Fortbildung'; subtitle = 'Ärztekammer · MedUni · DFP'; }
  else if (tab === 'chats')          { title = 'Nachrichten'; subtitle = `${unread} ungelesen`; }
  else if (tab === 'calendar')       { title = 'Kalender'; }
  else if (tab === 'profile')        { title = 'Profil'; }

  // Body
  let body = null;
  if (route.name === 'detail') {
    body = (
      <DesktopCenteredFrame maxWidth={920}>
        <ListingDetail
          listing={route.listing}
          eligible={eligibleFor(route.listing)}
          onBack={() => setRoute({ name: 'tab' })}
          onApply={() => setRoute({ name: 'applied', listing: route.listing })}
          onOpenPractice={() => setRoute({ name: 'practice', practice: { ...DEMO_PRACTICE, name: route.listing.hostPractice, host: route.listing.host, address: route.listing.location, specialty: route.listing.specialty || route.listing.sonderfach || 'Allgemeinmedizin', hasBefugnis: route.listing.type === 'Ausbildung' } })} />
      </DesktopCenteredFrame>
    );
  } else if (route.name === 'applied') {
    body = (
      <DesktopCenteredFrame maxWidth={560}>
        <ApplySuccess listing={route.listing}
          onChat={() => { setRoute({ name: 'tab' }); setTab('chats'); }}
          onDone={() => { setRoute({ name: 'tab' }); setTab('discover'); }} />
      </DesktopCenteredFrame>
    );
  } else if (route.name === 'new') {
    body = (
      <DesktopCenteredFrame maxWidth={680}>
        <NewListingFlow persona={persona}
          onClose={() => setRoute({ name: 'tab' })}
          onPublished={() => { setRoute({ name: 'tab' }); setTab(isHost ? 'listings' : 'home'); }} />
      </DesktopCenteredFrame>
    );
  } else if (route.name === 'applicants') {
    body = (
      <DesktopCenteredFrame maxWidth={1080}>
        <ApplicantsBoard listing={route.listing}
          onBack={() => setRoute({ name: 'tab' })}
          onChat={() => { setRoute({ name: 'tab' }); setTab('chats'); }}
          onCall={(a) => setRoute({ name: 'call', listing: route.listing, partner: a })} />
      </DesktopCenteredFrame>
    );
  } else if (route.name === 'call') {
    body = (
      <DesktopCenteredFrame maxWidth={480} background="#0F1B2D">
        <CallScreen doctor={route.partner}
          onHangup={() => { setRoute({ name: 'tab' }); setTab('chats'); }} />
      </DesktopCenteredFrame>
    );
  } else if (route.name === 'practice') {
    body = <DesktopCenteredFrame maxWidth={920}>
      <PracticeProfile practice={route.practice} onBack={() => setRoute({ name: 'tab' })} /></DesktopCenteredFrame>;
  } else if (route.name === 'booking') {
    body = <DesktopCenteredFrame maxWidth={760}>
      <BookingDetail booking={route.booking}
        onBack={() => setRoute({ name: 'tab' })}
        onChat={() => { setRoute({ name: 'tab' }); setTab('chats'); }}
        onCall={() => setRoute({ name: 'call', listing: route.booking, partner: { name: route.booking.partner } })}
        onCreateInvoice={() => setRoute({ name: 'honorar', booking: route.booking })}
        onCancel={() => setRoute({ name: 'tab' })} /></DesktopCenteredFrame>;
  } else if (route.name === 'honorar') {
    body = <DesktopCenteredFrame maxWidth={760}>
      <HonorarNoteBuilder booking={route.booking}
        onBack={() => setRoute({ name: 'tab' })}
        onSaveDraft={() => setRoute({ name: 'honorarList' })}
        onCreatePdf={() => setRoute({ name: 'honorarList' })} /></DesktopCenteredFrame>;
  } else if (route.name === 'honorarList') {
    body = <DesktopCenteredFrame maxWidth={760}>
      <HonorarNoteArchive
        onBack={() => setRoute({ name: 'tab' })}
        onOpen={() => setRoute({ name: 'honorar', booking: DEMO_BOOKING_FOR_INVOICE })}
        onNew={() => setRoute({ name: 'honorar', booking: DEMO_BOOKING_FOR_INVOICE })} /></DesktopCenteredFrame>;
  } else if (route.name === 'paywall') {
    body = <DesktopCenteredFrame maxWidth={680}>
      <SubscriptionPaywall persona={persona}
        onBack={() => setRoute({ name: 'tab' })}
        onSubscribe={() => setRoute({ name: 'tab' })} /></DesktopCenteredFrame>;
  } else if (route.name === 'savedSearches') {
    body = <DesktopCenteredFrame maxWidth={720}>
      <SavedSearches persona={persona}
        onBack={() => setRoute({ name: 'tab' })}
        onOpen={() => { setRoute({ name: 'tab' }); setTab('discover'); }}
        onNew={() => { setRoute({ name: 'tab' }); setTab('discover'); }} /></DesktopCenteredFrame>;
  } else if (route.name === 'settings') {
    body = <DesktopCenteredFrame maxWidth={720}>
      <SettingsScreen persona={persona}
        onBack={() => setRoute({ name: 'tab' })}
        onVerification={() => setRoute({ name: 'verification' })}
        onSubscription={() => setRoute({ name: 'paywall' })} /></DesktopCenteredFrame>;
  } else if (route.name === 'verification') {
    body = <DesktopCenteredFrame maxWidth={720}>
      <VerificationStatus persona={persona} onBack={() => setRoute({ name: 'tab' })} /></DesktopCenteredFrame>;
  } else if (tab === 'home') {
    body = <div style={{ height: '100%', overflow: 'auto' }}>
      <DesktopHome persona={persona}
        onOpenListing={openListing}
        onOpenApplicants={openApplicants}
        onOpenCalendar={() => { setRoute({ name: 'tab' }); setTab('calendar'); }}
        onNewListing={() => setRoute({ name: 'new' })} />
    </div>;
  } else if (tab === 'discover') {
    body = <DesktopDiscover persona={persona} onOpen={openListing} />;
  } else if (tab === 'listings') {
    body = <DesktopHostListings persona={persona}
      onOpenApplicants={openApplicants}
      onNewListing={() => setRoute({ name: 'new' })} />;
  } else if (tab === 'news') {
    body = <DesktopCenteredFrame maxWidth={1080}><NewsFeed /></DesktopCenteredFrame>;
  } else if (tab === 'chats') {
    body = <DesktopChats onOpenCall={(p, l) => setRoute({ name: 'call', listing: l, partner: p })} />;
  } else if (tab === 'calendar') {
    body = <DesktopCenteredFrame maxWidth={1100}>
      <MyCalendar persona={persona} wide
        onOpenBooking={(b) => setRoute({ name: 'booking', booking: b })} /></DesktopCenteredFrame>;
  } else if (tab === 'profile') {
    body = <DesktopCenteredFrame maxWidth={720}><ProfileScreen persona={persona} onOpen={(k) => {
      if (k === 'savedSearches') setRoute({ name: 'savedSearches' });
      else if (k === 'honorarList') setRoute({ name: 'honorarList' });
      else if (k === 'paywall') setRoute({ name: 'paywall' });
      else if (k === 'settings') setRoute({ name: 'settings' });
      else if (k === 'verification') setRoute({ name: 'verification' });
      else if (k === 'doctorProfile') setRoute({ name: 'practice', practice: { ...DEMO_PRACTICE, name: persona.name, host: persona.name, hostStage: MB.career[persona.stage]?.label || persona.stage, hasBefugnis: persona.hasBefugnis } });
    }} /></DesktopCenteredFrame>;
  }

  return (
    <div style={{ position: 'absolute', inset: 0, display: 'flex', background: MB.surface.canvas, overflow: 'hidden', fontFamily: MB.font }}>
      <DesktopSidebar persona={persona} active={tab} unread={unread}
        onChange={(t) => { setRoute({ name: 'tab' }); setTab(t); }}
        onNewListing={() => setRoute({ name: 'new' })} />
      <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
        <DesktopTopbar title={title} subtitle={subtitle} />
        <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>{body}</div>
      </div>
    </div>
  );
}

Object.assign(window, { BrowserFrame, DesktopApp, DesktopSidebar, DesktopTopbar });
