/* ─── LootStories ─ Instagram-style stories: avatar row → crossfade open →
   cube-fold snap scroller → pull-down dismiss. All classes st- prefixed.
   Fonts inherit from the host page on purpose (surgery-friendly). ─── */

/* ── Trigger row (IG-style: gradient rings, centered over the feed) ── */
.st-shell { position: relative; }

.st-row {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding: 14px 16px 10px;
  scrollbar-width: none;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain; /* row swipe must never become a Safari back-swipe */
  -webkit-overflow-scrolling: touch;
}
.st-row::-webkit-scrollbar { display: none; }

/* unconditional: Joe's desktop browser drew its focus square even for
   plain mouse taps, straight through :focus-visible filtering */
.st-ava:focus, .st-x:focus, .st-arrow:focus, .st-rnav:focus { outline: none; }

.st-ava {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  font: inherit;
}
/* the IG story ring: gradient circle, white gap, photo inside */
.st-ava-ring {
  width: 66px;
  height: 66px;
  border-radius: 50%;
  padding: 2.5px;
  /* two layers: the gradient lives ONLY in the padding annulus — painted
     under the whole circle it bled through the photo's antialiased edge as
     a faint tinted inner ring on light avatars (the apple logo) */
  background: linear-gradient(#fff, #fff) content-box,
              linear-gradient(45deg, #f09433, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888) border-box;
  transition: transform .15s ease;
}
.st-ava:active .st-ava-ring { transform: scale(.94); }
.st-ava-ring img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 2.5px solid #fff;
  object-fit: cover;
  display: block;
  pointer-events: none;
  /* white, not #eee: the gray placeholder ghosted through the antialiased
     edge as a faint inner ring on light avatars (the apple logo) */
  background: #fff;
}
.st-ava-name {
  font-size: 12px;
  font-weight: 500;
  color: #111;
  max-width: 74px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── the YOU slot — glowing first circle, wired to the Make Yours flow.
   COMPOSITOR-ONLY animation: the ring spins via a transform on a pseudo
   (never repaints), the halo is a static shadow, the name a static gradient.
   The first build animated conic/box-shadow/filter — that repainted the
   fixed header at 60fps and made the whole phone feel heavy. Never go back. ── */
.st-you {
  position: relative;
  isolation: isolate; /* keeps the -1 halos inside this button's stacking */
}
/* the splash Enter button's purple/pink emanation, ported compositor-only:
   two solid discs behind the ring, scale-breathing in counter-phase (the
   Enter original animates box-shadow spread = per-frame paint; scale isn't) */
.st-you::before,
.st-you::after {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;
  width: 66px;
  height: 66px;
  border-radius: 50%;
  left: 50%;
  top: 33px; /* ring center (ring is the button's first child) */
  margin: -33px 0 0 -33px;
  background: var(--st-halo, #ff2d95);
  /* no bottom fade: the glow continues down and pools into the YOU bubble */
  transform: scale(1.16);
  animation: st-you-halo 2.6s ease-in-out infinite;
}
.st-you::before { --st-halo: #ff2d95; }
.st-you::after  { --st-halo: #7b3ff2; animation-delay: 1.3s; }
@keyframes st-you-halo {
  0%, 100% { transform: scale(1.08); }
  50%      { transform: scale(1.32); }
}
.st-you .st-ava-ring {
  position: relative;
  overflow: hidden; /* clips the rotating gradient square to the ring circle */
  background: conic-gradient(#f09433, #ff5a96, #dc2743, #bc1888, #8134af, #7b3ff2, #f09433);
}
.st-you .st-ava-ring::before {
  content: '';
  position: absolute;
  inset: -25%;
  background: conic-gradient(#f09433, #ff5a96, #dc2743, #bc1888, #8134af, #7b3ff2, #f09433);
  animation: st-you-rot 2.8s linear infinite;
}
@keyframes st-you-rot { to { transform: rotate(360deg); } }
.st-you-face {
  position: relative;
  z-index: 1; /* above the ring's rotating gradient pseudo */
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 2.5px solid #fff;
  background: radial-gradient(circle at 32% 26%, #fff 0%, #ffe9f2 48%, #f1e6ff 100%);
  display: grid;
  place-items: center;
  color: #111;
  /* the face is the clipper: iOS won't reliably round-clip a <video> layer
     on the video itself, so clip here and force a composited clip */
  overflow: hidden;
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
}
.st-you-face img,
.st-you-face video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.st-you-face svg { width: 24px; height: 24px; display: block; }
/* the name is a filled gradient bubble the halo pours into — white ink */
.st-you .st-ava-name {
  font-weight: 800;
  color: #fff;
  background: linear-gradient(45deg, #ff5a96, #ff2d95 45%, #7b3ff2);
  padding: 2px 10px 3px;
  border-radius: 999px;
  margin-top: -3px; /* tuck the bubble up into the glow so they read connected */
  overflow: visible;
}
@media (prefers-reduced-motion: reduce) {
  .st-you .st-ava-ring::before, .st-you::before, .st-you::after { animation: none; }
}

/* row paging chevrons (desktop only) */
.st-rnav {
  position: absolute;
  z-index: 2;
  top: 47px; /* center of the ring: row padding-top + ring/2 */
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 0;
  background: #fff;
  box-shadow: 0 1px 6px rgba(17, 17, 17, .28);
  color: #111;
  cursor: pointer;
  display: none;
  place-items: center;
  padding: 0;
}
.st-rnav svg { width: 14px; height: 14px; display: block; }
.st-rprev { left: 2px; }
.st-rnext { right: 2px; }

/* desktop: exactly 6 rings visible, centered over the feed column */
@media (hover: hover) and (min-width: 768px) {
  .st-shell { max-width: 600px; margin: 0 auto; } /* 6×78 + 5×20 + 2×16 padding */
  .st-row { gap: 20px; padding: 16px 16px 12px; } /* 16px sides: the YOU halo breathes ~15px past the ring */
  .st-ava-ring { width: 78px; height: 78px; padding: 3px; }
  .st-ava-ring img, .st-you-face { border-width: 3px; }
  .st-you::before, .st-you::after { width: 78px; height: 78px; top: 39px; margin: -39px 0 0 -39px; }
  .st-ava-name { max-width: 84px; }
  .st-rnav { top: 55px; }
  .st-rnav[data-on] { display: grid; }
}

/* ── Overlay root ── */
.st-root {
  position: fixed;
  inset: 0;
  /* above all homepage chrome (≤100050), below splash/rotate-lock (≥999999) */
  z-index: 200000;
  display: none;
  /* one card size everywhere: 9:16, 82% of the small viewport height,
     capped so it never exceeds ~92vw on narrow screens */
  --st-h: min(82svh, 163vw);
  --st-w: calc(var(--st-h) * 9 / 16);
}
.st-root.st-on { display: block; }
html.st-lock, html.st-lock body { overflow: hidden; }

/* light veil — page stays faintly readable behind it, like the reference */
.st-veil {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, .93);
  opacity: 0;
  transition: opacity .38s ease;
}
.st-root.st-in .st-veil { opacity: 1; }

/* .st-tilt owns the cube-fold transform; the black .st-panel lives INSIDE it,
   so the black rotates with the card and can never escape its silhouette.
   Its squarer corners are what fills the crevices the cards' rounded corners
   open at the seam. Opacity is scroll-driven: invisible at rest. */
.st-tilt {
  position: relative;
  width: var(--st-w);
  height: var(--st-h);
  will-change: transform;
}
.st-panel {
  position: absolute;
  inset: 0;
  /* fully square: any radius here reopens a white pinhole at the seam */
  background: #000;
  opacity: 0;
  pointer-events: none;
}

/* ── Snap scroller ── */
.st-scroller {
  position: absolute;
  inset: 0;
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* slides are CARD-width; this padding centers the first/last card,
     and slide N settles exactly at scrollLeft = N * cardWidth */
  padding-inline: calc(50% - var(--st-w) / 2);
  /* pan-x: browser owns horizontal, JS owns vertical (pull-down dismiss).
     contain: no rubber-band leak, no Safari back/forward, no pull-to-refresh. */
  touch-action: pan-x;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.st-scroller::-webkit-scrollbar { display: none; }

/* Slides are exactly card-width so adjacent cards BUTT at the fold seam
   (the cube illusion). At rest, neighbors sit at 90° — edge-on, invisible. */
.st-slide {
  flex: none;
  width: var(--st-w);
  height: 100%;
  scroll-snap-align: center;
  scroll-snap-stop: always; /* one page per fling, like IG */
  display: grid;
  place-items: center;
  perspective: 1300px; /* the cube fold's vanishing point, per slide */
}

.st-card {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  overflow: hidden;
  background: #111;
}
/* The cube fold itself is attached from JS as a compositor-driven
   ViewTimeline animation (keyframe offsets depend on viewport/card ratio),
   with a scroll-event fallback where ViewTimeline is unsupported. */

/* FLIP flight (open/close): the real card goes fixed and flies between the
   avatar circle and its resting slot. */
.st-card.st-flying {
  position: fixed;
  z-index: 6;
  margin: 0;
}

/* ── Card layers ── */
/* segment layers: one per clip, stacked; the active one shows (instant cut,
   IG-style). Poster backstop under each video: a hiccup shows a frame, never black. */
.st-seg {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}
.st-seg.on { opacity: 1; z-index: 2; }
.st-back, .st-vid, .st-fade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.st-vid { z-index: 2; } /* video above its own poster backstop */
.st-fade { z-index: 5; display: none; } /* crossfade layer used only during flights */

.st-shade {
  position: absolute;
  z-index: 3;
  left: 0; right: 0; top: 0;
  height: 96px;
  background: linear-gradient(rgba(0, 0, 0, .42), rgba(0, 0, 0, 0));
  pointer-events: none;
}

.st-ticks {
  position: absolute;
  z-index: 4;
  top: 10px;
  left: 12px;
  right: 12px;
  display: flex;
  gap: 4px;
  pointer-events: none;
}
.st-tick {
  position: relative;
  flex: 1;
  height: 2.5px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .38);
  overflow: hidden;
}
/* IG progress: past ticks full, the current one fills across its clip */
.st-tick .st-fill {
  position: absolute;
  inset: 0;
  width: 0%;
  background: #fff;
  transition: width .25s linear; /* smooths the ~4Hz timeupdate steps */
}
.st-tick.on .st-fill { width: 100%; transition: none; }

.st-head {
  position: absolute;
  z-index: 4;
  top: 21px;
  left: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: #fff;
  pointer-events: none;
}
.st-head img {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  object-fit: cover;
}
.st-head b { font-size: 13px; font-weight: 700; }
.st-head span { font-size: 13px; color: rgba(255, 255, 255, .85); }

.st-x {
  position: absolute;
  z-index: 4;
  top: 13px;
  right: 6px;
  width: 42px;
  height: 42px;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.st-x svg { width: 20px; height: 20px; display: block; }

/* desktop pause/play — IG desktop puts it in the card's top right;
   mobile keeps press-and-hold, so this only exists on fine pointers */
.st-pp {
  position: absolute;
  z-index: 4;
  top: 13px;
  right: 44px;
  width: 42px;
  height: 42px;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  display: none;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.st-pp svg { width: 18px; height: 18px; display: block; }
@media (hover: hover) and (min-width: 768px) {
  .st-root.st-set .st-pp { display: grid; }
}

/* share sits left of the x; on desktop the pause button wedges between */
/* ── IG chrome (Joe's reference, Aug 29): ... then X top right; a bottom bar
   with the Send-message pill, the heart, and the paper plane (the old share
   button, same class, moved down). ── */
.st-menu {
  position: absolute;
  z-index: 4;
  top: 13px;
  right: 44px;
  width: 42px;
  height: 42px;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.st-menu svg { width: 22px; height: 22px; display: block; }
.st-sheet {
  position: absolute;
  z-index: 6;
  top: 58px;
  right: 28px;
  min-width: 168px;
  background: #fff;
  border-radius: 14px;
  padding: 4px 0;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .28);
  display: none;
}
.st-sheet.on { display: block; }
.st-sheet button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 13px 18px;
  font: inherit;
  font-size: 16px;
  color: #111;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.st-sheet .st-danger { color: #e0342b; }
.st-bar {
  position: absolute;
  z-index: 4;
  left: 10px;
  right: 8px;
  bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: flex-end;   /* no message pill — heart + plane keep the right */
  gap: 4px;
  color: #fff;
}
.st-like, .st-share {
  width: 42px;
  height: 42px;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  flex: none;
  -webkit-tap-highlight-color: transparent;
}
.st-like svg { width: 24px; height: 24px; display: block; }
.st-share svg { width: 22px; height: 22px; display: block; }
.st-like.liked { color: #ff3040; }
.st-like.liked svg path { fill: #ff3040; }
/* per-part bar ink: parts whose ground is light flip the bar to dark ink
   (the top chrome keeps its white — the top shade is still behind it) */
.st-card.st-ink-dark .st-bar { color: #1a1a1a; }
.st-card.st-ink-dark .st-like:not(.liked) { color: #1a1a1a; }
.st-card.st-ink-dark .st-share { color: #1a1a1a; }
.st-sheet .st-desk { display: none; }        /* Copy link: desktop only */
/* the page-level X (IG desktop: the close belongs to the viewport, not the card) */
.st-xd {
  position: absolute;
  z-index: 3;
  top: 16px;
  right: 20px;
  width: 48px;
  height: 48px;
  background: none;
  border: 0;
  color: #111;   /* IG's is white on their BLACK page; our veil is LIGHT (settled
                    contract), so the X goes dark like the arrows or it vanishes */
  cursor: pointer;
  display: none;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.st-xd svg { width: 26px; height: 26px; display: block; }
/* ── desktop split (Joe's desktop reference, Aug 29): X leaves the card for
   the viewport corner; the card's top right is play/pause then the dots;
   the bar is the reply pill + heart only — share moves into the sheet ── */
@media (hover: hover) and (min-width: 768px) {
  .st-x { display: none; }
  .st-root.st-set .st-xd { display: grid; }
  .st-menu { right: 6px; }
  .st-root.st-set .st-pp { right: 44px; }
  .st-bar .st-share { display: none; }
  .st-sheet .st-desk { display: block; }
}

/* per-card chrome appears only once the viewer has settled open */
.st-ticks, .st-head, .st-x, .st-pp, .st-menu, .st-bar {
  opacity: 0;
  transition: opacity .25s ease;
}
.st-root.st-set .st-ticks,
.st-root.st-set .st-head,
.st-root.st-set .st-x,
.st-root.st-set .st-menu,
.st-root.st-set .st-bar,
.st-root.st-set .st-pp { opacity: 1; }

/* ── Fixed chrome (outside the fold) ── */
.st-arrow {
  position: absolute;
  z-index: 3;
  top: 50%;
  width: 46px;
  height: 46px;
  margin-top: -23px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, .14);
  box-shadow: 0 2px 10px rgba(17, 17, 17, .10);
  display: grid;
  place-items: center;
  cursor: pointer;
  color: #111;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
}
.st-arrow svg { width: 18px; height: 18px; display: block; }
.st-prev { left: calc(50% - var(--st-w) / 2 - 74px); }
.st-next { right: calc(50% - var(--st-w) / 2 - 74px); }
.st-root.st-set .st-arrow { opacity: 1; pointer-events: auto; }
.st-root.st-set .st-arrow[disabled] { opacity: .3; pointer-events: none; }
@media (hover: none), (max-width: 760px) {
  .st-arrow { display: none; }
}

.st-counter { display: none; }   /* n/x pill removed entirely (Joe, Aug 24) — JS still writes into it, harmlessly */

/* press-and-hold: chrome melts away while paused, IG-style */
.st-root.st-held .st-ticks,
.st-root.st-held .st-head,
.st-root.st-held .st-x,
.st-root.st-held .st-menu,
.st-root.st-held .st-bar,
.st-root.st-held .st-sheet,
.st-root.st-held .st-arrow,
.st-root.st-held .st-counter,
.st-root.st-held .st-pp { opacity: 0; }

/* watched to the end this session: the ring goes quiet (IG seen state) */
.st-ava-ring.st-seen {
  background: linear-gradient(#fff, #fff) content-box,
              linear-gradient(#dbdbdb, #dbdbdb) border-box;
}

/* ══════════ avatarFx: 'leafwind' — the apple mark's leaf turns in the wind ══════════
   Body dead still, leaf tilting slowly on its own. No new image: p-apple.jpg is
   used TWICE with complementary clips. The art has exactly one interior row band
   with no ink in it (rows 331-335 of 960, verified), so leaf and body separate at
   34.7% with a plain horizontal cut — no cutout, no alpha channel.
   The 34.7% is specific to THIS art and does not transfer without re-measuring. */
.lw-face {
  position: relative; z-index: 2; display: block;
  width: 100%; height: 100%; border-radius: 50%; overflow: hidden;
  border: 2.5px solid #fff; background: #fff;
  /* MASK, not just overflow: iOS stops honouring a rounded overflow clip on
     composited children, and a 3D-animated child is composited — without this
     the square image plate escapes the circle on device. */
  -webkit-mask: radial-gradient(closest-side, #000 99%, transparent 100%);
          mask: radial-gradient(closest-side, #000 99%, transparent 100%);
}
.lw { position: absolute; inset: 0; perspective: 230px; }

/* SCOPED on purpose: `.st-ava-ring img` above is (0,1,1) and beats a bare class,
   which would silently restore position:relative and lay these two out stacked in
   normal flow instead of on top of each other. pointer-events:none is inherited
   from that same rule, so the button still takes the tap. */
.st-ava-ring .lw img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
  border: 0; border-radius: 0; background: none;
  /* white multiplies to nothing, so wherever the two clipped layers overlap or
     gap as the leaf turns, only the black registers and there is no seam */
  mix-blend-mode: multiply;
  transform-origin: 50% 50%;
}
.st-ava-ring .lw .lw-body { clip-path: inset(34.7% 0 0 0); }
.st-ava-ring .lw .lw-leaf {
  clip-path: inset(0 0 65.3% 0);
  will-change: transform;
  animation: lw-wind 9s ease-in-out infinite;
}

/* rotateY under perspective, NOT rotate: a flat CSS rotation is affine and reads
   as a propeller. Under a tight perspective the projection is non-affine, so the
   leaf foreshortens toward edge-on and opens out the other side — it turns in air.
   Transform only, no filter, so this stays on the compositor: the row lives inside
   the fixed header and animating filter/box-shadow there is what made the phone
   feel heavy on the first YOU-slot build.
   AMPLITUDE IS THE ONE NUMBER TO TUNE, and it is NOT linear. rotateY spins about
   the vertical centreline and the leaf sits close to that axis, so how far it
   actually travels goes with (1 - cos angle): 22deg = 0.073, 60deg = 0.50. A
   "subtle" 22deg therefore moves the leaf ~7x less than 60, which on a 61px
   avatar is under a pixel and reads as not moving at all. Tried it, Joe saw a
   dead leaf, back to 60. Go DOWN from here in small steps, not big ones. */
@keyframes lw-wind {
  0%, 100% { transform: rotateY(-60deg); }
  50%      { transform: rotateY(60deg); }
}

/* The 78px ring is the DESKTOP size — it lives under this exact query at the top
   of this file, NOT a max-width phone query. Phones keep the base 66px/2.5px, so
   the lens has to scale with the ring here: 230 * 78/66 = 272. */
@media (hover: hover) and (min-width: 768px) {
  .lw-face { border-width: 3px; }
  .lw { perspective: 272px; }
}
@media (prefers-reduced-motion: reduce) {
  .st-ava-ring .lw .lw-leaf { animation: none; }
}

/* ══════════ the + in the YOU slot beats ══════════
   Two quick knocks, then a long rest. 2.6s loop.
   THE REST IS THE POINT: all the motion is in the first 38%, the other 62% is
   dead still. A plus that pulses continuously reads as a loading spinner and the
   eye keeps going back to it; two knocks and silence reads as a heartbeat and
   stops competing with the stories next to it. Second knock is SMALLER than the
   first (1.16 after 1.24) — that asymmetry is what makes it a pulse and not a
   bounce. ease-out, not ease-in-out: each knock hits fast and settles slow.

   TRANSFORM ON THE GLYPH ONLY. Not .st-you-face (would scale its background and
   white border), not a positioned parent (would nudge the box the video avatar
   mounts into), and no opacity/filter anywhere — this row lives inside the fixed
   header and the first YOU build made the phone feel heavy exactly that way.
   The face already has translateZ(0), so the glyph is in a composited layer and
   this is about as cheap as motion gets here. Safe with the recorded avatar too:
   setYou() clears the face's innerHTML, so once someone records, the <svg> is
   gone and this rule matches nothing; setYou(null) writes the plus back and the
   beat returns with it.
   If it needs more presence, raise the two peaks BEFORE shortening the loop —
   a faster loop eats the rest, which is the part keeping it calm. */
.st-you-face svg {
  will-change: transform;
  animation: st-you-beat 2.6s ease-out infinite;
}
@keyframes st-you-beat {
  0%   { transform: scale(1); }
  8%   { transform: scale(1.24); }
  17%  { transform: scale(1.02); }
  26%  { transform: scale(1.16); }
  38%  { transform: scale(1); }
  100% { transform: scale(1); }   /* the long rest */
}
@media (prefers-reduced-motion: reduce) {
  .st-you-face svg { animation: none; }
}

/* ══════════ canvas avatar effects (avatarFx) ══════════
   One frame for both 'chomp' (apple, black ink on white) and 'lucci' (gucci,
   white type on black — .is-dark flips the ground). Renderer is loot-avatarfx.js;
   this is only the circular box it draws inside. Geometry copied from .lw-face,
   which already solved it. */
.fx-face {
  position: relative; z-index: 2; display: block;
  width: 100%; height: 100%; border-radius: 50%; overflow: hidden;
  border: 2.5px solid #fff; background: #fff;
  /* LOAD-BEARING, not belt-and-braces: iOS stops honouring a rounded overflow
     clip on composited children, and an animating canvas is composited, so
     without this the square canvas escapes the circle on device. */
  -webkit-mask: radial-gradient(closest-side, #000 99%, transparent 100%);
          mask: radial-gradient(closest-side, #000 99%, transparent 100%);
}
/* p-gucci.jpg is white type on black, the inverse of the apple */
.fx-face.is-dark { background: #000; }
/* pointer-events MUST be explicit: the <img> avatars inherit none from the
   `.st-ava-ring img` rule, but a <canvas> does not match that selector and would
   otherwise eat the tap that opens the story. */
.fx-face .fx-cv { display: block; width: 100%; height: 100%; pointer-events: none; }

@media (hover: hover) and (min-width: 768px) { .fx-face { border-width: 3px; } }
