/* ============================================================
   THE ASCENT — the red staircase at TNAADO HQ, on both tech pages.
   T-1152, 2026-08-14.

   Ethan supplied the frame with its own description: "red staircase at
   tnaado hq. every client is brought up the red carpet, our staircase up.
   a bold path up."

   WHY THIS PHOTOGRAPH GETS BUILT WORK AND THE OTHERS DID NOT.
   /media can point a camera at a shoot. /technology and /tech sell
   engineering, which photographs as somebody at a laptop — the frame Ethan
   has now rejected four times. So the answer on these two pages is designed
   and animated visuals carrying the argument, plus ONE real photograph used
   properly. This is that photograph, and it appears exactly ONCE per page.

   IT IS ALREADY THE BRAND, SO IT IS NOT "BRANDED".
   No scrim, no duotone, no red wash, no gradient. --red #c8102e and
   --bone #faf8f3 are literally the two colours in the frame. Anything laid
   over it would be painting red on red. It is served at full brightness.

   NO TEXT SITS ON THE IMAGE. Ethan, verbatim: "the design concept of little
   text white on black then big image needs to go — not what i want
   anywhere." Every word here is on the bone ground beside the frame, where
   ink on bone measures 18.6:1 and needs no scrim to be legible. That is the
   whole reason the light ground exists.

   THE ANIMATION IS EARNED BY THE SUBJECT, NOT APPLIED TO IT.
   The frame is near-perfect one-point perspective: the vanishing point is
   the lit doorway at the top, measured at 50% across and 22% down the
   source file. A slow scroll-driven push toward THAT point reads as
   ascending the stairs. The same push on any other photograph would read as
   a stock Ken Burns zoom, which is why it is not used anywhere else.
   Budget: 5.5% of scale across the whole section, transform only, no
   filter, no opacity churn. js/tech-ascent.js owns it and never registers
   under prefers-reduced-motion — the frame simply renders static.
   ============================================================ */

.asc {
  position: relative;
  overflow: hidden;
}

.asc__inner {
  margin-inline: auto;
  max-width: 1180px;
  padding-inline: clamp(1.15rem, 5vw, 3rem);
  display: grid;
  gap: clamp(1.9rem, 5vw, 4rem);
  align-items: center;
}

@media (min-width: 900px) {
  .asc__inner { grid-template-columns: 1fr 1fr; }
  /* /technology reads type -> photograph; /tech reads photograph -> type.
     Mirrored on purpose so the two pages do not run the identical block. */
  .asc--hq   .asc__inner { grid-template-columns: 1.02fr .98fr; }
  .asc--path .asc__inner { grid-template-columns: .94fr 1.06fr; }
}

/* ── THE FRAME ────────────────────────────────────────────────
   Contained, never edge to edge (tnaado-system.css §3). overflow:hidden is
   load-bearing: it is what the scaling image is clipped against, so the
   push happens INSIDE a fixed rectangle rather than growing the layout. */
.asc__fig { margin: 0; }

.asc__frame {
  position: relative;
  overflow: hidden;
  background: #efe9e2;                 /* the wall colour, so the box never
                                          flashes white before decode */
  border: 1px solid var(--sys-rule-light, rgba(10, 10, 10, .14));
}

/* Both crops are taller than the 4:3 source, which is the point: the source
   is LANDSCAPE, so cropping toward portrait removes the stairwell walls at
   the sides and NOTHING vertically. The doorway therefore cannot be cropped
   out at any width — the vanishing point survives every viewport.
   /technology takes 4:5, /tech takes a square, so the two pages carry the
   same frame in visibly different shapes on opposite sides of the grid. */
.asc--hq   .asc__frame { aspect-ratio: 4 / 5; }
.asc--path .asc__frame { aspect-ratio: 1 / 1; }

@media (max-width: 899px) {
  /* Stacked on a phone, a 4:5 frame is nearly the whole viewport and the
     copy beneath it never gets seen. Both pages go to 4:3 there — still the
     full height of the source, so the doorway is still in frame. */
  .asc--hq .asc__frame,
  .asc--path .asc__frame { aspect-ratio: 4 / 3; }
}

.asc__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 50% keeps the staircase centred at every width — the frame is
     symmetrical about its own centre line, so a horizontal shift would
     break the one-point perspective that makes the push work.
     30% down keeps the vanishing point in the upper third of any
     letterboxed crop instead of drifting off the top edge. */
  object-position: 50% 30%;
  /* The push converges on the doorway, not on the middle of the box. */
  transform-origin: 50% 22%;
  transform: scale(1);
  /* No transition: js/tech-ascent.js writes transform once per frame from
     the scroll position, and a transition would fight the scrub. */
}

.asc__cap {
  margin: .8rem 0 0;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--sys-mute-light, rgba(10, 10, 10, .62));
}

/* ── THE COPY COLUMN ──────────────────────────────────────── */
.asc__eyebrow {
  margin: 0 0 .9rem;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--sys-red-on-light, #a4132c);
}

/* --ink is INVERTED to bone inside some light scopes (pricing.css .pr-light),
   so `color: var(--ink)` can resolve to bone and render invisible type. This
   is the bug that made every headline on /pricing disappear. --ink-true never
   flips. Same reason the literal fallback is spelled out. */
.asc__h2 {
  margin: 0;
  font-family: var(--font-display, Fraunces, Georgia, serif);
  font-weight: 300;
  font-size: clamp(1.85rem, 4.4vw, 3.15rem);
  line-height: 1.08;
  letter-spacing: -.02em;
  color: var(--ink-true, #0a0a0a);
  /* Evens the line lengths so a two-line headline does not leave one word
     stranded. Ignored by browsers that do not support it, which just get
     the normal greedy wrap — no layout depends on it. */
  text-wrap: balance;
}

.asc__h2 em {
  font-style: italic;
  color: var(--sys-red-on-light, #a4132c);
}

.asc__p {
  margin: 1.1rem 0 0;
  max-width: 46ch;
  font-size: clamp(.98rem, 1.35vw, 1.08rem);
  line-height: 1.62;
  color: var(--sys-mute-light, rgba(10, 10, 10, .62));
}

.asc__addr {
  margin: 1.5rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--sys-rule-light, rgba(10, 10, 10, .14));
  font-style: normal;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .78rem;
  line-height: 1.85;
  letter-spacing: .04em;
  color: var(--ink-true, #0a0a0a);
}

/* ══════════════════════════════════════════════════════════════
   THE TREADS — /tech only.

   The photograph already contains a numbered sequence: the treads. So the
   stages of an engagement are drawn as steps climbing beside it rather than
   set as another three-column paragraph block, which is what this replaces
   in spirit — "we have less to physically show" is solved by drawing the
   thing, not by writing about it.

   THE LIST IS REVERSED VISUALLY, NOT IN THE DOM. column-reverse puts stage
   01 at the BOTTOM so the sequence climbs, matching the image beside it.
   The DOM stays 01 -> 05, so reading order, focus order and the numbering a
   screen reader announces are all still correct.
   ══════════════════════════════════════════════════════════════ */
.asc__steps {
  display: flex;
  flex-direction: column-reverse;
  justify-content: flex-end;
  gap: .1rem;
  margin: 1.7rem 0 0;
  padding: 0;
  list-style: none;
}

.asc__step {
  position: relative;
  /* Each step sits further right than the one below it AND stops further
     short of the right edge, so the whole column narrows as it climbs.
     Insetting the STEP rather than just its rule is what keeps the
     description text inside its own tread — the first cut inset only the
     rule and the copy overhung it by ~30px on the middle steps.
     Both sides are capped in vw so they cannot eat the label column on a
     phone. */
  padding: .62rem
           calc(var(--i, 0) * clamp(0px, 1.9vw, 22px))
           .62rem
           calc(var(--i, 0) * clamp(0px, 1.1vw, 13px));
  display: grid;
  grid-template-columns: 2.35rem 1fr;
  align-items: baseline;
  column-gap: .55rem;
}

.asc__n {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .72rem;
  letter-spacing: .08em;
  color: var(--sys-red-on-light, #a4132c);
}

.asc__t {
  font-size: clamp(.96rem, 1.3vw, 1.06rem);
  font-weight: 500;
  color: var(--ink-true, #0a0a0a);
}

.asc__d {
  grid-column: 2;
  margin: .18rem 0 0;
  font-size: .84rem;
  line-height: 1.5;
  color: var(--sys-mute-light, rgba(10, 10, 10, .62));
}

/* The tread itself: a red rule under each step that wipes in left to right.
   clip-path rather than scaleX so the bar never appears from nothing — an
   inset() reveal keeps the element at its true size the whole time.

   THE RULES CONVERGE AS THEY CLIMB. Each one is indented from the left by
   its own --i (the .asc__step padding) AND pulled in from the right by it,
   so the stack narrows toward the top. That is the same one-point
   perspective the photograph beside it is built on: the treads in the frame
   converge on the doorway, and these converge with them. The first cut had
   them ragged-left and flush-right, which read as five dividers rather than
   as a stair. */
.asc__tread {
  grid-column: 1 / -1;
  display: block;
  height: 2px;
  margin-top: .6rem;
  background: var(--sys-red, #c8102e);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 440ms cubic-bezier(0.23, 1, 0.32, 1);
  transition-delay: calc(var(--i, 0) * 70ms + 60ms);
}

/* Steps rise into place, staggered 70ms apart, bottom of the stair first —
   which is DOM order, so no per-item delay maths is needed beyond --i. */
.asc__step {
  opacity: 0;
  transform: translateY(9px);
  transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1),
              transform 300ms cubic-bezier(0.23, 1, 0.32, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.asc__steps.is-up .asc__step { opacity: 1; transform: none; }
.asc__steps.is-up .asc__tread { clip-path: inset(0 0 0 0); }

/* No-JS: the steps must not be permanently invisible. */
.no-js .asc__step { opacity: 1; transform: none; }
.no-js .asc__tread { clip-path: inset(0 0 0 0); }

/* NO LINK STYLES HERE ON PURPOSE. The first cut of this section carried its
   own "start a build" link; /tech already runs the handoff pair and the
   closing CTA within 400px of scroll below it, so a third call to action
   was clutter rather than a route. The rules were deleted rather than left
   unused — dead CSS is how a stylesheet stops describing the page. */

/* ── REDUCED MOTION ───────────────────────────────────────────
   Fewer and gentler, not zero: the treads still resolve so the sequence is
   readable, they just do not travel and they do not stagger. The push is
   never registered at all — js/tech-ascent.js returns before observing —
   so the photograph renders static at scale(1). */
@media (prefers-reduced-motion: reduce) {
  .asc__step {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0ms;
  }
  .asc__tread {
    clip-path: inset(0 0 0 0);
    transition: none;
    transition-delay: 0ms;
  }
  .asc__img { transform: none !important; }
}
