/* ========================================================================
   BRANDS — method sequence + anchor nav + five always-visible stage
   sections, each with an inline-expanding workflow plan. Visual system:
   white background, black/pale-grey typography, the site's own purple
   as the one interactive/active accent, Consolas for every functional
   label for numbered stage (matches the client's own BRANDS mockup).
   ======================================================================== */

.brands {
  background: var(--color-white);
  /* OUTSOURCE's hover accent — a lime distinct from the site's own
     purple, so contractor tags read as their own interactive unit. */
  --color-lime: #c9f24b;
}

/* ---- Hero gradient zone: intro + method nav only, hard-cut before
   0 | Brand Audit's white section. .brands-page gives the absolutely
   positioned bg a positioning root; .direction-intro/.brands get their
   own stacking context so they paint above it (scoped to this page only
   — direction-page.css itself stays untouched for Retail/Business/Films). ---- */
.brands-page { position: relative; }

/* Only .direction-intro needs promoting: its content is plain static
   flow, which paints *below* positioned siblings regardless of DOM
   order. .brands doesn't need this — its sticky .brands-method child is
   already explicitly positioned (z-index:50) and stacks above the
   hero-bg on its own; making .brands positioned too would just give
   .brands-method a closer offsetParent than .brands-page, throwing off
   the offsetTop measurement js/brands.js relies on for sizing. */
.brands-page > .direction-intro {
  position: relative;
  z-index: 1;
}

/* Lighter, more compact intro typography — BRANDS itself (the h1) stays
   at its normal editorial scale; everything under it (tagline, body
   copy including the Vision -> ... -> Activation line) comes down
   ~17%, scoped to this page only (--fs-body-lg is shared with
   Retail/Business/Films via direction-page.css). */
.brands-page .direction-intro__tagline,
.brands-page .direction-intro__body p {
  font-size: clamp(0.92rem, 0.83rem + 0.42vw, 1.2rem);
}

/* Trailing space after the last intro paragraph, before the method nav
   — was 128px (direction-page.css's shared --space-7) stacking with
   .brands-method's own top padding. First cut to 3rem (48px), then to
   2rem (32px) after client review still read the combined gap (this
   padding + .brands-method's own top padding) as too airy — scoped to
   Brands only so Retail/Business/Films keep the shared default. The
   intro's own top padding/content position is untouched — only this
   bottom gap shrinks, pulling the method nav + tagline + stages up as
   one block. Same value in EN and RU (this isn't language-dependent —
   the two only differ in how many lines the translated paragraphs
   wrap to, which is expected). */
.brands-page .direction-intro {
  padding-bottom: 2rem;
}

.brands-hero-bg {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 0;
  overflow: hidden; /* clean, hard edge at the bottom — no fade section */
}
.brands-hero-bg canvas {
  position: absolute;
}

/* Restrained reveal system — fade + light slide-up only, no bounce or
   spring (see prefers-reduced-motion in base.css, which already zeroes
   every transition/animation duration). */
.reveal-up {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--ease-editorial), transform 600ms var(--ease-editorial);
}
.reveal-up.is-visible { opacity: 1; transform: translateY(0); }

.reveal-fade-in {
  opacity: 0;
  transition: opacity 500ms var(--ease-editorial);
}
.reveal-fade-in.is-visible { opacity: 1; }

.reveal-seq {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 450ms var(--ease-editorial), transform 450ms var(--ease-editorial);
}
.reveal-seq.is-visible { opacity: 1; transform: translateY(0); }

/* ---- Method sequence: reveal animation + sticky anchor nav in one ----
   Sits in normal flow until scrolling carries it up to the header, then
   sticks just below it and stays put while the five stages scroll past
   underneath. .is-stuck (toggled by the sentinel in js/brands.js) swaps
   in a compact height once it's actually pinned, so the fixed bar never
   eats more vertical space than it needs to. */
.brands-method-sentinel {
  height: 1px;
}

.brands-method {
  position: sticky;
  top: calc(var(--nav-height) + 10px);
  z-index: 50;
  background: transparent; /* lets the hero gradient show through while still in flow */
  padding-block: var(--space-5) var(--space-6);
  border-bottom: 1px solid transparent;
  transition: padding-block var(--dur-base) var(--ease-editorial), background var(--dur-base) var(--ease-editorial), border-color var(--dur-base) var(--ease-editorial);
}

.brands-method.is-stuck {
  /* Opaque once pinned (to cleanly occlude stage content scrolling
     underneath) — pale grey rather than white, so the pinned bar
     still reads as its own band against the white page below it. */
  background: var(--color-pale-grey-soft);
  padding-block: 0.85rem;
  border-bottom-color: var(--color-border);
}

.brands-method__nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6em;
}

.brands-method__item {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  letter-spacing: var(--ls-normal);
  text-transform: uppercase;
  background: var(--color-black);
  color: var(--color-white);
  padding: 0.85em 1.2em;
  border-radius: var(--radius-btn);
  transition: background var(--dur-fast) var(--ease-editorial), color var(--dur-fast) var(--ease-editorial), padding var(--dur-base) var(--ease-editorial);
}

.is-stuck .brands-method__item {
  padding: 0.55em 1em;
}

.brands-method__item:hover,
.brands-method__item:focus-visible,
.brands-method__item.is-active {
  background: var(--color-accent);
  color: var(--color-black);
}

.brands-method__tagline {
  margin-top: 0.7em;
  font-weight: 700;
  font-size: var(--fs-body-lg);
  color: var(--color-black);
  transition: margin-top var(--dur-base) var(--ease-editorial), font-size var(--dur-base) var(--ease-editorial);
}

.is-stuck .brands-method__tagline {
  margin-top: 0.5em;
  font-size: var(--fs-body);
}

/* Heavier than the tagline's own bold (700) so the "scroll down" cue
   reads clearly, not as just another word in the sentence. */
.brands-method__tagline-arrow {
  font-weight: 900;
  -webkit-text-stroke: 0.5px currentColor;
  margin-left: 0.2em;
}

/* Small label-button between the nav pills and the tagline — same
   uppercase Consolas treatment as the pills, white by default (reads
   as a separate, secondary note), purple on hover. Lives inside the
   same sticky .brands-method bar, so it stays in place with the rest
   of the bar on scroll. */
.brands-method__duration {
  display: inline-flex;
  align-items: center;
  margin-top: var(--space-3);
  padding: 0.6em 1em;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  letter-spacing: var(--ls-normal);
  text-transform: uppercase;
  color: var(--color-black);
  background: var(--color-accent);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-btn);
  transition: background var(--dur-fast) var(--ease-editorial), border-color var(--dur-fast) var(--ease-editorial), padding var(--dur-base) var(--ease-editorial), font-size var(--dur-base) var(--ease-editorial), margin-top var(--dur-base) var(--ease-editorial);
}
.brands-method__duration:hover {
  background: var(--color-accent-dim);
  border-color: var(--color-accent-dim);
  color: var(--color-black);
}
.is-stuck .brands-method__duration {
  margin-top: 0.5em;
  padding: 0.45em 0.8em;
  font-size: var(--fs-micro);
}

/* ---- Stage sections ---- */
.brands-stage {
  padding-block: 4.4rem;
  border-top: 1px solid var(--color-border);
}

.brands-stage__title {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(2rem, 1.4rem + 3vw, 4rem);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  color: var(--color-black);
  margin-bottom: 1.6rem;
  transition: color var(--dur-base) var(--ease-editorial);
}

.brands-stage__index,
.brands-stage__name {
  font-family: var(--font-display);
}

.brands-stage__index {
  color: var(--color-pale-grey);
  transition: color var(--dur-base) var(--ease-editorial);
}

/* Follows the user down the page: whichever stage is currently active
   (js/brands.js observeActiveStage) picks up the same purple accent as
   its sticky-nav button — number, name, and this stage's own divider
   lines all move together. */
.brands-stage.is-active .brands-stage__index,
.brands-stage.is-active .brands-stage__title {
  color: var(--color-accent);
}
.brands-stage.is-active .brands-meta__row {
  border-top-color: var(--color-accent);
}
.brands-stage.is-active .brands-meta__row:last-child {
  border-bottom-color: var(--color-accent);
}

/* ---- Meta rows: ЦЕЛЬ / СОСТАВ РАБОТ / РЕЗУЛЬТАТ / КОМАНДА / СРОК ---- */
.brands-meta {
  max-width: 62rem;
}

.brands-meta__row {
  position: relative;
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: var(--space-3);
  align-items: start;
  padding-block: 0.7rem;
  border-top: 1px solid var(--color-border);
  transition: border-color var(--dur-base) var(--ease-editorial);
}
.brands-meta__row:last-child {
  border-bottom: 1px solid var(--color-border);
  transition: border-color var(--dur-base) var(--ease-editorial);
}

.brands-meta__label {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  width: 7.5rem;
  height: 2.2em;
  padding-left: 0.7em;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  background: var(--color-black);
  color: var(--color-white);
  border-radius: var(--radius-btn);
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-editorial), color var(--dur-fast) var(--ease-editorial);
}

.brands-meta__row:hover .brands-meta__label {
  background: var(--color-accent);
  color: var(--color-black);
}

.brands-meta__value {
  /* Grid items default to a min-width of their content's min/max-content
     size, which for the OUTSOURCE row's flex-wrap tag list let it blow
     past its 1fr track instead of wrapping — force it to actually
     shrink to the column's available width. */
  min-width: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  white-space: pre-line;
}

.brands-meta__row:hover .brands-meta__value {
  font-weight: 700;
}

/* ---- OUTSOURCE row — same black label as GOAL/SCOPE/RESULT/TEAM/
   TIMING (it's part of the same system, not a different one); its
   specialists render as pill tags instead of a text paragraph, with
   the "depending on ..." note inline right after the last tag. A
   lime accent (distinct from the site's purple) appears only on
   hover, on the label AND every tag in the row at once, so it reads
   as one interactive unit. ---- */
.brands-meta__value--outsource {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em;
  /* Reserves the same right-edge gutter the hover hint sits in
     (see .brands-meta__hint), on every wrapped line, all the time —
     not just on hover — so a tag near the row's right edge (e.g.
     Market Development's "Influencer Manager") never ends up directly
     under the hint chip once it appears. */
  padding-right: 14rem;
}

.brands-meta__tag {
  display: inline-flex;
  align-items: center;
  height: 2em;
  padding: 0 0.85em;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  background: var(--color-white);
  color: var(--color-black);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-editorial), border-color var(--dur-fast) var(--ease-editorial);
}

.brands-meta__note {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--color-black);
  opacity: 0.5;
}

/* Row hover (or focus on any one tag) lights up the label and every
   tag in lime at once — text stays black throughout. */
.brands-meta__row--outsource:hover .brands-meta__label,
.brands-meta__row--outsource:hover .brands-meta__tag,
.brands-meta__tag:hover {
  background: var(--color-lime);
  border-color: var(--color-lime);
  color: var(--color-black);
}

/* ---- Hover-only payment hints, pinned to the row's own right edge so
   they never shift the label/value layout. TEAM's "MONTHLY FEE" note
   applies to every stage; OUTSOURCE's "SEPARATE DEVELOPMENT BUDGET"
   only exists on rows that actually build the tag list (Brand Audit /
   Brand Foundation have neither tags nor this hint). ---- */
.brands-meta__hint {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  padding: 0.35em 0.7em;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  white-space: nowrap;
  color: var(--color-black);
  border-radius: var(--radius-btn);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-editorial), background var(--dur-fast) var(--ease-editorial);
}
.brands-meta__row:hover .brands-meta__hint {
  opacity: 1;
}

/* Same solid-chip construction for both — purple for TEAM, lime for
   OUTSOURCE — so the two payment hints read as one consistent system
   instead of one being a plain, easy-to-miss line of text. */
.brands-meta__row:hover .brands-meta__hint--team {
  background: var(--color-accent);
}
.brands-meta__row--outsource:hover .brands-meta__hint--outsource {
  background: var(--color-lime);
}

/* ---- CHECK WORKFLOW PLAN / DISCUSS YOUR PROJECT — stacked CTA pair,
   same visual system for both; Workflow itself lives after this group,
   never between the two buttons. ---- */
.brands-cta-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

.brands-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.7em 1.1em;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  letter-spacing: var(--ls-normal);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-black);
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-btn);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-editorial), color var(--dur-fast) var(--ease-editorial), border-color var(--dur-fast) var(--ease-editorial);
}
.brands-toggle[aria-expanded="true"] {
  color: var(--color-accent);
  border-color: var(--color-accent);
}
.brands-toggle:hover,
.brands-toggle[aria-expanded="true"]:hover {
  background: var(--color-accent);
  color: var(--color-black);
  border-color: var(--color-accent);
}

.brands-toggle__icon {
  font-family: var(--font-mono);
  font-size: 1.1em;
  line-height: 1;
}

/* Smooth inline expand via the grid-rows 0fr->1fr technique — no JS
   height math, no bounce. */
.brands-workflow-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 420ms var(--ease-editorial);
}
.brands-workflow-wrap.is-open { grid-template-rows: 1fr; }

.brands-workflow {
  overflow: hidden;
  min-height: 0;
  display: grid;
  grid-template-columns: 0.85fr 2.15fr;
  gap: var(--space-4);
  align-items: start;
  padding-top: var(--space-4);
}

.brands-workflow__quote {
  font-size: clamp(0.9rem, 0.82rem + 0.4vw, 1.2rem);
  font-weight: 700;
  line-height: 1.1;
  max-width: 22rem;
}

/* ---- Media grids — plain horizontal rows of equal-proportion windows,
   matching the client's own mockup (see brands-page.js `layout` per
   stage): a row of 3, a row of 4, or the same row staggered into a
   cascade. Not a varied editorial gallery — a visual workflow. ---- */
.brands-grid { display: grid; gap: var(--space-3); }

.brands-media { display: flex; flex-direction: column; }

.brands-media__head {
  display: flex;
  align-items: baseline;
  gap: 0.6em;
  margin-bottom: 0.6em;
}
.brands-media__num {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  color: var(--color-pale-grey);
}
.brands-media__label {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  text-transform: uppercase;
  color: var(--color-black);
}

.brands-media__window {
  position: relative;
  /* Never grow to fill a stretched .brands-media column — every window
     already has a fixed aspect-ratio (set per grid layout below), so
     letting it grow was the actual cause of uneven card sizes: Grid's
     default align-items:stretch hands whatever extra row height a
     longer-caption sibling creates to this, the only growable child,
     inflating the window past its ratio. Left at its natural size,
     any extra stretched height instead lands as blank space below the
     caption — invisible, and it keeps every .brands-media column (and
     therefore the divider between them) at the same full row height. */
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-pale-grey-soft);
  border: 1px solid var(--color-border);
  border-radius: calc(var(--radius-card) * 0.4);
  overflow: hidden;
}
.brands-media--open .brands-media__window { border-style: dashed; }

.brands-media__plus {
  font-family: var(--font-mono);
  font-size: 1.8rem;
  color: var(--color-pale-grey);
}

/* ---- Brand Foundation (1.1-1.4) — client-supplied vertical frames.
   .brands-media__window already clips overflow, so the contained hover
   scale can't spill past its own card. Same restrained zoom as the
   portfolio figures (direction-page.css .pf-project__figure). ---- */
.brands-media__window--image img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform 550ms var(--ease-editorial);
}
.brands-media__window--image:hover img {
  transform: scale(1.045);
}

/* Case tag / project label — not a CTA, just identifies which project
   the frame is drawn from. Pinned bottom-right inside the image, same
   corner/inset on all four cards. Colors invert on hover (site's usual
   brand-purple accent) rather than reusing .direction-link's own
   black-on-hover, so it reads as a small tag, not a clickable action. */
.brands-media__tag {
  position: absolute;
  right: 0.6em;
  bottom: 0.6em;
  z-index: 1;
  max-width: calc(100% - 1.2em);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  line-height: 1.3;
  letter-spacing: var(--ls-normal);
  text-align: right;
  padding: 0.5em 0.7em;
  border-radius: var(--radius-btn);
  background: var(--color-black);
  color: var(--color-white);
  transition: background var(--dur-fast) var(--ease-editorial), color var(--dur-fast) var(--ease-editorial);
}
.brands-media__tag:hover {
  background: var(--color-accent);
  color: var(--color-black);
}

/* ---- Product Experience — three structural system-diagrams, same
   visual language as Brand Audit's GIFs (black window, thin white/
   muted lines, purple accent on active nodes, Consolas micro-labels)
   but static: each draws in once on scroll reveal instead of looping,
   since these read as a product SYSTEM, not a time-based process. ---- */
.brands-media__window--product {
  background: var(--color-black);
  border-color: var(--color-black);
}
.product-diagram { position: relative; width: 100%; height: 100%; }
.product-diagram svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.product-diagram text { font-family: var(--font-mono); }

.pd-caption {
  fill: rgba(255, 255, 255, 0.45);
  font-size: 8px;
  letter-spacing: 0.08em;
}
.pd-caption--top { fill: rgba(255, 255, 255, 0.55); font-size: 9px; font-weight: 700; }
.pd-caption--right { text-anchor: start; }

/* Building — surrounding cards converge into the central offer card. */
.pd-line line {
  stroke: rgba(255, 255, 255, 0.4);
  stroke-width: 1.5;
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
}
.pd-line { opacity: 0; }
.brands-media__window.is-visible .pd-line {
  animation: pd-line-draw 560ms var(--ease-editorial) forwards;
}
@keyframes pd-line-draw { 0% { opacity: 0; stroke-dashoffset: 60; } 20% { opacity: 1; } 100% { opacity: 1; stroke-dashoffset: 0; } }

.pd-card rect, .pd-tier rect {
  fill: rgba(255, 255, 255, 0.03);
  stroke: rgba(255, 255, 255, 0.45);
  stroke-width: 1.2;
}
.pd-card text {
  fill: rgba(255, 255, 255, 0.75);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-anchor: middle;
}
.pd-card, .pd-core {
  opacity: 0;
  transform: scale(0.9);
  transform-box: fill-box;
  transform-origin: center;
}
.brands-media__window.is-visible .pd-card,
.brands-media__window.is-visible .pd-core {
  animation: pd-pop 460ms var(--ease-editorial) forwards;
}
@keyframes pd-pop { to { opacity: 1; transform: scale(1); } }

.pd-core rect { fill: var(--color-accent); stroke: none; }
.pd-core text { fill: var(--color-black); font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-anchor: middle; }
.pd-pulse { fill: var(--color-white); opacity: 0.9; transform-box: fill-box; transform-origin: center; animation: pd-pulse-anim 2.2s ease-in-out infinite; }
@keyframes pd-pulse-anim { 0%, 100% { opacity: 0.5; transform: scale(1); } 50% { opacity: 1; transform: scale(1.6); } }

.pd-plus line { stroke: var(--color-accent); stroke-width: 1.4; }

/* Architecture — Entry / Core / Premium tiers + a growth ladder. */
.pd-tier text {
  fill: rgba(255, 255, 255, 0.8);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.pd-tier {
  opacity: 0;
  transform: translateX(-8px);
}
.brands-media__window.is-visible .pd-tier {
  animation: pd-slide-in 480ms var(--ease-editorial) forwards;
}
@keyframes pd-slide-in { to { opacity: 1; transform: translateX(0); } }
.pd-tier--core rect { fill: var(--color-accent); stroke: none; }
.pd-tier--core text { fill: var(--color-black); }

.pd-connector line {
  stroke: rgba(255, 255, 255, 0.4);
  stroke-width: 1.2;
  stroke-dasharray: 3 4;
}
.pd-connector, .pd-ladder { opacity: 0; }
.brands-media__window.is-visible .pd-connector,
.brands-media__window.is-visible .pd-ladder {
  animation: pd-fade-in 400ms linear forwards;
}
@keyframes pd-fade-in { to { opacity: 1; } }
.pd-ladder line { stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.2; }
.pd-ladder__spine { stroke: var(--color-accent) !important; stroke-width: 1.4 !important; }
.pd-ladder__dot { fill: var(--color-accent); }
.pd-ladder__label { fill: rgba(255, 255, 255, 0.65); font-size: 9px; letter-spacing: 0.06em; }
.pd-pulse-dot { transform-box: fill-box; transform-origin: center; animation: pd-pulse-anim 2.2s ease-in-out infinite; }

/* Experience — a stepped journey line to a central "more than a
   product" motif (two layered reference cards, same construct as the
   Strategy & Road Map visual-reference frames). */
.pd-path polyline {
  fill: none;
  stroke: rgba(255, 255, 255, 0.45);
  stroke-width: 1.5;
  stroke-dasharray: 7 6;
  stroke-dashoffset: 700;
}
.brands-media__window.is-visible .pd-path polyline {
  animation: pd-path-draw 1100ms var(--ease-editorial) forwards;
}
@keyframes pd-path-draw { to { stroke-dashoffset: 0; } }

.pd-node {
  fill: var(--color-black);
  stroke: rgba(255, 255, 255, 0.7);
  stroke-width: 1.4;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.brands-media__window.is-visible .pd-node {
  animation: pd-pop 360ms var(--ease-editorial) forwards;
}
.pd-node--result { fill: var(--color-accent); stroke: none; }
.brands-media__window.is-visible .pd-node--result {
  animation: pd-pop 360ms var(--ease-editorial) forwards, pd-pulse-anim 2.2s ease-in-out 400ms infinite;
}
.pd-journey__label {
  fill: rgba(255, 255, 255, 0.65);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-anchor: middle;
}
.pd-journey__label--result { fill: var(--color-accent); font-weight: 700; }

.pd-glass rect {
  fill: url(#pdGlassGrad);
  stroke: var(--color-accent);
  stroke-width: 1.2;
  opacity: 0.85;
}
.pd-glass {
  opacity: 0;
  transform: scale(0.9);
  transform-box: fill-box;
  transform-origin: center;
}
.brands-media__window.is-visible .pd-glass { animation: pd-pop 500ms var(--ease-editorial) forwards; }
.pd-glass__label {
  fill: rgba(255, 255, 255, 0.85);
  font-size: 9px;
  letter-spacing: 0.04em;
  text-anchor: middle;
  font-weight: 700;
}

/* ---- Market Development (01-04) — animated typographic cards. Same
   scan mechanic as Brand Audit's audit-cycle, sized dynamically per
   card by JS (js/brands.js sizeMarketCycle) to fill the window the
   way "Audit_Gyph 1.mov" does, over its own ambient black/purple/lime
   canvas (market-cycle__bg) rather than a flat background. No step
   title inside the card — DIGITAL / FLAGMAN.../ etc. live only in the
   .brands-media__label above it, per spec. ---- */
.brands-media__window--market {
  background: var(--color-black);
  border-color: var(--color-black);
}

.market-cycle__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  transition: filter var(--dur-base) var(--ease-editorial);
}
.brands-media__window--market:hover .market-cycle__bg {
  filter: brightness(1.15) saturate(1.12);
}

.market-cycle {
  --market-line-h: 3rem;
  --market-word-size: 1.6rem;
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.market-cycle__mask {
  position: absolute;
  inset: 0 6% 0 0;
  overflow: hidden;
}
.market-cycle__highlight {
  position: absolute;
  left: 0;
  right: 6%;
  top: 50%;
  height: var(--market-line-h);
  overflow: hidden;
  transform: translateY(-50%);
  pointer-events: none;
}
.market-cycle__track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  display: flex;
  flex-direction: column;
  animation: market-cycle-scroll linear infinite;
}
@keyframes market-cycle-scroll { to { transform: translateY(-50%); } }
.market-cycle__word {
  height: var(--market-line-h);
  line-height: var(--market-line-h);
  padding-left: 0.5em;
  font-family: var(--font-body);
  font-size: var(--market-word-size);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.market-cycle__mask .market-cycle__word { color: #4b5378; }
.market-cycle__highlight .market-cycle__word {
  color: #aab0ff;
  font-weight: 800;
}
.brands-media__window--market:hover .market-cycle__mask .market-cycle__word { color: #5b6499; }
.brands-media__window--market:hover .market-cycle__highlight .market-cycle__word { color: #c3c8ff; }

.market-cycle__dots {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 0.2em;
  pointer-events: none;
  opacity: 0.85;
  transition: opacity var(--dur-fast) var(--ease-editorial);
}
.brands-media__window--market:hover .market-cycle__dots { opacity: 1; }
.market-cycle__dots i {
  width: 0.26em;
  height: 0.26em;
  border-radius: 50%;
  background: #aab0ff;
  font-size: var(--market-word-size);
}

/* Market Development's own cards are typographic, not the photo
   frames Brand Foundation's cascade4 was built for — scoped override
   so its aspect-ratio doesn't leak into that other stage. */
#market-development .brands-grid--cascade4 .brands-media__window {
  aspect-ratio: 3 / 4;
}

/* ---- Result button — purple, bottom-right inside the window (used in
   place of a case tag on the three diagrams above, since there's no
   client project behind them). A plain <button> so hover AND keyboard/
   touch focus both reveal the outcome panel above it. ---- */
.brands-result {
  position: absolute;
  right: 0.6em;
  bottom: 0.6em;
  z-index: 2;
}
.brands-result__btn {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: var(--ls-normal);
  padding: 0.5em 0.8em;
  border: none;
  border-radius: var(--radius-btn);
  background: var(--color-accent);
  color: var(--color-black);
  transition: background var(--dur-fast) var(--ease-editorial);
}
.brands-result__btn:hover,
.brands-result__btn:focus-visible {
  background: var(--color-white);
}
.brands-result__panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.5em);
  width: max-content;
  max-width: 13rem;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: var(--lh-snug);
  color: var(--color-black);
  background: var(--color-white);
  border-radius: var(--radius-btn);
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.28);
  padding: 0.8em 1em;
  margin: 0;
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-editorial), transform var(--dur-fast) var(--ease-editorial);
}
.brands-result__btn:hover + .brands-result__panel,
.brands-result__btn:focus-visible + .brands-result__panel {
  opacity: 1;
  transform: translateY(0);
}

/* Short process description under each frame — secondary to the
   FOUNDER IDENTITY / BRAND PLATFORM / ... label above the image:
   body font, regular weight, muted. */
.brands-media__caption {
  margin-top: 0.6em;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 400;
  line-height: var(--lh-snug);
  color: var(--color-black);
  opacity: 0.7;
}

/* ---- Brand Audit / Research — vertical looping word cycle ----
   Two identical tracks scroll in lockstep: a dim full-height copy (all
   words, muted) and a purple copy visible only through a one-line slit
   pinned to the window's vertical center. Whichever word is crossing
   that slit at any instant reads as "active" — no per-word timing to
   keep in sync, both tracks just share one animation. */
.brands-media__window--audit-cycle {
  background: var(--color-black);
  border-color: var(--color-black);
  justify-content: flex-start;
}

.audit-cycle {
  --audit-line-h: clamp(1.9rem, 1.5rem + 1vw, 2.6rem);
  /* Reserves room on the right for the accumulation meter so long words
     (e.g. "Competitors") never run under it. */
  --audit-right-gutter: 22%;
  position: relative;
  width: 100%;
  height: 100%;
}

.audit-cycle__mask {
  position: absolute;
  inset: 0 var(--audit-right-gutter) 0 0;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 22%, black 78%, transparent 100%);
}

.audit-cycle__highlight {
  position: absolute;
  left: 0;
  right: var(--audit-right-gutter);
  top: 50%;
  height: var(--audit-line-h);
  overflow: hidden;
  transform: translateY(-50%);
  pointer-events: none;
}

/* Both tracks hold the exact same doubled word list (12 words x2), so
   both are positioned by the same rule: centered so the boundary
   between the two copies sits at the container's own 50% mark, then
   animated up by exactly one copy's height. Since the mask spans the
   full window and the highlight box is itself pinned to that window's
   vertical center, their "50%" marks coincide — so whichever word sits
   in the highlight slit is always the very word the dim layer shows at
   that same point, not a neighboring one. */
.audit-cycle__track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  margin-top: calc(var(--audit-line-h) * -6);
  display: flex;
  flex-direction: column;
  animation: audit-cycle-scroll 24s linear infinite;
}

@keyframes audit-cycle-scroll {
  to { transform: translateY(-50%); }
}

.audit-cycle__word {
  height: var(--audit-line-h);
  line-height: var(--audit-line-h);
  padding-left: 2.4em;
  font-family: var(--font-display);
  font-size: clamp(1rem, 0.86rem + 0.5vw, 1.3rem);
  font-weight: 600;
  letter-spacing: var(--ls-tight);
  white-space: nowrap;
}

.audit-cycle__mask .audit-cycle__word {
  color: rgba(255, 255, 255, 0.35);
}

.audit-cycle__highlight .audit-cycle__word {
  color: var(--color-accent);
  font-weight: 800;
  background: var(--color-black);
}

.audit-cycle__dots {
  position: absolute;
  top: 50%;
  left: 0.9em;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 0.28em;
  pointer-events: none;
}
.audit-cycle__dots i {
  width: 0.3em;
  height: 0.3em;
  border-radius: 50%;
  background: var(--color-accent);
  font-size: clamp(1rem, 0.86rem + 0.5vw, 1.3rem);
}

/* ---- Brand Audit / Research + Unpacking — shared accumulation meter ----
   A thin vertical, segmented indicator on the right edge of both cards:
   reads at once as a loading scale, a battery/storage level, and simply
   "information piling up" — filling bottom-to-top in the site's accent
   purple over the same clock as each card's own cycle, then resetting
   with it. One shared track/fill structure; only the timing function
   differs (--meter-in: stepped "data points arriving" for Research,
   smooth "gathered through conversation" for Unpacking) so the two
   cards read as one system while still speaking to their own step. */
.progress-meter {
  position: absolute;
  top: 14%;
  bottom: 14%;
  right: 5%;
  width: clamp(4px, 0.6vw, 6px);
  pointer-events: none;
}
.progress-meter__track,
.progress-meter__fill {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column-reverse;
  gap: 14%;
}
.progress-meter__track .progress-meter__cell {
  background: rgba(255, 255, 255, 0.12);
}
.progress-meter__fill .progress-meter__cell {
  background: var(--color-accent);
}
.progress-meter__track .progress-meter__cell,
.progress-meter__fill .progress-meter__cell {
  flex: 1;
  border-radius: 1px;
}
.progress-meter__fill {
  clip-path: inset(96% 0 0 0);
  animation-name: progress-meter-fill;
  animation-iteration-count: infinite;
}
.progress-meter--stepped .progress-meter__fill {
  animation-duration: 24s;
  animation-timing-function: steps(6, end);
}
.progress-meter--smooth .progress-meter__fill {
  animation-duration: 33s;
  animation-timing-function: linear;
}
/* Interview-collage's own bottom-right corner word sits lower than
   Research's dot/word-list content, so the smooth variant needs a
   taller bottom clearance to stay clear of it. */
.progress-meter--smooth { bottom: 27%; }
@keyframes progress-meter-fill {
  from { clip-path: inset(96% 0 0 0); }
  to   { clip-path: inset(0% 0 0 0); }
}

/* ---- Brand Audit / Unpacking — looping interview-photo cycle ----
   Real Zoom-call screenshots (full gallery view, not cropped to one
   face — see assets/images/brands/unpacking/) cross-fade one at a time
   in the center, framed by two two-line corner words — matching the
   client's reference composition (black canvas, accent-purple
   Montserrat corners, grayscale center), scaled to fit this workflow
   card rather than a full hero frame. */
.brands-media__window--interview-collage {
  background: var(--color-black);
  border-color: var(--color-black);
}

.interview-collage {
  position: relative;
  width: 100%;
  height: 100%;
}

.interview-collage__stage {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 46%;
  aspect-ratio: 1.85;
  border-radius: calc(var(--radius-card) * 0.25);
  overflow: hidden;
}

.interview-collage__frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: interview-cycle 33s linear infinite;
}

.interview-collage__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Same grayscale treatment as other portrait photography on the site
     (css/profile.css) — unifies stills shot in wildly different rooms
     into one clean, consistent "screen" look. */
  filter: grayscale(100%) contrast(1.05);
}

/* One image visible at a time, staggered per-frame via animation-delay
   (see js/brands.js) so the 11 frames chase each other around one
   shared 33s loop. Each frame's own slot is exactly 100/11%  (~9.09%)
   of the cycle, so frame i's fade-out lands exactly on frame i+1's
   fade-in — a seamless crossfade with no gap where nothing is visible.
   Hardcoded for 11 images; update alongside js/brands.js if that count
   ever changes. */
@keyframes interview-cycle {
  0% { opacity: 0; }
  1% { opacity: 1; }
  8.09% { opacity: 1; }
  9.09% { opacity: 0; }
  100% { opacity: 0; }
}

.interview-collage__word {
  position: absolute;
  display: flex;
  flex-direction: column;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(0.66rem, 0.5rem + 0.7vw, 1.05rem);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  color: var(--color-accent);
  line-height: 1.05;
}
.interview-collage__word--tl { top: 0.5em; left: 0.5em; align-items: flex-start; }
.interview-collage__word--br { bottom: 0.5em; right: 0.5em; align-items: flex-end; text-align: right; }

/* Row of 3 equal cells — Brand Audit (01/02/03) and Product Experience
   (01-03). Grid's default align-items:stretch is exactly what we want
   here: every .brands-media column stretches to the row's full height
   (so the divider between columns always reaches the bottom, however
   long a sibling's caption wraps), while .brands-media__window itself
   no longer grows into that extra height (see its flex:none above),
   so the image still renders at its true 4:3 size and every caption
   starts on the same line regardless. */
.brands-grid--row3 {
  grid-template-columns: repeat(3, 1fr);
}
.brands-grid--row3 .brands-media__window { aspect-ratio: 4 / 3; }

/* Row of 4 equal cells — Visual Foundation / Product Experience / Market
   Development (2.1-2.4, 3.1-3.4, 4.1-4.4): one plain horizontal grid,
   same window proportions throughout, no single cell blown up. */
.brands-grid--row4 {
  grid-template-columns: repeat(4, 1fr);
}
.brands-grid--row4 .brands-media__window { aspect-ratio: 4 / 3; }

/* Visual Foundation's own frames (client-supplied mockups: Brand ID,
   Photo Content, SMM Guide, Web Design) are vertical, not the 4:3
   default the other row4 stages (still placeholders) use — scoped to
   this stage only so Product Experience / Market Development are
   unaffected until they get their own real content. */
#visual-foundation .brands-grid--row4 .brands-media__window {
  aspect-ratio: 4 / 5;
}

/* Brand Audit's own layout: all three steps in one horizontal row,
   top- and bottom-aligned, same gap throughout — one continuous
   workflow, not a 2-up-plus-1-below split. Strategy & Road Map's column
   is proportionally wider (its SVG is native 16:9 vs the other two
   cards' 4:3), and that exact ratio (4/3 : 4/3 : 16/9) is what keeps
   all three windows the same height despite the different widths — no
   separate alignment rule needed. */
.brands-grid--row3wide {
  grid-template-columns: 1fr 1fr 1.333fr;
}
.brands-grid--row3wide .brands-media__window { aspect-ratio: 4 / 3; }
.brands-grid--row3wide .brands-media:nth-child(3) .brands-media__window {
  aspect-ratio: 16 / 9;
}

/* Cascading staircase of 4 — Brand Foundation (1.1-1.4): each step sits
   a little lower than the one before it, same window proportions as the
   other stages (not tall vertical cards). */
.brands-grid--cascade4 {
  --cascade-step: 4.5rem;
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
}
.brands-grid--cascade4 .brands-media { flex: 1; }
/* Brand Foundation's own frames are vertical (client-supplied collage
   images, ~1080x1520) — not the 4:3 default the other stages use. */
.brands-grid--cascade4 .brands-media__window { aspect-ratio: 1080 / 1520; }
.brands-grid--cascade4 .brands-media:nth-child(1) { margin-top: 0; }
.brands-grid--cascade4 .brands-media:nth-child(2) { margin-top: var(--cascade-step); }
.brands-grid--cascade4 .brands-media:nth-child(3) { margin-top: calc(var(--cascade-step) * 2); }
.brands-grid--cascade4 .brands-media:nth-child(4) { margin-top: calc(var(--cascade-step) * 3); }

/* Thin brand-purple dividers between consecutive media windows within a
   workflow row — reads as one step leading into the next, not a loose
   photo gallery. Centered in the grid gap. */
.brands-grid--row3 .brands-media:not(:first-child),
.brands-grid--row4 .brands-media:not(:first-child),
.brands-grid--cascade4 .brands-media:not(:first-child),
.brands-grid--row3wide .brands-media:not(:first-child) {
  position: relative;
}
.brands-grid--row3 .brands-media:not(:first-child)::before,
.brands-grid--row4 .brands-media:not(:first-child)::before,
.brands-grid--cascade4 .brands-media:not(:first-child)::before,
.brands-grid--row3wide .brands-media:not(:first-child)::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--space-3) / -2);
  width: 1px;
  background: var(--color-accent);
}

/* Product Experience's dividers shouldn't slice through the "01 PRODUCT
   BUILDING" label above each card — start them just below the header
   row instead of at the very top of the column. */
.brands-grid--row3 .brands-media:not(:first-child)::before {
  top: 1.6em;
}

/* Cascade4's items are staggered via margin-top, so a plain top:0/bottom:0
   (relative to each item) only spans that one item's own height. Override
   per step so every divider instead runs the full block height — from the
   top of the first photo to the bottom of the last. */
.brands-grid--cascade4 .brands-media:nth-child(2)::before {
  top: calc(-1 * var(--cascade-step));
  bottom: calc(-2 * var(--cascade-step));
}
.brands-grid--cascade4 .brands-media:nth-child(3)::before {
  top: calc(-2 * var(--cascade-step));
  bottom: calc(-1 * var(--cascade-step));
}
.brands-grid--cascade4 .brands-media:nth-child(4)::before {
  top: calc(-3 * var(--cascade-step));
  bottom: 0;
}

@media (max-width: 900px) {
  .brands-workflow { grid-template-columns: 1fr; }
  .brands-meta__row { grid-template-columns: 1fr; }
  .brands-grid--row3,
  .brands-grid--row4,
  .brands-grid--row3wide { grid-template-columns: 1fr; }
  .brands-grid--cascade4 { flex-direction: column; }
  .brands-grid--cascade4 .brands-media { margin-top: 0 !important; }
  .brands-grid--row3 .brands-media:not(:first-child)::before,
  .brands-grid--row4 .brands-media:not(:first-child)::before,
  .brands-grid--cascade4 .brands-media:not(:first-child)::before,
  .brands-grid--row3wide .brands-media:not(:first-child)::before {
    left: 0;
    right: 0;
    top: calc(var(--space-3) / -2);
    bottom: auto;
    width: auto;
    height: 1px;
  }
}

/* ========================================================================
   Brand Audit / Strategy & Road Map — one continuous 20s loop:
   INFORMATION -> CONNECTIONS -> DIRECTION -> ROADMAP -> STRATEGY.
   Chaotic dashed lines (carrying the Research word-set) converge into a
   single line, straighten into a horizontal roadmap, pick up the five
   Development Strategy stage names, a few short detail lines and neutral
   visual-reference frames, then a final accent pulse sweeps the route
   before it resolves to the title card and loops. Every element shares
   one clock (--sr-dur) via plain percentage keyframes — same shared-
   animation approach as the audit cycle and interview collage above, so
   nothing needs JS-driven timing.
   ======================================================================== */
.brands-media__window--strategy-roadmap {
  background: var(--color-black);
  border-color: var(--color-black);
}

.strategy-roadmap {
  --sr-dur: 20s;
  --sr-muted: rgba(255, 255, 255, 0.32);
  --sr-muted-strong: rgba(255, 255, 255, 0.55);
  --sr-white: rgba(255, 255, 255, 0.92);
  position: relative;
  width: 100%;
  height: 100%;
}
.strategy-roadmap svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.strategy-roadmap text { font-family: var(--font-display); }

/* ---- scene 1 — chaotic dashed lines ---- */
.strategy-roadmap__chaos-line {
  fill: none;
  stroke: var(--sr-muted);
  stroke-width: 2;
  stroke-dasharray: 9 7;
  opacity: 0;
  animation: sr-chaos-line var(--sr-dur) linear infinite;
}
@keyframes sr-chaos-line {
  0%   { opacity: 0; stroke-dashoffset: 0; }
  2%   { opacity: 1; }
  11%  { opacity: 1; stroke-dashoffset: -120; }
  15%  { opacity: 0; }
  100% { opacity: 0; }
}
.strategy-roadmap__chaos-word {
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 0.04em;
  fill: var(--sr-white);
  opacity: 0;
}
@keyframes sr-chaos-word-1 { 0%,3%{opacity:0;} 5%{opacity:1;} 9%{opacity:1;} 12%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-2 { 0%,4%{opacity:0;} 6%{opacity:1;} 10%{opacity:1;} 13%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-3 { 0%,2%{opacity:0;} 4%{opacity:1;} 8%{opacity:1;} 11%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-4 { 0%,5%{opacity:0;} 7%{opacity:1;} 10.5%{opacity:1;} 13%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-5 { 0%,3.5%{opacity:0;} 5.5%{opacity:1;} 9%{opacity:1;} 12%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-6 { 0%,2.5%{opacity:0;} 4.5%{opacity:1;} 8%{opacity:1;} 11%{opacity:0;} 100%{opacity:0;} }
@keyframes sr-chaos-word-7 { 0%,4.5%{opacity:0;} 6.5%{opacity:1;} 10%{opacity:1;} 12.5%{opacity:0;} 100%{opacity:0;} }

/* ---- scene 2 — converging lines ---- */
.strategy-roadmap__converge-line {
  fill: none;
  stroke: var(--sr-muted-strong);
  stroke-width: 2;
  stroke-dasharray: 9 7;
  opacity: 0;
  animation: sr-converge-line var(--sr-dur) linear infinite;
}
@keyframes sr-converge-line {
  0%, 10%  { opacity: 0; }
  13%      { opacity: 1; }
  24%      { opacity: 1; }
  27%      { opacity: 0; }
  100%     { opacity: 0; }
}
.strategy-roadmap__converge-dot {
  fill: var(--sr-white);
  opacity: 0;
  animation: sr-converge-dot var(--sr-dur) linear infinite;
}
@keyframes sr-converge-dot {
  0%, 18% { opacity: 0; r: 0; }
  21%     { opacity: 1; r: 4; }
  26%     { opacity: 1; r: 4; }
  28%     { opacity: 0; r: 0; }
  100%    { opacity: 0; }
}

/* ---- scenes 3+4+7 — the roadmap itself ---- */
.strategy-roadmap__line-base {
  fill: none;
  stroke: var(--sr-muted-strong);
  stroke-width: 2;
  opacity: 0;
  animation: sr-line-in var(--sr-dur) linear infinite;
}
@keyframes sr-line-in {
  0%, 25%  { opacity: 0; }
  27%      { opacity: 1; }
  100%     { opacity: 1; }
}
.strategy-roadmap__line-purple {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 3;
  stroke-dasharray: 960;
  stroke-dashoffset: 960;
  animation: sr-line-purple var(--sr-dur) linear infinite;
}
@keyframes sr-line-purple {
  0%, 27%  { stroke-dashoffset: 960; opacity: 1; }
  50%      { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: 0; }
}

.strategy-roadmap__dot {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  fill: var(--sr-muted-strong);
}
.strategy-roadmap__dot.n0 { animation: sr-dot-in var(--sr-dur) linear infinite, sr-dot-fill-0 var(--sr-dur) linear infinite; }
.strategy-roadmap__dot.n1 { animation: sr-dot-in var(--sr-dur) linear infinite 0.12s, sr-dot-fill-1 var(--sr-dur) linear infinite; }
.strategy-roadmap__dot.n2 { animation: sr-dot-in var(--sr-dur) linear infinite 0.24s, sr-dot-fill-2 var(--sr-dur) linear infinite; }
.strategy-roadmap__dot.n3 { animation: sr-dot-in var(--sr-dur) linear infinite 0.36s, sr-dot-fill-3 var(--sr-dur) linear infinite; }
.strategy-roadmap__dot.n4 { animation: sr-dot-in var(--sr-dur) linear infinite 0.48s, sr-dot-fill-4 var(--sr-dur) linear infinite; }
@keyframes sr-dot-in {
  0%, 28% { opacity: 0; transform: scale(0); }
  32%     { opacity: 1; transform: scale(1.3); }
  35%     { opacity: 1; transform: scale(1); }
  100%    { opacity: 1; transform: scale(1); }
}
@keyframes sr-dot-fill-0 { 0%, 30% { fill: var(--sr-muted-strong); } 33% { fill: var(--color-accent); } 100% { fill: var(--color-accent); } }
@keyframes sr-dot-fill-1 { 0%, 39% { fill: var(--sr-muted-strong); } 42% { fill: var(--color-accent); } 100% { fill: var(--color-accent); } }
@keyframes sr-dot-fill-2 { 0%, 43% { fill: var(--sr-muted-strong); } 46% { fill: var(--color-accent); } 100% { fill: var(--color-accent); } }
@keyframes sr-dot-fill-3 { 0%, 47% { fill: var(--sr-muted-strong); } 50% { fill: var(--color-accent); } 100% { fill: var(--color-accent); } }
@keyframes sr-dot-fill-4 { 0%, 48% { fill: var(--sr-muted-strong); } 51% { fill: var(--color-accent); } 100% { fill: var(--color-accent); } }

/* ---- scene 4 — stage labels (Development Strategy roadmap) ---- */
.strategy-roadmap__label {
  font-weight: 800;
  font-size: 19px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  fill: var(--sr-muted-strong);
  opacity: 0;
}
.strategy-roadmap__label.l0 { animation: sr-label-in-0 var(--sr-dur) linear infinite, sr-dot-fill-0 var(--sr-dur) linear infinite; }
.strategy-roadmap__label.l1 { animation: sr-label-in-1 var(--sr-dur) linear infinite, sr-dot-fill-1 var(--sr-dur) linear infinite; }
.strategy-roadmap__label.l2 { animation: sr-label-in-2 var(--sr-dur) linear infinite, sr-dot-fill-2 var(--sr-dur) linear infinite; }
.strategy-roadmap__label.l3 { animation: sr-label-in-3 var(--sr-dur) linear infinite, sr-dot-fill-3 var(--sr-dur) linear infinite; }
.strategy-roadmap__label.l4 { animation: sr-label-in-4 var(--sr-dur) linear infinite, sr-dot-fill-4 var(--sr-dur) linear infinite; }
@keyframes sr-label-in-0 { 0%, 32% { opacity: 0; transform: translateY(6px);} 36% { opacity: 1; transform: translateY(0);} 100% { opacity: 1; transform: translateY(0);} }
@keyframes sr-label-in-1 { 0%, 41% { opacity: 0; transform: translateY(6px);} 45% { opacity: 1; transform: translateY(0);} 100% { opacity: 1; transform: translateY(0);} }
@keyframes sr-label-in-2 { 0%, 45% { opacity: 0; transform: translateY(6px);} 49% { opacity: 1; transform: translateY(0);} 100% { opacity: 1; transform: translateY(0);} }
@keyframes sr-label-in-3 { 0%, 49% { opacity: 0; transform: translateY(6px);} 53% { opacity: 1; transform: translateY(0);} 100% { opacity: 1; transform: translateY(0);} }
@keyframes sr-label-in-4 { 0%, 50% { opacity: 0; transform: translateY(6px);} 54% { opacity: 1; transform: translateY(0);} 100% { opacity: 1; transform: translateY(0);} }

/* ---- scene 5 — short detail blocks ---- */
.strategy-roadmap__detail { opacity: 0; }
.strategy-roadmap__detail-line { font-weight: 500; font-size: 14px; fill: var(--sr-muted-strong); }
.strategy-roadmap__detail-head { font-weight: 800; font-size: 14px; fill: var(--color-accent); letter-spacing: .04em; }
.strategy-roadmap__detail.d0 { animation: sr-detail-0 var(--sr-dur) linear infinite; }
.strategy-roadmap__detail.d1 { animation: sr-detail-1 var(--sr-dur) linear infinite; }
.strategy-roadmap__detail.d2 { animation: sr-detail-2 var(--sr-dur) linear infinite; }
@keyframes sr-detail-0 { 0%,54% {opacity:0;} 57% {opacity:1;} 62% {opacity:1;} 65%{opacity:0.18;} 100%{opacity:0.18;} }
@keyframes sr-detail-1 { 0%,61% {opacity:0;} 64% {opacity:1;} 69% {opacity:1;} 72%{opacity:0.18;} 100%{opacity:0.18;} }
@keyframes sr-detail-2 { 0%,68% {opacity:0;} 71% {opacity:1;} 76% {opacity:1;} 79%{opacity:0.18;} 100%{opacity:0.18;} }

/* ---- scene 6 — neutral visual-reference frames growing from the dots ---- */
.strategy-roadmap__card {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: bottom center;
  transform: scaleY(0);
}
.strategy-roadmap__card.c0 { animation: sr-card-0 var(--sr-dur) linear infinite; }
.strategy-roadmap__card.c1 { animation: sr-card-1 var(--sr-dur) linear infinite; }
.strategy-roadmap__card.c2 { animation: sr-card-2 var(--sr-dur) linear infinite; }
@keyframes sr-card-0 { 0%,74% {opacity:0; transform: scaleY(0);} 77%{opacity:1; transform: scaleY(1);} 83%{opacity:1; transform: scaleY(1);} 86%{opacity:0; transform: scaleY(0);} 100%{opacity:0;} }
@keyframes sr-card-1 { 0%,75% {opacity:0; transform: scaleY(0);} 78%{opacity:1; transform: scaleY(1);} 84%{opacity:1; transform: scaleY(1);} 87%{opacity:0; transform: scaleY(0);} 100%{opacity:0;} }
@keyframes sr-card-2 { 0%,76% {opacity:0; transform: scaleY(0);} 79%{opacity:1; transform: scaleY(1);} 85%{opacity:1; transform: scaleY(1);} 88%{opacity:0; transform: scaleY(0);} 100%{opacity:0;} }

/* ---- scene 7 — final accent pulse sweeping the completed route ---- */
.strategy-roadmap__pulse {
  opacity: 0;
  offset-path: path('M170,380 L1110,380');
  offset-distance: 0%;
  animation: sr-pulse-go var(--sr-dur) linear infinite;
}
@keyframes sr-pulse-go {
  0%, 85%  { opacity: 0; offset-distance: 0%; }
  87%      { opacity: 1; }
  93%      { opacity: 1; offset-distance: 100%; }
  95%      { opacity: 0; }
  100%     { opacity: 0; }
}

/* ---- everything collapses before the title card ---- */
.strategy-roadmap__group {
  animation: sr-roadmap-out var(--sr-dur) linear infinite;
  transform-box: fill-box;
  transform-origin: 640px 380px;
}
@keyframes sr-roadmap-out {
  0%, 92%  { opacity: 1; transform: scale(1); }
  97%      { opacity: 0; transform: scale(0.92); }
  100%     { opacity: 0; transform: scale(0.92); }
}

/* ---- final title card ---- */
.strategy-roadmap__title {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  opacity: 0;
  animation: sr-title-in var(--sr-dur) linear infinite;
  pointer-events: none;
}
.strategy-roadmap__title h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 58px;
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--color-accent);
  text-align: center;
}
@keyframes sr-title-in {
  0%, 95%  { opacity: 0; }
  97.5%    { opacity: 1; }
  99.5%    { opacity: 1; }
  100%     { opacity: 0; }
}
