/* services.css — 10 / Services
 *
 * Six panels stacked in one pinned stage. DOM ORDER IS THE Z-ORDER: a later
 * panel's growing media covers the previous panel's card. Nothing here sets
 * z-index on the panels, and nothing should — the sequence depends on source
 * order alone.
 *
 * The stage was authored at 1180 x 664. In production it is the viewport, so
 * every length that has to hold its proportion is expressed as a fraction of
 * that reference rather than a fixed pixel value. services.js does the same for
 * the motion constants.
 *
 * TRACK: 100vh pinned + 5 x STEP of scroll, one STEP per panel transition.
 * STEP lives in services.js and must match the 4500px below.
 */

.svc-track {
  height: calc(100vh + 4500px);
  position: relative;
}

.svc {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--char-lo);
  color: var(--on-dark);
  font-family: var(--body);
}

.panel { position: absolute; inset: 0; }


/* --- panel 00 · intro ----------------------------------------------------- */

.panel--intro { background: var(--char-lo); }
.panel__glow {
  position: absolute; inset: 0;
  background: radial-gradient(620px 380px at 50% 42%, rgba(var(--red-accent-rgb), .10), transparent 68%);
}

/* The opening screen is an INDEX, left-aligned, not a centred title card.
   Measured from the prototype: block 1180 wide, column gap 30.6px, the group
   grid 3 x 368.375px with a 37.44px gap. */
.intro {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: flex-start; justify-content: center;
  gap: 30px;
  text-align: left;
  padding: 0 clamp(28px, 6.1vw, 96px);
  will-change: transform;
}
.intro__eyebrow {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  font-family: var(--hud); font-weight: 400;
  font-size: 11px; letter-spacing: .34em; text-transform: uppercase;
  color: var(--red-dark);
}
.intro__eyebrow i {
  width: 7px; height: 7px;
  background: var(--red-dark);
  box-shadow: 0 0 14px 2px rgba(var(--red-accent-rgb), .7);
}
.intro__h2 {
  margin: 0;
  font-family: var(--display); font-weight: 900;
  font-size: clamp(30px, 4.9vw, 62px);
  line-height: 1.04;
  letter-spacing: -.025em;
  text-transform: uppercase;
  color: var(--on-dark);
  max-width: 20ch;
  text-wrap: balance;
}
/* Mobile only — the intro panel gains a scroll cue below 768px, where nothing
   else hints that the six panels advance on scroll. See services.small.css. */
.intro__cue { display: none; }

.intro__p {
  margin: 0;
  max-width: 62ch;
  font-size: clamp(13px, 1.05vw, 15px);
  line-height: 1.6;
  color: #8e8e96;
  border-top: 1px solid rgba(244, 242, 237, .14);
  padding-top: 20px;
}


/* --- panels 01-05 · the growing media window ------------------------------
   Bottom-pinned and centred. services.js drives width/height/top/margin-left;
   everything else is here. */

.panel__img {
  position: absolute;
  left: 50%;
  overflow: hidden;
  background: var(--char-base);
  opacity: 0;
  will-change: width, height, top;
}

/* Fixed at full stage size and centred inside the window, so the window opening
   REVEALS more of the frame instead of scaling it. Do not make this responsive
   to .panel__img — that would turn the effect into a zoom. */
.panel__media {
  position: absolute;
  left: 50%; top: 50%;
  width: 100vw; height: 100vh;
  margin: -50vh 0 0 -50vw;
}
/* The clips and stills run UNGRADED — no filter, no scrim. They previously
   carried saturate(.55) brightness(.7) plus a black gradient-and-vignette veil,
   which together rendered them at roughly a third of their native brightness.
   Per-panel brightness overrides existed only to reconcile the two stills against
   that grade, so they went with it; without the base grade they would have made
   those two panels darker than the rest, which is backwards.

   .panel__tint (below) is deliberately kept — it is the red accent wash, not a
   darkener. It reads stronger now that nothing is muting the frame under it. */
/* COVER, on Zsolt's instruction (2026-08-06): the background must fill the screen
   completely, growing in height and overflowing horizontally rather than being
   letterboxed.

   THIS DELIBERATELY REVERSES the earlier choice, which is recorded here because
   the trade-off has not gone away. Contain was chosen so every frame showed
   whole at any window shape; the cost was letterbox bars wherever the media box's
   aspect ratio disagreed with the image's. Cover removes the bars and fills the
   frame, at the cost of cropping — roughly 10% of the frame on a 16:10 screen and
   more on a near-square window. Aspect ratio is preserved either way, so nothing
   stretches; the difference is bars versus crop.

   object-position stays centred. Under cover it decides WHICH part is cropped,
   and centre is the safe default for these backgrounds — the subject sits mid-
   frame in all five. */
.panel__pic {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  /* M17 step 1. Saturation MUST come before the screen blend below — run the
     other way round and the hues shift. */
  filter: saturate(.30);
}

/* M17 steps 2 and 3 — the depth treatment, as two pseudo-elements so the media
   markup does not need extra divs.

   THE DIAGNOSIS THIS FIXES: the card (#12181e, lum 22.9) sat on the stage
   (#17171b, lum 23.5) — a 0.6 luminance step where the brief asks for 25-30.
   Separation was coming entirely from a drop shadow, which reads as a sticker on
   a dark ground.

   Step 2 is a SCREEN blend, not brightness(). Screen maps black onto the floor
   and leaves white untouched; brightness() multiplies, so 0 stays 0 and a
   crushed image stays crushed. Measured on the four supplied stills, this lifts
   their darkest pixel from 0.1-14 up to 33-73.

   The floor is what makes the same card hold on a high-key and a low-key image
   alike — which is what makes an alternating-key sequence viable at all. */
.panel__media { isolation: isolate; }        /* contain the blend */
.panel__media::before,
.panel__media::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
}
.panel__media::before {
  z-index: 1;
  background: #1E2128;
  mix-blend-mode: screen;
}
.panel__media::after {
  z-index: 2;
  background: #1E2128;
  opacity: .62;
}
.panel__tint {
  position: absolute; inset: 0;
  z-index: 3;
  background: radial-gradient(700px 400px at 40% 25%, rgba(var(--red-accent-rgb), .10), transparent 65%);
}


/* --- the description card -------------------------------------------------
   Vertical position is proportional (236/664 of the stage) because the card
   trigger in services.js is tuned against where the card's bottom edge sits.
   Horizontal inset is clamped instead — 72/1180 would be a 117px gutter at
   1920 and the three columns do not need it.

   RED ON THE CARD. The card is #f4f6f8, a light surface inside a dark section,
   and it is the one place in Services where the accent red lands on light.
   RED-CONTACT-SERVICES.md §0 and §2 are explicit that there is no exception:
   "All reds below are #ff0a32", covering the offset number (§2.4), the 2px
   paragraph border (§2.5) and the fact-strip keys (§2.6).

   THIS OVERRIDES M19 AND IT COSTS CONTRAST. These carried --red-deep (#c00020,
   5.94:1 on #f4f6f8). tokens.css records #ff0a32 being measured against this
   very card and rejected — 3.76:1 / 2.97:1 against its dark and bright extremes
   — under M19's "red on a light card is #c00020". The handoff supersedes that
   for Services, and this card was --red-deep's last consumer: the token has
   since been deleted from tokens.css, which keeps #c00020 on record. Note the
   card is now opaque #f4f6f8, so the translucency that produced the contrast
   RANGE in that measurement no longer applies — the single figure is 3.63:1,
   still under AA for the 9.5-12px type these rules carry. §2.7 is unaffected:
   there are still no red surfaces in Services. */

.card {
  position: absolute;
  left: clamp(28px, 6.1vw, 96px);
  right: clamp(28px, 6.1vw, 96px);
  top: 35.5vh;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: clamp(20px, 3.7vw, 44px);
  padding: 32px 40px 36px;
  /* M19, FINAL. This supersedes M17's step 4 (a dark translucent card with a
     backdrop-filter) — M17 says so itself: "card surface and card content are
     covered by M18-M20 below". */
  background: #f4f6f8;
  outline: 1px solid rgba(18, 28, 40, .12);
  box-shadow:
    0 1px 2px rgba(14, 18, 24, .16),
    0 18px 40px -16px rgba(14, 18, 24, .4);
  opacity: 0;
  transform: translateY(300px);
  will-change: transform, opacity;
}

.card__meta {
  display: flex; flex-direction: column; justify-content: space-between;
  gap: 14px;
}
.card__num {
  font-family: var(--hud); font-weight: 400;
  font-size: 12px; letter-spacing: .16em;
  color: var(--red-label);
}
.card__tag {
  font-family: var(--hud); font-weight: 400;
  font-size: 10.5px; letter-spacing: .12em; line-height: 1.7;
  text-transform: uppercase;
  color: var(--banner-black);
}

/* WIDE / NARROW VARIANTS. Two card paragraphs are rendered — the 358px one is
   different copy, not a re-break — and one is shown per width. The same pair
   also hides the surplus <br> inside a tagline or a long title, and the hyphen
   that goes with it; see netface_br_wide() in inc/copy.php.

   Defined here rather than in a shared sheet because Services is the only
   section using them today. If Achievements or About adopt the same pattern,
   promote the pair rather than copying it. */
.narrow-only { display: none; }

.card__body {
  margin: 0;
  align-self: center;
  font-family: var(--body); font-weight: 400;
  font-size: 13px; line-height: 1.6;
  color: #5c6672;
  max-width: 56ch;
  border-left: 2px solid var(--red-label);
  padding-left: clamp(16px, 2.7vw, 32px);
}
.card__body .em { color: var(--red-label); font-weight: 600; }

.card__head {
  display: flex; flex-direction: column;
  align-items: flex-end; justify-content: space-between;
  gap: 16px;
}
.card__kicker {
  font-family: var(--hud); font-weight: 400;
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--red-label);
}
.card__title {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(22px, 2.4vw, 34px); line-height: 1;
  letter-spacing: -.02em; text-transform: uppercase;
  color: var(--banner-black);
  text-align: right;
}
/* Panel 01's title is two lines, so it is set a step larger. */
.card__title--lg { font-size: clamp(28px, 3.1vw, 44px); line-height: .95; }


/* =========================================================================
   Reduced motion — the handoff's instruction: skip the grow and the rise, and
   present the six panels as a plain stacked list.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  .svc-track { height: auto; }
  .svc { position: relative; height: auto; }
  .panel { position: relative; inset: auto; min-height: 100vh; }
  .panel--intro { display: flex; }
  .intro { position: relative; inset: auto; padding: 12vh 6vw; }

  /* 16:9, not a fixed vh. The clips are all 16:9 and .panel__pic is `contain`,
     so matching the window to the footage fills it exactly — no letterbox and no
     crop. A fixed height would letterbox on the short side instead. */
  .panel__img {
    position: relative; left: auto;
    width: 100% !important; height: auto !important; aspect-ratio: 16 / 9;
    top: auto !important; margin-left: 0 !important;
    opacity: 1 !important;
  }
  .panel__media { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; }
  .card {
    position: relative; inset: auto;
    opacity: 1 !important; transform: none !important;
    margin: -12vh clamp(28px, 6.1vw, 96px) 12vh;
  }
}


/* ===========================================================================
   Card fact strip — M20 structure, M27 copy
   ---------------------------------------------------------------------------
   FLEX, NEVER A FIXED TRACK COUNT. This was repeat(4, minmax(0,1fr)), which
   left a quarter of the row empty on the three-cell services. flex:1 1 0 with
   min-width:0 makes 3- and 4-cell strips both fill the row (roughly 264px vs
   198px per cell at the design width).

   It also fixes the card's proportion: without it the card is a thin band
   floating in a full-viewport frame.
   =========================================================================== */

.card__facts {
  grid-column: 1 / -1;          /* full width beneath the three-column row */
  display: flex;
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid rgba(18, 28, 40, .12);
}

.fact {
  flex: 1 1 0;
  min-width: 0;                 /* required, or long terms push the row wider */
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 0 clamp(12px, 1.6vw, 22px);
  border-left: 1px solid rgba(18, 28, 40, .12);
}
.fact:first-child { padding-left: 0; border-left: none; }
.fact:last-child  { padding-right: 0; }

.fact__k {
  font-family: var(--hud); font-weight: 500;
  font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--red-label);
}
.fact__t {
  font-family: var(--body); font-weight: 600;
  font-size: 13px; line-height: 1.35;
  color: var(--near-black);
}
.fact__s {
  font-family: var(--body); font-weight: 400;
  font-size: 11px; line-height: 1.45;
  color: #565e67;
}


/* ===========================================================================
   Opening screen — the three value groups
   ---------------------------------------------------------------------------
   auto-fit rather than a fixed repeat(3,...): the group count is data, and M27's
   lesson on the fact strip applies here too — a fixed track count breaks the
   moment the content stops matching it.
   =========================================================================== */

.intro__meta {
  margin-left: auto;
  font-family: var(--hud); font-weight: 400;
  font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--on-dark-3);
}

.intro__p {
  max-width: 62ch;
  border-top: none;
  padding-top: 0;
}

.intro__groups {
  width: 100%;
  display: grid;
  /* auto-fit needs a REAL minimum. With minmax(0,1fr) the track count is
     unbounded — it generated 34 tracks, of which 31 were 0px. It happened to
     render as three columns, which is exactly the kind of accident that breaks
     the moment the group count changes. 240px is the narrowest a group reads at.
     min(240px, 100%) keeps that counting but lets the floor collapse to the
     container when the container is narrower, so it can never overflow. */
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(20px, 2.6vw, 37px);
  margin-top: 6px;
}

.vgroup { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.vgroup__head {
  display: flex; align-items: baseline; gap: 14px;
  font-family: var(--hud); font-weight: 400;
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
}
.vgroup__num   { color: var(--red-dark); }
.vgroup__count { color: var(--on-dark-3); }

.vgroup__h {
  margin: 0;
  font-family: var(--display); font-weight: 900;
  font-size: clamp(24px, 2.8vw, 40px); line-height: 1.05;
  letter-spacing: -.025em;
  color: var(--on-dark);
  text-wrap: balance;
}

.vgroup__p {
  margin: 0;
  max-width: 34ch;
  font-size: 13px; line-height: 1.5;
  color: #8e8e96;
}

.vgroup__list {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 4px;
}
.vitem {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  padding-top: 8px;
  border-top: 1px solid rgba(244, 242, 237, .10);
}
/* §2.3 — red, not grey. This carried --on-dark-3 (#5c5c63); the handoff lists
   the row number among the section's red marks and leaves only the service
   name beside it neutral. --red-dark is the accent red on this dark ground. */
.vitem__n {
  font-family: var(--hud); font-weight: 400;
  font-size: 10px; letter-spacing: .14em;
  color: var(--red-dark);
}
.vitem__t {
  font-family: var(--body); font-weight: 500;
  font-size: 13px; line-height: 1.35;
  color: var(--on-dark);
}
