/* ============================================================================
   service.css: the service pages' opening shot.

   Amir, 2026-09-25, approving the cinematic upgrade: every service page opens
   full screen on its own film clip, the same clip as its card in the homepage
   film, so a click on a card match cuts into the page (CINEMATIC-PLAN item 1).

   Loaded by the eight tsv-page pages only, after site.css and before type.css:
   these rules win over the old hero's at equal specificity, and type.css still
   has the last word on type everywhere below the hero.

   The frame is the viewport. The poster (frame 0 of the clip) is preloaded and
   paints first (Chrome reads a full viewport picture as a background, so the
   title stays the page's largest paint); hero.js lays the clip over it once the
   page has loaded, and only while the frame is on screen. The page's words sit
   over the lower part of the frame, the same elements in the same order. The
   one thing laid over Amir's footage is a gradient at the foot, for the words:
   no vignette, no tint, no blur.
   ========================================================================== */

/* ------------------------------------------------- 1. the top bar, over it */

/* The bar keeps its place and its links; it stops being a black strip across
   the top of the film. A shadow under the words, not a plate behind them, is
   what keeps them readable over a bright frame. */
.tsv-page .topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  background: transparent;
  border-bottom-color: transparent;
}

.tsv-page .topbar-brand,
.tsv-page .topbar-link {
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8), 0 0 16px rgba(0, 0, 0, 0.55);
}

/* the label grey reads on the page's black, not over a lit frame */
.tsv-page .topbar-link {
  color: rgba(242, 242, 245, 0.88);
}

.tsv-page .topbar .ig-mark {
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.75));
}

/* ------------------------------------------------------------ 2. the block */

.svc-hero {
  /* the frame's height: the small viewport, so a phone's toolbar never crops
     the foot of it (100vh where svh is unknown) */
  --hero-h: 100vh;
  /* the least film the words leave clear above them */
  --hero-top: max(96px, 22vh);

  position: relative;
  /* over the atmosphere canvas (site.css .atmos, fixed at z 3), as the
     sections below are: its streaks never cross Amir's frame */
  z-index: 5;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 100vh;
  padding-top: var(--hero-top);
  /* the scroll cue's band at the foot (site.css keeps the same with the cue
     in the page, at a higher specificity) */
  padding-bottom: calc(var(--cue-space, 92px) + 16px);
}

@supports (height: 100svh) {
  .svc-hero {
    --hero-h: 100svh;
    --hero-top: max(96px, 22svh);
    min-height: 100svh;
  }
}

/* ------------------------------------------------------------ 3. the frame */

/*
 * One viewport tall even when the words run longer (a phone): the frame is
 * the shot, the words that do not fit carry on below it over the page's own
 * black, which the gradient has already reached. The match cut expands the
 * homepage card to exactly this box, so it has to be the viewport: top left
 * at 0,0, full width, --hero-h tall, the picture covering it from the centre.
 *
 * It takes no pointer: nothing here is a player, and a custom cursor reading
 * the element under it should find the section, not a <video>.
 */
.svc-hero-media {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  width: 100%;
  height: var(--hero-h);
  overflow: hidden;
  background: var(--void);
  pointer-events: none;
}

.svc-hero-poster,
.svc-hero-video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--hero-focus, 50% 50%);
}

/* the clip fades up over its own first frame once it is really playing
   (hero.js adds .is-live on the video's first "playing") */
.svc-hero-video {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.svc-hero-media.is-live .svc-hero-video {
  opacity: 1;
}

/*
 * The gradient: the page's black rising from the foot, clear over the top of
 * the frame, so the words sit on it and the frame hands over to the page
 * without an edge. Inside the frame on purpose: the match cut then fades it in
 * with the picture instead of switching it on when the transition ends.
 */
.svc-hero-media::after {
  content: '';
  position: absolute;
  inset: 0;
  /* and, on a wide screen, a light shade from the left behind the words,
     where some frames are brightest (the SEO target, the content car);
     the lead, 2026-09-25 */
  background: linear-gradient(90deg, rgba(7, 7, 7, 0.5) 0%, rgba(7, 7, 7, 0.3) 38%, rgba(7, 7, 7, 0) 62%),
    linear-gradient(
    180deg,
    rgba(7, 7, 7, 0) 36%,
    rgba(7, 7, 7, 0.32) 52%,
    rgba(7, 7, 7, 0.66) 70%,
    rgba(7, 7, 7, 0.88) 86%,
    #070707 100%
  );
}

/* The match cut. The frame carries the shared name only while one is running
   (html[data-vt="match"] from the transition, or .hero-cut from this page's own
   head script before its first paint), so an ordinary navigation into or out
   of a service page never lifts a full screen picture over the site's own
   transition. The words get a name of their own so they come up over the
   picture during the cut instead of appearing when it ends. */
html[data-vt='match'] .svc-hero-media,
html.hero-cut .svc-hero-media {
  view-transition-name: toai-hero;
}

html[data-vt='match'] .svc-hero > .wrap,
html.hero-cut .svc-hero > .wrap {
  view-transition-name: toai-hero-copy;
}

/* ------------------------------------------------------------ 4. the words */

/* Left aligned with the top bar and the page's column below, free to run on
   to the right: the display line needs the room, the reading lines keep their
   measure. */
.svc-hero > .wrap {
  position: relative;
  width: 100%;
  max-width: none;
  margin: 0;
  padding-left: max(var(--gutter), calc(50% - var(--wrap) / 2 + var(--gutter)));
  padding-right: max(var(--gutter), 4vw);
}

/* Words over footage: a close shadow for the edge and a wide soft one for the
   ground, on the words themselves rather than on the picture. */
.svc-hero .eyebrow,
.svc-hero .lede,
.svc-hero .prose,
.svc-hero .microline,
.svc-hero .tsv-proof-row {
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7), 0 0 22px rgba(0, 0, 0, 0.45);
}

.svc-hero .svc-h1 {
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45), 0 0 44px rgba(0, 0, 0, 0.4);
}

/* the eyebrow's label grey is for the page's black; over a lit frame it is
   the page's white, a step down */
.svc-hero .eyebrow {
  color: rgba(242, 242, 245, 0.86);
}

/*
 * The display line. --fs-hero is the type set's size; two ceilings keep the
 * shot a shot:
 *   9svh    the titles are long (44 to 58 characters, SEO word for word), and
 *           at a flat 7vw a 1440x900 screen spent 400 to 600px, four to six
 *           lines, on the title alone, and the words ran off the frame. At
 *           9svh a 900px screen sets it at 81px in three or four lines, and a
 *           1080px one at 97: taller screens get the full size.
 *   --hero-fit  the page's longest word, in em (Orbitron, measured): no word
 *           is ever wider than the column. It only binds on a phone, and only
 *           for COMMERCIALS, OPTIMIZATION and PRODUCTION; hero.js measures it
 *           again if the display face ever changes.
 */
.svc-hero .svc-h1 {
  max-width: 14em;
  margin: 0 0 var(--s-6);
  font-family: var(--font-display, 'Orbitron', sans-serif);
  font-size: var(--fs-hero, clamp(44px, 7vw, 120px));
  font-size: min(
    var(--fs-hero, clamp(44px, 7vw, 120px)),
    9vh,
    calc((100vw - 2 * var(--gutter)) / var(--hero-fit, 9))
  );
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: var(--tracking-display, 0.02em);
  /* uppercase, as every heading on the site is and as the SEO record reads it */
  text-transform: uppercase;
  text-wrap: balance;
}

@supports (height: 100svh) {
  .svc-hero .svc-h1 {
    font-size: min(
      var(--fs-hero, clamp(44px, 7vw, 120px)),
      9svh,
      calc((100vw - 2 * var(--gutter)) / var(--hero-fit, 9))
    );
  }
}

.svc-hero .cta-row {
  margin-bottom: 0;
}

/* A wide screen sets the copy and the call to action side by side under the
   title, the buttons flush right: the same words in the same order, a hundred
   pixels less of the frame covered. */
@media (min-width: 1280px) {
  .svc-hero-foot {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 56px;
  }

  .svc-hero-copy {
    flex: 0 1 620px;
    min-width: 0;
  }

  .svc-hero-copy > :last-child {
    margin-bottom: 0;
  }

  .svc-hero .cta-row {
    flex: 0 0 auto;
    max-width: 460px;
    text-align: right;
  }

  .svc-hero .cta-row .btn {
    margin: 0 0 10px 14px;
  }
}

/* The two proof figures on the YouTube pages. The rebuild never carried their
   rules over, so they printed as four loose lines; these are the Webflow
   originals (toaihome.webflow.shared.403d32296.css, .tsv-proof-*). */
.tsv-proof-row {
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  margin: 0 0 var(--s-6);
}

.tsv-proof-item {
  padding-left: 16px;
  border-left: 2px solid var(--cyan);
}

.tsv-proof-num {
  color: var(--white);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
}

.tsv-proof-label {
  max-width: 220px;
  margin-top: 6px;
  color: var(--label);
  font-size: 13px;
}

/* ------------------------------------------------------------- 5. phones */

@media (max-width: 767px) {
  .svc-hero {
    --hero-top: max(88px, 26vh);
  }

  @supports (height: 100svh) {
    .svc-hero {
      --hero-top: max(88px, 26svh);
    }
  }

  /* the words run most of the frame's height here, so the black starts
     higher and reaches further */
  .svc-hero-media::after {
    background: linear-gradient(
      180deg,
      rgba(7, 7, 7, 0) 18%,
      rgba(7, 7, 7, 0.4) 36%,
      rgba(7, 7, 7, 0.72) 58%,
      rgba(7, 7, 7, 0.9) 80%,
      #070707 100%
    );
  }
}

/* ------------------------------------------------------ 6. reduced motion */

/* hero.js never starts the clip for these visitors; the rule is the belt */
@media (prefers-reduced-motion: reduce) {
  .svc-hero-video {
    display: none;
  }
}
