import { h, Fragment } from "../jsx";
import { FIRM } from "../branding";

const ICON_HOME = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>';
const ICON_CALC = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="6" x2="16" y2="6"/><line x1="8" y1="14" x2="8" y2="14.01"/><line x1="12" y1="14" x2="12" y2="14.01"/><line x1="16" y1="14" x2="16" y2="14.01"/><line x1="8" y1="18" x2="16" y2="18"/></svg>';
const ICON_CLOCK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>';
const ICON_DOWNLOAD = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>';
const ICON_LINK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>';
const ICON_BOOK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>';
// Open-book icon for the /tools/verfahrensablauf "Verfahrensablauf"
// nav entry (t-paliad-168 → t-paliad-179 Slice 1 split). Distinct from
// ICON_BOOK (Glossar, closed) so the two affordances read as different
// at a glance.
const ICON_BOOK_OPEN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h7a3 3 0 0 1 3 3v13a2 2 0 0 0-2-2H2z"/><path d="M22 4h-7a3 3 0 0 0-3 3v13a2 2 0 0 1 2-2h8z"/></svg>';
const ICON_TABLE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/></svg>';
// Document-with-lines icon for /submissions (t-paliad-240) — distinct
// from ICON_BOOK / ICON_BOOK_OPEN / ICON_NEWSPAPER so the Schriftsätze
// affordance reads as "a draft document" at a glance.
const ICON_FILE_TEXT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="8" y1="9" x2="10" y2="9"/></svg>';
const ICON_CHECK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>';
const ICON_GLOBE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10A15.3 15.3 0 0 1 12 2z"/></svg>';
const ICON_BUILDING = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v16"/><path d="M16 9h3a2 2 0 0 1 2 2v10"/><path d="M9 7h2"/><path d="M9 11h2"/><path d="M9 15h2"/></svg>';
const ICON_LOGOUT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>';
const ICON_PIN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 4v6l-2 4h10l-2-4V4"/><line x1="12" y1="16" x2="12" y2="21"/><line x1="8" y1="4" x2="16" y2="4"/></svg>';
const ICON_MENU = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></svg>';
const ICON_FOLDER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>';
const ICON_CALENDAR = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>';
const ICON_GAUGE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 14l3.5-3.5"/><path d="M3 12a9 9 0 0 1 18 0"/><path d="M12 3v2"/><path d="M3 12H5"/><path d="M19 12h2"/><path d="M5.6 5.6l1.4 1.4"/><path d="M17 7l1.4-1.4"/></svg>';
const ICON_GEAR = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>';
const ICON_MAIL = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><polyline points="3 7 12 13 21 7"/></svg>';
const ICON_SEARCH = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>';
const ICON_SPARKLE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v4"/><path d="M12 17v4"/><path d="M3 12h4"/><path d="M17 12h4"/><path d="M5.6 5.6l2.8 2.8"/><path d="M15.6 15.6l2.8 2.8"/><path d="M5.6 18.4l2.8-2.8"/><path d="M15.6 8.4l2.8-2.8"/></svg>';
const ICON_USERS = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>';
const ICON_SHIELD = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>';
const ICON_AUDIT_LOG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="9" y1="17" x2="15" y2="17"/></svg>';
// Newspaper icon for the /changelog "Neuigkeiten" entry. Sparkle is now
// reserved for the Paliadin AI surface so the two affordances don't
// share a glyph (m's 2026-05-08 21:11 dogfood).
const ICON_NEWSPAPER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/><path d="M18 14h-8"/><path d="M15 18h-5"/><path d="M10 6h8v4h-8z"/></svg>';
// Bell icon for the /inbox entry (t-paliad-138 4-eye approval inbox).
const ICON_BELL = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>';
// Theme-toggle icons. The button cycles auto → light → dark → auto, and
// the icon swaps to reflect the *current* preference (auto/light/dark)
// — not the eventual click target. SSR renders the auto variant; the
// runtime client (sidebar.ts) re-renders the matching icon on hydration
// after reading localStorage.
const ICON_THEME_AUTO = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor"/></svg>';
const ICON_THEME_LIGHT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="M4.93 4.93l1.41 1.41"/><path d="M17.66 17.66l1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="M4.93 19.07l1.41-1.41"/><path d="M17.66 6.34l1.41-1.41"/></svg>';
const ICON_THEME_DARK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';

interface SidebarProps {
  currentPath: string;
  // authenticated defaults to true; pass false on anon-facing pages (the
  // marketing landing) so we don't render auth-only affordances that would
  // fire 401s. Currently gates only the changelog badge link — the badge
  // client (sidebar.ts initChangelogBadge) early-returns when the link is
  // absent, so there is no client change needed.
  authenticated?: boolean;
}

function navItem(href: string, icon: string, i18nKey: string, label: string, currentPath: string, badgeID?: string): string {
  // "Active" is true for the item whose href is a prefix of currentPath.
  // That way sub-routes like /projekte/{id}/events keep the /projekte entry lit.
  // /akten and /akten/* are kept as legacy aliases and also highlight /projekte
  const active =
    href === currentPath ||
    (href !== "/" && currentPath.startsWith(href + "/"));
  return (
    <a href={href} className={`sidebar-item${active ? " active" : ""}`}>
      <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: icon }} />
      <span className="sidebar-label" data-i18n={i18nKey}>{label}</span>
      {badgeID ? <span className="sidebar-badge" id={badgeID} style="display:none" aria-hidden="true" /> : ""}
    </a>
  );
}

function navItemDisabled(icon: string, i18nKey: string, label: string, tooltipI18n: string, tooltipText: string): string {
  return (
    <span className="sidebar-item sidebar-item-disabled" title={tooltipText} data-i18n-title={tooltipI18n}>
      <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: icon }} />
      <span className="sidebar-label" data-i18n={i18nKey}>{label}</span>
    </span>
  );
}

function group(i18nKey: string, label: string, children: string): string {
  return (
    <div className="sidebar-group">
      <div className="sidebar-group-label" data-i18n={i18nKey}>{label}</div>
      {children}
    </div>
  );
}

export function Sidebar({ currentPath, authenticated = true }: SidebarProps): string {
  return (
    <Fragment>
      <aside className="sidebar">
        <div className="sidebar-header">
          <a href="/" className="sidebar-logo">
            <span className="sidebar-icon"><span className="logo-mark">p</span></span>
            <span className="sidebar-label logo-text">Paliad</span>
          </a>
          <button className="sidebar-pin" type="button" aria-label="Pin sidebar">
            <span dangerouslySetInnerHTML={{ __html: ICON_PIN }} />
          </button>
        </div>

        <nav className="sidebar-nav">
          <div className="sidebar-search" id="sidebar-search">
            <span className="sidebar-icon sidebar-search-icon"
                  dangerouslySetInnerHTML={{ __html: ICON_SEARCH }} />
            <input type="search" id="global-search-input"
                   className="sidebar-search-input"
                   autocomplete="off" spellcheck={false}
                   placeholder="Suchen..."
                   data-i18n-placeholder="search.placeholder"
                   aria-label="Suche" />
            <kbd className="sidebar-search-kbd" aria-hidden="true" title="/  oder  Ctrl/Cmd+K">/</kbd>
          </div>
          <div className="search-overlay" id="global-search-overlay"
               role="listbox" aria-label="Suchergebnisse"
               style="display:none" />

          {navItem("/", ICON_HOME, "nav.home", "Home", currentPath)}

          {/* Paliadin top-level entry (t-paliad-162) \u2014 owner-only, hidden
              by default. sidebar.ts reveals it after /api/me confirms the
              caller is the Paliadin owner (t-paliad-146 PoC scope). Same
              fail-closed pattern as the admin group below. Sits directly
              under Home per m's design call so owners hit their assistant
              with one click from anywhere. */}
          <a href="/paliadin"
             className={`sidebar-item sidebar-paliadin${currentPath === "/paliadin" ? " active" : ""}`}
             id="sidebar-paliadin-link" style="display:none">
            <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_SPARKLE }} />
            <span className="sidebar-label" data-i18n="nav.paliadin">Paliadin</span>
          </a>

          {group("nav.group.uebersicht", "\u00DCbersicht",
            navItem("/dashboard", ICON_GAUGE, "nav.dashboard", "Dashboard", currentPath) +
            navItem("/projects", ICON_FOLDER, "nav.projekte", "Projekte", currentPath) +
            navItem("/inbox", ICON_BELL, "nav.inbox", "Inbox", currentPath, "sidebar-inbox-badge") +
            navItem("/team", ICON_USERS, "nav.team", "Team", currentPath),
          )}

          {/* t-paliad-177 \u2014 contextual chart link, revealed by sidebar.ts
              when the user is on a /projects/{id}/* page (but NOT on the
              chart itself). The href is filled in client-side from the
              URL path so the same Sidebar TSX serves every page. */}
          <a href="#"
             className="sidebar-item sidebar-context-chart"
             id="sidebar-project-chart-link"
             style="display:none">
            <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_GAUGE }} />
            <span className="sidebar-label" data-i18n="nav.context.project_chart">Als Chart anzeigen</span>
          </a>

          {/* Ansichten \u2014 single consolidated group (m's 2026-05-08 20:32
              dogfood: "all views under one — not Ansichten and meine Ansichten").
              Holds the built-in Fristen + Termine, the user-defined views
              hydrated by client/sidebar.ts from /api/user-views, and the
              "+ Neue Sicht" entry. The previous "Meine Sichten" split is gone. */}
          <div className="sidebar-group sidebar-views-group" id="sidebar-views-group">
            <div className="sidebar-group-label" data-i18n="nav.group.ansichten">Ansichten</div>
            {navItem("/events?type=deadline", ICON_CLOCK, "nav.fristen", "Fristen", currentPath)}
            {navItem("/events?type=appointment", ICON_CALENDAR, "nav.termine", "Termine", currentPath)}
            <div className="sidebar-views-items" id="sidebar-views-items" />
            <a href="/views/new" className="sidebar-item sidebar-views-new">
              <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_FOLDER }} />
              <span className="sidebar-label" data-i18n="nav.user_views.new">Neue Sicht</span>
            </a>
          </div>

          {/* t-paliad-162 — single Werkzeuge group consolidating the prior
              Werkzeuge / Wissen / Ressourcen splits. Order follows m's
              brief: calculators first, then reference (Checklisten /
              Gerichte / Glossar), then content (Links / Downloads). */}
          {group("nav.group.werkzeuge", "Werkzeuge",
            navItem("/tools/fristenrechner", ICON_CLOCK, "nav.fristenrechner", "Fristenrechner", currentPath) +
            navItem("/tools/verfahrensablauf", ICON_BOOK_OPEN, "nav.verfahrensablauf", "Verfahrensablauf", currentPath) +
            navItem("/submissions", ICON_FILE_TEXT, "nav.submissions", "Schriftsätze", currentPath) +
            navItem("/tools/kostenrechner", ICON_CALC, "nav.kostenrechner", "Kostenrechner", currentPath) +
            navItem("/tools/gebuehrentabellen", ICON_TABLE, "nav.gebuehrentabellen", "Gebührentabellen", currentPath) +
            navItem("/checklists", ICON_CHECK, "nav.checklisten", "Checklisten", currentPath) +
            navItem("/courts", ICON_BUILDING, "nav.gerichte", "Gerichte", currentPath) +
            navItem("/glossary", ICON_BOOK, "nav.glossar", "Glossar", currentPath) +
            navItem("/links", ICON_LINK, "nav.links", "Links", currentPath) +
            navItem("/downloads", ICON_DOWNLOAD, "nav.downloads", "Downloads", currentPath),
          )}

          {group("nav.group.einstellungen", "Einstellungen",
            navItem("/settings", ICON_GEAR, "nav.einstellungen", "Einstellungen", currentPath),
          )}

          {/* Admin section: hidden by default. sidebar.ts reveals it after a
              successful /api/me lookup confirms role='admin'. Keeping the
              markup in the DOM (vs. fetched HTML) means there's nothing to
              flash in/out for admins on subsequent navigations once the
              role is known — only the first visit waits for /api/me. */}
          <div className="sidebar-group sidebar-admin-group" id="sidebar-admin-group" style="display:none">
            <div className="sidebar-group-label" data-i18n="nav.group.admin">Admin</div>
            {navItem("/admin", ICON_SHIELD, "nav.admin.bereich", "Admin-Bereich", currentPath)}
            {navItem("/admin/team", ICON_USERS, "nav.admin.team", "Team-Verwaltung", currentPath)}
            {navItem("/admin/partner-units", ICON_BUILDING, "nav.admin.partner_units", "Partner Units", currentPath)}
            {navItem("/admin/event-types", ICON_TABLE, "nav.admin.event_types", "Event-Typen", currentPath)}
            {navItem("/admin/rules", ICON_BOOK, "nav.admin.rules", "Regeln verwalten", currentPath)}
            {navItem("/admin/audit-log", ICON_AUDIT_LOG, "nav.admin.audit", "Audit-Log", currentPath)}
            {navItem("/admin/backups", ICON_DOWNLOAD, "nav.admin.backups", "Backups", currentPath)}
            {/* Paliadin Monitor — owner-only sub-entry; revealed by sidebar.ts together with the /paliadin link. */}
            <a href="/admin/paliadin" id="sidebar-admin-paliadin-link"
               className={`sidebar-item${currentPath === "/admin/paliadin" ? " active" : ""}`}
               style="display:none">
              <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_SPARKLE }} />
              <span className="sidebar-label" data-i18n="nav.admin.paliadin">Paliadin Monitor</span>
            </a>
          </div>
        </nav>

        <div className="sidebar-spacer" />

        <div className="sidebar-bottom">
          {authenticated ? (
            <a href="/changelog" className={`sidebar-item sidebar-changelog${currentPath === "/changelog" ? " active" : ""}`} id="sidebar-changelog-link">
              <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_NEWSPAPER }} />
              <span className="sidebar-label" data-i18n="nav.neuigkeiten">Neuigkeiten</span>
              <span className="sidebar-badge" id="sidebar-changelog-badge" style="display:none" aria-hidden="true" />
            </a>
          ) : ""}
          <button type="button" className="sidebar-item sidebar-invite-btn" id="sidebar-invite-btn">
            <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_MAIL }} />
            <span className="sidebar-label" data-i18n="invite.button">Kolleg:in einladen</span>
          </button>
          <div className="sidebar-item sidebar-lang-item">
            <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_GLOBE }} />
            <span className="sidebar-label">
              <span className="sidebar-lang">
                <button className="lang-btn lang-active" data-lang-toggle="de" type="button">DE</button>
                <span className="lang-sep">/</span>
                <button className="lang-btn" data-lang-toggle="en" type="button">EN</button>
              </span>
            </span>
          </div>
          {/* Theme toggle (m/paliad#2). SSR renders the auto/system variant;
              client/sidebar.ts swaps the icon + label to match the persisted
              preference on hydration, and re-renders on every cycle. The
              data-theme-toggle attribute is the click handle so the wiring
              survives any future markup churn. */}
          <button type="button" className="sidebar-item sidebar-theme-toggle"
                  id="sidebar-theme-toggle" data-theme-toggle="cycle"
                  aria-label="Theme">
            <span className="sidebar-icon" id="sidebar-theme-icon"
                  dangerouslySetInnerHTML={{ __html: ICON_THEME_AUTO }} />
            <span className="sidebar-label" id="sidebar-theme-label" data-i18n="theme.toggle.auto">Auto</span>
          </button>
          <a href="/logout" className="sidebar-item sidebar-logout">
            <span className="sidebar-icon" dangerouslySetInnerHTML={{ __html: ICON_LOGOUT }} />
            <span className="sidebar-label" data-i18n="nav.logout">Abmelden</span>
          </a>
        </div>

        {/* Drag-strip on the right edge — sidebar.ts wires mouse/touch
            handlers and persists the chosen width to localStorage.
            CSS hides it when the sidebar is collapsed/icon-rail or on mobile. */}
        <div className="sidebar-resize-handle" role="separator" aria-orientation="vertical"
             aria-label="Resize sidebar"
             title="Breite anpassen" data-i18n-title="sidebar.resize.title" />
      </aside>

      <button className="sidebar-hamburger" type="button" aria-label="Menu">
        <span dangerouslySetInnerHTML={{ __html: ICON_MENU }} />
      </button>
      <div className="sidebar-overlay" />

      {/* Invitation modal — lives alongside the sidebar so every page can
          open it. Hidden by default; sidebar.ts toggles display. */}
      <div className="modal-overlay" id="invite-modal" style="display:none">
        <div className="modal-card">
          <div className="modal-header">
            <h2 data-i18n="invite.modal.title">Kolleg:in zu Paliad einladen</h2>
            <button className="modal-close" id="invite-modal-close" type="button" aria-label="Close">&times;</button>
          </div>
          <p data-i18n="invite.modal.body" className="invite-modal-body">
            {`Senden Sie eine Einladung an eine ${FIRM}-E-Mail-Adresse. Die Empfänger:in erhält einen Registrierungslink.`}
          </p>
          <form id="invite-form" className="entity-form" autocomplete="off">
            <div className="form-field">
              <label htmlFor="invite-email" data-i18n="invite.modal.email">E-Mail-Adresse</label>
              <input type="email" id="invite-email" name="email" required placeholder="kolleg@hlc.com" />
            </div>
            <div className="form-field">
              <label htmlFor="invite-message" data-i18n="invite.modal.message">Pers&ouml;nliche Nachricht (optional)</label>
              <textarea id="invite-message" name="message" rows={4} data-i18n-placeholder="invite.modal.message.placeholder"
                placeholder="Hi, ich nutze Paliad f&uuml;r die Aktenverwaltung &mdash; schau es dir mal an." />
            </div>
            <div id="invite-feedback" className="form-msg" style="display:none" />
            <div className="form-actions">
              <button type="button" className="btn-cancel" id="invite-modal-cancel" data-i18n="invite.modal.cancel">Abbrechen</button>
              <button type="submit" className="btn-primary" id="invite-submit" data-i18n="invite.modal.send">Einladung senden</button>
            </div>
          </form>
        </div>
      </div>
    </Fragment>
  );
}
