/* ═══════════════════════════════════════════════════════════════════════════
   Social links + mascot — SHARED by / (Classic, index.html) and /cinematic/.
   Behaviour: /assets/social.js. Both pages carry the same markup (and the
   same <svg> sprite: #ffs-i-tt, #ffs-i-yt); text uses the page's own i18n
   (data-i18n="social.watchOn", from the shared /assets/i18n.js).

     .ffs          "Watch FindFilm on [TikTok] [YouTube Shorts]" strip
       --hero        in the hero, under the search (both layouts)
       --feed        Classic phones only: after the first feed row
       --desk        hidden on phones (Classic's hero strip, whose twin is --feed)
     .ffm          the mascot peeking from the bottom-right corner
                   (computers only, once the hero strip has scrolled away)
     .ffs-band     footer band: the mascot, full size, and large buttons
     .ffb          the mascot's moods during AI searches (think, idea,
                   success, confused): Classic's AI panel, Cinematic's
                   results heading, and the corner mascot
     .ffw          a first visit's welcome tip, under the AI search
     .ffm.is-egg   the corner mascot's easter egg (five quick clicks)
     .ffh          Classic: the mascot beside the hero search (computers ≥1200px)
     .ffp          Classic: the mascot peeking over "Your Taste DNA" (computers)

   Fonts and colours are inherited, so the strip reads as part of each layout.
   Both pages link this file as ?v=<hash> (the service worker serves /assets/*
   stale-while-revalidate): after editing it or social.js, bump ?v= in BOTH.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Brand buttons ───────────────────────────────────────────────────────── */
.ffs-links { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ffs-btn {
  position: relative; display: inline-flex; align-items: center; gap: 8px;
  box-sizing: border-box; height: 36px; margin: 0; padding: 0 14px 0 11px;
  border: 1px solid rgba(255,255,255,0.12); border-radius: 999px;
  background: rgba(255,255,255,0.06); color: #fff;
  font-size: 13.5px; font-weight: 600; line-height: 1; letter-spacing: -0.005em;
  white-space: nowrap; text-decoration: none;
  transition: transform 0.25s cubic-bezier(.22,1,.36,1), background-color 0.2s, border-color 0.2s, box-shadow 0.25s;
}
.ffs-btn svg { display: block; flex-shrink: 0; width: 18px; height: 18px; }
.ffs-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .ffs-btn:hover { transform: translateY(-2px); background: rgba(255,255,255,0.1); text-decoration: none; }
  /* Each brand glows in its own colours: TikTok's cyan + red, YouTube's red. */
  .ffs-tt:hover { border-color: rgba(255,255,255,0.28); box-shadow: -4px 6px 22px -8px rgba(37,244,238,0.65), 4px 6px 22px -8px rgba(254,44,85,0.65); }
  .ffs-yt:hover { border-color: rgba(255,60,60,0.55); box-shadow: 0 6px 22px -6px rgba(255,0,0,0.55); }
}
@media (hover: none) {
  .ffs-btn:active { transform: scale(0.95); background: rgba(255,255,255,0.12); transition-duration: 0.06s; }
}

/* ── Strip ───────────────────────────────────────────────────────────────── */
.ffs {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 12px;
  box-sizing: border-box; margin: 0;
}
.ffs-label { font-size: 13.5px; font-weight: 500; color: rgba(255,255,255,0.62); }
.ffs-bot { display: none; width: 34px; height: 58px; object-fit: contain; object-position: center bottom; }
.ffs--hero { width: 100%; margin-top: 18px; }
.ffs--feed { display: none; }

/* Phones: a small card — the mascot, then the label over the two buttons. */
@media (max-width: 768px) {
  .ffs {
    display: grid; grid-template-columns: 34px auto; grid-template-areas: "bot label" "bot links";
    justify-content: start; align-items: center; gap: 6px 12px;
  }
  .ffs--desk { display: none; }      /* a strip that has a phone-placed twin (Classic's hero) */
  .ffs-bot { display: block; grid-area: bot; }
  .ffs-label { grid-area: label; font-size: 13px; text-align: start; }   /* Cinematic's hero centres its text */
  .ffs-links { grid-area: links; }
  .ffs-btn { height: 34px; font-size: 13px; padding: 0 12px 0 10px; }
  .ffs-btn svg { width: 17px; height: 17px; }
  .ffs--hero { width: max-content; max-width: 100%; margin: 16px auto 0; }
  .ffs--feed {
    margin: 2px 18px 22px; padding: 12px 14px;
    border: 1px solid rgba(255,255,255,0.07); border-radius: 16px;
    background: linear-gradient(135deg, rgba(139,92,246,0.10), rgba(6,182,212,0.06));
  }
}

/* ── Corner mascot (computers) ───────────────────────────────────────────── */
.ffm { display: none; }
@media (min-width: 1024px) and (hover: hover) {
  .ffm {
    --ffm-h: 132px;      /* the mascot's height (ff-bot.webp is 186×320: 77px wide here) */
    --ffm-peek: 70px;    /* how much shows while peeking: the head and its 3D glasses */
    display: block; position: fixed; right: 28px; bottom: 0; z-index: 60;
    transform: translateY(calc(var(--ffm-h) + 24px)); visibility: hidden;
    transition: transform 0.55s cubic-bezier(.22,1,.36,1), visibility 0s linear 0.55s;
  }
  .ffm.is-in {
    transform: translateY(calc(var(--ffm-h) - var(--ffm-peek))); visibility: visible;
    transition: transform 0.55s cubic-bezier(.22,1,.36,1), visibility 0s;
  }
  .ffm.is-in:hover, .ffm.is-in.is-open, .ffm.is-in:focus-within { transform: none; }
  .ffm-bot {
    display: block; height: var(--ffm-h); margin: 0; padding: 0; border: 0; background: none;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  .ffm-bot img {
    display: block; height: 100%; width: auto; max-width: 150px; object-fit: contain;
    filter: drop-shadow(0 10px 24px rgba(0,0,0,0.55));
    animation: ffm-bob 3.4s ease-in-out infinite;
  }
  .ffm-bot:focus-visible { outline: 2px solid #fff; outline-offset: 4px; border-radius: 12px; }
  @keyframes ffm-bob { 50% { transform: translateY(-5px) rotate(-1.5deg); } }

  /* Speech bubble, above the mascot; it overlaps the mascot's top a little so
     moving the pointer from one to the other never drops the hover. */
  .ffm-bubble {
    position: absolute; right: 0; bottom: calc(100% - 10px); width: 236px; box-sizing: border-box;
    padding: 14px 14px 14px; border-radius: 18px;
    background: rgba(18,18,22,0.94); border: 1px solid rgba(255,255,255,0.1);
    box-shadow: 0 20px 50px -12px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.06);
    -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
    opacity: 0; transform: translateY(8px) scale(0.96); transform-origin: 85% 100%;
    visibility: hidden; pointer-events: none;
    transition: opacity 0.2s, transform 0.3s cubic-bezier(.22,1,.36,1), visibility 0s linear 0.3s;
  }
  .ffm-bubble::after {   /* tail, pointing down at the mascot */
    content: ""; position: absolute; right: 31px; bottom: -7px; width: 14px; height: 14px;   /* over the mascot's head */
    background: rgb(18,18,22); border: solid rgba(255,255,255,0.1); border-width: 0 1px 1px 0;
    transform: rotate(45deg);
  }
  .ffm.is-in:hover .ffm-bubble, .ffm.is-in.is-open .ffm-bubble, .ffm.is-in:focus-within .ffm-bubble {
    opacity: 1; transform: none; visibility: visible; pointer-events: auto;
    transition: opacity 0.2s, transform 0.3s cubic-bezier(.22,1,.36,1), visibility 0s;
  }
  .ffm-bubble .ffs-label { display: block; margin: 0 30px 12px 2px; font-size: 13.5px; font-weight: 600; color: #fff; }
  .ffm-bubble .ffs-links { flex-direction: column; align-items: stretch; }
  .ffm-bubble .ffs-btn { height: 40px; }
  .ffm-close {
    position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; margin: 0; padding: 0;
    display: grid; place-items: center; border: 0; border-radius: 999px;
    background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.7); cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
  }
  .ffm-close:hover { background: rgba(255,255,255,0.14); color: #fff; }
  .ffm-close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
  .ffm.is-gone { transform: translateY(calc(var(--ffm-h) + 24px)) !important; }
  .ffm.is-gone .ffm-bubble { opacity: 0 !important; visibility: hidden !important; }

  /* Easter egg (five quick clicks, social.js): all the way up, the bubble out of
     the way, then a crouch, a jump with a full spin and a squashed landing. */
  .ffm.is-in.is-egg { transform: none; }
  .ffm.is-egg .ffm-bubble { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important; }
  .ffm.is-egg .ffm-bot { animation: ffm-egg 1.1s cubic-bezier(.33,.9,.45,1) both; transform-origin: 50% 60%; }
  @keyframes ffm-egg {
    0%   { transform: none; }
    14%  { transform: translateY(4%) scale(1.07, 0.9); }
    50%  { transform: translateY(-40%) rotate(220deg); }
    70%  { transform: translateY(-26%) rotate(360deg); }
    86%  { transform: translateY(1%) rotate(360deg) scale(1.06, 0.92); }
    100% { transform: rotate(360deg); }
  }
}

/* ── Welcome tip (FFBot.welcome in social.js): a first visit only ─────────
   Placed by script in page coordinates, just under the AI search, its tail
   (--ffw-tail from the tip's left edge) at the field's start. On phones that's
   over Classic's sticky Movies / TV / Filters bar: same z-index (99), later in
   the document, so the tip is on top — under Classic's header (100). It goes as
   soon as the page scrolls, so no sticky bar ever slides under it. */
.ffw {
  position: absolute; z-index: 99; box-sizing: border-box; width: min(330px, calc(100vw - 32px));
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 10px 12px;
  padding-block: 14px; padding-inline: 12px 40px;
  border-radius: 18px; background: rgba(18,18,22,0.96); border: 1px solid rgba(255,255,255,0.1);
  box-shadow: 0 20px 50px -12px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.06);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  color: #fff; text-align: start;
  opacity: 0; transform: translateY(6px) scale(0.97); transform-origin: var(--ffw-tail, 40px) 0;
  transition: opacity 0.25s, transform 0.35s cubic-bezier(.22,1,.36,1);
}
.ffw.is-in { opacity: 1; transform: none; }
.ffw.is-out { opacity: 0; transform: translateY(4px); transition-duration: 0.2s; }
.ffw::before {   /* tail, pointing up at the search */
  content: ""; position: absolute; top: -7px; left: calc(var(--ffw-tail, 40px) - 7px); width: 14px; height: 14px;
  background: rgb(18,18,22); border: solid rgba(255,255,255,0.1); border-width: 1px 0 0 1px;
  transform: rotate(45deg);
}
.ffw-bot { grid-row: span 2; height: 56px; align-self: end; }
.ffw-text { margin: 0; font-size: 13.5px; font-weight: 500; line-height: 1.4; color: rgba(255,255,255,0.92); }
.ffw-try {
  justify-self: start; height: 32px; margin: 0; padding: 0 14px; border: 0; border-radius: 999px;
  background: linear-gradient(135deg, #8b5cf6, #6366f1); color: #fff;
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  transition: filter 0.2s, transform 0.2s;
}
.ffw-try:hover { filter: brightness(1.12); transform: translateY(-1px); }
.ffw-close {
  position: absolute; top: 8px; inset-inline-end: 8px; width: 28px; height: 28px; margin: 0; padding: 0;
  display: grid; place-items: center; border: 0; border-radius: 999px;
  background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.7); cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
}
.ffw-close:hover { background: rgba(255,255,255,0.14); color: #fff; }
.ffw-try:focus-visible, .ffw-close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ── Footer band ─────────────────────────────────────────────────────────── */
.ffs-band {
  position: relative; display: flex; align-items: center; justify-content: center; gap: 28px;
  box-sizing: border-box; max-width: 1160px; margin: 48px auto 0; padding: 28px 32px;
  border: 1px solid rgba(255,255,255,0.07); border-radius: 24px; overflow: hidden;
  background:
    radial-gradient(ellipse 60% 120% at 12% 100%, rgba(139,92,246,0.20), transparent 70%),
    radial-gradient(ellipse 50% 120% at 90% 0%, rgba(6,182,212,0.12), transparent 70%),
    rgba(255,255,255,0.02);
}
/* Taller than the band's content box: it rises from the band's bottom edge (overflow: hidden cuts its base). */
.ffs-band-bot { display: block; flex-shrink: 0; height: 180px; width: auto; object-fit: contain; margin: -10px 0 -36px; }
.ffs-band-title { margin: 0 0 14px; font-size: clamp(1.25rem, 2.2vw, 1.6rem); font-weight: 700; line-height: 1.2; letter-spacing: -0.02em; color: #fff; }
.ffs-band .ffs-btn { height: 46px; padding: 0 20px 0 16px; gap: 10px; font-size: 15px; }
.ffs-band .ffs-btn svg { width: 22px; height: 22px; }
@media (max-width: 768px) {
  .ffs-band { flex-direction: column; gap: 6px; margin: 36px 14px 0; padding: 22px 18px 24px; text-align: center; }
  .ffs-band-bot { height: 140px; margin: -6px 0 0; }
  .ffs-band .ffs-links { justify-content: center; }
}

/* ── Moods: the mascot reacts to the AI (FFBot in social.js) ───────────────
   A host [data-ffb] holds the standing pose (<img class="ffb-idle">, whose
   height sets the size) and, mounted by script, one layer per mood. The
   layers are frames of ONE sprite, so a switch never waits on a download;
   it is fetched on first intent (a search field focused, or the first mood),
   which adds html.ffb-on. Moods cross-fade in place on a box that never
   changes size, so nothing around a mascot moves.
     think → idea → success → idle      a search that found something
     confused (stays)                   no results, or an error
   Sprite: ff-bot-moods.webp, 4 frames of 256×320 in a row (think, idea,
   success, confused), cut from raw/ff-bot-emotions.jpg (tools/mascot/cut.sh). Each robot
   stands on the frame's bottom edge, centred on its helmet, helmet-to-feet
   238 of 320 — the same size as the idle pose inside a box 1/0.85 its
   height, so a cross-fade lines up; the props (?, bulb, sparks) use the room
   above and beside it. Its ?v= below is the sprite's own hash; changing it
   changes this file, so bump ?v= of social.* in both pages as usual. */
.ffb { position: relative; display: block; flex-shrink: 0; }
.ffb-idle { display: block; height: 100%; width: auto; transition: opacity 0.28s ease; }
.ffb-m {
  position: absolute; bottom: 0; left: 50%; translate: -50% 0;
  height: calc(100% / 0.85); aspect-ratio: 256 / 320;          /* frame box: props (?, bulb, sparks) overflow the host */
  opacity: 0; pointer-events: none; transform-origin: 50% 100%;
  background: no-repeat 0 0 / 400% 100%;
  transition: opacity 0.28s ease;
}
html.ffb-on .ffb-m, html.ffb-on .ffh-bot::before, html.ffb-on .ffh-bot::after, html.ffb-on .ffp-bot { background-image: url("/assets/ff-bot-moods.webp?v=1b892b12"); }
.ffb-m[data-m="think"]    { background-position: 0 0; }
.ffb-m[data-m="idea"]     { background-position: 33.3333% 0; }
.ffb-m[data-m="success"]  { background-position: 66.6667% 0; }
.ffb-m[data-m="confused"] { background-position: 100% 0; }
.ffb[data-mood]:not([data-mood="idle"]) > .ffb-idle { opacity: 0; }
.ffb[data-mood="think"]    > [data-m="think"]    { opacity: 1; animation: ffb-think 1.8s ease-in-out infinite; }
.ffb[data-mood="idea"]     > [data-m="idea"]     { opacity: 1; animation: ffb-pop 0.45s cubic-bezier(.34,1.56,.64,1) both, ffb-glow 1.4s ease-in-out 0.45s infinite; }
.ffb[data-mood="success"]  > [data-m="success"]  { opacity: 1; animation: ffb-bounce 0.7s cubic-bezier(.22,1,.36,1) both, ffb-twinkle 1.2s ease-in-out 0.7s infinite; }
.ffb[data-mood="confused"] > [data-m="confused"] { opacity: 1; animation: ffb-shrug 3.2s ease-in-out 0.15s infinite; }
/* Thinking: a gentle rock on the feet. Idea: a pop, then the bulb glows.
   Success: a bounce-in, then sparkle. Confused: a slow shrug-and-dip, then a pause. */
@keyframes ffb-think   { 0%, 100% { transform: rotate(-3deg); } 50% { transform: rotate(3deg) translateY(-3%); } }
@keyframes ffb-pop     { 0% { transform: scale(0.86); } 55% { transform: scale(1.07); } 100% { transform: none; } }
@keyframes ffb-glow    { 50% { filter: brightness(1.12); } }   /* the bulb's own glow is in the art */
@keyframes ffb-bounce  { 0% { transform: translateY(14%) scale(0.9); } 45% { transform: translateY(-9%) scale(1.04); } 70% { transform: translateY(2%) scale(0.99); } 100% { transform: none; } }
@keyframes ffb-twinkle { 50% { filter: brightness(1.16) saturate(1.2); } }
@keyframes ffb-shrug   { 0%, 60%, 100% { transform: none; } 18% { transform: translateY(3%) rotate(-4deg); } 36% { transform: translateY(1%) rotate(3deg); } }

/* Sizes per spot. The corner's host is its button (.ffm-bot, 132px). */
.ffb--panel { height: 56px; }             /* Classic: the AI results panel's header */
.ffb--empty { height: 120px; }            /* Classic: the panel's "nothing found" screen (was 🍿) */
.ffb--head  { height: 60px; }             /* Cinematic: beside the results heading */
@media (max-width: 768px) {
  .ffb--panel { height: 46px; }
  .ffb--head  { height: 48px; }
}
/* The corner mascot shows more of itself while it has something to say. */
@media (min-width: 1024px) and (hover: hover) {
  .ffm-bot.ffb { position: relative; }
  .ffm.is-in:where([data-mood]:not([data-mood="idle"])) { transform: translateY(calc(var(--ffm-h) - 104px)); }
  .ffm-bot[data-mood]:not([data-mood="idle"]) > .ffb-idle { animation: none; }
}

/* ── Hero mascot (Classic, #ffh): beside the search, computers ≥1200px ─────
   Stands in the gutter beside the 820px search bar (left; right in Arabic),
   its feet level with the vibe chips' bottom edge (40px under the search
   row), so it never covers the bar, its menus or the headline; absolute in
   .hero-search-anchor, so it pushes nothing. The idea pose with its bulb cut
   off (::before); the bulb is ::after. It fades in once the sprite is in
   (.is-ready, social.js), then bobs. Hover, focus, and its one-off hello
   (.is-hi): it waves and its bubble shows, centred over its head, where the
   bulb would be. The bubble stays inside the gutter column and under the
   header even in two lines, so it can't reach the headline in any language
   (Spanish starts 50px from the bar's edge at 1200px). A first visit's
   welcome tip: it waves with its bulb lit for the tip, which drops its own
   little mascot. Below 1200px the gutter is too narrow for it. */
.ffh { display: none; }
@media (min-width: 1200px) and (hover: hover) {
  .hero-search-anchor { position: relative; }
  .ffh {
    --ffh-h: 152px;   /* the frame (122×152); the robot is 113px of it */
    display: block; position: absolute; bottom: -40px; inset-inline-end: calc(50% + 418px);
    width: calc(var(--ffh-h) * 0.8); height: var(--ffh-h);
    margin: 0; padding: 0; border: 0; border-radius: 14px; background: none;
    color: inherit; font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent;
    opacity: 0; visibility: hidden; transform: translateY(10px) scale(0.94); transform-origin: 50% 100%;
    transition: opacity 0.5s ease, transform 0.6s cubic-bezier(.22,1,.36,1), visibility 0s linear 0.6s;
  }
  .ffh.is-ready {
    opacity: 1; visibility: visible; transform: none;
    transition: opacity 0.5s ease, transform 0.6s cubic-bezier(.22,1,.36,1), visibility 0s;
  }
  .ffh:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
  .ffh-bot {
    position: absolute; inset: 0; transform-origin: 50% 100%;
    filter: drop-shadow(0 10px 22px rgba(0,0,0,0.5));
    animation: ffh-bob 3.6s ease-in-out infinite;
  }
  .ffh-bot::before, .ffh-bot::after {
    content: ""; position: absolute; inset: 0;
    background: no-repeat 33.3333% 0 / 400% 100%;    /* the idea frame */
  }
  .ffh-bot::before { clip-path: inset(24% 0 0 0); }  /* the robot: rows 77–320 */
  .ffh-bot::after {                                  /* its bulb: rows 0–76 */
    clip-path: inset(0 0 76% 0);
    opacity: 0; transform: translateY(6px) scale(0.6); transform-origin: 50% 18%;
    transition: opacity 0.25s ease, transform 0.4s cubic-bezier(.34,1.56,.64,1);
  }
  .ffh-bubble {   /* its tail's tip at 24% of the frame: the helmet's antenna */
    position: absolute; bottom: 78%; left: 50%; translate: -50% 0; z-index: 1;
    width: max-content; max-width: 204px; box-sizing: border-box; padding: 9px 14px;   /* English in one line */
    border-radius: 16px;
    background: rgba(18,18,22,0.94); border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 16px 40px -12px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.06);
    font-size: 13px; font-weight: 600; line-height: 1.35; color: #fff; white-space: normal;
    text-align: center; text-wrap: balance;
    opacity: 0; transform: translateY(6px) scale(0.92); transform-origin: 50% 100%; pointer-events: none;
    transition: opacity 0.3s ease, transform 0.35s cubic-bezier(.22,1,.36,1);
  }
  .ffh-bubble::after {   /* tail, pointing down at the helmet */
    content: ""; position: absolute; bottom: -6px; left: calc(50% - 6px); width: 11px; height: 11px;
    background: rgb(18,18,22); border: solid rgba(255,255,255,0.12); border-width: 0 1px 1px 0;
    transform: rotate(45deg);
  }
  .ffh.is-ready:is(:hover, :focus-visible, .is-hi) .ffh-bubble { opacity: 1; transform: none; pointer-events: auto; }
  .ffh.is-ready:is(:hover, :focus-visible, .is-hi) .ffh-bot,
  html:has(.ffw.is-in) .ffh.is-ready .ffh-bot { animation: ffh-wave 2.4s ease-in-out infinite; }
  html:has(.ffw.is-in) .ffh.is-ready .ffh-bot::after { opacity: 1; transform: none; animation: ffb-glow 1.4s ease-in-out 0.4s infinite; }
  html:has(.ffh.is-ready) .ffw { grid-template-columns: 1fr; }
  html:has(.ffh.is-ready) .ffw-bot { display: none; }
  @keyframes ffh-bob  { 50% { transform: translateY(-4px); } }
  @keyframes ffh-wave {   /* a rock on its feet, then a rest */
    0%, 58%, 100% { transform: none; }
    10% { transform: rotate(-5deg); }
    22% { transform: rotate(4deg); }
    34% { transform: rotate(-3deg); }
    46% { transform: rotate(1.5deg); }
  }
}

/* ── Peeking mascot (Classic, .ffp): over "Your Taste DNA", computers ──────
   Inside the button (hovering it lights the button; a click opens Taste DNA),
   absolute above it in a box that clips at the button's top edge: the success
   pose rises from behind the button and shows its head and raised hands
   (--ffp-peek), a little more on hover. It rises the first time the button
   is on screen (.is-in, social.js) and hops twice (.is-hop). The row's card
   meets the sticky Movies / TV bar (z-index 99), so at rest the mascot is
   drawn over that bar's empty right end (same z-index, later in the page);
   once the row starts sliding under the bar it ducks (.is-ducked: z-index 98,
   under the bar at once, and it sinks back behind the button). */
.ffp { display: none; }
@media (min-width: 1024px) and (hover: hover) {
  .dna-trigger { position: relative; }
  .ffp {
    --ffp-h: 120px;    /* the frame (96×120) */
    --ffp-peek: 78px;  /* how much shows over the button: rows 0–205 of 320, antenna to popcorn rim */
    display: block; position: absolute; left: 50%; bottom: calc(100% + 1px); z-index: 99;   /* + the button's border: cut at its outer edge */
    width: calc(var(--ffp-h) * 0.8); height: var(--ffp-h); translate: -50% 0;
    overflow: hidden; pointer-events: none;
  }
  .ffp.is-ducked { z-index: 98; }
  .ffp-bot {
    position: absolute; inset: 0; pointer-events: auto; cursor: pointer;
    background: no-repeat 66.6667% 0 / 400% 100%;    /* the success frame */
    translate: 0 100%;
    transition: translate 0.55s cubic-bezier(.34,1.5,.64,1);
  }
  .ffp.is-in .ffp-bot { translate: 0 calc(var(--ffp-h) - var(--ffp-peek)); }
  .dna-trigger:hover .ffp.is-in .ffp-bot { translate: 0 calc(var(--ffp-h) - var(--ffp-peek) - 14px); }
  .ffp.is-in.is-ducked .ffp-bot { translate: 0 100%; transition: translate 0.3s cubic-bezier(.4,0,1,1); }
  .ffp.is-hop .ffp-bot { animation: ffp-hop 0.9s ease-out 0.5s; }
  @keyframes ffp-hop {
    0%, 44%, 80%, 100% { transform: none; }
    22% { transform: translateY(-8px); }
    62% { transform: translateY(-4px); }
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Classic's slots: fades only (no bob, wave, pop, rise or hops). */
  .ffh, .ffh.is-ready, .ffh-bubble, .ffh-bot::after { transform: none !important; transition: opacity 0.3s ease, visibility 0s !important; }
  .ffh-bot, .ffh-bot::after, .ffp-bot { animation: none !important; }
  .ffp-bot { transition: opacity 0.3s ease !important; }
  .ffp:not(.is-in) .ffp-bot, .ffp.is-ducked .ffp-bot { opacity: 0; }
  .ffm-bot img { animation: none; }
  .ffm, .ffm-bubble, .ffs-btn { transition-duration: 0.01s !important; }
  /* Moods only cross-fade (beats a page's blanket "*" reduced-motion rule by specificity). */
  .ffb-m { animation: none !important; }
  .ffb-m, .ffb-idle { transition-duration: 0.28s !important; }
  /* The easter egg keeps its cheer (a cross-fade) without the spin; the tip only fades. */
  .ffm.is-egg .ffm-bot { animation: none !important; }
  .ffw, .ffw.is-out { transform: none !important; transition: opacity 0.25s !important; }
}
