/*------------------------------------------------------------------
[Services film section]

Scroll-driven frame sequence behind the home page services section.
Built on the animated-website skill's canvas engine: the page scroll
position drives a WebP frame sequence rendered to a <canvas>, and the
same remapped progress highlights each service card in turn.

Companion component: components/ServicesFilm.tsx
Frames:              public/assets/frames/{desktop,mobile}/frame-NNNN.webp
-------------------------------------------------------------------*/

/* ------------------------------------------------------------------
   1. Scroll track + sticky stage
   ------------------------------------------------------------------ */

/*
  The section is a tall scroll track; the stage inside it is sticky and
  viewport-tall. Scrolling the track is what advances the film, so the
  track height sets how much scroll the sequence consumes.
*/
.services-film {
    position: relative;
    width: 100%;
    float: left;
    /* Overridden per-breakpoint below; see the height notes there. */
    height: 420vh;
    background-color: var(--accent--color);
}

.services-film__stage {
    position: sticky;
    top: 0;
    height: 100vh;
    /* min-height guards short landscape viewports where 100vh clips the grid */
    min-height: 700px;
    width: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    /*
      Content is anchored to the lower half rather than centred: the footage
      puts the container and truck across the middle of the frame, so copy
      centred vertically would sit straight on the subject. This keeps the
      film's own action visible above the cards.
    */
    justify-content: flex-end;
    padding-bottom: clamp(28px, 5vh, 72px);
    background-color: var(--accent--color);
}

.services-film__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    z-index: 0;
}

/*
  Scrim over the film. Copy sits on sky and on the truck body across the
  sequence, so a flat wash is not enough — this is a vertical gradient that
  is heaviest at the top (headline) and bottom (cards) and lets the middle
  of the frame stay readable as footage.
*/
.services-film__scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        /*
          Heavy wash across the lower half where the headline and cards live.
          The truck cab is bright yellow and passes directly behind the cards
          during the orbit, so white text needs a hard floor under it to hold
          WCAG AA — a light scrim measured fine over sky and failed over the cab.
        */
        linear-gradient(to bottom,
            rgba(7, 41, 92, 0.78) 0%,
            rgba(7, 41, 92, 0.42) 22%,
            rgba(7, 41, 92, 0.40) 38%,
            rgba(7, 41, 92, 0.80) 56%,
            rgba(7, 41, 92, 0.93) 72%,
            rgba(7, 41, 92, 0.96) 100%);
}

.services-film__inner {
    position: relative;
    z-index: 2;
    width: 100%;
    /*
      Deliberately NOT .main-container's 1417px cap. The whole point of the
      wide-screen fix is to use the real viewport width, so this only backs
      off from the very edges and caps far higher.
    */
    max-width: 2560px;
    margin: 0 auto;
    padding: 0 clamp(20px, 3vw, 64px);
    display: flex;
    flex-direction: column;
    gap: clamp(24px, 3.2vh, 46px);
}

/* ------------------------------------------------------------------
   2. Heading
   ------------------------------------------------------------------ */

.services-film__head {
    text-align: center;
    /*
      The heading enters with the sequence rather than sitting static, so the
      section reads as one continuous motion rather than a video swapped in
      behind a fixed block.
    */
    opacity: 0;
    transform: translateY(26px);
    transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.services-film.is-started .services-film__head {
    opacity: 1;
    transform: translateY(0);
}

.services-film__eyebrow {
    display: block;
    color: var(--primary--color);
    margin-bottom: 10px;
    text-shadow: 0 1px 12px rgba(4, 20, 46, 0.9);
}

.services-film__title {
    color: var(--secondary--color);
    margin-bottom: 0;
    /*
      The headline sits straight on the footage with no card behind it, so it
      carries its own shadow rather than a panel — per the skill's guidance to
      prefer precise text shadows over a translucent rectangle behind copy.
    */
    text-shadow: 0 2px 22px rgba(4, 20, 46, 0.85), 0 1px 3px rgba(4, 20, 46, 0.6);
}

/* ------------------------------------------------------------------
   3. Card grid — the wide-screen fix
   ------------------------------------------------------------------ */

/*
  Replaces the owl carousel, which showed four cards inside .main-container's
  1417px cap and left ~45% of a wide monitor unused.

  There are only four services, so the goal is not "fit more cards" but "let
  the four use the real width". A fixed 4-column track does that: the grid
  spans the full 2560px-capped inner width and each card grows with it, which
  is what actually fills the screen. auto-fit was tried first and is wrong
  here — with four items it creates empty phantom tracks on very wide screens.
*/
.services-film__grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: clamp(14px, 1.1vw, 26px);
    align-items: stretch;
    list-style: none;
    margin: 0;
    padding: 0;
}

.services-film__card {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: clamp(18px, 1.4vw, 26px);
    border-radius: 20px;
    /*
      Tinted with the brand navy rather than plain white alpha. A white wash
      over the yellow cab turns milky and drops text contrast; the navy tint
      keeps a consistent dark base whatever passes behind it, while the blur
      still lets the footage read through.
    */
    background-color: rgba(6, 30, 66, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.16);
    backdrop-filter: blur(11px);
    -webkit-backdrop-filter: blur(11px);
    overflow: hidden;
    /*
      Resting cards stay readable — dropping to 0.42 made three of the four
      services effectively unreadable at any given scroll position, which is
      the wrong trade for a section whose job is to list services.
    */
    opacity: 0.72;
    transform: translateY(14px) scale(0.975);
    transition:
        opacity 0.55s ease,
        transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
        background-color 0.55s ease,
        border-color 0.55s ease,
        box-shadow 0.55s ease;
}

/*
  Cards that have already been passed stay legible rather than dropping back
  to the resting state — scrolling should feel like lighting a row up, not
  like a single spotlight sliding along a dark row.
*/
.services-film__card.is-passed {
    opacity: 0.86;
    transform: translateY(0) scale(1);
    background-color: rgba(6, 30, 66, 0.68);
    border-color: rgba(255, 255, 255, 0.24);
}

.services-film__card.is-active {
    opacity: 1;
    transform: translateY(-10px) scale(1);
    background-color: rgba(6, 30, 66, 0.82);
    border-color: var(--primary--color);
    box-shadow: 0 22px 48px rgba(0, 0, 0, 0.5);
}

/* Progress rail across the top of each card, filled while it is active. */
.services-film__card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background-color: var(--primary--color);
    transform: scaleX(var(--card-progress, 0));
    transform-origin: left center;
    transition: transform 0.18s linear;
}

.services-film__card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.services-film__card-title {
    color: var(--secondary--color);
    margin-bottom: 0;
    font-size: clamp(19px, 1.25vw, 26px);
    line-height: 1.25;
}

.services-film__card-icon {
    /*
      Source icons are small grey glyphs (~50px), so they are kept near their
      native size — scaling them up only exposes their low resolution.
    */
    width: clamp(30px, 1.9vw, 40px);
    height: auto;
    flex-shrink: 0;
    /* Grey artwork flattened to white for the dark film. */
    filter: brightness(0) invert(1);
    opacity: 0.7;
    transition: filter 0.55s ease, opacity 0.55s ease;
}

.services-film__card.is-active .services-film__card-icon {
    /* Recoloured to the brand yellow (#fccf3a) on the active card. */
    filter: brightness(0) saturate(100%) invert(79%) sepia(52%) saturate(720%) hue-rotate(343deg) brightness(103%) contrast(97%);
    opacity: 1;
}

.services-film__card-text {
    /* 0.88 over the navy card base clears AA for body text. */
    color: rgba(255, 255, 255, 0.88);
    border-top: 1px solid rgba(255, 255, 255, 0.18);
    padding-top: 14px;
    margin-bottom: 18px;
    font-size: clamp(14px, 0.85vw, 16px);
    line-height: 1.5;
}

.services-film__card-link {
    margin-top: auto;
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    /* 44px minimum touch target. */
    min-width: 44px;
    min-height: 44px;
    padding: 0 18px;
    border-radius: 10px;
    background-color: var(--primary--color);
    color: var(--accent--color);
    font-size: 15px;
    text-decoration: none;
    transition: background-color 0.4s ease, color 0.4s ease;
}

.services-film__card-link:hover,
.services-film__card-link:focus-visible {
    background-color: var(--secondary--color);
    color: var(--accent--color);
    text-decoration: none;
}

/* Keyboard focus must stay visible against the film. */
.services-film__card-link:focus-visible {
    outline: 3px solid var(--secondary--color);
    outline-offset: 3px;
}

/* ------------------------------------------------------------------
   4. Telemetry rail
   ------------------------------------------------------------------ */

.services-film__rail {
    display: flex;
    align-items: center;
    gap: 16px;
    color: rgba(255, 255, 255, 0.72);
    font-size: 13px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.services-film__rail-track {
    flex: 1;
    height: 2px;
    background-color: rgba(255, 255, 255, 0.22);
    position: relative;
    overflow: hidden;
}

.services-film__rail-fill {
    position: absolute;
    inset: 0;
    background-color: var(--primary--color);
    transform: scaleX(var(--film-progress, 0));
    transform-origin: left center;
}

.services-film__rail-label {
    min-width: 16ch;
    color: var(--primary--color);
}

.services-film__rail-count {
    min-width: 7ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------
   5. Responsive
   ------------------------------------------------------------------ */

/*
  Track height scales with card-row count so every card still gets its own
  slice of scroll: fewer columns means more rows means a longer track.
*/
@media screen and (min-width: 1600px) {
    .services-film {
        height: 460vh;
    }
}

@media screen and (max-width: 1199px) {
    .services-film {
        height: 400vh;
    }
}

@media screen and (max-width: 991px) {
    .services-film {
        height: 380vh;
    }

    .services-film__stage {
        min-height: 640px;
    }

    .services-film__grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media screen and (max-width: 575px) {
    .services-film {
        height: 340vh;
    }

    /*
      Phones get the film at the top and the list below it, rather than the
      desktop's full-bleed overlay: four stacked full cards plus a heading do
      not fit in one viewport, and letting them overflow clipped both the
      heading and the first card.
    */
    .services-film__stage {
        min-height: 0;
        justify-content: flex-end;
        padding-bottom: 18px;
    }

    .services-film__inner {
        padding: 0 14px;
        gap: 12px;
    }

    /*
      The desktop headline is clamp(…, 66px); at 390px it wrapped to five
      lines and pushed the film out of view. Scaled down so the footage keeps
      roughly the top third of the screen.
    */
    .services-film__title {
        font-size: 26px;
        line-height: 1.16;
    }

    .services-film__eyebrow {
        font-size: 13px;
        margin-bottom: 6px;
    }

    /* The template hard-breaks this line for desktop width; let it reflow. */
    .services-film__title br {
        display: none;
    }

    /*
      padding-bottom keeps the last card clear of the template's fixed
      back-to-top button, which otherwise sits on top of its text.
    */
    .services-film__grid {
        grid-template-columns: 1fr;
        gap: 8px;
        padding-bottom: 26px;
    }

    /*
      Compact cards: title and icon on one row, supporting line beneath, and
      the whole card is the tap target so each one costs ~78px instead of
      ~190px. That fits all four plus the heading inside 100vh.
    */
    .services-film__card {
        padding: 11px 14px;
    }

    /* Content sits above the stretched link overlay defined below. */
    .services-film__card-top,
    .services-film__card-text {
        position: relative;
        z-index: 1;
        pointer-events: none;
    }

    .services-film__card-top {
        margin-bottom: 6px;
    }

    .services-film__card-title {
        font-size: 17px;
    }

    .services-film__card-icon {
        width: 24px;
    }

    .services-film__card-text {
        border-top: none;
        padding-top: 0;
        margin-bottom: 0;
        font-size: 13px;
        line-height: 1.4;
    }

    /*
      The visible button is dropped for space and the link is stretched over
      the whole card instead — a tap area far above the 44px minimum. The
      label text is kept (not font-size:0) and clipped to a screen-reader-only
      box so the link keeps its accessible name.
    */
    .services-film__card-link {
        position: absolute;
        inset: 0;
        margin: 0;
        min-height: 0;
        min-width: 0;
        padding: 0;
        border-radius: 20px;
        background-color: transparent;
        /* Keeps the name readable to assistive tech without showing the chip. */
        color: transparent;
        overflow: hidden;
    }

    .services-film__card-link .fa-angle-right {
        display: none;
    }

    .services-film__card-link:hover {
        background-color: rgba(252, 207, 58, 0.14);
    }

    .services-film__card-link:focus-visible {
        outline: 3px solid var(--primary--color);
        outline-offset: -3px;
        background-color: rgba(252, 207, 58, 0.14);
    }

    .services-film__rail-label {
        min-width: auto;
        font-size: 11px;
    }

    .services-film__rail-count {
        display: none;
    }
}

/* ------------------------------------------------------------------
   6. Reduced motion
   ------------------------------------------------------------------ */

/*
  No scroll-driven film: the section collapses to a normal, static block
  showing a single poster frame with every card fully legible.
*/
@media (prefers-reduced-motion: reduce) {
    .services-film {
        height: auto;
    }

    .services-film__stage {
        position: relative;
        height: auto;
        min-height: 0;
        padding: 80px 0;
    }

    .services-film__head {
        opacity: 1;
        transform: none;
        transition: none;
    }

    .services-film__card,
    .services-film__card.is-active,
    .services-film__card.is-passed {
        opacity: 1;
        transform: none;
        transition: none;
        box-shadow: none;
    }

    .services-film__card::before {
        transform: scaleX(0);
    }

    .services-film__rail {
        display: none;
    }
}
