// Omelette Studio — Design Components
// Shared components exported to window for use in Components.html

// ─── TOKENS ───────────────────────────────────────────────────
const T = {
  white: '#FFFFFF',
  offWhite: '#FAFAFA',
  lightGrey: '#F2F2F2',
  midGrey: '#D1D1D1',
  darkGrey: '#6B6B6B',
  nearBlack: '#1A1A1A',
  black: '#0A0A0A',
  coral: '#FF6C79',
  serif: "'Fraunces', serif",
  sans: "'Geist', sans-serif"
};

// ─── GOOGLE MEET ICON ─────────────────────────────────────────
function MeetIcon({ size = 18 }) {
  return (
    <img
      src="assets/google-meet.svg"
      alt="Google Meet"
      style={{ display: 'block', flexShrink: 0, width: size, height: size, objectFit: 'contain' }} />);


}

// ─── FIGMA ICON ───────────────────────────────────────────────
function FigmaIcon({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 38 57" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M19 28.5C19 25.9804 20.0009 23.5641 21.7825 21.7825C23.5641 20.0009 25.9804 19 28.5 19C31.0196 19 33.4359 20.0009 35.2175 21.7825C36.9991 23.5641 38 25.9804 38 28.5C38 31.0196 36.9991 33.4359 35.2175 35.2175C33.4359 36.9991 31.0196 38 28.5 38C25.9804 38 23.5641 36.9991 21.7825 35.2175C20.0009 33.4359 19 31.0196 19 28.5Z" fill="#1ABCFE" />
      <path d="M0 47.5C0 44.9804 1.00089 42.5641 2.78249 40.7825C4.56408 39.0009 6.98044 38 9.5 38H19V47.5C19 50.0196 17.9991 52.4359 16.2175 54.2175C14.4359 55.9991 12.0196 57 9.5 57C6.98044 57 4.56408 55.9991 2.78249 54.2175C1.00089 52.4359 0 50.0196 0 47.5Z" fill="#0ACF83" />
      <path d="M19 0V19H28.5C31.0196 19 33.4359 17.9991 35.2175 16.2175C36.9991 14.4359 38 12.0196 38 9.5C38 6.98044 36.9991 4.56408 35.2175 2.78249C33.4359 1.00089 31.0196 0 28.5 0H19Z" fill="#FF7262" />
      <path d="M0 9.5C0 12.0196 1.00089 14.4359 2.78249 16.2175C4.56408 17.9991 6.98044 19 9.5 19H19V0H9.5C6.98044 0 4.56408 1.00089 2.78249 2.78249C1.00089 4.56408 0 6.98044 0 9.5Z" fill="#F24E1E" />
      <path d="M0 28.5C0 31.0196 1.00089 33.4359 2.78249 35.2175C4.56408 36.9991 6.98044 38 9.5 38H19V19H9.5C6.98044 19 4.56408 20.0009 2.78249 21.7825C1.00089 23.5641 0 25.9804 0 28.5Z" fill="#A259FF" />
    </svg>);

}

// ─── POINTER TILT HOOK ────────────────────────────────────────
function usePointerTilt(strength = 4) {
  const ref = React.useRef(null);
  const [offset, setOffset] = React.useState({ x: 0, y: 0 });
  const [active, setActive] = React.useState(false);
  const target = React.useRef({ x: 0, y: 0 });
  const current = React.useRef({ x: 0, y: 0 });
  const raf = React.useRef(null);

  const running = React.useRef(false);

  function lerp(a, b, t) {return a + (b - a) * t;}

  function animate() {
    current.current.x = lerp(current.current.x, target.current.x, 0.12);
    current.current.y = lerp(current.current.y, target.current.y, 0.12);
    const dx = Math.abs(current.current.x - target.current.x);
    const dy = Math.abs(current.current.y - target.current.y);
    setOffset({ x: current.current.x, y: current.current.y });
    if (dx > 0.01 || dy > 0.01) {
      raf.current = requestAnimationFrame(animate);
    } else {
      setOffset({ x: target.current.x, y: target.current.y });
      current.current = { x: target.current.x, y: target.current.y };
      raf.current = null;
      running.current = false;
    }
  }

  function startLoop() {
    if (!running.current) {
      running.current = true;
      raf.current = requestAnimationFrame(animate);
    }
  }

  function onMouseMove(e) {
    const el = ref.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    const cx = rect.left + rect.width / 2;
    const cy = rect.top + rect.height / 2;
    const dx = (e.clientX - cx) / (rect.width / 2);
    const dy = (e.clientY - cy) / (rect.height / 2);
    target.current = { x: dx * strength, y: dy * strength };
    startLoop();
  }

  function onMouseLeave() {
    target.current = { x: 0, y: 0 };
    setActive(false);
    startLoop();
  }

  React.useEffect(() => () => cancelAnimationFrame(raf.current), []);

  const transform = `translate(${offset.x.toFixed(2)}px, ${offset.y.toFixed(2)}px)${active ? ' scale(0.97)' : ''}`;
  return { ref, transform, onMouseMove, onMouseLeave, setActive };
}

// ─── PRIMARY BUTTON ───────────────────────────────────────────
// `fullWidth` makes the button stretch to fill its parent — used on mobile
// hero so the CTAs are easy tap targets and read as a clean vertical stack.
function PrimaryButton({ children, icon, onClick, fullWidth = false }) {
  const [hovered, setHovered] = React.useState(false);
  const tilt = usePointerTilt(4);
  return (
    <button
      ref={tilt.ref}
      onClick={onClick}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => {setHovered(false);tilt.onMouseLeave();}}
      onMouseMove={tilt.onMouseMove}
      onMouseDown={() => tilt.setActive(true)}
      onMouseUp={() => tilt.setActive(false)}
      style={{
        display: fullWidth ? 'flex' : 'inline-flex',
        width: fullWidth ? '100%' : 'auto',
        alignItems: 'center', justifyContent: 'center', gap: 8,
        background: hovered ? T.nearBlack : T.black,
        color: T.white,
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        padding: '12px 28px',
        borderRadius: 9999, border: 'none', cursor: 'pointer',
        transition: 'background 150ms ease',
        transform: tilt.transform,
        outline: 'none',
        letterSpacing: 0,
        whiteSpace: 'nowrap'
      }}>
      {icon && icon}
      {children}
    </button>);

}

// ─── SECONDARY BUTTON ─────────────────────────────────────────
function SecondaryButton({ children, icon, onClick, fullWidth = false }) {
  const [hovered, setHovered] = React.useState(false);
  const tilt = usePointerTilt(4);
  return (
    <button
      ref={tilt.ref}
      onClick={onClick}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => {setHovered(false);tilt.onMouseLeave();}}
      onMouseMove={tilt.onMouseMove}
      onMouseDown={() => tilt.setActive(true)}
      onMouseUp={() => tilt.setActive(false)}
      style={{
        display: fullWidth ? 'flex' : 'inline-flex',
        width: fullWidth ? '100%' : 'auto',
        alignItems: 'center', justifyContent: 'center', gap: 8,
        background: 'transparent',
        color: T.nearBlack,
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        padding: '12px 28px',
        borderRadius: 9999,
        border: `1px solid ${hovered ? T.nearBlack : T.midGrey}`,
        cursor: 'pointer',
        transition: 'border-color 150ms ease',
        transform: tilt.transform,
        outline: 'none',
        whiteSpace: 'nowrap'
      }}>
      {icon && icon}
      {children}
    </button>);

}

// ─── TEXT LINK ────────────────────────────────────────────────
function TextLink({ children, href = '#' }) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <a
      href={href}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        color: hovered ? T.coral : T.nearBlack,
        textDecoration: 'underline',
        textUnderlineOffset: 3,
        transition: 'color 150ms ease',
        cursor: 'pointer'
      }}>
      {children}
    </a>);

}

// ─── ICON CHIP ────────────────────────────────────────────────
// Same shape as Tag, but with a leading emoji/icon.
function IconChip({ icon, children }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      background: 'transparent',
      border: `1px solid ${T.midGrey}`,
      borderRadius: 9999,
      padding: '4px 10px',
      fontFamily: T.sans, fontSize: 12, fontWeight: 500,
      color: T.nearBlack,
      whiteSpace: 'nowrap'
    }}>
      <span style={{ fontSize: 15, lineHeight: 1 }}>{icon}</span>
      {children}
    </span>);
}

// ─── DEFAULT TAG ──────────────────────────────────────────────
function Tag({ children, variant = 'default' }) {
  const isSection = variant === 'section';
  const isCoral = variant === 'coral';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center',
      background: 'transparent',
      border: `1px solid ${isCoral ? T.coral : T.midGrey}`,
      borderRadius: 9999,
      padding: isSection ? '6px 16px' : '4px 12px',
      fontFamily: T.sans,
      fontSize: isSection ? 13 : 12,
      fontWeight: 500,
      color: isCoral ? T.coral : T.nearBlack,
      letterSpacing: 0,
      whiteSpace: 'nowrap'
    }}>
      {children}
    </span>);

}

// ─── SECTION HEADER ───────────────────────────────────────────
function SectionHeader({ pill, headline, subhead, align = 'center' }) {
  return (
    <div style={{
      display: 'flex', flexDirection: 'column',
      alignItems: align === 'center' ? 'center' : 'flex-start',
      textAlign: align,
      marginBottom: 48
    }}>
      {pill && <Tag variant="section">{pill}</Tag>}
      <h2 style={{
        fontFamily: T.serif, fontSize: 'clamp(26px, 4.5vw, 36px)', lineHeight: 1.2,
        letterSpacing: '-0.01em', color: T.nearBlack,
        marginTop: pill ? 16 : 0, marginBottom: 0, fontWeight: 400
      }}>{headline}</h2>
      {subhead &&
      <p style={{
        fontFamily: T.sans, fontSize: 18, fontWeight: 400,
        lineHeight: 1.6, color: T.darkGrey,
        marginTop: 12, marginBottom: 0, maxWidth: 560
      }}>{subhead}</p>
      }
    </div>);

}

// ─── TOP NAV ──────────────────────────────────────────────────
function TopNav({ scrolled = false }) {
  const links = ['Services', 'Process', 'Work'];
  return (
    <div style={{
      width: '100%',
      display: 'flex',
      justifyContent: 'center',
      padding: '20px 24px',
      position: 'relative',
      zIndex: 50,
      background: T.offWhite
    }}>
      <nav style={{
        display: 'inline-flex', alignItems: 'center',
        background: 'rgba(26,26,26,0.97)',
        backdropFilter: 'blur(12px)',
        WebkitBackdropFilter: 'blur(12px)',
        borderRadius: 9999,
        padding: '6px 6px 6px 20px',
        boxShadow: '0 2px 24px rgba(0,0,0,0.12)', gap: 24,

      }}>
        {/* Logo */}
        <a href="#" style={{ display: 'flex', alignItems: 'center', textDecoration: 'none', flexShrink: 0 }}>
          <img src="assets/omelette-logo.svg" alt="Omelette" style={{ height: 18, width: 'auto', display: 'block', filter: 'invert(1)' }} />
        </a>
        {/* Links */}
        <div style={{ display: 'flex', alignItems: 'center', gap: "6px" }}>
          {links.map((l) =>
          <NavLink key={l} label={l} dark={true} />
          )}
        </div>
        {/* CTA */}
        <FloatingNavCTA />
      </nav>
    </div>);

}

function FloatingNavCTA() {
  const [hovered, setHovered] = React.useState(false);
  const tilt = usePointerTilt(4);
  return (
    <button
      ref={tilt.ref}
      onClick={() => window.open('https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ00n5Nw2R8lWu16_fpqRwWSzuzb-ujZ2OnoDn4zrlHL1Kla_OLocuHa_AG52BmmUXLiDMYFyL__', '_blank')}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => {setHovered(false);tilt.onMouseLeave();}}
      onMouseMove={tilt.onMouseMove}
      onMouseDown={() => tilt.setActive(true)}
      onMouseUp={() => tilt.setActive(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 8,
        background: hovered ? '#F2F2F2' : T.white,
        color: T.nearBlack,
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        padding: '11px 20px',
        borderRadius: 9999, border: 'none', cursor: 'pointer',
        transition: 'background 150ms ease',
        transform: tilt.transform,
        outline: 'none',
        whiteSpace: 'nowrap',
        flexShrink: 0
      }}>
      <MeetIcon size={16} />
      Book a Call
    </button>);

}

function NavLink({ label, active, dark = false }) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <a
      href="#"
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        color: dark ?
        hovered ? T.white : 'rgba(255,255,255,0.55)' :
        hovered ? T.nearBlack : T.darkGrey,
        textDecoration: 'none',
        transition: 'color 150ms ease, background 150ms ease',
        padding: '6px 10px',
        borderRadius: 9999,
        background: dark && hovered ? 'rgba(255,255,255,0.1)' : 'transparent',
        display: 'inline-block'
      }}>
      {label}
    </a>);

}

// ─── SERVICE PILL ─────────────────────────────────────────────
// The pill itself is transparent — the dark active state is drawn by a
// single sliding indicator inside ServicePillGroup, so the selected fill
// flows from pill to pill instead of popping.
const ServicePill = React.forwardRef(function ServicePill({ label, active, onClick }, ref) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <button
      ref={ref}
      onClick={onClick}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        position: 'relative',          // stack above the indicator
        zIndex: 1,
        background: active ? 'transparent' : (hovered ? T.white : 'transparent'),
        color: active ? T.white : T.nearBlack,
        border: 'none',
        fontFamily: T.sans, fontSize: 14, fontWeight: 500,
        padding: '10px 22px',
        borderRadius: 9999,
        cursor: 'pointer',
        transition: 'background 150ms ease, color 220ms ease',
        outline: 'none',
        whiteSpace: 'nowrap',
        boxShadow: !active && hovered ? '0 1px 3px rgba(0,0,0,0.06)' : 'none',
      }}>
      {label}
    </button>);
});

// ─── SERVICE PILL GROUP ───────────────────────────────────────
// Segmented control: three pills in a grey rounded container, with a single
// dark "indicator" that slides between them. The indicator is absolutely
// positioned and animates `transform`+`width` to the active pill's bounds,
// so the selected state appears to flow from one option to the next.
function ServicePillGroup({ options, activeIndex, onChange }) {
  const containerRef = React.useRef(null);
  const pillRefs = React.useRef([]);
  const [indicator, setIndicator] = React.useState({ x: 0, w: 0 });
  // Suppress the first transition so the indicator doesn't visibly slide in
  // from x=0 on initial paint.
  const [ready, setReady] = React.useState(false);

  const measure = React.useCallback(() => {
    const active = pillRefs.current[activeIndex];
    if (!active || !containerRef.current) return;
    const c = containerRef.current.getBoundingClientRect();
    const a = active.getBoundingClientRect();
    setIndicator({ x: a.left - c.left, w: a.width });
  }, [activeIndex]);

  React.useLayoutEffect(() => {
    measure();
    if (!ready) requestAnimationFrame(() => setReady(true));
  }, [measure, ready]);

  React.useEffect(() => {
    if (!containerRef.current) return;
    const ro = new ResizeObserver(measure);
    ro.observe(containerRef.current);
    return () => ro.disconnect();
  }, [measure]);

  return (
    <div style={{
      display: 'flex',
      justifyContent: 'center',
      marginTop: 32,
      marginBottom: 32,
    }}>
      <div ref={containerRef} style={{
        position: 'relative',
        display: 'inline-flex',
        background: T.lightGrey,
        borderRadius: 9999,
        padding: 4,
        gap: 4,
      }}>
        {/* Sliding active indicator */}
        <div style={{
          position: 'absolute',
          top: 4, bottom: 4, left: 0,
          width: indicator.w,
          transform: `translateX(${indicator.x}px)`,
          background: T.black,
          borderRadius: 9999,
          transition: ready
            ? 'transform 380ms cubic-bezier(0.4, 0, 0.2, 1), width 380ms cubic-bezier(0.4, 0, 0.2, 1)'
            : 'none',
          pointerEvents: 'none',
          zIndex: 0,
        }} />
        {options.map((label, i) =>
          <ServicePill
            key={i}
            ref={(el) => (pillRefs.current[i] = el)}
            label={label}
            active={activeIndex === i}
            onClick={() => onChange(i)} />
        )}
      </div>
    </div>);
}

// ─── SERVICE CARD ─────────────────────────────────────────────
function ServiceCard({ title, price, description, commitment, commitmentIcon, bullets, goodFit, cta, ctaIcon, darkRight = false, animKey = 0 }) {
  const rightBg = darkRight ? T.nearBlack : T.offWhite;
  const rightFg = darkRight ? T.white : T.nearBlack;
  const rightMuted = darkRight ? 'rgba(255,255,255,0.55)' : T.darkGrey;
  const rightDivider = darkRight ? 'rgba(255,255,255,0.85)' : T.darkGrey;
  const viewport = useViewport();
  const isMobile = viewport === 'mobile';
  const isTablet = viewport === 'tablet';
  const [includedOpen, setIncludedOpen] = React.useState(false);

  // Both columns settle upward; right column is staggered behind for a hand-crafted feel.
  const leftSlot = {
    animation: 'serviceContentSettle 520ms cubic-bezier(0.22, 1, 0.36, 1) both'
  };
  const rightSlot = {
    animation: 'serviceContentSettle 520ms cubic-bezier(0.22, 1, 0.36, 1) both',
    animationDelay: '80ms'
  };

  return (
    <div style={{
      background: T.white,
      border: `1px solid ${T.lightGrey}`,
      borderRadius: 4,
      padding: isMobile ? 24 : (isTablet ? 32 : 48),
      display: 'grid',
      gridTemplateColumns: isMobile ? '1fr' : '1.4fr 1fr',
      gap: isMobile ? 28 : (isTablet ? 40 : 56),
      overflow: 'hidden'
    }}>
      {/* LEFT COLUMN */}
      <div key={`left-${animKey}`} style={{ display: 'flex', flexDirection: 'column', ...leftSlot }}>
        <div style={{
          display: 'flex',
          // On mobile/tablet, force the commitment chip to stack below the
          // title for uniformity across all three cards (Marketing Site's
          // chip is short enough to stay inline, the other two wrap — the
          // resulting inconsistency reads as a layout bug).
          flexDirection: viewport === 'desktop' ? 'row' : 'column',
          alignItems: viewport === 'desktop' ? 'center' : 'flex-start',
          justifyContent: viewport === 'desktop' ? 'space-between' : 'flex-start',
          gap: viewport === 'desktop' ? 16 : 12,
          flexWrap: 'wrap',
        }}>
          <div style={{ fontFamily: T.serif, fontSize: isMobile ? 26 : 32, lineHeight: 1.2, letterSpacing: '-0.01em', color: T.nearBlack, fontWeight: 400 }}>
            {title}
          </div>
          {commitmentIcon ? (
            <IconChip icon={commitmentIcon}>{commitment}</IconChip>
          ) : (
            <Tag>{commitment}</Tag>
          )}
        </div>
        <div style={{ fontFamily: T.sans, fontSize: 17, fontWeight: 400, lineHeight: 1.6, color: T.darkGrey, marginTop: 16 }}>
          {description}
        </div>
        {isMobile ? (
          <>
            <button
              type="button"
              onClick={() => setIncludedOpen(o => !o)}
              aria-expanded={includedOpen}
              style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                width: '100%', background: 'none', border: 'none',
                borderTop: `1px solid ${T.lightGrey}`,
                padding: '20px 0',
                marginTop: 24,
                cursor: 'pointer',
                fontFamily: T.sans, fontSize: 13, fontWeight: 600, color: T.nearBlack,
                letterSpacing: '0.06em', textTransform: 'uppercase'
              }}>
              What's included
              <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true" style={{
                transform: includedOpen ? 'rotate(180deg)' : 'rotate(0deg)',
                transition: 'transform 420ms cubic-bezier(0.22, 1, 0.36, 1)',
                flexShrink: 0
              }}>
                <path d="M3 5l4 4 4-4" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
            <div style={{
              display: 'grid',
              gridTemplateRows: includedOpen ? '1fr' : '0fr',
              transition: 'grid-template-rows 420ms cubic-bezier(0.22, 1, 0.36, 1)'
            }}>
              <div style={{ overflow: 'hidden' }}>
                <div style={{
                  display: 'flex', flexDirection: 'column', gap: 10, paddingBottom: 8,
                  opacity: includedOpen ? 1 : 0,
                  transform: includedOpen ? 'translateY(0)' : 'translateY(-4px)',
                  transition: 'opacity 320ms cubic-bezier(0.22, 1, 0.36, 1) 60ms, transform 320ms cubic-bezier(0.22, 1, 0.36, 1) 60ms'
                }}>
                  {bullets.map((b, i) =>
                    <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                      <span style={{ color: T.coral, fontSize: 14, lineHeight: '26px', flexShrink: 0, fontWeight: 600 }}>✓</span>
                      <span style={{ fontFamily: T.sans, fontSize: 16, fontWeight: 400, lineHeight: 1.6, color: T.nearBlack }}>{b}</span>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </>
        ) : (
          <>
            <div style={{ fontFamily: T.sans, fontSize: 13, fontWeight: 600, color: T.nearBlack, marginTop: 32, marginBottom: 14, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
              What's included
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              {bullets.map((b, i) =>
                <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                  <span style={{ color: T.coral, fontSize: 14, lineHeight: '26px', flexShrink: 0, fontWeight: 600 }}>✓</span>
                  <span style={{ fontFamily: T.sans, fontSize: 16, fontWeight: 400, lineHeight: 1.6, color: T.nearBlack }}>{b}</span>
                </div>
              )}
            </div>
          </>
        )}
      </div>

      {/* RIGHT COLUMN — frame stays stable, content animates */}
      <div style={{
        background: rightBg,
        borderRadius: 4,
        padding: isMobile ? 24 : (isTablet ? 28 : 32),
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'space-between',
        gap: 24,
        overflow: 'hidden'
      }}>
        <div key={`right-${animKey}`} style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', gap: 24, flex: 1, ...rightSlot }}>
          <div>
            <div style={{ fontFamily: T.sans, fontSize: 13, fontWeight: 600, color: rightFg, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
              Good fit if
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 14 }}>
              {goodFit.map((g, i) =>
                <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
                  <span style={{ color: rightDivider, fontSize: 16, lineHeight: '26px', flexShrink: 0 }}>·</span>
                  <span style={{ fontFamily: T.sans, fontSize: 15, fontWeight: 400, lineHeight: 1.55, color: rightFg }}>{g}</span>
                </div>
              )}
            </div>
          </div>
          <div>
            <div style={{ fontFamily: T.sans, fontSize: 13, fontWeight: 500, color: rightMuted, letterSpacing: '0.02em', textTransform: 'uppercase' }}>
              Investment
            </div>
            <div style={{ fontFamily: T.serif, fontSize: isMobile ? 22 : 32, color: rightFg, marginTop: 4, fontWeight: 400, letterSpacing: '-0.01em' }}>
              {price}
            </div>
            <div style={{ marginTop: 20 }}>
              {darkRight ? (
                <button
                  onClick={() => window.open('https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ00n5Nw2R8lWu16_fpqRwWSzuzb-ujZ2OnoDn4zrlHL1Kla_OLocuHa_AG52BmmUXLiDMYFyL__', '_blank')}
                  style={{
                    display: isMobile ? 'flex' : 'inline-flex',
                    width: isMobile ? '100%' : 'auto',
                    alignItems: 'center', justifyContent: 'center', gap: 8,
                    background: T.white,
                    color: T.nearBlack,
                    fontFamily: T.sans, fontSize: 14, fontWeight: 500,
                    padding: '12px 28px',
                    borderRadius: 9999, border: 'none', cursor: 'pointer',
                    whiteSpace: 'nowrap'
                  }}>
                  {ctaIcon}
                  {cta}
                </button>
              ) : (
                <PrimaryButton fullWidth={isMobile} icon={ctaIcon} onClick={() => window.open('https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ00n5Nw2R8lWu16_fpqRwWSzuzb-ujZ2OnoDn4zrlHL1Kla_OLocuHa_AG52BmmUXLiDMYFyL__', '_blank')}>{cta}</PrimaryButton>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>);
}

// ─── ACCORDION ────────────────────────────────────────────────
function Accordion({ items }) {
  const [active, setActive] = React.useState(0);
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      {items.map((item, i) =>
      <AccordionItem
        key={i}
        step={String(i + 1).padStart(2, '0')}
        title={item.title}
        description={item.description}
        isOpen={active === i}
        onClick={() => setActive(i)}
        isLast={i === items.length - 1} />

      )}
    </div>);

}

function AccordionItem({ step, title, description, isOpen, onClick, isLast }) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <div
      onClick={onClick}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        padding: 24,
        borderBottom: isLast ? 'none' : `1px solid ${T.lightGrey}`,
        cursor: 'pointer',
        background: hovered && !isOpen ? T.lightGrey : 'transparent',
        transition: 'background 150ms ease'
      }}>
      <div style={{ fontFamily: T.sans, fontSize: 14, fontWeight: 600, color: T.coral, marginBottom: 6 }}>
        {step}
      </div>
      <div style={{ fontFamily: T.serif, fontSize: 26, lineHeight: 1.3, letterSpacing: '-0.01em', color: T.nearBlack, fontWeight: 400 }}>
        {title}
      </div>
      <div style={{
        maxHeight: isOpen ? 200 : 0,
        overflow: 'hidden',
        transition: 'max-height 300ms ease'
      }}>
        <div style={{
          fontFamily: T.sans, fontSize: 16, fontWeight: 400,
          lineHeight: 1.6, color: T.darkGrey,
          marginTop: 12
        }}>
          {description}
        </div>
      </div>
    </div>);

}

// ─── PROJECT BLOCK ────────────────────────────────────────────
function ProjectBlock({ tags, title, stat, quote, clientName, clientTitle, images }) {
  return (
    <div style={{ display: 'flex', gap: 48, alignItems: 'flex-start' }}>
      {/* Left: context 40% */}
      <div style={{ flex: '0 0 40%' }}>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
          {tags.map((t) => <Tag key={t}>{t}</Tag>)}
        </div>
        <h3 style={{
          fontFamily: T.serif, fontSize: 28, lineHeight: 1.3,
          letterSpacing: '-0.01em', color: T.nearBlack,
          fontWeight: 400, marginTop: 16, marginBottom: 0
        }}>{title}</h3>
        <div style={{ borderTop: `1px solid ${T.lightGrey}`, marginTop: 20 }} />
        {quote &&
        <p style={{
          fontFamily: T.sans, fontSize: 16, fontWeight: 400,
          fontStyle: 'italic', lineHeight: 1.6, color: T.nearBlack,
          marginTop: 24, marginBottom: 0
        }}>"{quote}"</p>
        }
        {clientName &&
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 12 }}>
            <div style={{
            width: 32, height: 32, borderRadius: '50%',
            background: T.lightGrey,
            flexShrink: 0
          }} />
            <div>
              <div style={{ fontFamily: T.sans, fontSize: 14, fontWeight: 600, color: T.nearBlack }}>{clientName}</div>
              <div style={{ fontFamily: T.sans, fontSize: 14, fontWeight: 400, color: T.darkGrey }}>{clientTitle}</div>
            </div>
          </div>
        }
      </div>
      {/* Right: screenshots 60% */}
      <div style={{ flex: '0 0 60%', display: 'flex', flexDirection: 'column', gap: 16 }}>
        {images.map((img, i) =>
        <div key={i} style={{
          borderRadius: 8,
          border: `1px solid ${T.lightGrey}`,
          background: T.lightGrey,
          height: img.height || 180,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          overflow: 'hidden'
        }}>
            {img.placeholder &&
          <span style={{ fontFamily: T.sans, fontSize: 12, color: T.midGrey }}>{img.placeholder}</span>
          }
          </div>
        )}
      </div>
    </div>);

}

// ─── STANDALONE TESTIMONIAL ───────────────────────────────────
function StandaloneTestimonial({ quote, name, title, hasAvatar = true }) {
  return (
    <div style={{ maxWidth: 720, margin: '0 auto', textAlign: 'center' }}>
      <p style={{
        fontFamily: T.serif, fontSize: 28, lineHeight: 1.3,
        letterSpacing: '-0.01em', fontStyle: 'italic',
        color: T.nearBlack, fontWeight: 400,
        marginBottom: 32
      }}>"{quote}"</p>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
        {hasAvatar &&
        <div style={{
          width: 48, height: 48, borderRadius: '50%',
          background: T.lightGrey, flexShrink: 0
        }} />
        }
        <div style={{ textAlign: 'left' }}>
          <div style={{ fontFamily: T.sans, fontSize: 16, color: T.nearBlack, fontWeight: "500" }}>{name}</div>
          <div style={{ fontFamily: T.sans, fontSize: 14, fontWeight: 400, color: T.darkGrey }}>{title}</div>
        </div>
      </div>
    </div>);

}

// ─── CLIENT LOGO STRIP ────────────────────────────────────────
function ClientLogoStrip({ logos }) {
  return (
    <div style={{ textAlign: 'center' }}>
      <div style={{
        fontFamily: T.sans, fontSize: 11, fontWeight: 500,
        letterSpacing: '0.08em', textTransform: 'uppercase',
        color: T.darkGrey, marginBottom: 24
      }}>Companies We've Worked With</div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 48, flexWrap: 'wrap' }}>
        {logos.map((logo, i) =>
        <LogoPlaceholder key={i} name={logo.name} width={logo.width || 80} />
        )}
      </div>
    </div>);

}

function LogoPlaceholder({ name, width }) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <div
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        opacity: hovered ? 1 : 0.4,
        transition: 'opacity 200ms ease',
        cursor: 'default',
        filter: 'grayscale(1)',
        height: 28,
        width: width,
        background: T.nearBlack,
        borderRadius: 3,
        display: 'flex', alignItems: 'center', justifyContent: 'center'
      }}>
      <span style={{ fontFamily: T.sans, fontSize: 11, fontWeight: 600, color: T.white, letterSpacing: '0.04em' }}>{name}</span>
    </div>);

}

// ─── CTA SECTION ──────────────────────────────────────────────
function CTASection() {
  return (
    <div style={{
      background: T.offWhite,
      padding: '96px 48px',
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', textAlign: 'center'
    }}>
      <h2 style={{
        fontFamily: T.serif, fontSize: 40, lineHeight: 1.2,
        letterSpacing: '-0.01em', color: T.nearBlack,
        fontWeight: 400, maxWidth: 600, marginBottom: 0
      }}>Ready to build something worth noticing?</h2>
      <p style={{
        fontFamily: T.sans, fontSize: 16, fontWeight: 400,
        lineHeight: 1.6, color: T.darkGrey,
        marginTop: 16, marginBottom: 0, maxWidth: 480
      }}>Let's talk about your project. No decks, no discovery calls. Just a direct conversation.</p>
      <div style={{ marginTop: 24 }}>
        <PrimaryButton icon={<MeetIcon />}>Book a Call</PrimaryButton>
      </div>
      <div style={{ marginTop: 16 }}>
        <TextLink>or email hello@theomelette.ca</TextLink>
      </div>
    </div>);

}

// ─── FOOTER ───────────────────────────────────────────────────
function Footer() {
  const cols = [
  {
    header: null,
    content:
    <div>
          <img src="assets/omelette-logo.svg" alt="Omelette" style={{ height: 20, width: 'auto', filter: 'invert(1)', marginBottom: 12, display: 'block' }} />
          <p style={{ fontFamily: T.sans, fontSize: 14, fontWeight: 400, color: 'rgba(255,255,255,0.7)', lineHeight: 1.6, marginTop: 8 }}>
            A small design studio making digital products that work.
          </p>
        </div>

  },
  {
    header: 'Navigation',
    links: ['Services', 'Process', 'Work']
  },
  {
    header: 'Contact',
    links: ['hello@theomelette.ca', 'LinkedIn', 'Book a Call']
  }];


  return (
    <footer style={{ background: T.nearBlack, padding: '64px 48px' }}>
      <div style={{ display: 'flex', gap: 64, flexWrap: 'wrap', maxWidth: 1200, margin: '0 auto' }}>
        {cols.map((col, i) =>
        <div key={i} style={{ flex: i === 0 ? '1.5' : '1', minWidth: 160 }}>
            {col.header &&
          <div style={{ fontFamily: T.sans, fontSize: 11, fontWeight: 500, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.4)', marginBottom: 16 }}>
                {col.header}
              </div>
          }
            {col.content || null}
            {col.links &&
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {col.links.map((l) =>
            <FooterLink key={l}>{l}</FooterLink>
            )}
              </div>
          }
          </div>
        )}
      </div>
      <div style={{
        maxWidth: 1200, margin: '48px auto 0',
        paddingTop: 24,
        borderTop: '1px solid rgba(255,255,255,0.2)',
        fontFamily: T.sans, fontSize: 14, fontWeight: 400,
        color: 'rgba(255,255,255,0.5)'
      }}>
        © 2026 Omelette Studio. All rights reserved.
      </div>
    </footer>);

}

function FooterLink({ children }) {
  const [hovered, setHovered] = React.useState(false);
  return (
    <a
      href="#"
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        fontFamily: T.sans, fontSize: 14, fontWeight: 400,
        color: hovered ? T.white : 'rgba(255,255,255,0.7)',
        textDecoration: 'none',
        transition: 'color 200ms ease'
      }}>
      {children}
    </a>);

}

// ─── VIEWPORT HOOK ────────────────────────────────────────────
// Returns 'mobile' | 'tablet' | 'desktop' based on window width.
// Breakpoints match the design tokens: <768 mobile, 768-1023 tablet, ≥1024 desktop.
function useViewport() {
  const get = () => {
    if (typeof window === 'undefined') return 'desktop';
    const w = window.innerWidth;
    if (w < 768) return 'mobile';
    if (w < 1024) return 'tablet';
    return 'desktop';
  };
  const [v, setV] = React.useState(get);
  React.useEffect(() => {
    const onResize = () => setV(get());
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return v;
}

// ─── EXPORTS ──────────────────────────────────────────────────
Object.assign(window, {
  T,
  useViewport,
  MeetIcon, FigmaIcon,
  PrimaryButton, SecondaryButton, TextLink,
  Tag, IconChip, SectionHeader,
  TopNav, NavLink,
  ServiceCard, ServicePillGroup,
  Accordion, AccordionItem,
  ProjectBlock,
  StandaloneTestimonial,
  ClientLogoStrip,
  CTASection,
  Footer
});