/* Playful app-card hovers. hover.js wraps each icon in .icon-stage > .icon-lift and adds the .hv items.
   Items are placed from the icon centre and kept 14px inside the card: x within ±136, top no higher than -116. */
.icon-stage {
  position: relative; display: inline-block; flex: none;
  width: 128px; height: 128px; margin: 36px auto auto;
  isolation: isolate;
}
.icon-lift { display: block; position: relative; z-index: 1; }
.icon-lift > .app-card-icon { display: block; margin: 0; }
.hv-mark { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* Stands in for the soft shadow baked under the ghost in the original icon. */
.hv-ghost-shadow {
  position: absolute; left: 24%; top: 74%; width: 52%; height: 12%; pointer-events: none;
  border-radius: 50%; background: radial-gradient(closest-side, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.18) 60%, transparent);
}
.hv, .hv-flash, .hv-spark, .hv-glow { display: none; }

@media (max-width: 600px) {
  .icon-stage { width: 112px; height: 112px; }
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .icon-stage {
    --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  /* The lift lives on the wrapper so the image is free for its own rotate and translate keyframes.
     The image transitions those properties too, so it eases home when a keyframe stops mid-way. */
  .icon-lift { transition: transform 280ms ease-out; }
  .app-card:is(:hover, :focus-within) .icon-lift {
    transform: translateY(-4px) scale(1.06);
    transition: transform 560ms var(--spring);
  }
  .icon-lift > .app-card-icon { transition: rotate 240ms ease-out, translate 300ms ease-out; }

  /* Items wait at the icon centre, small and hidden behind it, spring out with a stagger and leave together. */
  .hv {
    display: block; position: absolute; left: 50%; top: 50%; z-index: 0;
    pointer-events: none; opacity: 0;
    transform: translate(-50%, -50%) translate(var(--x0, 0px), var(--y0, 0px)) rotate(var(--r, 0deg)) scale(var(--s0, 0.6));
    transition: transform 240ms ease-in, opacity 200ms ease-in;
  }
  .app-card:is(:hover, :focus-within) .hv {
    opacity: 1;
    transform: translate(-50%, -50%) translate(var(--x), var(--y)) rotate(var(--r, 0deg)) scale(1);
    transition: transform 560ms var(--spring) var(--d, 0ms), opacity 180ms linear var(--d, 0ms);
  }

  /* One glass for every floating chip. Dark is the site default. */
  .hv-glass {
    background: rgb(44 44 48 / 0.78);
    border: 0.5px solid var(--hairline);
    box-shadow: 0 6px 18px rgb(0 0 0 / 0.18), inset 0 0.5px 0 rgb(255 255 255 / 0.12);
    -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%);
  }
  html[data-theme="light"] .hv-glass {
    background: rgb(255 255 255 / 0.82);
    box-shadow: 0 6px 18px rgb(0 0 0 / 0.18), inset 0 0.5px 0 rgb(255 255 255 / 0.5);
  }
  .hv-chip {
    display: flex; align-items: center; gap: 5px;
    width: max-content; height: 24px; box-sizing: border-box; border-radius: 12px;
    font: 500 12px/1 -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
    letter-spacing: -0.01em; white-space: nowrap; color: var(--ink);
  }

  /* Xcode: the hammer pivots near the end of its handle, winds up and strikes. On impact the BETA
     capsule is knocked down and three sparks fly off the hammer face. */
  .hv-hammer { transform-origin: 23.4% 75.4%; }
  .hv-strike .hv-hammer { animation: hv-swing 660ms; }
  .hv-strike .hv-beta { animation: hv-knock 260ms 360ms; }
  .hv-spark {
    display: block; position: absolute; left: 86.1%; top: 47.9%; z-index: 1;
    width: 2px; height: 9px; margin: -4.5px 0 0 -1px; border-radius: 1px;
    background: #fff; opacity: 0; pointer-events: none; rotate: var(--a);
  }
  .hv-strike .hv-spark { animation: hv-spark 260ms ease-out 360ms; }
  @keyframes hv-swing {
    0% { rotate: 0deg; animation-timing-function: ease-out; }
    33.3% { rotate: -28deg; animation-timing-function: ease-in; }
    54.5% { rotate: 8deg; animation-timing-function: ease-out; }
    69.7% { rotate: -3deg; animation-timing-function: ease-in-out; }
    84.8% { rotate: 1deg; animation-timing-function: ease-in-out; }
    100% { rotate: 0deg; }
  }
  @keyframes hv-knock {
    0% { translate: 0 0; scale: 1; animation-timing-function: ease-out; }
    25% { translate: 0 3px; scale: 0.94; animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
    100% { translate: 0 0; scale: 1; }
  }
  /* The spark's own transform runs along its --a direction, away from the strike point. */
  @keyframes hv-spark {
    0% { opacity: 1; transform: translateY(-4px) scaleY(0.5); }
    40% { opacity: 1; transform: translateY(-9px) scaleY(1); }
    100% { opacity: 0; transform: translateY(-16px) scaleY(0.4); }
  }

  /* Droppy Code: three Hydra heads rise out of the icon, land with a squash, and duck back in on leave. */
  .hv-drop {
    --s0: 0.4;
    width: var(--w); line-height: 0;
    transition: transform 240ms ease-in, opacity 240ms ease-in;
  }
  .hv-drop img {
    display: block; width: 100%; height: auto; transform-origin: 50% 100%;
    filter: drop-shadow(0 3px 5px rgb(0 0 0 / 0.25));
  }
  .hv-drop img.hv-flip { transform: scaleX(-1); }
  .app-card:is(:hover, :focus-within) .hv-drop img { animation: hv-squash 460ms ease-out calc(var(--d, 0ms) + 300ms); }
  @keyframes hv-squash {
    0%, 100% { scale: 1 1; }
    30% { scale: 1.08 0.85; }
    65% { scale: 0.97 1.05; }
  }

  /* Ghostty: the ghost floats up out of its tile, bobs side to side and hovers there.
     Its shadow stays on the tile and shrinks as it rises. */
  [data-app="ghostty"] .hv-mark {
    transition: translate 300ms ease-out, scale 300ms ease-out;
  }
  .hv-ghost-shadow { transition: scale 300ms ease-out, opacity 300ms ease-out; }
  .app-card:is(:hover, :focus-within) [data-app="ghostty"] .hv-mark {
    translate: 0 -26px; scale: 1.08;
    transition: translate 760ms cubic-bezier(0.22, 1, 0.36, 1), scale 760ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .app-card:is(:hover, :focus-within) .hv-ghost-shadow {
    scale: 0.62; opacity: 0.45;
    transition: scale 760ms cubic-bezier(0.22, 1, 0.36, 1), opacity 760ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .hv-mark.hv-wobble { animation: hv-wobble 1500ms ease-in-out 120ms; }
  @keyframes hv-wobble {
    0%, 100% { rotate: 0deg; }
    16% { rotate: -6deg; }
    36% { rotate: 6deg; }
    56% { rotate: -4.5deg; }
    76% { rotate: 3deg; }
    90% { rotate: -1deg; }
  }

  /* Claude: the asterisk makes one full turn; the icon behind it stays still. */
  .hv-mark.hv-spin { animation: hv-spin 900ms cubic-bezier(0.65, 0, 0.35, 1); }
  @keyframes hv-spin { to { rotate: 360deg; } }

  /* Icon Composer: the icon's own layers pull apart like its exploded layer view, stay apart while
     hovered and restack on leave. Each scales about its own centre. */
  .hv-layer { transition: transform 260ms ease-in; }
  .hv-l1 { transform-origin: 50% 62%; }
  .hv-l2 { transform-origin: 50% 49%; }
  .hv-l3 { transform-origin: 50% 36%; }
  .app-card:is(:hover, :focus-within) .hv-layer { transition: transform 600ms var(--spring) var(--d, 0ms); }
  .app-card:is(:hover, :focus-within) .hv-l3 { transform: translateY(-22px) scale(1.04); }
  .app-card:is(:hover, :focus-within) .hv-l2 { --d: 40ms; transform: translateY(-6px); }
  .app-card:is(:hover, :focus-within) .hv-l1 { --d: 80ms; transform: translateY(10px); }

  /* Aside: the globe turns once about its vertical axis, lit softly from behind while it turns. */
  [data-app="aside"] .icon-lift { perspective: 400px; }
  [data-app="aside"] .hv-mark { z-index: 1; }
  .hv-glow {
    display: block; position: absolute; inset: 12%; border-radius: 50%; pointer-events: none; opacity: 0;
    background: radial-gradient(closest-side, rgb(255 255 255 / 0.9), rgb(255 255 255 / 0.35) 55%, transparent);
  }
  .hv-mark.hv-turn { animation: hv-turn 900ms cubic-bezier(0.65, 0, 0.35, 1); }
  .hv-turn ~ .hv-glow { animation: hv-glow 900ms cubic-bezier(0.65, 0, 0.35, 1); }
  @keyframes hv-turn {
    from { transform: rotateY(0deg); }
    to { transform: rotateY(360deg); }
  }
  @keyframes hv-glow {
    0%, 100% { opacity: 0; }
    50% { opacity: 0.35; }
  }

  /* SF Symbols: a burst of monochrome glyphs. */
  .hv-symbol { color: var(--ink); line-height: 0; }
  .hv-symbol svg { display: block; }

  /* CleanShot: a flash across the icon, a selection around it and its size. */
  .hv-flash {
    display: block; position: absolute; inset: 0; z-index: 2; overflow: hidden;
    border-radius: 23%; pointer-events: none;
  }
  .hv-flash::before {
    content: ""; position: absolute; inset: -20% auto -20% 0; width: 45%; opacity: 0;
    background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.9), transparent);
    transform: translateX(-120%) skewX(-18deg);
  }
  .app-card:is(:hover, :focus-within) .hv-flash::before { animation: hv-sweep 560ms ease-out 80ms; }
  .hv-frame {
    width: 140px; height: 140px; box-sizing: border-box; border-radius: 2px;
    border: 1px solid #0a84ff; background: rgb(10 132 255 / 0.06);
  }
  .hv-frame i {
    position: absolute; width: 8px; height: 8px; border-radius: 50%;
    background: #fff; box-shadow: 0 0 0 0.5px rgb(0 0 0 / 0.25), 0 1px 2px rgb(0 0 0 / 0.2);
  }
  .hv-frame i:nth-child(1) { top: -4.5px; left: -4.5px; }
  .hv-frame i:nth-child(2) { top: -4.5px; right: -4.5px; }
  .hv-frame i:nth-child(3) { bottom: -4.5px; left: -4.5px; }
  .hv-frame i:nth-child(4) { bottom: -4.5px; right: -4.5px; }
  .hv-dims {
    padding: 0 9px;
    font: 500 11px/1 ui-monospace, "SF Mono", Menlo, monospace; font-variant-numeric: tabular-nums;
  }
}

@keyframes hv-sweep {
  0% { opacity: 1; transform: translateX(-120%) skewX(-18deg); }
  100% { opacity: 1; transform: translateX(320%) skewX(-18deg); }
}
