// Case study modal — Fitness Management App.
// UX research → personas → CJM → service blueprint → user flow → web product.

const FT_ACCENT = '#1E88E5';
const FT_BG = '#0E1722';
const FT_SURFACE = '#162436';
const FT_FG = '#EEF3F8';
const FT_MUTED = 'rgba(238,243,248,.65)';
const FT_DIM = 'rgba(238,243,248,.42)';
const FT_LINE = 'rgba(238,243,248,.12)';

// ── Atoms ────────────────────────────────────────────────────────────────────
const FTEyebrow = ({ children, color = FT_DIM }) => (
  <div style={{
    fontFamily: 'DM Sans, sans-serif', fontSize: 11,
    letterSpacing: '.22em', textTransform: 'uppercase',
    color, fontWeight: 600,
  }}>{children}</div>
);

const FTHeading = ({ children, size = 48, weight = 500, color = FT_FG, style }) => (
  <h2 style={{
    fontFamily: 'Libre Bodoni, serif', fontWeight: weight,
    fontSize: size, lineHeight: 1.05, letterSpacing: '-.02em',
    color, margin: 0, textWrap: 'balance', ...style,
  }}>{children}</h2>
);

const FTBody = ({ children, size = 16, color = FT_FG, opacity = .85, maxWidth = 640, style }) => (
  <p style={{
    fontFamily: 'DM Sans, sans-serif', fontSize: size, lineHeight: 1.6,
    color, opacity, margin: 0, maxWidth, textWrap: 'pretty', ...style,
  }}>{children}</p>
);

const FTSection = ({ children, py = 96, bg, style }) => (
  <section style={{ padding: `${py}px max(56px, 5vw)`, background: bg, ...style }}>{children}</section>
);

const FTReveal = ({ children, delay = 0, dir = 'up', style }) => {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return undefined;
    if (typeof IntersectionObserver === 'undefined') { setShown(true); return undefined; }
    const io = new IntersectionObserver(
      (es) => es.forEach((e) => { if (e.isIntersecting) { setShown(true); io.disconnect(); } }),
      { threshold: 0.12, rootMargin: '0px 0px -8% 0px' }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const offsets = { up: 'translateY(28px)', down: 'translateY(-22px)', left: 'translateX(-22px)', right: 'translateX(22px)', none: 'none' };
  return (
    <div ref={ref} style={{
      opacity: shown ? 1 : 0,
      transform: shown ? 'translate(0,0)' : offsets[dir] || offsets.up,
      transition: `opacity .8s cubic-bezier(.2,.7,.2,1) ${delay}ms, transform .9s cubic-bezier(.2,.7,.2,1) ${delay}ms`,
      ...style,
    }}>{children}</div>
  );
};

// Laptop frame that hosts a wide screen capture.
const FTLaptop = ({ src, alt, width = 720, accent = FT_ACCENT }) => {
  const w = width;
  const screenH = w * 0.625;
  const baseH = w * 0.04;
  return (
    <div style={{
      width: w, position: 'relative',
      display: 'flex', flexDirection: 'column', alignItems: 'center',
      filter: `drop-shadow(0 30px 60px rgba(0,0,0,.5)) drop-shadow(0 0 80px ${accent}22)`,
    }}>
      <div style={{
        width: '100%', height: screenH,
        background: '#0c0c0e', padding: w * 0.018,
        borderRadius: `${w * 0.022}px ${w * 0.022}px 4px 4px`,
        boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,.08)',
        position: 'relative',
      }}>
        <div style={{
          position: 'absolute', inset: w * 0.018,
          borderRadius: w * 0.014,
          overflow: 'hidden', background: '#fff',
        }}>
          <img src={src} alt={alt} draggable={false}
               style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
        </div>
        <div style={{
          position: 'absolute', top: w * 0.008, left: '50%',
          transform: 'translateX(-50%)',
          width: w * 0.008, height: w * 0.008, borderRadius: '50%',
          background: '#1a1a1c',
        }} />
      </div>
      <div style={{
        width: w * 1.06, height: baseH,
        background: 'linear-gradient(to bottom, #c8c9cc 0%, #9c9ea3 50%, #6e7075 100%)',
        borderRadius: `0 0 ${w * 0.012}px ${w * 0.012}px`,
        position: 'relative',
        boxShadow: 'inset 0 -1px 1px rgba(0,0,0,.35)',
      }}>
        <div style={{
          position: 'absolute', top: 0, left: '50%',
          transform: 'translateX(-50%)',
          width: w * 0.16, height: w * 0.008,
          background: '#5b5d62',
          borderRadius: `0 0 ${w * 0.006}px ${w * 0.006}px`,
        }} />
      </div>
    </div>
  );
};

// ── Hero ────────────────────────────────────────────────────────────────────
const FTHero = () => (
  <FTSection py={0} style={{ position: 'relative', paddingTop: 100, paddingBottom: 80 }}>
    <div className="ft-mesh" style={{
      position: 'absolute', inset: '8% -10% -10% -10%', pointerEvents: 'none', opacity: .85,
      background: `
        radial-gradient(50% 40% at 22% 30%, ${FT_ACCENT}24 0%, transparent 70%),
        radial-gradient(40% 35% at 78% 18%, #5BC0EB22 0%, transparent 70%),
        radial-gradient(60% 45% at 55% 85%, ${FT_ACCENT}1c 0%, transparent 65%)
      `,
    }} />

    <div style={{ position: 'relative', display: 'flex', flexDirection: 'column', gap: 48 }}>
      <FTReveal delay={50}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <FTEyebrow color={FT_ACCENT}>Case · 04</FTEyebrow>
          <span style={{ width: 32, height: 1, background: FT_LINE }} />
          <FTEyebrow>Health · Service design</FTEyebrow>
        </div>
      </FTReveal>

      <FTReveal delay={120}>
        <FTHeading size={'clamp(64px, 8vw, 144px)'}>
          Fitness <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>Management App</span>
        </FTHeading>
      </FTReveal>

      <FTReveal delay={220}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr',
                       gap: 'clamp(40px, 5vw, 80px)', maxWidth: 1080, alignItems: 'start' }}>
          <FTBody size={20} maxWidth={620}>
            A web product designed end-to-end through UX research — personas, customer
            journeys and a service blueprint mapping every touchpoint between users
            and the system across the whole fitness service.
          </FTBody>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '16px 48px' }}>
            {[
              ['Role',     'UX/UI Designer'],
              ['Type',     'Web app · service design'],
              ['Artefacts', 'Personas · CJM · Blueprint · Flow'],
              ['Status',    'Concept · validated'],
            ].map(([k, v]) => (
              <div key={k} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                <FTEyebrow>{k}</FTEyebrow>
                <div style={{ fontFamily: 'DM Sans, sans-serif', fontSize: 15, color: FT_FG }}>{v}</div>
              </div>
            ))}
          </div>
        </div>
      </FTReveal>

      {/* Hero — landing page in a laptop */}
      <FTReveal delay={300}>
        <div style={{ display: 'flex', justifyContent: 'center', marginTop: 32, position: 'relative' }}>
          <div style={{
            position: 'absolute', left: '50%', top: '50%',
            width: 760, height: 480, transform: 'translate(-50%, -45%)',
            background: `radial-gradient(circle, ${FT_ACCENT}28 0%, ${FT_ACCENT}10 35%, transparent 70%)`,
            filter: 'blur(40px)', pointerEvents: 'none',
          }} />
          <FTLaptop src="case-assets/fitness/landing-page.jpg" alt="Fitness Management — landing page" width={760} />
        </div>
      </FTReveal>
    </div>
  </FTSection>
);

// ── Design philosophy ───────────────────────────────────────────────────────
// Connects the case to broader UX + product principles.
const FTPrinciples = () => (
  <FTSection style={{ borderTop: `1px solid ${FT_LINE}` }}>
    <div style={{ maxWidth: 1280 }}>
      <FTReveal>
        <FTEyebrow>Approach · design philosophy</FTEyebrow>
        <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
          The product is the <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>service.</span>
        </FTHeading>
        <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
          A fitness app is not pixels — it's a chain of touchpoints between user,
          trainer, dietician, supplement vendor, club staff and the data underneath.
          The work was to make that chain visible, then design for the gaps.
        </FTBody>
      </FTReveal>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 24 }}>
        {[
          ['Research first',  'Design assumptions are debts. Every screen was paid for in interviews, personas and journey maps before a pixel was placed.'],
          ['System thinking', 'Front-stage and back-stage live on the same diagram. A feature is judged by what it costs the back-office as much as what it gives the user.'],
          ['User goals · business goals', 'A workout suggestion that doesn\'t move a business metric is a hobby. A business metric that hurts the user is a leak.'],
          ['Reduce, then add', 'Cut the journey down to the moments that actually matter. Decoration comes last, if at all.'],
        ].map(([t, d], i) => (
          <FTReveal key={t} delay={i * 70}>
            <div style={{ padding: 24, borderRadius: 14,
                            border: `1px solid ${FT_LINE}`,
                            background: 'rgba(0,0,0,.2)', height: '100%',
                            display: 'flex', flexDirection: 'column', gap: 14 }}>
              <span style={{ width: 28, height: 2, background: FT_ACCENT, borderRadius: 999 }} />
              <div style={{ fontFamily: 'Libre Bodoni, serif', fontSize: 22, color: FT_FG,
                              fontWeight: 500, letterSpacing: '-.01em' }}>{t}</div>
              <FTBody size={13.5} opacity={.72}>{d}</FTBody>
            </div>
          </FTReveal>
        ))}
      </div>
    </div>
  </FTSection>
);

// ── Personas ───────────────────────────────────────────────────────────────
const FTPersonas = () => {
  const personas = [
    {
      initials: 'AK', name: 'Anna · 34', role: 'Returning to training after a break',
      goals: ['Rebuild a consistent routine', 'Track recovery and supplements', 'See a clear "next step"'],
      pains: ['Forgets passwords on new devices', 'Hard to find a credible specialist', 'No-context recommendations'],
    },
    {
      initials: 'MN', name: 'Michał · 27', role: 'Strength training, muscle mass focus',
      goals: ['Plan supplementation properly', 'History of all sessions in one place', 'Recommendations he can trust'],
      pains: ['Survey-form fatigue', 'Marketing-y "specialist" lists', 'No reviews from real users'],
    },
    {
      initials: 'PD', name: 'Paulina · 41', role: 'Post-injury, working with a physio',
      goals: ['Follow specialist recommendations', 'Share her plan with the physio', 'Slow, sustainable progress'],
      pains: ['Email-based plans get lost', 'No way to ask the specialist back', 'Generic recovery advice'],
    },
  ];
  return (
    <FTSection bg={FT_SURFACE} style={{ borderTop: `1px solid ${FT_LINE}`, borderBottom: `1px solid ${FT_LINE}` }}>
      <div style={{ maxWidth: 1280 }}>
        <FTReveal>
          <FTEyebrow>Research · personas</FTEyebrow>
          <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
            Three users. <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>One product.</span>
          </FTHeading>
          <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
            Built from interviews and behavioural insights. Each persona maps onto a
            distinct path through the product — but the goals, pains and chances they
            share is where the shared product lives.
          </FTBody>
        </FTReveal>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 24 }}>
          {personas.map((p, i) => (
            <FTReveal key={p.initials} delay={i * 90}>
              <div style={{ padding: 28, borderRadius: 16,
                              border: `1px solid ${FT_LINE}`,
                              background: `linear-gradient(180deg, ${FT_BG} 0%, rgba(0,0,0,.2) 100%)`,
                              display: 'flex', flexDirection: 'column', gap: 18, height: '100%' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                  <div style={{
                    width: 52, height: 52, borderRadius: '50%',
                    background: `radial-gradient(circle at 30% 30%, ${FT_ACCENT}, ${FT_ACCENT}aa)`,
                    boxShadow: `0 0 24px ${FT_ACCENT}55`,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontFamily: 'Libre Bodoni, serif', fontStyle: 'italic',
                    color: '#fff', fontSize: 18, fontWeight: 500,
                  }}>{p.initials}</div>
                  <div>
                    <div style={{ fontFamily: 'Libre Bodoni, serif', fontWeight: 500,
                                    fontSize: 22, color: FT_FG, letterSpacing: '-.01em' }}>{p.name}</div>
                    <div style={{ fontFamily: 'DM Sans, sans-serif', fontSize: 12.5,
                                    color: FT_MUTED, marginTop: 2 }}>{p.role}</div>
                  </div>
                </div>
                <div>
                  <FTEyebrow color={FT_ACCENT}>Goals</FTEyebrow>
                  <ul style={{ margin: '10px 0 0', padding: 0, listStyle: 'none',
                                 display: 'flex', flexDirection: 'column', gap: 6 }}>
                    {p.goals.map((g) => (
                      <li key={g} style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
                        <span style={{ width: 5, height: 5, borderRadius: '50%',
                                         background: FT_ACCENT, marginTop: 8, flexShrink: 0 }} />
                        <FTBody size={13.5} opacity={.82}>{g}</FTBody>
                      </li>
                    ))}
                  </ul>
                </div>
                <div>
                  <FTEyebrow>Pain points</FTEyebrow>
                  <ul style={{ margin: '10px 0 0', padding: 0, listStyle: 'none',
                                 display: 'flex', flexDirection: 'column', gap: 6 }}>
                    {p.pains.map((g) => (
                      <li key={g} style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
                        <span style={{ width: 5, height: 5, borderRadius: '50%',
                                         background: FT_DIM, marginTop: 8, flexShrink: 0 }} />
                        <FTBody size={13.5} opacity={.7}>{g}</FTBody>
                      </li>
                    ))}
                  </ul>
                </div>
              </div>
            </FTReveal>
          ))}
        </div>
      </div>
    </FTSection>
  );
};

// ── Customer Journey Map — styled as table-like rows in the cool grey palette
const FTJourney = () => {
  const stages = [
    { name: 'Motivation',       sat: 3,  cb: 'Desire to improve well-being, build muscle, aid recovery.', tp: '—', pain: '—', chance: '—' },
    { name: 'Search info',      sat: 4,  cb: 'Asking about supplementation.', tp: 'Buzz marketing', pain: '—', chance: '—' },
    { name: 'Sign in',          sat: 2,  cb: 'Signing in via existing account.', tp: 'Sign in', pain: 'Forgot password', chance: 'Reset password to email' },
    { name: 'Survey',           sat: 4,  cb: 'Fills the survey.', tp: 'Survey', pain: '—', chance: '—' },
    { name: 'History',          sat: 4,  cb: 'Reviews workout history.', tp: 'History · fitness card', pain: '—', chance: '—' },
    { name: 'Recommendation',   sat: 3,  cb: 'Sees personalised suggestions.', tp: 'Landing page', pain: 'Hard to find a specialist', chance: 'Add specialists with profile descriptions' },
    { name: 'Send',             sat: 4,  cb: 'Sends recommendations to email.', tp: 'Send email', pain: '—', chance: '—' },
    { name: 'Share opinion',    sat: 2,  cb: 'Shares opinion via social / SMS / newsletter.', tp: 'Social · Newsletter · SMS', pain: 'No customer reviews', chance: 'Ask for feedback by email/SNS' },
  ];

  const satGlyph = (s) => s >= 4 ? '☺' : s >= 3 ? '〇' : '☹';
  const satColor = (s) => s >= 4 ? FT_ACCENT : s >= 3 ? FT_MUTED : '#FF8A8A';

  return (
    <FTSection style={{ borderTop: `1px solid ${FT_LINE}` }}>
      <div style={{ maxWidth: 1280 }}>
        <FTReveal>
          <FTEyebrow>Customer journey</FTEyebrow>
          <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
            Eight stages. <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>Two satisfaction dips.</span>
          </FTHeading>
          <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
            The CJM made design priorities self-evident. The two clearest dips —
            sign-in and share-opinion — became the two product bets: password reset
            via email, and review/feedback loops baked into the experience.
          </FTBody>
        </FTReveal>

        {/* Satisfaction line chart */}
        <FTReveal delay={120}>
          <div style={{
            padding: 'clamp(28px, 3vw, 40px)', borderRadius: 16,
            border: `1px solid ${FT_LINE}`,
            background: `linear-gradient(180deg, ${FT_SURFACE} 0%, ${FT_BG} 100%)`,
            marginBottom: 32,
          }}>
            <FTEyebrow color={FT_ACCENT}>Satisfaction line</FTEyebrow>
            <svg viewBox="0 0 1200 240" width="100%" height="200"
                 style={{ marginTop: 18, display: 'block' }}>
              <defs>
                <linearGradient id="satFill" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor={FT_ACCENT} stopOpacity="0.35" />
                  <stop offset="100%" stopColor={FT_ACCENT} stopOpacity="0" />
                </linearGradient>
              </defs>
              {/* Grid */}
              {[0, 1, 2, 3, 4].map(y => (
                <line key={y} x1="40" x2="1180" y1={40 + y * 40} y2={40 + y * 40}
                      stroke={FT_LINE} strokeWidth="1" strokeDasharray="2 4" />
              ))}
              {/* Curve */}
              {(() => {
                const xs = stages.map((_, i) => 40 + (i * (1140 / (stages.length - 1))));
                const ys = stages.map((s) => 40 + (4 - s.sat) * 40);
                const pts = xs.map((x, i) => `${x},${ys[i]}`).join(' L ');
                const fill = `M 40,200 L ${pts} L 1180,200 Z`;
                const stroke = `M ${pts}`;
                return (
                  <>
                    <path d={fill} fill="url(#satFill)" />
                    <path d={stroke} fill="none" stroke={FT_ACCENT} strokeWidth="2.5" />
                    {xs.map((x, i) => (
                      <circle key={i} cx={x} cy={ys[i]} r="6"
                              fill={stages[i].sat <= 2 ? '#FF8A8A' : FT_ACCENT}
                              stroke={FT_BG} strokeWidth="3" />
                    ))}
                  </>
                );
              })()}
              {/* Stage labels */}
              {stages.map((s, i) => {
                const x = 40 + (i * (1140 / (stages.length - 1)));
                return (
                  <text key={s.name} x={x} y={230} textAnchor="middle"
                        fontFamily="DM Sans, sans-serif" fontSize="11"
                        fontWeight="600" letterSpacing="1"
                        fill={s.sat <= 2 ? '#FF8A8A' : FT_MUTED}>
                    {s.name.toUpperCase()}
                  </text>
                );
              })}
            </svg>
          </div>
        </FTReveal>

        {/* Table rows */}
        <FTReveal delay={180}>
          <div style={{ borderRadius: 16, overflow: 'hidden',
                          border: `1px solid ${FT_LINE}`, background: FT_SURFACE }}>
            <div style={{ display: 'grid',
                            gridTemplateColumns: '140px 1fr 1fr 60px 1fr 1fr',
                            fontFamily: 'DM Sans, sans-serif', fontSize: 10,
                            letterSpacing: '.18em', textTransform: 'uppercase',
                            color: FT_DIM, fontWeight: 600,
                            padding: '14px 20px', borderBottom: `1px solid ${FT_LINE}`,
                            background: 'rgba(0,0,0,.18)' }}>
              <span>Stage</span><span>Customer behaviour</span><span>Touchpoints</span>
              <span style={{ textAlign: 'center' }}>Sat</span><span>Pain</span><span>Chance</span>
            </div>
            {stages.map((s, i) => (
              <div key={s.name} style={{
                display: 'grid',
                gridTemplateColumns: '140px 1fr 1fr 60px 1fr 1fr',
                fontFamily: 'DM Sans, sans-serif', fontSize: 13,
                color: FT_FG, padding: '16px 20px',
                borderTop: i ? `1px solid ${FT_LINE}` : 'none',
                alignItems: 'start',
              }}>
                <span style={{ fontFamily: 'Libre Bodoni, serif', fontSize: 16,
                                 color: FT_FG, fontWeight: 500, letterSpacing: '-.01em' }}>{s.name}</span>
                <span style={{ opacity: .85 }}>{s.cb}</span>
                <span style={{ opacity: .7 }}>{s.tp}</span>
                <span style={{ textAlign: 'center', color: satColor(s.sat),
                                 fontSize: 18 }}>{satGlyph(s.sat)}</span>
                <span style={{ opacity: s.pain === '—' ? .35 : .85,
                                 color: s.pain === '—' ? FT_DIM : '#FF8A8A' }}>{s.pain}</span>
                <span style={{ opacity: s.chance === '—' ? .35 : .85,
                                 color: s.chance === '—' ? FT_DIM : FT_ACCENT }}>{s.chance}</span>
              </div>
            ))}
          </div>
        </FTReveal>
      </div>
    </FTSection>
  );
};

// ── Service Blueprint — layered swim-lane diagram
const FTBlueprint = () => {
  const cols = ['Sign in', 'Survey', 'Workout history', 'Recommendation', 'Send'];
  const lanes = [
    { label: 'Physical evidence', items: ['Login panel · HCK', 'Survey · HCK · fitness card', 'History · screen to add workouts', 'Recommendation · Behaviolitics', 'Email screen'] },
    { label: 'User action',       items: ['Sign in to HCK', 'Fill the survey', 'Add workout history', 'Review suggested recommendations', 'Send recommendations via email'] },
    { label: 'Front-stage · staff', items: ['Trainer note · reception', '—', '—', '—', '—'] },
    { label: 'Technology',         items: ['Login screen', 'Survey form', 'Workout add screen', 'Landing page', '—'] },
    { label: 'Back-stage',         items: ['—', 'Fetch fitness-card + history', 'Pull history', 'Analyse + match recommendations', '—'] },
    { label: 'Support · Behaviolitics', items: ['—', 'Verify data · score Fitness Level', 'Verify history · update Fitness Level', 'Data analysis', '—'] },
  ];

  return (
    <FTSection bg={FT_SURFACE} style={{ borderTop: `1px solid ${FT_LINE}`, borderBottom: `1px solid ${FT_LINE}` }}>
      <div style={{ maxWidth: 1280 }}>
        <FTReveal>
          <FTEyebrow>Service blueprint</FTEyebrow>
          <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
            What the user sees. <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>What it costs the system.</span>
          </FTHeading>
          <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
            The blueprint pulls front-stage and back-stage onto one diagram. Every column
            is a stage of the journey; every row is a layer of the service. Lines of
            interaction, visibility and internal-interaction separate the layers.
          </FTBody>
        </FTReveal>

        <FTReveal delay={120}>
          <div style={{ borderRadius: 16, overflow: 'auto',
                          border: `1px solid ${FT_LINE}`, background: FT_BG,
                          scrollbarColor: `${FT_ACCENT}66 transparent`, scrollbarWidth: 'thin' }}>
            {/* Column headers */}
            <div style={{ display: 'grid',
                            gridTemplateColumns: `180px repeat(${cols.length}, minmax(180px, 1fr))`,
                            fontFamily: 'DM Sans, sans-serif', fontSize: 10,
                            letterSpacing: '.18em', textTransform: 'uppercase',
                            color: FT_DIM, fontWeight: 600,
                            borderBottom: `1px solid ${FT_LINE}`, background: 'rgba(0,0,0,.18)' }}>
              <div style={{ padding: '16px 18px' }}>Stage →</div>
              {cols.map((c) => (
                <div key={c} style={{ padding: '16px 18px',
                                        borderLeft: `1px solid ${FT_LINE}`,
                                        color: FT_FG }}>{c}</div>
              ))}
            </div>

            {/* Lanes */}
            {lanes.map((lane, li) => {
              // Divider lines: after Action (user) row → line of interaction
              //                after Technology row     → line of visibility
              //                after Back-stage row     → line of internal interaction
              const divider = li === 1 ? 'interaction' : li === 3 ? 'visibility' : li === 4 ? 'internal' : null;
              return (
                <React.Fragment key={lane.label}>
                  <div style={{
                    display: 'grid',
                    gridTemplateColumns: `180px repeat(${cols.length}, minmax(180px, 1fr))`,
                    background: li === 1 ? `${FT_ACCENT}08` : 'transparent',
                  }}>
                    <div style={{ padding: '20px 18px',
                                    fontFamily: 'DM Sans, sans-serif', fontSize: 11,
                                    color: FT_MUTED, fontWeight: 600,
                                    letterSpacing: '.08em', textTransform: 'uppercase',
                                    borderRight: `1px solid ${FT_LINE}` }}>{lane.label}</div>
                    {lane.items.map((it, i) => (
                      <div key={i} style={{
                        padding: '12px 14px',
                        borderLeft: i ? `1px solid ${FT_LINE}` : 'none',
                        display: 'flex', alignItems: 'center',
                      }}>
                        {it === '—' ? (
                          <span style={{ color: FT_DIM, fontSize: 14, opacity: .5 }}>—</span>
                        ) : (
                          <div style={{
                            padding: '10px 14px', borderRadius: 8,
                            border: `1px solid ${li === 1 ? FT_ACCENT + '66' : FT_LINE}`,
                            background: li === 1 ? `${FT_ACCENT}14` : 'rgba(0,0,0,.18)',
                            fontFamily: 'DM Sans, sans-serif', fontSize: 12.5,
                            color: FT_FG, lineHeight: 1.4, width: '100%',
                          }}>{it}</div>
                        )}
                      </div>
                    ))}
                  </div>
                  {divider && (
                    <div style={{
                      display: 'grid',
                      gridTemplateColumns: `180px 1fr`, alignItems: 'center',
                    }}>
                      <div style={{ padding: '10px 18px',
                                      fontFamily: 'DM Sans, sans-serif', fontSize: 9.5,
                                      letterSpacing: '.18em', textTransform: 'uppercase',
                                      color: FT_DIM, fontWeight: 600, fontStyle: 'italic' }}>
                        {divider === 'interaction' ? 'Line of interaction' :
                         divider === 'visibility'  ? 'Line of visibility' :
                                                     'Internal interaction'}
                      </div>
                      <div style={{ height: 1,
                                      borderTop: `1px ${divider === 'visibility' ? 'solid' : 'dashed'} ${FT_LINE}`,
                                      margin: '0 18px' }} />
                    </div>
                  )}
                </React.Fragment>
              );
            })}
          </div>
        </FTReveal>

        <FTReveal delay={220}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 24, marginTop: 24,
                          flexWrap: 'wrap', fontFamily: 'DM Sans, sans-serif', fontSize: 11,
                          color: FT_DIM }}>
            <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ width: 14, height: 1.5,
                              borderTop: `1.5px dashed ${FT_LINE}`, display: 'inline-block' }} />
              Line of interaction
            </span>
            <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ width: 14, height: 0, borderTop: `1.5px solid ${FT_LINE}` }} />
              Line of visibility
            </span>
            <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ width: 14, height: 1.5,
                              borderTop: `1.5px dashed ${FT_LINE}`, display: 'inline-block' }} />
              Internal interaction
            </span>
          </div>
        </FTReveal>
      </div>
    </FTSection>
  );
};

// ── User flow visualization ─────────────────────────────────────────────────
const FTFlow = () => (
  <FTSection style={{ borderTop: `1px solid ${FT_LINE}` }}>
    <div style={{ maxWidth: 1280 }}>
      <FTReveal>
        <FTEyebrow>User flow</FTEyebrow>
        <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
          From start screen to <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>email-out.</span>
        </FTHeading>
        <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
          A single map of every decision a user can take in the app — onboarding,
          fitness survey, recommendations branching to supplements and specialists,
          and the workout history that loops back to the dashboard.
        </FTBody>
      </FTReveal>

      <FTReveal delay={120}>
        <div style={{
          borderRadius: 16, overflow: 'hidden',
          border: `1px solid ${FT_LINE}`,
          background: '#fff',
          position: 'relative',
        }}>
          <img src="case-assets/fitness/user-flow.jpg" alt="User flow diagram"
               style={{ width: '100%', height: 'auto', display: 'block' }} />
        </div>
      </FTReveal>

      <FTReveal delay={200}>
        <div style={{ display: 'grid',
                        gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
                        gap: 24, marginTop: 32 }}>
          {[
            ['Branching paths', 'Yes / no decisions visualised as diamonds; happy paths in red, default flow in black.'],
            ['Two landing pages', 'Personalised vs default — depends on whether the survey is complete. Avoids cold dashboards.'],
            ['Recoverable forks', 'Every decision the user takes can be reversed within the same flow. No "Survey done" trap.'],
          ].map(([t, d], i) => (
            <div key={t} style={{ display: 'flex', flexDirection: 'column', gap: 8,
                                    paddingTop: 18, borderTop: `1px solid ${FT_LINE}` }}>
              <div style={{ fontFamily: 'Libre Bodoni, serif', fontSize: 20,
                              color: FT_FG, fontWeight: 500, letterSpacing: '-.01em' }}>{t}</div>
              <FTBody size={13.5} opacity={.72}>{d}</FTBody>
            </div>
          ))}
        </div>
      </FTReveal>
    </div>
  </FTSection>
);

// ── The product — landing page in laptop, large
const FTProduct = () => (
  <FTSection bg={FT_SURFACE} style={{ borderTop: `1px solid ${FT_LINE}`, borderBottom: `1px solid ${FT_LINE}` }}>
    <div style={{ maxWidth: 1280 }}>
      <FTReveal>
        <FTEyebrow>The product</FTEyebrow>
        <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 18, maxWidth: 880 }}>
          A dashboard that <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>answers the survey.</span>
        </FTHeading>
        <FTBody size={17} opacity={.78} maxWidth={780} style={{ marginBottom: 56 }}>
          Every card on the landing page maps to a stage of the journey. Personal data
          and trainer up top, fitness level surfaces survey completion, and a triplet
          of personalised cards anchors the recommendation engine.
        </FTBody>
      </FTReveal>

      <FTReveal delay={120}>
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <FTLaptop src="case-assets/fitness/landing-page.jpg" alt="Fitness landing page" width={920} />
        </div>
      </FTReveal>

      <FTReveal delay={200}>
        <div style={{ display: 'grid',
                        gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
                        gap: 24, marginTop: 48 }}>
          {[
            ['Twoje dane',          'Identity at the top — keeps the dashboard human.'],
            ['Trener personalny',   'Pulled in from the recommendations layer.'],
            ['Fitness level',       'A direct callback to the survey step.'],
            ['Suplementy',          'Recommendation engine output, with an "ask for more" path.'],
            ['Specjaliści',         'Pain point answered — clear profiles, contact, more info.'],
            ['Historia treningów',  'CJM stage 5 surfaced — workouts as table, addable inline.'],
          ].map(([t, d]) => (
            <div key={t} style={{ display: 'flex', flexDirection: 'column', gap: 6,
                                    paddingTop: 14, borderTop: `1px solid ${FT_LINE}` }}>
              <div style={{ fontFamily: 'Libre Bodoni, serif', fontSize: 18,
                              color: FT_FG, fontWeight: 500, letterSpacing: '-.01em' }}>{t}</div>
              <FTBody size={13} opacity={.7}>{d}</FTBody>
            </div>
          ))}
        </div>
      </FTReveal>
    </div>
  </FTSection>
);

// ── Outcome
const FTOutcome = () => {
  const stats = [
    ['3', 'Personas built', 'From interviews + behaviour. Each tied to a measurable goal.'],
    ['1', 'Service blueprint', 'Front-stage and back-stage on one diagram — visible to product, dev, ops.'],
    ['8', 'Journey stages mapped', 'Two satisfaction dips became the first two product bets.'],
  ];
  return (
    <FTSection style={{ borderTop: `1px solid ${FT_LINE}` }}>
      <div style={{ maxWidth: 1280 }}>
        <FTReveal>
          <FTEyebrow>Outcome</FTEyebrow>
          <FTHeading size={'clamp(36px, 3.8vw, 56px)'} style={{ marginTop: 14, marginBottom: 64, maxWidth: 760 }}>
            Service designed, <span style={{ fontStyle: 'italic', color: FT_ACCENT }}>product followed.</span>
          </FTHeading>
        </FTReveal>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 48 }}>
          {stats.map(([n, label, desc], i) => (
            <FTReveal key={label} delay={i * 110}>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 14,
                              paddingTop: 24, borderTop: `1px solid ${FT_LINE}` }}>
                <div style={{ fontFamily: 'Libre Bodoni, serif', fontWeight: 500,
                                fontSize: 'clamp(48px, 5.4vw, 78px)', lineHeight: 1, color: FT_ACCENT,
                                letterSpacing: '-.02em', textShadow: `0 0 32px ${FT_ACCENT}33` }}>{n}</div>
                <div style={{ fontFamily: 'DM Sans, sans-serif', fontSize: 14, color: FT_FG,
                                letterSpacing: '.14em', textTransform: 'uppercase', fontWeight: 600 }}>{label}</div>
                <FTBody size={14.5} opacity={.7} maxWidth={300}>{desc}</FTBody>
              </div>
            </FTReveal>
          ))}
        </div>
      </div>
    </FTSection>
  );
};

// ── Modal shell ─────────────────────────────────────────────────────────────
const FitnessCaseStudy = ({ open, onClose }) => {
  React.useEffect(() => {
    if (!open) return undefined;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = prev; };
  }, [open]);

  React.useEffect(() => {
    if (!open) return undefined;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);

  const scrollRef = React.useRef(null);
  const [progress, setProgress] = React.useState(0);
  const onScroll = (e) => {
    const el = e.currentTarget;
    const max = el.scrollHeight - el.clientHeight;
    setProgress(max > 0 ? el.scrollTop / max : 0);
  };
  React.useEffect(() => {
    if (open && scrollRef.current) { scrollRef.current.scrollTop = 0; setProgress(0); }
  }, [open]);

  return (
    <div aria-hidden={!open}
         style={{ position: 'fixed', inset: 0, zIndex: 100,
                   pointerEvents: open ? 'auto' : 'none' }}>
      <div onClick={onClose} style={{
        position: 'absolute', inset: 0, background: 'rgba(0,0,0,.55)',
        opacity: open ? 1 : 0, transition: 'opacity .5s ease',
        backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
      }} />

      <div ref={scrollRef} onScroll={onScroll}
           style={{
             position: 'absolute', inset: 0,
             background: FT_BG, color: FT_FG,
             transform: open ? 'translateY(0)' : 'translateY(40px)',
             opacity: open ? 1 : 0,
             transition: 'transform .55s cubic-bezier(.5,0,.2,1), opacity .45s ease',
             overflowY: 'auto', overflowX: 'hidden',
             scrollbarColor: `${FT_ACCENT}66 transparent`,
           }}>
        <style>{`
          @keyframes ftMeshDrift {
            0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
            50%      { transform: translate3d(-20px, 12px, 0) scale(1.04); }
          }
          .ft-mesh { animation: ftMeshDrift 14s ease-in-out infinite; }
        `}</style>

        <div style={{
          position: 'sticky', top: 0, zIndex: 50,
          background: `linear-gradient(${FT_BG} 70%, ${FT_BG}00)`,
          padding: '20px max(56px, 5vw)',
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <button onClick={onClose} style={{
              appearance: 'none', border: 'none', background: 'none', padding: 6,
              color: FT_FG, cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 12,
              fontFamily: 'DM Sans, sans-serif', fontSize: 12,
              letterSpacing: '.18em', textTransform: 'uppercase', fontWeight: 600,
            }}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <path d="M19 12H5M11 6l-6 6 6 6" stroke="currentColor" strokeWidth="1.6"
                      strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Back to portfolio</span>
            </button>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 18 }}>
              <FTEyebrow>Case 04 · Fitness</FTEyebrow>
              <button onClick={onClose} aria-label="Close" style={{
                appearance: 'none', border: 'none', background: 'none', cursor: 'pointer',
                color: FT_FG, padding: 6, display: 'inline-flex',
              }}>
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                  <path d="M6 6l12 12M18 6L6 18" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
                </svg>
              </button>
            </div>
          </div>
          <div style={{ position: 'relative', height: 1.5, marginTop: 16,
                         background: FT_LINE, borderRadius: 999 }}>
            <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0,
                             width: `${progress * 100}%`, background: FT_ACCENT,
                             borderRadius: 999, transition: 'width .1s linear' }} />
          </div>
        </div>

        <FTHero />
        <FTPrinciples />
        <FTPersonas />
        <FTJourney />
        <FTBlueprint />
        <FTFlow />
        <FTProduct />
        <FTOutcome />

        <FTSection py={72} style={{ borderTop: `1px solid ${FT_LINE}` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                          flexWrap: 'wrap', gap: 32 }}>
            <div>
              <FTEyebrow>End of case · 04 / 04</FTEyebrow>
              <FTHeading size={32} style={{ marginTop: 8 }}>Thanks for reading.</FTHeading>
            </div>
            <button onClick={onClose} style={{
              appearance: 'none', border: `1px solid ${FT_LINE}`, background: 'transparent',
              color: FT_FG, padding: '18px 32px', borderRadius: 999, cursor: 'pointer',
              fontFamily: 'DM Sans, sans-serif', fontSize: 13,
              letterSpacing: '.18em', textTransform: 'uppercase', fontWeight: 600,
              display: 'inline-flex', alignItems: 'center', gap: 14,
            }}>
              <span>Back to portfolio</span>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none">
                <path d="M19 12H5M11 6l-6 6 6 6" stroke="currentColor" strokeWidth="1.6"
                      strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
          </div>
        </FTSection>
      </div>
    </div>
  );
};

Object.assign(window, { FitnessCaseStudy });
