---
/**
 * "One platform" bento.
 *
 * Card anatomy follows the reference set rather than a flat panel: a tinted
 * plinth carries a faint texture, a back layer of real product UI bleeds off
 * the card edges and dissolves into a mask fade, and one floating element sits
 * on top with a heavier shadow. Depth comes from the layering, not from borders.
 *
 * Motion is viewport-gated: ambient loops only run while a card is on screen.
 */
import Icon from './Icon.astro';

const threads = [
  { who: 'Jenna Carter', sub: 'Re: quick question on outbound', time: '2m', tag: 'interested', grad: 'from-rose-400 to-amber-400' },
  { who: 'Aman Patel', sub: 'Re: intro from Maya', time: '14m', tag: 'interested', grad: 'from-sky-400 to-indigo-400' },
  { who: 'Lina Park', sub: 'Re: pricing tier?', time: '1h', tag: 'question', grad: 'from-emerald-400 to-teal-400' },
  { who: 'Karim Salah', sub: 'Re: not the right time', time: '3h', tag: 'not now', grad: 'from-violet-400 to-fuchsia-400' },
];

const tagClass = (t: string) =>
  t === 'interested' ? 'bg-emerald-50 text-emerald-700 ring-emerald-200'
  : t === 'question' ? 'bg-sky-50 text-sky-700 ring-sky-200'
  : 'bg-slate-100 text-slate-500 ring-slate-200';

// Warmup ramp, the repo default: start at 10/day, +1/day, ceiling 40.
const ramp = [10, 12, 14, 16, 18, 21, 23, 26, 28, 31, 33, 36, 38, 40, 40];

const providers = [
  { name: 'Gmail', pct: 97 },
  { name: 'Outlook', pct: 95 },
  { name: 'Yahoo', pct: 94 },
];
---

<section class="container-page py-16 md:py-20">
  <div class="max-w-3xl">
    <div class="text-[11px] uppercase tracking-[0.16em] text-[color:var(--brand)] font-semibold mb-4">One platform</div>
    <h2 class="text-[32px] md:text-[48px] font-semibold tracking-[-0.03em] leading-[1.04] text-heading">
      Warmup, sending, inbox, engineered together.
    </h2>
    <p class="mt-4 text-foreground/75 leading-relaxed max-w-2xl">
      The signal one part collects is the signal the next part acts on.
    </p>
  </div>

  <div class="bento mt-12 grid grid-cols-1 md:grid-cols-12 gap-3">
    <!-- ── Unified inbox ──────────────────────────────────────────── -->
    <article class="bento-card md:col-span-7">
      <div class="bento-stage h-[292px]">
        <span class="bento-texture bento-dots"></span>

        <!-- Back layer: the thread list, bleeding off the right edge. -->
        <div class="bento-layer bento-fade-b absolute left-7 right-0 top-7 rounded-tl-[10px] bg-white ring-1 ring-slate-200/70 shadow-[0_10px_30px_-18px_rgb(15_23_42_/_0.25)]">
          <div class="h-9 pl-4 pr-3 border-b border-slate-200 flex items-center gap-2.5">
            <span class="text-[9.5px] uppercase tracking-[0.14em] text-slate-400 font-semibold">Inbox</span>
            <span class="h-3 w-px bg-slate-200"></span>
            <span class="text-[11.5px] text-slate-600 whitespace-nowrap">12 unread across 8 mailboxes</span>
          </div>
          {threads.map((t, i) => (
            <div class="bento-row flex items-center gap-2.5 pl-4 pr-3 py-2.5 border-b border-slate-200/60" style={`--i:${i}`}>
              <span class={`w-6 h-6 rounded-full shrink-0 bg-gradient-to-br ${t.grad}`}></span>
              <div class="min-w-0 flex-1">
                <div class="text-[12px] font-semibold text-slate-900 truncate">{t.who}</div>
                <div class="text-[11.5px] text-slate-500 truncate">{t.sub}</div>
              </div>
              <span class="text-[10px] font-mono text-slate-400 shrink-0">{t.time}</span>
              <span class={`shrink-0 px-1.5 py-0.5 rounded text-[9.5px] font-semibold uppercase tracking-[0.06em] ring-1 whitespace-nowrap ${tagClass(t.tag)}`}>{t.tag}</span>
            </div>
          ))}
        </div>

        <!-- Front layer: the thing that just happened. -->
        <div class="bento-pop absolute left-10 right-10 bottom-5 rounded-[11px] bg-white ring-1 ring-slate-200 shadow-[0_22px_50px_-16px_rgb(15_23_42_/_0.30)] px-3 py-2.5 flex items-center gap-2.5">
          <span class="w-7 h-7 rounded-full shrink-0 bg-gradient-to-br from-rose-400 to-amber-400"></span>
          <div class="min-w-0 flex-1">
            <div class="text-[12px] font-semibold text-slate-900 truncate">Jenna Carter replied</div>
            <div class="text-[11px] text-slate-500 truncate">"Thursday 10am ET works for me."</div>
          </div>
          <span class="hidden sm:inline-flex shrink-0 px-1.5 py-0.5 rounded text-[9.5px] font-semibold uppercase tracking-[0.06em] ring-1 bg-emerald-50 text-emerald-700 ring-emerald-200">interested</span>
          <span class="shrink-0 inline-flex h-7 px-2.5 items-center rounded-md text-[11.5px] font-medium bg-sky-600 text-white">Reply</span>
        </div>
      </div>
      <div class="bento-copy">
        <span class="bento-eyebrow"><Icon name="inbox" size={13} />One inbox</span>
        <h3>Every reply lands in one place</h3>
        <p>Replies from all of your sending addresses arrive together, already sorted by what the person actually said.</p>
      </div>
    </article>

    <!-- ── Warmup ─────────────────────────────────────────────────── -->
    <article class="bento-card md:col-span-5">
      <div class="bento-stage h-[292px]">
        <span class="bento-texture bento-rings"></span>

        <!-- Back layer: the ramp, bleeding off the bottom right. -->
        <div class="bento-fade-r absolute left-7 right-0 bottom-0 h-[168px] flex items-end gap-[4px] pr-2">
          {ramp.map((v, i) => (
            <span
              class="bento-bar flex-1 rounded-t-[3px] bg-gradient-to-t from-sky-500/90 to-sky-300/90 origin-bottom"
              style={`height:${(v / 40) * 100}%; --i:${i}`}
            ></span>
          ))}
        </div>

        <!-- Front layer: today's number. -->
        <div class="bento-pop absolute left-7 top-7 w-[196px] rounded-[11px] bg-white ring-1 ring-slate-200 shadow-[0_22px_50px_-16px_rgb(15_23_42_/_0.30)] p-3.5">
          <div class="flex items-center justify-between">
            <span class="text-[9.5px] uppercase tracking-[0.14em] text-slate-400 font-semibold">Warmup</span>
            <span class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[9.5px] font-semibold bg-emerald-50 text-emerald-700 ring-1 ring-emerald-200">
              <span class="bento-live-dot w-1 h-1 rounded-full bg-emerald-500"></span>healthy
            </span>
          </div>
          <div class="mt-2.5 flex items-baseline gap-1.5">
            <span class="text-[30px] font-light leading-none text-slate-900 tabular-nums">40</span>
            <span class="text-[11.5px] text-slate-500">/ day</span>
          </div>
          <div class="mt-1.5 text-[10.5px] font-mono text-slate-400">up from 10, over 15 days</div>
        </div>
      </div>
      <div class="bento-copy">
        <span class="bento-eyebrow"><Icon name="flame" size={13} />Runs itself</span>
        <h3>Mailboxes that warm themselves up</h3>
        <p>New addresses start slow and build real sending history on their own, so your first campaign is not your first impression.</p>
      </div>
    </article>

    <!-- ── Branching ──────────────────────────────────────────────── -->
    <article class="bento-card md:col-span-4">
      <div class="bento-stage h-[266px]">
        <span class="bento-texture bento-canvas"></span>

        <div class="absolute inset-x-4 top-6">
          <!-- Root -->
          <div class="bento-node mx-auto w-[74%] rounded-[9px] bg-white ring-1 ring-slate-200 shadow-[0_10px_26px_-14px_rgb(15_23_42_/_0.32)] px-2.5 py-2" style="--i:0">
            <div class="text-[9px] font-mono uppercase tracking-wider text-slate-400">Step 1</div>
            <div class="text-[11.5px] font-medium text-slate-900 truncate">Intro email</div>
          </div>

          <!-- Split -->
          <!-- Base rails sit under a travelling pulse. The pulse paths carry no
               non-scaling-stroke: their dash length must stay in user units to
               match the path length the dashoffset animates over. -->
          <svg class="bento-edges w-full h-[30px]" viewBox="0 0 300 30" fill="none" preserveAspectRatio="none">
            <path d="M150 0 V9 Q150 15 140 15 H79 Q69 15 69 21 V30" stroke="#a7f3d0" stroke-width="1.5" vector-effect="non-scaling-stroke" />
            <path d="M150 0 V9 Q150 15 160 15 H221 Q231 15 231 21 V30" stroke="#e2e8f0" stroke-width="1.5" vector-effect="non-scaling-stroke" />
            <path class="bento-flow bento-flow-a" d="M150 0 V9 Q150 15 140 15 H79 Q69 15 69 21 V30" stroke="#10b981" stroke-width="2.5" stroke-linecap="round" />
            <path class="bento-flow bento-flow-b" d="M150 0 V9 Q150 15 160 15 H221 Q231 15 231 21 V30" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round" />
          </svg>

          <div class="grid grid-cols-2 gap-2.5">
            <!-- Replied branch -->
            <div>
              <div class="bento-branch-label text-emerald-600">replied</div>
              <div class="bento-node rounded-[9px] bg-emerald-50 ring-1 ring-emerald-200 px-2.5 py-2" style="--i:1">
                <div class="flex items-center gap-1.5">
                  <Icon name="check" size={11} strokeWidth={2.5} class="text-emerald-600 shrink-0" />
                  <span class="text-[11px] font-medium text-emerald-800 truncate">Stop here</span>
                </div>
                <div class="mt-0.5 text-[9.5px] text-emerald-700/80 truncate">no more follow-ups</div>
              </div>
            </div>
            <!-- No reply branch -->
            <div>
              <div class="bento-branch-label text-slate-400">no reply</div>
              <div class="bento-node rounded-[9px] bg-white ring-1 ring-slate-200 shadow-[0_8px_20px_-14px_rgb(15_23_42_/_0.3)] px-2.5 py-2" style="--i:2">
                <div class="flex items-center gap-1.5">
                  <Icon name="clock" size={11} class="text-slate-400 shrink-0" />
                  <span class="text-[11px] font-medium text-slate-900 truncate">Wait 3 days</span>
                </div>
                <div class="mt-0.5 text-[9.5px] text-slate-500 truncate">business hours</div>
              </div>
            </div>
          </div>

          <!-- Tail under the no-reply branch only -->
          <svg class="bento-edges w-full h-[22px]" viewBox="0 0 300 22" fill="none" preserveAspectRatio="none">
            <path d="M231 0 V22" stroke="#e2e8f0" stroke-width="1.5" vector-effect="non-scaling-stroke" />
            <path class="bento-flow bento-flow-c" d="M231 0 V22" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round" />
          </svg>
          <div class="grid grid-cols-2 gap-2.5">
            <span></span>
            <div class="bento-node rounded-[9px] bg-white ring-1 ring-slate-200 shadow-[0_8px_20px_-14px_rgb(15_23_42_/_0.3)] px-2.5 py-2" style="--i:3">
              <div class="text-[9px] font-mono uppercase tracking-wider text-slate-400">Step 2</div>
              <div class="text-[11.5px] font-medium text-slate-900 truncate">Follow-up</div>
            </div>
          </div>
        </div>
      </div>
      <div class="bento-copy">
        <span class="bento-eyebrow"><Icon name="workflow" size={13} />Knows when to stop</span>
        <h3>Follow-ups that end at "yes"</h3>
        <p>Each step branches on what the person did. Answer once and the rest of the sequence is cancelled automatically.</p>
      </div>
    </article>

    <!-- ── Placement ──────────────────────────────────────────────── -->
    <article class="bento-card md:col-span-4">
      <div class="bento-stage h-[266px]">
        <span class="bento-texture bento-rings"></span>

        <!-- Back layer: per-provider detail, dissolving at the bottom. -->
        <div class="bento-fade-b absolute left-7 right-0 top-7 rounded-tl-[10px] bg-white ring-1 ring-slate-200/70 shadow-[0_10px_30px_-18px_rgb(15_23_42_/_0.25)] pl-3.5 pr-4 py-3">
          <div class="text-[9.5px] uppercase tracking-[0.14em] text-slate-400 font-semibold">By provider</div>
          <div class="mt-2.5 space-y-2.5">
            {providers.map((p, i) => (
              <div class="bento-meter-row" style={`--i:${i}`}>
                <div class="flex items-center justify-between text-[11px] mb-1">
                  <span class="text-slate-600">{p.name}</span>
                  <span class="font-mono text-slate-400">{p.pct}%</span>
                </div>
                <div class="h-1.5 rounded-full bg-slate-100 overflow-hidden">
                  <span class="bento-meter block h-full rounded-full bg-sky-500" style={`--target:${p.pct}%`}></span>
                </div>
              </div>
            ))}
          </div>
        </div>

        <!-- Front layer: the headline number. -->
        <div class="bento-pop absolute left-6 right-8 bottom-5 rounded-[11px] bg-white ring-1 ring-slate-200 shadow-[0_22px_50px_-16px_rgb(15_23_42_/_0.30)] px-3.5 py-2.5 flex items-center gap-3">
          <div>
            <div class="text-[26px] font-light leading-none text-slate-900 tabular-nums">96%</div>
            <div class="mt-1 text-[10px] uppercase tracking-[0.12em] text-slate-400 font-semibold">reached the inbox</div>
          </div>
          <span class="ml-auto shrink-0 inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[9.5px] font-semibold bg-rose-50 text-rose-700 ring-1 ring-rose-200">
            1% spam
          </span>
        </div>
      </div>
      <div class="bento-copy">
        <span class="bento-eyebrow"><Icon name="chart" size={13} />No guessing</span>
        <h3>See if you landed in the inbox</h3>
        <p>We test where your mail actually arrives at each provider, so you find out before your reply rate does.</p>
      </div>
    </article>

    <!-- ── Personalization ────────────────────────────────────────── -->
    <article class="bento-card md:col-span-4">
      <div class="bento-stage h-[266px]">
        <span class="bento-texture bento-dots"></span>

        <!-- Back layer: the other copies of this email, stacked behind. -->
        <div class="bento-ghost absolute left-14 right-3 top-6 h-[54px] rounded-[10px] bg-white/70 ring-1 ring-slate-200/60" style="--i:2"></div>
        <div class="bento-ghost absolute left-11 right-6 top-9 h-[54px] rounded-[10px] bg-white/85 ring-1 ring-slate-200/70" style="--i:1"></div>

        <!-- Front layer: the one you actually wrote. -->
        <div class="bento-pop bento-fade-b absolute left-7 right-9 top-12 bottom-0 rounded-t-[11px] bg-white ring-1 ring-slate-200 shadow-[0_22px_50px_-16px_rgb(15_23_42_/_0.30)]">
          <div class="h-9 px-3.5 border-b border-slate-200 flex items-center gap-2">
            <span class="text-[9.5px] uppercase tracking-[0.14em] text-slate-400 font-semibold">Compose</span>
            <span class="ml-auto px-1.5 py-0.5 rounded text-[9.5px] font-semibold uppercase tracking-[0.06em] bg-sky-50 text-sky-700 ring-1 ring-sky-200 whitespace-nowrap">1 of 2,480</span>
          </div>
          <!-- Each field cross-fades between the placeholder and a resolved
               value. inline-grid stacks both in one cell so the box is as wide
               as the longer string and the paragraph never reflows. -->
          <div class="px-3.5 py-2.5 text-[11.5px] leading-[1.8] text-slate-700">
            <p>Hi <span class="bento-tag bento-swap" style="--i:0"><span class="swap-a">{'{{first_name}}'}</span><span class="swap-b">Jenna</span></span>,</p>
            <p class="mt-1">
              Saw <span class="bento-tag bento-swap" style="--i:1"><span class="swap-a">{'{{company}}'}</span><span class="swap-b">Northwind</span></span> is hiring across
              <span class="bento-tag bento-swap" style="--i:2"><span class="swap-a">{'{{team}}'}</span><span class="swap-b">support</span></span>. We keep outreach out of
              the spam folder for teams that size.
            </p>
            <p class="mt-1 text-slate-500">Worth a look?</p>
          </div>
        </div>
      </div>
      <div class="bento-copy">
        <span class="bento-eyebrow"><Icon name="spark" size={13} />Sounds human</span>
        <h3>Written once, personal to everyone</h3>
        <p>Pull real details from your contact list so each person gets their own version, without writing each one.</p>
      </div>
    </article>
  </div>
</section>

<style>
  /* ── Card shell ──────────────────────────────────────────────── */
  .bento-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 18px;
    background: linear-gradient(175deg, #fbfcfe 0%, var(--surface-2) 100%);
    box-shadow: inset 0 0 0 1px var(--border);
    transition: box-shadow 260ms cubic-bezier(0.22, 1, 0.36, 1),
                transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .bento-stage {
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
  }

  /* ── Plinth texture ──────────────────────────────────────────── */
  /* Faint pattern behind the artifact, masked so it never reaches an edge. */
  .bento-texture {
    position: absolute;
    inset: 0;
    pointer-events: none;
    -webkit-mask-image: radial-gradient(ellipse at 50% 40%, #000 30%, transparent 78%);
    mask-image: radial-gradient(ellipse at 50% 40%, #000 30%, transparent 78%);
  }
  .bento-dots {
    background-image: radial-gradient(circle, rgb(15 23 42 / 0.07) 1px, transparent 1.2px);
    background-size: 14px 14px;
  }
  .bento-rings {
    background-image: repeating-radial-gradient(
      circle at 50% 38%, transparent 0 19px, rgb(2 132 199 / 0.07) 19px 20px);
  }
  .bento-canvas {
    background-image:
      linear-gradient(to right, rgb(15 23 42 / 0.05) 1px, transparent 1px),
      linear-gradient(to bottom, rgb(15 23 42 / 0.05) 1px, transparent 1px);
    background-size: 22px 22px;
  }

  /* ── Edge fades ──────────────────────────────────────────────── */
  /* Back layers dissolve instead of hard-cropping, the way the references do. */
  .bento-fade-b {
    -webkit-mask-image: linear-gradient(to bottom, #000 52%, transparent 94%);
    mask-image: linear-gradient(to bottom, #000 52%, transparent 94%);
  }
  .bento-fade-r {
    -webkit-mask-image: linear-gradient(to right, #000 62%, transparent 99%);
    mask-image: linear-gradient(to right, #000 62%, transparent 99%);
  }

  /* Merge field, the way the composer renders one. */
  .bento-tag {
    display: inline-block;
    padding: 0 3px;
    border-radius: 3px;
    background: var(--brand-soft);
    color: var(--brand-strong);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 10.5px;
  }

  /* Both strings occupy one grid cell, so the field keeps the width of the
     longer of the two and swapping never reflows the sentence. */
  .bento-swap {
    display: inline-grid;
    vertical-align: bottom;
  }
  .bento-swap > span {
    grid-area: 1 / 1;
    text-align: center;
  }
  .bento-swap > .swap-b { opacity: 0; }

  .bento-branch-label {
    margin-bottom: 5px;
    text-align: center;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
  }

  /* ── Copy block ──────────────────────────────────────────────── */
  .bento-copy { padding: 20px 24px 24px; }
  .bento-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--brand);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.14em;
  }
  .bento-copy h3 {
    margin-top: 8px;
    font-size: 16px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.3;
    color: var(--heading);
  }
  .bento-copy p {
    margin-top: 6px;
    font-size: 13.5px;
    line-height: 1.6;
    color: color-mix(in oklab, var(--foreground) 70%, transparent);
  }

  /* ── Reveal ──────────────────────────────────────────────────── */
  /* Armed only once the inline script confirms JS is alive, so a script
     failure leaves every card visible instead of blank. */
  .bento.js-ready .bento-card {
    opacity: 0;
    transform: translateY(20px);
    will-change: opacity, transform;
  }
  /* box-shadow is restated because the shorthand would otherwise drop the
     hover transition inherited from .bento-card. */
  .bento.js-ready .bento-card.is-in {
    opacity: 1;
    transform: none;
    transition: opacity 700ms cubic-bezier(0.22, 1, 0.36, 1),
                transform 700ms cubic-bezier(0.22, 1, 0.36, 1),
                box-shadow 260ms ease;
  }
  /* Once the reveal has played out the card drops back to the short hover
     timing, so the lift is not stuck at the 700ms reveal duration. */
  .bento.js-ready .bento-card.is-settled {
    transition: box-shadow 260ms ease,
                transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  @media (hover: hover) {
    .bento-card:hover {
      transform: translateY(-3px);
      box-shadow: inset 0 0 0 1px var(--border-strong), var(--shadow-md);
    }
  }

  /* ── Artifact motion ─────────────────────────────────────────── */
  /* Gated on .is-live, which the script adds on enter and strips on leave, so
     nothing animates off screen. Delays key off an inline --i rather than
     nth-child, which would miscount against non-item siblings. */
  @media (prefers-reduced-motion: no-preference) {
    .bento.js-ready .bento-row,
    .bento.js-ready .bento-meter-row,
    .bento.js-ready .bento-node,
    .bento.js-ready .bento-ghost,
    .bento.js-ready .bento-edges,
    .bento.js-ready .bento-pop { opacity: 0; }

    /* Rows rise once, then a highlight keeps walking down the list so the
       inbox reads as still receiving mail. */
    .is-live .bento-row {
      animation: bento-rise 520ms cubic-bezier(0.22, 1, 0.36, 1) both,
                 bento-scan 7s ease-in-out infinite;
      animation-delay: calc(var(--i) * 80ms), calc(var(--i) * 800ms + 1200ms);
    }

    .is-live .bento-meter-row {
      animation: bento-rise 520ms cubic-bezier(0.22, 1, 0.36, 1) both;
      animation-delay: calc(var(--i) * 80ms);
    }

    /* Flow builds root, then branches, then the tail. */
    .is-live .bento-node {
      animation: bento-rise 460ms cubic-bezier(0.22, 1, 0.36, 1) both;
      animation-delay: calc(var(--i) * 150ms);
    }
    .is-live .bento-edges { animation: bento-fade 500ms ease-out 260ms both; }

    /* A pulse runs the flow forever: down the replied branch, then the no-reply
       branch, then on to step 2. --off is the dash travel per path length. */
    .bento-flow {
      stroke-dasharray: var(--dash, 12) var(--gap, 120);
      opacity: 0;
    }
    .is-live .bento-flow { animation: bento-flow 5.2s ease-in-out infinite; }
    .is-live .bento-flow-a { animation-delay: 1.1s; }
    .is-live .bento-flow-b { animation-delay: 3.1s; }
    .is-live .bento-flow-c {
      --dash: 8;
      --gap: 34;
      --off: 42;
      animation-delay: 3.85s;
    }

    /* Ghost copies fan out behind the composed email. */
    .is-live .bento-ghost {
      animation: bento-fan 620ms cubic-bezier(0.22, 1, 0.36, 1) both;
      animation-delay: calc(var(--i) * 90ms + 260ms);
    }

    /* The floating layer arrives last, after its backdrop has settled. */
    .is-live .bento-pop {
      animation: bento-drop 620ms cubic-bezier(0.34, 1.24, 0.64, 1) 420ms both;
    }

    /* The ramp rebuilds on a loop: grow left to right, hold, fall away. That
       cycle is the feature, so it is the one large continuous motion here.
       It scales rather than animating height, which would force layout on
       fifteen bars every frame for as long as the card is on screen. */
    .bento.js-ready .bento-bar { transform: scaleY(0); }
    .is-live .bento-bar {
      animation: bento-ramp-cycle 11s cubic-bezier(0.22, 1, 0.36, 1) infinite;
      animation-delay: calc(var(--i) * 55ms);
    }

    .bento.js-ready .bento-meter { width: 0; }
    .is-live .bento-meter {
      animation: bento-grow 900ms cubic-bezier(0.22, 1, 0.36, 1) both;
      animation-delay: calc(var(--i) * 80ms + 200ms);
    }
    /* A light sweep keeps crossing the filled bars. */
    .bento-meter { position: relative; overflow: hidden; }
    .is-live .bento-meter::after {
      content: '';
      position: absolute;
      inset: 0;
      background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.7), transparent);
      animation: bento-sweep 4.2s ease-in-out infinite;
      animation-delay: calc(var(--i) * 280ms + 1200ms);
    }

    /* Merge fields resolve to a real value and back, one after another. */
    .is-live .swap-a { animation: bento-swap-out 8s ease-in-out infinite; }
    .is-live .swap-b { animation: bento-swap-in 8s ease-in-out infinite; }
    .is-live .swap-a,
    .is-live .swap-b { animation-delay: calc(var(--i) * 900ms + 1400ms); }

    .is-live .bento-live-dot { animation: bento-pulse 2.4s ease-in-out infinite; }
  }

  @keyframes bento-rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes bento-drop {
    from { opacity: 0; transform: translateY(16px) scale(0.97); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes bento-fan {
    from { opacity: 0; transform: translate(-10px, 8px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes bento-fade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes bento-grow { from { width: 0; } to { width: var(--target); } }
  @keyframes bento-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

  @keyframes bento-ramp-cycle {
    0%        { transform: scaleY(0); }
    14%       { transform: scaleY(1); }
    84%       { transform: scaleY(1); }
    100%      { transform: scaleY(0); }
  }
  /* A brief sky wash passes over one row at a time. */
  @keyframes bento-scan {
    0%, 10%, 100% { background-color: rgb(240 249 255 / 0); }
    3%            { background-color: rgb(240 249 255 / 1); }
  }
  @keyframes bento-flow {
    0%        { stroke-dashoffset: var(--off, 132); opacity: 0; }
    6%        { opacity: 1; }
    38%       { stroke-dashoffset: 0; opacity: 1; }
    46%, 100% { stroke-dashoffset: 0; opacity: 0; }
  }
  @keyframes bento-sweep {
    0%        { transform: translateX(-130%); }
    55%, 100% { transform: translateX(260%); }
  }
  @keyframes bento-swap-out {
    0%, 34%, 92%, 100% { opacity: 1; }
    42%, 84%           { opacity: 0; }
  }
  @keyframes bento-swap-in {
    0%, 34%, 92%, 100% { opacity: 0; }
    42%, 84%           { opacity: 1; }
  }

  /* Reduced motion keeps every artifact in its resolved end state. The flow
     pulses are hidden outright: their opacity: 0 lives in the no-preference
     block, so without this they would sit on the rails as static dashes. */
  @media (prefers-reduced-motion: reduce) {
    .bento-flow { opacity: 0; }
    .bento-meter { width: var(--target); }
    .bento.js-ready .bento-card {
      opacity: 1;
      transform: none;
      transition: none;
    }
    .bento-card { transition: none; }
  }
</style>

<script is:inline>
  // Arm the reveal only when JS is running, before first paint of the section.
  document.querySelectorAll('.bento').forEach((el) => el.classList.add('js-ready'));
</script>

<script>
  import { inView } from 'motion';

  const cards = document.querySelectorAll<HTMLElement>('.bento-card');

  // Reveal once, staggered by DOM order.
  cards.forEach((card, i) => {
    inView(card, () => {
      setTimeout(() => {
        card.classList.add('is-in');
        card.addEventListener(
          'transitionend',
          () => card.classList.add('is-settled'),
          { once: true },
        );
      }, i * 70);
    }, { amount: 0.15 });
  });

  // Ambient artifact motion runs only while the card is on screen. Replaying
  // on re-entry is deliberate: the flow rebuilds when you scroll back.
  cards.forEach((card) => {
    inView(card, () => {
      card.classList.add('is-live');
      return () => card.classList.remove('is-live');
    }, { amount: 0.3 });
  });
</script>
