// The work on the left, what it costs on the right, and an arrow in the gutter
// saying the first causes the second. Hovering a group of work lights the
// consequences it drives; when nobody is interacting the section walks itself
// through the groups.
function TheWork() {
  const groups = [
    {
      key: 'close',
      label: 'Books & close',
      items: [
        'A chart of accounts built for your model',
        'Expenses categorized correctly, every month',
        'The monthly close run and landed on a date',
        'Your accountants managed',
      ],
      slips: [0, 3],
    },
    {
      key: 'cash',
      label: 'Cash & payables',
      items: [
        'Bills paid on time',
        'Enough cash in the operating account to cover them',
        'Idle balances earning interest',
      ],
      slips: [1, 3],
    },
    {
      key: 'billing',
      label: 'Billing & collections',
      items: [
        'Accurate invoices out on the first',
        'Customers paying on terms',
      ],
      slips: [1, 3],
    },
    {
      key: 'planning',
      label: 'Planning & modeling',
      items: [
        'An operating model tied to your hiring plan',
        'The annual plan and budget',
        'Expense rules and budgets so costs don’t drift',
        'Salary and equity numbers that hold up',
      ],
      slips: [1, 2],
    },
    {
      key: 'board',
      label: 'Investors & board',
      items: [
        'The metrics your next raise turns on, tracked',
        'Board decks that show progress and name the problems',
        'Investor updates written and sent',
      ],
      slips: [2, 4],
    },
    {
      key: 'capital',
      label: 'Capital & transactions',
      items: [
        'Cloud commitments negotiated',
        'Debt facilities sourced and negotiated',
        'Buy-side or sell-side diligence',
        '409A valuations on schedule',
        'Audit readiness',
      ],
      slips: [2, 3],
    },
  ];

  const slips = [
    'Books close late.',
    'Cash flow is poorly modeled and runway is uncertain.',
    'The metrics that matter go untracked and unimproved.',
    'Your time goes to clerical work instead of the decisions that determine whether this works.',
    'Board decks become a scramble.',
  ];

  const CYCLE_MS = 3600;
  const [active, setActive] = React.useState(0);
  const [pinned, setPinned] = React.useState(false);
  const [seen, setSeen] = React.useState(false);
  const [stacked, setStacked] = React.useState(false);
  const ref = React.useRef(null);

  // Below 900px the two columns stack and the spotlight has nothing left to
  // point at, so the whole thing goes static rather than tinting labels for a
  // connection the reader can no longer see.
  React.useEffect(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia('(max-width: 900px)');
    const sync = () => setStacked(mq.matches);
    sync();
    mq.addEventListener('change', sync);
    return () => mq.removeEventListener('change', sync);
  }, []);

  // Don't animate a section nobody is looking at
  React.useEffect(() => {
    const el = ref.current;
    if (!el || typeof IntersectionObserver === 'undefined') { setSeen(true); return; }
    const io = new IntersectionObserver(([e]) => setSeen(e.isIntersecting), { threshold: 0.25 });
    io.observe(el);
    return () => io.disconnect();
  }, []);

  React.useEffect(() => {
    if (pinned || !seen || stacked) return;
    const id = setTimeout(() => setActive((i) => (i + 1) % groups.length), CYCLE_MS);
    return () => clearTimeout(id);
  }, [active, pinned, seen, stacked]);

  const lit = stacked ? [] : groups[active].slips;

  return (
    <section ref={ref} id="the-work" className="section">
      <style>{`
        @keyframes workProg { from { transform: scaleX(0) } to { transform: scaleX(1) } }

        /* Three columns: the work, the arrow that says it causes the rest,
           and what slips. The middle column is the gutter. */
        .work-grid {
          margin-top: 36px;
          display: grid;
          grid-template-columns: 1.46fr 104px 1fr;
          align-items: stretch;
        }
        .work-groups {
          column-count: 2;
          column-gap: 16px;
        }
        .work-group {
          break-inside: avoid;
          -webkit-column-break-inside: avoid;
          display: inline-block;
          width: 100%;
          margin-bottom: 16px;
          padding: 20px 20px 22px;
          border-radius: 14px;
          background: var(--surface-2);
          border: 1px solid var(--hairline);
          -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
          cursor: default;
          transition: border-color 420ms var(--ease), background 420ms var(--ease),
                      box-shadow 420ms var(--ease), transform 420ms var(--ease);
        }
        .work-group:hover { transform: translateY(-2px); }
        .work-group.is-on {
          background: var(--surface-3);
          border-color: rgba(16,185,129,0.26);
          box-shadow:
            0 1px 0 rgba(255,255,255,0.06) inset,
            0 0 40px -18px rgba(16,185,129,0.4),
            0 24px 60px -34px rgba(0,0,0,1);
        }
        .work-group-label {
          font-family: 'JetBrains Mono', ui-monospace, monospace;
          font-size: 11.5px;
          letter-spacing: 0.12em;
          text-transform: uppercase;
          color: var(--ink-3);
          padding-bottom: 11px;
          border-bottom: 1px solid var(--hairline);
          transition: color 420ms var(--ease);
          display: flex; align-items: center; gap: 9px;
        }
        .work-group.is-on .work-group-label { color: var(--emerald); }

        /* the gutter: a hairline spine with a glowing node at its midpoint */
        .work-arrow { display: flex; flex-direction: column; align-items: center; }
        .work-arrow-line {
          flex: 1 1 auto; width: 1px;
          background: linear-gradient(to bottom, transparent, var(--hairline-2) 40%, var(--hairline-2));
        }
        .work-arrow:last-of-type .work-arrow-line { background: var(--hairline-2); }
        .work-arrow-node {
          flex: 0 0 auto;
          width: 48px; height: 48px; border-radius: 999px;
          display: grid; place-items: center;
          background: rgba(16,185,129,0.07);
          border: 1px solid rgba(16,185,129,0.3);
          margin: 16px 0;
          box-shadow: 0 0 36px -8px rgba(16,185,129,0.4),
                      0 0 0 6px rgba(16,185,129,0.04);
          animation: pulseRing 3.2s ease-out infinite;
        }

        /* the consequences, as cards that light when their cause is active */
        .work-slip {
          display: grid; grid-template-columns: 26px 1fr;
          gap: 14px; align-items: start;
          padding: 17px 20px;
          margin-bottom: 10px;
          border-radius: 13px;
          border: 1px solid transparent;
          transition: opacity 420ms var(--ease), background 420ms var(--ease),
                      border-color 420ms var(--ease), box-shadow 420ms var(--ease),
                      transform 420ms var(--ease);
        }
        .work-slip-tick {
          margin-top: 13px; height: 1px;
          background: var(--hairline-2);
          transition: background 420ms var(--ease), box-shadow 420ms var(--ease);
        }
        .work-slip.is-on {
          background: var(--surface-2);
          border-color: var(--hairline);
          transform: translateX(3px);
          box-shadow: 0 1px 0 rgba(255,255,255,0.05) inset,
                      0 20px 50px -38px rgba(0,0,0,1);
        }
        .work-slip.is-on .work-slip-tick {
          background: var(--emerald);
          box-shadow: 0 0 12px rgba(16,185,129,0.8);
        }

        @media (max-width: 1100px) {
          .work-grid { grid-template-columns: 1.3fr 80px 1fr; }
        }
        @media (max-width: 900px) {
          .work-grid { grid-template-columns: 1fr !important; }
          /* stacked, the arrow turns to point down the page instead of across */
          .work-arrow { flex-direction: row !important; padding: 16px 0 !important; }
          .work-arrow-line { width: auto !important; height: 1px !important; background: var(--hairline-2) !important; }
          .work-arrow-node { margin: 0 16px !important; }
          .work-arrow svg { transform: rotate(90deg); }
          .work-group, .work-slip { opacity: 1 !important; }
          .work-slip {
            background: var(--surface-2);
            border-color: var(--hairline);
          }
          .work-prog { display: none !important; }
        }
        @media (max-width: 640px) {
          .work-groups { column-count: 1 !important; }
        }
      `}</style>

      <div className="shell">
        {/* Line one ends on "time". The cap is in ems, not pixels, so the break
            holds as the clamp scales the type down: line one is 11.14em and
            pulling "that" up would take 12.57em, so 11.8em splits them at every
            size. Instrument Serif ships regular and italic only - no bold - so
            "time" is emphasised with the italic and the sand accent rather than
            a weight the browser would have to fake. */}
        <window.NlReveal>
          <h2 style={{ ...window.nlHeadingStyle, maxWidth: '11.8em' }}>
            Running finance well requires{' '}
            <span style={window.nlAccentStyle}>time</span>
            {' '}that founders don’t have.
          </h2>
        </window.NlReveal>

        <div className="work-grid">

          {/* LEFT: the work */}
          <window.NlReveal delay={80}>
            <div onMouseLeave={() => setPinned(false)}>
              <NlColumnLabel>Core finance tasks</NlColumnLabel>
              <div className="work-groups" style={{ marginTop: 26 }}>
                {groups.map((g, i) => {
                  const on = !stacked && i === active;
                  return (
                    <div
                      key={g.key}
                      className={on ? 'work-group is-on' : 'work-group'}
                      onMouseEnter={() => { setPinned(true); setActive(i); }}
                      style={{ position: 'relative' }}>

                      <div className="work-group-label">
                        <window.NlDot on={on} size={5} />
                        {g.label}
                      </div>

                      {on && !pinned &&
                      <span
                        key={`p-${active}`}
                        className="work-prog"
                        style={{
                          position: 'absolute', left: 20, right: 20, top: 48, height: 1,
                          background: 'var(--emerald)',
                          boxShadow: '0 0 10px rgba(16,185,129,.8)',
                          transformOrigin: 'left',
                          animation: `workProg ${CYCLE_MS}ms linear forwards`,
                        }} />
                      }

                      <ul style={{
                        margin: '14px 0 0', padding: 0, listStyle: 'none',
                        display: 'flex', flexDirection: 'column', gap: 9,
                      }}>
                        {g.items.map((t, j) =>
                          <li key={j} style={{
                            display: 'grid', gridTemplateColumns: '5px 1fr', gap: 12,
                            fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-2)',
                          }}>
                            <span style={{ marginTop: 8 }}>
                              <window.NlDot on={on} size={5} />
                            </span>
                            <span>{t}</span>
                          </li>
                        )}
                      </ul>
                    </div>);
                })}
              </div>
            </div>
          </window.NlReveal>

          {/* MIDDLE: the causation arrow */}
          <div className="work-arrow" aria-hidden="true">
            <span className="work-arrow-line" />
            <span className="work-arrow-node">
              <svg width="18" height="12" viewBox="0 0 17 12" fill="none">
                <path d="M1 6h14M10.5 1.2 15.6 6l-5.1 4.8"
                  stroke="var(--emerald)" strokeWidth="1.4"
                  strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </span>
            <span className="work-arrow-line" />
          </div>

          {/* RIGHT: what it costs */}
          <div>
            <NlColumnLabel>What often slips</NlColumnLabel>
            <div style={{ marginTop: 26 }}>
              {slips.map((t, i) => {
                const on = lit.indexOf(i) !== -1;
                return (
                  <div
                    key={i}
                    className={on ? 'work-slip is-on' : 'work-slip'}
                    style={{ opacity: on ? 1 : 0.42 }}>
                    <span className="work-slip-tick" />
                    <span className="serif" style={{
                      fontSize: 21, lineHeight: 1.3,
                      color: on ? 'var(--ink)' : 'var(--ink-2)',
                      transition: 'color 420ms var(--ease)',
                    }}>
                      {t}
                    </span>
                  </div>);
              })}
            </div>
          </div>

        </div>
      </div>
    </section>);
}

// One label treatment for both columns, centred over the content it heads and
// set to a common width so the two read as a matched pair.
function NlColumnLabel({ children }) {
  return (
    <div style={{ textAlign: 'center' }}>
      <span className="mono" style={{
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        gap: 10,
        width: 'min(340px, 100%)',
        fontSize: 13,
        fontWeight: 500,
        letterSpacing: '0.16em',
        textTransform: 'uppercase',
        color: 'var(--ink)',
        padding: '14px 26px',
        border: '1px solid var(--hairline-2)',
        borderRadius: 999,
        background: 'var(--surface)',
        WebkitBackdropFilter: 'blur(16px)',
        backdropFilter: 'blur(16px)',
        boxShadow: '0 1px 0 rgba(255,255,255,.06) inset, 0 18px 44px -34px rgba(0,0,0,1)',
      }}>
        {children}
      </span>
    </div>);
}

window.TheWork = TheWork;
