/* Notifications. Pile of 24 cards layered around the phone.
   Each card has an explicit `exitAt` threshold so the visible count
   steps down through the scroll story.

   Narrative timing — cards stay until Bob has the prompt:
     t < 0.55           24 visible        (chaos + ask, message not sent)
     t = 0.55           user message sent: "hey bob, what needs me today?"
     t = 0.57 to 0.62   exit 4   -> 20 visible  (Bob starts filtering)
     t = 0.64 to 0.70   exit 4   -> 16 visible
     t = 0.72 to 0.78   exit 6   -> 10 visible
     t = 0.80 to 0.86   exit 5   ->  5 visible
     t = 0.88 to 0.90   exit 2   ->  3 visible
     t = 0.92 to 0.96   exit 3   ->  0 visible  (only Bob's response remains)

   Cards sorted noise-first, signal-last. Front layer (depth 0) holds the
   real signal; back layer (depth 2) holds the noise that exits first.
*/

const NOTIFICATIONS = [
  /* ===== Last 3 to remain. front layer, real signal — pushed to corners
        so they don't overlap the phone interior at focus state. ===== */
  { id: 'msg-margo',     app: 'Messages',  title: 'Margo',           body: 'two drafts ready. second one is shorter.',          time: '9:42 AM', icon: 'imessage', depth: 0, x: -78, y: -22, rot: -6, exitAt: 0.56 },
  { id: 'mail-vendor',   app: 'Mail',      title: 'Vendor renewal',  body: 'Re: contract terms for Q3. Decision by Friday.',    time: '8:14',    icon: 'mail',     depth: 0, x:  82, y: -30, rot:  4, exitAt: 0.54 },
  { id: 'cal-pickup',    app: 'Calendar',  title: 'Jamie · school',  body: 'Pickup at 14:30. Leave by 13:50.',                  time: '14:30',   icon: 'calendar', depth: 0, x: -72, y:  42, rot:  3, exitAt: 0.52 },

  /* ===== Next 2 to leave (5 -> 3). front layer ===== */
  { id: 'cal-standup',   app: 'Calendar',  title: 'Eng standup',     body: 'in 5 min. Zoom. 4 attendees.',                      time: '10:00',   icon: 'calendar', depth: 0, x:  84, y:  46, rot: -5, exitAt: 0.50 },
  { id: 'slack-quinn',   app: 'Slack',     title: '#ship-it · Quinn',body: 'PR-1184 ready for review whenever.',                time: 'now',     icon: 'slack',    depth: 0, x:   8, y: -90, rot:  1, exitAt: 0.48 },

  /* ===== Next 5 to leave (10 -> 5). mid layer ===== */
  { id: 'rem-confirm',   app: 'Reminders', title: 'Confirm pickup',  body: 'Tate to send school an ETA at 13:35.',              time: '12:00',   icon: 'reminders', depth: 1, x: -92, y: -72, rot: -9, exitAt: 0.46 },
  { id: 'monday-okr',    app: 'monday.com',title: 'Q2 OKR review',   body: 'Status: At risk. Owner: you.',                      time: '11:30',   icon: 'monday',    depth: 1, x:  88, y: -78, rot: 11, exitAt: 0.44 },
  { id: 'wa-mom',        app: 'WhatsApp',  title: 'Mom',             body: 'are you coming sunday? aunt jean is asking.',       time: '7:23',    icon: 'whatsapp',  depth: 1, x: -86, y:  12, rot: -3, exitAt: 0.42 },
  { id: 'asana-deck',    app: 'Asana',     title: 'Q2 deck for board',body:'Due in 2 days. 3 subtasks open.',                   time: 'Tue',     icon: 'asana',     depth: 1, x:  92, y:   8, rot:  7, exitAt: 0.40 },
  { id: 'teams-pat',     app: 'Teams',     title: 'Pat (1:1)',       body: 'started a meeting. "got 5?"',                       time: 'now',     icon: 'teams',     depth: 1, x: -78, y:  82, rot: -7, exitAt: 0.38 },

  /* ===== Next 6 to leave (16 -> 10). mid + back ===== */
  { id: 'linear-bug',    app: 'Linear',    title: 'BUG-2104',        body: 'P1. login flow broken on Safari 17.',                time: '6:02',    icon: 'linear',    depth: 1, x:  78, y:  84, rot:  6, exitAt: 0.36 },
  { id: 'gmail-brief',   app: 'Gmail',     title: 'The Daily Brief', body: '7 stories. 4 min read.',                            time: '6:30',    icon: 'gmail',     depth: 1, x: -12, y:  98, rot: -2, exitAt: 0.34 },
  { id: 'cal-dentist',   app: 'Calendar',  title: 'Dentist',         body: 'Thu 3:00 PM. Dr. Lin.',                              time: 'Thu',     icon: 'calendar',  depth: 2, x:  98, y: -110, rot: 13, exitAt: 0.32 },
  { id: 'rem-vitamin',   app: 'Reminders', title: 'Take vitamin D',  body: 'Daily. 8:00 AM.',                                    time: '8:00',    icon: 'reminders', depth: 2, x: -104, y:  98, rot: -10, exitAt: 0.30 },
  { id: 'slack-design',  app: 'Slack',     title: '#design-crit',    body: 'Sammy: thoughts on the new icon set?',               time: '5:48',    icon: 'slack',     depth: 2, x: 104, y:  80, rot:  8, exitAt: 0.28 },
  { id: 'linear-pr',     app: 'Linear',    title: 'HEY-2104',        body: 'PR ready. waiting on review.',                       time: '5:30',    icon: 'linear',    depth: 2, x: -110, y: -44, rot: -6, exitAt: 0.26 },

  /* ===== Next 4 to leave (20 -> 16). back layer ===== */
  { id: 'zoom-now',      app: 'Zoom',      title: 'Sync starting',   body: 'Marketing weekly. join now.',                        time: 'now',     icon: 'zoom',      depth: 1, x: -44, y: -10, rot:  -5, exitAt: 0.24 },
  { id: 'phone-missed',  app: 'Phone',     title: 'Missed call',     body: 'Unknown. (415) 555-0182.',                           time: '8:51',    icon: 'phone',     depth: 1, x:  38, y:  42, rot:   7, exitAt: 0.22 },
  { id: 'mail-court',    app: 'Mail',      title: 'Court letter',    body: 'Filing scheduled for next Tuesday.',                 time: 'Mon',     icon: 'mail',      depth: 1, x: -42, y:  32, rot:  -6, exitAt: 0.20 },
  { id: 'mail-substack', app: 'Mail',      title: 'New comment',     body: 'on JoshuaScott · "On the noise."',                   time: '4:12',    icon: 'mail',      depth: 1, x:  44, y: -32, rot:   4, exitAt: 0.18 },

  /* ===== First 4 to leave (24 -> 20). back layer noise ===== */
  { id: 'asana-sub',     app: 'Asana',     title: 'Subtask overdue', body: 'Q2 deck. owner: you.',                               time: '3:48',    icon: 'asana',     depth: 1, x: -22, y: -28, rot: -11, exitAt: 0.16 },
  { id: 'cal-conflict',  app: 'Calendar',  title: 'Conflict',        body: 'Ops sync overlaps with school pickup.',              time: 'Fri',     icon: 'calendar',  depth: 0, x:  26, y:  16, rot:   9, exitAt: 0.14 },
  { id: 'wa-pat',        app: 'WhatsApp',  title: 'Pat',             body: 'are we still on for dinner?',                        time: '2:15',    icon: 'whatsapp',  depth: 0, x: -34, y:  10, rot:  -8, exitAt: 0.12 },
  { id: 'slack-board',   app: 'Slack',     title: '#board-updates',  body: 'Kay: monthly metrics ready for review.',             time: '1:02',    icon: 'slack',     depth: 1, x:  10, y: -22, rot:  12, exitAt: 0.10 },
];

/* Real brand marks rendered as 28x28 tiles.
   Brands with proprietary marks (Slack, Linear, monday.com, Microsoft Teams,
   Apple Reminders) are sourced from the official iOS app icons via Apple's
   iTunes Search API and stored in marketing-site/brand-icons/ as 512x512
   (Reminders 400x400) PNGs. Everything else stays inline SVG. */
const BRAND_PNG = {
  slack:     'brand-icons/slack.png',
  linear:    'brand-icons/linear.png',
  monday:    'brand-icons/monday.png',
  teams:     'brand-icons/teams.png',
  reminders: 'brand-icons/reminders.png',
  asana:     'brand-icons/asana.png',
};

function NotifIcon({ kind }) {
  const tile = {
    width: 28, height: 28, borderRadius: 7, flexShrink: 0, overflow: 'hidden',
    boxShadow: 'inset 0 0 0 0.5px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.18), 0 1px 1.5px rgba(0,0,0,0.05)',
    display: 'block',
  };
  if (BRAND_PNG[kind]) {
    return (
      <img
        src={BRAND_PNG[kind]}
        alt=""
        style={{ ...tile, objectFit: 'cover' }}
        loading="eager"
        decoding="async"
      />
    );
  }
  switch (kind) {
    case 'gmail':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <rect width="28" height="28" rx="7" fill="#fff"/>
          <path d="M5 10.2 V20 a1 1 0 0 0 1 1 h2.5 V13 L14 17 l5.5-4 V21 H22 a1 1 0 0 0 1-1 V10.2 a1.2 1.2 0 0 0-1.9-.96 L14 14.5 L6.9 9.24 A1.2 1.2 0 0 0 5 10.2 Z" fill="#EA4335"/>
          <path d="M8.5 13 V21 H6 a1 1 0 0 1 -1-1 V10.2 z" fill="#4285F4"/>
          <path d="M19.5 13 V21 H22 a1 1 0 0 0 1-1 V10.2 z" fill="#34A853"/>
          <path d="M8.5 13 L14 17 L19.5 13 V10.2 L14 14.5 L8.5 10.2 z" fill="#FBBC04"/>
        </svg>
      );
    case 'calendar':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <rect width="28" height="28" rx="7" fill="#fff"/>
          <text x="14" y="10.5" fontFamily="-apple-system, Helvetica, Arial, sans-serif" fontSize="6.2" fontWeight="700" textAnchor="middle" fill="#FF3B30" letterSpacing="0.2">APR</text>
          <text x="14" y="23" fontFamily="-apple-system, Helvetica, Arial, sans-serif" fontSize="14" fontWeight="300" textAnchor="middle" fill="#1A1A1A" letterSpacing="-0.5">27</text>
        </svg>
      );
    case 'imessage':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="msg-grad" x1="0" x2="0" y1="0" y2="1">
              <stop offset="0" stopColor="#5BD267"/>
              <stop offset="1" stopColor="#3BB94F"/>
            </linearGradient>
          </defs>
          <rect width="28" height="28" rx="7" fill="url(#msg-grad)"/>
          <path d="M14 6.6 c-5 0-9 3-9 6.8 0 2.2 1.3 4.2 3.4 5.4 -.2 .9-.8 1.9-1.5 2.6 1.5-.1 3-.7 4.2-1.6 .9 .2 1.8 .3 2.9 .3 5 0 9-3 9-6.7 s-4-6.8-9-6.8z" fill="#fff"/>
        </svg>
      );
    case 'whatsapp':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <rect width="28" height="28" rx="7" fill="#25D366"/>
          <path d="M14 6.5 c-4.4 0-8 3.6-8 8 0 1.4 .4 2.8 1.1 4 L6 23 l4.6-1.1 c1.1 .6 2.3 .9 3.5 .9 4.4 0 8-3.6 8-8s-3.6-8.3-8.1-8.3z m4.5 11.4 c-.2 .5-1.1 1-1.6 1.1 -.4 .1-.9 .1-1.4-.1 -.3-.1-.7-.2-1.3-.5 -2.3-1-3.7-3.3-3.8-3.4 -.1-.2-1-1.3-1-2.5 0-1.2 .6-1.8 .8-2 .2-.2 .5-.3 .7-.3 .2 0 .3 0 .5 0 .2 0 .4-.1 .6 .4 .2 .5 .7 1.7 .8 1.8 .1 .1 .1 .3 0 .4 -.1 .2-.1 .3-.3 .4 -.1 .1-.3 .3-.4 .4 -.1 .1-.3 .3-.1 .5 .2 .3 .8 1.3 1.7 2.1 1.2 1 2.1 1.4 2.4 1.5 .3 .1 .5 .1 .6-.1 .2-.2 .7-.8 .9-1.1 .2-.3 .4-.2 .6-.2 .3 .1 1.5 .7 1.8 .9 .3 .1 .5 .2 .5 .3 .1 .2 .1 .8-.1 1.4z" fill="#fff"/>
        </svg>
      );
    case 'zoom':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <rect width="28" height="28" rx="7" fill="#2D8CFF"/>
          <path d="M5 10 a1.5 1.5 0 0 1 1.5 -1.5 h9.5 a1.5 1.5 0 0 1 1.5 1.5 v8 a1.5 1.5 0 0 1 -1.5 1.5 h-9.5 a1.5 1.5 0 0 1 -1.5 -1.5 z M19 11 l4 -2.4 v10.8 l-4 -2.4 z" fill="#fff"/>
        </svg>
      );
    case 'phone':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="phone-grad" x1="0" x2="0" y1="0" y2="1">
              <stop offset="0" stopColor="#7BE581"/>
              <stop offset="1" stopColor="#34C759"/>
            </linearGradient>
          </defs>
          <rect width="28" height="28" rx="7" fill="url(#phone-grad)"/>
          <path d="M9.6 7.8 c.7 -.5 1.6 -.4 2.1 .3 l1.8 2.5 c.4 .6 .3 1.4 -.3 1.9 l-1.3 1 a8.5 8.5 0 0 0 4.6 4.6 l1 -1.3 c.5 -.6 1.3 -.7 1.9 -.3 l2.5 1.8 c.7 .5 .8 1.4 .3 2.1 l-1.5 2 a2 2 0 0 1 -2.3 .6 c-3.2 -1.2 -7 -4.9 -8.5 -8.5 a2 2 0 0 1 .6 -2.3 z" fill="#fff"/>
        </svg>
      );
    case 'mail':
      return (
        <svg viewBox="0 0 28 28" style={tile} xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient id="mail-grad" x1="0" x2="0" y1="0" y2="1">
              <stop offset="0" stopColor="#5DC1FA"/>
              <stop offset="1" stopColor="#0A7CDB"/>
            </linearGradient>
          </defs>
          <rect width="28" height="28" rx="7" fill="url(#mail-grad)"/>
          <rect x="5" y="9.5" width="18" height="11" rx="2" fill="#fff"/>
          <path d="M5.5 10.5 L14 16.5 L22.5 10.5" stroke="#0A7CDB" strokeWidth="1.4" fill="none" strokeLinejoin="round"/>
        </svg>
      );
    default:
      return <div style={{ ...tile, background: '#999' }} />;
  }
}

/* Liquid-glass notification card. Lifecycle is now driven by `exitAt` .
   a per-card threshold rather than a shared `delay`-shifted window. Each
   card holds steady from enter through `exitAt - 0.04`, then fades over
   ~0.06 of scroll progress with its own cubic ease. Slight per-card
   randomization (seeded by id-hash) so 24 cards don't feel like clones. */
function GlassNotification({ n, t, isReducedMotion }) {
  // Enter window. staggered slightly by depth so the pile arrives in waves
  const enterStart = -0.08 + n.depth * 0.02;
  const enterEnd   = enterStart + 0.10;

  // Exit window. explicit per card
  // Wider exit window than before (0.11 vs 0.07) so each card fades over a
  // longer slice of the timeline — softer "is being filtered out" feel.
  const exitStart = n.exitAt - 0.07;
  const exitEnd   = n.exitAt + 0.04;

  const inP  = clamp01((t - enterStart) / (enterEnd - enterStart));
  const outP = clamp01((t - exitStart) / (exitEnd - exitStart));
  if (outP >= 1) return null;

  const visible = inP > 0;
  if (!visible) return null;

  const easeIn  = easeOutCubic(inP);
  const easeOut = easeInOutQuint(outP);

  // Drift outward on exit
  const driftMag = 44 * easeOut;
  const driftX = Math.sign(n.x || 1) * driftMag;
  const driftY = Math.sign(n.y || 1) * driftMag * 0.6;

  const opacity = easeIn * (1 - easeOut);
  const baseScale  = [1, 0.86, 0.72][n.depth];
  const enterScale = 0.7 + 0.3 * easeIn;
  const exitScale  = 1 - 0.12 * easeOut;
  const scale = baseScale * enterScale * exitScale;

  // Idle float (subtle)
  const idleP = clamp01((t - enterEnd) / Math.max(0.001, exitStart - enterEnd));
  const seed = (n.id.charCodeAt(0) + n.id.charCodeAt(n.id.length - 1)) * 0.13;
  const floatPhase = (idleP * Math.PI * 2 * 1.4) + seed;
  const floatX = isReducedMotion ? 0 : Math.sin(floatPhase) * 4;
  const floatY = isReducedMotion ? 0 : Math.cos(floatPhase * 1.2) * 3;

  const width = [320, 260, 210][n.depth];
  const blur  = [0, 0.3, 0.8][n.depth];
  const layerOpacity = [1, 0.92, 0.78][n.depth];

  const tilt = (n.rot || 0) + (1 - easeIn) * 8 * Math.sign(n.x || 1);

  return (
    <div
      className={`glass-notif depth-${n.depth}`}
      style={{
        position: 'absolute',
        left: '50%',
        top: '50%',
        transform: `
          translate(-50%, -50%)
          translate(${n.x * 5.4 + driftX + floatX}px, ${n.y * 4.4 + driftY + floatY}px)
          rotate(${tilt}deg)
          scale(${scale})
        `,
        opacity: opacity * layerOpacity,
        filter: blur ? `blur(${blur}px)` : 'none',
        zIndex: 30 - n.depth * 5,
        pointerEvents: 'none',
        width,
        willChange: 'transform, opacity',
      }}
    >
      <div className="liquid-glass">
        <div className="lg-row">
          <NotifIcon kind={n.icon} />
          <div className="lg-meta">
            <div className="lg-app">{n.app}</div>
            <div className="lg-time">{n.time}</div>
          </div>
        </div>
        <div className="lg-title">{n.title}</div>
        <div className="lg-body">{n.body}</div>
      </div>
    </div>
  );
}

/* Helpers */
function clamp01(x){ return Math.max(0, Math.min(1, x)); }
function easeOutCubic(x){ return 1 - Math.pow(1 - x, 3); }
function easeInCubic(x){ return x * x * x; }
function easeInOutQuint(x){ return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2; }
function smootherStep(x){ return x * x * x * (x * (x * 6 - 15) + 10); }

/* Inject Liquid Glass card styles once */
(function injectGlassStyles(){
  if (document.getElementById('glass-styles')) return;
  const css = `
    .liquid-glass{
      position: relative;
      padding: 12px 14px 14px;
      border-radius: 22px;
      background:
        linear-gradient(180deg, rgba(255,255,255,0.88) 0%, rgba(255,255,255,0.74) 100%);
      backdrop-filter: saturate(180%) blur(28px);
      -webkit-backdrop-filter: saturate(180%) blur(28px);
      border: 1px solid rgba(255,255,255,0.7);
      /* Multi-layer drop shadow — each card floats above whatever's beneath.
         Depth 0 (front) gets the biggest shadow for max float. Depth 1/2 are
         scaled below this default. */
      box-shadow:
        0 1px 0 rgba(255,255,255,0.95) inset,
        0 0 0 0.5px rgba(255,255,255,0.6) inset,
        0 28px 56px -14px rgba(15,17,21,0.30),
        0 12px 26px -6px rgba(15,17,21,0.16),
        0 3px 8px rgba(15,17,21,0.10);
    }
    .liquid-glass::before{
      content: '';
      position: absolute; inset: 0;
      border-radius: inherit;
      background: linear-gradient(135deg, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 40%);
      pointer-events: none;
      mix-blend-mode: overlay;
    }
    .liquid-glass::after{
      content: '';
      position: absolute; inset: 0;
      border-radius: inherit;
      box-shadow: 0 0 0 0.5px rgba(0,0,0,0.06);
      pointer-events: none;
    }
    .lg-row{ display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
    .lg-meta{ flex: 1; display: flex; justify-content: space-between; align-items: baseline; }
    .lg-app{
      font: 600 11px/1 'Inter', system-ui, sans-serif;
      color: rgba(0,0,0,0.6);
      text-transform: uppercase;
      letter-spacing: 0.04em;
    }
    .lg-time{
      font: 500 11px/1 'Inter', system-ui, sans-serif;
      color: rgba(0,0,0,0.45);
    }
    .lg-title{
      font: 600 14px/1.25 'Inter', system-ui, sans-serif;
      color: #1a1a1a;
      letter-spacing: -0.01em;
      margin-top: 2px;
    }
    .lg-body{
      font: 400 13px/1.35 'Inter', system-ui, sans-serif;
      color: rgba(26,26,26,0.78);
      margin-top: 2px;
      letter-spacing: -0.005em;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .glass-notif.depth-1 .liquid-glass{
      padding: 10px 12px 12px; border-radius: 20px;
      box-shadow:
        0 1px 0 rgba(255,255,255,0.9) inset,
        0 0 0 0.5px rgba(255,255,255,0.55) inset,
        0 18px 36px -12px rgba(15,17,21,0.24),
        0 8px 16px -4px rgba(15,17,21,0.12),
        0 2px 6px rgba(15,17,21,0.07);
    }
    .glass-notif.depth-1 .lg-title{ font-size: 13px; }
    .glass-notif.depth-1 .lg-body{ font-size: 12px; }
    .glass-notif.depth-2 .liquid-glass{
      padding: 9px 11px 10px; border-radius: 18px;
      box-shadow:
        0 1px 0 rgba(255,255,255,0.85) inset,
        0 0 0 0.5px rgba(255,255,255,0.45) inset,
        0 12px 26px -10px rgba(15,17,21,0.18),
        0 5px 12px -3px rgba(15,17,21,0.09);
    }
    .glass-notif.depth-2 .lg-title{ font-size: 12px; }
    .glass-notif.depth-2 .lg-body{ font-size: 11px; -webkit-line-clamp: 1; }

    .theme-dark .liquid-glass{
      background: linear-gradient(180deg, rgba(40,42,48,0.78) 0%, rgba(30,32,38,0.62) 100%);
      border-color: rgba(255,255,255,0.12);
      box-shadow:
        0 1px 0 rgba(255,255,255,0.12) inset,
        0 0 0 0.5px rgba(255,255,255,0.08) inset,
        0 12px 30px -8px rgba(0,0,0,0.5),
        0 4px 10px -2px rgba(0,0,0,0.3);
    }
    .theme-dark .lg-app{ color: rgba(255,255,255,0.65); }
    .theme-dark .lg-time{ color: rgba(255,255,255,0.45); }
    .theme-dark .lg-title{ color: #fff; }
    .theme-dark .lg-body{ color: rgba(255,255,255,0.78); }
  `;
  const tag = document.createElement('style');
  tag.id = 'glass-styles';
  tag.textContent = css;
  document.head.appendChild(tag);
})();

window.NOTIFICATIONS = NOTIFICATIONS;
window.GlassNotification = GlassNotification;
window.NotifIcon = NotifIcon;
window.clamp01 = clamp01;
window.easeOutCubic = easeOutCubic;
window.easeInCubic = easeInCubic;
window.easeInOutQuint = easeInOutQuint;
window.smootherStep = smootherStep;
