# Apple Pro Display XDR

> Apple Pro Display XDR mockup for React and shadcn/ui with an aluminum frame, screen modes, and an animated macOS dock.

Source: https://www.cult-ui.com/docs/components/apple-pro-display-xdr

## Example

```tsx title="apple-pro-display-xdr-demo.tsx"
"use client"

import { AppleProDisplayXDR } from "@/components/ui/apple-pro-display-xdr"

export default function AppleProDisplayXDRDemo() {
  return (
    <div className="flex items-center justify-center">
      <AppleProDisplayXDR />
    </div>
  )
}
```

Apple Pro Display XDR is a React display mockup component for shadcn/ui, animated with Motion. Use it to showcase desktop apps on landing pages, or pass your own screen content.

## Installation

### CLI

```bash
npx shadcn@latest add @cult-ui/apple-pro-display-xdr
```

### Manual

**Install the required dependencies:**

```bash
npm install @tabler/icons-react motion
```

**Install the tooltip component from shadcn/ui:**

```bash
npx shadcn@latest add tooltip
```

**Copy and paste the following code into your project.**

```tsx title="apple-pro-display-xdr.tsx"
"use client"

/**
 * Apple Studio Display–style hero: aluminum frame, glass stack, screen bezel,
 * camera / “recording” LED, optional built-in demos, and a magnifying macOS dock.
 * Click the screen (not the dock) to cycle demos unless `screenContent` is set.
 */
import type { CSSProperties, ReactNode, SVGProps } from "react"
import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useId,
  useMemo,
  useRef,
  useState,
} from "react"
import Image from "next/image"
import { IconDownload } from "@tabler/icons-react"
import {
  motion,
  useMotionValue,
  useReducedMotion,
  useSpring,
  useTransform,
  type MotionValue,
} from "motion/react"

import { cn } from "@/lib/utils"
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/base-tooltip"

// ---------------------------------------------------------------------------
// Scene + frame tokens
// ---------------------------------------------------------------------------

/** Fills the cable-management cutout so the hole reads as depth, not transparency */
const SCENE_BG = "#000000"

/** Brush-metal bezel, chamfers, and hardware accents */
const ALUMINUM = {
  brushLo: "#c2c2c4",
  brushHi: "#d8d8da",
  chamfer: "#e8e8ea",
  bezel: "#000000",
  cameraDot: "#1a1a1a",
  led: "#30d158",
}

/** Outer shell padding; pairs with `R_*` for nested rounded rects */
const FRAME_PX = 5
const R_OUTER = 10
const R_GLASS = 8
const R_SCREEN = 6
/** Black inner frame insets (asymmetric bottom clears “chin” / dock visual) */
const BEZEL = { top: 11, side: 7, bottom: 16 }

/** Drop-shadow tint on hover; index aligns with `MODES` / `modeIndex` */
const SCREEN_GLOW = [
  "rgba(196, 72, 58, 0.35)",
  "rgba(88, 140, 220, 0.32)",
  "rgba(210, 170, 90, 0.3)",
  "rgba(150, 110, 230, 0.34)",
] as const

// ---------------------------------------------------------------------------
// Dock icons (inline SVG; Finder uses `useId` for unique gradient IDs)
// ---------------------------------------------------------------------------

const SpotifyIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} preserveAspectRatio="xMidYMid" viewBox="0 0 256 256">
    <title>Spotify Icon</title>
    <path
      d="M128 0C57.308 0 0 57.309 0 128c0 70.696 57.309 128 128 128 70.697 0 128-57.304 128-128C256 57.314 198.697.007 127.998.007l.001-.006Zm58.699 184.614c-2.293 3.76-7.215 4.952-10.975 2.644-30.053-18.357-67.885-22.515-112.44-12.335a7.981 7.981 0 0 1-9.552-6.007 7.968 7.968 0 0 1 6-9.553c48.76-11.14 90.583-6.344 124.323 14.276 3.76 2.308 4.952 7.215 2.644 10.975Zm15.667-34.853c-2.89 4.695-9.034 6.178-13.726 3.289-34.406-21.148-86.853-27.273-127.548-14.92-5.278 1.594-10.852-1.38-12.454-6.649-1.59-5.278 1.386-10.842 6.655-12.446 46.485-14.106 104.275-7.273 143.787 17.007 4.692 2.89 6.175 9.034 3.286 13.72v-.001Zm1.345-36.293C162.457 88.964 94.394 86.71 55.007 98.666c-6.325 1.918-13.014-1.653-14.93-7.978-1.917-6.328 1.65-13.012 7.98-14.935C93.27 62.027 168.434 64.68 215.929 92.876c5.702 3.376 7.566 10.724 4.188 16.405-3.362 5.69-10.73 7.565-16.4 4.187h-.006Z"
      fill="#1ED760"
    />
  </svg>
)

const SafariIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg
    {...props}
    viewBox="0 0 66.165833 65.803795"
    xmlnsXlink="http://www.w3.org/1999/xlink"
  >
    <title>Safari logo</title>
    <defs>
      <linearGradient id="safari__b">
        <stop offset="0" stopColor="#06c2e7" />
        <stop offset=".25000015" stopColor="#0db8ec" />
        <stop offset=".5000003" stopColor="#12aef1" />
        <stop offset=".75000012" stopColor="#1f86f9" />
        <stop offset="1" stopColor="#107ddd" />
      </linearGradient>
      <linearGradient id="safari__a">
        <stop offset="0" stopColor="#bdbdbd" />
        <stop offset="1" stopColor="#fff" />
      </linearGradient>
      <linearGradient
        gradientTransform="translate(206.79018 159.77261) scale(.35154)"
        gradientUnits="userSpaceOnUse"
        id="safari__d"
        x1="412.97501"
        x2="412.97501"
        xlinkHref="#safari__a"
        y1="237.60777"
        y2="59.392235"
      />
      <filter
        colorInterpolationFilters="sRGB"
        height="1.0446756"
        id="safari__f"
        width="1.0418189"
        x="-.02090938"
        y="-.0223378"
      >
        <feGaussianBlur stdDeviation=".95767362" />
      </filter>
      <filter
        colorInterpolationFilters="sRGB"
        height="1.096"
        id="safari__c"
        width="1.096"
        x="-.048"
        y="-.048"
      >
        <feGaussianBlur stdDeviation="3.5643107" />
      </filter>
      <radialGradient
        cx="413.06128"
        cy="136.81819"
        fx="413.06128"
        fy="136.81819"
        gradientTransform="translate(194.54473 155.58044) scale(.38143)"
        gradientUnits="userSpaceOnUse"
        id="safari__e"
        r="82.125351"
        xlinkHref="#safari__b"
      />
    </defs>
    <path
      d="M502.08277 148.5a89.107765 89.107765 0 0 1-89.10777 89.10777A89.107765 89.107765 0 0 1 323.86724 148.5 89.107765 89.107765 0 0 1 412.975 59.392235 89.107765 89.107765 0 0 1 502.08277 148.5Z"
      filter="url(#safari__c)"
      opacity=".52999998"
      paintOrder="markers stroke fill"
      transform="matrix(.33865 0 0 .3261 -106.76956 -14.47833)"
    />
    <path
      d="M383.29373 211.97671a31.325188 31.325188 0 0 1-31.32519 31.32519 31.325188 31.325188 0 0 1-31.32518-31.32519 31.325188 31.325188 0 0 1 31.32518-31.32519 31.325188 31.325188 0 0 1 31.32519 31.32519z"
      fill="url(#safari__d)"
      paintOrder="markers stroke fill"
      stroke="#cdcdcd"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth=".09301235"
      transform="translate(-318.88562 -180.59501)"
    />
    <path
      d="M380.83911 211.97671a28.870571 28.870571 0 0 1-28.87057 28.87057 28.870571 28.870571 0 0 1-28.87057-28.87057 28.870571 28.870571 0 0 1 28.87057-28.87057 28.870571 28.870571 0 0 1 28.87057 28.87057z"
      fill="url(#safari__e)"
      paintOrder="markers stroke fill"
      transform="translate(-318.88562 -180.59501)"
    />
    <path
      d="M33.08292 4.01671c-.23319 0-.42092.18772-.42092.42092V9.2928c0 .2332.18773.42092.42092.42092.2332 0 .42092-.18772.42092-.42092V4.43763c0-.2332-.18772-.42092-.42092-.42092zm-2.75367.17404c-.0279-.003-.0566-.003-.0856.00035-.23194.0242-.39917.2304-.37495.46234l.21218 2.03119c.0242.23194.23041.39918.46233.37496.23195-.0242.39919-.2304.37496-.46234l-.212-2.03118c-.0212-.20295-.18177-.35637-.37695-.37532zm5.5266.002c-.19519.0188-.35578.17221-.37714.37513l-.21363 2.03102c-.0244.23192.14285.43831.37478.4627.23191.0244.43811-.14268.46251-.3746l.21364-2.03119c.0244-.23192-.14286-.43814-.37478-.46252-.029-.003-.0575-.003-.0854-.00052zm-8.3553.4082c-.028.00022-.0565.003-.085.009-.22814.0483-.37294.27089-.32464.49903l1.00552 4.74981c.0483.22814.27088.37293.49902.32464.22814-.0483.37294-.27072.32465-.49886l-1.00552-4.74998c-.0423-.19963-.21792-.33543-.41401-.3339zm11.18382.004c-.19609-.002-.3718.13394-.41419.33353l-1.00897 4.74925c-.0485.22811.0962.45076.32427.49922.22811.0485.45076-.0962.49921-.32428l1.00897-4.74926c.0485-.2281-.0962-.45076-.32427-.49921-.0285-.006-.057-.009-.085-.009zM24.801 5.36212c-.0545-.005-.11077.001-.16622.0194-.22178.0721-.34238.3085-.27031.53028l.6311 1.94236c.0721.22179.30868.34238.53046.27032.22179-.0721.3422-.30868.27013-.53046l-.63109-1.94236c-.054-.16634-.20059-.27568-.36407-.28958zm16.56765.001c-.16348.0139-.30999.12324-.36406.28957l-.63147 1.94218c-.0721.22177.0484.45837.27014.53046.22178.0721.45837-.0484.53047-.27013l.63146-1.94236c.0721-.22178-.0484-.45837-.27014-.53046-.0554-.018-.11191-.0239-.1664-.0193zm-19.23721.9759c-.0547.001-.11004.013-.16331.0367-.21298.0947-.30836.34244-.21364.55553l1.97197 4.43662c.0947.21308.34244.30836.55553.21364.21298-.0947.30854-.34244.21382-.55553l-1.97216-4.43662c-.071-.15983-.22817-.25351-.39221-.25033zm21.93693.0149c-.16403-.003-.32132.0901-.39257.24979l-1.97798 4.4339c-.095.21296-.00004.46088.21292.55589.21297.095.46088.00005.5559-.21291L44.4446 6.9467c.095-.21297.00005-.46089-.21291-.5559-.0532-.0237-.10864-.0357-.16332-.0369zM19.65353 7.6501c-.0808-.006-.16406.012-.23979.0558-.20196.1166-.27065.37302-.15406.57497l1.02115 1.76869c.1166.20196.373.27065.57496.15405.20195-.1166.27065-.37301.15406-.57497L19.9887 7.85996c-.0729-.12623-.20047-.20041-.33517-.20983zm26.85877 0c-.13468.009-.26211.0836-.33498.20983l-1.02133 1.76868c-.1166.20196-.0477.45837.15424.57497.20196.1166.45837.0479.57497-.15405l1.02114-1.76869c.1166-.20195.0479-.45837-.15406-.57497-.0757-.0437-.15916-.0614-.23998-.0558zM17.24739 9.15083c-.081.003-.16211.029-.2329.0803-.18875.13693-.23048.39911-.0935.58787l2.85086 3.92995c.13693.18876.39929.23049.58805.0936.18876-.13693.23049-.39911.0935-.58787l-2.85104-3.92995c-.0856-.11798-.22004-.17847-.35497-.17386zm31.70122.0214c-.13493-.005-.26941.0555-.35516.17331l-2.8563 3.92614c-.1372.18857-.0958.45086.0928.58805.18858.13718.45087.0959.58806-.0926l2.85613-3.92614c.13718-.18858.0957-.45086-.0928-.58805-.0707-.0514-.15176-.0778-.23272-.0807zm-33.85196 1.78231c-.10744-.006-.21708.0299-.30374.10791-.17332.15602-.18725.42109-.0312.59441l1.36648 1.51799c.15601.17332.42109.18726.59441.0312.17332-.15602.18726-.42127.0312-.59459l-1.3663-1.51781c-.078-.0867-.18339-.13351-.29085-.13916zm35.97562.003c-.10745.006-.21282.0525-.29084.13915l-1.36648 1.51763c-.15606.1733-.14224.43855.0311.59459.17329.15604.43837.14205.59441-.0312l1.36666-1.51762c.15605-.17331.14205-.43856-.0312-.59459-.0867-.078-.19611-.11354-.30357-.10791zm-38.03696 1.97705c-.10745.006-.21266.0525-.29067.13916-.15602.17332-.14207.43839.0312.59441l3.60841 3.24834c.17332.15603.43839.14207.5944-.0312.15603-.17331.14226-.43839-.0311-.59441l-3.60858-3.24834c-.0867-.078-.1963-.11356-.30376-.10791zm40.10831.0142c-.10745-.006-.21722.0298-.30393.10773l-3.61059 3.24581c-.17342.15589-.18768.42097-.0318.5944.1559.17342.42117.18751.59459.0316l3.61077-3.2458c.17342-.1559.1875-.42098.0316-.59441-.078-.0867-.18322-.13361-.29066-.13933zm-41.8225 2.18998c-.13494-.005-.26949.0558-.35515.17367-.13707.18866-.0955.4508.0932.58787l1.65224 1.20044c.18866.13708.45079.0957.58786-.093.13708-.18866.0956-.45098-.093-.58805l-1.65224-1.20044c-.0707-.0514-.15193-.0776-.23289-.0805zm43.53505.0153c-.081.003-.16211.0289-.23289.0803l-1.65297 1.19936c-.18875.13694-.2305.39929-.0936.58805.13695.18875.39912.23031.58787.0934l1.65316-1.19935c.18875-.13694.23031-.39912.0934-.58787-.0856-.11797-.22004-.17847-.35497-.17385zM9.7192 17.48992c-.13469.009-.26211.0836-.33499.20982-.1166.20195-.0479.45837.15405.57497l4.20463 2.42758c.20195.1166.45837.0479.57497-.15405.1166-.20195.0479-.45837-.15405-.57497l-4.20463-2.42759c-.0757-.0437-.15917-.0614-.23998-.0558zm46.72744 0c-.0808-.006-.16425.012-.23998.0558l-4.20463 2.42759c-.20195.1166-.27065.37302-.15405.57497.1166.20195.37302.27065.57497.15405l4.20482-2.42758c.20195-.1166.27064-.37302.15404-.57497-.0729-.12622-.20048-.20041-.33517-.20982zm-47.9386 2.50606c-.16403-.004-.32133.0899-.39258.2496-.095.21298-.00006.46091.21292.5559l1.86532.83202c.21298.095.46091.00007.5559-.2129.095-.21298-.00012-.46091-.21309-.5559l-1.86515-.83202c-.0532-.0238-.10865-.0356-.16332-.0367zm49.15794.0173c-.0547.001-.11024.013-.16351.0367l-1.86569.83057c-.21304.0949-.3083.34267-.21346.55571.0949.21304.34286.3083.5559.21346l1.8657-.83076c.21303-.0948.30811-.34267.21327-.55571-.0711-.15978-.22818-.25323-.39221-.24997zM7.42859 22.61527c-.16349.0137-.31006.12291-.36424.28921-.0722.22172.048.45839.26977.53064l4.61629 1.50418c.22171.0722.45839-.0481.53064-.26977.0722-.22172-.048-.4584-.26977-.53064L7.595 22.6347c-.0554-.0181-.11192-.024-.16641-.0194zm51.31484.018c-.0545-.005-.11078.001-.16623.0194l-4.61736 1.50092c-.22178.0721-.34223.30869-.27014.53046.0721.22177.30868.34223.53046.27014l4.61719-1.50092c.22178-.0721.3424-.30869.27032-.53046-.0541-.16633-.20077-.2757-.36424-.28957zM6.75607 25.36479c-.1961-.002-.37196.13412-.41438.33371-.0485.2281.0962.45073.32427.49922l1.99777.42455c.2281.0485.45072-.0962.49921-.32427.0485-.22811-.0962-.45074-.32427-.49922l-1.99759-.42455c-.0285-.006-.057-.009-.085-.009zm52.65462.004c-.028.00023-.0563.004-.0848.009l-1.99778.42437c-.2281.0485-.37271.27093-.32426.49904.0485.2281.2711.3729.49921.32445l1.99759-.42437c.2281-.0485.3729-.27111.32445-.49922-.0424-.19959-.21829-.33537-.41437-.33371zM6.24704 28.13046c-.1952.0187-.35587.17185-.37731.37477-.0245.2319.14232.43838.37422.46288l4.82829.51048c.2319.0245.43838-.1425.46288-.37441.0245-.2319-.1425-.43838-.37441-.46288l-4.82828-.51048c-.029-.003-.0575-.003-.0854-.00035zm53.6763.0363c-.0279-.003-.0566-.003-.0856.00035l-4.82883.50394c-.23194.0242-.39914.2304-.37496.46233.0242.23194.2304.39918.46234.37496l4.82883-.50394c.23193-.0242.39914-.2304.37496-.46234-.0212-.20294-.1816-.35634-.37678-.37532zM6.16529 30.96149c-.2332 0-.42091.18772-.42091.42092 0 .23319.18771.42091.42091.42091h2.04228c.23319 0 .4211-.18772.4211-.42091 0-.2332-.18791-.42092-.4211-.42092zm51.79298 0c-.23319 0-.42092.18772-.42092.42092.00001.23319.18773.42091.42092.42091h2.04228c.23319 0 .42092-.18772.42092-.42091 0-.2332-.18773-.42092-.42092-.42092zM11.15508 33.2561c-.0279-.003-.0564-.003-.0854.00035l-4.82902.50394c-.23194.0242-.39913.2304-.37495.46233.0242.23194.2304.39918.46233.37496l4.82902-.50394c.23194-.0242.39913-.2304.37495-.46234-.0212-.20294-.18177-.35634-.37695-.37531zm43.85314.0298c-.19521.0187-.35588.17186-.37732.37478-.0245.2319.14233.43838.37423.46288l4.82829.51048c.23191.0245.43837-.14251.46288-.37441.0245-.2319-.14251-.43838-.37441-.46288l-4.8281-.51048c-.029-.003-.0577-.003-.0856-.00035zm-46.2602 2.8436c-.028.00024-.0565.003-.085.009l-1.99777.42436c-.22811.0485-.37271.27111-.32427.49922.0485.22811.27111.37272.49922.32427l1.99777-.42419c.2281-.0485.37271-.27111.32426-.49921-.0424-.1996-.2181-.33537-.41419-.33372zm48.66925.004c-.19609-.002-.37177.13394-.41419.33353-.0485.2281.096.45074.32409.49922l1.99777.42455c.22809.0485.45073-.096.49921-.32409.0485-.2281-.0962-.45092-.32426-.4994l-1.9976-.42455c-.0285-.006-.057-.009-.085-.009zm-45.30519 1.65787c-.0545-.005-.11077.001-.16622.0194L7.3285 39.31168c-.22178.0721-.34223.30869-.27014.53046.0721.22178.30868.34222.53046.27014l4.61719-1.50092c.22178-.0721.34241-.30869.27032-.53046-.0541-.16633-.20077-.2757-.36425-.28957zm41.93713.0149c-.16349.0137-.31005.12292-.36423.28921-.0722.22173.048.4584.26977.53065l4.61628 1.50418c.22172.0722.4584-.0481.53064-.26977.0723-.22172-.048-.4584-.26977-.53065l-4.61628-1.50418c-.0554-.0181-.11191-.024-.16641-.0194zm-43.69909 3.27251c-.0547.001-.11006.0128-.16332.0365l-1.86587.83075c-.21304.0948-.30812.34267-.21328.55571.0949.21304.34268.30812.55571.21328l1.86589-.83058c.21303-.0948.30811-.34267.21327-.55571-.0711-.15978-.22837-.25323-.3924-.24997zm45.45888.016c-.16403-.004-.32133.0899-.39258.24961-.095.21297-.00006.4609.21291.55589l1.86515.83202c.21297.095.46091.00006.5559-.21291.095-.21297.00006-.4609-.21291-.55589l-1.86515-.83203c-.0532-.0238-.10864-.0356-.16332-.0367zm-41.82613.91214c-.0808-.006-.16424.012-.23998.0558L9.53826 44.4903c-.20195.1166-.27065.37302-.15405.57497.1166.20195.37302.27065.57497.15405l4.20463-2.4274c.20195-.1166.27064-.3732.15405-.57515-.0729-.12622-.2003-.20041-.33499-.20982zm38.20028 0c-.13469.009-.26229.0836-.33517.20982-.1166.20195-.0479.45855.15405.57515l4.20463 2.4274c.20196.1166.45855.0479.57515-.15405.1166-.20195.0479-.45837-.15404-.57497l-4.20482-2.42758c-.0757-.0437-.15899-.0614-.2398-.0558zm-39.24903 3.56244c-.081.003-.16211.0291-.2329.0805l-1.65296 1.19935c-.18875.13694-.2305.39912-.0936.58787.13695.18875.39912.2305.58787.0935l1.65314-1.19935c.18877-.13693.23051-.39911.0936-.58786-.0856-.11797-.22022-.17866-.35516-.17404zm40.28761.0142c-.13494-.005-.26948.0558-.35515.17367-.13708.18865-.0955.45098.0932.58805l1.65224 1.20044c.18866.13707.4508.0955.58787-.0932.13707-.18866.0956-.4508-.093-.58787l-1.65224-1.20044c-.0707-.0514-.15193-.0778-.23289-.0807zm-36.54387.14533c-.10743-.006-.21702.0298-.30374.10773l-3.61076 3.2458c-.17342.15589-.18751.42098-.0316.59441.15589.17342.42097.1875.5944.0316l3.61077-3.2458c.17342-.15589.18751-.42098.0316-.59441-.0779-.0867-.18322-.13361-.29067-.13933zm32.80012.0116c-.10745.006-.21283.0525-.29084.13915-.15603.17332-.14207.43839.0312.59441l3.60841 3.24834c.17332.15604.43857.14208.59459-.0312.15603-.17331.14207-.43839-.0312-.5944l-3.6086-3.24835c-.0867-.078-.19611-.11355-.30356-.10791zm-29.37464 3.08358c-.13493-.005-.2696.0554-.35534.1733l-2.85613 3.92614c-.13719.18858-.0959.45087.0926.58805.18857.13719.45087.0959.58805-.0927l2.85613-3.92614c.13718-.18857.0959-.45086-.0926-.58805-.0707-.0514-.15175-.0778-.23271-.0806zm25.93573.0176c-.081.003-.16211.0289-.2329.0803-.18875.13694-.23048.39911-.0936.58787l2.85086 3.92995c.13693.18876.39911.2305.58787.0936.18876-.13693.23049-.3991.0936-.58786l-2.85086-3.92996c-.0856-.11797-.22004-.17846-.35498-.17385zm-29.6228.6064c-.10745.006-.21282.0525-.29084.13915l-1.36649 1.51763c-.15605.1733-.14223.43855.0311.59459.1733.15604.43837.14205.5944-.0313l1.36666-1.51762c.15606-.1733.14206-.43856-.0312-.59459-.0867-.078-.19611-.11354-.30357-.10791zm33.33076.002c-.10745-.006-.21691.0299-.30356.10791-.17333.156-.18726.42108-.0313.5944l1.3663 1.51799c.15602.17333.42109.18726.59442.0312.17332-.15601.18726-.42126.0312-.59459l-1.36631-1.5178c-.078-.0867-.18339-.13351-.29084-.13916zm-25.65524 1.68366c-.16403-.004-.32114.0899-.39239.24961l-1.97816 4.43389c-.095.21297-.00005.46089.21292.5559.21296.095.46089.00005.55589-.21291l1.97815-4.4339c.095-.21296.00005-.46089-.21292-.55589-.0532-.0238-.10881-.0356-.16349-.0367zm17.95556.0122c-.0547.001-.11023.0128-.1635.0365-.21297.0947-.30836.34244-.21363.55553l1.97196 4.43662c.0947.21297.34262.30836.55571.21364.21298-.0947.30836-.34244.21364-.55553l-1.97197-4.43662c-.071-.15973-.22818-.25329-.39221-.25015zM20.61581 52.5046c-.13468.009-.26212.0836-.33498.20982l-1.02115 1.76869c-.11659.20195-.0479.45837.15406.57497.20195.1166.45837.0479.57496-.15405l1.02115-1.76869c.11659-.20195.0479-.45837-.15406-.57497-.0757-.0437-.15916-.0614-.23998-.0558zm24.93421 0c-.0808-.006-.16406.0121-.23979.0558-.20195.1166-.27065.37302-.15405.57497l1.02114 1.76869c.1166.20195.37302.27064.57496.15405.20196-.1166.27066-.37302.15406-.57497l-1.02114-1.76869c-.0729-.12622-.20049-.20041-.33518-.20982zm-17.0545.0634c-.19609-.002-.3718.13394-.41419.33354l-1.00897 4.74926c-.0485.2281.0962.45076.32427.49921.22811.0485.45076-.0962.49922-.32427l1.00896-4.74926c.0485-.2281-.0962-.45076-.32427-.49921-.0285-.006-.057-.009-.085-.009zm9.1599.003c-.028.00022-.0563.003-.0848.009-.22814.0483-.37294.27071-.32465.49885l1.00553 4.74999c.0483.22814.27088.37293.49903.32464.22814-.0483.37293-.27089.32464-.49903l-1.0057-4.74965c-.0423-.19963-.21793-.33543-.41402-.33391zm-4.5725.47905c-.23319 0-.42092.18772-.42092.42092v4.85517c0 .2332.18773.42092.42092.42092.2332 0 .42092-.18772.42092-.42092v-4.85517c0-.2332-.18772-.42092-.42092-.42092zm-7.72657 1.56886c-.16347.0139-.31017.12324-.36423.28957l-.63129 1.94236c-.0721.22178.0484.45837.27014.53047.22177.0721.45836-.0486.53046-.27032l.63128-1.94218c.0721-.22177-.0484-.45836-.27013-.53046-.0554-.018-.11173-.024-.16623-.0194zm15.44987.001c-.0545-.005-.11078.001-.16622.0193-.22178.0721-.34238.30868-.27033.53047l.63111 1.94235c.0721.22179.30868.3422.53046.27014.22178-.0721.34238-.3085.27032-.53028l-.63128-1.94236c-.0541-.16634-.20058-.27568-.36406-.28957zm-10.36543 1.08181c-.1952.0188-.356.17203-.37732.37496l-.21346 2.03119c-.0244.23192.14268.43812.3746.46252.23192.0244.4383-.14268.4627-.3746l.21345-2.03101c.0244-.23192-.14268-.4383-.37458-.4627-.029-.003-.0575-.003-.0854-.00035zm5.26736.002c-.0279-.003-.0566-.003-.0856.00035-.23193.0242-.39917.2304-.37495.46233l.21218 2.03138c.0242.23193.2304.399.46234.37478.23193-.0242.39918-.23041.37496-.46234l-.212-2.03119c-.0212-.20295-.18178-.35637-.37697-.37533z"
      fill="#f4f2f3"
      paintOrder="markers stroke fill"
    />
    <path
      d="m469.09621 100.6068-65.50955 38.06124-41.41979 65.20654 60.59382-44.88117z"
      filter="url(#safari__f)"
      opacity=".40900005"
      paintOrder="markers stroke fill"
      transform="translate(-112.09544 -20.8224) scale(.35154)"
    />
    <path
      d="m36.3834003 34.83806178-6.60095092-6.91272438 23.41607429-15.75199774z"
      fill="#ff5150"
      paintOrder="markers stroke fill"
    />
    <path
      d="m36.38339038 34.83805895-6.60095092-6.91272438-16.81512624 22.66471911z"
      fill="#f1f1f1"
      paintOrder="markers stroke fill"
    />
    <path
      d="m12.96732 50.59006 23.41607-15.75201 16.81513-22.66472z"
      opacity=".243"
    />
  </svg>
)

const AppStoreIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} viewBox="0 0 800 800" xmlSpace="preserve">
    <title>App Store Icon</title>
    <linearGradient
      gradientTransform="matrix(1 0 0 -1 0 798.772)"
      gradientUnits="userSpaceOnUse"
      id="appstore__a"
      x1="400.05"
      x2="400.05"
      y1="798.772"
      y2="-1.228"
    >
      <stop offset="0" style={{ stopColor: "#18bffb" }} />
      <stop offset="1" style={{ stopColor: "#2072f3" }} />
    </linearGradient>
    <path
      d="M638.4 0H161.6C72.3 0 0 72.3 0 161.6v476.9C0 727.7 72.3 800 161.6 800h476.9c89.2 0 161.6-72.3 161.6-161.6V161.6C800 72.3 727.7 0 638.4 0z"
      fill="url(#appstore__a)"
    />
    <path
      d="m396.6 183.8 16.2-28c10-17.5 32.3-23.4 49.8-13.4s23.4 32.3 13.4 49.8L319.9 462.4h112.9c36.6 0 57.1 43 41.2 72.8H143c-20.2 0-36.4-16.2-36.4-36.4s16.2-36.4 36.4-36.4h92.8l118.8-205.9-37.1-64.4c-10-17.5-4.1-39.6 13.4-49.8 17.5-10 39.6-4.1 49.8 13.4l15.9 28.1zM256.2 572.7l-35 60.7c-10 17.5-32.3 23.4-49.8 13.4S148 614.5 158 597l26-45c29.4-9.1 53.3-2.1 72.2 20.7zm301.4-110.1h94.7c20.2 0 36.4 16.2 36.4 36.4s-16.2 36.4-36.4 36.4h-52.6l35.5 61.6c10 17.5 4.1 39.6-13.4 49.8-17.5 10-39.6 4.1-49.8-13.4-59.8-103.7-104.7-181.3-134.5-233-30.5-52.6-8.7-105.4 12.8-123.3 23.9 41 59.6 102.9 107.3 185.5z"
      fill="#FFF"
    />
  </svg>
)

const DiscordIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} preserveAspectRatio="xMidYMid" viewBox="0 0 256 199">
    <title>Discord Icon</title>
    <path
      d="M216.856 16.597A208.502 208.502 0 0 0 164.042 0c-2.275 4.113-4.933 9.645-6.766 14.046-19.692-2.961-39.203-2.961-58.533 0-1.832-4.4-4.55-9.933-6.846-14.046a207.809 207.809 0 0 0-52.855 16.638C5.618 67.147-3.443 116.4 1.087 164.956c22.169 16.555 43.653 26.612 64.775 33.193A161.094 161.094 0 0 0 79.735 175.3a136.413 136.413 0 0 1-21.846-10.632 108.636 108.636 0 0 0 5.356-4.237c42.122 19.702 87.89 19.702 129.51 0a131.66 131.66 0 0 0 5.355 4.237 136.07 136.07 0 0 1-21.886 10.653c4.006 8.02 8.638 15.67 13.873 22.848 21.142-6.58 42.646-16.637 64.815-33.213 5.316-56.288-9.08-105.09-38.056-148.36ZM85.474 135.095c-12.645 0-23.015-11.805-23.015-26.18s10.149-26.2 23.015-26.2c12.867 0 23.236 11.804 23.015 26.2.02 14.375-10.148 26.18-23.015 26.18Zm85.051 0c-12.645 0-23.014-11.805-23.014-26.18s10.148-26.2 23.014-26.2c12.867 0 23.236 11.804 23.015 26.2 0 14.375-10.148 26.18-23.015 26.18Z"
      fill="#ffffff"
    />
  </svg>
)

const ClaudeAIIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} preserveAspectRatio="xMidYMid" viewBox="0 0 256 257">
    <title>Claude Icon</title>
    <path
      d="m50.228 170.321 50.357-28.257.843-2.463-.843-1.361h-2.462l-8.426-.518-28.775-.778-24.952-1.037-24.175-1.296-6.092-1.297L0 125.796l.583-3.759 5.12-3.434 7.324.648 16.202 1.101 24.304 1.685 17.629 1.037 26.118 2.722h4.148l.583-1.685-1.426-1.037-1.101-1.037-25.147-17.045-27.22-18.017-14.258-10.37-7.713-5.25-3.888-4.925-1.685-10.758 7-7.713 9.397.649 2.398.648 9.527 7.323 20.35 15.75L94.817 91.9l3.889 3.24 1.555-1.102.195-.777-1.75-2.917-14.453-26.118-15.425-26.572-6.87-11.018-1.814-6.61c-.648-2.723-1.102-4.991-1.102-7.778l7.972-10.823L71.42 0 82.05 1.426l4.472 3.888 6.61 15.101 10.694 23.786 16.591 32.34 4.861 9.592 2.592 8.879.973 2.722h1.685v-1.556l1.36-18.211 2.528-22.36 2.463-28.776.843-8.1 4.018-9.722 7.971-5.25 6.222 2.981 5.12 7.324-.713 4.73-3.046 19.768-5.962 30.98-3.889 20.739h2.268l2.593-2.593 10.499-13.934 17.628-22.036 7.778-8.749 9.073-9.657 5.833-4.601h11.018l8.1 12.055-3.628 12.443-11.342 14.388-9.398 12.184-13.48 18.147-8.426 14.518.778 1.166 2.01-.194 30.46-6.481 16.462-2.982 19.637-3.37 8.88 4.148.971 4.213-3.5 8.62-20.998 5.184-24.628 4.926-36.682 8.685-.454.324.519.648 16.526 1.555 7.065.389h17.304l32.21 2.398 8.426 5.574 5.055 6.805-.843 5.184-12.962 6.611-17.498-4.148-40.83-9.721-14-3.5h-1.944v1.167l11.666 11.406 21.387 19.314 26.767 24.887 1.36 6.157-3.434 4.86-3.63-.518-23.526-17.693-9.073-7.972-20.545-17.304h-1.36v1.814l4.73 6.935 25.017 37.59 1.296 11.536-1.814 3.76-6.481 2.268-7.13-1.297-14.647-20.544-15.1-23.138-12.185-20.739-1.49.843-7.194 77.448-3.37 3.953-7.778 2.981-6.48-4.925-3.436-7.972 3.435-15.749 4.148-20.544 3.37-16.333 3.046-20.285 1.815-6.74-.13-.454-1.49.194-15.295 20.999-23.267 31.433-18.406 19.702-4.407 1.75-7.648-3.954.713-7.064 4.277-6.286 25.47-32.405 15.36-20.092 9.917-11.6-.065-1.686h-.583L44.07 198.125l-12.055 1.555-5.185-4.86.648-7.972 2.463-2.593 20.35-13.999-.064.065Z"
      fill="#ffffff"
    />
  </svg>
)

const FigmaIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} fill="none" viewBox="0 0 54 80">
    <title>Figma Icon</title>
    <g clipPath="url(#figma__clip0_912_3)">
      <path
        d="M13.3333 80.0002C20.6933 80.0002 26.6667 74.0268 26.6667 66.6668V53.3335H13.3333C5.97333 53.3335 0 59.3068 0 66.6668C0 74.0268 5.97333 80.0002 13.3333 80.0002Z"
        fill="#0ACF83"
      />
      <path
        d="M0 39.9998C0 32.6398 5.97333 26.6665 13.3333 26.6665H26.6667V53.3332H13.3333C5.97333 53.3332 0 47.3598 0 39.9998Z"
        fill="#A259FF"
      />
      <path
        d="M0 13.3333C0 5.97333 5.97333 0 13.3333 0H26.6667V26.6667H13.3333C5.97333 26.6667 0 20.6933 0 13.3333Z"
        fill="#F24E1E"
      />
      <path
        d="M26.6667 0H40.0001C47.3601 0 53.3334 5.97333 53.3334 13.3333C53.3334 20.6933 47.3601 26.6667 40.0001 26.6667H26.6667V0Z"
        fill="#FF7262"
      />
      <path
        d="M53.3334 39.9998C53.3334 47.3598 47.3601 53.3332 40.0001 53.3332C32.6401 53.3332 26.6667 47.3598 26.6667 39.9998C26.6667 32.6398 32.6401 26.6665 40.0001 26.6665C47.3601 26.6665 53.3334 32.6398 53.3334 39.9998Z"
        fill="#1ABCFE"
      />
    </g>
    <defs>
      <clipPath id="figma__clip0_912_3">
        <rect fill="white" height="80" width="53.3333" />
      </clipPath>
    </defs>
  </svg>
)

const GoogleCalendarIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} fill="none" viewBox="0 0 512 512">
    <title>Google Calendar Icon</title>
    <g clipPath="url(#google_calendar__clip0_5072_3766)">
      <path
        d="M390.736 121.264H121.264V390.736H390.736V121.264Z"
        fill="white"
      />
      <path
        d="M390.736 512L512 390.736L451.368 380.392L390.736 390.736L379.67 446.196L390.736 512Z"
        fill="#EA4335"
      />
      <path
        d="M0 390.736V471.578C0 493.912 18.088 512 40.42 512H121.264L133.714 451.368L121.264 390.736L55.198 380.392L0 390.736Z"
        fill="#188038"
      />
      <path
        d="M512 121.264V40.42C512 18.088 493.912 0 471.58 0H390.736C383.36 30.072 379.671 52.2027 379.67 66.392C379.67 80.58 383.359 98.8707 390.736 121.264C417.556 128.944 437.767 132.784 451.368 132.784C464.969 132.784 485.18 128.945 512 121.264Z"
        fill="#1967D2"
      />
      <path d="M512 121.264H390.736V390.736H512V121.264Z" fill="#FBBC04" />
      <path d="M390.736 390.736H121.264V512H390.736V390.736Z" fill="#34A853" />
      <path
        d="M390.736 0H40.422C18.088 0 0 18.088 0 40.42V390.736H121.264V121.264H390.736V0Z"
        fill="#4285F4"
      />
      <path
        d="M176.54 330.308C166.468 323.504 159.494 313.568 155.688 300.428L179.066 290.796C181.186 298.88 184.891 305.145 190.182 309.592C195.436 314.038 201.836 316.228 209.314 316.228C216.959 316.228 223.527 313.903 229.018 309.254C234.51 304.606 237.272 298.678 237.272 291.504C237.272 284.16 234.375 278.164 228.582 273.516C222.788 268.868 215.512 266.544 206.822 266.544H193.314V243.404H205.44C212.917 243.404 219.216 241.382 224.336 237.338C229.456 233.298 232.016 227.772 232.016 220.732C232.016 214.468 229.726 209.482 225.146 205.744C220.566 202.004 214.77 200.118 207.73 200.118C200.858 200.118 195.402 201.938 191.36 205.608C187.319 209.289 184.282 213.937 182.534 219.116L159.394 209.482C162.458 200.792 168.084 193.112 176.336 186.476C184.588 179.84 195.132 176.506 207.932 176.506C217.398 176.506 225.92 178.326 233.466 181.996C241.01 185.668 246.938 190.754 251.216 197.222C255.496 203.722 257.616 210.998 257.616 219.082C257.616 227.334 255.63 234.308 251.656 240.034C247.682 245.76 242.796 250.138 237.002 253.204V254.584C244.483 257.669 250.982 262.735 255.798 269.238C260.682 275.806 263.142 283.654 263.142 292.818C263.142 301.978 260.816 310.164 256.168 317.338C251.52 324.514 245.088 330.172 236.934 334.282C228.75 338.392 219.554 340.482 209.348 340.482C197.524 340.514 186.612 337.112 176.54 330.308ZM320.132 214.298L294.466 232.858L281.632 213.39L327.678 180.176H345.328V336.842H320.132V214.298Z"
        fill="#4285F4"
      />
    </g>
    <defs>
      <clipPath id="google_calendar__clip0_5072_3766">
        <rect fill="white" height="512" width="512" />
      </clipPath>
    </defs>
  </svg>
)

const ZoomIcon = (props: SVGProps<SVGSVGElement>) => (
  <svg {...props} preserveAspectRatio="xMidYMid" viewBox="0 0 256 256">
    <title>Zoom Icon</title>
    <defs>
      <linearGradient
        id="zoom__a"
        x1="23.666%"
        x2="76.334%"
        y1="95.6118%"
        y2="4.3882%"
      >
        <stop offset=".00006%" stopColor="#0845BF" />
        <stop offset="19.11%" stopColor="#0950DE" />
        <stop offset="38.23%" stopColor="#0B59F6" />
        <stop offset="50%" stopColor="#0B5CFF" />
        <stop offset="67.32%" stopColor="#0E5EFE" />
        <stop offset="77.74%" stopColor="#1665FC" />
        <stop offset="86.33%" stopColor="#246FF9" />
        <stop offset="93.88%" stopColor="#387FF4" />
        <stop offset="100%" stopColor="#4F90EE" />
      </linearGradient>
    </defs>
    <path
      d="M256 128c0 13.568-1.024 27.136-3.328 40.192-6.912 43.264-41.216 77.568-84.48 84.48C155.136 254.976 141.568 256 128 256c-13.568 0-27.136-1.024-40.192-3.328-43.264-6.912-77.568-41.216-84.48-84.48C1.024 155.136 0 141.568 0 128c0-13.568 1.024-27.136 3.328-40.192 6.912-43.264 41.216-77.568 84.48-84.48C100.864 1.024 114.432 0 128 0c13.568 0 27.136 1.024 40.192 3.328 43.264 6.912 77.568 41.216 84.48 84.48C254.976 100.864 256 114.432 256 128Z"
      fill="url(#zoom__a)"
    />
    <path
      d="M204.032 207.872H75.008c-8.448 0-16.64-4.608-20.48-12.032-4.608-8.704-2.816-19.2 4.096-26.112l89.856-89.856H83.968c-17.664 0-32-14.336-32-32h118.784c8.448 0 16.64 4.608 20.48 12.032 4.608 8.704 2.816 19.2-4.096 26.112l-89.6 90.112h74.496c17.664 0 32 14.08 32 31.744Z"
      fill="#FFF"
    />
  </svg>
)

/** macOS Finder tile; gradient IDs must be unique when multiple instances exist */
function FinderDockIcon(props: SVGProps<SVGSVGElement>) {
  const gradId = useId().replaceAll(":", "")
  return (
    <svg viewBox="0 0 64 64" {...props}>
      <title>Finder</title>
      <defs>
        <linearGradient
          gradientUnits="userSpaceOnUse"
          id={`finderDockFace-${gradId}`}
          x1="32"
          x2="32"
          y1="4"
          y2="60"
        >
          <stop stopColor="#5EB8FF" />
          <stop offset="1" stopColor="#0076FF" />
        </linearGradient>
      </defs>
      <rect
        fill={`url(#finderDockFace-${gradId})`}
        height="64"
        rx="13"
        width="64"
      />
      <path
        d="M32 18.5c-6.9 0-12.6 5-13.6 11.5h27.2c-1-6.5-6.7-11.5-13.6-11.5zm-14.8 12.2V45h29.6V30.7H17.2z"
        fill="white"
        opacity="0.94"
      />
    </svg>
  )
}

/** Left-to-right dock order; `color` seeds each tile’s gradient */
const dockApps = [
  { name: "Finder", icon: FinderDockIcon, color: "#0076FF" },

  { name: "Google Calendar", icon: GoogleCalendarIcon, color: "#ffffff" },
  { name: "Safari", icon: SafariIcon, color: "#ffffff" },
  { name: "Claude Code", icon: ClaudeAIIcon, color: "#E96A45" },
  { name: "Zoom", icon: ZoomIcon, color: "#0066F7" },
  { name: "Figma", icon: FigmaIcon, color: "#ffffff" },
  { name: "Spotify", icon: SpotifyIcon, color: "#ffffff" },
  { name: "Discord", icon: DiscordIcon, color: "#737DF8" },
  { name: "App Store", icon: AppStoreIcon, color: "#ffffff" },
] as const

const STUDIO_DOCK_MAGNET_PX = 118
const STUDIO_DOCK_MAX_EXTRA_SCALE = 0.44

/** Smoothstep curve: 1px baseline → up ~44% larger at cursor, falloff by `STUDIO_DOCK_MAGNET_PX` */
function studioDockScaleFromDistance(distancePx: number): number {
  const d = Math.abs(distancePx)
  if (d >= STUDIO_DOCK_MAGNET_PX) {
    return 1
  }
  const t = 1 - d / STUDIO_DOCK_MAGNET_PX
  return 1 + STUDIO_DOCK_MAX_EXTRA_SCALE * t * t * (3 - 2 * t)
}

interface StudioDockContextValue {
  /** Viewport X from `mousemove`; `Infinity` when pointer left the dock */
  mouseX: MotionValue<number>
  reduceMotion: boolean
}

const StudioDockContext = createContext<StudioDockContextValue | null>(null)

function useStudioDock() {
  const ctx = useContext(StudioDockContext)
  if (!ctx) {
    throw new Error("Studio dock context missing")
  }
  return ctx
}

/** Wraps the dock: tracks cursor X and resets to “idle” scale when mouse leaves */
function StudioDock({
  children,
  className,
  style,
  ariaLabel,
  reduceMotion,
}: {
  children: ReactNode
  className?: string
  style?: CSSProperties
  ariaLabel: string
  reduceMotion: boolean
}) {
  const mouseX = useMotionValue(Number.POSITIVE_INFINITY)
  const value = useMemo(
    () => ({ mouseX, reduceMotion }),
    [mouseX, reduceMotion]
  )

  return (
    <StudioDockContext.Provider value={value}>
      <motion.nav
        aria-label={ariaLabel}
        className={cn(className)}
        onMouseLeave={() => mouseX.set(Number.POSITIVE_INFINITY)}
        onMouseMove={(e) => mouseX.set(e.clientX)}
        style={style}
      >
        {children}
      </motion.nav>
    </StudioDockContext.Provider>
  )
}

/** Single dock tile: magnet scale from distance to nav `mouseX`, lift + z-index when enlarged */
function StudioDockIcon({
  label,
  children,
  showRunningDot,
}: {
  label: string
  children: ReactNode
  showRunningDot?: boolean
}) {
  const { mouseX, reduceMotion } = useStudioDock()
  const ref = useRef<HTMLButtonElement>(null)

  const scaleSync = useTransform(mouseX, (mx) => {
    if (!Number.isFinite(mx)) {
      return 1
    }
    const el = ref.current
    if (!el) {
      return 1
    }
    const b = el.getBoundingClientRect()
    const dist = mx - b.left - b.width / 2
    return studioDockScaleFromDistance(dist)
  })

  const scale = useSpring(scaleSync, {
    mass: 0.12,
    stiffness: reduceMotion ? 8000 : 380,
    damping: reduceMotion ? 160 : 26,
  })

  const y = useTransform(scale, (s) => -Math.max(0, s - 1) * 14)
  const z = useTransform(scale, (s) => (s > 1.025 ? 10 : 1))

  return (
    <Tooltip>
      <div className="mt-1 flex flex-col items-center gap-[5px]">
        <TooltipTrigger
          render={
            <motion.button
              aria-label={label}
              className="relative origin-bottom cursor-default border-0 bg-transparent p-0"
              onClick={(e) => e.stopPropagation()}
              onKeyDown={(e) => e.stopPropagation()}
              onPointerDown={(e) => e.stopPropagation()}
              ref={ref}
              style={{ scale, y, zIndex: z }}
              type="button"
            >
              {children}
            </motion.button>
          }
        />
        <div
          aria-hidden
          className="flex min-h-[4px] items-center justify-center"
        >
          {showRunningDot ? (
            <span className="h-[3px] w-[3px] rounded-full bg-[#2b2b30] shadow-[0_0_0_0.4px_rgba(255,255,255,0.45)]" />
          ) : null}
        </div>
      </div>
      <TooltipContent
        className="border-0 bg-[#1e1e1e] px-2 py-1 text-[10px] text-white"
        side="top"
      >
        {label}
      </TooltipContent>
    </Tooltip>
  )
}

export type StudioScreenMode = "grading" | "wallpaper" | "photo" | "gradient"

export interface AppleStudioDisplayProps {
  className?: string
  /** When set, replaces built-in screen demos */
  screenContent?: ReactNode
  /** Initial variant when using built-in content */
  initialMode?: StudioScreenMode
}

/** Fake color grading UI (Resolve-style chrome + scopes placeholder) */
function GradingScreen() {
  return (
    <div
      className="absolute inset-0 flex flex-col bg-[#121214]"
      style={{ fontFamily: "system-ui, sans-serif" }}
    >
      <div className="flex h-[9%] min-h-[20px] items-center border-[#2a2a2e] border-b px-[2.5%]">
        <div className="flex gap-[1.5%] opacity-80">
          {["File", "Edit", "Trim", "Color", "Fairlight", "Deliver"].map(
            (t) => (
              <span className="text-[#a8a8ad] text-[5px] sm:text-[6px]" key={t}>
                {t}
              </span>
            )
          )}
        </div>
        <div className="ml-auto flex items-center gap-1">
          <span className="rounded-sm bg-[#2a2a2e] px-1 py-px text-[#888] text-[4px]">
            5K
          </span>
        </div>
      </div>
      <div className="relative flex flex-1 gap-[1%] p-[1%]">
        <div className="flex w-[14%] flex-col gap-px border-[#252528] border-r pr-[1%]">
          <div className="h-[18%] min-h-[12px] rounded-sm bg-[#1c1c1f]" />
          <div className="h-[18%] min-h-[12px] rounded-sm bg-[#1c1c1f]" />
          <div className="h-[18%] min-h-[12px] rounded-sm bg-[#1c1c1f]" />
        </div>
        <div className="relative flex min-w-0 flex-1 items-center justify-center overflow-hidden rounded-sm bg-[#0a0a0c]">
          <div
            className="absolute inset-[4%] rounded-[2px]"
            style={{
              background: `
                radial-gradient(ellipse 70% 55% at 50% 45%, rgba(255,210,120,0.55) 0%, transparent 55%),
                radial-gradient(ellipse 50% 60% at 28% 60%, rgba(220,60,45,0.75) 0%, transparent 50%),
                radial-gradient(ellipse 45% 50% at 78% 35%, rgba(40,90,220,0.85) 0%, transparent 45%),
                linear-gradient(165deg, #1a0a14 0%, #0d1528 100%)
              `,
            }}
          />
          <div className="absolute inset-0 opacity-25 mix-blend-overlay">
            <div
              className="h-full w-full"
              style={{
                background:
                  "repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(255,255,255,0.03) 2px, rgba(255,255,255,0.03) 3px)",
              }}
            />
          </div>
        </div>
        <div className="flex w-[12%] flex-col gap-px border-[#252528] border-l pl-[1%]">
          <div className="h-[22%] min-h-[14px] rounded-sm bg-[#1c1c1f]" />
          <div className="flex flex-1 flex-col justify-end gap-px pb-[2%]">
            <div className="h-[40%] min-h-[24px] rounded-sm bg-linear-to-t from-[#b03028] via-[#3040a8] to-[#c9a035] opacity-90" />
          </div>
        </div>
      </div>
      <div className="flex h-[11%] min-h-[22px] flex-col border-[#2a2a2e] border-t bg-[#141416] px-[1.5%] pt-[1%]">
        <div className="mb-[2px] h-[22%] rounded-sm bg-[#1e1e22]" />
        <div className="flex flex-1 items-center gap-[2%]">
          <div className="size-[8px] rounded-sm bg-[#2e2e32]" />
          <div className="h-px flex-1 bg-[#333338]" />
          <div className="flex gap-1">
            <div className="size-[6px] rounded-full bg-[#3a3a40]" />
            <div className="size-[6px] rounded-full bg-[#3a3a40]" />
            <div className="size-[6px] rounded-full bg-[#dcdcd6]" />
          </div>
        </div>
      </div>
    </div>
  )
}

/** Full-bleed asset from `/public` */
function WallpaperScreen() {
  return (
    <div className="absolute inset-0">
      <Image
        alt=""
        className="object-cover"
        fill
        sizes="(max-width: 768px) 90vw, min(92vw, 752px)"
        src="/product-images/apple-wallpaper.jpg"
      />
    </div>
  )
}

/** Abstract multi-stop gradient (no raster) */
function GradientScreen() {
  return (
    <div
      aria-hidden
      className="absolute inset-0"
      style={{
        background: `
          radial-gradient(ellipse 100% 72% at 18% 22%, rgba(255, 130, 190, 0.42) 0%, transparent 48%),
          radial-gradient(ellipse 85% 65% at 88% 78%, rgba(70, 210, 255, 0.38) 0%, transparent 42%),
          radial-gradient(ellipse 55% 50% at 50% 48%, rgba(160, 130, 255, 0.32) 0%, transparent 52%),
          linear-gradient(128deg, #100818 0%, #181030 32%, #0a1426 66%, #120a18 100%)
        `,
      }}
    />
  )
}

/** Lightroom-style Develop / Library placeholder */
function PhotoEditScreen() {
  return (
    <div
      className="absolute inset-0 flex flex-col bg-[#1e1e22]"
      style={{ fontFamily: "system-ui, sans-serif" }}
    >
      <div className="flex h-[8%] min-h-[18px] items-center border-[#2e2e32] border-b px-[2%]">
        <span className="text-[#b0b0b5] text-[5px] sm:text-[6px]">Develop</span>
        <span className="ml-3 text-[#5c5c64] text-[5px] sm:text-[6px]">
          Library
        </span>
      </div>
      <div className="relative flex flex-1 overflow-hidden">
        <div className="w-[18%] border-[#2e2e32] border-r bg-[#18181c] p-[2%]">
          <div className="mb-1 h-[14%] rounded-sm bg-[#252528]" />
          <div className="mb-1 h-[14%] rounded-sm bg-[#252528]" />
          <div className="h-[14%] rounded-sm bg-[#252528]" />
        </div>
        <div className="relative flex min-w-0 flex-1 items-center justify-center bg-[#121216] p-[3%]">
          <div
            className="aspect-4/3 w-[85%] max-w-full rounded-sm shadow-2xl"
            style={{
              background:
                "linear-gradient(145deg, #e8c088 0%, #8b6040 35%, #3d5a78 70%, #1a2838 100%)",
            }}
          />
        </div>
        <div className="flex w-[16%] flex-col border-[#2e2e32] border-l bg-[#18181c] p-[2%]">
          <div className="mb-2 h-[28%] min-h-[20px] rounded-sm bg-[#2a2420]" />
          <div className="h-[12%] min-h-[10px] rounded-sm bg-[#222226]" />
        </div>
      </div>
    </div>
  )
}

/** Order must match `SCREEN_GLOW` indexing for hover tint */
const MODES: StudioScreenMode[] = ["grading", "wallpaper", "photo", "gradient"]

function resolveInitialModeIndex(mode: StudioScreenMode | undefined): number {
  const resolved = mode ?? "wallpaper"
  const idx = MODES.indexOf(resolved)
  return idx >= 0 ? idx : 0
}

/** Renders one built-in demo; superseded when parent passes `screenContent` */
function DefaultScreen({ mode }: { mode: StudioScreenMode }) {
  if (mode === "wallpaper") {
    return <WallpaperScreen />
  }
  if (mode === "photo") {
    return <PhotoEditScreen />
  }
  if (mode === "gradient") {
    return <GradientScreen />
  }
  return <GradingScreen />
}

// ---------------------------------------------------------------------------
// Root: layout wrapper + hardware + interactive screen
// ---------------------------------------------------------------------------

export function AppleProDisplayXDR({
  className,
  screenContent,
  initialMode = "wallpaper",
}: AppleStudioDisplayProps) {
  const reduceMotion = useReducedMotion()
  const [modeIndex, setModeIndex] = useState(() =>
    resolveInitialModeIndex(initialMode)
  )
  const [hoverDisplay, setHoverDisplay] = useState(false)
  const [cameraHot, setCameraHot] = useState(false)
  // Mimics recording LED: short green pulse on camera-area hover
  const [ledOn, setLedOn] = useState(false)

  const prevInitialModeRef = useRef(initialMode)
  useEffect(() => {
    // Prop-controlled remount of initial tab when `initialMode` changes externally
    if (prevInitialModeRef.current !== initialMode) {
      prevInitialModeRef.current = initialMode
      setModeIndex(resolveInitialModeIndex(initialMode))
    }
  }, [initialMode])

  const mode = MODES[modeIndex] ?? "wallpaper"
  const glowTint = SCREEN_GLOW[modeIndex % SCREEN_GLOW.length] ?? SCREEN_GLOW[0]

  const cycleContent = useCallback(() => {
    if (screenContent) {
      return
    }
    setModeIndex((i) => (i + 1) % MODES.length)
  }, [screenContent])

  const onCameraEnter = useCallback(() => {
    setCameraHot(true)
    setLedOn(true)
    window.setTimeout(() => setLedOn(false), 700)
  }, [])

  const onCameraLeave = useCallback(() => {
    setCameraHot(false)
  }, [])

  return (
    <div
      className={cn(
        "flex min-h-dvh items-center justify-center p-6",
        className
      )}
    >
      <motion.div
        className="relative flex w-[min(92vw,752px)] flex-col items-center"
        initial={false}
        transition={
          reduceMotion
            ? { duration: 0.15 }
            : { type: "spring", stiffness: 520, damping: 28 }
        }
      >
        <div
          className="relative flex w-full flex-col items-center"
          style={{ containerType: "inline-size" }}
        >
          {/* Display shadow */}
          <div
            aria-hidden
            className="-z-10 pointer-events-none absolute top-[6%] w-[90%]"
            style={{
              height: "58%",
              left: "5%",
              boxShadow: `
                  0 2px 6px rgba(0,0,0,0.15),
                  0 12px 40px rgba(0,0,0,0.12),
                  0 30px 80px rgba(0,0,0,0.08)
                `,
            }}
          />

          {/* Hover: colored glow tracks current demo (`glowTint` ↔ `MODES`) */}
          {/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: hover tint uses non-interactive hardware wrapper */}
          <figure
            aria-label="Apple Studio Display"
            className="relative m-0 w-full"
            onMouseEnter={() => setHoverDisplay(true)}
            onMouseLeave={() => setHoverDisplay(false)}
            style={{
              transition: "filter 0.25s ease-out",
              filter: hoverDisplay
                ? `drop-shadow(0 0 48px ${glowTint}) drop-shadow(0 0 24px ${glowTint})`
                : undefined,
            }}
          >
            <div className="relative w-full pb-1">
              {/* Brushed aluminum enclosure + inner glass lip */}
              <div
                className="relative box-border w-full rounded-[10px]"
                style={{
                  padding: FRAME_PX,
                  borderRadius: R_OUTER,
                  background: `
                      linear-gradient(180deg, rgba(255,255,255,0.14) 0%, transparent 22%, transparent 78%, rgba(0,0,0,0.06) 100%),
                      repeating-linear-gradient(
                        90deg,
                        ${ALUMINUM.brushLo} 0px,
                        ${ALUMINUM.brushHi} 1px,
                        ${ALUMINUM.brushLo} 2px,
                        ${ALUMINUM.brushHi} 3px,
                        ${ALUMINUM.brushLo} 4px
                      )
                    `,
                  boxShadow: `
                      inset 0 1px 0 ${ALUMINUM.chamfer},
                      inset 0 -1px 0 rgba(0,0,0,0.12),
                      inset 1px 0 0 rgba(255,255,255,0.06),
                      inset -1px 0 0 rgba(0,0,0,0.05)
                    `,
                }}
              >
                <div
                  aria-hidden
                  className="pointer-events-none absolute inset-[3px] rounded-[8px]"
                  style={{
                    borderRadius: R_GLASS,
                    boxShadow: "inset 0 0 0 1px rgba(232,232,234,0.55)",
                  }}
                />

                {/* Black bezel + panel; asymmetric padding = larger bottom “chin” */}
                <div
                  className="relative w-full overflow-hidden rounded-[8px] shadow-[inset_0_0_0_1px_rgba(0,0,0,0.45)]"
                  style={{
                    borderRadius: R_GLASS,
                    background: ALUMINUM.bezel,
                    paddingTop: BEZEL.top,
                    paddingLeft: BEZEL.side,
                    paddingRight: BEZEL.side,
                    paddingBottom: BEZEL.bottom,
                  }}
                >
                  {/* biome-ignore lint/a11y/noStaticElementInteractions lint/a11y/noNoninteractiveElementInteractions: decorative LED reaction */}
                  <div
                    className="-translate-x-1/2 absolute top-[3px] left-1/2 z-20 flex items-center gap-[3px]"
                    onMouseEnter={onCameraEnter}
                    onMouseLeave={onCameraLeave}
                  >
                    <div
                      className="size-[3px] shrink-0 rounded-full"
                      style={{
                        background: ALUMINUM.cameraDot,
                        boxShadow: cameraHot
                          ? "0 0 0 0.5px rgba(255,255,255,0.35), inset 0 0.5px 0 rgba(255,255,255,0.2)"
                          : "inset 0 0.5px 0 rgba(255,255,255,0.12)",
                      }}
                    />
                    <div
                      className="size-px shrink-0 rounded-full transition-opacity duration-150"
                      style={{
                        background: ALUMINUM.led,
                        opacity: ledOn ? 1 : 0.35,
                        boxShadow: ledOn
                          ? "0 0 3px rgba(48,209,88,0.9)"
                          : "none",
                      }}
                    />
                  </div>

                  <div
                    className="relative aspect-video w-full max-w-full overflow-hidden rounded-md bg-black text-left"
                    style={{ borderRadius: R_SCREEN }}
                  >
                    <div className="absolute inset-0 z-0 overflow-hidden rounded-[inherit]">
                      {screenContent ?? <DefaultScreen mode={mode} />}
                    </div>
                    {/* Full-area hit target; dock uses pointer-events-auto */}
                    <button
                      aria-label="Cycle demo screen content"
                      className="absolute inset-0 z-[1] cursor-pointer border-0 bg-transparent p-0 outline-none focus-visible:ring-2 focus-visible:ring-[#e8e8ea] focus-visible:ring-inset focus-visible:ring-offset-0"
                      onClick={cycleContent}
                      onKeyDown={(e) => {
                        if (e.key === "Enter" || e.key === " ") {
                          e.preventDefault()
                          cycleContent()
                        }
                      }}
                      type="button"
                    />
                    {!screenContent && (
                      <StudioDock
                        ariaLabel="Application dock (demo)"
                        className="-translate-x-1/2 pointer-events-auto absolute bottom-[5%] left-1/2 z-10 flex max-w-[98%] items-end justify-center space-x-0.5 rounded-[22px] px-2.5 pt-1 sm:bottom-[5.5%] sm:gap-1.5 sm:px-3"
                        reduceMotion={!!reduceMotion}
                        style={{
                          background:
                            "linear-gradient(180deg, rgba(255,255,255,0.42) 0%, rgba(250,250,252,0.22) 42%, rgba(255,255,255,0.16) 100%)",
                          backdropFilter: "blur(32px) saturate(190%)",
                          WebkitBackdropFilter: "blur(32px) saturate(190%)",
                          boxShadow: `
                            0 0 0 0.5px rgba(255,255,255,0.62),
                            0 0 0 1px rgba(0,0,0,0.05),
                            inset 0 1px 0 rgba(255,255,255,0.72),
                            inset 0 -1px 0 rgba(0,0,0,0.04),
                            0 12px 32px rgba(0,0,0,0.13)
                          `,
                        }}
                      >
                        {dockApps.map((app) => (
                          <StudioDockIcon
                            key={app.name}
                            label={app.name}
                            // showRunningDot={app.name === "Finder"}
                          >
                            <div
                              className="flex size-[28px] items-center justify-center overflow-hidden rounded-[9px] shadow-[0_1px_2px_rgba(0,0,0,0.12),inset_0_0.5px_0_rgba(255,255,255,0.35)] ring-1 ring-black/[0.08] sm:size-[26px]"
                              style={{
                                background: `linear-gradient(145deg, ${app.color} 0%, ${app.color}dd 100%)`,
                              }}
                            >
                              <app.icon
                                aria-hidden
                                className={cn("size-[16px] sm:size-[18px]")}
                              />
                            </div>
                          </StudioDockIcon>
                        ))}
                        <div
                          aria-hidden
                          className="mx-0.5 h-[22px] w-px shrink-0 bg-black/10"
                        />
                        <StudioDockIcon label="Downloads">
                          <div
                            className="flex size-[28px] items-center justify-center overflow-hidden rounded-[9px] shadow-[0_1px_2px_rgba(0,0,0,0.14),inset_0_0.5px_0_rgba(255,255,255,0.12)] ring-1 ring-black/15 sm:size-[26px]"
                            style={{
                              background:
                                "linear-gradient(145deg, #5a5a5e 0%, #2c2c2e 100%)",
                            }}
                          >
                            <IconDownload
                              aria-hidden
                              className="h-[16px] w-[16px] text-white/80 sm:h-[14px] sm:w-[14px]"
                            />
                          </div>
                        </StudioDockIcon>
                      </StudioDock>
                    )}
                  </div>

                  {/* Specular streak across glass (non-interactive) */}
                  <div
                    aria-hidden
                    className="pointer-events-none absolute inset-0 rounded-[inherit]"
                    style={{
                      background: `linear-gradient(
                          115deg,
                          transparent 38%,
                          rgba(255,248,235,0.055) 48%,
                          rgba(255,255,255,0.065) 50%,
                          rgba(255,248,235,0.05) 52%,
                          transparent 62%
                        )`,
                      mixBlendMode: "soft-light",
                      borderRadius: R_GLASS,
                    }}
                  />
                </div>
              </div>
            </div>

            {/* Contact shadow under display */}
            <div
              aria-hidden
              className="-translate-x-1/2 pointer-events-none absolute bottom-0 left-1/2 z-5 h-[10px] w-[42%] translate-y-[2px]"
              style={{
                background:
                  "radial-gradient(ellipse 100% 100% at 50% 0%, rgba(0,0,0,0.35) 0%, transparent 70%)",
              }}
            />
          </figure>

          {/* Stand: slim hinge seam, tapered column, foot with rubber feet */}
          <div
            className="relative flex w-full flex-col items-center"
            style={{ marginTop: "-1px" }}
          >
            <div
              aria-hidden
              className="mb-[2px] h-[2px] w-[min(30%,220px)] rounded-full bg-[#1c1c1e]"
              style={{
                boxShadow:
                  "inset 0 1px 0 rgba(0,0,0,0.5), 0 1px 0 rgba(255,255,255,0.04)",
              }}
            />

            <div
              className="relative flex w-[30%] flex-col items-center"
              style={{
                minWidth: "72px",
                height:
                  "clamp(120px, calc(0.4 * ((100cqw - 24px) * 9 / 16 + 37px)), 320px)",
              }}
            >
              <div
                className="relative w-full flex-1 overflow-visible rounded-md"
                style={{
                  borderRadius: "6px",
                  background: `
                      linear-gradient(90deg, rgba(0,0,0,0.07) 0%, transparent 15%, transparent 85%, rgba(0,0,0,0.07) 100%),
                      linear-gradient(180deg, rgba(255,255,255,0.1) 0%, transparent 40%),
                      repeating-linear-gradient(
                        0deg,
                        ${ALUMINUM.brushLo} 0px,
                        ${ALUMINUM.brushHi} 1px,
                        ${ALUMINUM.brushLo} 2px,
                        ${ALUMINUM.brushHi} 3px,
                        ${ALUMINUM.brushLo} 4px
                      )
                    `,
                  boxShadow: `
                      5px 0 10px rgba(0,0,0,0.08),
                      inset 0 1px 0 rgba(255,255,255,0.2),
                      inset 1px 0 0 rgba(255,255,255,0.08),
                      inset -1px 0 0 rgba(0,0,0,0.06),
                      inset 0 -1px 0 rgba(0,0,0,0.12)
                    `,
                }}
              >
                <Tooltip>
                  <TooltipTrigger
                    render={
                      <button
                        aria-label="Cable management opening"
                        className="-translate-x-1/2 absolute left-1/2 z-10 cursor-default border-0 bg-transparent p-0"
                        style={{
                          top: "20%",
                          width: "15%",
                          minWidth: "10px",
                          height: "20%",
                          minHeight: "22px",
                          borderRadius: "999px",
                          boxShadow: `
                            inset 0 1px 1px rgba(255,255,255,0.35),
                            inset 0 -2px 2px rgba(0,0,0,0.25),
                            0 0 0 1px rgba(0,0,0,0.12)
                          `,
                          background: SCENE_BG,
                        }}
                        type="button"
                      />
                    }
                  />
                  <TooltipContent
                    className="border border-[#2c2c2e] bg-[#1e1e1e] text-[#f5f5f7] text-[11px]"
                    side="right"
                  >
                    Cable management
                  </TooltipContent>
                </Tooltip>
              </div>

              <div
                className="relative mt-0 w-[52%] shrink-0"
                style={{
                  height: "9px",
                  borderRadius: "6px",
                  background: `
                      linear-gradient(180deg, rgba(255,255,255,0.12) 0%, transparent 35%),
                      repeating-linear-gradient(
                        90deg,
                        ${ALUMINUM.brushLo} 0px,
                        ${ALUMINUM.brushHi} 1px,
                        ${ALUMINUM.brushLo} 2px,
                        ${ALUMINUM.brushHi} 3px,
                        ${ALUMINUM.brushLo} 4px
                      )
                    `,
                  boxShadow: `
                      inset 0 1px 0 ${ALUMINUM.chamfer},
                      0 1px 3px rgba(0,0,0,0.2),
                      0 4px 16px rgba(0,0,0,0.1)
                    `,
                }}
              >
                <div
                  aria-hidden
                  className="absolute top-0 right-0 left-0 h-px rounded-t-md bg-black/22"
                />
                <div
                  aria-hidden
                  className="absolute top-px right-0 left-0 h-px rounded-t-md bg-white/18"
                />
                <div
                  aria-hidden
                  className="absolute bottom-0 left-[10%] h-[3px] w-[12%] rounded-full bg-[#141414] opacity-90"
                  style={{
                    boxShadow: "0 1px 0 rgba(255,255,255,0.05)",
                    transform: "translateY(40%)",
                  }}
                />
                <div
                  aria-hidden
                  className="absolute right-[10%] bottom-0 h-[3px] w-[12%] rounded-full bg-[#141414] opacity-90"
                  style={{
                    boxShadow: "0 1px 0 rgba(255,255,255,0.05)",
                    transform: "translateY(40%)",
                  }}
                />
              </div>
            </div>
          </div>
        </div>
      </motion.div>
    </div>
  )
}

export default AppleProDisplayXDR
```

**Update the import paths to match your project setup.**

**The built-in wallpaper demo loads `next/image` from `public/images/apple-wallpaper.jpg`. Add
  that asset or pass `screenContent` / adjust the source in the component.**

## Usage

`AppleProDisplayXDR` is a client component. Optionally pass `screenContent` to fully control the display area; otherwise the default cycling demos and dock run on click.

```tsx
import { AppleProDisplayXDR } from "@/components/apple-pro-display-xdr";

export function Hero() {
  return (
    <AppleProDisplayXDR initialMode="wallpaper" />
  );
}
```
