/* ═══════════════════════════════════════════════════════════════════════
   TransferSwitch.store — About, cinematic
   ───────────────────────────────────────────────────────────────────────
   Grammar borrowed from terawulf.com (band rhythm, narrow column, type
   discipline). Vocabulary is entirely TransferSwitch's own: the navy and
   amber are sampled from the logo pixels, not from the reference site.
   TeraWulf has no accent colour at all — the amber is what makes this his.

   ⚠ SCOPING — READ BEFORE EDITING
   This page renders inside the REAL theme header and footer, so Royal Kit's
   and Elementor's stylesheets are both loaded alongside this one. Every rule
   below is therefore scoped under `.tsc-page` (body) or `.tsc-main` (our
   content wrapper). Do NOT add bare element selectors like `h2 {}` or generic
   class selectors like `.btn {}` — they would restyle the theme's header and
   footer, and collide with Elementor's utility classes.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Fonts ──────────────────────────────────────────────────────────────
   Self-hosted, so there is no third-party request and no GDPR question.
   font-display:swap means text is readable immediately and never invisible. */

@font-face {
  font-family: "Satoshi";
  src: url("../fonts/Satoshi-Variable.woff2") format("woff2-variations");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/SpaceGrotesk-Variable.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* sampled from the logo itself */
  --tsc-navy: #192A4A;
  --tsc-navy-deep: #101C33;
  --tsc-amber: #F6A720;
  --tsc-slate: #33456A;          /* derived from the navy, not borrowed */
  --tsc-pale: #EDF0F5;
  --tsc-white: #FFFFFF;

  --tsc-ink: #192A4A;
  --tsc-ink-mut: rgba(25, 42, 74, .58);
  --tsc-on-dark: rgba(255, 255, 255, .62);
  --tsc-on-dark-str: rgba(255, 255, 255, .88);
  --tsc-hair: rgba(25, 42, 74, .16);
  --tsc-hair-dark: rgba(255, 255, 255, .14);

  --tsc-col: 975px;
  --tsc-pad: clamp(54px, 7.4vw, 76px);
  --tsc-gut: clamp(20px, 5vw, 40px);

  --tsc-sans: "Satoshi", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --tsc-mono: "Space Grotesk", ui-monospace, "Cascadia Mono", Consolas, "SF Mono", monospace;

  --tsc-ease: cubic-bezier(.22, .7, .3, 1);

  /* Outer silhouette of the mark, traced from the PNG at 97.6% fidelity.
     Inner holes are omitted deliberately: they never close when scaled up,
     which would leave gaps in the wipe. */
  --tsc-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 270 270'%3E%3Cpath fill='black' d='M124 0L206 0L195 21L197 23L268 50L248 203L154 269L114 269L100 258L92 269L76 269L83 247L20 202L0 50L119 5L124 1Z'/%3E%3C/svg%3E");
}

/* ── Base — scoped to our content only ────────────────────────────────── */

.tsc-page { overflow-x: hidden; }

.tsc-main, .tsc-main * , .tsc-main *::before, .tsc-main *::after { box-sizing: border-box; }

.tsc-main {
  font-family: var(--tsc-sans);
  color: var(--tsc-ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.tsc-main img, .tsc-main svg, .tsc-main canvas { max-width: 100%; display: block; }

.tsc-main :is(h1, h2, h3) {
  margin: 0;
  font-weight: 600;
  text-wrap: balance;
  letter-spacing: -.04em;
  font-family: var(--tsc-sans);
}
.tsc-main h1 { font-size: clamp(34px, 4.8vw, 55px); line-height: 1.06; }
.tsc-main h2 { font-size: clamp(27px, 3.6vw, 43px); line-height: 1.1; }
.tsc-main h3 { font-size: 18px; line-height: 1.35; letter-spacing: -.02em; }

.tsc-main p {
  margin: 20px 0 0;
  line-height: 1.65;
  color: var(--tsc-ink-mut);
  max-width: 58ch;
  font-size: 16.5px;
}
.tsc-main p.lede { font-size: clamp(16.5px, 1.5vw, 19px); color: var(--tsc-ink); }

.tsc-main a { color: inherit; }
.tsc-main ::selection { background: var(--tsc-amber); color: var(--tsc-navy); }

/* ── Reading progress ─────────────────────────────────────────────────── */

.tsc-progress {
  position: fixed; left: 0; top: 0; height: 3px; width: 100%; z-index: 9999;
  background: var(--tsc-amber);
  transform: scaleX(0); transform-origin: 0 50%;
  pointer-events: none;
}

/* ── Bands ────────────────────────────────────────────────────────────── */

.tsc-main .band { padding: var(--tsc-pad) var(--tsc-gut); position: relative; }
.tsc-main .band > .in { max-width: var(--tsc-col); margin: 0 auto; }

.tsc-main .band--navy  { background: var(--tsc-navy);  color: var(--tsc-on-dark); }
.tsc-main .band--slate { background: var(--tsc-slate); color: var(--tsc-on-dark); }
.tsc-main .band--pale  { background: var(--tsc-pale); }
.tsc-main .band--white { background: var(--tsc-white); }

.tsc-main .band--navy :is(h1, h2, h3),
.tsc-main .band--slate :is(h1, h2, h3) { color: #fff; }
.tsc-main .band--navy p, .tsc-main .band--slate p { color: var(--tsc-on-dark); }
.tsc-main .band--navy p.lede, .tsc-main .band--slate p.lede { color: var(--tsc-on-dark-str); }

.tsc-main .eyebrow {
  font-family: var(--tsc-mono); font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--tsc-slate); margin: 0 0 18px;
}
.tsc-main .band--navy .eyebrow,
.tsc-main .band--slate .eyebrow,
.tsc-main .eyebrow--amber { color: var(--tsc-amber); }

/* ── Reveal ───────────────────────────────────────────────────────────── */

.tsc-main .rv {
  opacity: 0; transform: translateY(20px);
  transition: opacity .75s var(--tsc-ease), transform .75s var(--tsc-ease);
}
.tsc-main .rv.in { opacity: 1; transform: none; }

/* ── Buttons ──────────────────────────────────────────────────────────── */

.tsc-main .btn {
  display: inline-block; font-family: var(--tsc-mono); font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; padding: 15px 26px;
  border: 1px solid currentColor; background: transparent; color: inherit;
  text-decoration: none; cursor: pointer; border-radius: 0;
  transition: background .18s, color .18s, border-color .18s;
}
.tsc-main .btn:hover { background: var(--tsc-pale); border-color: var(--tsc-pale); color: var(--tsc-navy); }
.tsc-main .btn--onlight { color: var(--tsc-navy); }
.tsc-main .btn--onlight:hover { background: var(--tsc-navy); border-color: var(--tsc-navy); color: #fff; }
.tsc-main .btn--amber { background: var(--tsc-amber); border-color: var(--tsc-amber); color: var(--tsc-navy); }
.tsc-main .btn--amber:hover { filter: brightness(1.08); background: var(--tsc-amber); border-color: var(--tsc-amber); color: var(--tsc-navy); }
.tsc-main .btn:focus-visible { outline: 2px solid var(--tsc-amber); outline-offset: 3px; }
.tsc-main .btn-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 36px; }

/* ── Hero ─────────────────────────────────────────────────────────────── */

.tsc-main .hero {
  min-height: min(84svh, 760px);
  display: flex; flex-direction: column; justify-content: space-between;
  overflow: hidden; isolation: isolate;
}
.tsc-main .hero-media { position: absolute; inset: 0; z-index: -2; background: var(--tsc-navy); overflow: hidden; }
.tsc-main .hero-canvas { position: absolute; inset: 0; opacity: 0; transition: opacity 1.1s var(--tsc-ease); }
.tsc-main .hero-canvas.ready { opacity: 1; }
.tsc-main .hero-canvas canvas { width: 100%; height: 100%; display: block; }
.tsc-main .hero-poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .5; transition: opacity .8s var(--tsc-ease);
}
.tsc-main .hero-canvas.ready ~ .hero-poster { opacity: 0; }

/* ── Per-page hero identity ───────────────────────────────────────────────
   All three pages shipped with the SAME opening: band--navy + the globe
   canvas + map-poster.svg, identical markup. Read back to back they looked
   like one page, and that is exactly what happened the first time anyone saw
   them together.

   The fix is NOT three different designs. Shared type, band rhythm and card
   language are the brand — every page below the fold stays identical on
   purpose. Only the first screen changes, so the pages are siblings instead
   of duplicates:

     guide      crisp blueprint   the object you are about to take apart
     sourcing   the live globe    geography IS that page's argument
     legacy     drained plate     equipment that is no longer built

   ⚠ The animated globe now belongs to the SOURCING page alone. Adding
   data-tsc-map to any other template collapses this straight back. */

/* Both blueprint heroes: contain, never cover. This is a technical drawing,
   not a photograph — cover crops the enclosure's top and bottom off and the
   thing stops reading as a piece of equipment.

   ⚠ Stays FULL-BLEED with object-position:right, not a right-hand column.
   Tried inset:0 0 0 auto + width:56% and it looks the same at 1905px but
   breaks below ~1500: the copy column is a fixed 975px centred, so the space
   to its right shrinks as the viewport does and a percentage-width panel
   walks straight under the words. Full-bleed + contain + right lets the
   drawing find its own edge at any width, which is exactly how the globe
   behaved here before. The copy overlapping the art is not a bug — the
   directional scrim is what buys legibility, same as it always did. */
.tsc-main .hero--blueprint .hero-poster {
  object-fit: contain; object-position: right center;
  opacity: .42;
}

/* ── legacy: the retirement list ──────────────────────────────────────────
   NOT a picture, on purpose. Greying out the guide's drawing was tried and
   rejected — it read as the guide's hero with the lights off, because it was
   the same composition in a different colour. A wall of struck-through part
   numbers differs in KIND, so the two pages can never be mistaken for each
   other, and it happens to be exactly what the page is about. */
.tsc-main .hero--legacy .tsc-registry {
  position: absolute; inset: 0; margin: 0;
  /* Upper-right, not centred. The hero is a top/bottom flex box: the eyebrow
     sits top-LEFT and the whole h1 + lede + buttons block sits at the BOTTOM,
     which leaves the top right corner empty. Centring the list put four part
     numbers straight across the headline — tolerable for the guide's drawing
     at .42, but text over text reads as a rendering fault rather than a
     layer. flex-start moves it into the gap instead of fighting for it. */
  /* DEFAULT = texture. Full width, behind the copy, faint enough that
     overlapping the headline reads as a layer rather than a collision. The
     tidier "register in the right margin" only works when there IS a right
     margin — see the min-width rule below, and read the note there before
     making this the default again. */
  padding: 10vh var(--tsc-gut);
  display: flex; flex-wrap: wrap;
  align-content: center; justify-content: flex-end;
  gap: .42em 1.05em;
  list-style: none;
  font-family: var(--tsc-mono);
  font-size: clamp(22px, 2.6vw, 44px);
  font-weight: 600; line-height: 1; letter-spacing: -.02em;
  /* Faint enough to be texture behind the headline, not a second headline
     competing with it. The scrim shields the copy side; this is the clear
     side, so it can carry a little more than a background image would. */
  color: rgba(255, 255, 255, .13);
  user-select: none; pointer-events: none;
}
.tsc-main .hero--legacy .tsc-registry li { position: relative; white-space: nowrap; }
/* Drawn rather than text-decoration: at 54px a real strike-through renders as
   a heavy bar straight through the digits and the numbers stop being
   readable. A 2px rule at low alpha reads as "retired" and still lets you
   read the part number, which is the entire point of showing it. */
.tsc-main .hero--legacy .tsc-registry li::after {
  content: ""; position: absolute; left: -.07em; right: -.07em; top: 53%;
  height: 2px; background: rgba(246, 167, 32, .30);
}

/* Promote to a proper register in the right margin — but ONLY where the
   margin is wide enough to hold one.
   ⚠ 1600px is measured, not taste. .in is a fixed 975px centred, so the clear
   space right of the copy is (viewport - 975) / 2: about 465px at 1905, but
   only 145px at 1280 — where this laid out as 13 rows of ONE designation in a
   106px strip, which looked far worse than the overlap it was avoiding. Below
   this breakpoint the texture treatment above is the better of the two. */
@media (min-width: 1600px) {
  .tsc-main .hero--legacy .tsc-registry {
    padding: 12vh var(--tsc-gut) 8vh calc(50% + var(--tsc-col) / 2);
    align-content: flex-start;
    font-size: 38px;
    color: rgba(255, 255, 255, .16);
  }
}

@media (max-width: 800px) {
  /* At phone width there is no "right half" to hold it in — the copy runs
     the full column, so a 56% panel would sit under the words. Full width
     and much fainter instead: texture behind the headline, not an image
     competing with it. */
  .tsc-main .hero--blueprint .hero-poster {
    object-position: center 38%; opacity: .22;
  }
  /* No "right half" to hold anything in at phone width — the copy runs the
     full column. The list moves behind the words and drops to texture. */
  .tsc-main .hero--legacy .tsc-registry {
    padding: 0 var(--tsc-gut);
    justify-content: flex-start; align-content: center;
    font-size: clamp(20px, 7vw, 34px); gap: .38em .8em;
    color: rgba(255, 255, 255, .085);
  }
  .tsc-main .hero--legacy .tsc-registry li::after { background: rgba(246, 167, 32, .20); }
}
/* The scrim used to veil the WHOLE canvas — up to .9 navy at the edges plus a
   .88 band across the lower third — which is most of the reason the sourcing
   animation read as barely-there. But it is not decoration: it is what keeps
   the headline legible, so it cannot simply be turned down.

   Reshaped instead of weakened. The copy lives in the left ~55% of the hero,
   so the shield is now DIRECTIONAL: heavy behind the words, clearing to
   nothing on the right where the arcs actually get to be seen. Net effect is
   more protection where the text is and far less everywhere else. */
.tsc-main .hero-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg,
      rgba(16,28,51,.86) 0%, rgba(16,28,51,.70) 36%,
      rgba(25,42,74,.16) 64%, rgba(25,42,74,0) 100%),
    radial-gradient(120% 90% at 50% 40%,
      rgba(25,42,74,0) 0%, rgba(25,42,74,.18) 70%, rgba(25,42,74,.48) 100%),
    linear-gradient(180deg,
      rgba(16,28,51,.34) 0%, rgba(25,42,74,.06) 34%,
      rgba(25,42,74,.60) 84%, var(--tsc-navy) 100%);
}
/* On a phone the copy spans the full width, so a left-weighted shield protects
   nothing. Fall back to a bottom-up one and let the top of the frame play. */
@media (max-width: 900px) {
  .tsc-main .hero-scrim {
    background:
      linear-gradient(180deg,
        rgba(16,28,51,.28) 0%, rgba(25,42,74,.06) 24%,
        rgba(16,28,51,.74) 58%, var(--tsc-navy) 100%);
  }
}
.tsc-main .hero > .in { position: relative; z-index: 2; width: 100%; max-width: var(--tsc-col); margin: 0 auto; }
.tsc-main .hero h1 { max-width: 17ch; margin-top: 22px; }
.tsc-main .hero .lede { margin-top: 24px; max-width: 46ch; }

.tsc-main .scroll-cue {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  font-family: var(--tsc-mono); font-size: 9.5px; letter-spacing: .24em;
  text-transform: uppercase; color: rgba(255,255,255,.45); z-index: 2;
}
.tsc-main .scroll-cue::after {
  content: ""; display: block; width: 1px; height: 26px; margin: 9px auto 0;
  background: linear-gradient(180deg, var(--tsc-amber), transparent);
  animation: tsc-cue 2.1s var(--tsc-ease) infinite;
}
@keyframes tsc-cue { 0%,100% { opacity: .25; transform: scaleY(.5); } 50% { opacity: 1; transform: scaleY(1); } }

/* ── Lead-time chart ──────────────────────────────────────────────────── */

.tsc-main .chart { margin-top: var(--tsc-pad); border: 1px solid var(--tsc-hair); background: var(--tsc-white); }
.tsc-main .chart-head, .tsc-main .chart-foot {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  padding: 13px 18px; font-family: var(--tsc-mono); font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--tsc-ink-mut);
}
.tsc-main .chart-head { border-bottom: 1px solid var(--tsc-hair); }
.tsc-main .chart-foot { border-top: 1px solid var(--tsc-hair); }
.tsc-main .chart-foot b { color: var(--tsc-navy); font-weight: 600; }
.tsc-main .rows { padding: 22px 18px; display: flex; flex-direction: column; gap: 18px; }
.tsc-main .qlabel {
  display: flex; justify-content: space-between; gap: 12px;
  font-family: var(--tsc-mono); font-size: 11px; letter-spacing: .1em;
  color: var(--tsc-ink-mut); margin-bottom: 7px;
}
.tsc-main .qlabel b { color: var(--tsc-navy); font-weight: 400; font-variant-numeric: tabular-nums; }
.tsc-main .qbar { height: 26px; background: var(--tsc-pale); position: relative; overflow: hidden; }
.tsc-main .qfill { position: absolute; inset: 0 100% 0 0; transition: right 1.15s var(--tsc-ease); }
.tsc-main .qfill.them { background: repeating-linear-gradient(135deg, var(--tsc-slate) 0 6px, rgba(51,69,106,.5) 6px 12px); }
.tsc-main .qfill.us { background: var(--tsc-amber); min-width: 7px; }
/* --w is set inline per bar in the template. The fallback keeps the bar in its
   unfilled state rather than collapsing the rule if it is ever absent. */
.tsc-main .chart.in .qfill { right: var(--w, 100%); }
.tsc-main .chart-note { margin-top: 26px; }

/* ── The logo wipe ────────────────────────────────────────────────────── */

.tsc-main .wipe { position: relative; height: 240vh; background: var(--tsc-white); }
.tsc-main .wipe-stick { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.tsc-main .wipe-bg {
  position: absolute; inset: 0; background: var(--tsc-navy);
  -webkit-mask-image: var(--tsc-mark); mask-image: var(--tsc-mark);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: var(--m, 0px); mask-size: var(--m, 0px);
}
.tsc-main .wipe-in {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; padding: 0 var(--tsc-gut); opacity: 0;
  transition: opacity .45s ease;
}
.tsc-main .wipe-in.show { opacity: 1; }
.tsc-main .wipe-in .box { max-width: var(--tsc-col); width: 100%; }
.tsc-main .wipe .num {
  font-family: var(--tsc-mono); font-weight: 400; font-size: clamp(84px, 17vw, 190px);
  line-height: .84; letter-spacing: -.05em; color: var(--tsc-amber);
  font-variant-numeric: tabular-nums;
}
.tsc-main .wipe .num small {
  display: block; font-size: .13em; letter-spacing: .22em; text-transform: uppercase;
  color: var(--tsc-on-dark); margin-top: 22px;
}
.tsc-main .wipe .rule {
  border-left: 2px solid var(--tsc-amber); padding: 14px 0 14px 20px;
  margin-top: 38px; max-width: 54ch;
}
.tsc-main .wipe .rule p { margin: 0; color: var(--tsc-on-dark-str); font-size: 15.5px; }
.tsc-main .wipe-hint {
  position: absolute; left: 50%; bottom: 28px; transform: translateX(-50%);
  font-family: var(--tsc-mono); font-size: 10px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--tsc-ink-mut); transition: opacity .4s;
}

/* ── Channels grid ────────────────────────────────────────────────────── */

.tsc-main .grid3 {
  display: grid; gap: 1px; background: var(--tsc-hair);
  border: 1px solid var(--tsc-hair); margin-top: var(--tsc-pad);
}
@media (min-width: 680px) { .tsc-main .grid3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 940px) { .tsc-main .grid3 { grid-template-columns: repeat(3, 1fr); } }
.tsc-main .cell {
  background: var(--tsc-white); padding: 26px 24px; display: flex;
  flex-direction: column; gap: 9px; transition: background .3s;
}
.tsc-main .cell:hover { background: var(--tsc-pale); }
.tsc-main .cell .n { font-family: var(--tsc-mono); font-size: 10px; letter-spacing: .18em; color: var(--tsc-amber); }
.tsc-main .cell p { margin: 0; font-size: 14.5px; }

/* ── Anatomy stage (3D ATS) ───────────────────────────────────────────── */

.tsc-main .anatomy { padding-bottom: 0; }
.tsc-main .stage {
  max-width: var(--tsc-col); margin: var(--tsc-pad) auto 0; position: relative;
  display: grid; gap: 1px; background: var(--tsc-hair-dark);
  border-top: 1px solid var(--tsc-hair-dark);
}
@media (min-width: 900px) { .tsc-main .stage { grid-template-columns: 1fr 260px; } }

/* Canvas and fallback share ONE grid cell and cross-fade.
   They used to be separate rows with `display: none` on the canvas until
   ready — but a display:none element has no box, so the first measurement
   came back 0x0 and the renderer sized itself wrong. Keeping both laid out
   in the same cell means the canvas always has a real, measurable size. */
.tsc-main .stage-canvas, .tsc-main .stage-fallback {
  grid-area: 1 / 1; background: var(--tsc-navy-deep);
  min-height: clamp(340px, 52vh, 560px);
  display: flex; align-items: center; justify-content: center;
}
.tsc-main .stage-canvas {
  position: relative; background: transparent;
  opacity: 0; pointer-events: none;
  transition: opacity .7s var(--tsc-ease);
}
.tsc-main .stage-canvas.ready { opacity: 1; pointer-events: auto; }
/* Three.js sets the canvas style in CSS pixels itself — do not force a
   percentage size here or the two fight and it overflows. */
.tsc-main .stage-canvas canvas { display: block; touch-action: pan-y; }

.tsc-main .stage-fallback { transition: opacity .7s var(--tsc-ease); }
.tsc-main .stage-canvas.ready ~ .stage-fallback { opacity: 0; pointer-events: none; }
.tsc-main .stage-fallback img { opacity: .82; padding: 22px; height: auto; }

.tsc-main .parts {
  grid-column: 1; list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--tsc-hair-dark);
}
@media (min-width: 900px) {
  .tsc-main .parts { grid-column: 2; grid-row: 1; grid-template-columns: 1fr; align-content: start; }
}
.tsc-main .parts li { list-style: none; margin: 0; }
.tsc-main .parts button {
  width: 100%; text-align: left; background: var(--tsc-navy); border: 0; border-radius: 0;
  color: var(--tsc-on-dark); font-family: var(--tsc-mono); font-size: 11px;
  letter-spacing: .1em; padding: 15px 16px; cursor: pointer;
  display: flex; gap: 10px; align-items: baseline; transition: background .2s, color .2s;
}
.tsc-main .parts button span { color: var(--tsc-amber); font-size: 10px; }
.tsc-main .parts button:hover { background: var(--tsc-slate); color: #fff; }
.tsc-main .parts button[aria-pressed="true"] { background: var(--tsc-amber); color: var(--tsc-navy); }
.tsc-main .parts button[aria-pressed="true"] span { color: var(--tsc-navy); }
.tsc-main .parts button:focus-visible { outline: 2px solid var(--tsc-amber); outline-offset: -2px; }

/* ── View control ─────────────────────────────────────────────────────────
   Three states: Closed, Cutaway (door open, gear in place and still wired),
   Exploded. A segmented control rather than a toggle, because the states are
   not opposites and a cycling button would hide two of them behind a guess.
   It only exists once the 3D canvas is live — with no canvas there is nothing
   to switch, and a dead control is worse than none. */
.tsc-main .viewmodes { display: none; }
.tsc-main .stage-canvas.ready ~ .viewmodes {
  grid-column: 1; display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1px; background: var(--tsc-hair-dark);
  border-top: 1px solid var(--tsc-hair-dark);
}
/* On desktop it takes the same cell as the part list and sits on the floor of
   it — the list is `align-content: start`, so that space is empty anyway. */
@media (min-width: 900px) {
  .tsc-main .stage-canvas.ready ~ .viewmodes { grid-column: 2; grid-row: 1; align-self: end; }
}
.tsc-main .viewmodes button {
  background: var(--tsc-navy); border: 0; border-radius: 0;
  color: var(--tsc-on-dark); font-family: var(--tsc-mono); font-size: 10px;
  letter-spacing: .08em; padding: 14px 6px; cursor: pointer; text-align: center;
  transition: background .2s, color .2s;
}
.tsc-main .viewmodes button:hover { background: var(--tsc-slate); color: #fff; }
.tsc-main .viewmodes button[aria-pressed="true"] { background: var(--tsc-amber); color: var(--tsc-navy); }
.tsc-main .viewmodes button:focus-visible { outline: 2px solid var(--tsc-amber); outline-offset: -2px; }

.tsc-main .part-copy {
  grid-column: 1 / -1; background: var(--tsc-navy);
  padding: 24px var(--tsc-gut) calc(var(--tsc-pad) - 10px);
}
.tsc-main .part-copy h3 { color: #fff; }
.tsc-main .part-copy p { color: var(--tsc-on-dark); margin-top: 10px; max-width: 62ch; }

/* Honesty line. The model is a schematic, and says so. */
.tsc-main .stage-note {
  grid-column: 1 / -1; background: var(--tsc-navy); margin: 0;
  padding: 0 var(--tsc-gut) var(--tsc-pad);
  font-family: var(--tsc-mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: rgba(255, 255, 255, .34); max-width: none;
}

/* ── Spec sheet ───────────────────────────────────────────────────────── */

.tsc-main .sheet { margin-top: var(--tsc-pad); border: 1px solid var(--tsc-hair); background: var(--tsc-white); }
.tsc-main .sheet-h {
  padding: 13px 18px; border-bottom: 1px solid var(--tsc-hair); display: flex;
  justify-content: space-between; flex-wrap: wrap; gap: 10px;
  font-family: var(--tsc-mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--tsc-ink-mut);
}
.tsc-main .srows { display: grid; gap: 1px; background: var(--tsc-hair); }
@media (min-width: 800px) { .tsc-main .srows { grid-template-columns: 1fr 1fr; } }
.tsc-main .srow {
  background: var(--tsc-white); padding: 16px 18px; display: flex;
  justify-content: space-between; gap: 16px; align-items: baseline;
  font-family: var(--tsc-mono); font-size: 12.5px;
}
.tsc-main .srow span:first-child {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--tsc-ink-mut);
}
.tsc-main .srow span:last-child { text-align: right; color: var(--tsc-navy); }

/* Data-first rows. The default .srow renders column one as a LABEL -- 10px,
   letter-spaced, uppercase -- which is right for "AMPERAGE / 30 – 4000 A" and
   wrong wherever column one is itself the DATA. On the legacy tables column
   one is a catalogue number being matched against a dirty nameplate, and
   letter-spaced caps is the hardest possible treatment to scan a part number
   in.
   ⚠ Opt IN per table rather than changing .srow: the nameplate sheet on that
   same page, and the Scope sheet on the sourcing page, both still want the
   label treatment. Scoped one level deeper than the base rule so it wins on
   specificity rather than on source order. */
.tsc-main .srows--data .srow span:first-child {
  font-size: 13px; letter-spacing: .01em; text-transform: none;
  color: var(--tsc-navy); font-weight: 600;
}

/* ── CTA + form ───────────────────────────────────────────────────────── */

.tsc-main .form-wrap { margin-top: var(--tsc-pad); border: 1px solid var(--tsc-hair); padding: clamp(22px, 4vw, 38px); }
.tsc-main .form-fallback { margin-top: 0; margin-bottom: 22px; }

/* Restyle WPForms so it reads as part of the page, not a bolted-on plugin. */
.tsc-main .wpforms-container { margin: 0; max-width: none; }
.tsc-main .wpforms-form .wpforms-field { padding: 0 0 18px; }
.tsc-main .wpforms-form .wpforms-field-label {
  font-family: var(--tsc-mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--tsc-ink-mut); font-weight: 400; margin-bottom: 8px;
}
.tsc-main .wpforms-form input[type="text"],
.tsc-main .wpforms-form input[type="email"],
.tsc-main .wpforms-form input[type="tel"],
.tsc-main .wpforms-form input[type="number"],
.tsc-main .wpforms-form select,
.tsc-main .wpforms-form textarea {
  width: 100%; border: 1px solid var(--tsc-hair); border-radius: 0; background: var(--tsc-white);
  padding: 13px 14px; font-family: var(--tsc-sans); font-size: 15.5px; color: var(--tsc-ink);
  transition: border-color .18s, box-shadow .18s;
}
.tsc-main .wpforms-form :is(input, select, textarea):focus {
  outline: 0; border-color: var(--tsc-navy); box-shadow: 0 0 0 3px rgba(246, 167, 32, .28);
}
.tsc-main .wpforms-form textarea { min-height: 130px; resize: vertical; }

/* Dropdowns, specifically.
   WPForms sets a fixed `height` on <select>. Stacked on the 13px padding above,
   the content box ends up shorter than a 15.5px line needs, so the chosen option
   renders visibly clipped -- Rick caught "Data Center" and "Within 30 Days" cut
   off on the Zenith page, 3 Aug 2026. Text inputs were never affected because
   they size to their content.
   ⚠ `appearance: none` is what lets padding govern the height, and it also
   removes the OS dropdown arrow -- hence the chevron below. Do not drop one
   without the other or the field reads as a text box. */
.tsc-main .wpforms-form select {
  height: auto; min-height: 0; line-height: 1.4;
  appearance: none; -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23192A4A' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 11px 8px;
}
.tsc-main .wpforms-form .wpforms-required-label { color: var(--tsc-amber); }
.tsc-main .wpforms-form button[type="submit"] {
  font-family: var(--tsc-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  background: var(--tsc-amber); border: 1px solid var(--tsc-amber); border-radius: 0;
  color: var(--tsc-navy); padding: 15px 28px; cursor: pointer; transition: filter .18s;
}
.tsc-main .wpforms-form button[type="submit"]:hover { filter: brightness(1.08); background: var(--tsc-amber); }
.tsc-main .wpforms-form .wpforms-error { color: #B3261E; font-family: var(--tsc-mono); font-size: 11px; }

/* ── Reduced motion ───────────────────────────────────────────────────────
   Not a nicety. Vestibular disorders are real and a pinned scroll-wipe is
   exactly the kind of motion that triggers them. Everything still reads. */

@media (prefers-reduced-motion: reduce) {
  .tsc-main *, .tsc-main *::before, .tsc-main *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .tsc-main .rv { opacity: 1; transform: none; }
  .tsc-main .qfill { right: var(--w, 100%) !important; }
  .tsc-main .wipe { height: auto; }
  .tsc-main .wipe-stick { position: static; height: auto; min-height: 70svh; background: var(--tsc-navy); }
  .tsc-main .wipe-bg { -webkit-mask-image: none; mask-image: none; }
  .tsc-main .wipe-in { position: static; opacity: 1; padding: var(--tsc-pad) var(--tsc-gut); }
  .tsc-main .wipe-hint, .tsc-main .scroll-cue { display: none; }
  .tsc-main .hero-canvas { display: none; }
  .tsc-main .hero-poster { opacity: .5 !important; }
}

/* ══ Guide + landing page components ═════════════════════════════════════
   Added 2026-07-31 for the SEO build (the ATS guide and the sourcing landing
   page). Everything stays scoped under .tsc-main like the rest of this file.
   ────────────────────────────────────────────────────────────────────── */

/* The answer block is the first thing a reader meets after the H1, so it is
   deliberately plain: a rule, a paragraph, no motion. The rest of the page
   can perform; this has to be readable in the half-second before the reader
   decides whether the page is worth their time. */
.tsc-main .answer {
  max-width: 62ch; margin-top: 30px; padding-left: 22px;
  border-left: 2px solid var(--tsc-amber);
}
.tsc-main .answer p { margin: 0; }
.tsc-main .answer strong { color: inherit; font-weight: 600; }

/* FAQ. <details> rather than a JS accordion: it is open-able before any script
   runs, Chrome's find-in-page still reaches text inside a closed one, and it
   degrades to plain readable text if the CSS never lands. */
.tsc-main .faq { margin-top: var(--tsc-pad); border-top: 1px solid var(--tsc-hair); }
.tsc-main .faq details { border-bottom: 1px solid var(--tsc-hair); }
.tsc-main .faq summary {
  display: flex; justify-content: space-between; align-items: baseline; gap: 20px;
  padding: 22px 0; cursor: pointer; list-style: none;
  font-family: var(--tsc-sans); font-size: clamp(17px, 1.5vw, 20px);
  font-weight: 500; color: var(--tsc-navy);
}
.tsc-main .faq summary::-webkit-details-marker { display: none; }
.tsc-main .faq summary::after {
  content: "+"; flex: none; font-family: var(--tsc-mono); font-size: 20px;
  color: var(--tsc-amber); transition: transform .25s var(--tsc-ease);
}
.tsc-main .faq details[open] summary::after { transform: rotate(45deg); }
.tsc-main .faq summary:hover { color: var(--tsc-amber); }
.tsc-main .faq summary:focus-visible { outline: 2px solid var(--tsc-amber); outline-offset: 3px; }
.tsc-main .faq .a { padding: 0 0 24px; max-width: 68ch; }
.tsc-main .faq .a p { margin: 0 0 12px; }
.tsc-main .faq .a p:last-child { margin-bottom: 0; }

/* Three-column comparison. .srow is flex (label | value), so this switches to
   grid rather than fighting justify-content, and .srows--stack opts out of the
   two-column spec-sheet layout on source order at equal specificity. */
.tsc-main .srows--stack { grid-template-columns: 1fr; }
.tsc-main .srow--3 { display: grid; grid-template-columns: 1.15fr 1fr 1fr; }
.tsc-main .srow--3 span, .tsc-main .srow--3 span:last-child { text-align: left; }
.tsc-main .srow--3 span:last-child { color: var(--tsc-amber); }
.tsc-main .srow--head span {
  color: var(--tsc-ink-mut); font-family: var(--tsc-mono); font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
}

/* ═══════════════════════════════════════════════════════════════════════
   THE FEATURE CARD DECK  —  templates/parts/card-deck.php
   ───────────────────────────────────────────────────────────────────────
   The TeraWulf grammar Jim pointed at: a big pale panel, a short left column
   of type, a render bleeding off the right edge, and the panels stacked so
   each one peeks above the next.

   What is NOT borrowed: the palette. TeraWulf has no accent colour at all.
   The amber is his, and on these cards it is spent on exactly one element
   each — the button on hover, and one closed contact in the artwork. Copying
   their blue-grey would have made his site look like theirs instead of his.

   ⚠ EVERY CLASS HERE IS `tsc-` PREFIXED ON PURPOSE. `.card` and `.pins` are
   common enough that Royal Kit or an Elementor widget could well define them,
   and scoping under .tsc-main protects our rules from theirs but NOT ours
   from theirs leaking in. The prefix is the actual protection.

   ⚠ The artwork SVGs bake in #101C33, so the art panel must be
   --tsc-navy-deep and NOT --tsc-navy (#192A4A) — otherwise there is a visible
   seam where the drawing meets the panel it sits in.
   ══════════════════════════════════════════════════════════════════════ */

/* Runs wider than the reading column: --tsc-col (975px) is set for prose,
   and these are pictures. The .band parent still supplies the vertical
   rhythm and gutters, so the deck cannot drift out of step with the page.

   ⚠ TRIED AND REVERTED (3 Aug): min(1560px, 92vw), to match terawulf.com's
   wider deck. Do not retry it on its own. Two reasons it failed:
     1. Below a ~1440px viewport the vw term wins and it changes NOTHING — the
        gutters were already the binding constraint, so on any normal window
        it is a no-op that looks like a broken change.
     2. Above that it widens the art panel but not its height, and the globe
        canvas sizes its radius off max(W,H) — so the sphere grew past the
        panel and lost its poles. Visible globe height went ~66% -> ~56%.
   Widening the deck REQUIRES retuning globe.js's R and the poster's
   object-fit together, or the cards get wider and the globe gets cropped. */
.tsc-main .tsc-deck,
.tsc-main .tsc-deck-head { max-width: 1320px; margin-inline: auto; }
/* Went 34-60 -> 56-104 -> this, because it kept reading as crowded. Two
   separate things eat the gap and both had to be handled:

   1. line-height .98 means the h2's BOX bottom sits above its own descenders,
      so a margin measured from the box is smaller than the gap you see. The
      padding-bottom below pays that back.
   2. The first card is a large solid panel, not text. A gap that looks
      generous under a paragraph looks tight under a filled rectangle.

   ⚠ This is the RESTING gap only. Once you scroll, card 1 sticks at
   --tsc-stack-top and the heading keeps scrolling, so the card WILL close on
   it and pass underneath. That is the stack working, not a spacing bug — no
   margin here can change it, and the reference behaves the same way. */
.tsc-main .tsc-deck-head { margin-bottom: clamp(80px, 8vw, 148px); }
/* ⚠ MEASURED, do not trim back to .1em. At 60px/.98 the line box is 16px
   shorter than the font wants (ascent 61 + descent 14 = 75 vs 58.8), so the
   glyphs overflow ~8px past the box top AND bottom. .1em paid back only 6px
   of that, leaving the descenders of "why you're" rendering ~2px OUTSIDE the
   h2's own border box — which is why the y-tails touched the card as the
   stack closed on them. .3em clears the overflow and leaves ~10px of real
   whitespace, so first contact is box-to-box, never ink-to-card. */
.tsc-main .tsc-deck-head h2 { padding-bottom: .3em; }
.tsc-main .tsc-deck-head h2 {
  max-width: 18ch; margin: 0;
  font-size: clamp(34px, 4.4vw, 60px); line-height: .98; letter-spacing: -.055em;
  text-wrap: balance;
}

/* ── The stack ────────────────────────────────────────────────────────────
   The peek is the whole trick. Each card sits BEHIND the next and is inset
   horizontally, so you see a sliver of its shoulder above — a stack of panels
   rather than a list of boxes. Insets shrink to zero on the last card, which
   is the one fully in front. */
.tsc-main .tsc-card {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  align-items: stretch;
  min-height: 440px; overflow: hidden;
  border-radius: 20px;
  background: var(--tsc-pale);
  /* Two shadows, not one: a tight edge and a wide soft lift. A single large
     blur reads as haze rather than as a card sitting on top of another card. */
  box-shadow: 0 1px 2px rgba(16, 28, 51, .10), 0 -14px 34px -18px rgba(16, 28, 51, .34);
}
/* ── The scroll stack ─────────────────────────────────────────────────────
   The reference does not just OVERLAP the cards, it COLLECTS them: each one
   sticks under the header and the next scrolls up over it, leaving a sliver
   of every card already read. The first pass faked that with negative margins,
   which produced the look standing still and nothing at all on scroll.

   Each card sticks one --tsc-stack-peek lower than the one before, so the
   stack accumulates visible shoulders as you go. Widths still step inward
   behind, so you see the previous card at the sides as well as above.

   ⚠ --tsc-stack-top must clear Royal Kit's header. It is a variable precisely
   because the live header height is not measurable from here — if the top card
   tucks under the header on the real site, this ONE number is the fix.
   ⚠ Sticky dies silently under any ancestor with overflow: hidden. `.tsc-page`
   sets overflow-x: hidden on BODY, which is safe — the root propagates it to
   the viewport — but do not move that rule onto a wrapper div. The logo wipe
   uses sticky too, so if the stack breaks, check the wipe: they fail together. */
.tsc-main .tsc-deck {
  --tsc-stack-top: 96px;
  --tsc-stack-peek: 26px;
}
.tsc-main .tsc-card { position: sticky; }
.tsc-main .tsc-card + .tsc-card { margin-top: clamp(20px, 2.4vw, 40px); }
.tsc-main .tsc-card:nth-child(1) {
  width: calc(100% - 92px); margin-inline: auto; z-index: 1;
  top: var(--tsc-stack-top);
}
.tsc-main .tsc-card:nth-child(2) {
  width: calc(100% - 46px); margin-inline: auto; z-index: 2;
  top: calc(var(--tsc-stack-top) + var(--tsc-stack-peek));
}
.tsc-main .tsc-card:nth-child(3) {
  width: 100%; z-index: 3;
  top: calc(var(--tsc-stack-top) + var(--tsc-stack-peek) * 2);
}
.tsc-main .tsc-card:nth-child(4) {
  width: 100%; z-index: 4;
  top: calc(var(--tsc-stack-top) + var(--tsc-stack-peek) * 3);
}

.tsc-main .tsc-card__copy {
  display: flex; flex-direction: column; justify-content: center; gap: 22px;
  padding: clamp(38px, 4.6vw, 76px);
}
.tsc-main .tsc-card__copy h3 {
  max-width: 15ch; margin: 0;
  font-size: clamp(30px, 3.5vw, 52px); line-height: 1.0; letter-spacing: -.052em;
  text-wrap: balance; color: var(--tsc-navy);
}
/* Beats the base `.tsc-main p` rule on specificity — these need no top margin
   (the flex gap owns the spacing) and a narrower measure than body prose. */
.tsc-main .tsc-card__copy p {
  max-width: 46ch; margin: 0;
  font-size: clamp(15px, 1.15vw, 18px); line-height: 1.55; color: var(--tsc-ink-mut);
}

/* Pill, not the square .btn: these cards need to read as a separate component
   rather than as a band with rounded corners. */
.tsc-main .tsc-card__cta {
  align-self: start;
  display: inline-flex; align-items: center; gap: 12px;
  padding: 14px 24px; border-radius: 999px;
  background: var(--tsc-navy-deep); color: var(--tsc-white);
  font-family: var(--tsc-mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: .15em; text-transform: uppercase; text-decoration: none;
  transition: background .3s var(--tsc-ease), color .3s var(--tsc-ease);
}
.tsc-main .tsc-card__cta svg { flex: none; transition: transform .3s var(--tsc-ease); }
.tsc-main .tsc-card__cta:hover { background: var(--tsc-amber); color: var(--tsc-navy-deep); }
.tsc-main .tsc-card__cta:hover svg { transform: translateX(4px); }
.tsc-main .tsc-card__cta:focus-visible { outline: 2px solid var(--tsc-amber); outline-offset: 3px; }

/* ── The render side ──────────────────────────────────────────────────────
   Bleeds off the right and bottom exactly as the reference does. The image is
   deliberately oversized and anchored left so the interesting part of the
   drawing stays in frame while the edge runs out of the card. */
.tsc-main .tsc-card__art { position: relative; overflow: hidden; background: var(--tsc-navy-deep); }
.tsc-main .tsc-card__art img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: left center;
}
/* Feathers the join so the artwork emerges from the panel instead of sitting
   in a hard-edged rectangle beside it. The transparent stop MUST be --tsc-pale
   in rgba form (#EDF0F5) — a mismatched stop tints the whole fade. */
.tsc-main .tsc-card__art::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, var(--tsc-pale) 0, rgba(237, 240, 245, 0) 22%);
}

/* ── The rotary mechanism (card 3) ────────────────────────────────────────
   Both layers are square and centre-anchored, so the sweep rotates about the
   hub rather than orbiting it. `object-position: left center` — the deck's
   default — would put the mechanism's centre off the element's centre and
   the arm would wobble around an empty point.

   ⚠ CSS rotation is RIGHT here and WRONG on the globe. A rotary mechanism
   genuinely turns in its own plane; a planet does not, which is why the globe
   is re-projected per frame in canvas instead. Same-looking problem, opposite
   correct answer — do not "unify" these two. */
.tsc-main .tsc-card__art--rotary img { object-position: center center; }

.tsc-main .tsc-rotary-spin {
  transform-origin: 50% 50%;
  will-change: transform;
  /* Longhands, not the shorthand: `animation: name linear infinite` sets
     duration to 0s, and a later rule adding animation-duration only works by
     cascade luck. Each layer supplies its own duration below. */
  animation-name: tsc-rotary-turn;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

/* Different rates, and alternating directions, because that is the whole
   point: matched speeds collapse back into one spinning picture. The outer
   bands are slow and heavy, the hub is quick and light — which is also how
   real gearing behaves, so it reads as machinery rather than as decoration.
   Durations are deliberately not multiples of each other; common factors make
   the stack visibly re-sync on a short loop. */
.tsc-main .tsc-rotary--outer { animation-duration: 47s; }
.tsc-main .tsc-rotary--mid   { animation-duration: 31s; animation-direction: reverse; }
.tsc-main .tsc-rotary--inner { animation-duration: 23s; }
.tsc-main .tsc-rotary--hub   { animation-duration: 11s; animation-direction: reverse; }
.tsc-main .tsc-rotary--sweep { animation-duration: 18s; }

@keyframes tsc-rotary-turn {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* The global reduced-motion block collapses animation-duration to .001ms,
   which would leave every layer frozen at a random angle. Stop them all at
   0deg instead, where the composition was actually designed. */
@media (prefers-reduced-motion: reduce) {
  .tsc-main .tsc-rotary-spin { animation: none !important; transform: none; }
}

/* ── The globe ────────────────────────────────────────────────────────────
   The canvas draws the SAME globe, re-projected every frame, and cross-fades
   in over the static SVG once it has actually painted — so there is never a
   blank hole. No JS, no canvas, or reduced-motion all keep the SVG, which is
   a real picture rather than a spinner.
   ⚠ The canvas must precede the <img> in the markup for the sibling rule. */
.tsc-main .tsc-card__art--globe img {
  object-position: center center; transition: opacity .6s var(--tsc-ease);
}
.tsc-main .tsc-globe-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; transition: opacity .6s var(--tsc-ease);
}
.tsc-main .tsc-globe-canvas.ready { opacity: 1; }
.tsc-main .tsc-globe-canvas.ready ~ img { opacity: 0; }
/* Its own feather: the default left-edge one is wide enough to cut the pins. */
.tsc-main .tsc-card__art--globe::after {
  background: linear-gradient(90deg, var(--tsc-pale) 0, rgba(237, 240, 245, 0) 16%);
}

/* Chips are HTML over the SVG rather than <text> inside it: they stay crisp at
   any scale, stay selectable, and a city can be edited without regenerating
   artwork. Positioned by --x/--y percentages of the art panel. */
.tsc-main .tsc-pins {
  position: absolute; inset: 0; margin: 0; padding: 0;
  list-style: none; pointer-events: none;
}
.tsc-main .tsc-pins li {
  position: absolute; left: var(--x); top: var(--y); transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; gap: 9px; white-space: nowrap;
  padding: 7px 13px; border-radius: 5px;
  border: 1px solid rgba(235, 240, 245, .14);
  background: rgba(16, 28, 51, .62);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  font-family: var(--tsc-mono); font-size: 11px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: rgba(235, 240, 245, .88);
}
.tsc-main .tsc-pins i { font-style: normal; color: var(--tsc-amber); opacity: .85; }

/* ── Responsive ───────────────────────────────────────────────────────────
   Below 860 the two-column split stops working: the type column gets too
   narrow to hold a 15ch headline. Stack, and let the art take a fixed band
   under the copy. The peek insets go too — overlapping cards on a phone just
   look like a rendering bug. */
@media (max-width: 860px) {
  .tsc-main .tsc-card { grid-template-columns: 1fr; min-height: 0; }
  .tsc-main .tsc-card__art { min-height: 260px; }
  .tsc-main .tsc-card__art::after,
  .tsc-main .tsc-card__art--globe::after {
    background: linear-gradient(180deg, var(--tsc-pale) 0, rgba(237, 240, 245, 0) 26%);
  }
  .tsc-main .tsc-card + .tsc-card { margin-top: 16px; }
  /* No sticky stack on a phone. Each card is nearly a full screen tall here,
     so collecting them would pin most of the viewport and leave a sliver to
     read through. Plain scroll instead. */
  .tsc-main .tsc-card:nth-child(n) { width: 100%; position: relative; top: auto; }
  /* Five chips will not fit over a 260px band without colliding. Show the
     three that read cleanly and drop the rest, rather than shrinking all five
     into illegibility. */
  .tsc-main .tsc-pins li { font-size: 9.5px; padding: 5px 9px; gap: 6px; }
  .tsc-main .tsc-pins li:nth-child(n+4) { display: none; }
}
