/* ══════════════════════════════════════════════════════════════════
   VISION SINDH — HOME, below the hero.
   "The dig": ink → paper (the excavated archive) → ink (the present).

   Contract
     · additive only — page is complete without this file and without JS
     · every pre-reveal (hidden) state is gated behind  html.vs-mo
       (set by home-sections.js only when motion is allowed), so a JS
       failure or prefers-reduced-motion can never hide content
     · html.vs-on  = JS built the decorative nodes (static styling)
     · ember #d9611f appears only as LIGHT — glows, sweeps, rim tips
   ══════════════════════════════════════════════════════════════════ */

:root {
  --vs-ember: #d9611f;
  --vs-bone: #e9e4da;
  --vs-slow: cubic-bezier(0.16, 1, 0.3, 1);
  /* travelling lights need near-constant speed — --vs-slow is so front-loaded
     that a spark crosses its rule in the first fifth of its duration */
  --vs-travel: cubic-bezier(0.42, 0.03, 0.28, 1);
}

.vs-sr {
  position: absolute !important; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════
   1 — THE BRIDGES
   Two long gradient cuts through the ground. Sediment strata sit in
   the ink half; one shared canvas carries the dust that rises out of
   the dark (bridge--up) and settles back into it (bridge).
   ══════════════════════════════════════════════════════════════════ */

.bridge, .bridge--up {
  position: relative;
  overflow: clip;
  height: clamp(230px, 34svh, 400px);
}

/* the one canvas — re-parented between the two bridges, never both */
.vs-dust {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* sediment: irregular hairlines, visible only where the ground is dark */
.vs-strata {
  position: absolute; left: 0; right: 0; top: -14%; bottom: -14%;
  pointer-events: none; z-index: 0;
  mix-blend-mode: overlay;
  opacity: 0.32;
  /* three co-prime periods so the bands never read as scan-lines */
  background-image:
    repeating-linear-gradient(to bottom, rgba(233, 228, 218, 0.26) 0 1px, transparent 1px 59px),
    repeating-linear-gradient(to bottom, rgba(233, 228, 218, 0.17) 0 1px, transparent 1px 97px),
    repeating-linear-gradient(to bottom, rgba(233, 228, 218, 0.11) 0 1px, transparent 1px 163px);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 72%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 72%, transparent);
  transform: translate3d(0, var(--vs-strata-y, 0px), 0);
  will-change: transform;
}
/* the paper→ink bridge is dark at the BOTTOM: flip the mask */
.bridge > .vs-strata {
  -webkit-mask-image: linear-gradient(to top, transparent, #000 18%, #000 72%, transparent);
  mask-image: linear-gradient(to top, transparent, #000 18%, #000 72%, transparent);
}

/* ══════════════════════════════════════════════════════════════════
   2 — CHAPTERS  (paper — keep it airy)
   A giant outlined Devanagari glyph is excavated behind each row:
   it wipes open on entry and drifts on scroll. The row's hairline
   draws left→right and an ember spark runs the length of it once.
   ══════════════════════════════════════════════════════════════════ */

.chapter-row {
  position: relative;
  overflow: clip;
  overflow-clip-margin: 8px;
}
/* real content always paints above the glyph layer */
.chapter-row > span { position: relative; z-index: 2; }

/* The glyph is a RUBBING, not a graphic: it surfaces at the head of the row
   and dissolves downward, so the paragraph and thumbnails always sit on
   clean paper. The mask — not opacity alone — is what guarantees that. */
.vs-glyph {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: clip;
  display: block;
  /* fades in at the very top too: otherwise the Devanagari shirorekha (the
     bar every letter hangs from) survives alone and reads as a stray rule */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, rgba(0, 0, 0, 0.45) 38%, transparent 62%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, rgba(0, 0, 0, 0.45) 38%, transparent 62%);
}
.vs-glyph b {
  position: absolute;
  left: var(--gx, 50%); top: 34%;
  font-family: var(--font-display); font-weight: 400;
  font-size: calc(clamp(210px, 46vw, 330px) * var(--gs, 1));
  line-height: 0.76; white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1px color-mix(in srgb, var(--ink) 9%, transparent);
  transform: translate(-50%, -50%) translate3d(var(--px, 0px), var(--py, 0px), 0);
  opacity: var(--go, 1);
}
@media (min-width: 781px) {
  /* desktop rows are short and wide — the copy sits in the left columns,
     so the glyph can carry a little more of the row height */
  .vs-glyph {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 18%, rgba(0, 0, 0, 0.5) 52%, transparent 82%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 18%, rgba(0, 0, 0, 0.5) 52%, transparent 82%);
  }
  .vs-glyph b { top: 42%; -webkit-text-stroke: 1.3px color-mix(in srgb, var(--ink) 10%, transparent); }
}

/* hairline that draws across the foot of the row */
.vs-hair {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; z-index: 1;
  background: var(--ink); opacity: 0.55;
  transform-origin: 0 50%;
  pointer-events: none;
}
/* ember spark riding that hairline — light, once */
.vs-spark {
  position: absolute; left: 0; bottom: -7px; z-index: 1;
  width: 120px; height: 15px; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(217, 97, 31, 0.55), rgba(217, 97, 31, 0.12) 45%, rgba(217, 97, 31, 0) 72%);
  transform: translate3d(-120px, 0, 0);
}
.chapter-row { container-type: inline-size; }

/* mono date digits roll into place */
/* The 20-cell column is taken OUT OF FLOW (absolute) — an in-flow column
   would push the date line to 20× its height. */
.vs-digit {
  position: relative;
  display: inline-block; width: 1ch; height: 1em;
  overflow: hidden; vertical-align: -0.2em;
}
.vs-digit i {
  position: absolute; top: 0; left: 0; right: 0;
  display: block; font-style: normal;
  transform: translate3d(0, calc(var(--d, 0) * -1em), 0);
}
.vs-digit b { display: block; height: 1em; line-height: 1em; font-weight: inherit; text-align: left; }

/* the live chapter carries an ember pilot-light */
/* leads the line rather than trailing it — trailing, it wraps onto a line of
   its own in the narrow desktop date column */
.vs-live {
  display: inline-block; width: 15px; height: 15px;
  margin-right: 0.45em; vertical-align: -0.28em;
  background: radial-gradient(circle at 50% 50%,
    rgba(217, 97, 31, 0.82) 0 7%, rgba(217, 97, 31, 0.26) 28%, rgba(217, 97, 31, 0) 66%);
}

/* ══════════════════════════════════════════════════════════════════
   3 — DROP GRID  (ink)
   One ember wavefront crosses the whole grid diagonally on entry —
   light raking black cloth (screen blend), never a fill.
   ══════════════════════════════════════════════════════════════════ */

/* (.card figure is already position:relative in site.css — nothing to add) */
/* A narrow specular RAKE — a bright core with only a warm fringe. Wide or
   strong here and `screen` stops reading as light and starts tinting the
   cloth sepia, which would make ember a surface colour. It must not. */
.vs-sweep {
  position: absolute; top: -18%; bottom: -18%; left: 0; width: 22%;
  pointer-events: none; z-index: 3; opacity: 0;
  mix-blend-mode: screen;
  background: linear-gradient(90deg,
    rgba(217, 97, 31, 0) 0%,
    rgba(217, 97, 31, 0.05) 26%,
    rgba(255, 247, 238, 0.17) 50%,
    rgba(217, 97, 31, 0.045) 74%,
    rgba(217, 97, 31, 0) 100%);
  transform: translate3d(-170%, 0, 0) skewX(-8deg);
}

/* ══════════════════════════════════════════════════════════════════
   4 — DRAWING RULE  (used under the drop heading + over the ritual hr)
   A hairline that draws itself with an ember tip travelling ahead.
   ══════════════════════════════════════════════════════════════════ */

.vs-rule {
  position: relative; height: 1px; margin-block: 30px 0;
  container-type: inline-size;
  /* the tip parks at 100cqw when it finishes; without this it pushes the
     document 130px wide. The clip-margin still lets the glow bleed. */
  overflow: clip;
  overflow-clip-margin: 12px;
}
.vs-rule::before {
  content: ""; position: absolute; inset: 0;
  background: currentColor; opacity: 0.42;
  transform-origin: 0 50%;
}
.vs-rule i {
  position: absolute; top: -8px; left: 0;
  width: 130px; height: 17px; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(217, 97, 31, 0.60), rgba(217, 97, 31, 0.14) 45%, rgba(217, 97, 31, 0) 72%);
  transform: translate3d(-130px, 0, 0);
}

/* ══════════════════════════════════════════════════════════════════
   5 — RITUAL  (ink)
   01–04 become large outlined numerals; a rule draws along the head
   of each step with an ember node lighting as it lands.
   ══════════════════════════════════════════════════════════════════ */

.vs-step { position: relative; padding-top: 30px; }
.vs-step__line {
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--ink-soft); opacity: 0.38;
  transform-origin: 0 50%;
}
.vs-step__node {
  position: absolute; top: -7px; left: -7px;
  width: 15px; height: 15px; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 50%,
    rgba(217, 97, 31, 0.95) 0 13%, rgba(217, 97, 31, 0.32) 34%, rgba(217, 97, 31, 0) 70%);
}
.vs-step .eyebrow {
  display: flex; align-items: baseline; gap: 14px;
  margin-bottom: 14px;
}
.vs-step__num {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(40px, 5.2vw, 66px); line-height: 0.82;
  letter-spacing: 0; text-transform: none;
  color: transparent;
  -webkit-text-stroke: 1.1px color-mix(in srgb, var(--ink) 52%, transparent);
}
.vs-step__label { color: var(--ash); }

/* ══════════════════════════════════════════════════════════════════
   6 — MOTION LAYER
   Everything below only exists when html.vs-mo is present.
   Without it the page renders in its finished state, static.
   ══════════════════════════════════════════════════════════════════ */

/* the rubbing is uncovered sideways (the vertical axis belongs to the mask) */
.vs-mo .vs-glyph b {
  clip-path: inset(0 102% 0 0);
  transition: clip-path 2.1s var(--vs-slow);
  will-change: transform;
}
.vs-mo .chapter-row.vs-in .vs-glyph b { clip-path: inset(0 -2% 0 0); }

.vs-mo .vs-hair {
  transform: scaleX(0);
  transition: transform 1.5s var(--vs-slow) 0.1s;
}
.vs-mo .chapter-row.vs-in .vs-hair { transform: none; }
.vs-mo .chapter-row.vs-in .vs-spark { animation: vs-run 2.6s var(--vs-travel) 0.4s both; }

.vs-mo .chapter-row__thumbs img {
  opacity: 0; transform: translate3d(0, 20px, 0);
  transition: opacity 1s var(--vs-slow), transform 1s var(--vs-slow);
}
.vs-mo .chapter-row.vs-in .chapter-row__thumbs img { opacity: 1; transform: none; }
.vs-mo .chapter-row__thumbs img:nth-child(1) { transition-delay: 0.30s; }
.vs-mo .chapter-row__thumbs img:nth-child(2) { transition-delay: 0.36s; }
.vs-mo .chapter-row__thumbs img:nth-child(3) { transition-delay: 0.42s; }

/* The RESTING state of a digit column is already the correct digit (set in
   §2). The roll is an animation away from 0 and back to rest, so a missed
   observer can never leave a wrong date on screen. */
.vs-mo .chapter-row.vs-in .vs-digit i {
  animation: vs-roll 1.25s var(--vs-slow) calc(var(--k, 0) * 90ms + 150ms) backwards;
}
@keyframes vs-roll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, calc(var(--d, 0) * -1em), 0); }
}

.vs-mo .vs-live { animation: vs-pilot 4.2s ease-in-out infinite; }

.vs-mo .on-ink .grid .card {
  opacity: 0; transform: translate3d(0, 24px, 0);
  transition: opacity 1s var(--vs-slow), transform 1.1s var(--vs-slow);
  transition-delay: var(--d, 0ms);
}
.vs-mo .on-ink .grid .card.vs-in { opacity: 1; transform: none; }
.vs-mo .on-ink .grid .card figure {
  clip-path: inset(0 0 100% 0);
  transition: transform 0.35s var(--ease), clip-path 1.25s var(--vs-slow);
  transition-delay: 0s, var(--d, 0ms);
}
.vs-mo .on-ink .grid .card.vs-in figure { clip-path: inset(0 0 0 0); }
.vs-mo .on-ink .grid .card.vs-in .vs-sweep {
  animation: vs-sweep 1.6s cubic-bezier(0.37, 0, 0.18, 1) calc(var(--d, 0ms) + 420ms) both;
}

.vs-mo .vs-rule::before {
  transform: scaleX(0);
  transition: transform 1.7s var(--vs-slow);
}
.vs-mo .vs-rule.vs-in::before { transform: none; }
.vs-mo .vs-rule.vs-in i { animation: vs-run 2.8s var(--vs-travel) 0.2s both; }

.vs-mo .vs-step__line {
  transform: scaleX(0);
  transition: transform 1.3s var(--vs-slow);
  transition-delay: calc(var(--i, 0) * 170ms);
}
.vs-mo .vs-step.vs-in .vs-step__line { transform: none; }
/* the node is part of the composition, not just the animation — it lights in
   reduced-motion too (vs-in is applied in both modes); only the fade is motion */
.vs-on .vs-step.vs-in .vs-step__node { opacity: 1; }
.vs-mo .vs-step__node {
  transition: opacity 0.9s ease;
  transition-delay: calc(var(--i, 0) * 170ms + 0.6s);
}
.vs-mo .vs-step__num {
  opacity: 0; transform: translate3d(0, 14px, 0);
  transition: opacity 1.1s var(--vs-slow), transform 1.1s var(--vs-slow);
  transition-delay: calc(var(--i, 0) * 170ms + 0.18s);
}
.vs-mo .vs-step.vs-in .vs-step__num { opacity: 1; transform: none; }
.vs-mo .io .vs-step[data-reveal] { transition-delay: calc(var(--i, 0) * 150ms); }

@keyframes vs-run {
  0%   { opacity: 0; transform: translate3d(-130px, 0, 0); }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(100cqw, 0, 0); }
}
@keyframes vs-sweep {
  0%   { opacity: 0; transform: translate3d(-170%, 0, 0) skewX(-8deg); }
  16%  { opacity: 1; }
  84%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(560%, 0, 0) skewX(-8deg); }
}
@keyframes vs-pilot {
  0%, 100% { opacity: 0.32; }
  50%      { opacity: 1; }
}

/* Belt-and-braces: html.vs-mo is only ever set when motion is allowed, but if
   the OS setting flips after load, freeze OUR decorations in their finished
   state. Scoped element-by-element — never a descendant wildcard, which would
   reach the hero (another owner's surface). */
@media (prefers-reduced-motion: reduce) {
  .vs-mo .vs-glyph b,
  .vs-mo .vs-hair,
  .vs-mo .vs-spark,
  .vs-mo .vs-digit i,
  .vs-mo .vs-live,
  .vs-mo .vs-strata,
  .vs-mo .vs-rule::before,
  .vs-mo .vs-rule i,
  .vs-mo .vs-sweep,
  .vs-mo .vs-step__line,
  .vs-mo .vs-step__node,
  .vs-mo .vs-step__num,
  .vs-mo .chapter-row__thumbs img,
  .vs-mo .on-ink .grid .card,
  .vs-mo .on-ink .grid .card figure {
    animation: none !important;
    transition: none !important;
  }
  .vs-mo .vs-glyph b { clip-path: none !important; }
  .vs-mo .vs-hair, .vs-mo .vs-rule::before, .vs-mo .vs-step__line { transform: none !important; }
  .vs-mo .vs-spark, .vs-mo .vs-rule i, .vs-mo .vs-sweep { opacity: 0 !important; }
  .vs-mo .vs-step__node { opacity: 1 !important; }
  .vs-mo .vs-step__num,
  .vs-mo .chapter-row__thumbs img,
  .vs-mo .on-ink .grid .card { opacity: 1 !important; transform: none !important; }
  .vs-mo .on-ink .grid .card figure { clip-path: inset(0) !important; }
}

/* ── coarse-pointer economy: blend modes force full repaints of large
     layers on every driven var change at mobile DPR — swap to plain
     low-alpha composites; the whisper layers read the same. ── */
@media (pointer: coarse) {
  .vs-strata { mix-blend-mode: normal !important; opacity: 0.5; }
  [class*="vs-"][style*="--px"] { will-change: transform; }
}

@media (pointer: coarse) { .vs-sweep { mix-blend-mode: normal !important; opacity: 0.55; } }
/* pre-promote the stroked glyph layers — a huge -webkit-text-stroke glyph
   re-rasterizes on its first driven transform unless already composited */
.vs-glyph b { will-change: transform, opacity; }
