/* The review-clip carousel.
 *
 * Its own file because the pages that use it do not share a head: the home
 * page builds its own and does not load site.css, so anything kept there
 * reached the reviews page and left the home page with a full-width gradient
 * block where the clips should be.
 *
 * Every colour here comes from the shared tokens, which both pages define.
 * The fallbacks are only for the odd page that forgets to.
 */

.reels{position:relative}

/* The rail is a real scroll container rather than a track we translate.
   A scroller is swipeable on a phone for nothing, snaps by itself, and is
   already the plain scroller this has to degrade to when somebody has asked
   for less motion -- so there is no second code path to keep working. */
.reels-track{
  /* Sized so roughly four cards sit across the rail: the hero, a whole
     neighbour each side and the next pair cropped by the edges. Wider than
     this and only the hero and one sliver fit, which does not read as a
     carousel -- and at 400px on a 1440 screen the section heading plus one
     clip filled the fold on a laptop. */
  --reel-w:clamp(236px,21vw,300px);
  /* No gap: the shrink on the side cards leaves the space instead, so the
     spacing grows and closes with the scale rather than fighting it. */
  display:flex;align-items:center;gap:0;
  overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;
  scroll-snap-type:x mandatory;
  /* Half the rail minus half a card, so the first and last clip can sit in
     the middle like any other. Percentage padding measures the parent, so
     this stays right at every width with no JS to keep in step. */
  padding-inline:calc(50% - var(--reel-w) / 2);
  /* The scroller clips both axes once either one scrolls, so the hero's
     shadow and its lift need room inside it or they get sliced off. */
  padding-block:16px 22px;
  -ms-overflow-style:none;scrollbar-width:none;
  /* The outer clips fade into the page instead of being cut off at the
     edge. A mask does it without having to know the colour behind: this
     carousel sits on white on the home page and on grey on the reviews
     page, and a gradient painted in either one showed a seam on the other. */
  -webkit-mask-image:linear-gradient(to right,transparent,#000 18%,#000 82%,transparent);
  mask-image:linear-gradient(to right,transparent,#000 18%,#000 82%,transparent);
}
.reels-track::-webkit-scrollbar{display:none}

/* Three tiers, so the eye has somewhere obvious to land. The scale is a
   transform and not a width: the layout box stays the same size whichever
   card is the hero, which is what keeps the centring arithmetic -- and so
   the slide -- from jumping as the sizes change under it. */
.reel{position:relative;flex:0 0 var(--reel-w);width:var(--reel-w);
  aspect-ratio:3 / 4;border-radius:var(--r-card,24px);
  background:var(--black,#141414);
  scroll-snap-align:center;
  transform:scale(.82);opacity:.42;
  box-shadow:var(--sh-sm,0 6px 20px rgba(20,20,20,.08));
  transition:transform .4s ease-out,opacity .4s ease-out,box-shadow .4s ease-out}
/* The neighbours are meant to be legible, not ghosts: at .56 they read as
   a rendering fault rather than as the next clip along. */
.reel.near{transform:scale(.91);opacity:.78}
.reel.is-live{transform:scale(1) translateY(-4px);opacity:1;
  box-shadow:var(--sh-lg,0 30px 70px rgba(20,20,20,.10)),
             0 0 0 1px rgba(21,113,198,.22)}

/* The stage does the clipping, not the card. The card has to stay unclipped
   so that the focus ring on the button filling it is not cut off by its own
   parent -- which is exactly what happened while the card had overflow
   hidden on it. */
.reel-stage{position:absolute;inset:0;border-radius:inherit;overflow:hidden}
.reel-v,.reel-yt,.reel-yt iframe,.reel-poster{position:absolute;inset:0;
  width:100%;height:100%;border:0;display:block}
.reel-v,.reel-poster{object-fit:cover}
.reel.playing .reel-poster{display:none}
.reel.playing .reel-back{opacity:0;transition:opacity .3s ease-out}

/* A 16:9 clip cannot fill a 9:13 card. Rather than two black bars, its own
   still sits behind it, blown up and blurred, so the gap reads as depth. */
.reel-back{position:absolute;inset:-10%;width:120%;height:120%;object-fit:cover;
  filter:blur(26px) brightness(.5);transform:scale(1.1)}

/* Instagram draws 54px of header and 154px of actions around the clip, and
   we cannot reach into the frame to remove them. So the frame is made taller
   than the card by exactly that much and pulled up by the header, which puts
   the clip itself against the card edges and leaves the rest outside. The
   width is over-scaled so a 4:5 frame covers the card rather than sitting in
   the middle of it -- the sides crop, which is what "fill the box" means
   here. */
.reel-ig{position:absolute;inset:0;overflow:hidden}
.reel-embed{position:absolute;top:-54px;left:50%;transform:translateX(-50%);
  width:143%;height:calc(100% + 208px);border:0;display:block;
  background:transparent}
/* Until an Instagram card is the one playing, its frame must not eat the
   press that would bring it to the middle -- the iframe is a different
   document and the click never reaches us. Once it is centre stage,
   Instagram's own controls are the only way to start it, so it gets them
   back. */
.reel:not(.is-live) .reel-embed{pointer-events:none}

/* --- the press target ---------------------------------------------------- */
/* Covers the whole card, so the generous touch target is the card itself.
   Not over a playing Instagram embed: Instagram's player is the only way one
   of those ever starts, so covering it would leave that card permanently
   still. */
.reel-hit{position:absolute;inset:0;z-index:3;padding:0;border:0;
  background:transparent;cursor:pointer;-webkit-appearance:none;appearance:none}
/* Neutralised, not removed. display:none on the element that currently holds
   focus drops focus to <body>, so tabbing into the Instagram clip sent the
   next Tab back to the top of the document. It keeps its place in the tab
   order and its label; it simply stops swallowing presses meant for the
   embed underneath. */
.reel[data-kind="instagram"].is-live .reel-hit{pointer-events:none}

/* --- sound -------------------------------------------------------------- */
/* The centre clip starts muted, because muted is the only autoplay a browser
   allows unprompted. This says so and switches it, and only appears on the
   card it applies to. */
.reel-sound{position:absolute;right:12px;bottom:12px;z-index:5;
  width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  display:grid;place-items:center;
  background:rgba(14,14,20,.58);color:#fff;
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  opacity:0;pointer-events:none;
  transition:opacity .2s ease-out,background .16s ease-out,transform .16s ease-out}
.reel.is-live .reel-sound{opacity:1;pointer-events:auto}
.reel-sound:hover{background:rgba(14,14,20,.86);transform:scale(1.06)}
.reel-sound svg{width:19px;height:19px;pointer-events:none}
/* Which half shows is the mute state. `loud` means the viewer turned it on. */
.reel-sound .on{display:none}
.reel-sound .off{display:grid}
.reel.loud .reel-sound{background:#fff;color:var(--cta-deep,#0F5BA3)}
.reel.loud .reel-sound .on{display:grid}
.reel.loud .reel-sound .off{display:none}

/* Every interactive thing in here, in one place. The ring is on the control
   rather than on the card so it traces the thing that actually has focus. */
.reel-hit:focus-visible,.reel-sound:focus-visible,
.reels-btn:focus-visible,.reels-dot:focus-visible{
  outline:2px solid var(--cta,#1571C6);outline-offset:2px}
.reel-hit:focus-visible{border-radius:var(--r-card,24px)}

/* A press on a large upload can take a few seconds to show its first frame.
   Without this the card sat unchanged and read as broken. */
.reel.buffering .reel-stage::after{content:"";position:absolute;left:50%;top:50%;
  width:38px;height:38px;margin:-19px 0 0 -19px;border-radius:50%;z-index:3;
  border:3px solid rgba(255,255,255,.3);border-top-color:#fff;
  animation:reel-spin .8s linear infinite;pointer-events:none}
@keyframes reel-spin{to{transform:rotate(360deg)}}

/* --- the overlay -------------------------------------------------------- */
.reel-cover{position:absolute;inset:0;z-index:2;display:flex;flex-direction:column;
  padding:16px;color:#fff;pointer-events:none;
  border-radius:inherit;overflow:hidden;
  transition:opacity .26s ease-out}
/* A soft gradient scrim and nothing like a bar: it starts well down the card
   and never reaches full black, so the clip stays legible through it. The old
   one covered 62% of the card at .92 and read as a solid panel. */
.reel-cover::before{content:"";position:absolute;inset:auto 0 0 0;height:46%;
  pointer-events:none;
  background:linear-gradient(to top,
    rgba(10,10,14,.82),rgba(10,10,14,.5) 34%,rgba(10,10,14,.14) 70%,transparent)}

/* Once the hero is playing, nothing sits over the person talking; on a
   laptop the detail comes back while the pointer is on the card.
   `is-live` as well as `playing`, not `playing` alone: every Instagram card
   keeps its embed loaded and so is marked as playing whether or not it is
   the one in the middle, and on `playing` alone that stripped the caption
   off every Instagram card in the rail. */
@media (hover:hover){
  .reel.is-live.playing .reel-cover{opacity:0}
  .reel.is-live.playing:hover .reel-cover{opacity:1}
}
/* Same reveal for a keyboard, so the quote is not pointer-only. Kept as its
   own rule: one selector a browser does not know would otherwise take the
   hover reveal down with it. */
@media (hover:hover){
  .reel.is-live.playing:focus-within .reel-cover{opacity:1}
}
/* Where there is no pointer to hover with, the overlay stays put -- a phone
   would otherwise never show who is speaking. That is the default above, so
   there is nothing to write here; this note is to stop someone adding it. */

.reel-top{position:relative;display:flex;align-items:flex-start;gap:8px}
.reel-tag{display:inline-flex;align-items:center;gap:6px;max-width:72%;
  padding:6px 11px;border-radius:999px;background:rgba(255,255,255,.94);
  color:var(--black,#141414);font-size:12px;font-weight:700;letter-spacing:-.01em;
  box-shadow:0 2px 10px rgba(8,8,16,.18);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.reel-time{margin-left:auto;padding:5px 9px;border-radius:8px;
  background:rgba(8,8,16,.6);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}

/* The play button that used to sit here held the words down by being a flex
   spacer. With it gone the words hold themselves down instead. */
.reel-say{position:relative;display:grid;gap:3px;margin-top:auto;
  /* Clear of the sound button, which sits in the same corner. */
  padding-right:52px}
.reel-say > b{font-size:20px;font-weight:800;letter-spacing:-.025em;line-height:1.2;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.reel-say > em{font-style:normal;font-size:13.5px;line-height:1.45;
  color:rgba(255,255,255,.82);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.reel-who{display:flex;align-items:center;gap:9px;margin-top:9px;
  padding-top:10px;border-top:1px solid rgba(255,255,255,.16)}
.reel-who img,.reel-init{width:30px;height:30px;border-radius:50%;flex:none;
  object-fit:cover;border:1.5px solid rgba(255,255,255,.5)}
.reel-init{display:grid;place-items:center;font-style:normal;font-size:13px;
  font-weight:800;background:rgba(255,255,255,.2);-webkit-backdrop-filter:blur(4px);
  backdrop-filter:blur(4px)}
.reel-who b{display:block;font-size:13.5px;font-weight:700;line-height:1.25}
.reel-who em{display:block;font-style:normal;font-size:12px;
  color:rgba(255,255,255,.72)}

/* --- arrows and dots ---------------------------------------------------- */
/* The bar does not wrap and neither do the dots: with a couple of dozen clips
   a wrapping row became four stacked rows of dots at 375px. They scroll
   instead, and the script keeps the active one in view. */
.reels-bar{display:flex;align-items:center;justify-content:center;gap:6px;
  flex-wrap:nowrap;margin-top:18px}
.reels-btn{flex:none;width:44px;height:44px;border-radius:50%;
  border:1px solid var(--line,#EAEAE7);background:#fff;
  display:grid;place-items:center;cursor:pointer;color:var(--ink,#151515);
  transition:background .16s ease-out,color .16s ease-out,border-color .16s ease-out,
             box-shadow .16s ease-out}
.reels-btn:hover{background:var(--cta,#1571C6);border-color:var(--cta,#1571C6);color:#fff}

/* Wide enough to have room beside the rail: the arrows sit on the stage,
   level with the middle of the hero card, which is where a hand reaches for
   them. Below this there is no such room and they stay on the bar under the
   dots, where they do not cover the clips. */
@media(min-width:900px){
  .reels{position:relative}
  .reels-btn{position:absolute;top:calc(50% - 28px);z-index:5;
    width:48px;height:48px;
    box-shadow:0 10px 26px rgba(16,22,40,.16)}
  .reels-btn[data-reel-prev]{left:6px}
  .reels-btn[data-reel-next]{right:6px}
  .reels-btn:hover{box-shadow:0 14px 32px rgba(21,113,198,.30)}
  /* The bar is only the dots once the arrows have left it. */
  .reels-bar{margin-top:14px}
}
.reels-btn svg{width:17px;height:17px;pointer-events:none}
/* Only as wide as the dots need, so the two arrows stay beside them instead
   of being pushed out to the far edges of the section.
   One row that scrolls rather than a block that wraps: the reviews page
   loads up to two dozen clips, and at 375px those wrapped into four rows of
   dots 176px deep underneath the carousel. Below the width where they all
   fit this scrolls instead, and the player keeps the current one in view.
   position:relative so a dot's offsetLeft is measured against this strip,
   which is what that scrolling reads. */
.reels-dots{position:relative;display:flex;flex-wrap:nowrap;align-items:center;
  justify-content:flex-start;flex:0 1 auto;min-width:0;max-width:100%;
  overflow-x:auto;scroll-behavior:smooth;
  -ms-overflow-style:none;scrollbar-width:none}
.reels-dots::-webkit-scrollbar{display:none}
/* 32 wide by 44 tall. A full 44 square each would be wider than a phone once
   there are eight of them, and these rows go up to two dozen. */
.reels-dot{flex:none;width:32px;height:44px;padding:0;border:0;
  background:transparent;cursor:pointer;display:grid;place-items:center}
.reels-dot i{display:block;width:7px;height:7px;border-radius:50%;
  background:#D6D6D2;
  transition:width .24s ease-out,background .24s ease-out,border-radius .24s ease-out}
.reels-dot:hover i{background:var(--faint,#9A9A96)}
.reels-dot[aria-current="true"] i{width:24px;border-radius:4px;
  background:var(--cta,#1571C6)}

/* --- one card at a time on a phone -------------------------------------- */
@media (max-width:640px){
  .reels-track{
    /* Full width of whatever box this sits in. Both percentages resolve
       against the same parent, so the side padding comes out at zero and the
       card fills the rail exactly -- no viewport units, and so nothing that
       can disagree with the page's own padding and push a scrollbar onto the
       body at 375px. */
    --reel-w:100%;
    gap:10px;padding-block:10px 16px;
    /* With a single card showing there are no neighbours to fade, and the
       mask would only dim the edges of the one clip being watched. */
    -webkit-mask-image:none;mask-image:none}
  /* Nothing is off to the side to shrink away from, so the hero is simply
     the card you are on. */
  .reel{transform:none;opacity:1}
  .reel.near{transform:none;opacity:1}
  .reel.is-live{transform:none;
    box-shadow:var(--sh,0 14px 36px rgba(20,20,20,.1)),
               0 0 0 1px rgba(21,113,198,.22)}
  .reel-cover{padding:14px}
  .reel-say > b{font-size:18px}
}

/* --- less motion -------------------------------------------------------- */
/* No auto-advance (the JS checks this too), no scaling and no crossfade:
   what is left is a plain snapping scroller that the viewer drives. */
@media (prefers-reduced-motion:reduce){
  .reels-track,.reels-dots{scroll-behavior:auto}
  .reels-track{gap:16px;-webkit-mask-image:none;mask-image:none}
  .reel,.reel.near,.reel.is-live{transform:none;opacity:1;transition:none}
  .reel.is-live{box-shadow:var(--sh,0 14px 36px rgba(20,20,20,.1)),
                           0 0 0 1px rgba(21,113,198,.22)}
  .reel-cover,.reel-sound,.reels-btn,.reels-dot i,.reel.playing .reel-back{
    transition:none}
  .reel-sound:hover{transform:none}
  .reel.buffering .reel-stage::after{animation-duration:2.4s}
}

/* --- what these clips are, under the carousel --------------------------- */
.reels-trust{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:18px;margin-top:26px;padding-top:22px;border-top:1px solid var(--line,#EAEAE7)}
.reels-trust > div{display:flex;align-items:center;gap:12px;min-width:0}
.reels-trust > div + div{padding-left:18px;border-left:1px solid var(--line,#EAEAE7)}
.rt-ic{width:38px;height:38px;flex:none;border-radius:11px;display:grid;
  place-items:center;background:#E8F1FB;color:var(--cta,#1571C6)}
.rt-ic svg{width:18px;height:18px}
.reels-trust b{display:block;font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.reels-trust em{display:block;font-style:normal;font-size:13px;
  color:var(--ink-2,#5B5B58);margin-top:1px}
@media (max-width:860px){
  .reels-trust{grid-template-columns:1fr;gap:14px}
  .reels-trust > div + div{padding-left:0;border-left:0;padding-top:14px;
    border-top:1px solid var(--line,#EAEAE7)}
}

/* --- the ends --------------------------------------------------------- */
/* Scenery, so the rail does not show an empty shoulder when the first clip
   is the one centred. Held a step back from a real neighbour: it is a hint
   that the row carries on, not a card you are being invited to watch. */
.reel-ghost{transform:scale(.86);opacity:.5;scroll-snap-align:none;
  pointer-events:none;filter:saturate(.8)}
.reel-ghost .reel-back{opacity:1;filter:blur(1px)}
@media(prefers-reduced-motion:reduce){.reel-ghost{transition:none}}
