// Direction A — System catalog (baseline)
// Tabular, indexed, slightly technical. Categories as rows in a data-table.
// Subcategories visible inline at all times as a tag-strip in a second column.
// Interaction model: subs always visible (no expand/collapse). Clicking a
// subcategory tag navigates to its index page.
//
// All colour values come from CSS custom properties on :root so brand
// variations can re-skin this layout by overriding the vars (see
// direction-a-motion.jsx and direction-a-mono.jsx).

const VAR_RULE  = 'var(--rule)';
const VAR_INK   = 'var(--ink)';
const VAR_INK2  = 'var(--ink-2)';
const VAR_INK3  = 'var(--ink-3)';
const VAR_PAPER = 'var(--paper)';
const VAR_PAPER2 = 'var(--paper-2)';

// Small inline lock icon used wherever an item is gated behind the
// existing password-protected page. SVG is sized in em so it tracks the
// surrounding text. currentColor lets the parent control color via CSS.
function LockIcon({ size = 12 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true"
      style={{ display: 'inline-block', verticalAlign: '-1px' }}>
      <rect x="2" y="5.5" width="8" height="5" stroke="currentColor" strokeWidth="1" />
      <path d="M3.75 5.5 V3.75 a2.25 2.25 0 0 1 4.5 0 V5.5" stroke="currentColor" strokeWidth="1" fill="none" />
    </svg>
  );
}

// Pattern icons by Spencer — 5x5 grid of rounded squares, currentColor fill.
// '1' = filled, '0' = empty. Original positions live in icons/*.svg.
const CATEGORY_ICON_PATTERNS = {
  architecture: ['00100', '01110', '11111', '11101', '11101'],
  visual:       ['10101', '01110', '11111', '01110', '10101'],
  coding:       ['11011', '10001', '10001', '10001', '11011'],
  material:     ['01010', '10101', '01010', '10101', '01010'],
};
function CategoryIcon({ name, size = 32, idx = 0, lit = true }) {
  const grid = CATEGORY_ICON_PATTERNS[name];
  if (!grid) return null;
  // Original SVG: viewBox 142.36, cell 20.47, step 30.47, radius 4.41.
  return (
    <svg width={size} height={size} viewBox="0 0 142.36 142.36" aria-hidden="true"
      style={{ display: 'block', color: 'currentColor' }}>
      {grid.flatMap((row, r) =>
        row.split('').map((v, c) => {
          if (v !== '1') return null;
          // Diagonal distance from the top-right corner (r=0,c=4): 0 → 8.
          // Lower distance lights first, so the wavefront runs top-right →
          // bottom-left. idx offsets each icon so they fire in succession.
          const diag = r + (4 - c);
          const delay = idx * 0.38 + diag * 0.06;
          return (
            <rect key={`${r}-${c}`}
              x={c * 30.47} y={r * 30.47}
              width="20.47" height="20.47" rx="4.41" ry="4.41"
              fill="currentColor"
              style={lit ? {
                animation: 'srLedFlash 6.5s linear infinite',
                animationDelay: `${delay}s`,
              } : undefined} />
          );
        })
      )}
    </svg>
  );
}

function SRLogo({ height = 32 }) {
  return (
    <svg viewBox="0 0 142.7 142.7" height={height} aria-label="Spencer Russell"
      style={{ display: 'block', color: 'currentColor', flexShrink: 0 }}>
      <path fill="currentColor" d="M133.28,142.7h-58.03c-2.15,0-3.9-1.75-3.9-3.9v-58.03c0-3.47,4.2-5.21,6.66-2.76l58.03,58.03c2.46,2.46.72,6.66-2.76,6.66Z" />
      <rect fill="currentColor" x="71.35" width="71.35" height="71.35" rx="3.9" ry="3.9" />
      <path fill="currentColor" d="M64.69,78.01L6.66,136.04c-2.46,2.46-6.66.72-6.66-2.76v-58.03c0-2.15,1.75-3.9,3.9-3.9h58.03c3.47,0,5.21,4.2,2.76,6.66Z" />
      <path fill="currentColor" d="M64.69,6.66L6.66,64.69c-2.46,2.46-6.66.72-6.66-2.76V3.9C0,1.75,1.75,0,3.9,0h58.03c3.47,0,5.21,4.2,2.76,6.66Z" />
    </svg>
  );
}

function A_Header({ now }) {
  const mobile = window.useIsMobile();
  if (mobile) {
    // Phone: logo + name on a row, then practice/location stacked compactly
    // below. The clock is dropped — it's a desktop flourish, not navigation.
    return (
      <div style={{ background: VAR_PAPER, color: VAR_INK,
        borderBottom: `1px solid ${VAR_RULE}`, padding: '20px 22px 16px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 13 }}>
          <SRLogo height={24} />
          <div>
            <div className="mono" style={{ fontSize: 9.5, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 2 }}>Index</div>
            <div style={{ fontSize: 14, fontWeight: 500, letterSpacing: -0.1 }}>Spencer Russell</div>
          </div>
        </div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '3px 16px', marginTop: 12, fontSize: 12, color: VAR_INK2 }}>
          <span>Design · Architecture · Making</span>
          <span className="mono tnum" style={{ color: VAR_INK3, fontSize: 11 }}>Portland, OR · 45.51°N</span>
        </div>
      </div>
    );
  }
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '56px 1fr auto', columnGap: 24,
      alignItems: 'flex-end',
      background: VAR_PAPER, color: VAR_INK,
      borderBottom: `1px solid ${VAR_RULE}`, padding: '28px 56px 18px', fontSize: 13 }}>
      <div style={{ color: VAR_INK, alignSelf: 'center', transition: 'color .2s ease', cursor: 'pointer' }}
        onMouseEnter={(e) => { e.currentTarget.style.color = 'oklch(0.90 0.26 124)'; }}
        onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--ink)'; }}>
        <SRLogo height={34} />
      </div>
      <div style={{ display: 'flex', gap: 56, alignItems: 'flex-end' }}>
        <div>
          <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4 }}>Index</div>
          <div style={{ fontSize: 15, fontWeight: 500, letterSpacing: -0.1 }}>Spencer Russell</div>
        </div>
        <div>
          <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4 }}>Practice</div>
          <div style={{ fontSize: 14, color: VAR_INK2 }}>Design · Architecture · Making</div>
        </div>
        <div>
          <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4 }}>Location</div>
          <div style={{ fontSize: 14, color: VAR_INK2 }}>Portland, OR · 45.51°N</div>
        </div>
      </div>
      <div className="mono tnum" style={{ fontSize: 12, color: VAR_INK3 }}>{now}</div>
    </div>
  );
}

function A_Statement({ collapsed }) {
  const mobile = window.useIsMobile();
  if (mobile) {
    // Phone: single column, left-aligned, natural wrapping (the desktop version
    // pins three nowrap lines flush-right — that overflows a narrow screen).
    // No hover on touch, so this just shows the bio at a comfortable size.
    return (
      <div style={{ padding: '34px 22px 30px', borderBottom: `1px solid ${VAR_RULE}` }}>
        <div className="mono" style={{ fontSize: 9.5, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 14 }}>§ 00 / About</div>
        <div style={{ fontSize: 'clamp(15px, 4.2vw, 17px)', lineHeight: 1.5, letterSpacing: -0.15, color: VAR_INK, textWrap: 'pretty', maxWidth: '34em' }}>
          A licensed architect and computational designer working across buildings, software, image, and the workshop, focused on creative technology and motion.
        </div>
        <div style={{ fontSize: 12, lineHeight: 1.55, color: VAR_INK3, marginTop: 16 }}>
          Work in four parts. Items marked with a lock require a password, available on request.
        </div>
      </div>
    );
  }
  return (
    <div style={{ height: collapsed ? 106 : 168, boxSizing: 'border-box',
      padding: collapsed ? '16px 56px' : '40px 56px 28px',
      display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 56, alignItems: 'start',
      borderBottom: `1px solid ${VAR_RULE}`, overflow: 'hidden',
      transition: 'height .55s cubic-bezier(.33,1,.68,1), padding .55s cubic-bezier(.33,1,.68,1)' }}>
      <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', paddingTop: collapsed ? 2 : 8, transition: 'padding .55s cubic-bezier(.33,1,.68,1)' }}>§ 00 / About</div>
      <div style={{ display: 'grid' }}>
        {/* Bio — shown at rest. Locked to three near-equal, right-aligned lines
            via controlled breaks; font scales with the viewport (clamp) so the
            three-line shape and occupied width hold responsively. */}
        <div style={{ gridArea: '1 / 1', justifySelf: 'end',
          fontSize: 'clamp(14px, 1.65vw, 24px)', lineHeight: 1.34, letterSpacing: -0.4, fontWeight: 400,
          color: VAR_INK, textAlign: 'right',
          opacity: collapsed ? 0 : 1, pointerEvents: collapsed ? 'none' : 'auto',
          transition: 'opacity .35s ease' }}>
          <span style={{ whiteSpace: 'nowrap' }}>A licensed architect and computational designer</span><br />
          <span style={{ whiteSpace: 'nowrap' }}>working across buildings, software, image, and the</span><br />
          <span style={{ whiteSpace: 'nowrap' }}>workshop, focused on creative technology and motion.</span>
        </div>
        {/* Catalog description — shown on hover */}
        <div style={{ gridArea: '1 / 1', justifySelf: 'end', maxWidth: 370,
          fontSize: 13, lineHeight: 1.5, color: VAR_INK2, textAlign: 'right', textWrap: 'balance',
          opacity: collapsed ? 1 : 0, pointerEvents: collapsed ? 'auto' : 'none',
          transition: 'opacity .4s ease .12s' }}>
          Work in four parts. Items marked with a lock require a password, available on request.
        </div>
      </div>
    </div>
  );
}

function A_FeaturedStrip({ items, hover, onPick }) {
  const wrapRef = React.useRef(null);
  const [fit, setFit] = React.useState(items ? items.length : 0);
  React.useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const CARD = 104, GAP = 12;
    const measure = () => {
      const w = el.clientWidth;
      if (!w) return;
      setFit(Math.max(1, Math.floor((w + GAP) / (CARD + GAP))));
    };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);
  if (!items || !items.length) return null;
  const shown = items.slice(0, Math.min(fit, items.length));
  return (
    <div ref={wrapRef} style={{
      gridColumn: '3 / 4',
      display: 'flex',
      gap: 12,
      overflow: 'hidden',
      maxHeight: hover ? 160 : 0,
      opacity: hover ? 1 : 0,
      marginTop: hover ? 20 : 0,
      transition: 'max-height .55s cubic-bezier(.33,1,.68,1), opacity .35s ease .08s, margin-top .55s cubic-bezier(.33,1,.68,1)',
      pointerEvents: hover ? 'auto' : 'none',
    }}>
      {shown.map((f, i) => (
        <div key={i}
          onClick={onPick ? (e) => { e.stopPropagation(); onPick(f); } : undefined}
          style={{
          width: 104,
          flexShrink: 0,
          cursor: onPick ? 'pointer' : 'default',
          transform: hover ? 'translateY(0)' : 'translateY(6px)',
          transition: `transform .5s cubic-bezier(.33,1,.68,1) ${0.05 * i}s`,
        }}>
          <div style={{
            aspectRatio: '4 / 3',
            backgroundColor: f.clip ? (f.bg || '#0a0a0a') : 'var(--paper)',
            backgroundImage: f.src ? `url(${f.src})` : (f.clip ? 'none' : 'repeating-linear-gradient(135deg, transparent 0 6px, var(--paper-2) 6px 7px)'),
            backgroundSize: 'cover', backgroundPosition: 'center',
            border: `1px solid ${VAR_RULE}`,
            position: 'relative',
            overflow: 'hidden',
            display: 'flex',
            alignItems: 'flex-end',
            justifyContent: 'flex-start',
          }}>
            {f.clip && (
              <video
                src={window.resolveClipSrc ? window.resolveClipSrc(f.clip) : f.clip}
                autoPlay muted loop playsInline
                style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
            )}
            {!f.src && !f.clip && (
              <div className="mono" style={{
                fontSize: 9, color: VAR_INK3, padding: '4px 6px',
                letterSpacing: 0.4, textTransform: 'uppercase',
              }}>[{f.tag}]</div>
            )}
          </div>
          <div className="mono" style={{
            display: 'flex', justifyContent: 'space-between',
            fontSize: 10, color: VAR_INK2, marginTop: 6, letterSpacing: 0.2, gap: 6,
          }}>
            <span style={{ fontFamily: 'var(--font-primary)', fontSize: 11, color: VAR_INK, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{f.title}</span>
            <span className="tnum" style={{ color: VAR_INK3, flexShrink: 0 }}>{f.yr}</span>
          </div>
        </div>
      ))}
    </div>
  );
}

function A_CategoryRow({ cat, idx, total, onOpen, onSub, onOpenProject, onHoverChange, active, rootRef }) {
  const [hover, setHover] = React.useState(false);
  const mobile = window.useIsMobile();
  const setH = (v) => { setHover(v); onHoverChange && onHoverChange(v); };
  // Categories with subsections count those; a sub-less category (architecture,
  // whose full list lives on its own page) counts its projects instead.
  const pages = window.CATEGORY_PAGES && window.CATEGORY_PAGES[cat.word];
  const rowCount = (pages && pages.rows) ? pages.rows.length : 0;
  const itemCount = cat.subs.length || rowCount;
  const itemLabel = cat.subs.length ? 'items' : 'projects';
  // Architecture's hover preview cards are derived from the futureform
  // (independent) projects rather than a hardcoded list — so they track the
  // ARCH_PROJECTS data. Other categories keep their authored `featured` set.
  const featuredItems = (cat.word === 'architecture' && window.ARCH_PROJECTS)
    ? window.ARCH_PROJECTS.filter((p) => p.firm === 'futureform').map((p) => {
        const imgs = p.images || [];
        const pick = imgs.find((im) => im.feature) || imgs[0] || {};
        return { title: p.title, yr: p.yr, tag: pick.tag || 'project', src: pick.src };
      })
    : cat.featured;

  if (mobile) {
    // Phone: a stacked block per category. Icon + index on a row, then the big
    // word, blurb, and the subcategory chips (full-width-friendly tap targets).
    // The hover-only featured strip is dropped on touch. `active` (set by the
    // landing's scroll tracker) darkens the block nearest the viewport middle —
    // the touch analogue of the desktop hover highlight.
    return (
      <div
        ref={rootRef}
        onClick={() => onOpen(cat)}
        style={{
          padding: '32px 22px',
          borderBottom: idx < total - 1 ? `1px solid ${VAR_RULE}` : 'none',
          background: active ? VAR_PAPER2 : 'transparent',
          transition: 'background .45s ease',
          cursor: 'pointer',
        }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 11,
            color: active ? 'oklch(0.84 0.20 128)' : VAR_INK2, transition: 'color .45s ease' }}>
            <CategoryIcon name={cat.word} size={24} idx={idx} lit={!active} />
            <span className="mono tnum" style={{ fontSize: 11, color: VAR_INK3 }}>{cat.n}</span>
          </div>
          <span className="mono tnum" style={{ fontSize: 10.5, color: active ? VAR_INK : VAR_INK3, transition: 'color .45s ease' }}>
            {String(itemCount).padStart(2, '0')} {itemLabel} →
          </span>
        </div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 9, marginBottom: 10, flexWrap: 'wrap' }}>
          <div style={{ fontSize: 'clamp(28px, 7.5vw, 34px)', fontWeight: 500, letterSpacing: -1, lineHeight: 1 }}>{cat.word}</div>
          <div className="mono" style={{ fontSize: 12, color: VAR_INK3, letterSpacing: -0.2 }}>[{cat.qual}]</div>
        </div>
        <div style={{ fontSize: 13, color: VAR_INK2, lineHeight: 1.55, marginBottom: 20, textWrap: 'pretty', maxWidth: '40em' }}>{cat.blurb}</div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7 }}>
          {!cat.subs.length && (
            <button
              onClick={(e) => { e.stopPropagation(); onOpen(cat); }}
              className="mono"
              style={{
                fontFamily: 'var(--font-mono)', fontSize: 11.5,
                padding: '7px 10px', minHeight: 36, boxSizing: 'border-box',
                border: `1px solid ${VAR_RULE}`, background: 'transparent', color: VAR_INK,
                cursor: 'pointer', letterSpacing: 0.1,
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}>
              <span style={{ fontFamily: 'var(--font-primary)', fontSize: 12.5 }}>built projects</span>
              <span style={{ opacity: 0.5 }}>→</span>
            </button>
          )}
          {cat.subs.map((s) => (
            <button key={s.id}
              onClick={(e) => { e.stopPropagation(); onSub(cat, s); }}
              className="mono"
              style={{
                fontFamily: 'var(--font-mono)', fontSize: 11.5,
                padding: '7px 10px', minHeight: 36, boxSizing: 'border-box',
                border: `1px solid ${VAR_RULE}`, background: 'transparent', color: VAR_INK,
                cursor: 'pointer', letterSpacing: 0.1,
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}>
              {s.locked && <span style={{ display: 'inline-flex', alignItems: 'center' }}><LockIcon size={10} /></span>}
              <span style={{ fontFamily: 'var(--font-primary)', fontSize: 12.5 }}>{s.label}</span>
              <span style={{ opacity: 0.5 }}>· {s.meta}</span>
            </button>
          ))}
        </div>
      </div>
    );
  }

  return (
    <div
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      onClick={() => onOpen(cat)}
      style={{
        display: 'grid',
        gridTemplateColumns: '56px 1.05fr 1.6fr 90px',
        alignItems: 'baseline',
        gap: 24,
        padding: '24px 56px',
        borderBottom: idx < total - 1 ? `1px solid ${VAR_RULE}` : 'none',
        background: hover ? VAR_PAPER2 : 'transparent',
        transition: 'background .4s ease',
        cursor: 'pointer',
      }}>
      <div style={{
        alignSelf: 'start', paddingTop: 10,
        display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 10,
        color: hover ? 'oklch(0.88 0.22 128)' : VAR_INK2,
        transition: 'color .35s ease',
      }}>
        <CategoryIcon name={cat.word} size={32} idx={idx} lit={!hover} />
        <div className="mono tnum" style={{ fontSize: 13, color: VAR_INK3 }}>{cat.n}</div>
      </div>
      <div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginBottom: 6 }}>
          <div style={{ fontSize: 44, fontWeight: 500, letterSpacing: -1.4, lineHeight: 1 }}>{cat.word}</div>
          <div className="mono" style={{ fontSize: 16, color: VAR_INK3, letterSpacing: -0.2 }}>[{cat.qual}]</div>
        </div>
        <div style={{ fontSize: 13, color: VAR_INK2, lineHeight: 1.5, maxWidth: 320 }}>{cat.blurb}</div>
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignContent: 'start', paddingTop: 16 }}>
        {!cat.subs.length && (
          <button
            onClick={(e) => { e.stopPropagation(); onOpen(cat); }}
            className="mono"
            style={{
              fontFamily: 'var(--font-mono)',
              fontSize: 12,
              padding: '7px 11px',
              border: `1px solid ${VAR_RULE}`,
              background: 'transparent',
              color: VAR_INK,
              cursor: 'pointer',
              letterSpacing: 0.1,
              display: 'inline-flex', alignItems: 'center', gap: 6,
              transition: 'background .12s, border-color .12s, color .12s',
            }}
            onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--ink)'; e.currentTarget.style.color = 'var(--paper)'; e.currentTarget.style.borderColor = 'var(--ink)'; }}
            onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink)'; e.currentTarget.style.borderColor = 'var(--rule)'; }}>
            <span style={{ fontFamily: 'var(--font-primary)', fontSize: 13 }}>built projects</span>
            <span style={{ opacity: 0.5 }}>→</span>
          </button>
        )}
        {cat.subs.map((s) => (
          <button key={s.id}
            onClick={(e) => { e.stopPropagation(); onSub(cat, s); }}
            className="mono"
            style={{
              fontFamily: 'var(--font-mono)',
              fontSize: 12,
              padding: '7px 11px',
              border: `1px solid ${VAR_RULE}`,
              background: 'transparent',
              color: VAR_INK,
              cursor: 'pointer',
              letterSpacing: 0.1,
              display: 'inline-flex', alignItems: 'center', gap: 6,
              transition: 'background .12s, border-color .12s, color .12s',
            }}
            onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--ink)'; e.currentTarget.style.color = 'var(--paper)'; e.currentTarget.style.borderColor = 'var(--ink)'; }}
            onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink)'; e.currentTarget.style.borderColor = 'var(--rule)'; }}>
            {s.locked && <span style={{ display: 'inline-flex', alignItems: 'center' }}><LockIcon size={11} /></span>}
            <span style={{ fontFamily: 'var(--font-primary)', fontSize: 13 }}>{s.label}</span>
            <span style={{ opacity: 0.5 }}>· {s.meta}</span>
          </button>
        ))}
      </div>
      <div className="mono tnum" style={{ fontSize: 12, color: hover ? VAR_INK : VAR_INK3, alignSelf: 'start', paddingTop: 18, textAlign: 'right' }}>
        {String(itemCount).padStart(2, '0')} {itemLabel} →
      </div>
      <A_FeaturedStrip items={featuredItems} hover={hover}
        onPick={(item) => {
          if (item.sub && onSub) return onSub(cat, { id: item.sub });
          if (onOpenProject) return onOpenProject(cat, item.title);
        }} />
    </div>
  );
}

function A_Footer() {
  const mobile = window.useIsMobile();
  if (mobile) {
    return (
      <div style={{ background: VAR_PAPER, color: VAR_INK,
        padding: '30px 22px', borderTop: `1px solid ${VAR_RULE}`, fontSize: 13 }}>
        <div className="mono" style={{ fontSize: 9.5, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 18 }}>§ 05 / Contact</div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <button onClick={() => window.openContactModal && window.openContactModal()} className="mono"
            style={{ fontFamily: 'var(--font-mono)', fontSize: 13, padding: '14px 16px', cursor: 'pointer',
              border: `1px solid ${VAR_INK}`, background: VAR_INK, color: VAR_PAPER,
              display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
            <span>Get in touch</span><span style={{ opacity: 0.7 }}>→</span>
          </button>
          <div>
            <div className="mono" style={{ fontSize: 9.5, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 3 }}>Instagram</div>
            <a href={window.META.instaUrl} target="_blank" rel="noopener"
              style={{ color: VAR_INK, textDecoration: 'underline', textUnderlineOffset: 3 }}>{window.META.insta} ↗</a>
          </div>
        </div>
        <div className="mono" style={{ fontSize: 9.5, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase', marginTop: 24 }}>{window.META.copyright} · V1.0</div>
      </div>
    );
  }
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '160px 1fr 1fr 1fr', gap: 24,
      position: 'sticky', bottom: 0, zIndex: 5,
      background: VAR_PAPER, color: VAR_INK,
      padding: '18px 56px 16px', borderTop: `1px solid ${VAR_RULE}`, fontSize: 13 }}>
      <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase' }}>§ 05 / Contact</div>
      <div>
        <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4 }}>Inquiries</div>
        <button onClick={() => window.openContactModal && window.openContactModal()}
          style={{ font: 'inherit', fontSize: 13, color: VAR_INK, background: 'none', border: 'none', padding: 0,
            cursor: 'pointer', textDecoration: 'underline', textUnderlineOffset: 3 }}>
          Get in touch →
        </button>
      </div>
      <div>
        <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4 }}>Instagram</div>
        <a href={window.META.instaUrl} target="_blank" rel="noopener"
          style={{ color: VAR_INK, textDecoration: 'underline', textUnderlineOffset: 3 }}>{window.META.insta} ↗</a>
      </div>
      <div style={{ textAlign: 'right' }}>
        <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase' }}>{window.META.copyright} · V1.0</div>
      </div>
    </div>
  );
}

function DirectionA_Landing({ navigate }) {
  const go = navigate || (() => {});
  // Live Pacific-time clock in the header — ticks every second so the date and
  // time stay current. Format: "YYYY-MM-DD HH:MM PDT" (zone label auto-switches
  // PDT/PST with daylight saving).
  const fmtNow = React.useCallback(() => {
    const d = new Date();
    const parts = new Intl.DateTimeFormat('en-CA', {
      timeZone: 'America/Los_Angeles', hour12: false,
      year: 'numeric', month: '2-digit', day: '2-digit',
      hour: '2-digit', minute: '2-digit', timeZoneName: 'short',
    }).formatToParts(d).reduce((acc, p) => (acc[p.type] = p.value, acc), {});
    return `${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute} ${parts.timeZoneName}`;
  }, []);
  const [now, setNow] = React.useState(fmtNow);
  React.useEffect(() => {
    const t = setInterval(() => setNow(fmtNow()), 1000);
    return () => clearInterval(t);
  }, [fmtNow]);
  const [toast, setToast] = React.useState(null);
  const [anyHover, setAnyHover] = React.useState(false);
  const mobile = window.useIsMobile();
  const rowRefs = React.useRef([]);
  const [activeIdx, setActiveIdx] = React.useState(-1);
  React.useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 1400); return () => clearTimeout(t); }, [toast]);

  // Mobile: highlight the category block whose vertical center is nearest the
  // viewport middle as the page scrolls — the touch counterpart of the desktop
  // hover state. rAF-throttled; only active on the phone breakpoint.
  React.useEffect(() => {
    if (!mobile) { setActiveIdx(-1); return; }
    const update = () => {
      const mid = window.innerHeight / 2;
      let best = -1, bestDist = Infinity;
      rowRefs.current.forEach((el, i) => {
        if (!el) return;
        const r = el.getBoundingClientRect();
        const dist = Math.abs((r.top + r.height / 2) - mid);
        if (dist < bestDist) { bestDist = dist; best = i; }
      });
      setActiveIdx((prev) => (prev === best ? prev : best));
    };
    update();
    window.addEventListener('scroll', update, { passive: true });
    window.addEventListener('resize', update);
    return () => {
      window.removeEventListener('scroll', update);
      window.removeEventListener('resize', update);
    };
  }, [mobile]);

  return (
    <div className="page" style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
      <A_Header now={now} />
      <div style={{ flex: 1, minHeight: 0, overflow: 'visible', display: 'flex', flexDirection: 'column' }}>
        <A_Statement collapsed={anyHover} />
        <div style={{ flex: 1, minHeight: 0 }}>
          {window.CATEGORIES.map((c, i) => (
            <A_CategoryRow key={c.n} cat={c} idx={i} total={window.CATEGORIES.length}
              onOpen={(cat) => go({ page: 'category', cat: cat.word })}
              onSub={(cat, s) => go({ page: 'subcategory', cat: cat.word, sub: s.id })}
              onOpenProject={(cat, title) => go({ page: 'category', cat: cat.word, open: title })}
              onHoverChange={setAnyHover}
              active={mobile && i === activeIdx}
              rootRef={(el) => { rowRefs.current[i] = el; }} />
          ))}
        </div>
      </div>
      <A_Footer />
      {toast && (
        <div className="mono" style={{ position: 'absolute', bottom: 96, left: '50%', transform: 'translateX(-50%)',
          fontSize: 12, padding: '8px 14px', background: VAR_INK, color: VAR_PAPER }}>{toast}</div>
      )}
    </div>
  );
}

function DirectionA_Arch() {
  // Single-open accordion: only one project's detail is expanded at a time so
  // the artboard's fixed height bounds to (collapsed table + one open detail).
  const [openTitle, setOpenTitle] = React.useState(null);
  return (
    <div className="ab" style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        borderBottom: `1px solid ${VAR_RULE}`, padding: '20px 56px', fontSize: 13 }}>
        <div className="mono" style={{ color: VAR_INK3 }}>
          <span style={{ cursor: 'pointer' }}>← index</span>
          <span style={{ margin: '0 12px', opacity: 0.4 }}>/</span>
          <span style={{ color: VAR_INK }}>architecture</span>
          <span className="mono" style={{ color: VAR_INK3, marginLeft: 8 }}>[spatial]</span>
        </div>
        <div className="mono" style={{ color: VAR_INK3, fontSize: 12 }}>§ 01</div>
      </div>

      <div style={{ padding: '56px 56px 36px', display: 'grid', gridTemplateColumns: '1fr 320px',
        gap: 56, alignItems: 'start', borderBottom: `1px solid ${VAR_RULE}` }}>
        <div>
          <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 20 }}>§ 01 / Architecture</div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 18, marginBottom: 16 }}>
            <div style={{ fontSize: 88, fontWeight: 500, letterSpacing: -3, lineHeight: 0.95 }}>architecture</div>
            <div className="mono" style={{ fontSize: 22, color: VAR_INK3, letterSpacing: -0.3 }}>[spatial]</div>
          </div>
          <div style={{ fontSize: 16, color: VAR_INK2, lineHeight: 1.55, maxWidth: 540 }}>
            Completed projects shown publicly below. A detailed portfolio
            of work samples — drawings, process, and case studies — is available to prospective
            clients on request.
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, paddingTop: 8 }}>
          <a href={window.META.workSamplesUrl} target="_blank" rel="noopener"
            className="mono"
            style={{ fontFamily: 'var(--font-mono)', fontSize: 13, padding: '14px 16px',
              border: `1px solid ${VAR_INK}`, background: VAR_INK, color: VAR_PAPER,
              cursor: 'pointer', textDecoration: 'none',
              display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
              <LockIcon size={13} />
              <span>work samples</span>
              <span style={{ opacity: 0.55 }}>· request access</span>
            </span>
            <span style={{ opacity: 0.7 }}>↗</span>
          </a>
          <div className="mono" style={{ fontSize: 11, color: VAR_INK3, lineHeight: 1.55, padding: '0 2px' }}>
            Password-protected. Request credentials through the contact form, or note it in your message.
          </div>
        </div>
      </div>

      <div className="mono" style={{ display: 'grid', gridTemplateColumns: '90px 1.6fr 1fr 110px 1fr 0.8fr 0.7fr',
        gap: 16, padding: '14px 56px', fontSize: 11, color: VAR_INK3, letterSpacing: 0.5, textTransform: 'uppercase',
        background: VAR_PAPER2, borderBottom: `1px solid ${VAR_RULE}` }}>
        <div>Year</div><div>Project</div><div>Role</div><div>Firm</div><div>Location</div><div>Type</div><div style={{ textAlign: 'right' }}>Status</div>
      </div>

      <div style={{ flex: 1 }}>
        {window.ARCH_PROJECTS.map((p, i) => (
          <A_ProjectRow key={p.title} p={p} last={i === window.ARCH_PROJECTS.length - 1}
            open={openTitle === p.title}
            onToggle={() => setOpenTitle((t) => (t === p.title ? null : p.title))} />
        ))}
      </div>

      <A_Footer />
    </div>
  );
}

function A_ProjectRow({ p, last, open, onToggle }) {
  const [h, setH] = React.useState(false);
  // Treat 'TVA' as the primary/inked firm; other firms (e.g. futureform)
  // render in ink-2 so the table reads as 'mostly TVA, with these others'.
  // If futureform becomes the larger bucket later, just flip the check.
  const firmStrong = p.firm === 'TVA';
  return (
    <div style={{ borderBottom: last && !open ? 'none' : `1px solid ${VAR_RULE}`,
      background: open ? VAR_PAPER2 : 'transparent', transition: 'background .18s' }}>
      <div onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
        onClick={onToggle}
        style={{ display: 'grid', gridTemplateColumns: '90px 1.6fr 1fr 110px 1fr 0.8fr 0.7fr', gap: 16,
          padding: '18px 56px', alignItems: 'center', fontSize: 14,
          background: h && !open ? VAR_PAPER2 : 'transparent', cursor: 'pointer', transition: 'background .12s' }}>
        <div className="mono tnum" style={{ color: VAR_INK3, fontSize: 12 }}>{p.yr}</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, fontWeight: 500 }}>
          <span className="mono" style={{ fontSize: 11, color: VAR_INK3, width: 9, flexShrink: 0,
            display: 'inline-block', transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
            transition: 'transform .25s cubic-bezier(.33,1,.68,1)' }}>›</span>
          {p.title}
        </div>
        <div style={{ color: VAR_INK2 }}>{p.role}</div>
        <div className="mono" style={{ fontSize: 12, color: firmStrong ? VAR_INK : VAR_INK2, letterSpacing: 0.1 }}>{p.firm}</div>
        <div style={{ color: VAR_INK2 }}>{p.loc}</div>
        <div className="mono" style={{ color: VAR_INK3, fontSize: 12 }}>{p.tag}</div>
        <div className="mono" style={{ color: VAR_INK2, fontSize: 12, textAlign: 'right',
          display: 'inline-flex', alignItems: 'center', gap: 6, justifyContent: 'flex-end' }}>
          <span style={{ width: 7, height: 7, borderRadius: 0,
            background: p.status === 'in construction' ? 'oklch(60% 0.14 70)' : VAR_INK }} />
          {p.status}
        </div>
      </div>
      <A_ProjectDetail p={p} open={open} />
    </div>
  );
}

function A_ProjectDetail({ p, open }) {
  const imgs = p.images || [];
  return (
    <div style={{
      display: 'grid', gridTemplateRows: open ? '1fr' : '0fr',
      transition: 'grid-template-rows .5s cubic-bezier(.33,1,.68,1)',
    }}>
      <div style={{ overflow: 'hidden' }}>
        <div style={{
          padding: '8px 56px 44px', display: 'grid', gridTemplateColumns: '320px 1fr', gap: 56, alignItems: 'start',
          opacity: open ? 1 : 0, transform: open ? 'translateY(0)' : 'translateY(8px)',
          transition: 'opacity .4s ease .1s, transform .5s cubic-bezier(.33,1,.68,1) .05s',
        }}>
          {/* left: brief + quick facts */}
          <div>
            <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.5,
              textTransform: 'uppercase', marginBottom: 12 }}>Brief</div>
            <div style={{ fontSize: 14, color: VAR_INK2, lineHeight: 1.6, marginBottom: 24 }}>{p.brief}</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 0,
              borderTop: `1px solid ${VAR_RULE}` }}>
              {[['Area', p.area], ['Client', p.client], ['Role', p.role], ['Location', p.loc]]
                .filter(([, v]) => v).map(([k, v]) => (
                <div key={k} className="mono" style={{ display: 'flex', justifyContent: 'space-between',
                  gap: 16, fontSize: 12, padding: '9px 0', borderBottom: `1px solid ${VAR_RULE}` }}>
                  <span style={{ color: VAR_INK3, letterSpacing: 0.4, textTransform: 'uppercase', fontSize: 11 }}>{k}</span>
                  <span style={{ color: VAR_INK, textAlign: 'right' }}>{v}</span>
                </div>
              ))}
            </div>
          </div>
          {/* right: sample images */}
          <div>
            <div className="mono" style={{ fontSize: 11, color: VAR_INK3, letterSpacing: 0.5,
              textTransform: 'uppercase', marginBottom: 12 }}>Selected images · {imgs.length}</div>
            <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}>
              {imgs.map((f, i) => (
                <div key={i} style={{ width: 196, flexShrink: 0 }}>
                  <div style={{
                    aspectRatio: '4 / 3',
                    backgroundColor: 'var(--paper)',
                    backgroundImage: f.src ? `url(${f.src})` : 'repeating-linear-gradient(135deg, transparent 0 6px, var(--paper-2) 6px 7px)',
                    backgroundSize: 'cover', backgroundPosition: 'center',
                    border: `1px solid ${VAR_RULE}`,
                    display: 'flex', alignItems: 'flex-end', justifyContent: 'flex-start',
                  }}>
                    {!f.src && (
                      <div className="mono" style={{ fontSize: 9, color: VAR_INK3, padding: '5px 7px',
                        letterSpacing: 0.4, textTransform: 'uppercase' }}>[{f.tag}]</div>
                    )}
                  </div>
                  <div className="mono" style={{ fontSize: 10, color: VAR_INK2, marginTop: 6,
                    letterSpacing: 0.2 }}>{f.title}</div>
                </div>
              ))}
            </div>
            <div className="mono" style={{ fontSize: 11, color: VAR_INK3, lineHeight: 1.55, marginTop: 18 }}>
              Full drawing set &amp; process available in <a href={window.META.workSamplesUrl} target="_blank" rel="noopener" style={{ color: VAR_INK, textDecoration: 'underline', textUnderlineOffset: 2 }}>work samples ↗</a>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

window.DirectionA_Landing = DirectionA_Landing;
window.DirectionA_Arch = DirectionA_Arch;
// Shared atoms used by category-page.jsx / subcategory-page.jsx (separate Babel
// scopes), exposed on window so they can be reused across files.
window.LockIcon = LockIcon;
window.CategoryIcon = CategoryIcon;
window.SRLogo = SRLogo;
window.A_Footer = A_Footer;
