/* =========================================================================
   UI Video Snippets — /UI-Video-Snippets
   Figma: CW / 1694:1121 "Frame 2147223629" (1919 × 11621)

   Eleven blocks, all 1440 wide, all drawn at one width. Rather than give
   every number its own clamp(), the card is a container and one unit is
   derived from it:

       --u: calc(1cqw / 14.4)

   1cqw is a hundredth of the card, so at the frame's 1440 the unit is
   exactly 1px and `calc(48 * var(--u))` is the frame's 48. Below 1440 the
   whole block scales as one drawing — no value drifts against another,
   which is what a per-value clamp() cannot promise. Under 1024 the columns
   stack and the type leaves the unit behind, because a proportional 1440
   at phone width is a 13px heading.

   Two things worth knowing before reading:

   **The film carries its own background.** The colour behind the app UI is
   part of the recording, which is why the stage under a film is painted only
   as a resting state — what you see before a file lands, not something the
   film sits on. The frame draws group 1 in four colours from one walkthrough;
   the films that arrived share one ground, so --grade is the same on all of
   them and the group varies by layout instead.

   **Nothing is centred that the frame does not centre.** The film is pinned
   to the stage's top-left corner and allowed to run off the far edge. The
   crop is the design: the app UI has to read as a window onto something
   larger than the panel.
   ========================================================================= */

.page-snips {
  background: var(--snip-page);
  color: var(--snip-ink);

  /* the frame's palette */
  --snip-page:  #272727;   /* the artboard the blocks sit on — not the
                              frame's #dfeaed; asked for, so that the light
                              cards read as objects laid on a surface */
  --snip-card:  #fcfaf5;   /* Core White — the card under both halves */
  --snip-ink:   #02030b;   /* Text/primary */
  --snip-blue:  #0541e9;
  --snip-rule:  rgba(2, 3, 11, .2);   /* the hairlines in group 2 */
  --snip-edge:  rgba(2, 3, 11, .3);   /* the outline button */

  /* Opening a film in group 3: eased at both ends, the same .7s the /video
     page's cards take, so the two pages feel like one machine. */
  --snip-ease:  cubic-bezier(.5, 0, .2, 1);
  --snip-open:  .7s;
}

/* ------------------------------------------------------------- the page -- */
/* The frame puts its title at y185 and each group's number roughly 100 above
   the first of its blocks. Between groups it leaves 340. */
.snips {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 100px;
  padding: 185px var(--gutter) 200px;
}

/* White, because these are the only headings on the page that sit on the
   artboard rather than inside a card. The blocks keep their own ink: they are
   the thing being shown, and their colour is part of it. */
.snips__title,
.snips__num {
  width: min(1440px, 100%);
  font-family: var(--sans);
  font-weight: 600;
  font-size: clamp(30px, 3.334vw, 48px);
  line-height: 1.084;
  color: var(--white);
  text-box: trim-both cap alphabetic;
}

/* Every prototype carries its own number, and the number belongs to the block
   under it: the flex gap gives it 100 above and the -30 takes it to 70 below,
   so it reads as a label on the block rather than as something floating
   between two of them.

   --group is the first of each three — 1a, 2a, 3a — and it is the only one
   that carries the air between the groups. `:first-of-type` is 1a, which
   follows the page title and needs none of it; the pseudo-class outweighs
   --group on its own, so the order of these two lines does not matter. */
.snips__num               { margin: 0 0 -30px; }
.snips__num--group        { margin-top: 240px; }
.snips__num:first-of-type { margin-top: 40px; }

/* ------------------------------------------------------------- the card -- */
/* One caveat about the unit, because it decides how this file is written: a
   container cannot query itself. Inside .snip's own declarations 1cqw would
   resolve against the nearest container *above* it — there is none, so it
   would fall back to the viewport and the card would come out 42px too tall
   at 1520. Descendants are fine; they see .snip.

   So the card's own box is given without --u — aspect-ratio for the split
   blocks, and the padding that would have gone here is handed down to
   .snip__head and .snip__row, which can measure it. --u is declared here
   only so that everything below inherits it. */
.snip {
  container-type: inline-size;
  --u: calc(1cqw / 14.4);

  position: relative;
  width: min(1440px, 100%);
  background: var(--snip-card);
  color: var(--snip-ink);
  font-family: var(--sans);
}

/* --------------------------------------------------- group 1 + 3: split -- */
/* Two halves of the card, not two contents: opening a group-3 film animates
   these two widths and nothing inside either one reflows. Which is what the
   inner box is for — see the note on .snip__copy-in. */
/* 680 rather than the frame's 760. The card is one ratio and everything in it
   is measured off that, so this is the only place the height is written down:
   the copy keeps its 40 corner, the films keep their own proportion and re-crop
   to the new height on their own, and only group 3's two fixed boxes below had
   to be worked out again. */
.snip--split {
  display: flex;
  align-items: stretch;
  aspect-ratio: 1440 / 680;
  overflow: clip;
}

/* Blocks 2 and 4 hang the film on the left. Only the row direction turns
   over; the copy stays first in the source, where a reader wants it. */
.snip--flip { flex-direction: row-reverse; }

.snip__copy {
  flex: 0 0 50%;
  min-width: 0;
  position: relative;
  background: var(--white);
  transition: flex-basis var(--snip-open) var(--snip-ease),
              opacity .3s ease;
}

/* The copy is measured against the card, not against the column it is in.
   A flex item will not go below its own longest word, so a column that is
   closing would rewrap the text — which reads as the words being squeezed
   rather than passed by. Half the card (50cqw) holds the width it was laid
   out at while the column closes over it. */
.snip__copy-in {
  position: absolute;
  left: calc(40 * var(--u));
  top:  calc(40 * var(--u));
  width: calc(587 * var(--u));
  max-width: calc(50cqw - 80 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(40 * var(--u));
}

.snip__h {
  font-weight: 600;
  font-size: calc(48 * var(--u));
  line-height: calc(52 * var(--u));
  text-box: trim-both cap alphabetic;
}

.snip__p {
  width: calc(504 * var(--u));
  max-width: 100%;
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: calc(28 * var(--u));
  text-box: trim-both cap alphabetic;
}

/* ------------------------------------------------------------ the stage -- */
/* Black under the film, as the frame has it, with --grade painted over it as
   the resting state: the grading the film would arrive with. When the file
   lands it covers this completely. */
.snip__stage {
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
  overflow: clip;
  background: var(--grade, var(--black));
}

.snip__film {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Group 1: the film takes the stage's full height and keeps its own ratio,
   so the crop is horizontal and nothing is lost off the top or the bottom.
   That is what the frame does — its film node is 1350 × 759, which is a 16:9
   recording at the card's height and not a box the film was fitted into — and
   it is what the choice of edge below is about.

   --film-ar comes off each block, so the width is known before the file has
   loaded and the stage does not resize under the film when it arrives. */
.snip__stage--bleed .snip__film {
  width: auto;
  max-width: none;
  height: 100%;
  aspect-ratio: var(--film-ar, 1350 / 759);
}

/* Which edge the film is hung from is a per-film decision, not a per-layout
   one: the block shows 720 of a film that is 1080 or more wide, so the edge
   picks which 720. Left is the default and the frame's; --right is for a
   recording whose subject sits in the right of its own frame, where anchoring
   left would frame empty ground.

   It reads the same on a block that opens, and does one more thing there: the
   film's right edge is already the card's, so opening moves only the far side
   of the picture. */
.snip__stage--right .snip__film { left: auto; right: 0; }

/* Group 3, the two states of one card.

   The frame sizes these off a screenshot — 1084 × 761 closed, 1440 × 1011
   open — and a screenshot is 1.42 where the films that arrived are 16:9. Held
   to the frame's boxes they would be cropped twice over: once by object-fit
   to reach 1.42, and again by the stage. So the boxes are rebuilt at the
   film's own ratio and pinned to the two things the frame actually decides —
   closed, the film is the height of the card; open, it is the width of it.

   Closed  680 tall → 1209 wide, of which the half-card shows 720.
   Open   1440 wide →  810 tall, 130 more than the card, centred by the -65.

   Both are 16:9, so the move is one scale and a rise: the picture grows into
   the space the copy leaves rather than re-cropping halfway. Both also cover
   the stage outright, which is what keeps the mesh — baked into the recording
   — from meeting the mesh drawn under it. */
.snip__stage--mesh .snip__film {
  width:  83.9506cqw;  /* 1209 */
  height: 47.2222cqw;  /*  680 */
  top: 0;
  transition: width var(--snip-open) var(--snip-ease),
              height var(--snip-open) var(--snip-ease),
              top var(--snip-open) var(--snip-ease);
}

.snip--opens[data-state="open"] .snip__copy {
  flex-basis: 0%;
  opacity: 0;
}

.snip--opens[data-state="open"] .snip__stage--mesh .snip__film {
  width:  100cqw;      /* 1440 */
  height: 56.25cqw;    /*  810 */
  top: -4.5139cqw;     /*  -65 */
}

/* ---------------------------------------------------------- the control -- */
/* A 48 disc at 24 from the corner — 8 off the frame's 56, and the corner it
   sits in unchanged.

   The offsets are not 24 because the disc is not the file. Each export is 72
   square with the disc drawn at 8 from its left and 12 up from its bottom, the
   rest being the room the shadow needs. So the box is the file, scaled by
   48/56, and the padding baked into it — 6.857 and 10.286 once scaled — comes
   back out of the offsets to leave the disc itself on 24. */
.snip__max {
  position: absolute;
  left:   calc(17.1429 * var(--u));  /* 24 − 8 × 48/56  */
  bottom: calc(13.7143 * var(--u));  /* 24 − 12 × 48/56 */
  width:  calc(61.7143 * var(--u));  /* 72 × 48/56      */
  height: calc(61.7143 * var(--u));
  display: block;
  z-index: 2;
}

.snip__ico {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity .3s ease, transform .3s var(--snip-ease);
}

.snip__ico--min,
[data-state="open"] .snip__ico--max { opacity: 0; }
[data-state="open"] .snip__ico--min { opacity: 1; }

.snip__max:hover .snip__ico { transform: scale(1.08); }

/* --------------------------------------------------- before and after -- */
/* The block the page opens on: three pairs, one under another, on the page's
   own ground. No card and no frame around the media — see the note in the
   markup — so the only things this needs to set are the two columns, the
   label over each and the air between the pairs.

   It carries its own --u for the same reason .snip does: the numbers below
   are the 1440 layout's, and a container cannot query itself, so the unit is
   declared here and read only by the descendants. */
.ba {
  container-type: inline-size;
  --u: calc(1cqw / 14.4);

  width: min(1440px, 100%);
  display: flex;
  flex-direction: column;
  gap: calc(60 * var(--u));
  font-family: var(--sans);
  /* This block has no card under it, so its BEFORE/AFTER labels are on the
     artboard with the page's headings and take the artboard's colour, not the
     ink the cards use. */
  color: var(--white);
}

/* Tops aligned, not centres: the two sides of a pair are different heights by
   design, and a shared top edge is what lets the eye read across them. */
.ba__pair {
  display: flex;
  align-items: flex-start;
  gap: calc(20 * var(--u));
}

.ba__side {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--u));
}

.ba__label {
  font-family: var(--mono);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: calc(18 * var(--u));
  text-transform: uppercase;
  opacity: .5;
  text-box: trim-both cap alphabetic;
}

/* The ratio is written on each element rather than here — the six assets have
   six of them — so the space is held before a file has loaded and the row
   does not jump when it does. */
.ba__media {
  display: block;
  width: 100%;
  height: auto;
}

/* ------------------------------------------------------ group 2: ruled -- */
/* The card is white edge to edge and everything is held inside it: 60 of card
   padding top and bottom, 60 down each side, 20 between the columns. The copy
   sits inside a hairline above and a hairline below and carries its own 40,
   which is why its heading starts 100 in from the card. */
.snip--bound {
  background: var(--white);
}

/* 100 = the card's own 60 plus the row's 40; 120 = the card's 60 plus the
   row's. Both belong to the card in the frame and are carried here because
   the card cannot measure its own unit — see the note on .snip. */
.snip__row {
  display: flex;
  align-items: stretch;
  gap: calc(20 * var(--u));
  padding: calc(100 * var(--u)) calc(60 * var(--u)) calc(120 * var(--u));
}

.snip__ruled {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--snip-rule);
}

.snip__pane {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: calc(40 * var(--u));
  padding: calc(60 * var(--u)) calc(40 * var(--u));
  border-bottom: 1px solid var(--snip-rule);
  overflow: clip;
}

.snip__text {
  display: flex;
  flex-direction: column;
  gap: calc(40 * var(--u));
}

.snip__h2 {
  font-weight: 500;
  font-size: calc(64 * var(--u));
  line-height: calc(62 * var(--u));
  letter-spacing: -.03em;
  text-box: trim-both cap alphabetic;
}

.snip__ps {
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: calc(24 * var(--u));
  letter-spacing: -.02em;
  text-box: trim-both cap alphabetic;
}

/* The film box is a fixed 650 with the row's 60 to spare on its right. Its
   height is the block's one variable: 385, then 560, and the copy beside it
   does not change — the taller box simply crops more off the film's sides. */
.snip__box {
  flex: 0 0 auto;
  width: calc(650 * var(--u));
  align-self: center;
}

.snip__box--short { height: calc(385 * var(--u)); }
.snip__box--tall  { height: calc(560 * var(--u)); }
.snip__box--full  { align-self: stretch; }

.snip__box .snip__stage { height: 100%; }

/* Inside a box the film fills it and is cropped by it, rather than being
   pinned to a corner and running off. */
.snip__film--cover {
  width: 100%;
  height: 100%;
}

/* Same decision as --right two groups up — which part of the recording the
   crop keeps — made the way an object-fit crop is made rather than by moving
   the element. `cover` takes its loss out of both sides equally; --left hangs
   the film on the box's left edge, so the whole of the left of the frame is
   kept and all of the loss is on the right.

   2b and 2c carry it: their boxes are 560 and 547 tall against a 650 width,
   narrower than the film, so the crop they take is sideways. 2a does not —
   its box is wider than the film, so it crops off the top and the bottom and
   an edge here would mean nothing. */
.snip__stage--left .snip__film--cover { object-position: left center; }

/* ------------------------------------------------------- group 2, third -- */
.snip__head {
  display: flex;
  flex-direction: column;
  gap: calc(40 * var(--u));
  padding: calc(120 * var(--u)) calc(60 * var(--u));
}

.snip__eyebrow {
  display: flex;
  align-items: flex-start;
  gap: calc(10 * var(--u));
  font-family: var(--mono);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: calc(18 * var(--u));
}

.snip__eyebrow span { text-box: trim-both cap alphabetic; }

.snip__eyebrow img {
  width:  calc(10 * var(--u));
  height: calc(10 * var(--u));
  flex: none;
}

.snip__h3 {
  max-width: calc(984 * var(--u));
  font-weight: 500;
  font-size: calc(44 * var(--u));
  line-height: calc(46 * var(--u));
  letter-spacing: -.03em;
  text-box: trim-both cap alphabetic;
}

.snip__h4 {
  font-weight: 500;
  font-size: calc(32 * var(--u));
  line-height: calc(34 * var(--u));
  letter-spacing: -.03em;
  text-box: trim-both cap alphabetic;
}

/* The third block's panes are read by their content, not given a height, so
   they carry the frame's even 40 all round instead of the 60/40 the first
   two use to hold a fixed box open. */
.snip--bound:has(.snip__head) .snip__pane { padding: calc(40 * var(--u)); }
.snip--bound:has(.snip__head) .snip__row  { padding-top: 0; }

.snip__arrow {
  display: block;
  width:  calc(44 * var(--u));
  height: calc(44 * var(--u));
}

.snip__arrow img { width: 100%; height: 100%; }

.snip__arrow:hover img { transform: scale(1.08); }
.snip__arrow img { transition: transform .3s var(--snip-ease); }

/* ----------------------------------------------------------- the button -- */
/* 44 tall, 24 either side, a 2px radius — the design system's Button, at the
   two weights the frame gives it: SemiBold filled, Bold outlined. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: calc(44 * var(--u));
  padding: 0 calc(24 * var(--u));
  border-radius: calc(2 * var(--u));
  font-size: calc(16 * var(--u));
  line-height: calc(24 * var(--u));
  letter-spacing: -.02em;
  white-space: nowrap;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.snip__btns {
  display: flex;
  flex-wrap: wrap;
  gap: calc(20 * var(--u));
}

.btn--fill {
  background: var(--snip-blue);
  color: var(--white);
  font-weight: 600;
}

.btn--fill:hover { background: #0433bc; }

/* A Figma stroke does not grow the box it is on and a CSS border does, so the
   outline is drawn as an inset shadow and the button stays 44. */
.btn--line {
  box-shadow: inset 0 0 0 1px var(--snip-edge);
  color: var(--snip-ink);
  font-weight: 700;
}

.btn--line:hover { box-shadow: inset 0 0 0 1px var(--snip-ink); }

/* ---------------------------------------------------------------- small -- */
/* Below 1024 the unit is retired: a 1440 layout scaled to a phone puts the
   heading at 13px. The columns stack, the film takes the full width at the
   ratio it was drawn in, and the type goes back to the site's own scale. */
@media (max-width: 1023px) {
  .snips { gap: 60px; padding: 100px var(--gutter) 120px; }
  .snips__num               { margin: 0 0 -20px; }
  .snips__num--group        { margin-top: 100px; }
  .snips__num:first-of-type { margin-top: 20px; }

  .snip { --u: 1px; }

  .snip--split,
  .snip--flip {
    flex-direction: column;
    aspect-ratio: auto;
  }

  .snip__copy { flex: none; }

  .snip__copy-in {
    position: static;
    width: auto;
    max-width: none;
    padding: var(--pad-48) var(--gutter);
    gap: 28px;
  }

  .snip__h  { font-size: var(--fs-h1); line-height: 1.084; }
  .snip__p  { width: auto; font-size: var(--fs-lede); line-height: 1.4; }
  .snip__h2 { font-size: var(--fs-h1); line-height: 1.084; }
  .snip__h3 { font-size: var(--fs-h2); line-height: 1.05; max-width: none; }
  .snip__h4 { font-size: var(--fs-h3); line-height: 1.06; }
  .snip__ps { font-size: var(--fs-body-m); line-height: 1.5; }
  .snip__eyebrow { font-size: var(--fs-label); }

  .btn { height: 44px; padding: 0 20px; font-size: 15px; border-radius: 2px; }
  .snip__btns { gap: 12px; }

  /* One rule for every stage: full width, and the shape of the film in it.
     The corner crops that make the desktop blocks are gone — at this width
     there is no far edge to run off, and a film cropped to 720 of itself on a
     390 screen would be unreadable — so the stage takes the film's own ratio
     and shows the whole frame. */
  .snip__stage {
    flex: none;
    width: 100%;
    aspect-ratio: var(--film-ar, 16 / 9);
    height: auto;
  }

  .snip__stage--bleed .snip__film,
  .snip__stage--mesh .snip__film,
  .snip--opens[data-state="open"] .snip__stage--mesh .snip__film {
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    left: 0;
    right: auto;
    top: 0;
  }

  .snip--opens[data-state="open"] .snip__copy { flex-basis: auto; opacity: 1; }
  .snip__max { display: none; }

  .snip__head { padding: var(--pad-48) var(--gutter) 28px; gap: 24px; }
  .snip__row  { flex-direction: column; padding: var(--pad-48) var(--gutter); gap: 0; }
  .snip--bound:has(.snip__head) .snip__row { padding-top: 0; }

  /* The :has() rule above the media query outweighs a bare .snip__pane —
     media queries carry no specificity of their own — so the override has to
     name the same selector rather than trusting source order. */
  .snip__pane,
  .snip--bound:has(.snip__head) .snip__pane { padding: 28px 0; gap: 24px; }
  .snip__box  { width: 100%; height: auto; align-self: stretch; margin-top: 28px; }
  .snip__box .snip__stage { height: auto; }
  .snip__arrow { width: 44px; height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .snip__copy,
  .snip__film,
  .snip__ico,
  .btn { transition-duration: .01ms; }
}
