// signal.jsx — GhostLabs homepage
// A+C direction. Palette-swappable via Tweaks. Workshop promoted to its own
// prominent full-width section between hero and gallery.

// ─── Palettes ──────────────────────────────────────────────────
// Each palette is a flat map of CSS variable suffixes → color. The current
// palette is written onto the document root as CSS custom properties.

// Each palette has three accents now: primary, secondary (used for
// in-progress states + complementary spots), and a softer "highlight" used
// for data emphasis. Optional `bg-grad` lets a palette set a gradient bg.

const PALETTES = {
  'signal-lime': {
    name: 'Signal Lime',
    note: 'Default · lime primary, peach secondary',
    mode: 'dark',
    vars: {
      bg: '#0a0a0b', surface: '#131316', 'surface-hi': '#1a1a1e',
      line: '#26262c', 'line-hi': '#3a3a42',
      text: '#ececea', 'text-dim': '#9c9a94', 'text-mute': '#5e5d57',
      accent: '#c8fb59', 'accent-2': '#fdba74', 'accent-ink': '#0a0a0b',
      highlight: '#e8f9c0', red: '#ff6a4a',
      'tile-bg': '#1a1a1e', 'panel-bg': '#0c0c0e',
      'bg-grad': 'var(--sig-bg)'
    }
  },
  'cobalt': {
    name: 'Cobalt Research',
    note: 'Institutional blue · sky secondary · subtle radial',
    mode: 'dark',
    vars: {
      bg: '#08090d', surface: '#101218', 'surface-hi': '#171a23',
      line: '#22262f', 'line-hi': '#343a47',
      text: '#ecedef', 'text-dim': '#9097a3', 'text-mute': '#565c6a',
      accent: '#5b8eff', 'accent-2': '#7ad8ff', 'accent-ink': '#08090d',
      highlight: '#c8d9ff', red: '#ff6a4a',
      'tile-bg': '#171a23', 'panel-bg': '#0a0c11',
      'bg-grad': 'radial-gradient(ellipse 1400px 900px at 50% -10%, #0e1424 0%, #08090d 60%)'
    }
  },
  'phosphor': {
    name: 'Phosphor CRT',
    note: 'Vintage terminal green · amber-vintage secondary',
    mode: 'dark',
    vars: {
      bg: '#050807', surface: '#0a100d', 'surface-hi': '#0e1611',
      line: '#1a241e', 'line-hi': '#2a3a30',
      text: '#d6f5e1', 'text-dim': '#7ea88c', 'text-mute': '#476054',
      accent: '#5cff95', 'accent-2': '#ffce5c', 'accent-ink': '#050807',
      highlight: '#b3ffce', red: '#ff6a4a',
      'tile-bg': '#0e1611', 'panel-bg': '#070b09',
      'bg-grad': 'var(--sig-bg)'
    }
  },
  'aurora': {
    name: 'Aurora Boreal',
    note: 'Mint primary · peach secondary · deep-navy gradient',
    mode: 'dark',
    vars: {
      bg: '#0a1019', surface: '#0f1722', 'surface-hi': '#152030',
      line: '#1f2c40', 'line-hi': '#2e3f58',
      text: '#e9f1f7', 'text-dim': '#8fa5be', 'text-mute': '#566580',
      accent: '#7affc8', 'accent-2': '#ffba88', 'accent-ink': '#0a1019',
      highlight: '#b6ffe0', red: '#ff6a4a',
      'tile-bg': '#152030', 'panel-bg': '#0c131e',
      'bg-grad': 'radial-gradient(ellipse 1600px 1000px at 85% -10%, #18324a 0%, #0a1019 55%)'
    }
  },
  'tungsten': {
    name: 'Tungsten Foundry',
    note: 'Brass primary · steel-blue secondary · warm charcoal',
    mode: 'dark',
    vars: {
      bg: '#0f0c08', surface: '#1a1612', 'surface-hi': '#221c16',
      line: '#322a23', 'line-hi': '#463c33',
      text: '#f5ecdc', 'text-dim': '#a89c8c', 'text-mute': '#6a604f',
      accent: '#d4a93d', 'accent-2': '#6585a8', 'accent-ink': '#0f0c08',
      highlight: '#f0e3b8', red: '#cc4a3a',
      'tile-bg': '#221c16', 'panel-bg': '#120f0b',
      'bg-grad': 'var(--sig-bg)'
    }
  },
  'magenta-static': {
    name: 'Magenta Static',
    note: 'Magenta × cyan · high-energy punk',
    mode: 'dark',
    vars: {
      bg: '#0a0810', surface: '#15101c', 'surface-hi': '#1d1626',
      line: '#2c2238', 'line-hi': '#3e3050',
      text: '#f4ebf6', 'text-dim': '#a995b3', 'text-mute': '#6a5a78',
      accent: '#ff3d8c', 'accent-2': '#3df0ff', 'accent-ink': '#0a0810',
      highlight: '#ffb3d4', red: '#ff5a4a',
      'tile-bg': '#1d1626', 'panel-bg': '#0e0b14',
      'bg-grad': 'linear-gradient(180deg, #100815 0%, #0a0810 100%)'
    }
  },
  'sodium': {
    name: 'Sodium Vapor',
    note: 'Sodium-orange × electric blue · industrial night',
    mode: 'dark',
    vars: {
      bg: '#08070a', surface: '#110f14', 'surface-hi': '#19161d',
      line: '#2a2530', 'line-hi': '#3c3645',
      text: '#f0e8dc', 'text-dim': '#a89986', 'text-mute': '#665a47',
      accent: '#ffae3c', 'accent-2': '#4a9eff', 'accent-ink': '#08070a',
      highlight: '#ffd99e', red: '#ff5a4a',
      'tile-bg': '#19161d', 'panel-bg': '#0b0a0d',
      'bg-grad': 'radial-gradient(ellipse 1200px 800px at 15% 0%, #1c1408 0%, #08070a 50%)'
    }
  },
  'plum-atelier': {
    name: 'Plum Atelier',
    note: 'Deep plum · brass primary · sage secondary',
    mode: 'dark',
    vars: {
      bg: '#14101a', surface: '#1c1626', 'surface-hi': '#241c30',
      line: '#332a44', 'line-hi': '#473b5e',
      text: '#ede6f2', 'text-dim': '#a695b5', 'text-mute': '#6a5a78',
      accent: '#d4a93d', 'accent-2': '#8aab8b', 'accent-ink': '#14101a',
      highlight: '#ede6c2', red: '#cc4a3a',
      'tile-bg': '#241c30', 'panel-bg': '#16121d',
      'bg-grad': 'var(--sig-bg)'
    }
  },
  'bone': {
    name: 'Bone & Ink',
    note: 'Light mode · oxblood × forest · atelier register',
    mode: 'light',
    vars: {
      bg: '#f1ede4', surface: '#eae3d2', 'surface-hi': '#e0d8c2',
      line: '#d6cfbd', 'line-hi': '#c2b9a1',
      text: '#1a1814', 'text-dim': '#5e5a51', 'text-mute': '#8a8576',
      accent: '#6b1e1e', 'accent-2': '#3e5f4a', 'accent-ink': '#f1ede4',
      highlight: '#9d6a1f', red: '#a8331f',
      'tile-bg': '#eae3d2', 'panel-bg': '#eae3d2',
      'bg-grad': 'var(--sig-bg)'
    }
  }
};

const v = (k) => `var(--sig-${k})`; // shorthand: v('accent') → 'var(--sig-accent)'

// ─── Brief endpoint ───────────────────────────────────────────
// Where submitted briefs go. Drop in a Firebase Cloud Function URL like
//   https://europe-west3-<project>.cloudfunctions.net/submitBrief
// While this is empty, the form falls back to a prefilled mailto.
const BRIEF_ENDPOINT = '';
const BRIEF_EMAIL = 'ghostlabsoftware@gmail.com';

// ─── Mobile detection ─────────────────────────────────────────
// Single source of truth for the "this is a small screen" branch. Every
// section that has a forked mobile layout reads this hook directly.
//
// Breakpoint: 760px. Tablets in portrait fall into mobile (they're narrow
// enough that the desktop multi-column grids don't fit); tablets in
// landscape stay on the desktop layout. SSR-safe (defaults to false).
const MOBILE_BREAKPOINT = 760;
function useIsMobile() {
  const get = () => typeof window !== 'undefined' && window.innerWidth <= MOBILE_BREAKPOINT;
  const [m, setM] = React.useState(get);
  React.useEffect(() => {
    const onResize = () => setM(get());
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return m;
}

// Smooth-scroll helper. Uses window.scrollTo (NOT element.scrollIntoView,
// which can desync the sticky nav transform).
function smoothScrollTo(id, offset = 24) {
  const el = document.getElementById(id);
  if (!el) return;
  const top = el.getBoundingClientRect().top + window.scrollY - offset;
  window.scrollTo({ top, behavior: 'smooth' });
}

// ─── Accordion row ────────────────────────────────────────────
// Reusable expand/collapse row for mobile-only sections that pack a lot of
// copy (Practice, Engagement). Tap a row, body expands smoothly.
// `defaultOpen` lets the first one auto-expand so the section doesn't look
// dead on first render.
function MobileAccordion({ index, eyebrow, title, body, defaultOpen = false }) {
  const [open, setOpen] = React.useState(defaultOpen);
  return (
    <div style={{ borderTop: index === 0 ? `1px solid ${v('line-hi')}` : `1px solid ${v('line')}` }}>
      <button
        type="button"
        onClick={() => setOpen((o) => !o)}
        aria-expanded={open}
        style={{
          width: '100%', textAlign: 'left', background: 'transparent', border: 0,
          padding: '20px 0', cursor: 'pointer',
          display: 'flex', gap: 14, alignItems: 'flex-start',
          fontFamily: SIG_FONTS.sans, color: v('text')
        }}>
        
        {eyebrow &&
        <div className="sig-mono" style={{ fontSize: 11, color: open ? v('accent') : v('text-mute'), letterSpacing: '0.12em', flexShrink: 0, paddingTop: 4, minWidth: 32 }}>
            {eyebrow}
          </div>
        }
        <div style={{ flex: 1, fontSize: 17, fontWeight: 500, lineHeight: 1.28, letterSpacing: '-0.015em' }}>
          {title}
        </div>
        <div style={{
          flexShrink: 0, color: open ? v('accent') : v('text-mute'),
          fontSize: 16, transition: 'transform .2s ease', paddingTop: 4,
          transform: open ? 'rotate(180deg)' : 'rotate(0deg)'
        }}>▾</div>
      </button>
      <div style={{
        maxHeight: open ? 600 : 0, overflow: 'hidden',
        transition: 'max-height .3s ease, opacity .2s ease',
        opacity: open ? 1 : 0
      }}>
        <div style={{ paddingBottom: 22, fontSize: 14, color: v('text-dim'), lineHeight: 1.65 }}>{body}</div>
      </div>
    </div>);

}

// ─── Tweak defaults (persisted via host) ───────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "phosphor",
  "galleryLayout": "spotlight"
} /*EDITMODE-END*/;

const SIG_FONTS = {
  sans: "'Inter Tight', system-ui, sans-serif",
  mono: "'JetBrains Mono', ui-monospace, monospace"
};

// One-time style injection. All colors are CSS vars; the palette sets them.
if (typeof document !== 'undefined' && !document.getElementById('sig-styles')) {
  const s = document.createElement('style');s.id = 'sig-styles';
  s.textContent = `
    :root { color-scheme: dark; }
    html, body { background: var(--sig-bg-grad, var(--sig-bg)); }
    .sig-root { font-family: ${SIG_FONTS.sans}; color: ${v('text')}; background: var(--sig-bg-grad, var(--sig-bg)); min-height: 100vh; transition: background-color .25s ease, color .25s ease; }
    .sig-root *, .sig-root *::before, .sig-root *::after { box-sizing: border-box; }
    .sig-mono { font-family: ${SIG_FONTS.mono}; }
    .sig-eyebrow { font-family: ${SIG_FONTS.mono}; font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: ${v('text-dim')}; }
    .sig-h1 { font-family: ${SIG_FONTS.sans}; font-weight: 500; font-size: 80px; line-height: 0.98; letter-spacing: -0.035em; margin: 0; }
    .sig-h2 { font-family: ${SIG_FONTS.sans}; font-weight: 500; font-size: 44px; line-height: 1.04; letter-spacing: -0.025em; margin: 0; }
    .sig-h3 { font-family: ${SIG_FONTS.sans}; font-weight: 500; font-size: 22px; line-height: 1.18; letter-spacing: -0.015em; margin: 0; }
    .sig-display { font-family: ${SIG_FONTS.sans}; font-weight: 500; font-size: 64px; line-height: 1; letter-spacing: -0.03em; margin: 0; }
    .sig-body { font-size: 17px; line-height: 1.6; color: ${v('text-dim')}; font-weight: 300; }
    .sig-rule { height: 1px; background: ${v('line')}; width: 100%; }
    .sig-link { color: ${v('accent')}; text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px; }
    .sig-pill { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px 6px 10px; border: 1px solid ${v('line')}; border-radius: 999px; font-family: ${SIG_FONTS.mono}; font-size: 11px; color: ${v('text-dim')}; letter-spacing: 0.04em; }
    .sig-dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
    .sig-dot.live  { background: ${v('accent')};   box-shadow: 0 0 0 3px color-mix(in srgb, ${v('accent')}   14%, transparent); }
    .sig-dot.amber { background: ${v('accent-2')}; box-shadow: 0 0 0 3px color-mix(in srgb, ${v('accent-2')} 14%, transparent); }
    .sig-dot.red   { background: ${v('red')}; }
    .sig-dot.mute  { background: ${v('text-mute')}; }

    /* Pulsing variant for prominent workshop rows */
    @keyframes sig-pulse-live {
      0%   { box-shadow: 0 0 0 0   color-mix(in srgb, ${v('accent')} 55%, transparent); }
      60%  { box-shadow: 0 0 0 9px color-mix(in srgb, ${v('accent')}  0%, transparent); }
      100% { box-shadow: 0 0 0 0   color-mix(in srgb, ${v('accent')}  0%, transparent); }
    }
    @keyframes sig-pulse-amber {
      0%   { box-shadow: 0 0 0 0   color-mix(in srgb, ${v('accent-2')} 50%, transparent); }
      60%  { box-shadow: 0 0 0 9px color-mix(in srgb, ${v('accent-2')}  0%, transparent); }
      100% { box-shadow: 0 0 0 0   color-mix(in srgb, ${v('accent-2')}  0%, transparent); }
    }
    .sig-dot-pulse       { width: 10px; height: 10px; border-radius: 50%; display: inline-block; background: ${v('accent')};   animation: sig-pulse-live  2.4s ease-out infinite; }
    .sig-dot-pulse.amber { background: ${v('accent-2')}; animation: sig-pulse-amber 2.4s ease-out infinite; }
    .sig-dot-pulse.mute  { background: ${v('text-mute')}; animation: none; }

    .sig-btn-primary { display: inline-flex; align-items: center; gap: 10px; padding: 15px 24px; background: ${v('accent')}; color: ${v('accent-ink')}; border: 0; font-family: ${SIG_FONTS.sans}; font-weight: 500; font-size: 15px; letter-spacing: -0.005em; cursor: pointer; border-radius: 2px; transition: filter .15s; }
    .sig-btn-primary:hover { filter: brightness(1.08); }
    .sig-btn-ghost { display: inline-flex; align-items: center; gap: 10px; padding: 14px 24px; background: transparent; color: ${v('text')}; border: 1px solid ${v('line-hi')}; font-family: ${SIG_FONTS.sans}; font-weight: 400; font-size: 15px; cursor: pointer; border-radius: 2px; }
    .sig-card { background: ${v('surface')}; border: 1px solid ${v('line')}; }
    .sig-tile-img { background: ${v('tile-bg')}; border-bottom: 1px solid ${v('line')}; overflow: hidden; position: relative; }
    .sig-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid ${v('line')}; border-radius: 2px; font-family: ${SIG_FONTS.mono}; font-size: 11px; color: ${v('text-dim')}; }
    .sig-chip.on { background: ${v('text')}; color: ${v('accent-ink')}; border-color: ${v('text')}; }
    .sig-input { background: transparent; border: 0; border-bottom: 1px solid ${v('line')}; padding: 12px 0; color: ${v('text')}; font-family: ${SIG_FONTS.sans}; font-size: 16px; width: 100%; outline: none; }
    .sig-input:focus { border-bottom-color: ${v('accent')}; }
    .sig-label { font-family: ${SIG_FONTS.mono}; font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: ${v('text-mute')}; }

    /* Workshop section */
    .sig-workshop { background: ${v('panel-bg')}; border-top: 1px solid ${v('line')}; border-bottom: 1px solid ${v('line')}; }
    .sig-ws-row { display: grid; grid-template-columns: 28px 1.3fr 2.2fr 110px 140px 24px; gap: 28px; align-items: center; padding: 26px 0; border-top: 1px solid ${v('line')}; cursor: pointer; transition: background-color .15s, padding .2s; }
    .sig-ws-row:hover { background: color-mix(in srgb, ${v('accent')} 4%, transparent); padding-left: 12px; padding-right: 12px; }
    .sig-ws-row:hover .sig-ws-arrow { color: ${v('accent')}; transform: translateX(4px); }
    .sig-ws-row:first-of-type { border-top: 1px solid ${v('line-hi')}; }
    .sig-ws-arrow { color: ${v('text-mute')}; font-size: 22px; transition: transform .2s, color .15s; justify-self: end; }
    .sig-ws-status { font-family: ${SIG_FONTS.mono}; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; padding: 6px 10px; border-radius: 2px; display: inline-block; text-align: center; }
    .sig-ws-status.live  { background: color-mix(in srgb, ${v('accent')}   16%, transparent); color: ${v('accent')};   border: 1px solid color-mix(in srgb, ${v('accent')}   30%, transparent); }
    .sig-ws-status.amber { background: color-mix(in srgb, ${v('accent-2')} 16%, transparent); color: ${v('accent-2')}; border: 1px solid color-mix(in srgb, ${v('accent-2')} 30%, transparent); }
    .sig-ws-status.mute  { background: transparent; color: ${v('text-mute')}; border: 1px solid ${v('line')}; }

    /* Marquee */
    @keyframes sig-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
    .sig-marquee { display: flex; gap: 56px; animation: sig-marquee 70s linear infinite; width: max-content; }

    /* Hide WebKit scrollbar for swipeable carousels */
    .gl-snap-scroll::-webkit-scrollbar { display: none; }

    /* ───────────────────────────────────────────────────────────
       Mobile overrides (≤ 760px)
       The JSX layout is fully forked via useIsMobile() — what
       lives here is the stuff that's too nested to branch:
         · global type scale
         · cluster.jsx 4-col node grid + 5-col aggregate strip
         · gallery section padding
         · sticky CTA chip size
       Use !important sparingly — only where inline styles fight us.
       ─────────────────────────────────────────────────────────── */
    @media (max-width: 760px) {
      .sig-h1      { font-size: 38px !important; line-height: 1.03 !important; letter-spacing: -0.025em !important; }
      .sig-h2      { font-size: 26px !important; line-height: 1.12 !important; }
      .sig-h3      { font-size: 18px !important; }
      .sig-display { font-size: 34px !important; line-height: 1.04 !important; }
      .sig-body    { font-size: 15px !important; line-height: 1.6 !important; }

      .sig-btn-primary, .sig-btn-ghost { padding: 13px 18px !important; font-size: 14px !important; width: 100%; justify-content: center; }

      /* Cluster — node grid 4-col → 1-col, aggregate strip 5-col → 2-col */
      .cl-node-grid { grid-template-columns: 1fr !important; gap: 10px !important; }
      .cl-stats     { grid-template-columns: 1fr 1fr !important; }
      .cl-stats > div { border-right: none !important; border-bottom: 1px solid var(--sig-line); }
      .cl-stats > div:nth-child(odd) { border-right: 1px solid var(--sig-line) !important; }
      .cl-stats > div:nth-last-child(-n+2) { border-bottom: none; }
      .cl-stats > div:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: none !important; }

      /* Marquee gap can be tighter */
      .sig-marquee { gap: 32px; }

      /* Workshop section padding */
      .sig-workshop > div { padding-left: 20px !important; padding-right: 20px !important; }

      /* Gallery section padding (set on the outer wrapper) */
      .gl-section { padding: 56px 20px 24px !important; }
      .gl-tile.row { flex-direction: column !important; gap: 28px !important; }
    }
  `;
  document.head.appendChild(s);
}

// ─── Data ──────────────────────────────────────────────────────

const SIG_PROJECTS = [
{ code: 'JTR', label: 'Product', realName: 'JTR Command Center', kind: 'Bespoke iPadOS · Field operations', disc: 'apple', ver: 'v3.4', status: 'live',
  blurb: 'A bespoke business operating system for a modern master craftsman. Native iPadOS, predictive CRM, integrated SMS, decade-scale archive. Shipping with the first cohort.',
  href: 'https://www.youtube.com/embed/uJaOHdDOrKM',
  cta: 'Watch the case film' },
{ code: 'ARCHITECT SCALER', label: 'Product', realName: 'Architect Scaler', kind: 'Precision tool · iOS · App Store', disc: 'apple', ver: 'v1.2', status: 'live',
  blurb: 'A precision scale calculator for working architects and structural planners. Pure SwiftUI. No analytics, no account, one purchase. Maintained quietly.',
  href: 'https://apps.apple.com/us/app/architectscaler/id6748638487',
  cta: 'View on App Store' }];


const SIG_TICKER = [
['JTR', 'v3.4 in production with first-cohort TestFlight'],
['ARCHITECT SCALER', 'maintained on the App Store · v1.2'],
['CLUSTER', 'four nodes · 1.3 TB unified memory · always running'],
['INDEX', 'further engagements held under non-disclosure'],
['—', 'engineered in-house · brief through to shipped product']];


const STATUS_LABEL = { live: 'Running', dev: 'In development', hold: 'Maintained', fab: 'In fabrication' };
const STATUS_TONE = { live: 'live', dev: 'amber', hold: 'mute', fab: 'amber' };

// ─── Project preview tiles (CSS/SVG fakes of real "live builds") ─

function PreviewJTR() {
  // JTR Command Center — inbound SMS being parsed into job records.
  return (
    <div style={{ position: 'absolute', inset: 0, background: v('tile-bg'), padding: '18px 22px', display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ width: 6, height: 6, borderRadius: '50%', background: v('accent') }} />
        <div className="sig-mono" style={{ fontSize: 10, color: v('text-dim'), letterSpacing: '0.14em' }}>JTR · INBOX · TUESDAY</div>
        <div style={{ flex: 1 }} />
        <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute') }}>3 new</div>
      </div>
      <div style={{ fontSize: 18, color: v('text'), letterSpacing: '-0.01em', fontWeight: 500 }}>5 jobs · 3 estimates · 2 invoices</div>
      {[
      ['Mercer · 555-0118', 'Want to confirm Friday roof job at 9am?', 'parsed → estimate'],
      ['Ridgeway · 555-0119', 'Send updated quote for the rear addition', 'parsed → quote'],
      ['Court St · 555-0120', 'Install going long, need two more hours', 'parsed → reschedule']].
      map((r, i) =>
      <div key={i} style={{ padding: '8px 0', borderBottom: `1px solid ${v('line')}` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 3 }}>
            <div className="sig-mono" style={{ fontSize: 10, color: v('text') }}>{r[0]}</div>
            <div className="sig-mono" style={{ fontSize: 9, color: v('accent'), letterSpacing: '0.06em' }}>{r[2]}</div>
          </div>
          <div style={{ fontSize: 11, color: v('text-dim'), lineHeight: 1.4 }}>{r[1]}</div>
        </div>
      )}
      <div style={{ flex: 1 }} />
      <div style={{ display: 'flex', gap: 6 }}>
        <div style={{ padding: '6px 10px', background: v('accent'), color: v('accent-ink'), fontSize: 11, fontWeight: 500, borderRadius: 2 }}>Open today</div>
        <div style={{ padding: '6px 10px', border: `1px solid ${v('line')}`, color: v('text-dim'), fontSize: 11, borderRadius: 2 }}>Search</div>
      </div>
    </div>);

}

function PreviewBasilisk() {
  return (
    <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse at 50% 40%, #1c1426 0%, #0a0612 70%)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div style={{ width: 130, height: 230, background: '#000', border: `1px solid ${v('line-hi')}`, borderRadius: 14, padding: 6, position: 'relative' }}>
        <div style={{ position: 'absolute', top: 6, left: '50%', transform: 'translateX(-50%)', width: 38, height: 6, background: '#000', zIndex: 2 }} />
        <div style={{ width: '100%', height: '100%', background: 'linear-gradient(180deg, #2a1f3d 0%, #5a3a7a 50%, #1a1226 100%)', borderRadius: 9, position: 'relative', overflow: 'hidden' }}>
          {[[20, 30], [80, 20], [110, 60], [40, 80], [95, 110], [15, 140], [70, 170], [105, 200]].map((p, i) =>
          <div key={i} style={{ position: 'absolute', left: p[0], top: p[1], width: 2, height: 2, background: '#fff', opacity: 0.7 }} />
          )}
          <div style={{ position: 'absolute', left: '50%', top: '58%', width: 18, height: 22, background: v('accent'), transform: 'translate(-50%,-50%)', clipPath: 'polygon(50% 0,100% 100%,50% 80%,0 100%)' }} />
          <div style={{ position: 'absolute', left: 30, top: 50, width: 14, height: 14, background: '#ff6a4a', borderRadius: '50%' }} />
          <div style={{ position: 'absolute', right: 18, top: 90, width: 10, height: 10, background: '#ff6a4a', borderRadius: '50%' }} />
          <div className="sig-mono" style={{ position: 'absolute', top: 12, left: 8, fontSize: 8, color: '#fff' }}>HP ████░</div>
          <div className="sig-mono" style={{ position: 'absolute', top: 12, right: 8, fontSize: 8, color: '#fff' }}>14 320</div>
          <div style={{ position: 'absolute', bottom: 14, left: 14, width: 36, height: 36, border: '1.5px solid rgba(255,255,255,.5)', borderRadius: '50%' }}>
            <div style={{ position: 'absolute', top: '50%', left: '50%', width: 16, height: 16, background: 'rgba(255,255,255,.4)', borderRadius: '50%', transform: 'translate(-50%,-50%)' }} />
          </div>
        </div>
      </div>
    </div>);

}

function PreviewArchitectScaler() {
  // Architect Scaler — iOS app shown as a light/screenshot-feel mockup.
  return (
    <div style={{ position: 'absolute', inset: 0, background: '#f4f1e8', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '14px' }}>
      <div style={{ width: '70%', height: '94%', background: '#fafaf6', border: '1px solid #d6cfbd', borderRadius: 18, padding: '18px 16px 14px', display: 'flex', flexDirection: 'column', fontFamily: SIG_FONTS.mono }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8, fontSize: 8, color: '#1a1814' }}>
          <span>14:02</span>
          <span style={{ letterSpacing: '0.06em' }}>•••</span>
        </div>
        <div style={{ fontSize: 9, color: '#7a7466', letterSpacing: '0.2em', textTransform: 'uppercase' }}>Scale&nbsp;&nbsp;1 : 50</div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 14, fontFamily: "'Instrument Serif', serif" }}>
          <span style={{ fontSize: 48, color: '#1a1814', lineHeight: 1, letterSpacing: '-0.02em', fontWeight: 400 }}>14.6</span>
          <span style={{ fontSize: 16, color: '#8a8576' }}>m</span>
        </div>
        <div style={{ fontSize: 10, color: '#7a7466', marginTop: 4, fontStyle: 'italic', fontFamily: "'Instrument Serif', serif" }}>on plan</div>
        <div style={{ flex: 1 }} />
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 5, marginBottom: 10 }}>
          {['7', '8', '9', '4', '5', '6', '1', '2', '3', '.', '0', '='].
          map((k, i) =>
          <div key={i} style={{
            background: i === 11 ? '#1a1814' : '#eee9dd',
            color: i === 11 ? '#fafaf6' : '#1a1814',
            textAlign: 'center', padding: '7px 0', fontSize: 10, borderRadius: 3
          }}>{k}</div>
          )}
        </div>
        <div style={{ height: 1, background: '#1a1814' }} />
        <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 3, fontSize: 7, color: '#7a7466' }}>
          {[0, 1, 2, 3, 4, 5].map((i) => <span key={i}>{i}m</span>)}
        </div>
      </div>
    </div>);

}

function PreviewHallway() {
  return (
    <div style={{ position: 'absolute', inset: 0, background: v('tile-bg'), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <svg viewBox="0 0 320 240" width="86%" height="86%" style={{ overflow: 'visible' }}>
        <defs>
          <linearGradient id="pcbg" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#1d4a2a" />
            <stop offset="1" stopColor="#0f2a18" />
          </linearGradient>
        </defs>
        <g transform="translate(160,130) skewX(-30) scale(1,0.55)">
          <rect x="-110" y="-80" width="220" height="160" fill="url(#pcbg)" stroke="#2d6b3a" strokeWidth="1.5" />
          {[-60, -30, 0, 30, 60].map((y) =>
          <line key={y} x1="-100" y1={y} x2="100" y2={y} stroke="var(--sig-accent)" strokeWidth="0.6" opacity="0.55" />
          )}
          {[-90, -50, -10, 30, 70].map((x) =>
          <line key={x} x1={x} y1="-70" x2={x} y2="70" stroke="var(--sig-accent)" strokeWidth="0.6" opacity="0.4" />
          )}
          <rect x="-40" y="-30" width="50" height="36" fill="var(--sig-bg)" stroke="#7a8a55" />
          <rect x="30" y="20" width="32" height="22" fill="var(--sig-bg)" stroke="#7a8a55" />
          <rect x="-90" y="40" width="20" height="28" fill="var(--sig-bg)" stroke="#7a8a55" />
          <rect x="-110" y="-10" width="14" height="22" fill="#2a2a2a" stroke="#888" />
          {Array.from({ length: 12 }).map((_, i) =>
          <rect key={i} x={-100 + i * 18} y="78" width="6" height="6" fill="var(--sig-tile-bg)" stroke="#2d6b3a" />
          )}
        </g>
        <text x="20" y="220" fill="var(--sig-text-dim)" fontFamily={SIG_FONTS.mono} fontSize="10">HALLWAY · rev D · 4-layer · 64 × 38 mm</text>
      </svg>
    </div>);

}

function PreviewPinefall() {
  return (
    <div style={{ position: 'absolute', inset: 0, background: v('tile-bg'), padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div className="sig-mono" style={{ fontSize: 10, color: v('text-dim'), letterSpacing: '0.14em' }}>UNIT-07 · LIVE · 41ms</div>
        <div className="sig-mono" style={{ fontSize: 10, color: v('accent') }}>● 6 nodes</div>
      </div>
      <div style={{ height: 90, background: 'linear-gradient(135deg, rgba(0,0,0,0.25) 0%, rgba(255,255,255,0.04) 100%)', border: `1px solid ${v('line')}`, position: 'relative', overflow: 'hidden' }}>
        <svg viewBox="0 0 200 90" width="100%" height="100%" preserveAspectRatio="none">
          <path d="M0,70 L40,55 L80,60 L120,40 L160,45 L200,30 L200,90 L0,90 Z" fill="rgba(255,255,255,0.05)" />
          <circle cx="120" cy="40" r="3" fill="var(--sig-accent)" />
        </svg>
        <div className="sig-mono" style={{ position: 'absolute', bottom: 6, left: 8, fontSize: 9, color: v('text') }}>FRONT_CAM · 30fps</div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6 }}>
        {[['BATT', '78%', 'accent'], ['TEMP', '41°C', 'accent-2'], ['CPU', '24%', 'text-dim']].map(([l, val, colorKey], i) =>
        <div key={i} style={{ background: v('surface'), border: `1px solid ${v('line')}`, padding: '6px 8px' }}>
            <div className="sig-mono" style={{ fontSize: 8, color: v('text-mute') }}>{l}</div>
            <div className="sig-mono" style={{ fontSize: 14, color: v(colorKey), marginTop: 2 }}>{val}</div>
            <svg viewBox="0 0 60 14" width="100%" height="12">
              <polyline points="0,8 8,6 16,9 24,5 32,7 40,4 48,6 60,3" fill="none" stroke={`var(--sig-${colorKey})`} strokeWidth="1" opacity="0.7" />
            </svg>
          </div>
        )}
      </div>
      <div style={{ flex: 1 }} />
      <div className="sig-mono" style={{ fontSize: 9, color: v('text-mute') }}>WAYPOINT 04/12 · ETA 03:42 · MODE: AUTONOMOUS</div>
    </div>);

}

function PreviewVesper() {
  return (
    <div style={{ position: 'absolute', inset: 0, background: v('panel-bg'), padding: '14px 18px', display: 'flex', gap: 10 }}>
      <div style={{ width: '42%', display: 'flex', flexDirection: 'column', gap: 6 }}>
        <div className="sig-mono" style={{ fontSize: 9, color: v('text-mute'), letterSpacing: '0.14em' }}>NOTE · 14 sources</div>
        <div style={{ fontSize: 11, color: v('text'), lineHeight: 1.6 }}>
          On-device inference unlocks a new class of <span style={{ background: `color-mix(in srgb, ${v('accent')} 20%, transparent)`, color: v('accent'), padding: '0 2px' }}>privacy-first</span> product surfaces, where the model never leaves the user's…
        </div>
        <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', marginTop: 4 }}>
          {['[01]', '[02]', '[03]', '[07]', '[09]'].map((c) =>
          <span key={c} className="sig-mono" style={{ fontSize: 9, color: v('accent'), border: `1px solid ${v('line')}`, padding: '1px 4px' }}>{c}</span>
          )}
        </div>
      </div>
      <div style={{ flex: 1, position: 'relative', background: v('tile-bg'), border: `1px solid ${v('line')}` }}>
        {[[40, 30, 'A'], [110, 50, 'B'], [80, 90, 'C'], [150, 80, 'D'], [60, 140, 'E'], [130, 140, 'F'], [180, 40, 'G']].map(([x, y, l], i) =>
        <React.Fragment key={i}>
            <div style={{ position: 'absolute', left: x, top: y, width: 18, height: 18, borderRadius: '50%', background: i === 2 ? v('accent') : v('surface'), border: `1px solid ${i === 2 ? v('accent') : v('line-hi')}`, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 8, color: i === 2 ? v('accent-ink') : v('text-dim'), fontFamily: SIG_FONTS.mono }}>{l}</div>
          </React.Fragment>
        )}
        <svg style={{ position: 'absolute', inset: 0 }} width="100%" height="100%">
          <line x1="49" y1="39" x2="119" y2="59" stroke="var(--sig-line)" />
          <line x1="89" y1="99" x2="119" y2="59" stroke="var(--sig-line)" />
          <line x1="89" y1="99" x2="159" y2="89" stroke="var(--sig-accent)" strokeOpacity="0.6" />
          <line x1="69" y1="149" x2="89" y2="99" stroke="var(--sig-line)" />
          <line x1="139" y1="149" x2="159" y2="89" stroke="var(--sig-line)" />
          <line x1="189" y1="49" x2="159" y2="89" stroke="var(--sig-line)" />
        </svg>
      </div>
    </div>);

}

const SIG_PREVIEW_BY_CODE = {
  'JTR': PreviewJTR,
  'ARCHITECT SCALER': PreviewArchitectScaler,
  BASILISK: PreviewBasilisk,
  HALLWAY: PreviewHallway,
  PINEFALL: PreviewPinefall,
  VESPER: PreviewVesper
};

// ─── Sections ──────────────────────────────────────────────────

function Logo({ size = 32 }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <img src="assets/ghostlabs-orb.png" alt="" width={size} height={size}
      style={{ display: 'block', filter: 'brightness(1.15) contrast(1.1)', width: `${size}px`, height: `${size}px` }} />
      <div style={{ fontWeight: 600, letterSpacing: '0.08em', fontSize: 13, color: v('text') }}>GHOSTLABS</div>
    </div>);

}

const NAV_LINKS = [
['Workshop', 'workshop'],
['Work', 'work'],
['Store', 'store'],
['Disciplines', 'disciplines'],
['Practice', 'practice'],
['Brief', 'brief']];


function SignalNav() {
  const isMobile = useIsMobile();
  const [open, setOpen] = React.useState(false);
  const [activeId, setActiveId] = React.useState('hero');

  // Close drawer if viewport flips back to desktop
  React.useEffect(() => {if (!isMobile) setOpen(false);}, [isMobile]);

  // Lock body scroll while drawer is open
  React.useEffect(() => {
    if (!open) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {document.body.style.overflow = prev;};
  }, [open]);

  // Track which section is currently in view so the drawer can light it up.
  // Uses scrollY against each section's top — cheaper than IntersectionObserver
  // and behaves predictably with our sticky nav.
  React.useEffect(() => {
    if (!isMobile) return;
    const ids = ['hero', ...NAV_LINKS.map(([, id]) => id)];
    const onScroll = () => {
      const y = window.scrollY + window.innerHeight * 0.35; // probe 35% from viewport top
      let current = ids[0];
      for (const id of ids) {
        const el = document.getElementById(id);
        if (!el) continue;
        if (el.offsetTop <= y) current = id;
      }
      setActiveId(current);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, [isMobile]);

  if (isMobile) {
    return (
      <React.Fragment>
        <div style={{
          display: 'flex', alignItems: 'center', padding: '16px 20px',
          borderBottom: `1px solid ${v('line')}`, gap: 12,
          position: 'sticky', top: 0, background: v('bg'), zIndex: 60
        }}>
          <a href="#hero" onClick={(e) => {e.preventDefault();smoothScrollTo('hero');setOpen(false);}} style={{ textDecoration: 'none', cursor: 'pointer' }}>
            <Logo size={28} />
          </a>
          <div style={{ flex: 1 }} />
          <div className="sig-pill" style={{ fontSize: 10, padding: '5px 10px 5px 8px' }}><span className="sig-dot live" />2026</div>
          <button
            type="button"
            aria-label={open ? 'Close menu' : 'Open menu'}
            aria-expanded={open}
            onClick={() => setOpen((o) => !o)}
            style={{
              width: 40, height: 40, border: `1px solid ${v('line-hi')}`,
              background: 'transparent', cursor: 'pointer', borderRadius: 2,
              display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 5
            }}>
            
            <span style={{ width: 16, height: 1.5, background: v('text'), transition: 'transform .2s', transform: open ? 'translateY(3.5px) rotate(45deg)' : 'none' }} />
            <span style={{ width: 16, height: 1.5, background: v('text'), transition: 'transform .2s', transform: open ? 'translateY(-3px) rotate(-45deg)' : 'none' }} />
          </button>
        </div>

        {/* Drawer */}
        <div
          role="dialog"
          aria-hidden={!open}
          style={{
            position: 'fixed', inset: 0, zIndex: 55,
            background: v('bg'),
            opacity: open ? 1 : 0,
            pointerEvents: open ? 'auto' : 'none',
            transition: 'opacity .2s ease',
            padding: '88px 24px 32px',
            display: 'flex', flexDirection: 'column', gap: 4
          }}>
          
          {NAV_LINKS.map(([l, id]) => {
            const isActive = activeId === id;
            return (
              <a
                key={l}
                href={`#${id}`}
                onClick={(e) => {e.preventDefault();setOpen(false);setTimeout(() => smoothScrollTo(id), 80);}}
                style={{
                  padding: '20px 4px', borderBottom: `1px solid ${v('line')}`,
                  fontFamily: SIG_FONTS.sans, fontWeight: 500, fontSize: 28,
                  color: isActive ? v('accent') : v('text'), textDecoration: 'none', letterSpacing: '-0.02em',
                  display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                  transition: 'color .15s'
                }}>
                
                <span style={{ display: 'flex', alignItems: 'baseline', gap: 14 }}>
                  {isActive && <span style={{ width: 6, height: 6, borderRadius: '50%', background: v('accent'), display: 'inline-block', alignSelf: 'center' }} />}
                  {l}
                </span>
                <span style={{ fontFamily: SIG_FONTS.mono, fontSize: 11, color: isActive ? v('accent') : v('text-mute'), letterSpacing: '0.14em' }}>
                  0{NAV_LINKS.findIndex(([, x]) => x === id) + 1}
                </span>
              </a>);

          })}
          <div style={{ flex: 1 }} />
          <a
            href="mailto:ghostlabsoftware@gmail.com"
            className="sig-mono"
            style={{ fontSize: 12, color: v('text-dim'), textDecoration: 'none', marginTop: 24 }}>
            ghostlabsoftware@gmail.com</a>
          <div className="sig-mono" style={{ fontSize: 11, color: v('text-mute'), letterSpacing: '0.08em', marginTop: 4 }}>● Accepting briefs · 2026</div>
        </div>
      </React.Fragment>);

  }

  return (
    <div style={{ display: 'flex', alignItems: 'center', padding: '24px 56px', borderBottom: `1px solid ${v('line')}`, gap: 32, position: 'sticky', top: 0, background: v('bg'), zIndex: 10 }}>
      <a href="#hero" onClick={(e) => {e.preventDefault();smoothScrollTo('hero');}} style={{ textDecoration: 'none', cursor: 'pointer' }}>
        <Logo size={36} />
      </a>
      <div style={{ flex: 1 }} />
      <div style={{ display: 'flex', gap: 32 }}>
        {NAV_LINKS.map(([l, id]) =>
        <a key={l} href={`#${id}`} onClick={(e) => {e.preventDefault();smoothScrollTo(id);}} className="sig-mono" style={{ fontSize: 12, color: v('text-dim'), textDecoration: 'none', letterSpacing: '0.06em', textTransform: 'uppercase', cursor: 'pointer' }}>{l}</a>
        )}
      </div>
      <div className="sig-pill"><span className="sig-dot live" />Accepting requests · 2026</div>
    </div>);

}

function SignalHero() {
  const isMobile = useIsMobile();
  if (isMobile) {
    return (
      <div id="hero" style={{ padding: '48px 20px 56px', borderBottom: `1px solid ${v('line')}` }}>
        <div className="sig-eyebrow" style={{ marginBottom: 22 }}>◇ INDEPENDENT ENGINEERING</div>
        <h1 className="sig-h1">
          Bespoke software, intelligence, and systems — <span style={{ color: v('accent') }}>engineered end-to-end.</span>
        </h1>
        <p className="sig-body" style={{ marginTop: 24 }}>
          GhostLabs designs and builds custom solutions for businesses that need a system made for them. Native applications, AI systems, games, robotics, and custom hardware — taken from brief through to shipped product.
        </p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 32 }}>
          <button className="sig-btn-primary" onClick={() => smoothScrollTo('brief')}>Send a brief <span style={{ fontSize: 16, lineHeight: 1 }}>→</span></button>
          <button className="sig-btn-ghost" onClick={() => smoothScrollTo('work')}>See the work</button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 24, marginTop: 48, paddingTop: 24, borderTop: `1px solid ${v('line')}` }}>
          {[
          ['End-to-end', 'Brief through to shipped product. No subcontractors, no relays.'],
          ['Cross-discipline', 'Software, intelligence, and hardware engineered in one team.'],
          ['Confidential', 'Most engagements stay private. Your work belongs to your business.']].
          map(([h, b]) =>
          <div key={h}>
              <div className="sig-label">{h}</div>
              <div style={{ fontSize: 14, color: v('text-dim'), marginTop: 8, lineHeight: 1.6 }}>{b}</div>
            </div>
          )}
        </div>
      </div>);

  }
  return (
    <div id="hero" style={{ padding: '112px 56px 96px', borderBottom: `1px solid ${v('line')}`, maxWidth: 1400, margin: '0 auto' }}>
      <div className="sig-eyebrow" style={{ marginBottom: 36 }}>◇ AN INDEPENDENT ENGINEERING FIRM</div>
      <h1 className="sig-h1" style={{ maxWidth: 1100 }}>
        Bespoke software,&nbsp;intelligence,<br />and systems — <span style={{ color: v('accent') }}>engineered end-to-end.</span>
      </h1>
      <p className="sig-body" style={{ maxWidth: 680, marginTop: 36, fontSize: 20 }}>GhostLabs designs and builds custom solutions for businesses that need a system made for them, not adapted from a template. Native applications, AI systems, games, robotics, custom hardware and more — taken from initial concept through to shipped product.

      </p>
      <div style={{ display: 'flex', gap: 12, marginTop: 44 }}>
        <button className="sig-btn-primary" onClick={() => smoothScrollTo('brief')}>Send a brief <span style={{ fontSize: 18, lineHeight: 1 }}>→</span></button>
        <button className="sig-btn-ghost" onClick={() => smoothScrollTo('work')}>See the work</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 56, marginTop: 88, paddingTop: 32, borderTop: `1px solid ${v('line')}`, maxWidth: 1100 }}>
        {[
        ['End-to-end', 'Brief through to shipped product. No subcontractors, no relays.'],
        ['Cross-discipline', 'Software, intelligence, and hardware engineered in one team.'],
        ['Confidential', 'Most engagements stay private. Your work belongs to your business.']].
        map(([h, b]) =>
        <div key={h}>
            <div className="sig-label">{h}</div>
            <div style={{ fontSize: 14, color: v('text-dim'), marginTop: 12, lineHeight: 1.6, maxWidth: 300 }}>{b}</div>
          </div>
        )}
      </div>
    </div>);

}

// ─── The promoted Workshop section ────────────────────────────
// Live simulation of our Mac Studio inference cluster.

function SignalWorkshop() {
  const isMobile = useIsMobile();
  const [expanded, setExpanded] = React.useState(false);

  if (isMobile) {
    return (
      <div id="workshop" className="sig-workshop">
        <div style={{ padding: '40px 20px 20px' }}>
          <div className="sig-eyebrow" style={{ marginBottom: 14 }}>
            <span style={{ color: v('accent') }}>●</span>&nbsp;&nbsp;LIVE · CLUSTER
          </div>
          <h2 className="sig-display" style={{ marginBottom: 14 }}>
            Four Mac Studios.<br />
            <span style={{ color: v('text-dim') }}>Always running.</span>
          </h2>
          <div className="sig-mono" style={{ fontSize: 12, color: v('text-dim'), lineHeight: 1.6, marginBottom: 18 }}>
            Our inference cluster runs research, benchmarks, 3D design and the nightly builds behind every active project.
          </div>

          {/* Summary card — quick at-a-glance stats + expand toggle */}
          <button
            type="button"
            onClick={() => setExpanded((x) => !x)}
            aria-expanded={expanded}
            style={{
              width: '100%', textAlign: 'left',
              background: v('surface'),
              border: `1px solid ${v('line-hi')}`,
              padding: '16px 18px',
              fontFamily: SIG_FONTS.mono,
              color: v('text'), cursor: 'pointer',
              display: 'flex', flexDirection: 'column', gap: 10
            }}>
            
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span className="sig-dot-pulse" style={{ width: 8, height: 8 }} />
                <span style={{ fontSize: 11, letterSpacing: '0.14em', color: v('text-dim') }}>4 NODES · LIVE</span>
              </div>
              <span style={{
                fontSize: 16, color: v('accent'),
                transition: 'transform .2s ease',
                transform: expanded ? 'rotate(180deg)' : 'rotate(0deg)'
              }}>▾</span>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8 }}>
              {[['1.3 TB', 'memory'], ['M3 Ultra', 'silicon'], ['24 / 7', 'uptime']].map(([val, lbl]) =>
              <div key={lbl}>
                  <div style={{ fontSize: 14, color: v('text'), letterSpacing: '-0.01em', fontWeight: 500, lineHeight: 1 }}>{val}</div>
                  <div style={{ fontSize: 9, color: v('text-mute'), letterSpacing: '0.14em', textTransform: 'uppercase', marginTop: 4 }}>{lbl}</div>
                </div>
              )}
            </div>
            <div style={{ fontSize: 11, color: v('text-mute'), letterSpacing: '0.04em', marginTop: 2 }}>
              {expanded ? 'Tap to collapse' : 'Tap to expand live monitor →'}
            </div>
          </button>
        </div>

        {/* Expanded cluster — only mount the live simulation when expanded
                 so the page stays light on first paint. */}
        {expanded &&
        <div style={{ padding: '0 20px 32px' }}>
            {window.SignalCluster ? <window.SignalCluster /> :
          <div style={{ padding: 24, border: `1px dashed ${v('line')}`, color: v('text-dim'), fontFamily: SIG_FONTS.mono, fontSize: 12 }}>cluster.jsx not loaded</div>
          }
          </div>
        }

        <div style={{ padding: '20px', borderTop: `1px solid ${v('line')}`, display: 'flex', flexDirection: 'column', gap: 12 }}>
          <a href="#brief" onClick={(e) => {e.preventDefault();smoothScrollTo('brief');}} className="sig-link sig-mono" style={{ fontSize: 12, cursor: 'pointer' }}>Request introduction →</a>
        </div>
      </div>);

  }
  return (
    <div id="workshop" className="sig-workshop">
      <div style={{ padding: '112px 56px 24px', maxWidth: 1400, margin: '0 auto' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 48, alignItems: 'end', marginBottom: 56 }}>
          <div>
            <div className="sig-eyebrow" style={{ marginBottom: 20 }}>
              <span style={{ color: v('accent') }}>●</span>&nbsp;&nbsp;LIVE · PRODUCTION CLUSTER
            </div>
            <h2 className="sig-display" style={{ maxWidth: 920 }}>
              Four Mac Studios.<br />
              <span style={{ color: v('text-dim') }}>Always running.</span>
            </h2>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div className="sig-label" style={{ marginBottom: 10 }}>Sampled live</div>
            <div className="sig-mono" style={{ fontSize: 12, color: v('text-dim'), maxWidth: 300, lineHeight: 1.6, textAlign: 'right' }}>Our inference cluster runs research, benchmarks, 3D design and the nightly builds behind every active project. The log below is sanitized for public surfacing.

            </div>
          </div>
        </div>
      </div>

      <div style={{ maxWidth: 1400, margin: '0 auto', padding: '0 56px 56px' }}>
        {window.SignalCluster ? <window.SignalCluster /> :
        <div style={{ padding: '40px', border: `1px dashed ${v('line')}`, color: v('text-dim'), fontFamily: SIG_FONTS.mono, fontSize: 12 }}>
            cluster.jsx not loaded
          </div>
        }
      </div>

      <div style={{ maxWidth: 1400, margin: '0 auto', padding: '40px 56px 112px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderTop: `1px solid ${v('line')}` }}>
        <div className="sig-mono" style={{ fontSize: 11, color: v('text-mute'), letterSpacing: '0.04em', maxWidth: 680 }}>
          Project-tagged log lines reference public-cleared workloads. Production traffic for client engagements is fully anonymized before surfacing.
        </div>
        <a href="#brief" onClick={(e) => {e.preventDefault();smoothScrollTo('brief');}} className="sig-link sig-mono" style={{ fontSize: 12, whiteSpace: 'nowrap', cursor: 'pointer' }}>Request introduction →</a>
      </div>
    </div>);

}

function SignalTicker() {
  const items = [...SIG_TICKER, ...SIG_TICKER];
  return (
    <div style={{ borderBottom: `1px solid ${v('line')}`, padding: '16px 0', overflow: 'hidden', background: v('bg') }}>
      <div className="sig-marquee">
        {items.map((it, i) =>
        <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14, fontFamily: SIG_FONTS.mono, fontSize: 12, color: v('text-dim'), whiteSpace: 'nowrap' }}>
            <span className="sig-dot live" />
            <span style={{ color: v('text'), letterSpacing: '0.02em' }}>{it[0]}</span>
            <span>{it[1]}</span>
            <span style={{ color: v('text-mute'), marginLeft: 14 }}>━━</span>
          </div>
        )}
      </div>
    </div>);

}

function SignalGallery() {
  // Delegate to the device-frame gallery (gallery.jsx). We pass the layout via
  // a CSS custom property on the body so it can be controlled from a tweak;
  // the layout itself is selected by the parent (SignalPage) and forwarded.
  return null; // — unused, real gallery rendered in SignalPage via window.SignalGalleryV2
}

function SignalDisciplines() {
  const isMobile = useIsMobile();
  const rows = [
  ['Apple-Native', 'Swift · SwiftUI · CoreData · CoreML · CarPlay · visionOS'],
  ['Games', 'Godot · Unity · WebGL · iOS · Android'],
  ['AI Systems', 'On-device inference · agents · domain-tuned models'],
  ['Robotics', 'ROS · WebRTC · remote-operations consoles'],
  ['Hardware', 'PCB design · CAD · 3D-print · short-run fabrication'],
  ['Web & Research', 'Local-first tools · realtime systems · internal platforms']];

  if (isMobile) {
    return (
      <div id="disciplines" style={{ padding: '40px 20px 56px', borderTop: `1px solid ${v('line')}` }}>
        <div className="sig-eyebrow" style={{ marginBottom: 22 }}>◇ Disciplines we practice</div>
        <div style={{ border: `1px solid ${v('line')}` }}>
          {rows.map((r, i) =>
          <div key={r[0]} style={{ padding: '22px 18px', borderTop: i === 0 ? 'none' : `1px solid ${v('line')}` }}>
              <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.14em' }}>0{i + 1}</div>
              <div style={{ fontSize: 20, color: v('text'), fontWeight: 500, marginTop: 8, letterSpacing: '-0.02em' }}>{r[0]}</div>
              <div style={{ fontSize: 13, color: v('text-dim'), marginTop: 6, lineHeight: 1.55 }}>{r[1]}</div>
            </div>
          )}
        </div>
        <div style={{ marginTop: 20, fontSize: 14, color: v('text-dim'), lineHeight: 1.6 }}>
          Most engagements draw on two or three of these in combination. The boundary between an application, the intelligence inside it, and the hardware it runs on is something we'd rather not hand off between studios.
        </div>
      </div>);

  }
  return (
    <div id="disciplines" style={{ padding: '56px 56px 112px', borderTop: `1px solid ${v('line')}`, maxWidth: 1400, margin: '0 auto' }}>
      <div className="sig-eyebrow" style={{ marginBottom: 28 }}>◇ Disciplines we practice</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 0, border: `1px solid ${v('line')}` }}>
        {rows.map((r, i) =>
        <div key={r[0]} style={{ padding: '28px 24px', borderRight: i % 3 !== 2 ? `1px solid ${v('line')}` : 'none', borderBottom: i < 3 ? `1px solid ${v('line')}` : 'none' }}>
            <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.14em' }}>0{i + 1}</div>
            <div style={{ fontSize: 24, color: v('text'), fontWeight: 500, marginTop: 10, letterSpacing: '-0.02em' }}>{r[0]}</div>
            <div style={{ fontSize: 13, color: v('text-dim'), marginTop: 8, lineHeight: 1.55 }}>{r[1]}</div>
          </div>
        )}
      </div>
      <div style={{ marginTop: 28, fontSize: 14, color: v('text-dim'), maxWidth: 680, lineHeight: 1.6 }}>
        Most engagements draw on two or three of these in combination. The boundary between an application, the intelligence inside it, and the hardware it runs on is something we'd rather not hand off between studios.
      </div>
    </div>);

}

function SignalPractice() {
  const isMobile = useIsMobile();
  const tenets = [
  ['We commit to finished work, not deliverables.',
  'An engagement ends when something works in production for the people who commissioned it, not when a milestone is marked complete on a project plan.'],
  ['Most of what we build stays private.',
  'Client repositories never appear in this gallery. What you see surfaced here is internal research, our own tools, and the work we are explicitly cleared to show.'],
  ['Direct contact with the people writing the code.',
  'No account managers, no relay through project leads. The engineers who read your brief are the engineers who ship the result.'],
  ['We say no when we should.',
  'We work on a small number of projects at a time. If a brief sits outside our practice, or the timing isn\'t right for either side, we say so on the first call.']];

  if (isMobile) {
    return (
      <div id="practice" style={{ padding: '48px 20px', background: v('panel-bg'), borderTop: `1px solid ${v('line')}`, borderBottom: `1px solid ${v('line')}` }}>
        <div className="sig-eyebrow" style={{ marginBottom: 14 }}>◇ How we practise</div>
        <h2 className="sig-h2" style={{ marginBottom: 24 }}>Four commitments we make to every engagement.</h2>
        <div>
          {tenets.map((t, i) =>
          <MobileAccordion
            key={i}
            index={i}
            eyebrow={String(i + 1).padStart(2, '0')}
            title={t[0]}
            body={t[1]}
            defaultOpen={i === 0} />

          )}
          {/* Trailing border to close the accordion stack visually */}
          <div style={{ borderTop: `1px solid ${v('line')}` }} />
        </div>
      </div>);

  }
  return (
    <div id="practice" style={{ padding: '112px 56px', background: v('panel-bg'), borderTop: `1px solid ${v('line')}`, borderBottom: `1px solid ${v('line')}` }}>
      <div style={{ maxWidth: 1400, margin: '0 auto' }}>
        <div className="sig-eyebrow" style={{ marginBottom: 24 }}>◇ How we practise</div>
        <h2 className="sig-h2" style={{ maxWidth: 780, marginBottom: 56 }}>Four commitments we make to every engagement.</h2>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '56px 72px' }}>
          {tenets.map((t, i) =>
          <div key={i} style={{ borderTop: `1px solid ${v('line')}`, paddingTop: 26 }}>
              <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.14em', marginBottom: 14 }}>{String(i + 1).padStart(2, '0')}</div>
              <h3 className="sig-h3" style={{ marginBottom: 14 }}>{t[0]}</h3>
              <p style={{ fontSize: 15, color: v('text-dim'), lineHeight: 1.65, margin: 0 }}>{t[1]}</p>
            </div>
          )}
        </div>
      </div>
    </div>);

}

function SignalEngagement() {
  const isMobile = useIsMobile();
  const phases = [
  ['01 / Brief',
  'A short letter describing what you are trying to build. We reply within a working day, either with a call slot or a clear note explaining why we are not the right studio for the work.'],
  ['02 / Discovery',
  'A first call, followed by a written response: our reading of the problem, a sketch of the approach, and a fixed scope and cost for the first phase. No verbal estimates.'],
  ['03 / Build',
  'Direct, frequent contact through whichever channel you prefer. Working builds shared at the end of every short cycle. No status decks, no theatre.'],
  ['04 / Ship',
  'Into production, with the artifacts you need to extend it. We hold the build after launch — most engagements continue into a second phase.']];

  if (isMobile) {
    return (
      <div style={{ padding: '48px 20px', borderBottom: `1px solid ${v('line')}` }}>
        <div className="sig-eyebrow" style={{ marginBottom: 14 }}>◇ What working with us looks like</div>
        <h2 className="sig-h2" style={{ marginBottom: 14 }}>Four phases. One team from first letter to production.</h2>
        <p className="sig-body" style={{ marginBottom: 24 }}>
          Most engagements run between six weeks and six months. We scope and price each phase explicitly before it begins.
        </p>
        <div>
          {phases.map((p, i) => {
            // p[0] is "01 / Brief" — split for eyebrow + title styling
            const [num, name] = p[0].split(' / ');
            return (
              <MobileAccordion
                key={i}
                index={i}
                eyebrow={num}
                title={name}
                body={p[1]}
                defaultOpen={i === 0} />);


          })}
          <div style={{ borderTop: `1px solid ${v('line')}` }} />
        </div>
      </div>);

  }
  return (
    <div style={{ padding: '120px 56px', borderBottom: `1px solid ${v('line')}`, maxWidth: 1400, margin: '0 auto' }}>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 80 }}>
        <div>
          <div className="sig-eyebrow" style={{ marginBottom: 24 }}>◇ What working with us looks like</div>
          <h2 className="sig-h2" style={{ marginBottom: 24 }}>Four phases. One team from first letter to production.</h2>
          <p className="sig-body" style={{ maxWidth: 420 }}>
            Most engagements run between six weeks and six months. We scope and price each phase explicitly before it begins, and you are free to stop at the end of any phase without renewing.
          </p>
        </div>
        <div>
          {phases.map((p, i) =>
          <div key={i} style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: 32, padding: '28px 0', borderTop: i === 0 ? `1px solid ${v('line-hi')}` : `1px solid ${v('line')}`, alignItems: 'baseline' }}>
              <div className="sig-mono" style={{ fontSize: 13, color: v('accent'), letterSpacing: '0.08em' }}>{p[0]}</div>
              <div style={{ fontSize: 15, color: v('text-dim'), lineHeight: 1.65 }}>{p[1]}</div>
            </div>
          )}
        </div>
      </div>
    </div>);

}

function SignalBrief() {
  const [businessName, setBusinessName] = React.useState('');
  const [discipline, setDiscipline] = React.useState('Apple');
  const [timing, setTiming] = React.useState('6–12 weeks');
  const [description, setDescription] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [submitted, setSubmitted] = React.useState(false);
  const [error, setError] = React.useState(null);

  const DISCIPLINES = ['Apple', 'Games', 'AI', 'Robotics', 'HW', 'Web'];
  const TIMINGS = ['< 6 weeks', '6–12 weeks', '3–6 months', '6 months +'];

  const buildPayload = () => ({ businessName, discipline, timing, description, email, submittedAt: new Date().toISOString() });

  const mailtoFallback = () => {
    const subject = `New brief · ${businessName || 'untitled'}`;
    const body = [
    `Business or project: ${businessName || '—'}`,
    `Discipline:          ${discipline}`,
    `First-phase timing:  ${timing}`,
    ``,
    `What I am trying to build:`,
    description || '—',
    ``,
    `Reach me at: ${email}`].
    join('\n');
    window.location.href = `mailto:${BRIEF_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError(null);
    if (!email.trim() || !description.trim()) {
      setError('Please include an email and a short description.');
      return;
    }
    if (!BRIEF_ENDPOINT) {
      // No endpoint configured yet — hand off to the user's email client.
      mailtoFallback();
      setSubmitted(true);
      return;
    }
    setSubmitting(true);
    try {
      const res = await fetch(BRIEF_ENDPOINT, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(buildPayload())
      });
      if (!res.ok) throw new Error('endpoint returned ' + res.status);
      setSubmitted(true);
    } catch (err) {
      setError("Couldn't reach the server. We've opened your email client as a fallback.");
      mailtoFallback();
    } finally {
      setSubmitting(false);
    }
  };

  const isMobile = useIsMobile();
  return (
    <div id="brief" style={isMobile ?
    { padding: '56px 20px', display: 'flex', flexDirection: 'column', gap: 40 } :
    { padding: '128px 56px', display: 'grid', gridTemplateColumns: '0.9fr 1.1fr', gap: 80, maxWidth: 1400, margin: '0 auto' }
    }>
      <div>
        <div className="sig-eyebrow" style={{ marginBottom: 24 }}>◇ Send a brief</div>
        <h2 className="sig-h2" style={{ marginBottom: 24 }}>Tell us what you're trying to build.</h2>
        <p className="sig-body" style={{ maxWidth: 440, fontSize: isMobile ? 15 : 17 }}>We read every brief within a working day and reply with either a call slot or a short note explaining how we can help you build a custom solution for your needs. We provide you a free technical demo to decide a direction before we commit to production.
        </p>
        <div style={{ marginTop: isMobile ? 32 : 48, paddingTop: 24, borderTop: `1px solid ${v('line')}`, display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div><span className="sig-label">Direct email</span><div className="sig-mono" style={{ color: v('text'), fontSize: 14, marginTop: 4, wordBreak: 'break-all' }}>{BRIEF_EMAIL}</div></div>
          <div><span className="sig-label">Response window</span><div className="sig-mono" style={{ color: v('text'), fontSize: 14, marginTop: 4 }}>Within one working day</div></div>
          <div><span className="sig-label">Currently</span><div className="sig-mono" style={{ color: v('accent'), fontSize: 14, marginTop: 4 }}>● Accepting briefs for 2026</div></div>
        </div>
      </div>
      <div className="sig-card" style={{ padding: isMobile ? 24 : 40 }}>
        {submitted ?
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minHeight: 360, justifyContent: 'center' }}>
            <div className="sig-eyebrow" style={{ color: v('accent') }}>● Brief received</div>
            <h3 className="sig-h2" style={{ fontSize: 32 }}>Thank you. We'll be in touch.</h3>
            <p className="sig-body" style={{ fontSize: 15 }}>
              {BRIEF_ENDPOINT ?
            'A reply will arrive within one working day. Watch for an email from ghostlabsoftware@gmail.com.' :
            'Your email client should have opened with the brief prefilled. Send it whenever ready.'}
            </p>
            <button
            className="sig-btn-ghost"
            style={{ alignSelf: 'flex-start', marginTop: 12 }}
            onClick={() => {setSubmitted(false);setError(null);}}>
            Send another brief</button>
          </div> :

        <form onSubmit={handleSubmit}>
            <div style={{
            display: 'grid',
            gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr',
            gap: isMobile ? '24px' : '32px 28px'
          }}>
              <div style={{ gridColumn: isMobile ? 'auto' : 'span 2' }}>
                <div className="sig-label">01 · The business or project</div>
                <input
                className="sig-input"
                placeholder="A short name for what you are working on"
                value={businessName}
                onChange={(e) => setBusinessName(e.target.value)} />
              
              </div>
              <div>
                <div className="sig-label">02 · Discipline</div>
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 12 }}>
                  {DISCIPLINES.map((d) =>
                <span
                  key={d}
                  className={`sig-chip ${discipline === d ? 'on' : ''}`}
                  style={{ fontSize: 10, cursor: 'pointer' }}
                  onClick={() => setDiscipline(d)}>
                  {d}</span>
                )}
                </div>
              </div>
              <div>
                <div className="sig-label">03 · First-phase timing</div>
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 12 }}>
                  {TIMINGS.map((t) =>
                <span
                  key={t}
                  className={`sig-chip ${timing === t ? 'on' : ''}`}
                  style={{ fontSize: 10, cursor: 'pointer' }}
                  onClick={() => setTiming(t)}>
                  {t}</span>
                )}
                </div>
              </div>
              <div style={{ gridColumn: isMobile ? 'auto' : 'span 2' }}>
                <div className="sig-label">04 · What you are trying to build</div>
                <textarea
                className="sig-input"
                style={{ minHeight: 110, resize: 'vertical' }}
                placeholder="The outcome you want, not the features you think you need. A few sentences is enough."
                value={description}
                onChange={(e) => setDescription(e.target.value)}
                required />
              
              </div>
              <div style={{ gridColumn: isMobile ? 'auto' : 'span 2' }}>
                <div className="sig-label">05 · Reach you</div>
                <input
                className="sig-input"
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                required />
              
              </div>
              {error &&
            <div style={{ gridColumn: isMobile ? 'auto' : 'span 2', fontFamily: SIG_FONTS.mono, fontSize: 11, color: v('red'), letterSpacing: '0.04em' }}>{error}</div>
            }
              <div style={{
              gridColumn: isMobile ? 'auto' : 'span 2',
              display: 'flex',
              flexDirection: isMobile ? 'column-reverse' : 'row',
              alignItems: isMobile ? 'stretch' : 'center',
              justifyContent: 'space-between',
              gap: isMobile ? 16 : 0,
              marginTop: 8
            }}>
                <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.04em' }}>Held in confidence. Read only by the engineers.</div>
                <button type="submit" className="sig-btn-primary" disabled={submitting}>
                  {submitting ? 'Sending…' : 'Send brief →'}
                </button>
              </div>
            </div>
          </form>
        }
      </div>
    </div>);

}

function StickyBriefCTA() {
  const [visible, setVisible] = React.useState(false);
  React.useEffect(() => {
    const onScroll = () => {
      const hero = document.getElementById('hero');
      const brief = document.getElementById('brief');
      if (!hero) return;
      const heroBottom = hero.getBoundingClientRect().bottom;
      const past = heroBottom < 0;
      const briefTop = brief ? brief.getBoundingClientRect().top : Infinity;
      // Hide once the user is in or just above the brief section
      const beforeBrief = briefTop > window.innerHeight * 0.55;
      setVisible(past && beforeBrief);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return (
    <button
      type="button"
      onClick={() => smoothScrollTo('brief')}
      style={{
        position: 'fixed', bottom: 24, right: 24, zIndex: 90,
        opacity: visible ? 1 : 0,
        pointerEvents: visible ? 'auto' : 'none',
        transform: visible ? 'translateY(0)' : 'translateY(8px)',
        transition: 'opacity .25s, transform .25s',
        display: 'inline-flex', alignItems: 'center', gap: 10,
        padding: '13px 22px',
        background: v('accent'),
        color: v('accent-ink'),
        border: 0,
        borderRadius: 999,
        fontFamily: SIG_FONTS.sans,
        fontWeight: 500, fontSize: 14,
        letterSpacing: '-0.005em',
        boxShadow: '0 14px 30px rgba(0,0,0,0.32), 0 0 0 1px rgba(0,0,0,0.35)',
        cursor: 'pointer'
      }}>
      
      <span style={{ width: 7, height: 7, borderRadius: '50%', background: v('accent-ink'), opacity: 0.55 }} />
      Send a brief
      <span style={{ fontSize: 16, lineHeight: 1, marginLeft: 2 }}>→</span>
    </button>);

}

function SignalFooter() {
  const isMobile = useIsMobile();
  return (
    <div style={{ padding: isMobile ? '48px 20px 32px' : '72px 56px 44px', borderTop: `1px solid ${v('line')}`, background: v('panel-bg') }}>
      <div style={{ maxWidth: 1400, margin: '0 auto' }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: isMobile ? '1fr' : '2fr 1fr 1fr 1fr',
          gap: isMobile ? 32 : 56,
          marginBottom: isMobile ? 32 : 56
        }}>
          <div>
            <Logo size={36} />
            <p style={{ fontSize: 13, color: v('text-dim'), marginTop: 18, maxWidth: 340, lineHeight: 1.65 }}>An independent engineering firm. We build custom software, intelligence, and hardware for businesses that need custom solutions.

            </p>
          </div>
          <div>
            <div className="sig-label">Channels</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 16 }}>
              <a href="mailto:ghostlabsoftware@gmail.com" className="sig-mono" style={{ fontSize: 12, color: v('text-dim'), textDecoration: 'none', wordBreak: 'break-all' }}>ghostlabsoftware@gmail.com</a>
              <span className="sig-mono" style={{ fontSize: 12, color: v('text-dim') }}>Telegram · available on request</span>
              <span className="sig-mono" style={{ fontSize: 12, color: v('text-dim') }}>Hosted in europe-west3</span>
            </div>
          </div>
          <div>
            <div className="sig-label">Pages</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 16 }}>
              {NAV_LINKS.map(([label, id]) =>
              <a key={label} href={`#${id}`} onClick={(e) => {e.preventDefault();smoothScrollTo(id);}} className="sig-mono" style={{ fontSize: 12, color: v('text-dim'), textDecoration: 'none', cursor: 'pointer' }}>{label}</a>
              )}
            </div>
          </div>
          <div>
            <div className="sig-label">Status</div>
            <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 10 }}>
              <span className="sig-mono" style={{ fontSize: 12, color: v('accent') }}>● Accepting requests · 2026</span>
              <span className="sig-mono" style={{ fontSize: 12, color: v('text-mute') }}>All work held under appropriate non-disclosure</span>
            </div>
          </div>
        </div>
        <div style={{
          display: 'flex',
          flexDirection: isMobile ? 'column' : 'row',
          gap: isMobile ? 10 : 0,
          justifyContent: 'space-between',
          alignItems: isMobile ? 'flex-start' : 'center',
          paddingTop: 24,
          borderTop: `1px solid ${v('line')}`
        }}>
          <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.08em' }}>© GHOSTLABS SOFTWARE LAB · EUROPE-WEST3</div>
          <div className="sig-mono" style={{ fontSize: 10, color: v('text-mute'), letterSpacing: '0.08em' }}>This page surfaces only what we are cleared to show.</div>
        </div>
      </div>
    </div>);

}

// ─── Palette wiring + Tweaks panel ─────────────────────────────

function usePalette(paletteKey) {
  React.useEffect(() => {
    const p = PALETTES[paletteKey] || PALETTES['signal-lime'];
    const root = document.documentElement;
    Object.entries(p.vars).forEach(([k, val]) => root.style.setProperty(`--sig-${k}`, val));
    root.style.colorScheme = p.mode === 'light' ? 'light' : 'dark';
  }, [paletteKey]);
}

function SignalTweaks({ t, setTweak }) {
  if (!window.TweaksPanel) return null;
  const { TweaksPanel, TweakSection, TweakSelect } = window;
  const paletteOptions = Object.entries(PALETTES).map(([k, p]) => ({ value: k, label: p.name }));
  const layoutOptions = window.GALLERY_LAYOUTS || [{ value: 'grid', label: 'Grid' }];
  const current = PALETTES[t.palette] || PALETTES['signal-lime'];
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Color palette">
        <TweakSelect
          label="Palette"
          value={t.palette}
          options={paletteOptions}
          onChange={(value) => setTweak('palette', value)} />
        
        <div style={{ padding: '8px 14px 14px', fontFamily: SIG_FONTS.mono, fontSize: 11, color: '#777', lineHeight: 1.5 }}>
          {current.note}
        </div>
      </TweakSection>
      <TweakSection label="Gallery layout">
        <TweakSelect
          label="Arrangement"
          value={t.galleryLayout}
          options={layoutOptions}
          onChange={(value) => setTweak('galleryLayout', value)} />
        
        <div style={{ padding: '8px 14px 14px', fontFamily: SIG_FONTS.mono, fontSize: 11, color: '#777', lineHeight: 1.5 }}>
          Each project renders inside its native device frame. Switch the arrangement of the gallery here.
        </div>
      </TweakSection>
    </TweaksPanel>);

}

function SignalPage() {
  const useTweaks = window.useTweaks;
  // Fallback when tweaks panel not loaded — render with defaults
  const [t, setTweak] = useTweaks ? useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];
  usePalette(t.palette);
  const GalleryV2 = window.SignalGalleryV2;
  return (
    <div className="sig-root" style={{ width: '100%', minHeight: '100%' }}>
      <SignalNav />
      <SignalHero />
      <SignalWorkshop />
      <SignalTicker />
      {GalleryV2 ?
      <div id="work"><GalleryV2 projects={SIG_PROJECTS} layout={t.galleryLayout || 'grid'} /></div> :
      <SignalGallery />}
      {window.SignalStore && <window.SignalStore />}
      <SignalDisciplines />
      <SignalPractice />
      <SignalEngagement />
      <SignalBrief />
      <SignalFooter />
      <SignalTweaks t={t} setTweak={setTweak} />
      <StickyBriefCTA />
    </div>);

}

window.SignalPage = SignalPage;