/* Intellica homepage — hero v3 (2026-09-22). Plan: docs/hero-collage-plan.md
   Five clusters in an arc over the headline. Each is one big window of footage (Charlie, the team)
   with two or three small things around it. Built in code: windows, notifications, tapbacks, buttons. Everything physical
   (the cart, mailbox, register, phone, products, GIFs) is Calvin's image. No code-drawn paper, tape, stickers or pen.
   Layout: a fixed 1440 × 1026 stage, scaled to fit by hero.js. Under 1024px it becomes a stack.
   Everything sits straight except the cart and the ghosts. The big five never float; small pieces may. */

.hx { --hx-k: .8;   /* Calvin: everything but the h1, subhead and buttons smaller. One knob for the whole collage. */
  position: relative; height: calc(1026px * var(--hx-s, 1));   /* 1026: the film's 29px floor (AD pass 2026-09-23) */
  overflow: hidden; overflow-x: clip; overflow-y: visible; }   /* clip the sides only: the film's drop shadow spills past the floor (Calvin) */
.hx-stage { position: absolute; top: 0; left: 50%; width: 1440px; height: 1026px;
  transform: translateX(-50%) scale(var(--hx-s, 1)); transform-origin: top center; background: var(--ground); }

/* ---------- centre stack ---------- */
.hx-center { position: absolute; left: 320px; top: 288px; width: 800px; z-index: 5; text-align: center; }
/* the centre column is wide and sits on top: let clicks through to the collage, except on its two buttons */
.hx-center { pointer-events: none; }
.hx-center a, .hx-center button { pointer-events: auto; }
.hx-center .h1 { font-size: 82px; margin: 0 0 22px; }
.hx-center .sub { font-size: 19px; line-height: 1.5; color: var(--ink-2); max-width: 560px; margin: 0 auto 30px; }

/* ---------- every collage piece ---------- */
.hx-obj { position: absolute; left: var(--x); top: var(--y); width: var(--w); margin: 0; z-index: 2;
  rotate: var(--r, 0deg);
  animation: hx-in .8s var(--ease) calc(var(--i, 0) * 60ms) backwards,
             hx-float var(--fd, 8s) ease-in-out var(--fdl, 0s) infinite alternate;
  transition: scale .4s var(--ease), opacity .3s ease;
  transform: scale(var(--hx-k));   /* composes after rotate / scale / translate, so hover, float and tilt still work */ }
.hx-obj.hx-still, .hx-obj.hx-win { animation: hx-in .8s var(--ease) calc(var(--i, 0) * 60ms) backwards; }   /* the big five never float (Calvin); small pieces may */
/* layering: the big five and the film in the middle; GIFs tuck a little under them; everything else sits on top */
.hx-obj { z-index: 3; }
.hx-win, .hx-film { z-index: 2; }
.hx-obj.hx-gif, .hx-obj.hx-texts { z-index: 1; }   /* the text sits behind the top-left window (Calvin): Jack Archer, Mizzen+Main since the window swap (2026-10-17) */
@keyframes hx-in { from { opacity: 0; scale: .9; } }
@keyframes hx-float { from { translate: 0 0; } to { translate: 0 calc(var(--float-amp) * -1); } }

/* ---------- the big five: stylized macOS windows, footage goes here ----------
   Same window as the film's cart scene (s04-05, Calvin's v3 note): "an artistic browser window, not the
   real UI". A title bar with three bigger traffic lights and nothing else. No address bar, no icons, no title.
   The footage slot sits in the page; the joke filename sits under the window, heyclicky-style. */
.hx-win .win { position: relative; overflow: hidden; background: #fff; border-radius: 10px;
  box-shadow: 0 0 0 1px rgba(0,0,0,.08), 0 24px 60px rgba(16,17,20,.16); transition: box-shadow .35s var(--ease); }
.hx-win .tb { position: relative; height: 28px; background: #F5F5F7; border-bottom: 1px solid #DCDCE0; }
.hx-tl { position: absolute; left: 11px; top: 50%; translate: 0 -50%; display: flex; gap: 6px; }
.hx-tl i { display: block; width: 11px; height: 11px; border-radius: 50%; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.14); }
.hx-tl i.r { background: var(--red); } .hx-tl i.y { background: var(--yellow); } .hx-tl i.g { background: var(--green); }
.hx-win .scr, .hx-film .scr { position: relative; overflow: hidden; cursor: pointer;
  background: radial-gradient(120% 95% at 28% 18%, #1E2B55 0%, #0B1633 52%, #050B1F 100%); }
.hx-win .scr { aspect-ratio: var(--ar, 16 / 10); }
/* the three testimonials: the current site's Vimeo videos, muted background loops. Clicks pass through to the window. */
.hx-vm { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; }
.hx-wv { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }   /* a real clip in a window: the blooper reel */
.hx-win .scr::before { content: ""; position: absolute; inset: -40%; pointer-events: none;
  background: linear-gradient(110deg, transparent 42%, rgba(255,255,255,.07) 50%, transparent 58%);
  animation: hx-sheen 7s linear infinite; }
@keyframes hx-sheen { from { translate: -35% 0; } to { translate: 35% 0; } }
.hx-mk { position: absolute; top: 10px; left: 10px; z-index: 1; font-family: var(--mono); font-size: 10px; letter-spacing: .08em;
  line-height: 1; color: rgba(255,255,255,.78); padding: 5px 8px 5px 19px; border-radius: 6px; background: rgba(255,255,255,.1); }
.hx-mk::before { content: ""; position: absolute; left: 8px; top: 50%; width: 6px; height: 6px; margin-top: -3px; border-radius: 50%; background: var(--red); }
.hx-win .scr p, .hx-film .scr p { position: absolute; inset: 0; display: grid; place-items: center; margin: 0;
  padding: 30px 12%; text-align: center; font-size: 13px; line-height: 1.35; color: rgba(255,255,255,.88); }
/* sound on / off, top right. Click: the window plays or pauses. Hover: it grows (Calvin, 2026-09-22). */
.hx-sound { position: absolute; top: 8px; right: 8px; z-index: 3; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; background: rgba(2,11,36,.42); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .2s, scale .2s var(--ease); }
.hx-sound:hover { background: rgba(2,11,36,.65); scale: 1.1; }
.hx-sound svg { display: block; width: 14px; height: 14px; }
.hx-sound .on, .hx-win.sound-on .hx-sound .off { display: none; }
.hx-win.sound-on .hx-sound .on { display: block; }
.hx-pp { position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 2; width: 44px; height: 44px; pointer-events: none;
  opacity: 0; transition: opacity .2s; filter: drop-shadow(0 4px 14px rgba(2,11,36,.45)); }
.hx-pp svg { display: block; width: 100%; height: 100%; }
.hx-win.paused .hx-pp { opacity: 1; }
.hx-win .scr { cursor: pointer; }
.hx-bar { position: absolute; left: 10px; right: 10px; bottom: 10px; z-index: 1; height: 26px; border-radius: 13px;
  display: flex; align-items: center; gap: 9px; padding: 0 11px; background: rgba(255,255,255,.16);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); opacity: 0; translate: 0 6px; transition: opacity .3s, translate .3s var(--ease); }
.hx-bar svg { width: 10px; height: 10px; flex: none; }
.hx-bar i { flex: 1; height: 3px; border-radius: 2px; background: rgba(255,255,255,.25); position: relative; overflow: hidden; }
.hx-bar i::after { content: ""; position: absolute; inset: 0; width: 36%; border-radius: inherit; background: #fff; }
.hx-win.on .hx-bar { opacity: 1; translate: 0 0; }
.hx-win.on, .hx-win:focus-visible { scale: 1.5; z-index: 9; }   /* quite a bit bigger. .on = a real mouse is over it (hero.js) */
/* while one of the big five is hovered, everything else in the collage steps back.
   The headline, subhead and buttons are not collage pieces, so they stay. */
.hx-stage.focus .hx-obj:not(.on) { opacity: .4; }
.hx-win.on .win { box-shadow: 0 0 0 1px rgba(0,0,0,.08), 0 34px 80px rgba(16,17,20,.24); }
.hx-win figcaption { margin-top: 9px; text-align: center; font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); }
/* a testimonial is captioned with the person, not a filename */
.hx-tm figcaption { font-family: var(--sans); font-size: 13px; line-height: 1.3; color: var(--ink-3); }
.hx-tm figcaption b { display: block; font-weight: 600; color: var(--ink); }
.hx-tm figcaption span { display: block; }

/* the film, big, under the buttons: a rounded video, no window (heyclicky's big video).
   Calvin: no autoplay, a cover shot of Charlie at the desk, a bare play button in the centre, and the
   controls (sound, timeline) only once it plays. */
.hx-film .scr { aspect-ratio: 16 / 9; border-radius: 28px; cursor: pointer;
  background: #0B1633;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 0 0 1px rgba(2,11,36,.12), 0 40px 90px rgba(2,11,36,.24); }
.hx-vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hx-bigplay { position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 2; width: 84px; height: 84px; padding: 0; border: 0;
  background: none; cursor: pointer; filter: drop-shadow(0 6px 22px rgba(2,11,36,.38)); transition: scale .25s var(--ease), opacity .25s; }
.hx-bigplay svg { width: 100%; height: 100%; }
.hx-film:hover .hx-bigplay { scale: 1.08; }
.hx-film.started .hx-bigplay { opacity: 0; pointer-events: none; }
.hx-film.started.paused .hx-bigplay { opacity: 1; pointer-events: auto; }
.hx-ctl { position: absolute; left: 18px; right: 18px; bottom: 18px; z-index: 2; height: 42px; border-radius: 21px; display: flex; align-items: center; gap: 12px;
  padding: 0 14px; background: rgba(2,11,36,.44); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4);
  opacity: 0; translate: 0 8px; pointer-events: none; transition: opacity .3s, translate .3s var(--ease); cursor: default; }
.hx-film.started:hover .hx-ctl, .hx-film.started.paused .hx-ctl, .hx-film.started .hx-ctl:focus-within { opacity: 1; translate: 0 0; pointer-events: auto; }
@media (hover: none) { .hx-film.started .hx-ctl { opacity: 1; translate: 0 0; pointer-events: auto; } }
.hx-ctl button { width: 28px; height: 28px; flex: none; padding: 0; border: 0; border-radius: 50%; background: none; display: grid; place-items: center; cursor: pointer; }
.hx-ctl button:hover { background: rgba(255,255,255,.12); }
.hx-ctl button svg { width: 16px; height: 16px; }
.hx-ctl .tl { position: relative; flex: 1; height: 4px; border-radius: 2px; background: rgba(255,255,255,.28); cursor: pointer; transition: height .15s; touch-action: none; }
.hx-ctl .tl::before { content: ""; position: absolute; left: 0; right: 0; top: -9px; bottom: -9px; }   /* a fatter hit area */
.hx-ctl .tl:hover, .hx-ctl .tl:focus-visible { height: 6px; }
.hx-ctl .tl i { position: absolute; left: 0; top: 0; bottom: 0; width: 0; border-radius: inherit; background: #fff; }
.hx-ctl .tm { flex: none; font-family: var(--mono); font-size: 11.5px; color: rgba(255,255,255,.88); white-space: nowrap; }

/* the conversation window (client feedback, 2026-10-17): a real thread where the Loom clip was. Sized in the window's own
   width (cqw), so it reads the same at every stage scale and simply grows with the hover. hero.js builds and replays it. */
.hx-chatwin .scr { background: #fff; }
.hx-chatwin .scr::before { display: none; }   /* no sheen on a white screen */
.hx-chat { position: absolute; inset: 0; container-type: size; overflow: hidden; background: #fff; }
.hx-cin { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; padding: 0 3.6cqw 3.4cqw;
  font-family: var(--sans); font-size: 3.55cqw; }
.hx-cb { max-width: 78%; margin-top: .42em; padding: .42em .78em .48em; border-radius: 1.05em; line-height: 1.32; letter-spacing: -.004em; }
.hx-cb.in { align-self: flex-start; background: var(--bubble-in); color: #0B0B0F; }
.hx-cb.out { align-self: flex-end; background: var(--blue); color: #fff; }
.hx-cb.cont { margin-top: .14em; }
.hx-cst { align-self: center; margin: .9em 0 .1em; font-size: .8em; color: var(--ink-3); }
.hx-ctyp { align-self: flex-start; display: inline-flex; gap: .26em; margin-top: .42em; padding: .62em .8em; border-radius: 1.05em; background: var(--bubble-in); }
.hx-ctyp i { width: .44em; height: .44em; border-radius: 50%; background: #8E8E93; animation: hx-typ 1s ease-in-out infinite; }
.hx-ctyp i:nth-child(2) { animation-delay: .15s; }
.hx-ctyp i:nth-child(3) { animation-delay: .3s; }
@keyframes hx-typ { 0%, 60%, 100% { opacity: .35; translate: 0 0; } 30% { opacity: 1; translate: 0 -.12em; } }
.hx-cin > .arrive { animation: hx-carrive .38s var(--ease) both; }
@keyframes hx-carrive { from { opacity: 0; translate: 0 .6em; } }

/* testimonials: the Vimeo still until you hover, then the video plays (muted); it pauses when you leave */
.hx-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; pointer-events: none; transition: opacity .35s; }
.hx-tm.seen .hx-poster { opacity: 0; }

/* ---------- people: static headshots ---------- */
.hx-shot .ph { position: relative; overflow: hidden; box-shadow: 0 0 0 1px rgba(2,11,36,.08), 0 18px 44px rgba(2,11,36,.2); }
.hx-shot img { width: 100%; height: 100%; object-fit: cover; object-position: var(--op, 50% 25%); }
.hx-shot figcaption { margin-top: 7px; text-align: center; font-size: 12.5px; color: var(--ink-2); }
.hx-shot figcaption b { color: var(--ink); font-weight: 600; }
.hx-shot .ph { aspect-ratio: 5 / 6; border-radius: 14px; }
.hx-shot img { transition: scale .45s var(--ease), rotate .45s var(--ease); }
.hx-out { position: absolute; left: 50%; bottom: 8px; translate: -50% 4px; white-space: nowrap; font-family: var(--mono); font-size: 9.5px; letter-spacing: .06em;
  color: #fff; background: rgba(2,11,36,.62); padding: 3px 7px; border-radius: 5px; opacity: 0; transition: opacity .25s, translate .25s var(--ease); }

/* ---------- objects: IMAGE slots until the real images land ---------- */
.hx-slot { position: relative; height: var(--h); display: grid; place-content: center; gap: 3px; padding: 8px; text-align: center; border-radius: 16px;
  border: 1.5px dashed color-mix(in oklab, var(--ink) 24%, transparent); background: color-mix(in oklab, var(--surface) 60%, transparent); }
.hx-slot .k { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; color: var(--ink-3); }
.hx-slot .n { font-size: 12px; font-weight: 500; line-height: 1.25; color: var(--ink-2); }
.hx-slot.sm { border-radius: 12px; padding: 5px; gap: 2px; border-width: 1.25px; }
.hx-slot.sm .k { font-size: 7.5px; }
.hx-slot.sm .n { font-size: 10px; }
.hx-slot .s2 { display: none; }
.hx-slot.open .s1 { display: none; }
.hx-slot.open .s2 { display: inline; }
/* Calvin's small assets, used as sent (fit to size only): little accents */
.hx-acc img { width: 100%; }
.mult { mix-blend-mode: multiply; }   /* white-backed images sit straight on the ground */
.hx-card img { border-radius: 8px; box-shadow: 0 0 0 1px rgba(2,11,36,.08), 0 10px 24px rgba(2,11,36,.16); }
.hx-gif img { border-radius: 0; box-shadow: 0 10px 24px rgba(2,11,36,.16); }   /* hard edges (Calvin) */
.hx-cut img { filter: drop-shadow(0 8px 14px rgba(2,11,36,.22)); }   /* the cut-outs: telephone, card terminal, shirt */
.hx-obj.hx-bill { z-index: 1; }   /* the torn dollar lies flat, its edge under the Manly Bands window */
.hx-hang.swing > * { transform-origin: 49% 2%; }   /* the shirt sways from its hook on the Loom's bottom edge */
.hx-acc[data-click] { cursor: pointer; }
.fade > * { transition: opacity .7s var(--ease), translate .7s var(--ease); }
.fade:hover > * { opacity: .12; translate: 0 -10px; }   /* the ghosts ghost you */
.hx-prod { mix-blend-mode: multiply; }   /* white packshot ground drops out against the stage */
.hx-prod img { width: 100%; }

/* what each object does on hover */
.swing > * { transform-origin: 50% 0; }
.swing:hover > * { animation: hx-swing 1.5s var(--ease) both; }
@keyframes hx-swing { 0% { rotate: 0deg; } 18% { rotate: 7deg; } 40% { rotate: -5deg; } 62% { rotate: 3deg; } 82% { rotate: -1deg; } 100% { rotate: 0deg; } }
.roll > * { transition: rotate .8s var(--ease), translate .8s var(--ease); }
.roll:hover > * { rotate: calc(var(--r) * -1); translate: 18px 0; }
.jiggle:hover > *, .jiggle.ringing > * { animation: hx-jiggle .45s ease-in-out 2; }
@keyframes hx-jiggle { 25% { rotate: -3deg; } 75% { rotate: 3deg; } }
.press { cursor: pointer; }
.hx-cash { position: absolute; left: 50%; top: -4px; translate: -50% 0; font-family: var(--mono); font-size: 13px; font-weight: 600;
  color: var(--green-ui); opacity: 0; pointer-events: none; white-space: nowrap; }
.hx-slot.open .hx-cash, .hx-reg.open .hx-cash { animation: hx-cash 1.5s var(--ease) both; }
.hx-reg { cursor: pointer; }
.hx-reg .hx-cash { top: -10px; }
@keyframes hx-cash { 0% { opacity: 0; translate: -50% 6px; } 20% { opacity: 1; } 100% { opacity: 0; translate: -50% -26px; } }

/* the meme: its two photos are IMAGE slots, its text is the joke */

/* ---------- notifications: exact, straight, still ---------- */
/* iMessage banner, lock-screen style: the customer's words in the machine's chrome */
.hx-texts { height: 66px; cursor: pointer; }
.hx-ban { position: absolute; left: 0; right: 0; top: 0; display: flex; gap: 11px; align-items: center; padding: 11px 14px 11px 11px; border-radius: 22px;
  background: rgba(255,255,255,.76); backdrop-filter: blur(24px) saturate(1.6); -webkit-backdrop-filter: blur(24px) saturate(1.6);
  box-shadow: 0 0 0 .5px rgba(2,11,36,.08), 0 10px 30px rgba(2,11,36,.10); }
.hx-ban .av { position: relative; width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: linear-gradient(180deg, #A9AFBC, #878D9A); color: #fff; font-size: 15px; font-weight: 600; letter-spacing: .02em; }
.hx-ban .av i { position: absolute; right: -3px; bottom: -3px; width: 18px; height: 18px; border-radius: 5px; display: grid; place-items: center;
  background: linear-gradient(180deg, #6BE07C, #20B845); box-shadow: 0 0 0 1.5px #fff; }
.hx-ban .av i svg { width: 12px; height: 12px; }
.hx-ban .tx { flex: 1; min-width: 0; }
.hx-ban .t { display: flex; justify-content: space-between; gap: 8px; font-size: 14px; line-height: 1.25; }
.hx-ban .t b { font-weight: 600; }
.hx-ban .t time { font-size: 12.5px; color: var(--ink-3); }
.hx-ban .b { font-size: 14px; line-height: 1.3; color: var(--ink); }

/* tapbacks: exact iMessage reactions, bigger */
.hx-tb { position: relative; display: grid; place-items: center; width: 48px; height: 40px; border-radius: 20px; background: var(--bubble-in);
  box-shadow: 0 6px 18px rgba(2,11,36,.14); }
.hx-tb::before, .hx-tb::after { content: ""; position: absolute; border-radius: 50%; background: var(--bubble-in); }
.hx-tb::before { width: 12px; height: 12px; left: 3px; bottom: -3px; }
.hx-tb::after { width: 6px; height: 6px; left: -3px; bottom: -8px; }
/* the reactions, drawn as iOS 18 paints them: colourful and a little puffy (Calvin: match Apple's actual UI) */
.hx-tb svg { width: 23px; height: 23px; overflow: visible; }
.hx-tb svg.g-ha { width: 28px; height: 24px; }
.hx-tap { width: 48px; }
@keyframes hx-pop { 0% { scale: 1; } 40% { scale: 1.25; } 70% { scale: .94; } 100% { scale: 1; } }

/* Shopify: a stack that fans out on hover; a new order lands on top every few seconds */
.hx-stack { height: 96px; }
.hx-stack .notif { position: absolute; left: 0; top: 0; width: 100%; align-items: center; box-shadow: var(--shadow-1); border: 1px solid var(--line);
  transform-origin: 50% 0; transition: translate .45s var(--ease), scale .45s var(--ease), opacity .45s; }
.hx-stack .notif:nth-child(1) { z-index: 3; }
.hx-stack .notif > div:not(.icon), .hx-slack .tx { flex: 1; min-width: 0; }
.hx-stack .th { width: 40px; height: 40px; flex: none; margin-left: auto; border-radius: 8px; object-fit: cover; border: 1px solid var(--line); }

/* Slack: the reactions tick up on hover */
.hx-slack { width: var(--w); border: 1px solid var(--line); box-shadow: var(--shadow-1); }
.hx-slack .t { justify-content: flex-start; }
.hx-slack .t .ch { font-weight: 400; color: var(--ink-3); margin-left: 5px; }
.hx-slack .t time { margin-left: auto; padding-left: 8px; }
.hx-rx { display: flex; gap: 6px; margin-top: 8px; }
.hx-rx span { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 999px; font-size: 12px; line-height: 1.5;
  background: #F2F4F7; border: 1px solid var(--line); }
.hx-rx span.me { background: #E8F0FE; border-color: #B8CCF5; color: #1D4ED8; }
.hx-rx b { font-weight: 600; font-size: 11.5px; }

.hx [data-click] { cursor: pointer; }
.hx [data-click]:focus-visible { outline: 2px solid var(--hero); outline-offset: 4px; }

/* ---------- under 1024px: a short stack of the film, the top cluster and the sale cluster ---------- */
@media (max-width: 1023px) {
  .hx { height: auto; padding: 40px 20px 48px; }
  .hx-stage { position: static; width: auto; height: auto; transform: none; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 18px 16px; align-items: center; justify-items: center; }
  .hx-center { position: static; width: auto; grid-column: 1 / -1; margin-bottom: 14px; }
  .hx-center .h1 { font-size: clamp(46px, 12vw, 82px); }
  .hx-obj { position: relative; left: auto; top: auto; width: min(var(--w), 100%); rotate: 0deg; animation: none; order: var(--o, 50); transform: none; }
  .hx-obj.m-hide { display: none; }
  .hx-obj.m-wide { grid-column: 1 / -1; width: min(var(--w), 100%); }
  .hx-film { width: 100% !important; }
  .hx-stack { height: 110px; }
}
@media (prefers-reduced-motion: reduce) {
  .hx-obj, .hx-win .scr::before { animation: none !important; }
}

/* ---------- one Shopify, one text, one Slack: a click brings the next. Similar, never the same. ---------- */
/* the whole chip is the button: no text selection, no image drag, every child passes the click up */
.hx-stack, .hx-texts, .hx-slack { cursor: pointer; user-select: none; -webkit-user-select: none; }
.hx-stack *, .hx-texts *, .hx-slack * { cursor: pointer; }
.hx-stack img, .hx-texts img, .hx-slack img { -webkit-user-drag: none; }
.hx-stack { height: 74px; }
.hx-stack .notif.in { animation: hx-shop-in .55s cubic-bezier(.2,.9,.25,1.15) both; }         /* Shopify: drops in from above */
.hx-stack .notif.out { animation: hx-shop-out .5s var(--ease) both; }                         /*          and the old order sinks behind */
@keyframes hx-shop-in { from { translate: 0 -22px; opacity: 0; scale: .97; } }
@keyframes hx-shop-out { to { translate: 0 14px; opacity: 0; scale: .92; } }
.hx-texts .hx-ban.in { animation: hx-text-in .6s cubic-bezier(.3,1.5,.5,1) both; }            /* the text: springs down, like an iOS banner */
.hx-texts .hx-ban.out { animation: hx-text-out .32s ease-in both; }                          /*           and the old one flicks up and away */
@keyframes hx-text-in { from { translate: 0 -26px; opacity: 0; } }
@keyframes hx-text-out { to { translate: 0 -30px; opacity: 0; scale: .96; } }
.hx-slack.fresh { animation: hx-slack-glow 1.4s ease-out both; }                              /* Slack: swaps in place with the new-message glow */
@keyframes hx-slack-glow { 0% { background-color: #FFF4D6; } 100% { background-color: rgba(255,255,255,.88); } }
.hx-slack .tx.swap { animation: hx-slack-swap .45s var(--ease) both; }
@keyframes hx-slack-swap { from { opacity: 0; translate: 0 4px; } }
.hx-slack .hx-rx span.pop { animation: hx-rx-pop .45s var(--ease) both; animation-delay: calc(var(--k, 0) * 140ms + 250ms); }
@keyframes hx-rx-pop { 0% { scale: 0; opacity: 0; } 55% { scale: 1.2; opacity: 1; } 100% { scale: 1; } }

/* ---------- phones and tablets (AD pass, 2026-10-17, then Calvin's notes the same day). Every rule that mentions .hx-m is
   here; the older "under 1024px" block above it stays as it is.
   Calvin: the headline sits lower, small pieces gather above and around it, nothing follows the film. A phone gets no UI cards:
   his real objects at emoji size (ghosts, cart, phone, the card terminal, the torn dollar) and iMessage's own reactions, each
   reaction riding on a piece the way a tapback rides on a text. Loose clusters at uneven heights, never a tidy arc (Calvin).
   Everything sits straight except the cart and the ghosts.
   One lockup: the h1 and every piece are drawn in one unit, --hu (1px at 390; it scales with the screen up to 512px, then holds,
   where the h1 reaches the desktop's 82px). Each piece is placed from the headline's centre line and the top of the stack, never
   from the column's edges or the text below, so a line wrap or a button wrap can't walk it into the copy, and every phone width
   shows the same picture. The h1's glyph box (what the collision check measures), in --hu: x -106..106 from the centre,
   y 112..193 from the top of the stack. Pieces stay above it or beside it, never below it or beside the subhead, the buttons
   or the film. Desktop doesn't show .hx-m and is otherwise untouched. ---------- */
.hx-m { display: none; }
@media (max-width: 1023px) {
  .hx { padding: 6px 20px 28px; }                               /* 28 (was 40): the trust strip follows the film, no dead air */
  .hx-stage { display: block; }
  .hx-obj { display: none; }                                    /* below the film: nothing */
  .hx-obj.hx-film { display: block; position: relative; width: 100% !important; margin-top: 28px; }
  /* the film at phone size: the desktop's 28px corner and 90px haze turn a 350px film into a blob with a grey cloud under it */
  .hx-film .scr { border-radius: 20px; box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 0 0 1px rgba(2,11,36,.12), 0 18px 44px rgba(2,11,36,.18); }
  .hx-center { --hu: min(.25641vw, 1.3141px); --hx-top: 122;
    position: relative; left: auto; top: auto; width: auto; z-index: auto; margin: 0; padding-top: calc(var(--hx-top) * var(--hu)); }
  /* relative, so the desktop offsets go; no z-index, so the dollar multiplies into the ground as it does on desktop */
  .hx-center .h1 { font-size: calc(62.4 * var(--hu)); margin-bottom: 18px; }   /* 62px at 390 (was 47): the anchor the pieces hang on */
  .hx-center .sub { text-wrap: balance; }                       /* two even lines at every phone width: no lone "conversations." */

  /* ---------- the pieces ---------- */
  .hx-m { display: block; position: absolute; inset: 0; pointer-events: none; }
  .hx-m > * { position: absolute; margin: 0; pointer-events: auto;
    left: calc(50% + var(--mx) * var(--hu)); top: calc(var(--my) * var(--hu)); width: calc(var(--mw) * var(--hu));
    rotate: var(--mr, 0deg);
    animation: hx-in .7s var(--ease) .2s backwards; }           /* one entrance, all together on one beat */
  .hx-m > .hx-m-i { --float-amp: calc(4 * var(--hu));           /* the cart, the ghosts and the phone float, gently; the rest sit still */
    animation: hx-in .7s var(--ease) .2s backwards, hx-float var(--fd) ease-in-out var(--fdl) infinite alternate; }
  .hx-m img { width: 100%; }

  /* loose clusters at uneven heights (Calvin, 2026-10-17: no gap in the middle, but no tidy arc either; the card terminal in,
     the mailbox out): the sale (terminal, heart, dollar, "!!") a little left of centre, the abandoned cart by the headline's
     left end with its ghosts over it, the phone off on its own on the right */
  .hx-m-ghosts { --mx: -164; --my: 58;  --mw: 46; --mr: -8deg;  --fd: 6.5s; --fdl: -3s; }
  .hx-m-cart   { --mx: -190; --my: 104; --mw: 64; --mr: -10deg; --fd: 9s;   --fdl: -1s; }
  .hx-m-phone  { --mx: 122;  --my: 40;  --mw: 27; --fd: 7s;   --fdl: -5s; }
  .hx-m-pos    { --mx: -34;  --my: 8;   --mw: 44; z-index: 2; }   /* the dollar tucks under its edge */
  .hx-m-money  { --mx: 2;    --my: 40;  --mw: 62; height: calc(50 * var(--hu)); z-index: 1; }

  /* the cut-outs (the phone, the terminal): a desk shadow in proportion to their size */
  .hx-m .hx-cut img { filter: drop-shadow(0 calc(3 * var(--hu)) calc(5 * var(--hu)) rgba(2,11,36,.22)); }
  .hx-m .hx-reg .hx-cash { top: calc(-12 * var(--hu)); font-size: calc(11 * var(--hu)); }   /* the sale it rings up, at the lockup's scale */
  /* the money: the dollar lies flat at the bottom left, its "!!" on its top-right corner */
  .hx-m-money img { position: absolute; left: 0; bottom: 0; width: calc(44 * var(--hu)); }
  .hx-m-money .tb-bang { --tw: 30; right: 0; top: 0; }
  /* the reactions ride on pieces, the tail pointing in: HA HA on the ghosts' corner (turned back upright), the heart on the
     phone's top ear (Calvin). When the ghosts ghost you (tap), their HA HA stays. */
  .hx-m-ghosts .tb-ha { --tw: 36; left: 86%; top: -58%; rotate: 8deg; z-index: 1; }
  .hx-m-phone .tb-heart { --tw: 26; left: 34%; top: -42%; z-index: 1; }
  .hx-m .fade:hover > .hx-tb { opacity: 1; translate: none; }

  /* tapbacks at the lockup's scale: the desktop's 48 x 40 bubble and its two tail dots, redrawn in em (--tw = width in --hu) */
  .hx-m .hx-tb { position: absolute; width: 3em; height: 2.5em; border-radius: 1.25em; font-size: calc(var(--tw, 40) * var(--hu) / 3);
    box-shadow: 0 .08em .25em rgba(2,11,36,.10), 0 .3em .8em rgba(2,11,36,.10); }
  .hx-m .hx-tb::before { width: .75em; height: .75em; left: .19em; bottom: -.19em; }
  .hx-m .hx-tb::after { width: .375em; height: .375em; left: -.19em; bottom: -.5em; }
  .hx-m .hx-tb svg { width: 1.45em; height: 1.45em; }
  .hx-m .hx-tb svg.g-ha { width: 1.75em; height: 1.5em; }
  .hx-m .hx-tb svg.g-bang { width: 1.55em; height: 1.55em; }    /* the "!!" from the v1 hero (index-v1.html) */
}
@media (max-width: 479px) {   /* phones: the two buttons stack at one width (they used to wrap at natural widths, the ghost wider than the primary) */
  .hx-center .ctas { flex-direction: column; align-items: center; }
  .hx-center .ctas .btn { width: min(100%, 272px); justify-content: center; }
}
