/* ==========================================================================
   TECHMATIC SYSTEMS — motion + visual layer
   --------------------------------------------------------------------------
   Part 1 (blocks 1-10) is the motion layer.
   Part 2 (blocks 11-15) adds this page's visual devices: the CI pipeline
   panel, ghost section numerals, the cross-module ripple diagram, the
   hardware device chips and the headline figure.

   ADDITIVE. Loaded AFTER style.css, only by
   quality-engineering-solutions.html. It adds nothing to the
   other pages and overrides no existing rule destructively, so style.css stays
   the single source of truth for the design system.

   MOTION CONCEPT — "an instrument coming online"
     Light moves across surfaces; type rises into place; rails fill as you
     travel them. Every effect is anchored to the page's existing directional
     light (violet key upper-right, cyan fill lower-left). Nothing drifts,
     spins, bounces or floats for its own sake.

   SAFETY — the same guarantee style.css makes
     Every hidden starting state is gated on html.tq-anim, which anim.js adds
     at run time. If anim.js fails to load or throws, the class never lands and
     the page renders exactly like the static version. A script failure can
     never blank or half-hide content.

     anim.js also refuses to add .tq-anim at all when prefers-reduced-motion is
     set, so reduced-motion users get the static page rather than a stripped
     approximation of an animation.
   ========================================================================== */

.tmqa {
  --tq-spring: cubic-bezier(.22, 1, .36, 1);
  --tq-glide:  cubic-bezier(.33, 1, .68, 1);
}


/* ==========================================================================
   1 · SPLIT-WORD TYPE REVEAL
   Words rise out of a clipping mask, staggered. anim.js wraps each word in
   .tq-w > .tq-wi and sets --i for the stagger index.
   ========================================================================== */
.tmqa .tq-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* room for descenders and for the serif italic's overshoot */
  padding-bottom: .14em;
  margin-bottom: -.14em;
}
.tq-anim .tmqa [data-split] .tq-wi {
  display: inline-block;
  transform: translateY(105%);
  opacity: 0;
}
.tq-anim .tmqa [data-split].is-lit .tq-wi {
  transform: translateY(0);
  opacity: 1;
  transition:
    transform .82s var(--tq-spring) calc(var(--i, 0) * 42ms),
    opacity   .62s ease             calc(var(--i, 0) * 42ms);
}


/* ==========================================================================
   2 · BLOCK RISE
   For everything that is not split type: ledes, panels, grids, notes.
   Replaces the base [data-rv] distance with a slightly longer, softer move.
   ========================================================================== */
.tq-anim .tmqa [data-rise] {
  opacity: 0;
  transform: translateY(26px);
}
.tq-anim .tmqa [data-rise].is-lit {
  opacity: 1;
  transform: none;
  transition:
    opacity   .8s ease                calc(var(--d, 0) * 1ms),
    transform .9s var(--tq-spring)    calc(var(--d, 0) * 1ms);
}


/* ==========================================================================
   3 · SECTION INDEX — the hairline draws itself across
   ========================================================================== */
.tmqa .tq-idx { position: relative; border-bottom-color: transparent; }
.tmqa .tq-idx::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg,
    rgba(124,92,255,.85), rgba(34,211,238,.55) 40%, var(--line) 78%, var(--line));
  transform: scaleX(0); transform-origin: left center;
}
.tq-anim .tmqa .tq-idx.is-lit::after {
  transform: scaleX(1);
  transition: transform 1.15s var(--tq-glide);
}
/* Without the motion layer the rule is simply there, undrawn. */
html:not(.tq-anim) .tmqa .tq-idx::after { transform: scaleX(1); }

/* Eyebrow glyph turns into place */
.tq-anim .tmqa .tq-eyebrow::before {
  transform: rotate(45deg) scale(0);
  transition: transform .6s var(--tq-spring) .1s;
}
.tq-anim .tmqa .tq-eyebrow.is-lit::before { transform: rotate(45deg) scale(1); }


/* ==========================================================================
   4 · POINTER SPOTLIGHT
   A pool of key light follows the cursor across a surface. Applied to cells,
   step rows and the comparison table. NOTE: no transforms on these elements —
   they are butted hairline grids, and moving them would break the 1px seams
   the design depends on.
   ========================================================================== */
.tmqa .tq-cell,
.tmqa .tq-step,
.tmqa .tq-vs-row:not(.tq-vs-head) { position: relative; }

.tmqa .tq-cell::after,
.tmqa .tq-step::after {
  content: ""; position: absolute; inset: 0; z-index: 0;
  pointer-events: none; opacity: 0;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    rgba(124,92,255,.20), rgba(34,211,238,.06) 45%, transparent 72%);
  transition: opacity .4s ease;
}
.tmqa .tq-cell > *,
.tmqa .tq-step > * { position: relative; z-index: 1; }

@media (hover: hover) and (min-width: 900px) {
  .tmqa .tq-cell:hover::after,
  .tmqa .tq-step:hover::after { opacity: 1; }
}

/* Lit top edge that brightens with the pointer */
.tmqa .tq-cell::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; z-index: 2;
  background: linear-gradient(90deg, transparent,
    rgba(255,255,255,.34) var(--mx, 50%), transparent);
  opacity: 0; transition: opacity .4s ease;
}
@media (hover: hover) and (min-width: 900px) {
  .tmqa .tq-cell:hover::before { opacity: 1; }
}


/* ==========================================================================
   5 · STEP ROWS — travel, and a rail that fills as you scroll it
   ========================================================================== */
.tmqa .tq-steps { position: relative; }
.tmqa .tq-steps::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--line-2);
}
.tmqa .tq-steps::after {
  content: ""; position: absolute; left: 0; top: 0; width: 2px;
  height: var(--fill, 0%);
  background: linear-gradient(180deg, var(--vio), var(--cyan));
  transition: height .18s linear;
}
.tmqa .tq-steps .tq-step { padding-left: clamp(20px, 2.4vw, 34px); }

.tq-anim .tmqa .tq-step { transition: transform .45s var(--tq-spring); }
@media (hover: hover) and (min-width: 900px) {
  .tmqa .tq-step:hover { transform: translateX(7px); }
}

.tmqa .tq-step-no { transition: color .35s ease, letter-spacing .35s ease; }
.tmqa .tq-step.is-passed .tq-step-no { color: var(--cyan-hi); letter-spacing: .18em; }


/* ==========================================================================
   6 · COMPARISON TABLE — rows wipe in, the winning column sweeps
   ========================================================================== */
.tq-anim .tmqa .tq-vs-row:not(.tq-vs-head) {
  clip-path: inset(0 100% 0 0);
}
.tq-anim .tmqa .tq-vs-row.is-lit {
  clip-path: inset(0 0 0 0);
  transition: clip-path .78s var(--tq-glide) calc(var(--i, 0) * 90ms);
}
/* The wash on the Playwright column arrives after its row has wiped in. */
.tq-anim .tmqa .tq-vs-row:not(.tq-vs-head) .tq-vs-new {
  background-size: 220% 100%;
  background-position: 100% 0;
}
.tq-anim .tmqa .tq-vs-row.is-lit .tq-vs-new {
  background-position: 0 0;
  transition: background-position 1.1s var(--tq-glide) calc(var(--i, 0) * 90ms + 420ms);
}


/* ==========================================================================
   7 · AURORA — the light drifts with scroll and leans toward the pointer
   anim.js writes --ax / --ay; both are plain translations, so this stays on
   the compositor and never triggers layout.
   ========================================================================== */
.tq-anim .tmqa .tq-aura {
  transform: translate3d(var(--ax, 0px), var(--ay, 0px), 0);
  will-change: transform;
}


/* ==========================================================================
   8 · MAGNETIC BUTTONS + PRACTICE STRIP
   ========================================================================== */
.tq-anim .tmqa .tq-btn {
  transform: translate3d(var(--tx, 0px), var(--ty, 0px), 0);
  transition: transform .35s var(--tq-spring), background-color .22s var(--ease-io),
              color .22s var(--ease-io), border-color .22s var(--ease-io),
              box-shadow .3s var(--ease-io);
}
.tmqa .tq-btn-key { position: relative; overflow: hidden; }
.tmqa .tq-btn-key::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(120px circle at var(--mx, 50%) var(--my, 50%),
    rgba(124,92,255,.30), transparent 70%);
  transition: opacity .35s ease;
}
.tmqa .tq-btn-key:hover::after { opacity: 1; }

.tmqa .tq-stack-grid li { position: relative; overflow: hidden; }

/* This strip carries FOUR practices; the component was built for six, so it
   needs its own column counts. These must live in CSS, not as an inline
   style attribute: an inline style beats every media query, which is exactly
   what pinned the strip at four 82.5px columns on a phone.
   The 1180px rule exists only to override style.css's 3-column step, which
   would leave a 3 + 1 orphan row. */
.tmqa .tq-stack-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1180px) {
  .tmqa .tq-stack-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .tmqa .tq-stack-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .tmqa .tq-stack-4 { grid-template-columns: minmax(0, 1fr); }
}

/* Each practice cell jumps to its section. The anchor takes over the cell's
   padding so the whole cell is the hit area, not just the words.
   outline-offset is negative on purpose: the li is overflow:hidden for the
   light sweep, which would clip the default +3px focus ring entirely. */
.tmqa .tq-stack-grid li { padding: 0; }
.tmqa .tq-stack-grid li > a {
  position: relative; display: block;
  /* height:100% matters: the li is a grid item stretched to the tallest cell
     in the row, so without it the anchor only covers its own content and the
     bottom of the taller cells is not clickable. */
  height: 100%;
  padding: 18px 16px;
  color: inherit; text-decoration: none;
}
.tmqa .tq-stack-grid li > a:focus-visible { outline-offset: -3px; }

/* HOVER / FOCUS — no arrow glyph, so the state has to carry the affordance on
   its own. Three signals at once, all in the page's existing language:
     1. the surface lifts two steps (void -> slate), not one
     2. a 2px violet-to-cyan bar grows down the leading edge, the same device
        the section index rules and step rails use
     3. the sub-label turns cyan, the way .tq-link does elsewhere
   Applied to the anchor rather than the li so keyboard focus gets the same
   treatment as the pointer, without needing :has(). No transform on the cell
   itself — these are butted hairline cells and moving one breaks the seams. */
.tmqa .tq-stack-grid li > a {
  transition: background-color .28s var(--ease-io);
}
.tmqa .tq-stack-grid li > a:hover,
.tmqa .tq-stack-grid li > a:focus-visible { background: var(--slate); }

.tmqa .tq-stack-grid li > a::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(180deg, var(--vio), var(--cyan));
  transform: scaleY(0); transform-origin: center top;
  transition: transform .38s var(--tq-spring);
}
.tmqa .tq-stack-grid li > a:hover::before,
.tmqa .tq-stack-grid li > a:focus-visible::before { transform: scaleY(1); }

.tmqa .tq-stack-grid li > a span { transition: color .28s var(--ease-io); }
.tmqa .tq-stack-grid li > a:hover span,
.tmqa .tq-stack-grid li > a:focus-visible span { color: var(--cyan-hi); }

@media (prefers-reduced-motion: reduce) {
  .tmqa .tq-stack-grid li > a,
  .tmqa .tq-stack-grid li > a::before,
  .tmqa .tq-stack-grid li > a span { transition: none !important; }
}
.tq-anim .tmqa .tq-stack-grid li {
  opacity: 0; transform: translateY(18px);
}
.tq-anim .tmqa .tq-stack-grid.is-lit li {
  opacity: 1; transform: none;
  transition: opacity .7s ease calc(var(--i, 0) * 90ms),
              transform .8s var(--tq-spring) calc(var(--i, 0) * 90ms);
}
/* A single pass of light travels the strip once it has landed. */
.tmqa .tq-stack-grid li::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 42%,
    rgba(255,255,255,.09) 50%, transparent 58%);
  transform: translateX(-140%);
}
.tq-anim .tmqa .tq-stack-grid.is-swept li::after {
  transform: translateX(140%);
  transition: transform 1.05s var(--tq-glide) calc(var(--i, 0) * 90ms + 500ms);
}


/* ==========================================================================
   9 · SCROLL PROGRESS
   Fixed, and gated by anim.js on this block owning the viewport, exactly like
   the section rail — it must never sit over the host site's header.
   ========================================================================== */
.tmqa .tq-prog {
  /* --tq-prog-top exists for one reason: this bar is fixed to the viewport,
     so if the host site's header is fixed or sticky the bar would otherwise
     draw ON TOP of it. Set this to the header's height in that case and the
     bar sits just beneath it. Default 0 is correct for a header that scrolls
     away with the page. */
  position: fixed; left: 0; top: var(--tq-prog-top, 0px);
  height: 2px; width: 100%;
  z-index: 45; pointer-events: none;
  opacity: 0; transition: opacity .3s ease;
}
.tmqa .tq-prog.is-on { opacity: 1; }
.tmqa .tq-prog i {
  display: block; height: 100%; width: var(--p, 0%);
  background: linear-gradient(90deg, var(--vio), var(--cyan));
  box-shadow: 0 0 14px rgba(124,92,255,.55);
}


/* ==========================================================================
   10 · SECTION EDGE LIGHT
   Each section's top hairline lights briefly as it enters.
   ========================================================================== */
.tmqa .tq-sec { overflow: hidden; }
.tmqa .tq-sec > .tq-edge {
  position: absolute; left: 0; right: 0; top: 0; height: 1px; z-index: 3;
  background: linear-gradient(90deg, transparent,
    rgba(124,92,255,.75) 30%, rgba(34,211,238,.55) 60%, transparent);
  transform: scaleX(0); transform-origin: left center; opacity: 0;
}
.tq-anim .tmqa .tq-sec.is-lit > .tq-edge {
  transform: scaleX(1); opacity: 1;
  transition: transform 1.3s var(--tq-glide), opacity 1.3s ease;
}


/* ==========================================================================
   REDUCED MOTION
   anim.js does not add .tq-anim under prefers-reduced-motion, so nothing above
   is hidden. These rules additionally neutralise the always-on flourishes.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .tmqa .tq-cell::after, .tmqa .tq-step::after,
  .tmqa .tq-cell::before, .tmqa .tq-btn-key::after,
  .tmqa .tq-stack-grid li::after { display: none !important; }
  .tmqa .tq-step:hover { transform: none !important; }
  .tmqa .tq-idx::after { transform: scaleX(1) !important; }
  .tmqa .tq-steps::after { transition: none !important; }
  .tmqa .tq-prog { display: none !important; }
}


/* ==========================================================================
   PART 2 · VISUAL DEVICES
   Each device illustrates something the source document claims. Nothing here
   is invented data: the pipeline stages are the CI systems the document
   names, the ripple nodes are the four ERP subsystems its opening paragraph
   lists, and the device chips are the peripherals its POS section enumerates.
   ========================================================================== */

/* --------------------------------------------------------------------------
   11 · CI PIPELINE PANEL  (hero)
   Illustrates "we integrate quality checks directly into your CI/CD
   pipelines, preventing defective code from reaching production".
   -------------------------------------------------------------------------- */
.tmqa .tq-pipe {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  font-family: var(--f-mono);
}
.tmqa .tq-pipe-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px; border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.02);
  font-size: 11px; letter-spacing: .04em; color: var(--mute);
}
.tmqa .tq-pipe-bar b { color: var(--text); font-weight: 500; }
.tmqa .tq-pipe-state {
  margin-left: auto; display: inline-flex; align-items: center; gap: 7px;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pass); transition: color .3s ease;
}
.tmqa .tq-pipe.is-held .tq-pipe-state { color: var(--warn); }

.tmqa .tq-pipe-list { padding: 6px 0; position: relative; }

/* The rail the run travels down.
   Geometry comes from anim.js, which measures the first and last stage nodes
   and writes --rail-x / --rail-top / --rail-span. Hard-coded offsets were
   wrong in three ways: 3px left of the node centres, overhanging 6.6px past
   the first and last dot, and — because the fill height was a percentage of
   the whole list rather than of the node span — running past the last node
   into the footer at 100%. --runf is a unitless 0..1 fraction of the span. */
.tmqa .tq-pipe-list::before {
  content: ""; position: absolute;
  left: var(--rail-x, 28.5px); top: var(--rail-top, 22px);
  width: 1px; height: var(--rail-span, 0px);
  background: var(--line-2);
}
.tmqa .tq-pipe-list::after {
  content: ""; position: absolute;
  left: var(--rail-x, 28.5px); top: var(--rail-top, 22px);
  width: 1px;
  height: calc(var(--rail-span, 0px) * var(--runf, 0));
  background: linear-gradient(180deg, var(--vio), var(--cyan));
  transition: height .42s var(--tq-glide);
}

.tmqa .tq-stage {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: 26px 1fr auto;
  gap: 12px; align-items: center;
  padding: 8px 16px; font-size: 11.5px; line-height: 1.5;
}
/* State is carried by the node colour and by the two text colours below —
   NEVER by row opacity. Dimming the row multiplied with each text's own alpha
   and drove queued rows to 1.94:1, the identical failure the token ramp had.
   Colour alone keeps every state independently measurable, and it leaves the
   static fallback (no .tq-anim) fully bright. */

.tmqa .tq-stage-node {
  justify-self: center;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--abyss); border: 1.5px solid var(--line-3);
  transition: background-color .3s ease, border-color .3s ease,
              transform .3s var(--tq-spring);
}
.tmqa .tq-stage.is-on .tq-stage-node {
  border-color: var(--cyan-hi); background: var(--cyan-hi); transform: scale(1.3);
}
.tmqa .tq-stage.is-done .tq-stage-node { border-color: var(--pass); background: var(--pass); }
.tmqa .tq-stage.is-flag .tq-stage-node { border-color: var(--warn); background: var(--warn); }
.tmqa .tq-stage.is-held .tq-stage-node { border-color: var(--fail); background: var(--abyss); }

.tmqa .tq-stage-n { color: rgba(238,240,246,.86); transition: color .35s ease; }
.tmqa .tq-stage-n b { color: var(--text); font-weight: 500; }
.tmqa .tq-stage-t {
  font-size: 10.5px; color: rgba(238,240,246,.62);
  font-variant-numeric: tabular-nums; white-space: nowrap;
  transition: color .35s ease;
}
/* Queued — reached by nothing yet. 6.1:1, clearly secondary but readable. */
.tq-anim .tmqa .tq-stage:not(.is-on):not(.is-done):not(.is-flag):not(.is-held) .tq-stage-n,
.tq-anim .tmqa .tq-stage:not(.is-on):not(.is-done):not(.is-flag):not(.is-held) .tq-stage-t {
  color: rgba(238,240,246,.58);
}
.tmqa .tq-stage.is-flag .tq-stage-t { color: var(--warn); }
.tmqa .tq-stage.is-held .tq-stage-t { color: var(--fail); }

.tmqa .tq-pipe-foot {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 13px 16px; border-top: 1px solid var(--line);
  background: rgba(255,255,255,.02);
  font-size: 10.5px; letter-spacing: .05em; color: var(--mute);
}
.tmqa .tq-pipe-foot b {
  font-weight: 500; font-variant-numeric: tabular-nums; color: var(--text);
}
.tmqa .tq-pipe-foot .tq-f-warn b { color: var(--warn); }
.tmqa .tq-pipe-foot .tq-f-end { margin-left: auto; color: rgba(238,240,246,.58); }


/* --------------------------------------------------------------------------
   12 · GHOST SECTION NUMERALS
   A large, quiet numeral behind each section opening. Editorial weight at
   almost no cost, and it makes the five sections instantly countable.
   -------------------------------------------------------------------------- */
.tmqa .tq-ghost {
  position: absolute; z-index: 0; pointer-events: none;
  right: clamp(-8px, 1vw, 40px); top: clamp(16px, 3.4vw, 56px);
  font-family: var(--f-disp); font-weight: 800;
  font-size: clamp(110px, 16vw, 260px); line-height: .82;
  letter-spacing: -.05em;
  color: transparent;
  -webkit-text-stroke: 1px rgba(238,240,246,.08);
  user-select: none;
}
.tq-anim .tmqa .tq-ghost {
  opacity: 0; transform: translateY(30px);
  transition: opacity 1.1s ease, transform 1.3s var(--tq-glide);
}
.tq-anim .tmqa .tq-sec.is-lit .tq-ghost { opacity: 1; transform: none; }

@media (max-width: 760px) { .tmqa .tq-ghost { display: none; } }


/* --------------------------------------------------------------------------
   13 · CROSS-MODULE RIPPLE  (ERP)
   Illustrates the document's own first bullet — one change in a custom flow
   breaking journal entries, stock valuation and procurement downstream —
   using the four subsystems its opening paragraph names.
   -------------------------------------------------------------------------- */
.tmqa .tq-ripple { display: block; width: 100%; height: auto; overflow: visible; }
.tmqa .tq-ripple-edge {
  fill: none; stroke: var(--line-2); stroke-width: 1; stroke-dasharray: 3 5;
}
.tmqa .tq-ripple-live {
  fill: none; stroke: url(#tqRipGrad); stroke-width: 1.7; stroke-linecap: round;
}
.tmqa .tq-ripple-node circle {
  fill: var(--abyss); stroke: var(--line-3); stroke-width: 1;
  transition: fill .45s ease, stroke .45s ease;
}
.tmqa .tq-ripple-node text {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .05em;
  fill: rgba(238,240,246,.62); transition: fill .45s ease;
}
.tmqa .tq-ripple-node.is-hit circle { fill: rgba(124,92,255,.30); stroke: var(--vio-hi); }
.tmqa .tq-ripple-node.is-hit text { fill: var(--text); }
.tmqa .tq-ripple-src circle { stroke: var(--cyan-hi); }
.tmqa .tq-ripple-src.is-hit circle { fill: rgba(34,211,238,.26); stroke: var(--cyan-hi); }
.tmqa .tq-ripple-cap {
  font-family: var(--f-mono); font-size: 10.5px; line-height: 1.62;
  color: rgba(238,240,246,.52); margin: 14px 0 0;
}


/* --------------------------------------------------------------------------
   14 · HARDWARE DEVICE CHIPS  (POS)
   The exact peripherals the document lists.
   -------------------------------------------------------------------------- */
.tmqa .tq-devs {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
}
.tmqa .tq-dev {
  position: relative; background: var(--abyss);
  padding: clamp(16px, 1.8vw, 22px) clamp(12px, 1.4vw, 16px);
  transition: background-color .35s var(--ease-io);
}
.tmqa .tq-dev:hover { background: var(--slate); }
.tmqa .tq-dev svg {
  width: 22px; height: 22px; display: block; margin-bottom: 12px;
  stroke: var(--cyan-hi); stroke-width: 1.25; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s var(--tq-spring);
}
.tmqa .tq-dev:hover svg { transform: translateY(-3px); }
.tmqa .tq-dev b {
  display: block; font-family: var(--f-disp); font-size: 13px; font-weight: 600;
  letter-spacing: -.012em; color: var(--text); margin-bottom: 4px;
}
.tmqa .tq-dev span {
  display: block; font-family: var(--f-mono); font-size: 10px;
  letter-spacing: .04em; color: rgba(238,240,246,.52);
}

@media (max-width: 900px) { .tmqa .tq-devs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .tmqa .tq-devs { grid-template-columns: minmax(0, 1fr); } }


/* --------------------------------------------------------------------------
   15 · HEADLINE FIGURE
   The document's one number, given the weight of a claim.
   -------------------------------------------------------------------------- */
.tmqa .tq-figure {
  display: flex; align-items: baseline; gap: 2px;
  font-family: var(--f-disp); font-weight: 800;
  font-size: clamp(56px, 7.6vw, 104px); line-height: .9; letter-spacing: -.045em;
  color: var(--text); margin: 0 0 12px;
}
.tmqa .tq-figure i {
  font-style: normal; font-size: .44em; letter-spacing: -.02em;
  background: linear-gradient(120deg, var(--vio-hi), var(--cyan-hi));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.tmqa .tq-figure-k {
  font-family: var(--f-mono); font-size: 11px; line-height: 1.62;
  letter-spacing: .06em; color: rgba(238,240,246,.52); margin: 0; max-width: 34ch;
}


@media (prefers-reduced-motion: reduce) {
  .tmqa .tq-dev:hover svg { transform: none !important; }
  .tmqa .tq-pipe-list::after { transition: none !important; }
}
