/* ---------------------------------------------------------------------------------------------
   Blendable FX

   The site's own look, worn louder. Blendable FX is an effects plugin, so its pages are made of
   effects: every look and starter plays as footage recorded in the engine, every change of page
   is a transition, titles land with a split of colour and headings glitch in. The effects here are
   drawn in plain CSS; the footage is the plugin's own.

   Nothing moves for a reader who has asked for less motion.
   --------------------------------------------------------------------------------------------- */

.product--blendable-fx {
  /* Blendable FX's key look, its keystone's: no colour but the negative's paper, and wherever it glows the light
     splits at the edges into cyan and magenta, as a lens splits it. */
  --accent: #f6f7fb;
  --accent-soft: #8e97a8;
  --accent-glow: rgba(246, 247, 251, 0.10);
  --tone: var(--accent);
  --glow: -2px 0 0 rgba(62, 224, 255, 0.55), 2px 0 0 rgba(255, 61, 174, 0.55), 0 0 0 1px rgba(246, 247, 251, 0.28), 0 14px 38px -12px rgba(246, 247, 251, 0.6);
  --glow-soft: -1.5px 0 0 rgba(62, 224, 255, 0.5), 1.5px 0 0 rgba(255, 61, 174, 0.5), 0 0 22px -5px rgba(246, 247, 251, 0.5);

  /* The impact frame's ink and paper, and the two colours a lens splits white into. */
  --fx-ink: #07080b;
  --fx-paper: #f6f7fb;
  --fx-cyan: #3ee0ff;
  --fx-magenta: #ff3dae;
}

/* A link in paper reads like the text round it, so it carries the split instead: a hairline of cyan and magenta. */
.product--blendable-fx .doc a:not(.anchor):not(.card a),
.product--blendable-fx .lede a {
  text-shadow: -0.7px 0 rgba(62, 224, 255, 0.8), 0.7px 0 rgba(255, 61, 174, 0.8);
}

/* ---- The wordmark ---------------------------------------------------------------------------- */

.product--blendable-fx .nav__product img,
.product--blendable-fx.product .product__logo {
  max-width: 220px;
  filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.12));
}
.product--blendable-fx .nav__product:hover img,
.product--blendable-fx.product:hover .product__logo {
  filter: drop-shadow(-3px 0 0 var(--fx-cyan)) drop-shadow(3px 0 0 var(--fx-magenta));
}

/* ---- Footage ---------------------------------------------------------------------------------- */

/* One effect, large: a viewfinder's corners in the accent and a heads-up display over the picture. */
.fxclip, .fxreel { margin: 28px 0; }
.fxreel { margin: 6px 0 34px; }
.fxclip__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--fx-ink);
  border: 1px solid var(--rule);
  border-radius: 2px;
  overflow: hidden;
}
.fxclip__frame video { display: block; width: 100%; height: 100%; object-fit: cover; }
.fxclip__frame::before,
.fxclip__frame::after {
  content: "";
  position: absolute;
  width: 26px;
  height: 26px;
  pointer-events: none;
  z-index: 2;
  /* A hairline of dark round the paper-white corners, so they hold on a frame struck down to paper too. */
  filter: drop-shadow(0 0 1.5px rgba(0, 0, 0, 0.85));
}
.fxclip__frame::before { top: 10px; left: 10px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); }
.fxclip__frame::after { right: 10px; bottom: 10px; border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent); }
.fxclip figcaption { margin-top: 9px; font-size: 0.92rem; color: var(--ink-faint); }

.fxhud {
  position: absolute;
  inset: 16px 18px auto 44px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 2;
  font: 600 11px/1 var(--chrome);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
  pointer-events: none;
}
.fxhud__kind { padding: 3px 6px 2px; background: var(--accent); color: var(--fx-ink); text-shadow: none; }
.fxhud__kind:empty { display: none; }
/* The name and the timecode sit on dark chips, as a camera's readout does: an impact frame can turn the whole picture
   white, and plain light lettering would go with it. */
.fxhud__name,
.fxhud__tc { padding: 3px 6px 2px; background: rgba(5, 6, 9, 0.62); text-shadow: none; }
.fxhud__name:empty { display: none; }
.fxhud__tc { margin-left: auto; font: 500 11px/1 var(--mono); letter-spacing: 0.06em; }
/* A recording light while it plays. */
.fxhud::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #ff3b30;
  opacity: 0;
}
.is-playing .fxhud::before { opacity: 1; }

/* The reel's name changes with each effect: it strikes in rather than fading. */
.fxreel .fxhud__name { display: inline-block; font-size: 13px; }
.fxreel .fxhud__name.is-new { animation: fx-strike 0.34s steps(1) both; }

/* Effects side by side: stills until hovered or focused, then playing. */
.fxgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
  margin: 18px 0 30px;
  padding: 0;
  list-style: none;
}
.fxcard {
  position: relative;
  margin: 0;
  background: var(--ground-2);
  border: 1px solid var(--rule);
  border-radius: 2px;
  cursor: pointer;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.fxcard:hover, .fxcard:focus-visible { border-color: var(--accent-soft); box-shadow: var(--glow); }
.fxcard__frame { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--fx-ink); }
.fxcard__frame img, .fxcard__frame video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.fxcard__frame video { opacity: 0; transition: opacity 0.12s steps(2); }
.fxcard.is-playing .fxcard__frame video { opacity: 1; }
.fxcard__kind {
  position: absolute;
  top: 7px;
  left: 7px;
  padding: 2px 5px 1px;
  background: rgba(7, 8, 11, 0.72);
  font: 600 9.5px/1.3 var(--chrome);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fx-paper);
}
.fxcard__t { margin: 9px 11px 2px; font: 600 14px/1.3 var(--sans); color: var(--ink-strong); }
.fxcard__s { margin: 0 11px 10px; font-size: 12.5px; line-height: 1.45; color: var(--ink-faint); }
.fxcard:hover .fxcard__t, .fxcard:focus-visible .fxcard__t {
  text-shadow: -1.5px 0 var(--fx-cyan), 1.5px 0 var(--fx-magenta);
}

/* The name of the transition that just played, struck in at the corner as the new page arrives. */
.fx-cutname {
  position: fixed;
  top: 72px;
  right: 18px;
  z-index: 60;
  padding: 6px 10px 5px;
  background: var(--fx-ink);
  border: 1px solid var(--accent);
  font: 600 11px/1 var(--chrome);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fx-paper);
  pointer-events: none;
}
.fx-cutname b { color: var(--accent); font-weight: 600; }

@media (prefers-reduced-motion: no-preference) {
  /* ---- Arrivals ------------------------------------------------------------------------------ */

  /* A page's title lands like an impact: its colours split apart and snap back together. */
  .product--blendable-fx .page-head h1 { animation: fx-land 0.6s cubic-bezier(0.2, 0.9, 0.2, 1) both; }

  /* Headings glitch in, once, as they come into view (fx.js marks them). */
  .product--blendable-fx .doc h2.fx-in,
  .product--blendable-fx .doc h3.fx-in { animation: fx-glitch-in 0.42s steps(1) both; }

  .product--blendable-fx .nav__product:hover img,
  .product--blendable-fx.product:hover .product__logo { animation: fx-jolt 0.3s steps(1) 1; }

  .fx-cutname { animation: fx-cutname 1.5s steps(1) both; }

  /* A hovered card pops: a burst of lines out from behind it for a moment. */
  .fxcard::before {
    content: "";
    position: absolute;
    inset: -18px;
    z-index: -1;
    background: repeating-conic-gradient(from 3deg, var(--fx-paper) 0 0.9deg, transparent 0.9deg 7deg);
    -webkit-mask: radial-gradient(closest-side, transparent 62%, #000 70%, transparent 100%);
    mask: radial-gradient(closest-side, transparent 62%, #000 70%, transparent 100%);
    opacity: 0;
    pointer-events: none;
  }
  .fxcard:hover::before, .fxcard:focus-visible::before { animation: fx-pop 0.36s ease-out 1; }
}

@keyframes fx-land {
  0% { opacity: 0; transform: translateX(-6px) skewX(-8deg); text-shadow: -14px 0 var(--fx-cyan), 14px 0 var(--fx-magenta); }
  18% { opacity: 1; transform: translateX(3px) skewX(4deg); text-shadow: 8px 0 var(--fx-cyan), -8px 0 var(--fx-magenta); }
  40% { transform: none; text-shadow: -3px 0 var(--fx-cyan), 3px 0 var(--fx-magenta); }
  100% { transform: none; text-shadow: 0 0 transparent, 0 0 transparent; }
}
@keyframes fx-glitch-in {
  0% { clip-path: inset(0 0 62% 0); transform: translateX(-9px); text-shadow: 3px 0 var(--fx-magenta); }
  20% { clip-path: inset(48% 0 12% 0); transform: translateX(7px); text-shadow: -3px 0 var(--fx-cyan); }
  40% { clip-path: inset(12% 0 40% 0); transform: translateX(-3px); text-shadow: 2px 0 var(--fx-magenta); }
  60% { clip-path: inset(0 0 0 0); transform: translateX(2px); text-shadow: -1px 0 var(--fx-cyan); }
  80%, 100% { clip-path: none; transform: none; text-shadow: none; }
}
@keyframes fx-jolt {
  0% { transform: translate(-3px, 1px); }
  25% { transform: translate(3px, -2px); }
  50% { transform: translate(-1px, 2px); }
  75%, 100% { transform: none; }
}
@keyframes fx-strike {
  0% { transform: translateX(-6px); color: var(--fx-ink); background: var(--fx-paper); }
  45% { transform: translateX(3px); color: var(--fx-paper); background: transparent; }
  100% { transform: none; }
}
@keyframes fx-pop {
  0% { opacity: 0; transform: scale(0.86); }
  35% { opacity: 0.55; }
  100% { opacity: 0; transform: scale(1.12); }
}
@keyframes fx-cutname {
  0% { opacity: 0; transform: translateX(14px); }
  8% { opacity: 1; transform: translateX(-4px); }
  14% { transform: none; }
  82% { opacity: 1; }
  100% { opacity: 0; }
}

/* ---- Changing page --------------------------------------------------------------------------- */

/* The old page is frozen as the plugin freezes the old shot, and the new page is revealed through a
   look: a shape opening over it, or both pages carried through a blend. fx-cut.js picks the look. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }

@property --fx-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@property --fx-b { syntax: '<length>'; inherits: false; initial-value: 0px; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.7, 0, 0.25, 1);
}

/* Covers: the old page stays still and the new one opens over it. */
html:active-view-transition-type(fx-iris, fx-star, fx-bars, fx-wipe, fx-diamond, fx-blinds, fx-clock, fx-glitch, fx-ink)::view-transition-old(root) {
  animation: none;
}
html:active-view-transition-type(fx-iris)::view-transition-new(root) { animation-name: fx-iris; }
html:active-view-transition-type(fx-star)::view-transition-new(root) {
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M50 0 61.8 38.2 100 38.2 69.1 61.8 80.9 100 50 76.4 19.1 100 30.9 61.8 0 38.2 38.2 38.2Z'/%3E%3C/svg%3E") var(--fx-x, 50%) var(--fx-y, 50%) / 0 0 no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M50 0 61.8 38.2 100 38.2 69.1 61.8 80.9 100 50 76.4 19.1 100 30.9 61.8 0 38.2 38.2 38.2Z'/%3E%3C/svg%3E") var(--fx-x, 50%) var(--fx-y, 50%) / 0 0 no-repeat;
  animation-name: fx-star;
}
html:active-view-transition-type(fx-bars)::view-transition-new(root) { animation-name: fx-bars; }
html:active-view-transition-type(fx-wipe)::view-transition-new(root) { animation-name: fx-wipe; animation-timing-function: cubic-bezier(0.8, 0, 0.2, 1); }
html:active-view-transition-type(fx-diamond)::view-transition-new(root) { animation-name: fx-diamond; }
html:active-view-transition-type(fx-blinds)::view-transition-new(root) {
  -webkit-mask-image: repeating-linear-gradient(to bottom, #000 0 var(--fx-b), transparent var(--fx-b) 9vh);
  mask-image: repeating-linear-gradient(to bottom, #000 0 var(--fx-b), transparent var(--fx-b) 9vh);
  animation-name: fx-blinds;
}
html:active-view-transition-type(fx-clock)::view-transition-new(root) {
  -webkit-mask-image: conic-gradient(from 0deg at 50% 50%, #000 var(--fx-a), transparent 0);
  mask-image: conic-gradient(from 0deg at 50% 50%, #000 var(--fx-a), transparent 0);
  animation-name: fx-clock;
  animation-timing-function: cubic-bezier(0.45, 0, 0.3, 1);
}
html:active-view-transition-type(fx-glitch)::view-transition-new(root) { animation: fx-glitch 0.5s steps(1) both; }
html:active-view-transition-type(fx-ink)::view-transition-new(root) { animation: fx-ink 0.62s steps(1) both; }

/* Blends: both pages carried through it together. */
html:active-view-transition-type(fx-zoom)::view-transition-old(root) { animation-name: fx-zoom-out; }
html:active-view-transition-type(fx-zoom)::view-transition-new(root) { animation-name: fx-zoom-in; }
html:active-view-transition-type(fx-whip)::view-transition-old(root) { animation: fx-whip-out 0.42s cubic-bezier(0.6, 0, 0.9, 0.4) both; }
html:active-view-transition-type(fx-whip)::view-transition-new(root) { animation: fx-whip-in 0.46s cubic-bezier(0.1, 0.6, 0.3, 1) 0.08s both; }
html:active-view-transition-type(fx-flash)::view-transition-old(root) { animation: fx-flash-out 0.28s ease-in both; }
html:active-view-transition-type(fx-flash)::view-transition-new(root) { animation: fx-flash-in 0.5s ease-out 0.18s both; }

@keyframes fx-iris {
  from { clip-path: circle(0% at var(--fx-x, 50%) var(--fx-y, 50%)); }
  to { clip-path: circle(145% at var(--fx-x, 50%) var(--fx-y, 50%)); }
}
@keyframes fx-star { from { mask-size: 0 0; -webkit-mask-size: 0 0; } to { mask-size: 460vmax 460vmax; -webkit-mask-size: 460vmax 460vmax; } }
@keyframes fx-bars { from { clip-path: inset(50% 0 50% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-diamond {
  from { clip-path: polygon(var(--fx-x, 50%) var(--fx-y, 50%), var(--fx-x, 50%) var(--fx-y, 50%), var(--fx-x, 50%) var(--fx-y, 50%), var(--fx-x, 50%) var(--fx-y, 50%)); }
  to { clip-path: polygon(var(--fx-x, 50%) -160%, 260% var(--fx-y, 50%), var(--fx-x, 50%) 260%, -160% var(--fx-y, 50%)); }
}
@keyframes fx-blinds { from { --fx-b: 0vh; } to { --fx-b: 9vh; } }
@keyframes fx-clock { from { --fx-a: 0deg; } to { --fx-a: 360deg; } }
@keyframes fx-glitch {
  0% { clip-path: inset(12% 0 64% 0); transform: translateX(-14px); filter: hue-rotate(80deg) saturate(2); }
  12% { clip-path: inset(52% 0 18% 0); transform: translateX(11px); }
  24% { clip-path: inset(30% 0 41% 0); transform: translateX(-7px); filter: hue-rotate(-60deg) saturate(2); }
  36% { clip-path: inset(0 0 58% 0); transform: translateX(5px); }
  48% { clip-path: inset(38% 0 0 0); transform: translateX(-3px); filter: none; }
  62% { clip-path: inset(0 0 0 0); transform: translateX(2px); }
  76%, 100% { clip-path: inset(0 0 0 0); transform: none; filter: none; }
}
@keyframes fx-ink {
  /* An impact frame on arrival: struck to its negative in ink and paper, redrawn the right way out, then itself. */
  0% { filter: grayscale(1) contrast(14) brightness(1.1) invert(1); transform: translate(-4px, 2px); }
  22% { filter: grayscale(1) contrast(14) brightness(1.1); transform: translate(3px, -2px); }
  44% { filter: grayscale(1) contrast(14) brightness(1.1) invert(1); transform: translate(-1px, 1px); }
  62%, 100% { filter: none; transform: none; }
}
@keyframes fx-zoom-out { to { transform: scale(1.22); filter: blur(10px); opacity: 0; } }
@keyframes fx-zoom-in { from { transform: scale(0.9); filter: blur(6px); opacity: 0; } }
@keyframes fx-whip-out { to { transform: translateX(-42%); filter: blur(16px); opacity: 0; } }
@keyframes fx-whip-in { from { transform: translateX(42%); filter: blur(16px); opacity: 0; } }
@keyframes fx-flash-out { to { filter: brightness(7) saturate(0); } }
@keyframes fx-flash-in { from { filter: brightness(7) saturate(0); } }
