/*
 * Application shell — sidebar, topbar, page frame.
 *
 * The structure mirrors Arbiter (apps/ARBITER-FRONTEND/src/components/layout):
 *
 *   AppShell
 *     AppShellSidebar        collapsible on desktop, overlay drawer on mobile
 *     AppShellContent
 *       AppShellTopbar       sticky, h-14, translucent
 *       AppShellPage         the only scroll container
 *         PageContainer / PageHeader / Section
 *
 * Adapted rather than copied, because this repo has no build step: JSX is
 * compiled in the browser by Babel standalone, so there are no ES module
 * exports, no `@/` aliases and no lucide-react. Everything here lives inside an
 * IIFE and is published on window.Shell — the wrapper is load-bearing, since
 * Babel appends each transformed file as a plain <script>, which means top-level
 * declarations in separate .jsx files share one global scope and would collide
 * with the helpers already declared in PackagingAudit.jsx.
 *
 * No colour is hard-coded. Every class here refers to a semantic token defined
 * in index.html (background/foreground/card/border/muted/primary and the
 * sidebar-* family), so the palette is a one-place edit.
 */

(function () {
  const { createContext, useContext, useState } = React;

  const cn = (...parts) => parts.filter(Boolean).join(' ');

  /* ---------- icons ---------- */

  const Svg = ({ className = 'h-4 w-4', children, fill = 'none' }) => (
    <svg
      className={className}
      viewBox="0 0 24 24"
      fill={fill}
      stroke="currentColor"
      strokeWidth="1.75"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      {children}
    </svg>
  );

  const Icons = {
    Box: p => (
      <Svg {...p}>
        <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
        <path d="M3.3 7 12 12l8.7-5" />
        <path d="M12 22V12" />
      </Svg>
    ),
    Gauge: p => (
      <Svg {...p}>
        <path d="M3 20a9 9 0 1 1 18 0" />
        <path d="M12 20v-6" />
        <path d="m15.5 10.5-3.5 3.5" />
      </Svg>
    ),
    Info: p => (
      <Svg {...p}>
        <circle cx="12" cy="12" r="9" />
        <path d="M12 16v-5" />
        <path d="M12 8h.01" />
      </Svg>
    ),
    Mail: p => (
      <Svg {...p}>
        <rect x="3" y="5" width="18" height="14" rx="2" />
        <path d="m3.5 6.5 8.5 6 8.5-6" />
      </Svg>
    ),
    Menu: p => (
      <Svg {...p}>
        <path d="M4 6h16" />
        <path d="M4 12h16" />
        <path d="M4 18h16" />
      </Svg>
    ),
    Close: p => (
      <Svg {...p}>
        <path d="M6 6l12 12" />
        <path d="M18 6 6 18" />
      </Svg>
    ),
    ChevronLeft: p => (
      <Svg {...p}>
        <path d="m14 6-6 6 6 6" />
      </Svg>
    ),
    ChevronRight: p => (
      <Svg {...p}>
        <path d="m10 6 6 6-6 6" />
      </Svg>
    ),
    External: p => (
      <Svg {...p}>
        <path d="M14 4h6v6" />
        <path d="M20 4 10 14" />
        <path d="M18 14v6H4V4h6" />
      </Svg>
    ),
    ArrowRight: p => (
      <Svg {...p}>
        <path d="M4 12h15" />
        <path d="m13 6 6 6-6 6" />
      </Svg>
    ),
    Ruler: p => (
      <Svg {...p}>
        <rect x="2" y="8" width="20" height="8" rx="1.5" />
        <path d="M7 8v3M12 8v3M17 8v3" />
      </Svg>
    ),
    Weight: p => (
      <Svg {...p}>
        <circle cx="12" cy="5" r="2" />
        <path d="M8.5 7h7l3 13h-13Z" />
      </Svg>
    ),
    Truck: p => (
      <Svg {...p}>
        <path d="M2 6h11v11H2z" />
        <path d="M13 10h4l3 3v4h-7" />
        <circle cx="6.5" cy="19" r="1.6" />
        <circle cx="16.5" cy="19" r="1.6" />
      </Svg>
    ),
    Sparkle: p => (
      <Svg {...p}>
        <path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8Z" />
      </Svg>
    ),
    Check: p => (
      <Svg {...p}>
        <path d="m4 12.5 5 5L20 6.5" />
      </Svg>
    ),
    ArrowUpRight: p => (
      <Svg {...p}>
        <path d="M7 17 17 7" />
        <path d="M8 7h9v9" />
      </Svg>
    ),
    Upload: p => (
      <Svg {...p}>
        <path d="M12 16V4" />
        <path d="m7.5 8.5 4.5-4.5 4.5 4.5" />
        <path d="M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" />
      </Svg>
    ),
    Download: p => (
      <Svg {...p}>
        <path d="M12 4v12" />
        <path d="m7.5 11.5 4.5 4.5 4.5-4.5" />
        <path d="M4 19h16" />
      </Svg>
    ),
    File: p => (
      <Svg {...p}>
        <path d="M13 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V9Z" />
        <path d="M13 3v6h6" />
      </Svg>
    ),
    Layers: p => (
      <Svg {...p}>
        <path d="m12 3 8 4.5-8 4.5-8-4.5Z" />
        <path d="m4 12.5 8 4.5 8-4.5" />
      </Svg>
    ),
    Bolt: p => (
      <Svg {...p}>
        <path d="M13.5 3 5 14h5.5L9.5 21 19 10h-5.5Z" />
      </Svg>
    ),
    Chart: p => (
      <Svg {...p}>
        <path d="M4 20V4" />
        <path d="M4 20h16" />
        <path d="m7.5 15 3.5-4.5 3 2.5L20 7" />
      </Svg>
    ),
    Scissors: p => (
      <Svg {...p}>
        <circle cx="6" cy="6" r="2.5" />
        <circle cx="6" cy="18" r="2.5" />
        <path d="M8 7.5 20 18" />
        <path d="M8 16.5 20 6" />
      </Svg>
    ),
    /* The five below carry the platform capabilities on the About page, which is
       where the marketing site's icon set landed. Same 24-grid outlines. */
    Warehouse: p => (
      <Svg {...p}>
        <path d="M3 21V9l9-6 9 6v12" />
        <path d="M9 21v-6h6v6" />
        <path d="M7 10h10" />
      </Svg>
    ),
    Bell: p => (
      <Svg {...p}>
        <path d="M18 8a6 6 0 1 0-12 0c0 7-3 7-3 7h18s-3 0-3-7" />
        <path d="M13.7 21a2 2 0 0 1-3.4 0" />
      </Svg>
    ),
    Users: p => (
      <Svg {...p}>
        <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
        <circle cx="9" cy="7" r="3.5" />
        <path d="M22 21v-2a4 4 0 0 0-3-3.87" />
        <path d="M16 3.6a4 4 0 0 1 0 7.75" />
      </Svg>
    ),
    Lock: p => (
      <Svg {...p}>
        <rect x="3.5" y="10.5" width="17" height="10.5" rx="2" />
        <path d="M7.5 10.5V7a4.5 4.5 0 0 1 9 0v3.5" />
      </Svg>
    ),
    Shield: p => (
      <Svg {...p}>
        <path d="M12 21.5s7.5-3.75 7.5-9.5V5L12 2.5 4.5 5v7c0 5.75 7.5 9.5 7.5 9.5Z" />
        <path d="m9 11.5 2 2 4-4" />
      </Svg>
    ),
  };

  /* ---------- shell context ---------- */

  const ShellContext = createContext({
    mobileOpen: false,
    setMobileOpen: () => {},
    collapsed: false,
    setCollapsed: () => {},
  });

  const useShell = () => useContext(ShellContext);

  function AppShell({ children }) {
    const [mobileOpen, setMobileOpen] = useState(false);
    const [collapsed, setCollapsed] = useState(false);
    return (
      <ShellContext.Provider value={{ mobileOpen, setMobileOpen, collapsed, setCollapsed }}>
        {/* The app floats as a rounded panel on a darker canvas. Only from lg up:
            on a phone the inset would waste scarce width, so there it goes
            edge-to-edge and the rounding is dropped. */}
        <div className="h-screen bg-canvas p-0 lg:p-2.5">
          <div className="flex h-full overflow-hidden bg-background text-foreground lg:rounded-2xl lg:border lg:border-border lg:shadow-2xl">
            {children}
          </div>
        </div>
      </ShellContext.Provider>
    );
  }

  function AppShellSidebar({ children }) {
    const { mobileOpen, setMobileOpen, collapsed } = useShell();
    return (
      <React.Fragment>
        {mobileOpen && (
          <div
            className="fixed inset-0 z-40 bg-foreground/40 backdrop-blur-sm lg:hidden"
            onClick={() => setMobileOpen(false)}
          />
        )}
        <aside
          className={cn(
            'fixed inset-y-0 left-0 z-50 flex w-64 flex-col border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-all duration-300 ease-in-out lg:static lg:z-auto',
            mobileOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0',
            collapsed ? 'lg:w-16' : 'lg:w-64'
          )}
        >
          {children}
        </aside>
      </React.Fragment>
    );
  }

  function AppShellContent({ children }) {
    return <div className="flex min-w-0 flex-1 flex-col overflow-hidden">{children}</div>;
  }

  function AppShellTopbar({ children }) {
    return (
      <header className="sticky top-0 z-30 flex h-14 shrink-0 items-center justify-between gap-3 border-b border-border bg-card/80 px-4 backdrop-blur-xl lg:px-6">
        {children}
      </header>
    );
  }

  function AppShellPage({ children }) {
    return <main className="flex-1 overflow-y-auto">{children}</main>;
  }

  /* ---------- sidebar pieces ---------- */

  function SidebarLogo({ title, subtitle }) {
    const { collapsed, setMobileOpen } = useShell();
    return (
      <div className="flex h-14 shrink-0 items-center gap-2.5 border-b border-sidebar-border px-3">
        {/* The accent as a fill, which is the one thing --primary is for; the
            glyph on top therefore takes --primary-foreground and goes dark,
            since the green is far too light to carry white text. */}
        <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground">
          <span className="text-sm font-black leading-none">A</span>
        </div>
        {!collapsed && (
          <div className="min-w-0 leading-tight">
            <div className="truncate text-sm font-black tracking-tight">{title}</div>
            <div className="truncate text-2xs font-light opacity-50">{subtitle}</div>
          </div>
        )}
        <button
          onClick={() => setMobileOpen(false)}
          className="ml-auto rounded-md p-1.5 opacity-70 hover:bg-sidebar-accent hover:opacity-100 lg:hidden"
          aria-label="Close navigation"
        >
          <Icons.Close />
        </button>
      </div>
    );
  }

  function SidebarGroup({ label, children }) {
    const { collapsed } = useShell();
    return (
      <div className="px-2 py-3">
        {!collapsed && label && (
          <div className="px-2.5 pb-1.5 text-2xs font-bold uppercase tracking-widest opacity-40">
            {label}
          </div>
        )}
        <div className="space-y-0.5">{children}</div>
      </div>
    );
  }

  function SidebarNavItem({ icon, label, active, badge, onClick }) {
    const { collapsed, setMobileOpen } = useShell();
    const Icon = icon;
    return (
      <button
        onClick={() => {
          setMobileOpen(false);
          onClick?.();
        }}
        aria-current={active ? 'page' : undefined}
        title={collapsed ? label : undefined}
        className={cn(
          'flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',
          collapsed && 'lg:justify-center',
          // A neutral raised pill marks the active row, and only the icon carries
          // the accent — the whole-row blue it replaced competed with the content.
          active
            ? 'bg-sidebar-accent font-semibold text-sidebar-foreground shadow-sm ring-1 ring-sidebar-foreground/5'
            : 'font-medium opacity-60 hover:bg-sidebar-accent/60 hover:opacity-100'
        )}
      >
        {Icon && (
          <Icon className={cn('h-4 w-4 shrink-0', active && 'text-sidebar-primary')} />
        )}
        {!collapsed && <span className="truncate">{label}</span>}
        {!collapsed && badge != null && (
          <span className="ml-auto rounded-md bg-sidebar-foreground/10 px-1.5 py-0.5 text-2xs font-semibold tabular-nums opacity-80">
            {badge}
          </span>
        )}
      </button>
    );
  }

  function SidebarFooter({ children }) {
    const { collapsed } = useShell();
    if (collapsed) return null;
    return <div className="mt-auto px-4 py-4 text-2xs leading-relaxed opacity-50">{children}</div>;
  }

  function SidebarCollapseToggle() {
    const { collapsed, setCollapsed } = useShell();
    return (
      <button
        onClick={() => setCollapsed(c => !c)}
        className={cn(
          'hidden shrink-0 items-center gap-2.5 border-t border-sidebar-border px-4 py-3 text-2xs font-semibold uppercase tracking-widest opacity-50 hover:bg-sidebar-accent hover:opacity-100 lg:flex',
          collapsed && 'justify-center px-0'
        )}
        aria-label={collapsed ? 'Expand navigation' : 'Collapse navigation'}
      >
        {collapsed ? <Icons.ChevronRight /> : <Icons.ChevronLeft />}
        {!collapsed && <span>Collapse</span>}
      </button>
    );
  }

  function SidebarMobileTrigger() {
    const { setMobileOpen } = useShell();
    return (
      <button
        onClick={() => setMobileOpen(true)}
        className="-ml-1 rounded-md p-2 text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden"
        aria-label="Open navigation"
      >
        <Icons.Menu className="h-5 w-5" />
      </button>
    );
  }

  /* ---------- page pieces ---------- */

  function PageContainer({ children, fluid = false, className }) {
    return (
      <div className={cn('px-4 py-6 sm:px-6 lg:px-8', !fluid && 'mx-auto max-w-7xl', className)}>
        {children}
      </div>
    );
  }

  function PageHeader({ title, description, actions }) {
    return (
      <div className="mb-6 flex flex-wrap items-start justify-between gap-4">
        <div className="min-w-0">
          <h1 className="truncate text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
            {title}
          </h1>
          {description && <p className="mt-1 text-sm text-muted-foreground">{description}</p>}
        </div>
        {actions && <div className="flex shrink-0 items-center gap-2">{actions}</div>}
      </div>
    );
  }

  /* `id` is for in-page jump targets (the About page's section index). The
     scroll margin keeps a jumped-to heading clear of the sticky topbar. */
  function Section({ id, title, description, actions, children }) {
    return (
      <section id={id} className="scroll-mt-6 space-y-4 py-6 first:pt-0">
        {(title || actions) && (
          <div className="flex flex-wrap items-end justify-between gap-3">
            <div>
              {title && <h2 className="text-base font-semibold text-foreground">{title}</h2>}
              {description && <p className="mt-0.5 text-sm text-muted-foreground">{description}</p>}
            </div>
            {actions}
          </div>
        )}
        {children}
      </section>
    );
  }

  function Card({ children, className }) {
    return (
      <div className={cn('rounded-2xl border border-border bg-card p-5', className)}>{children}</div>
    );
  }

  /* ---------- card language ----------
   *
   * Small bordered chip, a tinted summary band, and two compact charts. These
   * exist so a board of scenario cards reads at a glance instead of as a wall of
   * numbers: the chips carry the secondary metrics, the band carries the headline.
   *
   * Every one takes an `invert` flag, because the selected card in a board is
   * rendered dark-on-light and its contents have to follow it across.
   */

  function Chip({ icon, children, invert, tone }) {
    const Icon = icon;
    const base = invert
      ? 'border-background/20 bg-background/10 text-background/85'
      : tone === 'good'
      ? 'border-success/25 bg-success/10 text-success'
      : tone === 'bad'
      ? 'border-danger/25 bg-danger/10 text-danger'
      : tone === 'accent'
      ? 'border-primary/25 bg-primary/10 text-primary-ink'
      : 'border-border bg-muted/60 text-muted-foreground';
    return (
      <span
        className={cn(
          'inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-2xs font-medium',
          base
        )}
      >
        {Icon && <Icon className="h-3 w-3" />}
        {children}
      </span>
    );
  }

  function SummaryBand({ children, className }) {
    return (
      <div
        className={cn(
          'grid gap-6 rounded-2xl border border-border bg-card-raised px-5 py-6 sm:px-7 lg:grid-cols-[minmax(0,1.1fr)_auto_minmax(0,1fr)] lg:items-center lg:gap-8',
          className
        )}
      >
        {children}
      </div>
    );
  }

  /** One big number in the summary band, optionally with a trailing arrow. */
  function BandFigure({ label, value, sub, tone, arrow }) {
    const toneClass =
      tone === 'good' ? 'text-success' : tone === 'bad' ? 'text-danger' : 'text-foreground';
    return (
      <div className="min-w-0">
        <div className={cn('truncate text-3xl font-semibold tabular-nums', toneClass)}>{value}</div>
        <div className="mt-1.5 flex items-center gap-2">
          <div className="min-w-0">
            <div className="text-xs font-medium text-foreground">{label}</div>
            {sub && <div className="text-2xs text-muted-foreground">{sub}</div>}
          </div>
          {arrow && <Icons.ArrowRight className="ml-auto h-4 w-4 shrink-0 text-muted-foreground" />}
        </div>
      </div>
    );
  }

  /**
   * Ticked semicircular gauge.
   *
   * Ticks rather than a solid arc because at these sizes a stroke reads as a
   * progress bar bent in half, while discrete ticks read as a dial — and the
   * unfilled ticks still show the full scale, so 43% does not look like an error.
   */
  function TickGauge({ percent, label, sublabel, ticks = 30 }) {
    const value = Math.max(0, Math.min(100, Number(percent) || 0));
    // Geometry chosen so the inner radius clears the centred number: the arc is
    // 190 wide and the opening under it is ~120, which fits "100.0%" at text-2xl.
    const cx = 95;
    const cy = 95;
    const outer = 83;
    const inner = 66;
    const filled = Math.round((value / 100) * ticks);
    const marks = [];
    for (let i = 0; i < ticks; i++) {
      const a = Math.PI * (1 - i / (ticks - 1));
      marks.push(
        <line
          key={i}
          x1={cx + outer * Math.cos(a)}
          y1={cy - outer * Math.sin(a)}
          x2={cx + inner * Math.cos(a)}
          y2={cy - inner * Math.sin(a)}
          strokeWidth="3"
          strokeLinecap="round"
          // The unfilled ticks have to stay legible or the gauge loses its scale
          // and 43% reads as a broken arc rather than as less than half.
          className={i < filled ? 'stroke-foreground' : 'stroke-foreground/20'}
        />
      );
    }
    return (
      <div className="flex shrink-0 flex-col items-center">
        {/* The number is pinned to the bottom of the arc, which is where the bowl
            is widest — placed at the vertical centre it collides with the ticks. */}
        <div className="relative h-[100px] w-[190px]">
          <svg viewBox="0 0 190 100" className="h-full w-full" aria-hidden="true">
            {marks}
          </svg>
          <div className="absolute inset-x-0 bottom-0 text-center text-2xl font-semibold leading-none tabular-nums text-foreground">
            {value.toFixed(1)}%
          </div>
        </div>
        <div className="mt-2 text-center">
          <div className="text-xs font-medium text-foreground">{label}</div>
          {sublabel && <div className="text-2xs text-muted-foreground">{sublabel}</div>}
        </div>
      </div>
    );
  }

  /**
   * Compact labelled bar chart. Bars are signed: anything below zero draws in the
   * danger tone downward from the axis, so a scenario that costs money is visibly
   * different from one that merely saves little.
   */
  function BarSpark({ bars, caption }) {
    const peak = Math.max(1e-9, ...bars.map(b => Math.abs(b.value)));
    const anyNegative = bars.some(b => b.value < 0);
    const NEG_ZONE = 14;
    return (
      <div className="min-w-0">
        <div className="flex items-end gap-2 sm:gap-3">
          {bars.map((b, i) => {
            const negative = b.value < 0;
            const magnitude = Math.abs(b.value) / peak;
            // Small-but-real values still get a few pixels, so a scenario that
            // saves almost nothing is distinguishable from one that saves nothing.
            const height = b.value === 0 ? 0 : Math.max(4, Math.round(magnitude * 72));
            return (
              <div key={b.label + i} className="flex min-w-0 flex-1 flex-col items-center">
                <div className="flex h-[76px] w-full flex-col justify-end">
                  {!negative && (
                    <div
                      title={b.title}
                      style={{ height: `${height}px` }}
                      className={cn(
                        'w-full rounded-t-sm',
                        b.highlight ? 'bg-foreground' : 'bg-foreground/25'
                      )}
                    />
                  )}
                </div>
                {/* The axis is drawn per column rather than as one rule, so it
                    stays aligned with the bars at any column count. */}
                {anyNegative && (
                  <React.Fragment>
                    <div className="h-px w-full bg-foreground/25" />
                    <div className="flex w-full flex-col justify-start" style={{ height: NEG_ZONE }}>
                      {negative && (
                        <div
                          title={b.title}
                          style={{ height: `${Math.max(4, Math.min(NEG_ZONE, height))}px` }}
                          className="w-full rounded-b-sm bg-danger"
                        />
                      )}
                    </div>
                  </React.Fragment>
                )}
                <div className="mt-1.5 w-full truncate text-center text-2xs text-muted-foreground">
                  {b.label}
                </div>
              </div>
            );
          })}
        </div>
        {caption && <div className="mt-2 text-2xs text-muted-foreground">{caption}</div>}
      </div>
    );
  }

  /** Column of cards, in the manner of a board. */
  function BoardColumn({ title, count, children }) {
    return (
      <div className="flex min-w-0 flex-col">
        <div className="mb-3 flex items-center gap-2">
          <h3 className="truncate text-sm font-semibold text-foreground">{title}</h3>
          {count != null && (
            <span className="rounded-md border border-border bg-muted/60 px-1.5 py-0.5 text-2xs font-semibold tabular-nums text-muted-foreground">
              {count}
            </span>
          )}
        </div>
        <div className="space-y-3">{children}</div>
      </div>
    );
  }

  /* ---------- dashboard kit ----------
   *
   * The pieces a panel-based dark dashboard is assembled from. The shared rules:
   * a panel is `rounded-2xl` on `bg-card` with a hairline border, labels are small
   * and muted, values are large and light, and units/deltas are demoted to a
   * smaller size beside the value rather than given their own row.
   */

  /** Dashboard panel. `tone="accent"` is the one saturated element on a screen. */
  function Panel({ title, subtitle, eyebrow, actions, children, className, tone }) {
    const accent = tone === 'accent';
    return (
      <div
        className={cn(
          'rounded-2xl border p-5',
          accent ? 'border-primary bg-primary text-primary-foreground' : 'border-border bg-card',
          className
        )}
      >
        {(title || actions || eyebrow) && (
          <div className="mb-4 flex items-start justify-between gap-3">
            <div className="min-w-0">
              {eyebrow && (
                <div
                  className={cn(
                    'text-2xs font-bold uppercase tracking-widest',
                    accent ? 'text-primary-foreground/70' : 'text-muted-foreground'
                  )}
                >
                  {eyebrow}
                </div>
              )}
              {title && (
                <h3 className={cn('text-sm font-semibold', eyebrow && 'mt-1')}>{title}</h3>
              )}
              {subtitle && (
                <p
                  className={cn(
                    'mt-1 text-xs leading-relaxed',
                    accent ? 'text-primary-foreground/80' : 'text-muted-foreground'
                  )}
                >
                  {subtitle}
                </p>
              )}
            </div>
            {actions && <div className="flex shrink-0 items-center gap-1.5">{actions}</div>}
          </div>
        )}
        {children}
      </div>
    );
  }

  /** Rounded square holding an outline icon — the label marker on a metric card. */
  function IconTile({ icon, className, size = 'md' }) {
    const Icon = icon;
    const box = size === 'lg' ? 'h-11 w-11 rounded-xl' : 'h-8 w-8 rounded-lg';
    return (
      <span
        className={cn(
          'inline-flex shrink-0 items-center justify-center border border-border bg-card-raised text-foreground',
          box,
          className
        )}
      >
        <Icon className={size === 'lg' ? 'h-5 w-5' : 'h-4 w-4'} />
      </span>
    );
  }

  /** Circular icon button, as used in the corner of a panel. */
  function IconButton({ icon, label, onClick, href, tone }) {
    const Icon = icon;
    const cls = cn(
      'inline-flex h-8 w-8 items-center justify-center rounded-full border transition-colors',
      tone === 'accent'
        ? 'border-primary-foreground/30 text-primary-foreground hover:bg-primary-foreground/15'
        : 'border-border text-muted-foreground hover:bg-card-raised hover:text-foreground'
    );
    if (href) {
      return (
        <a href={href} className={cls} aria-label={label} title={label}>
          <Icon className="h-4 w-4" />
        </a>
      );
    }
    return (
      <button onClick={onClick} className={cls} aria-label={label} title={label}>
        <Icon className="h-4 w-4" />
      </button>
    );
  }

  /**
   * Area sparkline over an arbitrary series.
   *
   * Values are normalised across the series and a zero line is drawn when the
   * series crosses it, so a chart with a negative point cannot be mistaken for one
   * that merely starts low. The gradient id is derived from the caller-supplied
   * `id` because several of these render on one page and duplicate SVG ids would
   * make every chart adopt the first one's fill.
   */
  function Sparkline({ id, values, height = 56, tone = 'default', markLast = true }) {
    const series = (values || []).map(v => Number(v) || 0);
    if (series.length < 2) return null;
    const W = 240;
    const H = height;
    const pad = 6;
    const lo = Math.min(0, ...series);
    const hi = Math.max(0, ...series);
    const span = hi - lo || 1;
    const x = i => (i / (series.length - 1)) * (W - pad * 2) + pad;
    const y = v => H - pad - ((v - lo) / span) * (H - pad * 2);

    const line = series.map((v, i) => `${i ? 'L' : 'M'}${x(i).toFixed(2)},${y(v).toFixed(2)}`).join(' ');
    const area = `${line} L${x(series.length - 1).toFixed(2)},${(H - pad).toFixed(2)} L${x(0).toFixed(
      2
    )},${(H - pad).toFixed(2)} Z`;
    // The line has to be legible, so it takes the ink green; the area beneath it is
    // a 28%-opacity wash off `fill`, which is where the vivid green still reads.
    const stroke = tone === 'accent' ? 'stroke-primary-ink' : 'stroke-foreground';
    const fill = tone === 'accent' ? 'text-primary' : 'text-foreground';
    const grad = `spark-${id}`;
    const crossesZero = lo < 0 && hi > 0;

    // The height is fixed in pixels and the width is whatever the container gives,
    // so the viewBox is stretched horizontally (preserveAspectRatio="none").
    // non-scaling-stroke keeps the line an even 2px through that stretch; the
    // end-point marker is a DOM element positioned in percentages rather than an
    // SVG circle, which would come out as an ellipse.
    const lastLeft = (x(series.length - 1) / W) * 100;
    const lastTop = (y(series[series.length - 1]) / H) * 100;

    return (
      <div className="relative w-full" style={{ height: `${H}px` }}>
        <svg
          viewBox={`0 0 ${W} ${H}`}
          className="h-full w-full"
          preserveAspectRatio="none"
          aria-hidden="true"
        >
          <defs>
            <linearGradient id={grad} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor="currentColor" stopOpacity="0.28" />
              <stop offset="100%" stopColor="currentColor" stopOpacity="0" />
            </linearGradient>
          </defs>
          <path d={area} fill={`url(#${grad})`} className={fill} />
          {crossesZero && (
            <line
              x1={pad}
              x2={W - pad}
              y1={y(0)}
              y2={y(0)}
              strokeDasharray="3 4"
              className="stroke-border"
              strokeWidth="1"
            />
          )}
          <path
            d={line}
            fill="none"
            strokeWidth="2"
            strokeLinejoin="round"
            className={stroke}
            vectorEffect="non-scaling-stroke"
          />
        </svg>
        {markLast && (
          <span
            className={cn(
              'pointer-events-none absolute h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 bg-background',
              tone === 'accent' ? 'border-primary' : 'border-foreground'
            )}
            style={{ left: `${lastLeft}%`, top: `${lastTop}%` }}
          />
        )}
      </div>
    );
  }

  /**
   * Metric tile: icon + label, big value with a demoted unit, a delta chip and an
   * optional chart underneath. The value never wraps; long values shrink instead.
   */
  function MetricCard({ icon, label, value, unit, delta, deltaTone, sub, chart, action, className }) {
    const dt =
      deltaTone === 'good'
        ? 'border-success/30 bg-success/10 text-success'
        : deltaTone === 'bad'
        ? 'border-danger/30 bg-danger/10 text-danger'
        : 'border-border bg-card-raised text-muted-foreground';
    return (
      <div className={cn('flex flex-col rounded-2xl border border-border bg-card p-4', className)}>
        <div className="flex items-start justify-between gap-2">
          <div className="flex min-w-0 items-center gap-2.5">
            {icon && <IconTile icon={icon} />}
            <span className="truncate text-xs font-medium text-muted-foreground">{label}</span>
          </div>
          {action}
        </div>
        <div className="mt-4 flex items-baseline gap-1.5">
          <span className="text-3xl font-semibold leading-none tracking-tight tabular-nums">
            {value}
          </span>
          {unit && <span className="text-sm font-medium text-muted-foreground">{unit}</span>}
        </div>
        <div className="mt-2 flex items-center gap-2">
          {delta != null && (
            <span className={cn('rounded-md border px-1.5 py-0.5 text-2xs font-semibold tabular-nums', dt)}>
              {delta}
            </span>
          )}
          {sub && <span className="truncate text-2xs text-muted-foreground">{sub}</span>}
        </div>
        {chart && <div className="mt-3">{chart}</div>}
      </div>
    );
  }

  /**
   * Labelled proportional bar. Used where a share of a total is the point — the
   * number alone does not show that one box carries a third of all shipments.
   */
  function Meter({ label, percent, value, tone }) {
    const p = Math.max(0, Math.min(100, Number(percent) || 0));
    const fill =
      tone === 'accent' ? 'bg-primary' : tone === 'muted' ? 'bg-muted-foreground/40' : 'bg-foreground';
    return (
      <div>
        <div className="flex items-baseline justify-between gap-3 text-xs">
          <span className="truncate font-medium text-foreground">{label}</span>
          <span className="shrink-0 tabular-nums text-muted-foreground">{value}</span>
        </div>
        <div className="mt-1.5 h-1.5 overflow-hidden rounded-full bg-card-raised">
          <div className={cn('h-full rounded-full transition-all', fill)} style={{ width: `${p}%` }} />
        </div>
      </div>
    );
  }

  /** Pill group for switching between views. */
  function SegmentedControl({ options, value, onChange, className }) {
    return (
      <div
        className={cn(
          'inline-flex items-center gap-1 rounded-full border border-border bg-card p-1',
          className
        )}
      >
        {options.map(o => (
          <button
            key={o.value}
            onClick={() => onChange(o.value)}
            aria-pressed={o.value === value}
            className={cn(
              'rounded-full px-3 py-1.5 text-xs font-medium transition-colors',
              o.value === value
                ? 'bg-foreground text-background'
                : 'text-muted-foreground hover:bg-card-raised hover:text-foreground'
            )}
          >
            {o.label}
          </button>
        ))}
      </div>
    );
  }

  /** Small labelled fact, used across the informational modules. */
  function Fact({ label, value, hint }) {
    return (
      <div className="rounded-2xl border border-border bg-card p-4">
        <div className="text-2xs font-semibold uppercase tracking-widest text-muted-foreground">
          {label}
        </div>
        <div className="mt-1.5 text-base font-semibold text-foreground">{value}</div>
        {hint && <div className="mt-1 text-xs text-muted-foreground">{hint}</div>}
      </div>
    );
  }

  function StatusDot({ tone = 'muted', label }) {
    const dot =
      tone === 'good' ? 'bg-success' : tone === 'bad' ? 'bg-danger' : 'bg-muted-foreground/50';
    return (
      <span className="inline-flex items-center gap-1.5 text-xs text-muted-foreground">
        <span className={cn('h-1.5 w-1.5 rounded-full', dot)} />
        {label}
      </span>
    );
  }

  window.Shell = {
    cn,
    Icons,
    useShell,
    AppShell,
    AppShellSidebar,
    AppShellContent,
    AppShellTopbar,
    AppShellPage,
    SidebarLogo,
    SidebarGroup,
    SidebarNavItem,
    SidebarFooter,
    SidebarCollapseToggle,
    SidebarMobileTrigger,
    PageContainer,
    PageHeader,
    Section,
    Card,
    Fact,
    StatusDot,
    Chip,
    SummaryBand,
    BandFigure,
    TickGauge,
    BarSpark,
    BoardColumn,
    Panel,
    IconTile,
    IconButton,
    Sparkline,
    MetricCard,
    Meter,
    SegmentedControl,
  };
})();
