/* ==========================================================================
   COMPONENTS
   Reusable pieces, in the order they first appear on the page.
   Depends on: tokens.css, base.css
   ========================================================================== */

/* --------------------------------------------------------------------------
   MEDIA
   Figma crops images by over-sizing and offsetting them inside a clipping
   frame rather than by using object-fit. Those offsets are percentages of the
   frame, so they survive any viewport: each element sets --crop-* inline with
   the exact values from the design and this rule applies them.
   With no --crop-* set the image simply covers its frame.
   -------------------------------------------------------------------------- */

.media {
  position: relative;
  overflow: hidden;
}

.media__img {
  position: absolute;
  left:   var(--crop-x, 0%);
  top:    var(--crop-y, 0%);
  width:  var(--crop-w, 100%);
  height: var(--crop-h, 100%);
  max-width: none;
  /* Figma sizes the image box explicitly, so a cropped element uses `fill`
     (the percentages already carry the aspect ratio); an uncropped one
     behaves like object-fit: cover. */
  object-fit: var(--crop-fit, cover);
  object-position: var(--crop-pos, center);
}


/* --------------------------------------------------------------------------
   SITE HEADER + PRIMARY NAV
   Frame: 144px tall bar, #323237. Wordmark left, pill-shaped nav centred,
   LinkedIn mark right. Below 1024px the pill is replaced by a toggle and a
   collapsible panel.
   -------------------------------------------------------------------------- */

.site-header {
  /* Pinned: the page scrolls underneath. The bar is fully opaque, so no
     backdrop treatment is needed for content passing behind it. body carries
     a matching padding-top (base.css) to offset the space it no longer takes
     up in the flow, and html has scroll-padding-top so in-page anchors don't
     land underneath it. */
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 20;
  background-color: var(--color-surface-header);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-16);
  min-height: var(--header-height);
}

.site-header__wordmark {
  flex: 0 0 auto;
  /* Keep the wordmark a full touch target on phones without moving it. */
  display: flex;
  align-items: center;
  min-height: var(--tap-target);
  color: #fafafa;                     /* frame 715:8183 */
  font-size: var(--fs-wordmark);
  font-weight: var(--fw-medium);
  line-height: 1.125;
  letter-spacing: var(--ls-eyebrow);
  white-space: nowrap;
}

/* --- Header actions: mail · LinkedIn · menu ------------------------------
   Figma 742:15540. The frame sets 40 between the icon boxes and puts the
   group's right edge on the page margin. Each control is a 44 touch target
   with its glyph centred, so the gap between BOXES is the frame's 40 less
   the padding those targets add either side.
   ------------------------------------------------------------------------ */
.site-header__actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(0.0625rem, -0.57752rem + 2.73058vw, 1.46875rem);
  margin-inline-start: auto;
  /* The frame puts the LAST glyph's right edge on the page margin, but a 44
     target centred on a 22.5 menu icon holds it ~11 short of that. Pulling
     the group out by that padding lands the glyph on the margin without
     shrinking the target or disturbing the gaps between the icons. */
  margin-inline-end: -10.75px;
}

.site-header__mail,
.site-header__social {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  color: var(--color-text);
}

.site-header__mail-icon {
  width: 25px;
  height: 20px;
}

.site-header__mail:hover { color: var(--color-text-strong); }
.site-header__social img {
  /* The frame's revised header (node 675:11870) draws the mark at a flat 32.
     It no longer ramps: 32 is already the small end of the old 32 -> 54 range,
     so there is nothing to scale down to. The 44px touch target is held by
     the anchor's min-width/height above, not by the image. */
  width: 2rem;    /* 32 */
  height: 2rem;
  max-width: none;
}

/* --- Primary nav row (desktop up; collapses to a panel below 1200) ------ */
.primary-nav {
  flex: 1 1 auto;
  min-width: 0;
}

.primary-nav__list {
  display: flex;
  align-items: center;
  /* The frame right-aligns the items to the nav box's right edge, so the
     last one lands 60px clear of the LinkedIn mark. */
  justify-content: flex-end;
  /* Ramped across 1200 -> 1920, the range in which the row is shown. */
  gap: clamp(1.5rem, -1rem + 3.33333vw, 3rem);                /*  24 ->  48 */
  max-width: 1286px;
  min-width: 0;
  margin-inline: auto;
}

.primary-nav__link {
  display: flex;
  align-items: center;
  min-height: 66px;
  color: var(--color-text);
  font-size: var(--fs-nav);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-normal);
  text-align: center;
  white-space: nowrap;
  /* Hover / active styling arrives with the interactions phase. */
  transition: color var(--duration-fast) var(--ease);
}
.primary-nav__link:hover { color: var(--color-text-strong); }

/* --- Toggle: below the nav breakpoint only ------------------------------
   Drawn to match the frame's menu icon (742:15548): three 22.5 rules, 2.5
   thick with round caps, on a 7.5 pitch — which is what the 5px gap between
   2.5-tall bars gives.
   ------------------------------------------------------------------------ */
.nav-toggle {
  flex: 0 0 auto;
  display: grid;
  place-content: center;
  gap: 5px;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.nav-toggle__bar {
  display: block;
  width: 22.5px;
  height: 2.5px;
  border-radius: 1.25px;               /* the frame's round line caps */
  background-color: var(--color-text);
  transition: transform var(--duration) var(--ease),
              opacity   var(--duration) var(--ease);
}

/* Mobile / tablet: nav collapses into a panel under the bar. */
@media (max-width: 1199px) {
  .primary-nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    z-index: 20;
    display: none;                     /* JS flips this in phase 2 */
    padding: var(--space-8) var(--page-gutter) var(--space-24);
    background-color: var(--color-surface-header);
    border-top: var(--border-hairline) solid var(--color-border-nav);
    /* The header is fixed, so the panel hangs off it and cannot grow with
       the page. Cap it to what is left of the viewport and let it scroll,
       so no item becomes unreachable on a short screen. */
    max-height: calc(100svh - var(--header-height));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* The interactions phase toggles [data-open] on the header. */
  .site-header[data-nav-open="true"] .primary-nav { display: block; }

  .primary-nav__list {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 0;
    max-width: none;
  }
  .primary-nav__link {
    justify-content: flex-start;
    min-height: var(--tap-target);      /* touch target floor */
    padding-block: var(--space-8);
    border-bottom: var(--border-hairline) solid var(--color-border-nav);
  }

}

/* --- Below the nav breakpoint: the mobile header (Figma 742:15538) -------
   A taller bar — 114 against the desktop header's 90 — carrying the wordmark
   and the three icons and nothing else. Overriding the token means body's
   padding-top and the scroll-padding for anchors both follow it, on the home
   page and on the case studies alike.
   ------------------------------------------------------------------------ */
@media (max-width: 1199px) {
  :root {
    --header-height: 7.125rem;          /* 114 (742:15538) */
  }
}

@media (min-width: 1200px) {
  /* Only the menu goes. The mail icon has replaced the row's "Get in touch"
     item (frame 715:8183), so it is shown at every width now. */
  .nav-toggle { display: none; }

  /* Frame 715:8183 across the 1760 content box: the wordmark sits left and
     the cluster is hard against the right margin -
       nav row (658 at its natural width) | 41 | mail 30 | 38 | LinkedIn 32
     The icon anchors stay 44px touch targets with their glyphs centred, so
     the gaps between BOXES are the frame's gaps less the padding those
     targets add: 41 - 9.5 = 34 before the group, 40.5 - 9.5 - 6 = 25 inside
     it, and the trailing target overhangs the margin by 6. */
  .site-header__inner {
    display: flex;
    align-items: center;
    gap: 34px;
  }
  .site-header__wordmark { flex: 0 0 auto; }
  .primary-nav { flex: 0 0 auto; margin-inline-start: auto; }
  .primary-nav__list { max-width: none; margin-inline: 0; }
  .site-header__actions {
    flex: 0 0 auto;
    margin-inline-start: 0;
    gap: 25px;
    margin-inline-end: -6px;
  }

}


/* --------------------------------------------------------------------------
   WORK CARD
   440 x 310 in the frame (aspect 44:31), no border - frame D draws all six
   cards edge to edge. Each card is a single flattened image; the project name
   appears only on hover, consistently across all six.
   -------------------------------------------------------------------------- */

.work-card {
  position: relative;
  display: block;
  /* Sizes the hover overlay against the card, not the viewport, so the
     composition stays exactly as drawn at any card width. */
  container-type: inline-size;
  aspect-ratio: 440 / 310;
  overflow: hidden;
  background-color: var(--color-bg);
}

.work-card__media { position: absolute; inset: 0; }


/* --------------------------------------------------------------------------
   WORK CARD - HOVER OVERLAY
   Frame 675:11185 ("SELECTION behaivior"): a rgba(0,0,0,0.7) veil over the
   whole 440x310 card with the project name and a short descriptor centred on
   it. Title 20/25 bold at -0.92 tracking, descriptor 14/22 regular, with a
   blank 25px line between them.

   Sizes are given in cqw against the 440px card (20/440 = 4.5455cqw) so the
   overlay scales with the card, with a floor so it stays legible on the
   narrower cards at 1024. Hover is gated on a real pointer, so it never
   fires on touch; :focus-visible mirrors it for keyboard users.
   -------------------------------------------------------------------------- */

.work-card__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5%;
  background-color: var(--color-card-veil);
  opacity: 0;
  transition: opacity var(--duration) var(--ease);
}

.work-card__overlay-inner {
  width: max(var(--overlay-w, 50cqw), 150px);
  color: var(--color-text-strong);
  text-align: center;
}

.work-card__project {
  display: block;
  font-size: max(0.875rem, 4.5455cqw);   /* 20 at a 440 card */
  font-weight: var(--fw-bold);
  line-height: 1.25;                     /* 25 / 20 */
  letter-spacing: -0.046em;              /* -0.92 at 20 */
  text-transform: uppercase;
}

.work-card__desc {
  display: block;
  margin-top: max(0.75rem, 5.6818cqw);   /* the frame's blank 25px line */
  font-size: max(0.6875rem, 3.1818cqw);  /* 14 at a 440 card */
  font-weight: var(--fw-regular);
  line-height: 1.5714;                   /* 22 / 14 */
  letter-spacing: normal;
}

.work-card__note {
  display: block;
  margin-top: max(0.75rem, 5.6818cqw);
  font-size: max(0.6875rem, 3.1818cqw);
  font-weight: var(--fw-bold);
  line-height: 1.5714;
  text-transform: uppercase;
}

@media (hover: hover) and (pointer: fine) {
  .work-card:hover .work-card__overlay { opacity: 1; }
}

/* Keyboard parity - deliberately outside the hover query. */
.work-card:focus-visible .work-card__overlay { opacity: 1; }

/* "VIBE CODING" is set a step smaller than the other five labels - 17 against
   a 440 card in frame 734:10415, where the rest are 20. */
.work-card__project--sm { font-size: max(0.75rem, 3.8636cqw); }


/* --------------------------------------------------------------------------
   ABILITY
   Title + body with a hairline rule to the left of the body copy.
   In the frame the rule is a fixed 132px starting 46px down - i.e. it brackets
   the body paragraph, not the title. Tying it to the paragraph box reproduces
   that relationship at any width instead of freezing two pixel values.
   -------------------------------------------------------------------------- */

.ability {
  padding-inline-start: var(--space-14);
}

.ability__title {
  margin: 0;
  color: var(--color-text);
  font-size: var(--fs-title);
  font-weight: var(--fw-regular);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
}

.ability__body {
  position: relative;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
}
.ability__body::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(var(--space-14) * -1);
  width: var(--border-thin);
  background-color: var(--color-rule-ability);
}


/* --------------------------------------------------------------------------
   STAT  (inside the impact panel)
   -------------------------------------------------------------------------- */

.stat { min-width: 0; }

.stat__figure {
  display: block;
  color: var(--color-text);
  font-size: var(--fs-stat);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-stat);
}

.stat__detail {
  margin: var(--space-16) 0 0;
  color: var(--color-text-muted);
  font-size: var(--fs-ui);
  font-weight: var(--fw-regular);
  line-height: 1.25;                 /* 16 / 20 */
  letter-spacing: var(--ls-stat-meta);
}

.stat__brand {
  display: block;
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
}


/* --------------------------------------------------------------------------
   BRAND ROW
   A label, then a row of logos. Logo boxes keep the frame's exact aspect
   ratios; --logo-scale steps them down on smaller screens.
   -------------------------------------------------------------------------- */

.brand-group + .brand-group { margin-top: var(--section-gap); }

/* The start-up row is 52px label-top to logo-top in the frame, not 56. */
.brand-group--tight .brand-group__label { margin-bottom: 4px; }

/* The frame gives the label a 48px box with its 26px line centred inside,
   then only 8px before the logo row - so label-top to logo-row-top is 56. */
.brand-group__label {
  display: flex;
  align-items: center;
  min-height: 48px;
  margin: 0 0 8px;
  color: var(--color-text-muted);
  font-size: var(--fs-brand-label);
  font-weight: var(--fw-medium);
  line-height: var(--lh-brand);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
}

.brand-group__logos {
  --logo-scale: 0.55;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--brand-gap);
  min-height: 75px;
}

/* Each logo sets --logo-w (frame width in px) and --logo-ar (w / h). */
.brand-logo {
  position: relative;
  flex: 0 0 auto;
  width: calc(var(--logo-w) * var(--logo-scale) * 1px);
  aspect-ratio: var(--logo-ar);
  overflow: hidden;
}
.brand-logo__img {
  position: absolute;
  left:   var(--crop-x, 0%);
  top:    var(--crop-y, 0%);
  width:  var(--crop-w, 100%);
  height: var(--crop-h, 100%);
  max-width: none;
  object-fit: var(--crop-fit, cover);
  object-position: var(--crop-pos, center);
}

/* The WayFinder lockup is a mark plus live text, not an image. */
.brand-lockup {
  display: flex;
  align-items: center;
  gap: var(--space-8);
}
.brand-lockup__mark {
  width: calc(44 * var(--logo-scale) * 1px);
  height: auto;
}
.brand-lockup__name {
  color: var(--color-accent-yellow);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--fw-medium);
  line-height: var(--lh-normal);
  white-space: nowrap;
}
.brand-lockup__name em {
  font-style: normal;
  font-weight: var(--fw-light);
}

/* Short vertical divider closing each logo row in the frame. Drawn as a
   pseudo-element so it is not announced as a list item. */
.brand-group__logos::after {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: 1px;
  height: 16px;
  background-color: var(--color-divider);
  opacity: 0.5;
}

@media (min-width: 768px)  { .brand-group__logos { --logo-scale: 0.75; } }
@media (min-width: 1024px) { .brand-group__logos { --logo-scale: 0.85; } }
@media (min-width: 1440px) { .brand-group__logos { --logo-scale: 1;    } }


/* --------------------------------------------------------------------------
   RECOMMENDATION CARD
   407 x 336, 32px padding, 16px radius. Quote fills the top; the author
   block is pinned to the bottom above a hairline rule.
   -------------------------------------------------------------------------- */

.rec-card {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  height: 336px;
  padding: var(--space-32);
  border-radius: var(--radius-card);
  background-color: var(--color-surface-card);
  /* The frame's 1px edge is drawn as an inset ring rather than a border.
     A real border would come out of the 336px border-box and leave the
     quote 270px of room where the frame allots it 272, which was enough to
     chop the last line off the longest card. */
  box-shadow: var(--shadow-card),
              inset 0 0 0 var(--border-thin) var(--color-border-panel);
}

/* The rail's list items carry the track sizing; the card fills its item. */
.rec-rail > li {
  display: flex;
  flex: 0 0 min(85vw, 407px);
  scroll-snap-align: start;
}

.rec-card__quote {
  flex: 1 1 auto;
  min-height: 0;
  /* Not clipped. The frame doesn't clip either - its longest quote runs a
     fraction past the slot and simply sits in the 16px gap above the rule.
     Clipping here removed the descenders from that card's last line. */
  margin: 0;
  color: var(--color-text);
  font-size: var(--fs-ui);
  font-style: italic;
  font-weight: var(--fw-regular);
  line-height: var(--lh-quote);
  letter-spacing: var(--ls-quote);
}

/* Placeholder for the expand affordance; wired up in the interactions phase. */
.rec-card__more {
  color: var(--color-link-more);
  font-style: italic;
}

.rec-card__author {
  display: flex;
  flex: 0 0 auto;
  align-items: flex-start;
  gap: var(--space-16);
  padding-top: var(--space-16);
  border-top: var(--border-hairline) solid var(--color-rule-card);
}

.rec-card__avatar {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-avatar);
  object-fit: cover;
}

.rec-card__meta { min-width: 0; }

.rec-card__name {
  margin: 0;
  color: var(--color-text);
  font-size: var(--fs-ui);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-name);
  letter-spacing: var(--ls-quote);
  text-transform: uppercase;
}

.rec-card__role {
  margin: var(--space-2) 0 0;
  color: var(--color-text-meta);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  line-height: var(--lh-role);
  letter-spacing: var(--ls-quote);
}


/* --------------------------------------------------------------------------
   MEDIA — MULTIPLY
   Two of the case-study diagrams are drawn in Figma with a multiply blend so
   their white paper drops out against the band behind them. Reproduced as a
   modifier rather than baked into the asset, so the same file works on any
   background.
   -------------------------------------------------------------------------- */

.media--multiply .media__img { mix-blend-mode: multiply; }


/* --------------------------------------------------------------------------
   CASE-STUDY NAV
   The second bar, shown only on a case-study page and pinned directly under
   the primary header. Frame nodes 687:5076 (the bar) and 687:5077 (the row).

     bar        1920 x 51, #FAFAFA — the page colour, so it reads as a strip
                of the page held under the dark header rather than as chrome
     labels     Inter Semi Bold 14, #454545, 48px gap, centred in the bar
     placement  the row's right edge lands on 1726 at 1920, level with the
                header nav's right edge above it
     selected   an underline. The frame draws no marker for the current page
                at all (the outlined pill it used to carry was deleted), so
                this is Mike's, not the frame's.

   It lives INSIDE .site-header so both bars are pinned by the same fixed
   ancestor — everything on the page scrolls under the pair — and so the
   collapsed mobile nav panel (positioned at top:100% of .site-header) drops
   below both rather than on top of this one.
   -------------------------------------------------------------------------- */

.case-nav {
  background-color: var(--cs-subnav-bg);
}

.case-nav__inner {
  display: flex;
  align-items: center;
  min-height: var(--cs-subnav-h);
  /* Below the nav breakpoint the five labels are wider than the bar, so it
     scrolls sideways rather than wrapping or shrinking the type. The page
     itself never scrolls horizontally (base.css). */
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.case-nav__inner::-webkit-scrollbar { display: none; }

.case-nav__list {
  display: flex;
  align-items: center;
  gap: var(--cs-subnav-gap);
  min-width: max-content;    /* keeps the labels on one line while scrolling */
}

.case-nav__link {
  display: flex;
  align-items: center;
  /* Full touch target without moving the label off the bar's centre line.
     The bar is 51 tall at 1920, so the target overhangs it slightly rather
     than forcing it taller than the frame draws it. */
  min-height: var(--tap-target);
  color: var(--cs-subnav-ink);
  font-size: var(--fs-nav);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-normal);
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration-thickness: var(--cs-subnav-underline);
  text-decoration-color: var(--cs-subnav-underline-ink);
  /* The frame draws its rule 7px under the baseline (glyphs end at y=119,
     Line 1087 sits at y=127). */
  text-underline-offset: 7px;
  transition: color var(--duration-fast) var(--ease);
}

a.case-nav__link:hover {
  color: var(--cs-ink);
  text-decoration-line: underline;
}

/* The project this page is. A <span>, not a link — there is nowhere for it to
   go — carrying the underline that marks it as selected. The frame keeps every
   label at --cs-subnav-ink; only the rule marks the current one. */
.case-nav__link--current {
  text-decoration-line: underline;
}

/* At the frame's own width the row sits where the frame puts it. Below the
   nav breakpoint the bar scrolls, so it starts from the left instead. */
@media (min-width: 1200px) {
  .case-nav__list {
    margin-inline-start: auto;
    margin-inline-end: var(--cs-subnav-inset-end);
  }
}


/* --------------------------------------------------------------------------
   CASE-STUDY QUOTE BLOCK
   The frame opens ROLE, BOARDING APP and IPAD STAND & TARGET with a rule set
   10px inside the content edge and the copy 9px clear of it.
   -------------------------------------------------------------------------- */

.cs-quote {
  margin: 0 0 0 10px;
  padding-block: 6px;
  padding-inline-start: var(--cs-quote-inset);
  border-inline-start: var(--cs-quote-rule) solid var(--cs-rule);
  color: var(--cs-ink);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.cs-quote p + p { margin-top: var(--lh-body); }

/* IPAD STAND & TARGET only. The frame used to give this one block a solid 20px
   black slab outboard of its rule; that has been removed and its rule is now
   the same 3px #282626 hairline as the other two. What remains particular to
   it is the copy colour — pure black rather than #2F2E2E, still true in the
   frame (sampled off its render, not read off the node). */
.cs-quote--strong {
  color: var(--cs-ink-strong);
}


/* --------------------------------------------------------------------------
   CASE-STUDY FIGURE
   A media frame with a caption under it. Used for the hero photograph, the
   four app screens and the three iPad-stand photographs.
   -------------------------------------------------------------------------- */

.cs-figure { margin: 0; }

.cs-figure__caption {
  margin-top: var(--cs-hero-caption-gap);
  color: var(--cs-ink);
  font-size: var(--fs-cs-caption-sm);
  font-weight: var(--fw-regular);
  line-height: var(--lh-cs-caption-sm);
}

.cs-figure__caption--lg {
  font-size: var(--fs-cs-caption);
  line-height: var(--lh-cs-caption);
}

/* The frame emphasises two runs inside the BOARDING APP quote at different
   weights — Semi Bold for the headline result, Bold for the feature lead-in. */
.cs-quote strong          { font-weight: var(--fw-bold); }
.cs-quote .cs-quote__semi { font-weight: var(--fw-semibold); }


/* --------------------------------------------------------------------------
   VIDEO
   A clip that fills its slot exactly the way an image would, with the three
   controls Mike asked for laid over the foot of it: play/pause, a scrubbable
   progress bar, and elapsed/total time.

   Not in the Figma frame — the frame draws the clip's poster frame and
   nothing else — so the control bar is composed from existing tokens and
   overlaid rather than given its own space, which keeps the frame's layout
   untouched.
   -------------------------------------------------------------------------- */

.video {
  position: relative;
  overflow: hidden;
  background-color: var(--color-bg);
}

.video__el {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Control bar -------------------------------------------------------- */

.video__controls {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-8) var(--space-16);
  /* A scrim, so white controls hold up over a bright frame of the clip. */
  background-image: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.55),
    rgba(0, 0, 0, 0)
  );
}

.video__toggle {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text-strong);
  cursor: pointer;
}

.video__icon { width: 24px; height: 24px; }

/* Which glyph shows is driven by the state on the wrapper, so the button's
   markup never changes and its accessible name is the only thing JS swaps. */
.video__icon--pause { display: none; }
.video[data-playing="true"] .video__icon--play  { display: none; }
.video[data-playing="true"] .video__icon--pause { display: block; }

/* --- Mute ----------------------------------------------------------------
   A clip has to load muted or it will not autoplay - every browser blocks
   audible autoplay - so this is how a reader turns the sound on. Only on
   pages whose clip has an audio track worth hearing; main.js tolerates the
   button being absent.
   ------------------------------------------------------------------------ */

.video__mute {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text-strong);
  cursor: pointer;
}

/* Same trick as the play/pause pair: the state lives on the wrapper, so the
   button's markup never changes and its accessible name is the only thing JS
   swaps. Muted is the default, so the crossed-out speaker is what shows until
   the wrapper says otherwise. */
.video__icon--unmuted { display: none; }
.video[data-muted="false"] .video__icon--muted   { display: none; }
.video[data-muted="false"] .video__icon--unmuted { display: block; }

.video__time {
  flex: 0 0 auto;
  margin: 0;
  color: var(--color-text-strong);
  font-size: var(--fs-nav);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* --- Scrubber ------------------------------------------------------------
   A real <input type="range">, so keyboard seeking, screen-reader semantics
   and touch dragging all come for free. --p is the played fraction, set by
   js/main.js, and paints the filled part of the track.
   ------------------------------------------------------------------------ */

.video__scrub {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--tap-target);      /* full-height grab area, hairline track */
  margin: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
}

.video__scrub:focus { outline: none; }
.video__scrub:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* WebKit / Blink */
.video__scrub::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background-image: linear-gradient(
    to right,
    var(--color-text-strong) 0 calc(var(--p, 0) * 100%),
    rgba(255, 255, 255, 0.35) calc(var(--p, 0) * 100%) 100%
  );
}
.video__scrub::-webkit-slider-thumb {
  -webkit-appearance: none;
          appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -4px;               /* centres the 12px thumb on the 4px track */
  border: 0;
  border-radius: 50%;
  background-color: var(--color-text-strong);
}

/* Firefox */
.video__scrub::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background-color: rgba(255, 255, 255, 0.35);
}
.video__scrub::-moz-range-progress {
  height: 4px;
  border-radius: 2px;
  background-color: var(--color-text-strong);
}
.video__scrub::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background-color: var(--color-text-strong);
}
