/* Streambar FRAME CHROME — the eight border styles a media CLIP wears, and
 * nothing else.
 *
 * ONE SCOPE, AND IT IS `.fc-frame`. This is the stylesheet of the clip page
 * (/c/<token>), whose frame element carries that class round one GIF or video.
 * It is NOT the Streamcam's: a Streamcam (/o/<token> of an overlay of type
 * `frame`) draws from frame.css alone, every rule of it under #root, and the
 * two pages share the BUILDER (frame-chrome.js) rather than a cascade. That
 * separation is the rule here, not a detail — the panel loads both stylesheets
 * at once to preview either kind, so a rule in this file that was not under
 * `.fc-frame` would reach straight into a Streamcam. Every selector below
 * therefore starts at `.fc-frame`, and every @keyframes here is `fc-`-named so
 * they cannot collide with frame.css's own (tests/frame-chrome.test.mjs).
 *
 * THE FRAME WRAPS THE PICTURE. That is what every number here is for. The
 * element is the FRAME BOX, which the page sizes as the picture's own rect
 * grown outward by that style's `inner`; so every style is drawn from the box's
 * own edge INWARD, its band ends exactly where the picture begins, and nothing
 * is ever painted over the picture. Everything decorative — Pulse's glow,
 * Broadcast's brackets, Blaze's fire, Blade's streaks, Floodlight's beams —
 * goes OUTWARD instead, past the box's edge, which is why neither the box nor
 * this element may ever be `overflow: hidden`. (Crest is the one style that
 * needs no room at all: its colour and its comet are clipped to the ring they
 * paint, so it reaches nothing outside its own band.)
 *
 * TWO MULTIPLIERS, and the difference is the whole trick:
 *   * `--fc-k` is WEIGHT — every stroke, band, gap and the room a decoration
 *     needs. Each style's band is its own coefficient, and the page divides the
 *     ring it wants by that (frame-chrome.js FRAME_GEOMETRY), so all eight come
 *     out the SAME WIDTH at the same thickness: a Blade double line and a
 *     Chevron band weigh what a Pulse ring weighs.
 *   * `--fc-s` is SHAPE — anything measured against the PICTURE rather than the
 *     line: corner radii, corner cuts, bracket arms, the travel of a shimmer,
 *     the height of the fire. 1 is a picture as tall as the Streamcam's stage
 *     (484 px). One multiplier could not do both jobs: a clip's ring is 3.5 %
 *     of its picture's short side, some three times the Streamcam's
 *     proportionally, and a 34 px corner cut scaled by THAT was a notch a fifth
 *     of the picture wide.
 * Both default to 1, so an unset dial draws the design at its own numbers.
 *
 * A ROUNDED or CUT corner is stated as the INNER one — the picture's — and the
 * outer follows by adding the band: `calc(22px * var(--fc-s) + 4px * var(--fc-k))`
 * is "an inner radius of 22 shape-px round a 4-unit ring". The page clips the
 * picture to that same inner number, so a square video corner can never poke
 * past a rounded frame or sit in a chamfer's notch.
 *
 * ONE MORE DIAL, for the one thing that cannot be worked out from a rule:
 * `--fc-ring`, how big the Pulse spinner's square is (it must cover the frame
 * box's diagonal).
 *
 * MOTION IS `transform` and `opacity`, and nothing is DRAWN by a keyframe: at
 * `[data-anim="off"]` every style is still whole.
 *
 * The identity block, LIVE pill, locked plate, flash and the pitch band's sweep
 * belong to the Streamcam and are frame.css's. */

/* The clip page's frame element: the FRAME BOX itself, edge to edge of the box
   the page laid out, taking no clicks and drawing only its border. Overflow is
   VISIBLE and must stay so — the glow, the fire and the beams live outside it. */
.fc-frame {
  position: absolute;
  inset: 0;
  overflow: visible;
  pointer-events: none;
  --f-a: #7B2FBE;      --f-a-rgb: 123, 47, 190;
  --f-b: #E5B800;      --f-b-rgb: 229, 184, 0;
}

/* ======================================================================
 * PULSE — a soft glowing gradient border in the two brand colours.
 *
 * The border is the padding-box mask trick: the ring's own padding, a mask that
 * keeps it and drops the content box, so the middle stays see-through. BOTH
 * mask layers and the composite pair are on the SAME element — a single-layer
 * mask with `xor` composites to nothing in some Chromium builds. Inside it one
 * oversized square carrying the conic gradient spins on `transform`; that
 * gradient is PAINTED, so at `data-anim="off"` the ring is still and whole.
 *
 * The ring's padding IS the band, its content box IS the picture, and the glow
 * behind it throws light OUTWARD only: the inset shadow this style used to wear
 * over a camera would have fogged the clip it now surrounds.
 * ====================================================================== */
.fc-frame[data-style="pulse"] .sc-ring {
  position: absolute;
  inset: 0;
  border-radius: calc(22px * var(--fc-s, 1) + 4px * var(--fc-k, 1));
  padding: calc(4px * var(--fc-k, 1));
  overflow: hidden;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  transition: filter 0.25s ease;
}
/* 1040px square: the Streamcam's ring is 828 x 452, a ~942px diagonal, so the
   spinner covers every edge at every angle. A clip's box is another size
   entirely, so it writes its own diagonal into `--fc-ring` and the margin —
   half of it, negative — follows without a second number. */
.fc-frame[data-style="pulse"] .sc-ring::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--fc-ring, 1040px);
  height: var(--fc-ring, 1040px);
  margin: calc(var(--fc-ring, 1040px) / -2) 0 0 calc(var(--fc-ring, 1040px) / -2);
  background: conic-gradient(from 0deg, var(--f-a), var(--f-b) 35%, var(--f-a) 62%, var(--f-b) 85%, var(--f-a) 100%);
  transform: rotate(0deg);
}
.fc-frame[data-style="pulse"][data-anim="calm"] .sc-ring::before { animation: fc-spin 18s linear infinite; }
.fc-frame[data-style="pulse"][data-anim="lively"] .sc-ring::before { animation: fc-spin 7s linear infinite; }
@keyframes fc-spin { to { transform: rotate(360deg); } }

/* The glow: one box-shadow on an empty box behind the ring, rasterised once,
   and every layer of it OUTWARD — 20 + 4 units of reach, which is the room
   frame-chrome.js keeps for this style inside the canvas. */
.fc-frame[data-style="pulse"] .sc-glow {
  position: absolute;
  inset: 0;
  border-radius: calc(22px * var(--fc-s, 1) + 4px * var(--fc-k, 1));
  box-shadow: 0 0 calc(10px * var(--fc-k, 1)) calc(2px * var(--fc-k, 1)) rgba(var(--f-a-rgb), 0.42),
    0 0 calc(20px * var(--fc-k, 1)) calc(4px * var(--fc-k, 1)) rgba(var(--f-b-rgb), 0.16);
  opacity: 0.92;
  transition: opacity 0.25s ease, filter 0.25s ease;
}

/* ======================================================================
 * PITCH — the cut-corner frame. The corners are a clip-path on the border layer
 * (top-left and bottom-right; its two mask layers and composite pair are on
 * that one element too). The Streamcam's brand BAND along the bottom is its
 * identity block, so it is frame.css's and not here.
 *
 * `--fc-cut` is the OUTER chamfer: the inner one — the chamfer the page cuts
 * the picture to — is 34 shape-px, and the outer is that plus the band on both
 * of the corner's sides.
 * ====================================================================== */
.fc-frame[data-style="pitch"] { --fc-cut: calc(34px * var(--fc-s, 1) + 10px * var(--fc-k, 1)); }
.fc-frame[data-style="pitch"] .sc-cut {
  position: absolute;
  inset: 0;
  padding: calc(5px * var(--fc-k, 1));
  background: linear-gradient(135deg, var(--f-a) 0%, var(--f-b) 55%, var(--f-a) 100%);
  clip-path: polygon(var(--fc-cut) 0, 100% 0, 100% calc(100% - var(--fc-cut)), calc(100% - var(--fc-cut)) 100%, 0 100%, 0 var(--fc-cut));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
/* …and the frame arrives from below once, on load. `both` so it holds where it
   lands; `off` never plays it, and the frame is drawn either way. The other
   half of this rule — the band — is frame.css's, beside the node it moves. */
.fc-frame[data-style="pitch"]:not([data-anim="off"]) .sc-cut {
  animation: fc-rise 0.6s cubic-bezier(0.16, 0.84, 0.32, 1) both;
}
@keyframes fc-rise {
  from { transform: translateY(calc(72px * var(--fc-s, 1))); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

/* ======================================================================
 * BROADCAST — a clean rule with L-shaped corner brackets and a short bright
 * segment travelling the top and bottom lines.
 *
 * THE RULE WENT INVISIBLE IN OBS and nothing was hiding it — no mask, no
 * keyframe, no inset, no overflow. It was 2px of `rgba(var(--f-text-rgb),.6)`:
 * a 60% tint of the TEXT colour, the one colour here that is NOT a brand
 * colour, which washes out of a bright camera and sinks into a dark one. So:
 * the BRAND colour, 3px, opaque, over a dark keyline — an OUTER box-shadow,
 * clipped to outside the border box, so it can never fog the see-through
 * middle (`inset` would, and is banned here). NO mask here, so nothing waits
 * on `mask-composite`, and the shimmer rides ON the line instead of drawing
 * it: `data-anim="off"` is a whole frame.
 *
 * The BRACKETS sit OUTSIDE the rule now, a band's width clear of it, where they
 * used to sit inside it over the camera. Their arms are shape-px, because a
 * bracket is a proportion of the picture and not a multiple of the line.
 * ====================================================================== */
.fc-frame[data-style="broadcast"] .sc-edge {
  position: absolute;
  inset: 0;
  border: calc(3px * var(--fc-k, 1)) solid var(--f-a);
  border-radius: calc(4px * var(--fc-s, 1) + 3px * var(--fc-k, 1));
  box-shadow: 0 0 0 1px rgba(0,0,0,.55), 0 0 6px rgba(0,0,0,.35);
}
.fc-frame .sc-corner {
  position: absolute;
  width: calc(70px * var(--fc-s, 1));
  height: calc(70px * var(--fc-s, 1));
  border: calc(3px * var(--fc-k, 1)) solid var(--f-a);
}
/* A bracket is a square with two borders off, so a shadow all round it would
   lay dark lines across the picture; offset to the corner's own two sides it
   lands only on the stroke that is there. */
.fc-frame .sc-corner.is-tl { left: calc(-6px * var(--fc-k, 1)); top: calc(-6px * var(--fc-k, 1)); border-right: 0; border-bottom: 0; box-shadow: -1px -1px 0 rgba(0,0,0,.55); }
.fc-frame .sc-corner.is-tr { right: calc(-6px * var(--fc-k, 1)); top: calc(-6px * var(--fc-k, 1)); border-left: 0; border-bottom: 0; box-shadow: 1px -1px 0 rgba(0,0,0,.55); }
.fc-frame .sc-corner.is-bl { left: calc(-6px * var(--fc-k, 1)); bottom: calc(-6px * var(--fc-k, 1)); border-right: 0; border-top: 0; box-shadow: -1px 1px 0 rgba(0,0,0,.55); }
.fc-frame .sc-corner.is-br { right: calc(-6px * var(--fc-k, 1)); bottom: calc(-6px * var(--fc-k, 1)); border-left: 0; border-top: 0; box-shadow: 1px 1px 0 rgba(0,0,0,.55); }
/* The shimmer: one segment per line, as deep as the rule so it rides on it; the
   bottom one runs the other way, so the two read as a circuit. It is
   decoration — the line is whole without it. The strip SPANS its edge and
   clips itself, exactly as a Chevron edge does, so the segment can travel the
   whole line without the box having to crop anything. */
.fc-frame .sc-shim {
  position: absolute;
  left: 0;
  right: 0;
  height: calc(3px * var(--fc-k, 1));
  overflow: hidden;
  opacity: 0.9;
}
.fc-frame .sc-shim::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(var(--f-b-rgb), 0) 0%, var(--f-b) 50%, rgba(var(--f-b-rgb), 0) 100%) no-repeat;
  background-size: calc(150px * var(--fc-s, 1)) 100%;
  transform: translateX(calc(-170px * var(--fc-s, 1)));
}
.fc-frame .sc-shim.is-top { top: 0; }
.fc-frame .sc-shim.is-bot { bottom: 0; }
.fc-frame[data-style="broadcast"][data-anim="calm"] .sc-shim::before { animation: fc-shim 8s linear infinite; }
.fc-frame[data-style="broadcast"][data-anim="lively"] .sc-shim::before { animation: fc-shim 3s linear infinite; }
/* …after the shorthand above, which would otherwise reset the direction. */
.fc-frame[data-style="broadcast"] .sc-shim.is-bot::before { animation-direction: reverse; }
@keyframes fc-shim {
  from { transform: translateX(calc(-170px * var(--fc-s, 1))); }
  to   { transform: translateX(100%); }
}

/* ======================================================================
 * BLAZE — fire. Tongues licking up at the frame's lower edge and round its two
 * bottom corners, the first brand colour their core and the second their tips,
 * under a fine line that carries the rest of the edge.
 *
 * The fire is PAINTED, in two layers of radial ellipses — one on the element,
 * one on its ::before, their tongues at different places along the edge — so
 * `off` is a fire that is drawn and still. The keyframes only scale the layers
 * up from the bottom at DIFFERENT speeds, which is what reads as a flicker
 * rather than a pulse; `calm` swaps that for one slow breath of the same
 * flames. Every tongue is sized in PER CENT of the band it rises from, so it is
 * the same fire round a thumbnail and round a full-width clip.
 *
 * THE BAND IS OUTSIDE THE PICTURE. Its top is the picture's own bottom edge —
 * `100%` less the band this style wears — and it falls 90 shape-px from there,
 * so the tallest tongues reach the frame's line and everything below it is
 * clear of the clip. It used to start at 54 % of the box and burn straight
 * across the middle of whatever it was framing.
 * ====================================================================== */
/* The plain line TWO styles wear — Blaze's edge over the fire, Floodlight's
   frame under its lamps — one rule, one band, in the same money as the rest. */
.fc-frame .sc-fline {
  position: absolute;
  inset: 0;
  border: calc(4px * var(--fc-k, 1)) solid var(--f-a);
  border-radius: calc(6px * var(--fc-s, 1) + 4px * var(--fc-k, 1));
  box-shadow: 0 0 0 calc(1px * var(--fc-k, 1)) rgba(0, 0, 0, 0.45);
}
.fc-frame[data-style="blaze"] .sc-flame {
  position: absolute;
  left: calc(-6px * var(--fc-k, 1));
  right: calc(-6px * var(--fc-k, 1));
  top: calc(100% - 4px * var(--fc-k, 1));
  height: calc(90px * var(--fc-s, 1));
  transform-origin: 50% 100%;
  background:
    radial-gradient(ellipse 8% 44% at 11% 100%, rgba(var(--f-b-rgb), 0.9), rgba(var(--f-a-rgb), 0.62) 40%, rgba(var(--f-a-rgb), 0) 70%),
    radial-gradient(ellipse 11% 66% at 28% 100%, rgba(var(--f-b-rgb), 0.82), rgba(var(--f-a-rgb), 0.6) 38%, rgba(var(--f-a-rgb), 0) 68%),
    radial-gradient(ellipse 9% 50% at 47% 100%, rgba(var(--f-b-rgb), 0.86), rgba(var(--f-a-rgb), 0.58) 42%, rgba(var(--f-a-rgb), 0) 70%),
    radial-gradient(ellipse 12% 70% at 67% 100%, rgba(var(--f-b-rgb), 0.8), rgba(var(--f-a-rgb), 0.6) 36%, rgba(var(--f-a-rgb), 0) 66%),
    radial-gradient(ellipse 8% 46% at 87% 100%, rgba(var(--f-b-rgb), 0.88), rgba(var(--f-a-rgb), 0.6) 40%, rgba(var(--f-a-rgb), 0) 70%),
    radial-gradient(ellipse 20% 30% at 0% 76%, rgba(var(--f-b-rgb), 0.55), rgba(var(--f-a-rgb), 0.45) 40%, rgba(var(--f-a-rgb), 0) 72%),
    radial-gradient(ellipse 20% 30% at 100% 76%, rgba(var(--f-b-rgb), 0.55), rgba(var(--f-a-rgb), 0.45) 40%, rgba(var(--f-a-rgb), 0) 72%),
    linear-gradient(to top, rgba(var(--f-a-rgb), 0.34) 0%, rgba(var(--f-a-rgb), 0) 34%);
}
/* The second rank, BETWEEN the first: the two never line up, which is why it
   reads as fire and not as a bar of light. */
.fc-frame[data-style="blaze"] .sc-flame::before {
  content: "";
  position: absolute;
  inset: 0;
  transform-origin: 50% 100%;
  opacity: 0.85;
  background:
    radial-gradient(ellipse 7% 56% at 19% 100%, rgba(var(--f-b-rgb), 0.85), rgba(var(--f-a-rgb), 0.5) 40%, rgba(var(--f-a-rgb), 0) 70%),
    radial-gradient(ellipse 9% 40% at 38% 100%, rgba(var(--f-b-rgb), 0.8), rgba(var(--f-a-rgb), 0.5) 42%, rgba(var(--f-a-rgb), 0) 72%),
    radial-gradient(ellipse 10% 62% at 57% 100%, rgba(var(--f-b-rgb), 0.85), rgba(var(--f-a-rgb), 0.5) 38%, rgba(var(--f-a-rgb), 0) 68%),
    radial-gradient(ellipse 8% 46% at 77% 100%, rgba(var(--f-b-rgb), 0.8), rgba(var(--f-a-rgb), 0.5) 42%, rgba(var(--f-a-rgb), 0) 72%),
    radial-gradient(ellipse 7% 38% at 95% 100%, rgba(var(--f-b-rgb), 0.85), rgba(var(--f-a-rgb), 0.5) 40%, rgba(var(--f-a-rgb), 0) 70%);
}
/* CALM is a glow — the same flames, breathing, the two layers out of step.
   LIVELY is the flicker. */
.fc-frame[data-style="blaze"][data-anim="calm"] .sc-flame           { animation: fc-ember 6s ease-in-out infinite; }
.fc-frame[data-style="blaze"][data-anim="calm"] .sc-flame::before   { animation: fc-ember 8.5s ease-in-out infinite; animation-delay: -3s; }
.fc-frame[data-style="blaze"][data-anim="lively"] .sc-flame         { animation: fc-fire 1.5s ease-in-out infinite; }
.fc-frame[data-style="blaze"][data-anim="lively"] .sc-flame::before { animation: fc-fire2 1.1s ease-in-out infinite; }
@keyframes fc-ember {
  0%, 100% { transform: scaleY(1); opacity: 0.88; }
  50%      { transform: scaleY(1.06); opacity: 1; }
}
@keyframes fc-fire {
  0%, 100% { transform: scaleY(1) scaleX(1); opacity: 0.92; }
  30%      { transform: scaleY(1.16) scaleX(0.97); opacity: 1; }
  64%      { transform: scaleY(0.9) scaleX(1.03); opacity: 0.82; }
}
@keyframes fc-fire2 {
  0%, 100% { transform: scaleY(0.96) translateX(0); opacity: 0.8; }
  38%      { transform: scaleY(1.22) translateX(1%); opacity: 0.95; }
  71%      { transform: scaleY(0.86) translateX(-1%); opacity: 0.68; }
}

/* ======================================================================
 * BLADE — two sharp diagonal cuts at opposite corners and a DOUBLE line: a
 * heavy outer edge with a fine inner one held off it, both on the padding-box
 * mask Pitch uses, so the air between them stays the motif. A light runs each
 * cut — a bar as long as that cut's own hypotenuse, rotated onto it, the
 * highlight travelling inside it under `overflow: hidden`, so at `off` it is
 * parked out of sight and the two lines are the whole style.
 *
 * The DOUBLE LINE is the band: 8 units of outer edge, 5 of air, 3 of inner
 * line, 16 in all — which is why `--fc-k` divides by 16 here and by 4 for a
 * Pulse ring. Before that it divided by the outer line alone and a Blade frame
 * was twice the weight of every other style at the same setting.
 *
 * Both chamfers are stated from the picture's: 80 shape-px is the cut the page
 * gives the picture, the inner line's own clip is that plus its two paddings,
 * and the outer line's is offset from it by the band, so the two cuts run
 * parallel down the diagonal.
 * ====================================================================== */
.fc-frame[data-style="blade"] {
  --fc-cut-in: calc(80px * var(--fc-s, 1) + 6px * var(--fc-k, 1));
  --fc-cut-out: calc(80px * var(--fc-s, 1) + 10px * var(--fc-k, 1));
}
.fc-frame .sc-blade {
  position: absolute;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
.fc-frame .sc-blade.is-out {
  inset: 0;
  padding: calc(8px * var(--fc-k, 1));
  background: linear-gradient(135deg, var(--f-a) 0%, var(--f-b) 52%, var(--f-a) 100%);
  clip-path: polygon(var(--fc-cut-out) 0, 100% 0, 100% calc(100% - var(--fc-cut-out)), calc(100% - var(--fc-cut-out)) 100%, 0 100%, 0 var(--fc-cut-out));
}
.fc-frame .sc-blade.is-in {
  inset: calc(13px * var(--fc-k, 1));
  padding: calc(3px * var(--fc-k, 1));
  background: rgba(var(--f-b-rgb), 0.85);
  clip-path: polygon(var(--fc-cut-in) 0, 100% 0, 100% calc(100% - var(--fc-cut-in)), calc(100% - var(--fc-cut-in)) 100%, 0 100%, 0 var(--fc-cut-in));
}
/* The cut's middle is half its own chamfer from both sides, and its hypotenuse
   is that chamfer times root two — which is the bar. */
.fc-frame .sc-streak {
  position: absolute;
  width: calc(113px * var(--fc-s, 1) + 14px * var(--fc-k, 1));
  height: calc(6px * var(--fc-k, 1));
  overflow: hidden;
  opacity: 0.9;
}
.fc-frame .sc-streak::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(var(--f-b-rgb), 0) 0%, rgba(255, 255, 255, 0.95) 50%, rgba(var(--f-b-rgb), 0) 100%);
  transform: translateX(-130%);
}
.fc-frame .sc-streak.is-tl { left: calc(40px * var(--fc-s, 1) + 5px * var(--fc-k, 1)); top: calc(40px * var(--fc-s, 1) + 5px * var(--fc-k, 1)); transform: translate(-50%, -50%) rotate(-45deg); }
.fc-frame .sc-streak.is-br { right: calc(40px * var(--fc-s, 1) + 5px * var(--fc-k, 1)); bottom: calc(40px * var(--fc-s, 1) + 5px * var(--fc-k, 1)); transform: translate(50%, 50%) rotate(-45deg); }
.fc-frame[data-style="blade"][data-anim="calm"] .sc-streak::before   { animation: fc-cutlight 7s ease-in-out infinite; }
.fc-frame[data-style="blade"][data-anim="lively"] .sc-streak::before { animation: fc-cutlight 2.6s ease-in-out infinite; }
/* …after the shorthand, so the far cut lights half a cycle behind the near one. */
.fc-frame[data-style="blade"] .sc-streak.is-br::before { animation-delay: -1.3s; }
@keyframes fc-cutlight {
  0%        { transform: translateX(-130%); }
  62%, 100% { transform: translateX(230%); }
}

/* ======================================================================
 * CHEVRON — the border is a RING OF CHEVRONS pointing clockwise, alternating
 * the two brand colours, with a light chasing them round.
 *
 * Four nodes, one per edge, and NOT one per segment. Each edge is two
 * background layers, a near half and a far half, tiled in squares of
 * `--fc-chev` — half the strip's height, so the tile is square whatever the
 * box is. In a square tile a 45deg hard-stop gradient splits corner to corner
 * and the two halves are mirror images: that is a chevron. Turn both angles a
 * quarter and they point the next way round. The chase is a TRANSLATING
 * highlight, one per edge, a quarter cycle apart.
 *
 * The strips start at the box's own edge and are two tiles deep, so the band is
 * 18 units — the style's whole weight, and what `--fc-k` is divided by. The
 * chase's length is shape-px: it is a highlight running an EDGE, not a multiple
 * of the line's thickness.
 * ====================================================================== */
.fc-frame[data-style="chevron"] {
  --fc-chev: calc(9px * var(--fc-k, 1));
  --fc-chase: 9s;
}
.fc-frame[data-style="chevron"][data-anim="lively"] { --fc-chase: 3.6s; }
.fc-frame .sc-chev { position: absolute; overflow: hidden; }
.fc-frame .sc-chev.is-top, .fc-frame .sc-chev.is-bot    { left: 0; right: 0; height: calc(2 * var(--fc-chev)); }
.fc-frame .sc-chev.is-left, .fc-frame .sc-chev.is-right { top: calc(2 * var(--fc-chev)); bottom: calc(2 * var(--fc-chev)); width: calc(2 * var(--fc-chev)); }
.fc-frame .sc-chev.is-top   { top: 0; }
.fc-frame .sc-chev.is-bot   { bottom: 0; }
.fc-frame .sc-chev.is-left  { left: 0; }
.fc-frame .sc-chev.is-right { right: 0; }
/* 49.5/50.5 rather than a flat 50: one per cent of the tile is the softest edge
   a gradient can be given with no length of its own, and it is what stops the
   diagonal crawling on a big box. */
.fc-frame .sc-chev.is-top {
  background:
    linear-gradient(45deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left top / var(--fc-chev) 50% repeat-x,
    linear-gradient(135deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left bottom / var(--fc-chev) 50% repeat-x;
}
.fc-frame .sc-chev.is-right {
  background:
    linear-gradient(135deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) right top / 50% var(--fc-chev) repeat-y,
    linear-gradient(225deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left top / 50% var(--fc-chev) repeat-y;
}
.fc-frame .sc-chev.is-bot {
  background:
    linear-gradient(225deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left bottom / var(--fc-chev) 50% repeat-x,
    linear-gradient(315deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left top / var(--fc-chev) 50% repeat-x;
}
.fc-frame .sc-chev.is-left {
  background:
    linear-gradient(315deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) left top / 50% var(--fc-chev) repeat-y,
    linear-gradient(45deg, var(--f-a) 0 49.5%, var(--f-b) 50.5% 100%) right top / 50% var(--fc-chev) repeat-y;
}
/* The chase has the shape Broadcast's shimmer has: the element spans the edge
   it rides, the highlight is painted into one end with `background-size`, and
   the keyframe ends one full edge along. */
.fc-frame .sc-chev::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.72) 50%, rgba(255, 255, 255, 0) 100%) no-repeat;
  background-size: calc(140px * var(--fc-s, 1)) 100%;
  transform: translateX(calc(-160px * var(--fc-s, 1)));
}
.fc-frame .sc-chev.is-left::before, .fc-frame .sc-chev.is-right::before {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.72) 50%, rgba(255, 255, 255, 0) 100%) no-repeat;
  background-size: 100% calc(140px * var(--fc-s, 1));
  transform: translateY(calc(-160px * var(--fc-s, 1)));
}
.fc-frame[data-style="chevron"]:not([data-anim="off"]) .sc-chev::before { animation: fc-chevx var(--fc-chase) linear infinite; }
/* …then each edge is turned to face the way round: the uprights run on the Y
   keyframe, the bottom and the left run backwards, and the four are a quarter
   of a cycle apart — which is the light going round. */
.fc-frame[data-style="chevron"] .sc-chev.is-right::before { animation-name: fc-chevy; animation-delay: calc(var(--fc-chase) * -0.75); }
.fc-frame[data-style="chevron"] .sc-chev.is-bot::before   { animation-direction: reverse; animation-delay: calc(var(--fc-chase) * -0.5); }
.fc-frame[data-style="chevron"] .sc-chev.is-left::before  { animation-name: fc-chevy; animation-direction: reverse; animation-delay: calc(var(--fc-chase) * -0.25); }
@keyframes fc-chevx {
  from { transform: translateX(calc(-160px * var(--fc-s, 1))); }
  to   { transform: translateX(100%); }
}
@keyframes fc-chevy {
  from { transform: translateY(calc(-160px * var(--fc-s, 1))); }
  to   { transform: translateY(100%); }
}

/* ======================================================================
 * FLOODLIGHT — a thin frame with a lamp at each top corner throwing a soft beam
 * down past the picture, the way a stadium does at night.
 *
 * A beam is ONE node: a box hung OUTSIDE the frame — `right: 100%` puts the
 * left one entirely beyond the left edge, `left: 100%` the right one beyond the
 * right — with its lamp at the top corner it belongs to, the cone cut out with
 * a `clip-path` in PER CENT (so it opens at the same angle whatever the box is)
 * and filled with a gradient all but gone two thirds of the way down. It used
 * to be thrown ACROSS the middle, which over a camera was the style and over a
 * clip was a wash of colour on somebody's picture. The flicker is opacity and
 * nothing else, the two lamps out of step, slower at `calm`, absent at `off` —
 * where the beams are still drawn, because they ARE the style. The frame under
 * them is `.sc-fline`, the rule Blaze's edge is drawn by.
 * ====================================================================== */
.fc-frame .sc-beam {
  position: absolute;
  top: 0;
  width: calc(110px * var(--fc-s, 1));
  height: 86%;
  opacity: 0.9;
}
.fc-frame .sc-beam.is-l {
  right: 100%;
  clip-path: polygon(88% 0, 100% 0, 34% 100%, 0 100%);
  background:
    radial-gradient(ellipse 14% 5% at 96% 0%, rgba(var(--f-b-rgb), 0.95), rgba(var(--f-b-rgb), 0) 72%),
    linear-gradient(to bottom, rgba(var(--f-b-rgb), 0.32) 0%, rgba(var(--f-b-rgb), 0.12) 38%, rgba(var(--f-a-rgb), 0.05) 70%, rgba(var(--f-a-rgb), 0) 100%);
}
.fc-frame .sc-beam.is-r {
  left: 100%;
  clip-path: polygon(0 0, 12% 0, 100% 100%, 66% 100%);
  background:
    radial-gradient(ellipse 14% 5% at 4% 0%, rgba(var(--f-b-rgb), 0.95), rgba(var(--f-b-rgb), 0) 72%),
    linear-gradient(to bottom, rgba(var(--f-b-rgb), 0.32) 0%, rgba(var(--f-b-rgb), 0.12) 38%, rgba(var(--f-a-rgb), 0.05) 70%, rgba(var(--f-a-rgb), 0) 100%);
}
.fc-frame[data-style="floodlight"][data-anim="calm"] .sc-beam   { animation: fc-flood 11s ease-in-out infinite; }
.fc-frame[data-style="floodlight"][data-anim="lively"] .sc-beam { animation: fc-flood 4.5s ease-in-out infinite; }
/* …after the shorthand, so the two lamps never flicker together. */
.fc-frame[data-style="floodlight"] .sc-beam.is-r { animation-delay: -2.6s; }
@keyframes fc-flood {
  0%, 100% { opacity: 0.88; }
  34%      { opacity: 0.72; }
  53%      { opacity: 1; }
  72%      { opacity: 0.8; }
}

/* ======================================================================
 * CREST — the border that goes with the Crest BAR: a box with CUT CORNERS
 * whose edge is slanted blocks of the two brand colours travelling slowly
 * round it, with a narrow white comet washing the chamfers as it passes.
 *
 * ONE NODE for the whole thing, as it is on a Streamcam. `.sc-crest` is a
 * STENCIL — an `evenodd` clip-path of two cut-corner octagons, the outer one
 * the frame box and the inner one the picture — and what shows through the ring
 * between them is its ::before, an oversized square of colour that turns. The
 * blocks are a conic gradient whose stops sample EQUAL RUNS OF THE PERIMETER
 * and are converted back to angles with `atan2`, which is why the blocks come
 * out the same length along a short edge and a long one; the container is the
 * element itself (`container-type: size`), so `cqw`/`cqh` are this picture's
 * own rect (the clip page also writes the stop angles in degrees — below).
 *
 * THE STROKE IS ONE WIDTH ALL THE WAY ROUND, chamfers included, which is the
 * whole reason for the stencil rather than a mask over a clipped box: the two
 * octagons' diagonals are PARALLEL, a band apart. That is the arithmetic in
 * `--fc-crest-cut` — a 45° chamfer held off by one band moves its intercept by
 * 2 − √2 of it, so the OUTER cut is the picture's plus 0.586 of the band, and
 * the hole's is the picture's plus the whole band, which lands it exactly on
 * the chamfer the page cuts the picture to.
 *
 * Only `transform` and `opacity` move, linear and infinite, and the colour is
 * PAINTED: at `data-anim="off"` the ring is whole and still (the comet is the
 * one thing that goes, because a parked white wash on one corner is a smear
 * rather than a glint). The SKIN a Streamcam's Crest can wear is not a thing a
 * clip has — this is the default look and the only one.
 * ====================================================================== */
.fc-frame[data-style="crest"] {
  /* The picture's chamfer is 18 shape-px; the two the stencil is cut to follow
     from it and the band, and never the other way round. */
  --fc-crest-cut: calc(18px * var(--fc-s, 1) + 2.343px * var(--fc-k, 1));
  --fc-crest-cut-in: calc(18px * var(--fc-s, 1) + 4px * var(--fc-k, 1));
  --fc-crest-run: 20s;
  --fc-crest-comet: 7s;
  --fc-crest-enter: 0.5s;
  --fc-crest-light: 0.6;
  --fc-crest-tail: 16deg;
}
/* The style shipped with two speeds and no dial of its own: calm is what a clip
   fires at, lively is quicker and brighter. `off` reads neither. */
.fc-frame[data-style="crest"][data-anim="lively"] {
  --fc-crest-run: 12s;
  --fc-crest-comet: 4s;
  --fc-crest-light: 0.95;
}
.fc-frame[data-style="crest"] .sc-crest {
  position: absolute;
  inset: 0;
  /* The band, twice over: the padding is what makes the container query box the
     PICTURE's rect, and the same number is the stencil's own hole. */
  padding: calc(4px * var(--fc-k, 1));
  overflow: hidden;
  container-type: size;
  clip-path: polygon(evenodd,
    var(--fc-crest-cut) 0, calc(100% - var(--fc-crest-cut)) 0,
    100% var(--fc-crest-cut), 100% calc(100% - var(--fc-crest-cut)),
    calc(100% - var(--fc-crest-cut)) 100%, var(--fc-crest-cut) 100%,
    0 calc(100% - var(--fc-crest-cut)), 0 var(--fc-crest-cut), var(--fc-crest-cut) 0,
    var(--fc-crest-cut-in) calc(4px * var(--fc-k, 1)),
    calc(4px * var(--fc-k, 1)) var(--fc-crest-cut-in),
    calc(4px * var(--fc-k, 1)) calc(100% - var(--fc-crest-cut-in)),
    var(--fc-crest-cut-in) calc(100% - 4px * var(--fc-k, 1)),
    calc(100% - var(--fc-crest-cut-in)) calc(100% - 4px * var(--fc-k, 1)),
    calc(100% - 4px * var(--fc-k, 1)) calc(100% - var(--fc-crest-cut-in)),
    calc(100% - 4px * var(--fc-k, 1)) var(--fc-crest-cut-in),
    calc(100% - var(--fc-crest-cut-in)) calc(4px * var(--fc-k, 1)),
    var(--fc-crest-cut-in) calc(4px * var(--fc-k, 1)),
    var(--fc-crest-cut) 0);
}
/* The sheet of colour, big enough to cover the box's diagonal at every angle.
   `--p1`/`--p2` are a sixth and a third of the way round the half-perimeter and
   `atan2` turns each back into the angle that point stands at, which is what
   keeps a block the same LENGTH top and side rather than the same angle.
   The stop angles are ALSO written by the clip page as plain degrees
   (`--fc-crest-aN`, frame-chrome.js's `clipCrestAngles`, the same maths off
   this box): OBS's older Chromium cannot resolve atan2 here and would paint no
   ring. The atan2 is the fallback. */
.fc-frame[data-style="crest"] .sc-crest::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(100cqw + 100cqh);
  height: calc(100cqw + 100cqh);
  transform: translate(-50%, -50%) rotate(0turn);
  --p1: calc((100cqw + 100cqh) * 0.16666667);
  --a1: var(--fc-crest-a1, atan2(min(var(--p1), 50cqw), calc(50cqh - max(0cqw, var(--p1) - 50cqw))));
  --p2: calc((100cqw + 100cqh) * 0.33333333);
  --a2: var(--fc-crest-a2, atan2(min(var(--p2), 50cqw), calc(50cqh - max(0cqw, var(--p2) - 50cqw))));
  background: conic-gradient(var(--f-a) 0deg var(--a1),
    var(--f-b) var(--a1) var(--a2),
    var(--f-a) var(--a2) 90deg,
    var(--f-b) 90deg calc(180deg - var(--a2)),
    var(--f-a) calc(180deg - var(--a2)) calc(180deg - var(--a1)),
    var(--f-b) calc(180deg - var(--a1)) 180deg,
    var(--f-a) 180deg calc(180deg + var(--a1)),
    var(--f-b) calc(180deg + var(--a1)) calc(180deg + var(--a2)),
    var(--f-a) calc(180deg + var(--a2)) 270deg,
    var(--f-b) 270deg calc(360deg - var(--a2)),
    var(--f-a) calc(360deg - var(--a2)) calc(360deg - var(--a1)),
    var(--f-b) calc(360deg - var(--a1)) 360deg);
}
/* The glint: a narrow white head with a tail fading out behind it, on the same
   square and turning faster than the colour underneath. */
.fc-frame[data-style="crest"] .sc-crest::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(100cqw + 100cqh);
  height: calc(100cqw + 100cqh);
  transform: translate(-50%, -50%) rotate(0turn);
  background: conic-gradient(rgba(255, 255, 255, 1) 0deg, rgba(255, 255, 255, 0.4) 2deg,
    transparent var(--fc-crest-tail), transparent 360deg);
  opacity: var(--fc-crest-light);
}
/* The colour draws itself out from the middle once, then turns for good; the
   glint waits that long and follows. `both`, so each holds where it lands. */
.fc-frame[data-style="crest"]:not([data-anim="off"]) .sc-crest::before {
  animation: fc-crest-draw var(--fc-crest-enter) cubic-bezier(0.16, 1, 0.3, 1) both,
    fc-crest-run var(--fc-crest-run) linear var(--fc-crest-enter) infinite;
}
.fc-frame[data-style="crest"]:not([data-anim="off"]) .sc-crest::after {
  animation: fc-crest-lit var(--fc-crest-enter) steps(1, end) both,
    fc-crest-comet var(--fc-crest-comet) linear var(--fc-crest-enter) infinite;
}
.fc-frame[data-style="crest"][data-anim="off"] .sc-crest::after { display: none; }
@keyframes fc-crest-run {
  from { transform: translate(-50%, -50%) rotate(0turn); }
  to   { transform: translate(-50%, -50%) rotate(-1turn); }
}
@keyframes fc-crest-comet {
  from { transform: translate(-50%, -50%) rotate(0turn); }
  to   { transform: translate(-50%, -50%) rotate(-1turn); }
}
@keyframes fc-crest-draw {
  from { transform: translate(-50%, -50%) scaleX(0); opacity: 0; }
  to   { transform: translate(-50%, -50%) scaleX(1); opacity: 1; }
}
@keyframes fc-crest-lit {
  from { opacity: 0; }
  to   { opacity: var(--fc-crest-light); }
}

/* ======================================================================
 * REDUCED MOTION — blunt, and for the CLIP page's scope only: frame.css has the
 * same rule for #root and it has to stay there, because it covers the pill, the
 * band and the flash as well. A machine that asks for less gets a frame that is
 * FINISHED and still — every gradient, bracket, flame, chevron and beam here is
 * PAINTED, never an animation's first frame.
 * ====================================================================== */
@media (prefers-reduced-motion: reduce) {
  .fc-frame, .fc-frame *, .fc-frame *::before, .fc-frame *::after {
    animation: none !important;
    transition: none !important;
  }
}
