{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "live-activity",
  "title": "Live Activity",
  "description": "A lock-screen live activity shows a render progress bar and remaining time.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "registryDependencies": ["@remocn/gsh"],
  "files": [
    {
      "path": "registry/remocn/live-activity/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont } from \"@remotion/google-fonts/HankenGrotesk\";\nimport type React from \"react\";\nimport { useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  spring,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\nimport type { GradientParams } from \"@/lib/remocn/gsh/gradient-engine\";\nimport { GshGround } from \"@/lib/remocn/gsh/gsh-ground\";\nimport type { GshPresetId } from \"@/lib/remocn/gsh/presets\";\n\nconst { fontFamily } = loadFont(\"normal\", {\n  weights: [\"300\", \"400\"],\n  subsets: [\"latin\"],\n});\n\nexport interface LiveActivityStatus {\n  app: string;\n  title: string;\n  doneTitle: string;\n  details: string[];\n  doneDetail: string;\n  steps: string[];\n  seconds: number;\n  format?: \"clock\" | \"minutes\";\n  glyph?: \"render\" | \"delivery\" | \"deploy\";\n  lines?: string[];\n}\n\nexport interface LiveActivityProps {\n  status?: LiveActivityStatus;\n  date?: string;\n  accent?: string;\n  speed?: number;\n  theme?: \"light\" | \"dark\";\n  ground?: GshPresetId;\n  groundParams?: Partial<GradientParams>;\n}\n\nexport const LIVE_ACTIVITY_RENDER: LiveActivityStatus = {\n  app: \"remocn\",\n  title: \"Rendering launch.mp4\",\n  doneTitle: \"launch.mp4 is ready\",\n  details: [\n    \"Bundling 214 modules\",\n    \"1080p · 30 fps · {pct}\",\n    \"Uploading to CDN\",\n  ],\n  doneDetail: \"42.8 MB · 0:58 · Tap to share\",\n  steps: [\"Bundle\", \"Render\", \"Upload\"],\n  seconds: 27,\n  format: \"clock\",\n  glyph: \"render\",\n  lines: [\n    \"Your render, live.\",\n    \"Progress at a glance.\",\n    \"Ready on the Lock Screen.\",\n  ],\n};\n\nexport const LIVE_ACTIVITY_DELIVERY: LiveActivityStatus = {\n  app: \"Fernway\",\n  title: \"Leo is on the way\",\n  doneTitle: \"Your order has arrived\",\n  details: [\"Packing 12 items\", \"Toyota Prius · 7KX 204\", \"Pulling up outside\"],\n  doneDetail: \"Left at the front door\",\n  steps: [\"Packed\", \"On the way\", \"Arrived\"],\n  seconds: 6 * 60,\n  format: \"minutes\",\n  glyph: \"delivery\",\n  lines: [\"Track every order.\", \"Minutes, not guesses.\", \"Left at the door.\"],\n};\n\nconst SW = 390;\nconst SH = 844;\nconst BEZEL = 12;\nconst BW = SW + BEZEL * 2;\nconst BH = SH + BEZEL * 2;\n\nconst ISL_TOP = 11;\nconst ISL_W = 124;\nconst ISL_H = 36;\nconst CMP_W = 198;\nconst EXP_W = 370;\nconst EXP_H = 188;\nconst EXP_R = 44;\nconst CARD_Y = 584;\n\nconst T_START = 14;\nconst T_PRESS = 54;\nconst T_EXP = 62;\nconst T_COL = 150;\nconst T_SWIPE = 190;\nconst T_RELEASE = 202;\nconst T_FIN = 240;\n\nconst clamp = { extrapolateLeft: \"clamp\", extrapolateRight: \"clamp\" } as const;\nconst enterE = Easing.bezier(0.22, 1, 0.36, 1);\nconst exitE = Easing.bezier(0.55, 0, 1, 0.45);\nconst moveE = Easing.bezier(0.65, 0, 0.35, 1);\nconst camE = Easing.bezier(0.87, 0, 0.13, 1);\nconst sheet = Easing.bezier(0.32, 0.72, 0, 1);\nconst tween = (f: number, a: number, b: number, easing = enterE) =>\n  interpolate(f, [a, b], [0, 1], {\n    extrapolateLeft: \"clamp\",\n    extrapolateRight: \"clamp\",\n    easing,\n  });\n\ntype SpringCfg = { mass?: number; damping: number; stiffness?: number };\nconst HEAVY: SpringCfg = { mass: 1, damping: 26, stiffness: 120 };\nconst CARD: SpringCfg = { mass: 0.8, damping: 18, stiffness: 160 };\nconst CHIP: SpringCfg = { mass: 0.5, damping: 12, stiffness: 200 };\nconst MORPH: SpringCfg = { damping: 200 };\nconst LINE_AT = [0, T_EXP, T_SWIPE];\n\nconst DARK = {\n  stage: \"#03050B\",\n  scrim: \"rgba(2,3,8,0.25)\",\n  copy: \"#F4F5F8\",\n  sky: [\"#0d1530\", \"#2a2f5c\", \"#7a4e74\", \"#e09a7a\"],\n  ridges: [\"#3b3a63\", \"#2a2b4c\", \"#1b1c36\", \"#11122a\"],\n  sun: \"#ffd2a8\",\n  card: \"rgba(24,24,28,0.6)\",\n  cardText: \"#f5f5f7\",\n  cardMuted: \"rgba(235,235,245,0.6)\",\n  cardTrack: \"rgba(255,255,255,0.16)\",\n  button: \"rgba(18,18,24,0.42)\",\n  phoneShadow: \"0 40px 90px rgba(0,0,0,0.55), 0 12px 30px rgba(0,0,0,0.4)\",\n};\nconst LIGHT: typeof DARK = {\n  stage: \"#EEF0F5\",\n  scrim: \"rgba(246,246,248,0.18)\",\n  copy: \"#121216\",\n  sky: [\"#3d7fd6\", \"#6fa6e4\", \"#a9cdee\", \"#e8f0f4\"],\n  ridges: [\"#8eaacb\", \"#6a8db5\", \"#4a6f9b\", \"#2f5280\"],\n  sun: \"#fff8e6\",\n  card: \"rgba(250,250,252,0.72)\",\n  cardText: \"#111113\",\n  cardMuted: \"rgba(60,60,67,0.66)\",\n  cardTrack: \"rgba(60,60,67,0.16)\",\n  button: \"rgba(255,255,255,0.32)\",\n  phoneShadow:\n    \"0 40px 80px rgba(30,32,40,0.2), 0 12px 28px rgba(30,32,40,0.12), 0 2px 6px rgba(30,32,40,0.08)\",\n};\ntype Palette = typeof DARK;\n\nconst PATH = {\n  render:\n    \"M4 6.5A2.5 2.5 0 016.5 4h11A2.5 2.5 0 0120 6.5v11a2.5 2.5 0 01-2.5 2.5h-11A2.5 2.5 0 014 17.5zM10 9v6l5-3z\",\n  delivery:\n    \"M6 8h12l-1 11.2a1 1 0 01-1 .8H8a1 1 0 01-1-.8zM9 8V7a3 3 0 016 0v1\",\n  deploy: \"M12 4l8 14H4z\",\n  check: \"M7 12.5l3.2 3.2L17 9\",\n  torch: \"M8 3h8v4l-2 3v10a2 2 0 01-4 0V10L8 7zM8 7h8\",\n  camera:\n    \"M4 8.5A1.5 1.5 0 015.5 7h2.3l1.5-2h5.4l1.5 2h2.3A1.5 1.5 0 0120 8.5v9a1.5 1.5 0 01-1.5 1.5h-13A1.5 1.5 0 014 17.5zM12 10a3.2 3.2 0 110 6.4 3.2 3.2 0 010-6.4z\",\n};\n\nconst HOME_APPS: { name: string; bg: [string, string]; d: string }[] = [\n  {\n    name: \"Orbitly\",\n    bg: [\"#ff7a59\", \"#f0473c\"],\n    d: \"M5 7h14v12H5zM5 11h14M9 4v4M15 4v4\",\n  },\n  {\n    name: \"Lumen\",\n    bg: [\"#5d6370\", \"#2f333b\"],\n    d: \"M12 9a3.5 3.5 0 110 7 3.5 3.5 0 010-7zM4 8h16v11H4z\",\n  },\n  {\n    name: \"Fernway\",\n    bg: [\"#3fcf8e\", \"#1c9a63\"],\n    d: \"M12 21s6-5.4 6-10.5a6 6 0 00-12 0C6 15.6 12 21 12 21zM12 8.5a2 2 0 110 4 2 2 0 010-4z\",\n  },\n  {\n    name: \"Halcyon\",\n    bg: [\"#5ab8ff\", \"#2f7fe8\"],\n    d: \"M12 5v2M5 12H3M7 7L5.6 5.6M17 7l1.4-1.4M8 15.5a4.5 4.5 0 118 0M5 18.5h14\",\n  },\n  {\n    name: \"Tessel\",\n    bg: [\"#ffd65a\", \"#f5b52e\"],\n    d: \"M7 4h10v16H7zM10 9h4M10 13h4\",\n  },\n  {\n    name: \"Kitebase\",\n    bg: [\"#4c8dff\", \"#2759e0\"],\n    d: \"M4 7h16v10H4zM4 7l8 6 8-6\",\n  },\n  {\n    name: \"Quarry\",\n    bg: [\"#7b86a6\", \"#4b5470\"],\n    d: \"M4 7.5A1.5 1.5 0 015.5 6H10l2 2h6.5A1.5 1.5 0 0120 9.5v8a1.5 1.5 0 01-1.5 1.5h-13A1.5 1.5 0 014 17.5z\",\n  },\n  { name: \"Pulse\", bg: [\"#ff6f91\", \"#e43f6f\"], d: \"M3 12h4l2-5 4 10 2-5h6\" },\n  {\n    name: \"Chord\",\n    bg: [\"#ff8e5e\", \"#ef5b3b\"],\n    d: \"M9 18V6l10-2v12M9 18a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zM19 16a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z\",\n  },\n  {\n    name: \"Ledger\",\n    bg: [\"#2fbf8f\", \"#14795a\"],\n    d: \"M5 18V10M10 18V6M15 18v-5M20 18V8\",\n  },\n  {\n    name: \"Atlas\",\n    bg: [\"#53c7d9\", \"#2a8fb0\"],\n    d: \"M12 3a9 9 0 110 18 9 9 0 010-18zM3 12h18M12 3c2.5 2.6 3.6 5.6 3.6 9s-1.1 6.4-3.6 9c-2.5-2.6-3.6-5.6-3.6-9s1.1-6.4 3.6-9z\",\n  },\n  {\n    name: \"Tally\",\n    bg: [\"#3a3a40\", \"#1c1c20\"],\n    d: \"M6 4h12v16H6zM9 8h6M9 12h.01M12 12h.01M15 12h.01M9 16h.01M12 16h.01M15 16h.01\",\n  },\n];\nconst DOCK: (typeof HOME_APPS)[number][] = [\n  {\n    name: \"Call\",\n    bg: [\"#5ee07a\", \"#2fb350\"],\n    d: \"M6.5 4h3l1.5 4-2 1.5a10 10 0 005.5 5.5L16 13l4 1.5v3a2 2 0 01-2 2A15 15 0 014.5 6a2 2 0 012-2z\",\n  },\n  {\n    name: \"Relay\",\n    bg: [\"#5ee07a\", \"#2fb350\"],\n    d: \"M12 4c4.4 0 8 3 8 6.8s-3.6 6.7-8 6.7c-1 0-2-.1-2.9-.4L5 19l1-3.6C4.8 14.2 4 12.6 4 10.8 4 7 7.6 4 12 4z\",\n  },\n  { name: \"Atlas\", bg: [\"#53c7d9\", \"#2a8fb0\"], d: HOME_APPS[10].d },\n  { name: \"Chord\", bg: [\"#ff8e5e\", \"#ef5b3b\"], d: HOME_APPS[8].d },\n];\n\nfunction Glyph({\n  d,\n  size = 24,\n  color,\n  sw = 1.8,\n}: {\n  d: string;\n  size?: number;\n  color: string;\n  sw?: number;\n}) {\n  return (\n    <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n      <path\n        d={d}\n        stroke={color}\n        strokeWidth={sw}\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  );\n}\n\nfunction StatusIcons({ color }: { color: string }) {\n  return (\n    <div style={{ display: \"flex\", gap: 6, alignItems: \"center\" }}>\n      <svg width=\"18\" height=\"12\" viewBox=\"0 0 18 12\">\n        {[0, 1, 2, 3].map((i) => (\n          <rect\n            key={i}\n            x={i * 4.6}\n            y={9 - i * 3}\n            width={3.2}\n            height={3 + i * 3}\n            rx={0.8}\n            fill={color}\n          />\n        ))}\n      </svg>\n      <svg width=\"17\" height=\"12\" viewBox=\"0 0 17 12\">\n        <path\n          d=\"M8.5 11.5l2.4-2.9a3.6 3.6 0 00-4.8 0zM3.7 6.2a7 7 0 019.6 0l1.6-1.9a9.6 9.6 0 00-12.8 0zM.5 2.9a12 12 0 0116 0\"\n          fill={color}\n          stroke={color}\n          strokeWidth={0.6}\n        />\n      </svg>\n      <div\n        style={{\n          width: 26,\n          height: 12.5,\n          borderRadius: 4,\n          border: `1px solid ${color}`,\n          padding: 1.5,\n          boxSizing: \"border-box\",\n        }}\n      >\n        <div\n          style={{\n            width: \"80%\",\n            height: \"100%\",\n            borderRadius: 2,\n            background: color,\n          }}\n        />\n      </div>\n    </div>\n  );\n}\n\nfunction Frame({ children }: { children: React.ReactNode }) {\n  const side = (s: \"left\" | \"right\", top: number, h: number) => (\n    <div\n      style={{\n        position: \"absolute\",\n        [s]: -2.5,\n        top,\n        width: 4,\n        height: h,\n        borderRadius: 2,\n        background: \"linear-gradient(90deg,#6f6f75,#d6d6db 50%,#6f6f75)\",\n      }}\n    />\n  );\n  return (\n    <div style={{ position: \"relative\", width: BW, height: BH }}>\n      {side(\"left\", 168, 30)}\n      {side(\"left\", 226, 60)}\n      {side(\"left\", 298, 60)}\n      {side(\"right\", 258, 96)}\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          borderRadius: 67,\n          background:\n            \"linear-gradient(140deg,#e4e4e8 0%,#8a8a91 16%,#cfcfd4 38%,#77777e 62%,#c8c8cd 84%,#8b8b91 100%)\",\n          boxShadow: \"inset 0 0 0 1px rgba(0,0,0,0.35)\",\n        }}\n      />\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 3,\n          borderRadius: 64,\n          background: \"#050506\",\n        }}\n      />\n      <div\n        style={{\n          position: \"absolute\",\n          left: BEZEL,\n          top: BEZEL,\n          width: SW,\n          height: SH,\n          borderRadius: 55,\n          overflow: \"hidden\",\n          background: \"#000\",\n        }}\n      >\n        {children}\n      </div>\n    </div>\n  );\n}\n\nfunction Wallpaper({ c, dim = 0 }: { c: Palette; dim?: number }) {\n  const id = useId().replace(/[^a-zA-Z0-9_-]/g, \"\");\n  const ridge = (y: number, amp: number, seed: number) => {\n    let d = `M0 ${SH}L0 ${y}`;\n    for (let x = 0; x <= SW; x += 6) {\n      const h =\n        Math.sin(x * 0.019 + seed) * amp +\n        Math.sin(x * 0.051 + seed * 2.3) * amp * 0.35 +\n        Math.sin(x * 0.17 + seed * 5.1) * amp * 0.08;\n      d += `L${x} ${y + h}`;\n    }\n    return `${d}L${SW} ${SH}Z`;\n  };\n  return (\n    <svg\n      width={SW}\n      height={SH}\n      viewBox={`0 0 ${SW} ${SH}`}\n      style={{ position: \"absolute\", inset: 0 }}\n    >\n      <defs>\n        <linearGradient id={`sky${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor={c.sky[0]} />\n          <stop offset=\"0.35\" stopColor={c.sky[1]} />\n          <stop offset=\"0.6\" stopColor={c.sky[2]} />\n          <stop offset=\"0.78\" stopColor={c.sky[3]} />\n        </linearGradient>\n        <radialGradient id={`sun${id}`} cx=\"0.62\" cy=\"0.6\" r=\"0.4\">\n          <stop offset=\"0\" stopColor={c.sun} stopOpacity={0.9} />\n          <stop offset=\"0.25\" stopColor={c.sun} stopOpacity={0.35} />\n          <stop offset=\"1\" stopColor={c.sun} stopOpacity={0} />\n        </radialGradient>\n        {c.ridges.map((col, i) => (\n          <linearGradient\n            key={col}\n            id={`r${i}${id}`}\n            x1=\"0\"\n            y1=\"0\"\n            x2=\"0\"\n            y2=\"1\"\n          >\n            <stop offset=\"0\" stopColor={col} />\n            <stop offset=\"0.5\" stopColor={c.ridges[i + 1] ?? col} />\n          </linearGradient>\n        ))}\n      </defs>\n      <rect width={SW} height={SH} fill={`url(#sky${id})`} />\n      <rect width={SW} height={SH} fill={`url(#sun${id})`} />\n      {c.ridges.map((col, i) => (\n        <path\n          key={col}\n          d={ridge(470 + i * 80, 34 - i * 4, i * 1.7 + 0.4)}\n          fill={`url(#r${i}${id})`}\n        />\n      ))}\n      <rect width={SW} height={SH} fill=\"#000\" opacity={dim} />\n    </svg>\n  );\n}\n\nfunction HomeScreen({ c, accent }: { c: Palette; accent: string }) {\n  const tile = (\n    app: (typeof HOME_APPS)[number],\n    x: number,\n    y: number,\n    label: boolean,\n  ) => (\n    <div\n      key={`${app.name}${x}${y}`}\n      style={{\n        position: \"absolute\",\n        left: x,\n        top: y,\n        width: 62,\n        display: \"flex\",\n        flexDirection: \"column\",\n        alignItems: \"center\",\n        gap: 5,\n      }}\n    >\n      <div\n        style={{\n          width: 62,\n          height: 62,\n          borderRadius: 14,\n          background: `linear-gradient(180deg, ${app.bg[0]}, ${app.bg[1]})`,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n        }}\n      >\n        <Glyph d={app.d} size={32} color=\"#ffffff\" sw={1.7} />\n      </div>\n      {label ? (\n        <span\n          style={{\n            fontSize: 12,\n            fontWeight: 400,\n            color: \"#ffffff\",\n            textShadow: \"0 1px 2px rgba(0,0,0,0.25)\",\n          }}\n        >\n          {app.name}\n        </span>\n      ) : null}\n    </div>\n  );\n  const apps = [\n    ...HOME_APPS.slice(0, 11),\n    {\n      name: \"remocn\",\n      bg: [accent, accent] as [string, string],\n      d: PATH.render,\n    },\n    ...HOME_APPS.slice(11),\n  ];\n  return (\n    <>\n      <Wallpaper c={c} dim={0.08} />\n      {apps.map((app, i) =>\n        tile(app, 27 + (i % 4) * 88, 74 + Math.floor(i / 4) * 102, true),\n      )}\n      <div\n        style={{\n          position: \"absolute\",\n          left: (SW - 82) / 2,\n          bottom: 128,\n          height: 30,\n          width: 82,\n          borderRadius: 15,\n          background: \"rgba(255,255,255,0.22)\",\n          color: \"#ffffff\",\n          fontSize: 13,\n          fontWeight: 400,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          gap: 4,\n        }}\n      >\n        <Glyph\n          d=\"M10.5 4a6.5 6.5 0 110 13 6.5 6.5 0 010-13zM20 20l-4.8-4.8\"\n          size={13}\n          color=\"#ffffff\"\n          sw={2.2}\n        />\n        Search\n      </div>\n      <div\n        style={{\n          position: \"absolute\",\n          left: 12,\n          right: 12,\n          bottom: 12,\n          height: 94,\n          borderRadius: 34,\n          background: \"rgba(255,255,255,0.2)\",\n          backdropFilter: \"blur(20px)\",\n        }}\n      />\n      {DOCK.map((app, i) => tile(app, 27 + i * 88, SH - 12 - 94 + 16, false))}\n    </>\n  );\n}\n\nfunction fmtTime(sec: number, format: \"clock\" | \"minutes\") {\n  if (format === \"minutes\") return `${Math.max(1, Math.ceil(sec / 60))} min`;\n  const s = Math.max(0, Math.round(sec));\n  return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, \"0\")}`;\n}\n\nfunction Ticker({\n  value,\n  prev,\n  since,\n  style,\n}: {\n  value: string;\n  prev: string;\n  since: number;\n  style: React.CSSProperties;\n}) {\n  const t = enterE(Math.min(1, since / 4));\n  const chars = Array.from(value);\n  const old = Array.from(prev.padStart(chars.length, \" \"));\n  return (\n    <span\n      style={{\n        display: \"inline-flex\",\n        fontVariantNumeric: \"tabular-nums\",\n        ...style,\n      }}\n    >\n      {chars.map((ch, i) => {\n        const changed = old[i] !== ch && prev.length === value.length;\n        return (\n          <span\n            key={i}\n            style={{\n              position: \"relative\",\n              display: \"inline-block\",\n              whiteSpace: \"pre\",\n              overflow: \"hidden\",\n            }}\n          >\n            <span\n              style={{\n                display: \"inline-block\",\n                transform: changed ? `translateY(${(1 - t) * 45}%)` : undefined,\n                opacity: changed ? t : 1,\n              }}\n            >\n              {ch}\n            </span>\n            {changed && t < 1 ? (\n              <span\n                style={{\n                  position: \"absolute\",\n                  left: 0,\n                  top: 0,\n                  transform: `translateY(${-t * 45}%)`,\n                  opacity: 1 - t,\n                }}\n              >\n                {old[i]}\n              </span>\n            ) : null}\n          </span>\n        );\n      })}\n    </span>\n  );\n}\n\ninterface ActivityState {\n  timeText: string;\n  prevText: string;\n  sinceTick: number;\n  progress: number;\n  step: number;\n  done: number;\n  detail: string;\n}\n\nfunction AppBadge({\n  size,\n  glyph,\n  accent,\n}: {\n  size: number;\n  glyph: string;\n  accent: string;\n}) {\n  return (\n    <div\n      style={{\n        width: size,\n        height: size,\n        borderRadius: size * 0.28,\n        background: accent,\n        display: \"flex\",\n        alignItems: \"center\",\n        justifyContent: \"center\",\n        flexShrink: 0,\n      }}\n    >\n      <Glyph d={glyph} size={size * 0.62} color=\"#ffffff\" sw={1.9} />\n    </div>\n  );\n}\n\nfunction ActivityBody({\n  s,\n  status,\n  accent,\n  text,\n  muted,\n  track,\n  glyph,\n  compactTop,\n}: {\n  s: ActivityState;\n  status: LiveActivityStatus;\n  accent: string;\n  text: string;\n  muted: string;\n  track: string;\n  glyph: string;\n  compactTop: boolean;\n}) {\n  const title = s.done > 0.5 ? status.doneTitle : status.title;\n  const detail = s.done > 0.5 ? status.doneDetail : s.detail;\n  const swap = s.done > 0 && s.done < 1 ? Math.abs(s.done - 0.5) * 2 : 1;\n  return (\n    <>\n      <div style={{ display: \"flex\", alignItems: \"flex-start\", gap: 12 }}>\n        <AppBadge size={compactTop ? 46 : 40} glyph={glyph} accent={accent} />\n        <div\n          style={{\n            flex: 1,\n            minWidth: 0,\n            paddingTop: compactTop ? 4 : 1,\n            opacity: compactTop ? 0 : 1,\n          }}\n        >\n          <div style={{ fontSize: 13, color: muted }}>{status.app}</div>\n          <div\n            style={{\n              fontSize: 17,\n              fontWeight: 400,\n              color: text,\n              marginTop: 1,\n              opacity: swap,\n            }}\n          >\n            {title}\n          </div>\n        </div>\n        <div\n          style={{\n            position: \"relative\",\n            textAlign: \"right\",\n            paddingTop: compactTop ? 6 : 2,\n          }}\n        >\n          <div style={{ opacity: 1 - s.done }}>\n            <Ticker\n              value={s.timeText}\n              prev={s.prevText}\n              since={s.sinceTick}\n              style={{\n                fontSize: 32,\n                fontWeight: 300,\n                color: text,\n                letterSpacing: \"-0.03em\",\n                lineHeight: 1,\n              }}\n            />\n            <div style={{ fontSize: 12, color: muted, marginTop: 3 }}>\n              remaining\n            </div>\n          </div>\n          {s.done > 0 ? (\n            <div\n              style={{\n                position: \"absolute\",\n                right: 0,\n                top: compactTop ? 4 : 0,\n                width: 32,\n                height: 32,\n                borderRadius: 16,\n                background: accent,\n                display: \"flex\",\n                alignItems: \"center\",\n                justifyContent: \"center\",\n                opacity: s.done,\n                transform: `scale(${0.9 + s.done * 0.1})`,\n              }}\n            >\n              <Glyph d={PATH.check} size={22} color=\"#ffffff\" sw={2.4} />\n            </div>\n          ) : null}\n        </div>\n      </div>\n      {compactTop ? (\n        <div\n          style={{\n            fontSize: 18,\n            fontWeight: 400,\n            color: text,\n            marginTop: 12,\n            opacity: swap,\n          }}\n        >\n          {title}\n        </div>\n      ) : null}\n      <div\n        style={{\n          fontSize: 13,\n          color: muted,\n          marginTop: compactTop ? 2 : 8,\n          fontVariantNumeric: \"tabular-nums\",\n          opacity: swap,\n        }}\n      >\n        {detail}\n      </div>\n      <div\n        style={{\n          position: \"relative\",\n          height: 6,\n          borderRadius: 3,\n          background: track,\n          marginTop: 14,\n        }}\n      >\n        <div\n          style={{\n            position: \"absolute\",\n            left: 0,\n            top: 0,\n            bottom: 0,\n            width: `${s.progress * 100}%`,\n            borderRadius: 3,\n            background: accent,\n          }}\n        />\n        <div\n          style={{\n            position: \"absolute\",\n            top: -4,\n            left: `calc(${s.progress * 100}% - 7px)`,\n            width: 14,\n            height: 14,\n            borderRadius: 7,\n            background: \"#ffffff\",\n            boxShadow: `0 0 0 3px ${accent}`,\n            opacity: 1 - s.done,\n          }}\n        />\n      </div>\n      <div\n        style={{\n          display: \"flex\",\n          justifyContent: \"space-between\",\n          marginTop: 8,\n          fontSize: 12,\n        }}\n      >\n        {status.steps.map((label, i) => (\n          <span\n            key={label}\n            style={{\n              color: i <= s.step || s.done > 0.5 ? text : muted,\n            }}\n          >\n            {label}\n          </span>\n        ))}\n      </div>\n    </>\n  );\n}\n\nexport function LiveActivity({\n  status = LIVE_ACTIVITY_RENDER,\n  date = \"Tuesday, October 24\",\n  accent = \"#3B5BFD\",\n  speed = 1,\n  theme = \"dark\",\n  ground,\n  groundParams,\n}: LiveActivityProps) {\n  const frame = useCurrentFrame();\n  const { fps, width, height } = useVideoConfig();\n  const f = frame * speed;\n  const c: Palette = theme === \"light\" ? LIGHT : DARK;\n  const tall = height > width;\n  const k = (height * (tall ? 0.66 : 0.92)) / BH;\n  const phoneCx = tall ? width / 2 : width * 0.7;\n  const yOff = tall ? 0.1 : 0;\n  const lines = status.lines ?? [];\n  const sp = (at: number, config: SpringCfg, durationInFrames?: number) =>\n    spring({ frame: f - at, fps, config, durationInFrames });\n  const format = status.format ?? \"clock\";\n  const glyph = PATH[status.glyph ?? \"render\"];\n\n  const iosSpring = (at: number) => sp(at, CARD);\n  const bump = (at: number) => sp(at - 2, MORPH, 3) - sp(at + 2, CHIP);\n\n  const span = T_FIN - T_START;\n  const tickLen = span / status.seconds;\n  const live = Math.max(0, Math.min(span, f - T_START));\n  const tick = Math.floor(live / tickLen);\n  const remaining = status.seconds - tick;\n  const timeText = fmtTime(remaining, format);\n  const prevText = fmtTime(remaining + 1, format);\n  const sinceTick =\n    timeText === prevText || tick === 0 ? 99 : live - tick * tickLen;\n  const progress = interpolate(live, [0, span], [0.04, 1], clamp);\n  const step = progress < 0.18 ? 0 : progress < 0.82 ? 1 : 2;\n  const pct = `${Math.round(progress * 100)}%`;\n  const done = Math.min(1, sp(T_FIN + 2, CHIP));\n  const act: ActivityState = {\n    timeText,\n    prevText,\n    sinceTick: format === \"minutes\" ? 99 : sinceTick,\n    progress,\n    step,\n    done,\n    detail: (status.details[step] ?? \"\").replace(\"{pct}\", pct),\n  };\n\n  const cover = (() => {\n    const pull = interpolate(f, [T_SWIPE, T_RELEASE], [0, 0.42], {\n      ...clamp,\n      easing: moveE,\n    });\n    const rest = interpolate(f, [T_RELEASE, T_RELEASE + 11], [0, 0.58], {\n      ...clamp,\n      easing: sheet,\n    });\n    return pull + rest;\n  })();\n  const bloom = iosSpring(T_START) * (1 - iosSpring(T_SWIPE + 4));\n  const m = iosSpring(T_EXP) - iosSpring(T_COL);\n  const islW = ISL_W + (CMP_W - ISL_W) * bloom + (EXP_W - CMP_W) * m;\n  const islH = ISL_H + (EXP_H - ISL_H) * m;\n  const islR = Math.min(islH / 2, 18 + (EXP_R - 18) * m);\n  const compactOp =\n    interpolate(m, [0.05, 0.35], [1, 0], clamp) * Math.min(1, bloom * 1.6);\n  const expandOp = interpolate(m, [0.2, 0.6], [0, 1], clamp);\n\n  const camT = [0, 22, 46, 160, 182, 204, 226];\n  const camEase = { ...clamp, easing: camE };\n  const camS = interpolate(\n    f,\n    camT,\n    tall ? [1, 1, 1.5, 1.5, 1, 1, 1.04] : [1, 1, 1.85, 1.85, 1, 1, 1.38],\n    camEase,\n  );\n  const camFy = interpolate(\n    f,\n    camT,\n    [\n      BH / 2,\n      BH / 2,\n      140,\n      140,\n      BH / 2,\n      BH / 2,\n      tall ? BH / 2 : BEZEL + CARD_Y + 30,\n    ],\n    camEase,\n  );\n  const camTy = interpolate(\n    f,\n    camT,\n    [0.5, 0.5, 0.36, 0.36, 0.5, 0.5, 0.5].map((v) => v + yOff),\n    camEase,\n  );\n  const rise = sp(0, HEAVY);\n  const S = k * camS;\n\n  const touches = [\n    { t: 40, x: 250, y: 230 },\n    { t: T_PRESS, x: SW / 2 + 4, y: 30 },\n    { t: T_COL - 1, x: 296, y: 398 },\n    { t: T_SWIPE - 10, x: 70, y: 90 },\n    { t: T_SWIPE, x: 64, y: 14 },\n    { t: T_RELEASE, x: 74, y: 380 },\n  ];\n  let touch = { x: touches[0].x, y: touches[0].y };\n  for (let i = 0; i < touches.length - 1; i++) {\n    const a = touches[i];\n    const b = touches[i + 1];\n    const dragging = a.t === T_SWIPE;\n    const start = dragging ? a.t : a.t + 3;\n    const end = dragging ? b.t : b.t - 2;\n    if (f >= start) {\n      const p = Math.min(1, (f - start) / (end - start));\n      const e = moveE(p);\n      const arc = dragging ? 0 : Math.sin(Math.PI * e) * 22;\n      touch = {\n        x: a.x + (b.x - a.x) * e + arc * 0.5,\n        y: a.y + (b.y - a.y) * e - arc * 0.4,\n      };\n    }\n  }\n  const down = Math.min(\n    1,\n    interpolate(\n      f,\n      [T_PRESS, T_PRESS + 2, T_EXP + 2, T_EXP + 4],\n      [0, 1, 1, 0],\n      clamp,\n    ) +\n      bump(T_COL - 1) +\n      interpolate(\n        f,\n        [T_SWIPE - 2, T_SWIPE, T_RELEASE, T_RELEASE + 2],\n        [0, 1, 1, 0],\n        clamp,\n      ),\n  );\n  const touchOpacity = interpolate(\n    f,\n    [\n      40,\n      46,\n      T_EXP + 4,\n      T_EXP + 9,\n      T_COL - 10,\n      T_COL - 5,\n      T_COL + 3,\n      T_COL + 8,\n      T_SWIPE - 10,\n      T_SWIPE - 5,\n      T_RELEASE + 2,\n      T_RELEASE + 7,\n    ],\n    [0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0],\n    clamp,\n  );\n  const pressScale = 1 - 0.04 * bump(T_PRESS + 2);\n\n  const cardIn = sp(T_RELEASE - 2, CARD);\n\n  return (\n    <AbsoluteFill\n      style={{ fontFamily, overflow: \"hidden\", background: c.stage }}\n    >\n      <GshGround\n        preset={ground ?? (theme === \"light\" ? \"glasswork\" : \"earthshine\")}\n        params={groundParams}\n        timeOffset={theme === \"light\" ? 3 : 6}\n        timeScale={0.3}\n      />\n      <AbsoluteFill style={{ background: c.scrim }} />\n      <div\n        style={{\n          position: \"absolute\",\n          left: tall ? width * 0.08 : width * 0.075,\n          top: tall ? height * 0.075 : height * 0.5 - height * 0.12,\n          width: tall ? width * 0.84 : width * 0.38,\n          height: tall ? height * 0.12 : height * 0.24,\n          overflow: \"hidden\",\n        }}\n      >\n        {lines.slice(0, LINE_AT.length).map((line, i) => {\n          const at = LINE_AT[i];\n          const next = LINE_AT[i + 1] ?? 100000;\n          const pin = i === 0 ? rise : tween(f, at, at + 12);\n          const pout = tween(f, next - 7, next, exitE);\n          if (f < at - 1 || f > next + 1) return null;\n          return (\n            <div\n              key={line}\n              style={{\n                position: \"absolute\",\n                inset: 0,\n                display: \"flex\",\n                alignItems: tall ? \"flex-start\" : \"center\",\n                fontSize: tall ? height * 0.04 : height * 0.085,\n                fontWeight: 300,\n                lineHeight: 1.04,\n                letterSpacing: \"-0.035em\",\n                color: c.copy,\n                textWrap: \"balance\",\n                transform: `translateY(${(1 - pin) * 70 - pout * 50}%)`,\n                opacity: pin * (1 - pout),\n              }}\n            >\n              {line}\n            </div>\n          );\n        })}\n      </div>\n      <div\n        style={{\n          position: \"absolute\",\n          left: 0,\n          top: 0,\n          width: BW,\n          height: BH,\n          transformOrigin: \"0 0\",\n          transform: `translate(${phoneCx - (BW / 2) * S}px, ${height * camTy - camFy * S + (1 - rise) * height}px) scale(${S})`,\n          WebkitFontSmoothing: \"antialiased\",\n        }}\n      >\n        <div\n          style={{\n            position: \"absolute\",\n            inset: 0,\n            borderRadius: 67,\n            boxShadow: c.phoneShadow,\n          }}\n        />\n        <Frame>\n          <HomeScreen c={c} accent={accent} />\n          <div\n            style={{\n              position: \"absolute\",\n              top: 0,\n              left: 0,\n              right: 0,\n              height: 54,\n              display: \"flex\",\n              alignItems: \"center\",\n              justifyContent: \"space-between\",\n              padding: \"4px 24px 0 44px\",\n              color: \"#ffffff\",\n              zIndex: 5,\n            }}\n          >\n            <span style={{ fontSize: 17, fontWeight: 400 }}>9:41</span>\n            <StatusIcons color=\"#ffffff\" />\n          </div>\n          {cover > 0 ? (\n            <div\n              style={{\n                position: \"absolute\",\n                inset: 0,\n                transform: `translateY(${-(1 - cover) * SH}px)`,\n                zIndex: 10,\n                overflow: \"hidden\",\n              }}\n            >\n              <Wallpaper c={c} />\n              <div\n                style={{\n                  position: \"absolute\",\n                  top: 0,\n                  right: 30,\n                  height: 54,\n                  paddingTop: 4,\n                  display: \"flex\",\n                  alignItems: \"center\",\n                }}\n              >\n                <StatusIcons color=\"#ffffff\" />\n              </div>\n              <div\n                style={{\n                  position: \"absolute\",\n                  top: 92,\n                  left: 0,\n                  right: 0,\n                  textAlign: \"center\",\n                  color: \"rgba(255,255,255,0.92)\",\n                }}\n              >\n                <div style={{ fontSize: 20, fontWeight: 400 }}>{date}</div>\n                <div\n                  style={{\n                    fontSize: 104,\n                    fontWeight: 300,\n                    letterSpacing: \"-0.03em\",\n                    lineHeight: 1,\n                    marginTop: 4,\n                    fontVariantNumeric: \"tabular-nums\",\n                  }}\n                >\n                  9:41\n                </div>\n              </div>\n              <div\n                style={{\n                  position: \"absolute\",\n                  left: 12,\n                  right: 12,\n                  top: CARD_Y,\n                  padding: \"16px 18px 14px\",\n                  borderRadius: 26,\n                  background: c.card,\n                  backdropFilter: \"blur(24px) saturate(1.4)\",\n                  opacity: cardIn,\n                  transform: `translateY(${(1 - cardIn) * 14}px) scale(${0.97 + cardIn * 0.03})`,\n                }}\n              >\n                <ActivityBody\n                  s={act}\n                  status={status}\n                  accent={accent}\n                  text={c.cardText}\n                  muted={c.cardMuted}\n                  track={c.cardTrack}\n                  glyph={glyph}\n                  compactTop={false}\n                />\n              </div>\n              {[PATH.torch, PATH.camera].map((d, i) => (\n                <div\n                  key={d}\n                  style={{\n                    position: \"absolute\",\n                    bottom: 50,\n                    left: i ? SW - 46 - 50 : 46,\n                    width: 50,\n                    height: 50,\n                    borderRadius: 25,\n                    background: c.button,\n                    backdropFilter: \"blur(16px)\",\n                    display: \"flex\",\n                    alignItems: \"center\",\n                    justifyContent: \"center\",\n                  }}\n                >\n                  <Glyph d={d} size={22} color=\"#ffffff\" sw={1.7} />\n                </div>\n              ))}\n            </div>\n          ) : null}\n          <div\n            style={{\n              position: \"absolute\",\n              top: ISL_TOP,\n              left: (SW - islW) / 2,\n              width: islW,\n              height: islH,\n              borderRadius: islR,\n              background: \"#000\",\n              zIndex: 40,\n              overflow: \"hidden\",\n              transform: `scale(${pressScale})`,\n              transformOrigin: \"50% 0\",\n              boxShadow: m > 0.02 ? \"0 10px 30px rgba(0,0,0,0.28)\" : \"none\",\n            }}\n          >\n            {compactOp > 0 ? (\n              <div\n                style={{\n                  position: \"absolute\",\n                  left: 0,\n                  right: 0,\n                  top: 0,\n                  height: ISL_H,\n                  display: \"flex\",\n                  alignItems: \"center\",\n                  justifyContent: \"space-between\",\n                  padding: \"0 10px 0 8px\",\n                  opacity: compactOp,\n                  filter: `blur(${(1 - compactOp) * 4}px)`,\n                }}\n              >\n                <div style={{ paddingLeft: 4 }}>\n                  <Glyph d={glyph} size={18} color={accent} sw={1.75} />\n                </div>\n                {done > 0 ? (\n                  <Glyph d={PATH.check} size={20} color={accent} sw={2} />\n                ) : (\n                  <div\n                    style={{ display: \"flex\", alignItems: \"center\", gap: 7 }}\n                  >\n                    <Ticker\n                      value={timeText}\n                      prev={prevText}\n                      since={act.sinceTick}\n                      style={{ fontSize: 15, color: accent }}\n                    />\n                    <svg width={18} height={18} viewBox=\"0 0 18 18\">\n                      <circle\n                        cx={9}\n                        cy={9}\n                        r={7}\n                        fill=\"none\"\n                        stroke=\"rgba(255,255,255,0.18)\"\n                        strokeWidth={2.2}\n                      />\n                      <circle\n                        cx={9}\n                        cy={9}\n                        r={7}\n                        fill=\"none\"\n                        stroke={accent}\n                        strokeWidth={2.2}\n                        strokeLinecap=\"round\"\n                        pathLength={1}\n                        strokeDasharray={`${progress} 1`}\n                        transform=\"rotate(-90 9 9)\"\n                      />\n                    </svg>\n                  </div>\n                )}\n              </div>\n            ) : null}\n            {expandOp > 0 ? (\n              <div\n                style={{\n                  position: \"absolute\",\n                  left: (islW - EXP_W) / 2,\n                  top: 0,\n                  width: EXP_W,\n                  height: EXP_H,\n                  padding: \"18px 22px 0\",\n                  opacity: expandOp,\n                  filter: `blur(${(1 - expandOp) * 3}px)`,\n                  transform: `scale(${(islW / EXP_W) * (0.96 + expandOp * 0.04)})`,\n                  transformOrigin: \"50% 0\",\n                }}\n              >\n                <ActivityBody\n                  s={act}\n                  status={status}\n                  accent={accent}\n                  text=\"#f5f5f7\"\n                  muted=\"rgba(235,235,245,0.6)\"\n                  track=\"rgba(255,255,255,0.16)\"\n                  glyph={glyph}\n                  compactTop\n                />\n              </div>\n            ) : null}\n          </div>\n          <div\n            style={{\n              position: \"absolute\",\n              bottom: 8,\n              left: (SW - 136) / 2,\n              width: 136,\n              height: 5,\n              borderRadius: 3,\n              background: \"#ffffff\",\n              zIndex: 40,\n            }}\n          />\n          <div\n            style={{\n              position: \"absolute\",\n              left: touch.x - 22,\n              top: touch.y - 22,\n              width: 44,\n              height: 44,\n              borderRadius: 22,\n              background: \"rgba(255,255,255,0.22)\",\n              border: \"1.5px solid rgba(255,255,255,0.8)\",\n              boxShadow: \"0 2px 10px rgba(0,0,0,0.25)\",\n              opacity: touchOpacity,\n              transform: `scale(${1 - down * 0.14})`,\n              zIndex: 45,\n            }}\n          />\n        </Frame>\n      </div>\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/live-activity.tsx"
    }
  ],
  "type": "registry:component"
}
