/* ─────────────────────────────────────────────────────────────────────────
   jt-services.css - the Services rack, dressed as equipment.

   The page was five identical boxes stacking six blocks of flat text each.
   Nothing here moves a word or reorders a block: every rule dresses a block
   that was already there, so the page still reads top to bottom the way it
   was written.

   Most of these elements carry inline styles from the design-tool export, and
   an inline style beats any selector - so where a rule restyles a property the
   markup already sets, it has to say !important. Rules that only add something
   new (pseudo-elements, backgrounds on a bare element) do not, and are left
   plain so the difference stays visible.

   Motion: every transition below waits on [data-lit], which jt-reveal.js sets
   once per dossier. Nothing animates on load, on scroll, or twice.
   ───────────────────────────────────────────────────────────────────────── */

/* ══ 0. the file: pull tab, and folding it shut ════════════════════════ */
/* Same two parts Industries and Technologies already use, so a visitor who has
   seen one rack knows what the tab and the mark do here. Collapsing leaves the
   red header and the front panel standing: a rack unit that is closed but
   still powered, which is a more useful summary than a bare title bar. */

.jt-dossier {
  position: relative;
  /* the tab hangs above the article's top edge; the export clips it away */
  overflow: visible !important;
}

.jt-file-tab {
  position: absolute;
  top: -2px;
  right: 22px;
  transform: translateY(-100%);
  padding: 6px 12px 5px;
  border-radius: 3px 3px 0 0;
  background: var(--kb-red);
  color: #F3EEDF;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.14s;
}
.jt-file-tab:hover { background: var(--color-accent-2-700); }

/* with overflow visible the header would square off the article's rounded top */
.jt-tab-head { border-radius: 3px 3px 0 0; }
.jt-tab-head:focus-visible { outline: 3px solid #FFF; outline-offset: -3px; }

.jt-file-mark {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 21px;
  height: 21px;
  border: 1.5px solid rgba(255, 255, 255, 0.55);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.16);
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
}

/* 1fr -> 0fr collapses to nothing without needing the height measured */
.jt-file-body {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.34s cubic-bezier(0.22, 0.9, 0.25, 1);
}
.jt-file-body > div { min-height: 0; overflow: hidden; }
.jt-file-body[data-open="0"] { grid-template-rows: 0fr; }
@media (prefers-reduced-motion: reduce) {
  .jt-file-body { transition: none; }
}

/* ══ 1. front panel: three dials under the folder tab ═══════════════════ */
/* The readings are the lengths of the lists further down the dossier, so the
   panel is a summary of the article rather than decoration bolted onto it. */

.jt-gauges {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(10px, 2vw, 26px);
  padding: clamp(12px, 1.8vw, 18px) clamp(18px, 2.6vw, 34px);
  border-bottom: 2px solid var(--jt-navy);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.55), rgba(0, 35, 73, 0.05)),
    repeating-linear-gradient(90deg, #E4DDCA 0 2px, #DED7C4 2px 4px);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.6), inset 0 -3px 6px rgba(0, 35, 73, 0.08);
}

.jt-gauge {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* the instrument answers to the hand: glass brightens, plate sinks on press */
.jt-gauge:hover .jt-gauge-face {
  box-shadow:
    inset 0 0 0 2px #8E8776,
    inset 0 3px 7px rgba(0, 35, 73, 0.22),
    0 2px 0 rgba(255, 255, 255, 0.7),
    0 0 0 3px rgba(222, 50, 38, 0.16);
}
.jt-gauge:hover .jt-gauge-plate b { color: var(--kb-red); }
.jt-gauge:active .jt-gauge-plate {
  transform: translateY(1px);
  box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.38);
}
.jt-gauge-face,
.jt-gauge-plate { transition: box-shadow 0.16s linear, transform 0.08s linear; }

/* Cooling louvres closing out the panel. A rack panel this wide would not be
   left blank to the right of its instruments, and stamped slots are the
   cheapest honest thing to put there - no invented readout, no filler copy. */
/* A real element rather than ::after: the slats take a click, so they have to
   be something the pointer and the tab order can reach. */
.jt-vent {
  flex: 1 1 90px;
  align-self: stretch;
  min-height: 34px;
  margin-left: auto;
  border-radius: 2px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background: repeating-linear-gradient(
    180deg,
    rgba(0, 35, 73, 0.22) 0 2px,
    rgba(255, 255, 255, 0.5) 2px 3px,
    transparent 3px 9px
  );
  box-shadow: inset 0 0 0 1px rgba(0, 35, 73, 0.12);
  opacity: 0.75;
  transition: opacity 0.16s linear, box-shadow 0.16s linear, background-position 0.16s linear;
}
.jt-vent:hover { opacity: 1; box-shadow: inset 0 0 0 1px rgba(0, 35, 73, 0.3); }
.jt-vent:active { background-position: 0 2px; }
.jt-vent:focus-visible,
.jt-gauge:focus-visible {
  outline: 2px solid var(--kb-red);
  outline-offset: 3px;
}

/* click: the slats run once, the way a shutter sweeps when the fan kicks in */
.jt-vent[data-tick] { animation: jt-vent-run 0.42s steps(9) 1; }
@keyframes jt-vent-run {
  from { background-position: 0 0; opacity: 1; }
  to { background-position: 0 9px; opacity: 0.75; }
}

/* The service's own mark, punched into the panel. The dials are near enough
   identical across the five services because the offer is deliberately
   uniform, so this is what makes one front panel distinguishable from the
   next at a glance. */
/* Cell size is stated, not derived. Sizing the tile and letting `1fr` columns
   plus `aspect-ratio: 1` work out the cell gave a 3.71px column holding a
   5.25px square: the grid overflowed its own tile by 3px and the tile came out
   50x60 instead of square. Fixed tracks in both axes cannot disagree. */
.jt-emblem {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: repeat(7, 5px);
  grid-auto-rows: 5px;
  gap: 2px;
  width: max-content;
  padding: 8px;
  border-radius: 3px;
  background: linear-gradient(178deg, #EFEADB, #DED7C4);
  box-shadow: inset 0 0 0 2px var(--jt-navy), inset 0 2px 0 rgba(255, 255, 255, 0.7);
}
.jt-emblem span {
  display: block;
  border-radius: 1px;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.4s linear, transform 0.4s cubic-bezier(0.2, 0.9, 0.25, 1);
}
[data-lit] .jt-emblem span { opacity: 1; transform: none; }
/* the mark resolves out of the grid rather than appearing all at once: a
   diagonal wipe, cheap to express as a delay per column of the 7x7 */
.jt-emblem span:nth-child(7n+1) { transition-delay: 0.02s; }
.jt-emblem span:nth-child(7n+2) { transition-delay: 0.05s; }
.jt-emblem span:nth-child(7n+3) { transition-delay: 0.08s; }
.jt-emblem span:nth-child(7n+4) { transition-delay: 0.11s; }
.jt-emblem span:nth-child(7n+5) { transition-delay: 0.14s; }
.jt-emblem span:nth-child(7n+6) { transition-delay: 0.17s; }
.jt-emblem span:nth-child(7n+7) { transition-delay: 0.20s; }

.jt-gauge-face {
  position: relative;
  width: clamp(46px, 5.2vw, 60px);
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 36%, #FBF7EC 0%, #E7E0CC 58%, #C9C1AC 100%);
  box-shadow:
    inset 0 0 0 2px #9E9787,
    inset 0 3px 7px rgba(0, 35, 73, 0.22),
    0 2px 0 rgba(255, 255, 255, 0.7);
  overflow: hidden;
}

/* the printed scale: ticks around the sweep, and a red band at full deflection */
.jt-gauge-arc {
  position: absolute;
  inset: 15%;
  border-radius: 50%;
  background:
    /* redline over the last third of the dial */
    conic-gradient(from 128deg, transparent 0 62deg, rgba(222, 50, 38, 0.5) 62deg 104deg, transparent 104deg),
    /* tick marks */
    repeating-conic-gradient(from 128deg, var(--jt-navy) 0 1.2deg, transparent 1.2deg 14.6deg);
  -webkit-mask: radial-gradient(circle, transparent 58%, #000 59%, #000 100%);
  mask: radial-gradient(circle, transparent 58%, #000 59%, #000 100%);
  opacity: 0.55;
}

.jt-gauge-needle {
  position: absolute;
  left: 50%;
  bottom: 50%;
  width: 2px;
  height: 34%;
  border-radius: 1px;
  background: var(--kb-red);
  box-shadow: 0 0 6px rgba(222, 50, 38, 0.7);
  transform-origin: 50% 100%;
  transform: translateX(-50%) rotate(-52deg);
  /* a hair of overshoot, the way a moving-coil movement settles */
  transition: transform 1s cubic-bezier(0.34, 1.42, 0.64, 1);
}
[data-lit] .jt-gauge-needle { transform: translateX(-50%) rotate(var(--deg)); }

/* Pointer inside the glass: the needle follows the hand, the way a moving-coil
   movement chases whatever it is fed. jt-panel.js writes the angle inline, so
   the transition here only has to smooth the gap between pointer samples.
   Leaving the dial drops the inline angle and the rule below takes the needle
   home on the same 1s settle it arrived on - the delays that stagger the three
   dials on reveal are zeroed, or the needle would sit still before returning. */
.jt-gauge[data-track] .jt-gauge-needle {
  transition: transform 0.07s linear;
  transition-delay: 0s;
  animation: none;
}
.jt-gauge[data-settle] .jt-gauge-needle { transition-delay: 0s; }

/* under the hand the movement runs a little hotter */
.jt-gauge[data-track] .jt-gauge-needle {
  box-shadow: 0 0 9px rgba(222, 50, 38, 0.95);
}

/* tapping the dial knocks the movement: it swings off the reading and settles
   back on it. The end state is the reading itself, so a click can never leave
   the needle disagreeing with the number on the plate. */
.jt-gauge[data-tick] .jt-gauge-needle {
  animation: jt-needle-kick 0.62s cubic-bezier(0.34, 1.42, 0.64, 1) 1;
}
@keyframes jt-needle-kick {
  0%   { transform: translateX(-50%) rotate(var(--deg)); }
  22%  { transform: translateX(-50%) rotate(calc(var(--deg) - 11deg)); }
  55%  { transform: translateX(-50%) rotate(calc(var(--deg) + 5deg)); }
  100% { transform: translateX(-50%) rotate(var(--deg)); }
}

/* the three dials answer one after another rather than in unison */
.jt-gauge:nth-child(2) .jt-gauge-needle { transition-delay: 0.11s; }
.jt-gauge:nth-child(3) .jt-gauge-needle { transition-delay: 0.22s; }

.jt-gauge-pin {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #F7F4EA, #8E8877);
  box-shadow: 0 1px 2px rgba(0, 35, 73, 0.5);
}

/* glass: a single soft highlight across the top-left of the crystal */
.jt-gauge-face::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background: linear-gradient(148deg, rgba(255, 255, 255, 0.5) 0 26%, transparent 52%);
}

/* engraved nameplate beside each dial */
.jt-gauge-plate {
  position: relative;
  display: grid;
  gap: 2px;
  padding: 5px 9px;
  border-radius: 2px;
  background: linear-gradient(180deg, #BDB6A6, #CCC5B5);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.28), inset 0 -1px 0 rgba(255, 255, 255, 0.5);
}
.jt-gauge-plate span {
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #6B655A;
}
.jt-gauge-plate b {
  font-family: var(--font-screen), var(--font-mono);
  font-size: 15px;
  line-height: 1;
  letter-spacing: 0.06em;
  color: var(--jt-navy);
}

/* Pressing the nameplate lights it: the lamp behind the engraving comes on,
   the digits roll over, and the legend reads the full scale for as long as the
   lamp is lit - the dial face carries no numbers, so 08 only means something
   once you can see it is 08 of 10. jt-panel.js swaps the legend text and puts
   the original back when the lamp goes out. */
/* The legend is drawn by the pseudo-element rather than swapped in the DOM:
   the engraved word is a template binding, and rewriting its text would be
   undone the next time the page re-renders the panel. attr(data-full) reads
   the scale the markup already carries, so nothing here can drift from it. */
.jt-gauge-plate[data-read] > span { visibility: hidden; }
.jt-gauge-plate[data-read]::before {
  content: "of " attr(data-full);
  position: absolute;      /* out of flow: the plate keeps its resting width */
  left: 9px;
  right: 9px;
  top: 5px;
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #6E4E14;
}

.jt-gauge-plate[data-read] {
  background: linear-gradient(180deg, #E9D6A6, #D8C08A);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.2),
    inset 0 -1px 0 rgba(255, 255, 255, 0.6),
    0 0 12px rgba(226, 176, 76, 0.55);
}
.jt-gauge-plate[data-read] span { color: #6E4E14; }
.jt-gauge-plate[data-read] b {
  color: #3A2A08;
  animation: jt-plate-roll 0.32s cubic-bezier(0.3, 0.9, 0.3, 1) 1;
}
/* the digit leaves upward and the next one arrives from below, a counter wheel */
@keyframes jt-plate-roll {
  0%   { transform: translateY(0); opacity: 1; }
  45%  { transform: translateY(-80%); opacity: 0; }
  55%  { transform: translateY(80%); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}

/* ══ 2. capabilities: a rolling monitor ════════════════════════════════ */
/* Eight capabilities with a line of copy each is the densest block on the
   page and the one that made five dossiers read as five walls of text. It now
   runs as a crawl on its own monitor, the way a newsroom runs a lower third.
   
   The loop is pure CSS on one transform, so it costs a compositor layer and no
   script. Two rules keep it from being a trap: it holds on hover, tap or
   keyboard focus, and under reduced motion it stops being a crawl at all and
   becomes an ordinary scrollable list. The copy is in the DOM either way, so
   find-in-page and screen readers get all eight regardless of where the
   animation happens to be. */

/* The monitor is one of two columns in the same flex row; beside it a terminal
   and an index card stack up. A fixed screen height left the two columns
   bottoming out at different points. The bezel now fills the row's height and
   the screen takes whatever is left under the head and foot, so the monitor
   ends level with the card next to it. min-height is the floor for the wrapped
   single-column case, where there is no sibling to match. */
.jt-caps { display: flex; }

.jt-caps-bezel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 2px solid var(--jt-navy);
  border-radius: 8px 8px 4px 4px;
  padding: 10px 10px 8px;
  background: linear-gradient(178deg, #DED7C4, #C3BBA6);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.7), 5px 5px 0 rgba(0, 35, 73, 0.22);
}

.jt-caps-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 2px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--jt-navy);
}
.jt-caps-head > span:first-child { display: flex; align-items: center; gap: 8px; }
.jt-caps-head i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--kb-red);
  box-shadow: 0 0 8px rgba(222, 50, 38, 0.85);
  animation: jtblink 1.2s steps(1, end) infinite;
}
.jt-caps-count { opacity: 0.6; }

.jt-caps-screen {
  position: relative;
  /* basis 0, not auto: the track holds two copies of the list, so an auto basis
     would size the screen to the crawl instead of to the column beside it */
  flex: 1 1 0;
  min-height: 260px;
  overflow: hidden;
  border-radius: 4px;
  background: #05070A;
  box-shadow: inset 0 0 0 2px #3A4250, inset 0 0 30px rgba(0, 0, 0, 0.95);
}
.jt-caps-screen:focus-visible { outline: 3px solid var(--jt-primary-screen); outline-offset: 2px; }

.jt-caps-track {
  will-change: transform;
  animation: jtcaps 34s linear infinite;
}
/* -50% is exactly one copy of the list, so the seam never shows */
@keyframes jtcaps {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
/* hold it: pointer, touch or keyboard */
.jt-caps-screen:hover .jt-caps-track,
.jt-caps-screen:focus-within .jt-caps-track,
.jt-caps-screen:active .jt-caps-track { animation-play-state: paused; }

.jt-caps-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid rgba(160, 180, 210, 0.1);
}
.jt-caps-num {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 9px;
  line-height: 1.7;
  letter-spacing: 0.12em;
  color: #5E6A7C;
}
.jt-caps-body { min-width: 0; }
.jt-caps-name {
  display: block;
  font-family: var(--font-screen), var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #7DE39A;
  text-shadow: 0 0 8px rgba(125, 227, 154, 0.45);
}
.jt-caps-note {
  display: block;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.6;
  color: #9FB0C4;
}

/* phosphor grain, scanlines, and a vignette so rows enter and leave softly
   instead of being chopped off at the bezel */
.jt-caps-grain,
.jt-caps-lines,
.jt-caps-vignette {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}
.jt-caps-grain {
  background-image: radial-gradient(rgba(120, 150, 190, 0.16) 0.8px, transparent 0.9px);
  background-size: 3px 3px;
}
.jt-caps-lines {
  opacity: 0.38;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.6) 0 1px, transparent 1px 3px);
}
.jt-caps-vignette {
  background:
    linear-gradient(180deg, #05070A 0, rgba(5, 7, 10, 0) 13%, rgba(5, 7, 10, 0) 87%, #05070A 100%);
  box-shadow: inset 0 0 26px rgba(0, 0, 0, 0.85);
}

.jt-caps-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 2px 0;
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #6B655A;
}
.jt-caps-led {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #7DE39A;
  box-shadow: 0 0 7px rgba(125, 227, 154, 0.9);
  animation: jtblink 1.9s steps(1) infinite;
}
/* there is no hover on a touch screen, so the plate must not tell a phone to
   do something it cannot. Touch-and-hold pauses it via :active. */
@media (pointer: coarse) {
  .jt-caps-foot > span:first-child { font-size: 0; }
  .jt-caps-foot > span:first-child::after {
    /* literal ·, not \00b7 - a hex escape swallows the space that follows it */
    content: "Rolling · touch to hold";
    font-size: 8.5px;
  }
}

/* Reduced motion: not a slower crawl - no crawl. The screen becomes a plain
   scrollable list and the duplicate copy is removed so it is not read twice. */
@media (prefers-reduced-motion: reduce) {
  .jt-caps-track { animation: none; }
  .jt-caps-screen { overflow-y: auto; }
  .jt-caps-row[aria-hidden="true"] { display: none; }
  .jt-caps-head i,
  .jt-caps-led { animation: none; }
}

/* ══ 3. "you need this if": a punched index card ═══════════════════════ */

.jt-card {
  position: relative;
  /* left gutter clears the punch column and the margin rule; the bottom one
     keeps the stamp off the last symptom */
  padding: 13px 14px 32px 34px !important;
  border-radius: 3px !important;
  background:
    /* the red margin rule a filing card is printed with */
    linear-gradient(90deg, transparent 0 25px, rgba(222, 50, 38, 0.3) 25px 26px, transparent 26px),
    linear-gradient(180deg, rgba(255, 255, 255, 0.7), transparent 24%),
    #EFEADB !important;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.5),
    3px 3px 0 rgba(0, 35, 73, 0.18);
}
/* Perforation runs at a fixed pitch down the filing edge, the way punched
   stock is made - spacing it as a fraction of the card's height tied it to how
   many lines of copy happened to be inside, so it lined up with nothing.
   Each hole is a dark well with a lit lower lip, which is what sells it as
   punched through rather than printed on. */
.jt-card::before {
  content: "";
  position: absolute;
  left: 9px;
  top: 10px;
  bottom: 10px;
  width: 11px;
  background-image: radial-gradient(
    circle at 50% 46%,
    rgba(0, 20, 45, 0.55) 0 3.3px,
    rgba(0, 35, 73, 0.28) 3.4px 4.0px,
    rgba(255, 255, 255, 0.9) 4.1px 4.9px,
    transparent 5px
  );
  background-size: 11px 24px;
  background-position: 0 3px;
  background-repeat: repeat-y;
}
/* the stamp, landed slightly off-square the way a hand stamp does */
.jt-card::after {
  content: "SYMPTOMS";
  position: absolute;
  right: 11px;
  bottom: 8px;
  padding: 3px 8px;
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: 0.2em;
  color: rgba(174, 31, 22, 0.85);
  border: 2px solid rgba(174, 31, 22, 0.6);
  border-radius: 2px;
  /* the second, inner rule a real rubber stamp carries */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.55), inset 0 0 0 2.5px rgba(174, 31, 22, 0.28);
  transform: rotate(-7deg);
  opacity: 0.92;
  pointer-events: none;
}

/* ══ 4. "what you get": rack cards ═════════════════════════════════════ */

.jt-rack-card {
  position: relative;
  /* the cut corner, top-right, the way a filing card is clipped */
  clip-path: polygon(0 0, calc(100% - 13px) 0, 100% 13px, 100% 100%, 0 100%);
  background: linear-gradient(178deg, #FFFDF7, #F2EDE0) !important;
  padding: 12px 13px 13px !important;
}
/* embossed label strip behind the number */
.jt-rack-card > div:first-child {
  display: inline-block;
  padding: 2px 7px !important;
  border-radius: 2px;
  background: var(--jt-navy);
  color: #F3EEDF !important;
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.4), 0 1px 0 rgba(255, 255, 255, 0.6);
}

/* ══ 5. "how it runs": punched paper tape ══════════════════════════════ */

.jt-tape {
  position: relative;
  padding: 13px 0 !important;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.5), transparent 22%, transparent 78%, rgba(0, 35, 73, 0.07)),
    repeating-linear-gradient(90deg, #E7E1D0 0 9px, #DED7C4 9px 10px) !important;
}
/* sprocket holes running the length of both edges */
.jt-tape::before,
.jt-tape::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 7px;
  pointer-events: none;
  background-image: radial-gradient(circle, #B6AF9E 0 2.6px, transparent 2.8px);
  background-size: 17px 7px;
  background-repeat: repeat-x;
}
.jt-tape::before { top: 3px; }
.jt-tape::after { bottom: 3px; }

/* each step rides in from the feed direction as the tape advances */
.jt-tape-step {
  padding: 6px 14px !important;
  opacity: 0;
  transform: translateX(-14px);
  transition: opacity 0.5s linear, transform 0.5s cubic-bezier(0.2, 0.9, 0.25, 1);
}
[data-lit] .jt-tape-step { opacity: 1; transform: none; }
.jt-tape > div:nth-child(2) { transition-delay: 0.09s; }
.jt-tape > div:nth-child(3) { transition-delay: 0.18s; }
.jt-tape > div:nth-child(4) { transition-delay: 0.27s; }
.jt-tape > div:nth-child(5) { transition-delay: 0.36s; }

/* ══ 6. stack chips: keycaps ═══════════════════════════════════════════ */
/* the same moulded cap the landing page's hero board is built from, so the
   two pages read as the same kit */

.jt-key {
  padding: 6px 10px 7px !important;
  border: 0 !important;
  border-radius: 3px !important;
  background: linear-gradient(180deg, #F5F0E2, #E2DBC8) !important;
  box-shadow:
    inset 0 -3px 0 #C9C1AC,
    inset 3px 0 0 rgba(255, 255, 255, 0.34),
    inset 0 2px 0 rgba(255, 255, 255, 0.62),
    inset 0 0 0 1px rgba(0, 0, 0, 0.14),
    0 3px 0 #C9C1AC,
    0 5px 0 rgba(0, 35, 73, 0.4);
  transition: transform 0.09s ease-out, box-shadow 0.09s ease-out;
}
.jt-key:hover {
  transform: translateY(2px);
  box-shadow:
    inset 0 -2px 0 #C9C1AC,
    inset 3px 0 0 rgba(255, 255, 255, 0.34),
    inset 0 2px 0 rgba(255, 255, 255, 0.62),
    inset 0 0 0 1px rgba(0, 0, 0, 0.14),
    0 1px 0 #C9C1AC,
    0 3px 0 rgba(0, 35, 73, 0.4);
}

/* ══ narrow screens ════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  /* Dial beside its plate is ~114px wide, so three of them plus the emblem
     cannot hold one line at 390. Standing each plate under its own dial gets
     the gauge down to ~52px and the whole panel back onto a single row. */
  .jt-gauges {
    gap: 12px;
    padding: 12px 4vw;
    align-items: flex-start;
  }
  .jt-gauge {
    flex-direction: column;
    align-items: center;
    gap: 5px;
  }
  .jt-gauge-face { width: 46px; }
  .jt-gauge-plate {
    justify-items: center;
    padding: 4px 7px;
  }
  .jt-gauge-plate b { font-size: 13px; }
  /* the phone plate is narrower than "OF 10" set at desktop tracking */
  .jt-gauge-plate[data-read]::before {
    left: 3px;
    right: 3px;
    top: 4px;
    text-align: center;
    font-size: 7.5px;
    letter-spacing: 0.1em;
  }
  .jt-tape-step { padding: 6px 12px !important; }
  /* the louvres need width to read as louvres; a phone panel has none spare */
  .jt-vent { display: none; }
}

/* ══ reduced motion ════════════════════════════════════════════════════ */
/* jt-reveal.js already skips the observer and lights everything up front when
   this is set; belt and braces, in case an element is lit some other way. */

@media (prefers-reduced-motion: reduce) {
  .jt-gauge-needle,
  .jt-tape-step,
  .jt-port::before,
  .jt-key { transition: none !important; }
  .jt-tape-step { opacity: 1; transform: none; }
  /* the press still registers - the plate still lights, the legend still reads
     the full scale - but nothing swings, rolls or chases the pointer */
  .jt-vent[data-tick],
  .jt-gauge[data-tick] .jt-gauge-needle,
  .jt-gauge-plate[data-read] b { animation: none !important; }
}
