/* ==================================================================
   Hello Rocket — the technical register (light).

   One world, not two. The opening band is a painted ridge under an
   open white sky; everything after it stays in that daylight and gets
   structure added rather than the lights turned off. Foundation
   Section 13 is the reason: "if one section feels like it came from a
   different website, it is wrong." A dark interior under a bright
   hero fails that test no matter how good the dark interior is.

   So the technical feeling here comes from PRECISION, not darkness:
   hairline grids, mono annotations, real diagrams, and signal drawn
   as light moving through the page. White and pale cobalt carry it.

   Colour discipline, straight from foundation Section 9 — "one job
   per colour, the accent is reserved for the things we want clicked":

     cobalt  — structure, signal, diagrams, emphasis. Everywhere.
     coral   — buttons and CTAs. NOTHING ELSE.

   That is why no rule below paints a number, a rule or a label coral.
   Spending the accent on decoration is what stops it pulling the eye
   on the one element that has to.

   Pairs with tech.js. `about.css` still owns the opening band.
   ================================================================== */

:root{
  /* --- grounds ----------------------------------------------------
     All warm-white to pale cobalt, so a section change reads as a
     change of light rather than a change of place. */
  --tk-bg:     #FFFFFF;
  --tk-wash-1: #F8FBFF;
  --tk-wash-2: #E9F2FD;
  --tk-panel:  #FFFFFF;
  --tk-well:   #F7FBFF;

  /* hairlines. --tk-line is a visible border; --tk-rule is structure
     you should feel rather than see (grids, table rules). */
  --tk-line: #DCE7F3;
  --tk-rule: rgba(24,120,242,.10);

  /* type — the site's existing ink ramp, unchanged, so the two
     registers cannot drift apart on colour */
  --tk-ink:   #12243A;
  --tk-ink-2: #46607F;
  --tk-ink-3: #7089A5;

  --tk-beam:      #1878F2;
  --tk-beam-deep: #0B5EC4;
  --tk-beam-pale: #EAF3FE;

  /* one shadow recipe for the whole register. Cobalt-tinted, never
     grey — a neutral shadow next to this blue reads as dirt. */
  --tk-lift:   0 1px 2px rgba(12,46,92,.05), 0 8px 22px -12px rgba(12,46,92,.16);
  --tk-lift-2: 0 2px 4px rgba(12,46,92,.06), 0 22px 44px -20px rgba(12,46,92,.26);

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* ==================================================================
   1. Section shells
   ================================================================== */

/* `main > section:not(.hero)` in styles.css paints every section white
   at (0,1,2) so the home page can cover its fixed hero. Any section
   that wants its own ground has to match that weight — the same move
   `.ab-field` makes further down styles.css. Drop the `main > section`
   prefix and every washed band below silently turns white. */
main > section.tk{
  position: relative;
  z-index: 2;
  background: var(--tk-bg);
  color: var(--tk-ink-2);
  padding: clamp(5.5rem, 13vh, 9.5rem) 0;
  overflow: hidden;
  isolation: isolate;
}
/* These have to carry the `main > section` prefix too. Written bare
   they are (0,1,0) and lose to the rule directly above, which means
   the modifier silently does nothing — which is exactly what happened
   to `--scened` and let the bleed artwork climb over its own copy. */
main > section.tk--tight{ padding: clamp(3.5rem, 8vh, 5.5rem) 0; }
/* Tightened from 17vh. That spacing was set when these sections were pure
   type and needed air; with a scene in every one, the same gap reads as a
   hole between pictures rather than breathing room. */
main > section.tk--tall{  padding: clamp(4.5rem, 10vh, 7rem) 0; }

/* The washed band. Foundation Section 7 wants rhythm without noise,
   so the page alternates white and ONE pale cobalt wash and never
   introduces a third ground. */
main > section.tk--wash{
  background: linear-gradient(180deg, var(--tk-wash-1) 0%, var(--tk-wash-2) 100%);
  border-block: 1px solid rgba(24,120,242,.07);
}

.tk__in{ position: relative; z-index: 3; }

/* ---- the hairline grid -------------------------------------------
   Drawn in CSS so it stays crisp at any DPR and costs nothing. Masked
   to a soft ellipse: a grid at full strength edge to edge is graph
   paper, but one resolving out of the page reads as a space the
   content is standing in. On white it has to be far fainter than it
   would be on a dark ground — at equal alpha it reads as a printing
   fault rather than as structure. */
.tk-grid{
  position: absolute; inset: -1px;
  --g: 64px;
  background-image:
    linear-gradient(to right,  var(--tk-rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--tk-rule) 1px, transparent 1px);
  background-size: var(--g) var(--g);
  opacity: .55;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 8%, #000 0%, transparent 70%);
          mask-image: radial-gradient(120% 90% at 50% 8%, #000 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.tk-grid--wide{ --g: 96px; }
.tk-grid--fine{ --g: 34px; }

/* A cobalt bloom behind the content — daylight coming through rather
   than a glow in the dark, so it stays very low in alpha. */
.tk-glow{
  position: absolute;
  width: var(--w, 46rem); aspect-ratio: 1;
  left: var(--x, 50%); top: var(--y, 0%);
  transform: translate(-50%, -50%);
  background: radial-gradient(circle,
    rgba(24,120,242,var(--i, .1)) 0%,
    rgba(24,120,242,calc(var(--i, .1) * .32)) 36%,
    rgba(24,120,242,0) 68%);
  pointer-events: none;
  z-index: 1;
  animation: tk-breathe var(--dur, 16s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
@keyframes tk-breathe{
  0%,100%{ opacity: .7; transform: translate(-50%,-50%) scale(1); }
  50%    { opacity: 1;  transform: translate(-50%,-50%) scale(1.12); }
}

.tk-canvas{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; pointer-events: none; z-index: 0;
}

/* ==================================================================
   2. Scene — a painted band that carries a section

   The custom Higgsfield visuals live here. They are the SAME world as
   the opening band, which is the whole point of using them instead of
   an abstract gradient: foundation Section 10's consistency rule says
   every image on the site has to belong to one treatment.

   The art always dissolves into the page rather than sitting in a box
   with a hard top edge — a rectangle of illustration dropped on white
   is one of the things that makes a site look assembled.
   ================================================================== */

.tk-scene{
  position: relative;
  margin-top: clamp(2.6rem, 6vw, 4rem);
  border-radius: 20px;
  overflow: hidden;
  box-shadow: var(--tk-lift-2);
  background: var(--tk-beam-pale);
}
.tk-scene img,
.tk-scene video{
  display: block; width: 100%; height: auto;
  /* the art is generated with open sky at the top; fading that edge
     lets the picture rise out of the page instead of starting at a
     hard line */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 15%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 15%);
}

/* Full-bleed variant: the art runs the width of the viewport and
   bleeds off the bottom of its section — the same move the opening
   band makes, so the two read as one device used twice rather than as
   two different treatments. */
/* The band is given an EXPLICIT height and the section reserves
   exactly that much padding, which is the same contract `.wd--hero`
   uses in about.css. Letting the image size itself is what put the
   art on top of the copy: a 2400px-wide picture scaled to a 1440px
   window is ~610px tall, taller than the section's own content, so it
   climbed straight up through the paragraph. Reserving the height
   makes the overlap impossible at any viewport rather than at the
   ones that happened to be checked. */
.tk-scene--bleed{
  --art-h: clamp(13rem, 28vw, 24rem);
  position: absolute;
  left: -3%; right: -3%; bottom: -1px;
  height: var(--art-h);
  margin: 0; border-radius: 0; box-shadow: none; background: none;
  z-index: 1; pointer-events: none;
}
.tk-scene--bleed picture{ display: block; height: 100%; }
.tk-scene--bleed img,
.tk-scene--bleed video{
  height: 100%;
  object-fit: cover;
  object-position: center bottom;   /* keep the land, crop the sky */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 38%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 38%);
}
/* `main > section` again, and last in the file, so it beats both the
   base padding AND the `--tall` modifier a scened section also carries */
main > section.tk--scened{
  padding-bottom: calc(clamp(13rem, 28vw, 24rem) + clamp(2.5rem, 6vw, 5rem));
}

.tk-scene__cap{
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: clamp(1rem, 2.4vw, 1.6rem) clamp(1.1rem, 3vw, 2rem);
  background: linear-gradient(180deg, rgba(255,255,255,0), rgba(255,255,255,.92) 62%);
  font-family: var(--mono); font-size: .65rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--tk-ink-3);
}

/* ==================================================================
   3. Type
   ================================================================== */

/* Every section on the technical side is numbered. It is what makes
   the page read as documentation of a system rather than a brochure. */
.tk-label{
  display: inline-flex; align-items: center; gap: .65rem;
  font-family: var(--mono);
  font-size: .7rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--tk-beam);
  margin: 0 0 clamp(1.1rem, 2.6vw, 1.6rem);
}
.tk-label::before{
  content: ""; width: 1.7rem; height: 1px;
  background: currentColor; opacity: .55;
}
.tk-label b{ font-weight: 400; color: var(--tk-ink-3); }

.tk-h{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(2.2rem, 5.4vw, 4.1rem);
  line-height: .98; letter-spacing: -.045em;
  color: var(--tk-ink);
  margin: 0; max-width: 17ch; text-wrap: balance;
}
.tk-h--sm{ font-size: clamp(1.75rem, 3.5vw, 2.6rem); max-width: 20ch; }
.tk-h--xl{ font-size: clamp(2.5rem, 7vw, 5.2rem); max-width: 14ch; }
/* the one emphasis available inside a heading. Cobalt, never coral —
   see the colour note at the top of this file. */
.tk-h em{ font-style: normal; color: var(--tk-beam); }

.tk-p{
  margin: clamp(1.2rem, 2.6vw, 1.75rem) 0 0;
  color: var(--tk-ink-2);
  font-size: clamp(1.01rem, 1.24vw, 1.14rem);
  line-height: 1.68; max-width: 46ch; text-wrap: pretty;
}
.tk-p--wide{ max-width: 62ch; }
.tk-p strong{ color: var(--tk-ink); font-weight: 600; }

.tk-lead{
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.3rem, 2.5vw, 1.95rem);
  line-height: 1.38; letter-spacing: -.022em;
  color: var(--tk-ink); max-width: 30ch;
  margin: clamp(1.4rem, 3vw, 2rem) 0 0;
}

.tk-head{
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(1.5rem, 5vw, 4.5rem);
  align-items: end;
}
.tk-head .tk-p{ margin-top: 0; }
@media (max-width: 900px){
  .tk-head{ grid-template-columns: 1fr; align-items: start; gap: 1.4rem; }
}

/* ---- pillars: three words that carry a paragraph ---------------- */
.tk-pillars{
  list-style: none; margin: clamp(2.2rem,5vw,3.2rem) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: clamp(1rem, 2.6vw, 2rem);
}
.tk-pillars li{ padding-top: 1.1rem; border-top: 2px solid var(--tk-beam); }
.tk-pillars b{
  display: block; font-family: var(--display); font-weight: 600;
  font-size: clamp(1.05rem, 1.7vw, 1.3rem); letter-spacing: -.028em;
  color: var(--tk-ink); margin-bottom: .35rem;
}
.tk-pillars span{ display: block; font-size: .95rem; line-height: 1.55; color: var(--tk-ink-2); }

/* ==================================================================
   4. Panels
   ================================================================== */

.tk-panel{
  position: relative;
  background: var(--tk-panel);
  border: 1px solid var(--tk-line);
  border-radius: 18px;
  padding: clamp(1.5rem, 3vw, 2.2rem);
  box-shadow: var(--tk-lift);
  transition: border-color .45s ease, transform .55s cubic-bezier(.22,.7,.3,1),
              box-shadow .45s ease;
}
.tk-panel:hover{
  border-color: rgba(24,120,242,.34);
  box-shadow: var(--tk-lift-2);
  transform: translateY(-4px);
}
/* Sits directly on the heading it numbers. The glyph above already
   opens the card; a second large gap here reads as the number having
   drifted loose from its own title. */
.tk-panel__n{
  display: block;
  font-family: var(--mono); font-size: .67rem; letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--tk-beam); margin-bottom: .6rem;
}
.tk-panel h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.15rem, 1.9vw, 1.45rem);
  letter-spacing: -.03em; line-height: 1.15;
  color: var(--tk-ink); margin: 0 0 .55rem;
}
.tk-panel p{
  margin: 0; color: var(--tk-ink-2);
  font-size: clamp(.93rem, 1.1vw, 1.01rem); line-height: 1.62;
}

.tk-cols{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: clamp(1rem, 2.2vw, 1.5rem);
  margin-top: clamp(2.2rem, 5vw, 3.4rem);
}
.tk-cols--2{ grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr)); }

/* ---- the looping glyph that rides in a panel -------------------- */
.tk-glyph{
  position: relative;
  width: 3.1rem; height: 3.1rem;
  margin-bottom: clamp(1.1rem, 2.4vw, 1.5rem);
  flex: none;
}
.tk-glyph svg{ width: 100%; height: 100%; overflow: visible; display: block; }
.tk-glyph .st{ fill: none; stroke: var(--tk-beam); stroke-width: 1.35; }
.tk-glyph .st--dim{ stroke: #B9CEE5; }
.tk-glyph .fl{ fill: var(--tk-beam); }

.tk-spin{ animation: tk-spin var(--dur, 18s) linear infinite; transform-origin: 50% 50%; }
.tk-pulse{ animation: tk-pulse var(--dur, 3.4s) ease-in-out infinite; transform-origin: 50% 50%; }
.tk-trace{
  stroke-dasharray: var(--len, 100);
  stroke-dashoffset: var(--len, 100);
  animation: tk-trace var(--dur, 4.5s) cubic-bezier(.6,0,.35,1) infinite;
}
/* A short dash travelling a path — signal moving along a specific
   line. The path needs a dim static twin underneath it, or the link
   only exists while the dash is on it. --len is the path length,
   rounded up: over-stating it parks the dash off the end for slightly
   longer, while under-stating it shows two dashes at once. */
.tk-send{
  stroke-dasharray: 5 var(--len, 200);
  stroke-dashoffset: var(--len, 200);
  animation: tk-send var(--dur, 3s) linear infinite;
  animation-delay: var(--delay, 0s);
}
@keyframes tk-spin{ to{ transform: rotate(360deg); } }
@keyframes tk-pulse{
  0%,100%{ opacity: .3; transform: scale(.86); }
  50%    { opacity: 1;  transform: scale(1.1); }
}
@keyframes tk-trace{
  0%  { stroke-dashoffset: var(--len, 100); }
  55% { stroke-dashoffset: 0; }
  100%{ stroke-dashoffset: calc(var(--len, 100) * -1); }
}
@keyframes tk-send{ to{ stroke-dashoffset: -5; } }

/* ==================================================================
   5. The engine — a rail with signal moving along it

   The centrepiece. A rail runs behind a row of stage cards and pulses
   travel it, so the process is shown working rather than listed. The
   rail is drawn once and each pulse is one element on a delay, so
   this costs no JS at all.
   ================================================================== */

.tk-engine{ position: relative; margin-top: clamp(2.6rem, 6vw, 4rem); }

.tk-engine__rail{
  position: absolute;
  left: 0; right: 0; top: var(--rail-y, 3.4rem);
  height: 2px;
  pointer-events: none; z-index: 0;
  /* the pulse is animated past the end of the rail so it clears the
     last node; without this it keeps travelling as a bright bar out
     across the rest of the section */
  overflow: hidden;
}
.tk-engine__rail::before{
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent, var(--tk-line) 6%, var(--tk-line) 94%, transparent);
}
.tk-engine__pulse{
  position: absolute; top: 0; left: 0;
  width: 7rem; height: 2px;
  background: linear-gradient(90deg,
    rgba(24,120,242,0), rgba(24,120,242,.85), var(--tk-beam-deep), rgba(24,120,242,0));
  animation: tk-run var(--dur, 6s) linear infinite;
  animation-delay: var(--delay, 0s);
  opacity: 0;
}
@keyframes tk-run{
  0%  { transform: translateX(-8rem); opacity: 0; }
  8%  { opacity: 1; }
  92% { opacity: 1; }
  100%{ transform: translateX(calc(100vw + 8rem)); opacity: 0; }
}

.tk-stages{
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(.7rem, 1.6vw, 1.2rem);
  list-style: none; margin: 0; padding: 0;
}
/* a column, so the footer line can be pushed to the bottom — stage
   paragraphs differ in length and left in flow those footers land on
   five different baselines, which turns a precise diagram into a
   ragged one */
.tk-stage{ position: relative; display: flex; flex-direction: column; }

.tk-stage__dot{
  position: relative;
  width: 2.2rem; height: 2.2rem;
  margin: calc(var(--rail-y, 3.4rem) - 1.1rem) 0 1.4rem;
  border-radius: 50%;
  background: var(--tk-bg);
  border: 1px solid var(--tk-line);
  box-shadow: var(--tk-lift);
  display: grid; place-items: center;
  font-family: var(--mono); font-size: .64rem; color: var(--tk-ink-3);
  transition: border-color .4s ease, color .4s ease, box-shadow .4s ease;
}
/* the halo lives on a pseudo so the dot itself never scales and the
   rail alignment cannot drift */
.tk-stage__dot::after{
  content: "";
  position: absolute; inset: -.5rem;
  border-radius: 50%;
  border: 1px solid rgba(24,120,242,.4);
  opacity: 0;
  animation: tk-ping 5.6s ease-out infinite;
  animation-delay: calc(var(--i, 0) * 1.12s);
}
@keyframes tk-ping{
  0%  { opacity: 0;  transform: scale(.72); }
  14% { opacity: .8; }
  46% { opacity: 0;  transform: scale(1.5); }
  100%{ opacity: 0;  transform: scale(1.5); }
}
.tk-stage:hover .tk-stage__dot{
  border-color: var(--tk-beam); color: var(--tk-ink);
  box-shadow: 0 0 0 4px rgba(24,120,242,.09), var(--tk-lift);
}
.tk-stage h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1rem, 1.4vw, 1.18rem);
  letter-spacing: -.028em; color: var(--tk-ink); margin: 0 0 .45rem;
}
.tk-stage p{
  margin: 0; font-size: clamp(.86rem, 1vw, .94rem);
  line-height: 1.56; color: var(--tk-ink-2);
}
.tk-stage__out{
  display: block; margin-top: auto; padding-top: .9rem;
  font-family: var(--mono); font-size: .63rem; letter-spacing: .1em;
  color: var(--tk-ink-3); text-transform: uppercase;
}
.tk-stage__out b{ color: var(--tk-beam); font-weight: 400; }

/* Phones get the rail turned on its side rather than a squashed row:
   five columns at 390px is four characters wide. */
@media (max-width: 860px){
  .tk-stages{ grid-template-columns: 1fr; gap: 0; }
  .tk-engine__rail{ left: 1.1rem; right: auto; top: 0; bottom: 0; width: 2px; height: auto; }
  .tk-engine__rail::before{
    background: linear-gradient(180deg, transparent, var(--tk-line) 5%, var(--tk-line) 95%, transparent);
  }
  /* The horizontal pulse crosses on translateX(100vw), which is safe
     because the rail can never be wider than the window. Turned
     vertical that assumption breaks — the stacked rail is several
     screens tall — so the vertical pulse animates `top`, where 100% is
     the rail's own height and the traverse is exact at any length. */
  .tk-engine__pulse{
    width: 2px; height: 6rem;
    background: linear-gradient(180deg,
      rgba(24,120,242,0), rgba(24,120,242,.85), var(--tk-beam-deep), rgba(24,120,242,0));
    transform: none;
    animation-name: tk-run-v;
  }
  @keyframes tk-run-v{
    0%  { top: -6rem; opacity: 0; }
    8%  { opacity: 1; }
    92% { opacity: 1; }
    100%{ top: 100%;  opacity: 0; }
  }
  .tk-stage{
    display: grid; grid-template-columns: 2.2rem minmax(0,1fr);
    gap: 0 1.2rem; padding-bottom: 2.2rem;
  }
  .tk-stage__dot{ margin: 0; grid-row: span 3; }
  .tk-stage h3{ margin-top: .35rem; }
}

/* ---- the return -------------------------------------------------
   The copy says the process is a loop; a row of five cards says it is
   a line. This closes it. A literal arc from stage five back to stage
   one would have to travel around the outside of the cards at every
   breakpoint, so the loop is stated on the rule instead — same
   information, no geometry to maintain. */
.tk-loopback{
  position: relative;
  margin: clamp(2.4rem, 5vw, 3.4rem) 0 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: .67rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--tk-ink-3);
}
.tk-loopback::before{
  content: "";
  position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  background: repeating-linear-gradient(90deg, var(--tk-line) 0 5px, transparent 5px 11px);
}
/* the label knocks a hole in the dashes by painting the section's own
   ground behind itself — cheaper and crisper than masking the rule */
.tk-loopback span{
  position: relative;
  display: inline-flex; align-items: center; gap: .65rem;
  background: var(--tk-bg);
  padding: 0 clamp(.8rem, 2vw, 1.2rem);
  text-align: center;
}
.tk--wash .tk-loopback span{ background: var(--tk-wash-2); }
.tk-loopback svg{ width: 1.05rem; height: 1.05rem; flex: none; overflow: visible; }
.tk-loopback .st{ fill: none; stroke: var(--tk-beam); stroke-width: 1.6; }
.tk-loopback .fl{ fill: var(--tk-beam); }
@media (max-width: 560px){ .tk-loopback{ font-size: .61rem; letter-spacing: .1em; } }

/* ==================================================================
   6. Comparison — the same work, two systems

   Two figures making one honest point: nothing about the business
   changed, only whether anything carries it. No numbers are claimed
   anywhere in here, and none should be added — the piece works
   because it is a mechanism, not a statistic.
   ================================================================== */

.tk-vs{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(1rem, 2.4vw, 1.6rem);
  margin-top: clamp(2.4rem, 5.5vw, 3.6rem);
}
.tk-vs__cell{
  position: relative;
  border: 1px solid var(--tk-line);
  border-radius: 18px;
  padding: clamp(1.4rem, 2.8vw, 2rem);
  background: var(--tk-panel);
  box-shadow: var(--tk-lift);
  overflow: hidden;
}
.tk-vs__cell--lit{
  border-color: rgba(24,120,242,.28);
  background:
    radial-gradient(120% 80% at 50% 100%, rgba(24,120,242,.08), transparent 62%),
    var(--tk-panel);
  box-shadow: var(--tk-lift-2);
}
.tk-vs__fig{
  height: clamp(9rem, 20vw, 13rem);
  display: grid; place-items: center;
  margin-bottom: clamp(1.1rem, 2.4vw, 1.5rem);
}
.tk-vs__fig svg{ width: 100%; height: 100%; overflow: visible; }
.tk-vs__cap{
  font-family: var(--mono); font-size: .65rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--tk-ink-3); margin: 0 0 .6rem;
}
.tk-vs__cell--lit .tk-vs__cap{ color: var(--tk-beam); }
.tk-vs h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.1rem, 1.8vw, 1.38rem); letter-spacing: -.03em;
  color: var(--tk-ink); margin: 0 0 .5rem;
}
.tk-vs p{ margin: 0; font-size: .95rem; line-height: 1.6; color: var(--tk-ink-2); }

.tk-fig-node{ fill: #AFC5DC; }
.tk-fig-node--lit{ fill: var(--tk-beam); }
.tk-fig-link{ stroke: rgba(24,120,242,.45); stroke-width: 1; fill: none; }
.tk-fig-link--dead{ stroke: rgba(18,36,58,.13); stroke-dasharray: 3 5; }
.tk-fig-core{ fill: var(--tk-beam-deep); }

/* ==================================================================
   7. Measures — a truthful counter strip

   These count facts about the site itself, which anyone can verify by
   clicking. Performance figures do NOT go in this strip without a real
   source behind them — same reasoning as the articles under /learn/:
   an invented number on a page that argues you are the expert is the
   worst trade available.
   ================================================================== */

.tk-measures{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px;
  margin-top: clamp(2.2rem, 5vw, 3.2rem);
  background: var(--tk-line);       /* the gaps become the rules */
  border: 1px solid var(--tk-line);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--tk-lift);
}
.tk-measure{ background: var(--tk-panel); padding: clamp(1.4rem, 3vw, 2rem); }
.tk-measure__v{
  display: block;
  font-family: var(--display); font-weight: 600;
  font-size: clamp(2.1rem, 4.4vw, 3.1rem);
  line-height: 1; letter-spacing: -.05em;
  color: var(--tk-beam-deep);
  font-variant-numeric: tabular-nums;   /* stops the width jumping while counting */
}
.tk-measure__k{
  display: block; margin-top: .6rem;
  font-family: var(--mono); font-size: .65rem; letter-spacing: .15em;
  text-transform: uppercase; color: var(--tk-ink-3);
}

/* ==================================================================
   8. Big link rows
   ================================================================== */

.tk-go{ list-style: none; margin: clamp(2.2rem,5vw,3.2rem) 0 0; padding: 0; }
.tk-go li{ border-top: 1px solid var(--tk-line); }
.tk-go li:last-child{ border-bottom: 1px solid var(--tk-line); }
.tk-go a{
  position: relative;
  display: grid;
  grid-template-columns: auto auto minmax(0,1fr) auto;
  align-items: center; gap: clamp(1rem, 3vw, 2.4rem);
  padding: clamp(1.3rem, 3vw, 2rem) clamp(.6rem, 1.5vw, 1.2rem);
  text-decoration: none; color: inherit;
  transition: background .4s ease, padding-left .45s cubic-bezier(.22,.7,.3,1);
}
.tk-go a::before{     /* a rule that grows from the left on hover */
  content: "";
  position: absolute; left: 0; top: -1px; height: 1px; width: 0;
  background: var(--tk-beam);
  transition: width .55s cubic-bezier(.22,.7,.3,1);
}
.tk-go a:hover{ background: var(--tk-well); padding-left: clamp(1.1rem, 2.5vw, 2rem); }
.tk-go a:hover::before{ width: 100%; }
/* Scoped as `span.tk-go__n`, deliberately. The number IS a span, and
   `.tk-go span` below is (0,1,1) — higher than a bare class — so it was
   winning and forcing display:block. That is why the row kept four
   children below 640px, wrapped its arrow onto a second line, and at
   360px squeezed the picture column until the building sat on the text. */
.tk-go span.tk-go__n{
  display: block; margin-top: 0;
  font-family: var(--mono); font-size: .68rem; color: var(--tk-ink-3); letter-spacing: .14em;
}
.tk-go strong{
  display: block; font-family: var(--display); font-weight: 600;
  font-size: clamp(1.3rem, 2.7vw, 2rem); letter-spacing: -.035em;
  color: var(--tk-ink);
}
.tk-go span{ display: block; margin-top: .3rem; font-size: .95rem; color: var(--tk-ink-2); }
.tk-go em{
  font-style: normal; font-size: 1.25rem; color: var(--tk-ink-3);
  transition: transform .45s cubic-bezier(.22,.7,.3,1), color .35s ease;
}
.tk-go a:hover em{ color: var(--tk-beam); transform: translateX(7px); }
/* one small building per row — the same city, at footnote scale */
.tk-go__pic{ display: block; width: clamp(3rem, 6.5vw, 5rem); }
.tk-go__pic img{
  display: block; width: 100%; height: auto;
  transition: transform .45s cubic-bezier(.22,.7,.3,1);
}
.tk-go a:hover .tk-go__pic img{ transform: translateY(-5px) scale(1.05); }

@media (max-width: 640px){
  .tk-go a{ grid-template-columns: auto minmax(0,1fr) auto; }
  .tk-go span.tk-go__n{ display: none; }
  .tk-go__pic{ width: 3.1rem; }
}
@media (prefers-reduced-motion: reduce){
  .tk-go a:hover .tk-go__pic img{ transform: none; }
}

/* ==================================================================
   9. Ledger — numbered statements
   ================================================================== */

.tk-ledger{ list-style: none; margin: clamp(2.2rem,5vw,3.2rem) 0 0; padding: 0; }
.tk-ledger li{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.6rem);
  align-items: start;
  padding: clamp(1.4rem, 3vw, 2.1rem) 0;
  border-top: 1px solid var(--tk-line);
  transition: background .4s ease;
}
.tk-ledger li:last-child{ border-bottom: 1px solid var(--tk-line); }
.tk-ledger li:hover{ background: var(--tk-well); }
.tk-ledger__n{
  font-family: var(--mono); font-size: .68rem; letter-spacing: .14em;
  color: var(--tk-beam); padding-top: .45rem;
}
.tk-ledger h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.15rem, 2.1vw, 1.55rem); letter-spacing: -.032em;
  line-height: 1.16; color: var(--tk-ink); margin: 0;
}
.tk-ledger p{ margin: 0; color: var(--tk-ink-2); font-size: clamp(.94rem,1.1vw,1.02rem); line-height: 1.62; }
@media (max-width: 820px){
  .tk-ledger li{ grid-template-columns: auto minmax(0,1fr); }
  .tk-ledger p{ grid-column: 2; margin-top: .5rem; }
}

/* ==================================================================
   10. Ladder — the positions a business can hold

   A ladder of PREFERENCE, not a chart of results: the labels are
   states a company occupies and the heights are ordinal. Nothing here
   is measured, so it must never be given an axis, a percentage or a
   unit — the moment it carries a number it is claiming data it does
   not have.
   ================================================================== */

.tk-ladder{
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(.6rem, 1.6vw, 1.1rem);
  align-items: end;
  margin-top: clamp(2.4rem, 5vw, 3.6rem);
  padding-bottom: 1.4rem;
  border-bottom: 1px solid var(--tk-line);
}
.tk-ladder__step{ display: flex; flex-direction: column; justify-content: flex-end; }
.tk-ladder__bar{
  position: relative;
  height: calc(var(--h, 1) * clamp(3.4rem, 7vw, 5.4rem));
  border-radius: 8px 8px 0 0;
  background: linear-gradient(180deg, rgba(24,120,242,.22), rgba(24,120,242,.05));
  border: 1px solid rgba(24,120,242,.22);
  border-bottom: 0;
  margin-bottom: 1rem;
  /* grows out of the baseline as it arrives; the origin is the rule
     the bars stand on, so they rise rather than inflate */
  transform: scaleY(0); transform-origin: 50% 100%;
  transition: transform .95s cubic-bezier(.2,.75,.25,1);
  transition-delay: calc(var(--i, 0) * 120ms);
}
.is-in .tk-ladder__bar{ transform: scaleY(1); }
.tk-ladder__bar::after{
  content: "";
  position: absolute; inset: -1px 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--tk-beam), transparent);
  border-radius: 2px;
}
/* the top rung is the goal, so it gets the deepest cobalt rather than
   the accent — coral stays on buttons */
.tk-ladder__step--now .tk-ladder__bar{
  background: linear-gradient(180deg, rgba(11,94,196,.5), rgba(11,94,196,.1));
  border-color: rgba(11,94,196,.42);
}
.tk-ladder__step--now .tk-ladder__bar::after{
  background: linear-gradient(90deg, transparent, var(--tk-beam-deep), transparent);
}
.tk-ladder h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(.95rem, 1.5vw, 1.18rem); letter-spacing: -.025em;
  color: var(--tk-ink); margin: 0 0 .35rem;
}
.tk-ladder p{ margin: 0; font-size: clamp(.82rem, .98vw, .92rem); line-height: 1.5; color: var(--tk-ink-2); }
@media (max-width: 700px){
  .tk-ladder{ grid-template-columns: repeat(2, 1fr); row-gap: 1.8rem; }
}

/* ==================================================================
   11. Spec rows — what goes in, what comes out

   A stage that only describes itself is a claim; a stage that states
   its inputs, its output and what the client keeps is a contract.
   Keep the last row honest — it is the one a reader will hold you to.
   ================================================================== */

.tk-spec{ list-style: none; margin: clamp(2.4rem,5vw,3.4rem) 0 0; padding: 0; }
.tk-spec > li{
  display: grid;
  grid-template-columns: auto minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.8rem);
  align-items: start;
  padding: clamp(1.6rem, 3.4vw, 2.4rem) 0;
  border-top: 1px solid var(--tk-line);
  transition: background .4s ease;
}
.tk-spec > li:last-child{ border-bottom: 1px solid var(--tk-line); }
.tk-spec > li:hover{ background: var(--tk-well); }
.tk-spec__n{
  font-family: var(--mono); font-size: .68rem; letter-spacing: .14em;
  color: var(--tk-beam); padding-top: .5rem;
}
.tk-spec h3{
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.25rem, 2.3vw, 1.75rem); letter-spacing: -.035em;
  line-height: 1.12; color: var(--tk-ink); margin: 0 0 .6rem;
}
.tk-spec__main p{ margin: 0; color: var(--tk-ink-2); font-size: clamp(.95rem,1.1vw,1.03rem); line-height: 1.62; }

.tk-spec__io{ margin: 0; display: grid; gap: .8rem; }
.tk-spec__io > div{
  display: grid; grid-template-columns: 5rem minmax(0, 1fr);
  gap: .9rem; align-items: baseline;
}
.tk-spec__io dt{
  font-family: var(--mono); font-size: .62rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--tk-ink-3);
}
.tk-spec__io dd{
  margin: 0; font-size: clamp(.88rem, 1.02vw, .96rem);
  line-height: 1.5; color: var(--tk-ink);
}
/* the row a reader is actually buying */
.tk-spec__io > div:last-child dt{ color: var(--tk-beam); }
@media (max-width: 900px){
  .tk-spec > li{ grid-template-columns: auto minmax(0,1fr); }
  .tk-spec__io{ grid-column: 2; margin-top: 1.2rem; padding-top: 1.2rem; border-top: 1px solid var(--tk-line); }
}

/* ==================================================================
   12. The quarter — a plan drawn as a plan

   Twelve week columns with the phases laid across them. The columns
   ARE the weeks, so a bar's position is set by `grid-column` and can
   never drift out of agreement with the ruler above it.
   ================================================================== */

.tk-quarter{
  margin-top: clamp(2.4rem, 5vw, 3.4rem);
  border: 1px solid var(--tk-line);
  border-radius: 16px;
  padding: clamp(1.2rem, 2.6vw, 1.9rem);
  background: var(--tk-panel);
  box-shadow: var(--tk-lift);
}
.tk-quarter__ruler,
.tk-quarter__row{
  display: grid;
  grid-template-columns: 7.5rem repeat(12, minmax(0, 1fr));
  gap: 0 .3rem;
  align-items: center;
}
.tk-quarter__ruler{
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--tk-line);
  margin-bottom: .9rem;
}
.tk-quarter__ruler span{
  font-family: var(--mono); font-size: .6rem; letter-spacing: .08em;
  color: var(--tk-ink-3); text-align: center;
}
.tk-quarter__ruler b{
  font-family: var(--mono); font-size: .6rem; font-weight: 400;
  letter-spacing: .14em; text-transform: uppercase; color: var(--tk-ink-3);
}
.tk-quarter__row{ padding: .34rem 0; }
.tk-quarter__row > i{
  font-style: normal;
  font-family: var(--display); font-weight: 600; font-size: .9rem;
  color: var(--tk-ink); letter-spacing: -.015em;
}
.tk-quarter__bar{
  grid-column: calc(var(--from) + 2) / calc(var(--to) + 2);
  height: 1.9rem;
  border-radius: 7px;
  background: linear-gradient(90deg, rgba(24,120,242,.2), rgba(24,120,242,.08));
  border: 1px solid rgba(24,120,242,.28);
  display: flex; align-items: center;
  padding: 0 .65rem;
  font-family: var(--mono); font-size: .59rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--tk-beam-deep);
  white-space: nowrap; overflow: hidden;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .8s cubic-bezier(.2,.75,.25,1);
  transition-delay: calc(var(--i, 0) * 130ms);
}
.is-in .tk-quarter__bar{ transform: scaleX(1); }
/* the one that never stops */
.tk-quarter__bar--on{
  background: linear-gradient(90deg, rgba(11,94,196,.3), rgba(11,94,196,.1));
  border-color: rgba(11,94,196,.4);
}

/* The phone gets a real layout rather than a cropped one. This used to
   scroll sideways, and because the late phases start at weeks 9 and 11
   they fell off the right edge and rendered as EMPTY ROWS — a chart
   that silently omits its last two bars is worse than no chart. Here
   the label lifts onto its own line and the bar takes the full twelve
   columns underneath it. Nothing scrolls, nothing is hidden. */
@media (max-width: 720px){
  .tk-quarter__ruler,
  .tk-quarter__row{ grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .tk-quarter__ruler b{ grid-column: 1 / -1; margin-bottom: .5rem; }
  .tk-quarter__row{ row-gap: .4rem; padding: .5rem 0; }
  .tk-quarter__row > i{ grid-column: 1 / -1; font-size: .86rem; }
  .tk-quarter__bar{
    grid-column: calc(var(--from) + 1) / calc(var(--to) + 1);
    height: 1.5rem; padding: 0 .4rem;
  }
  /* a three-week bar is ~80px here — not enough for its caption, and a
     truncated one reads as a bug. The row label already names it. */
  .tk-quarter__bar b{ display: none; }
}

/* ==================================================================
   13. Closing band
   ================================================================== */

.tk-close{ text-align: center; }
/* The LABEL alone sits left, on the same rule as 01 through 06. Everything
   under it stays centred. As a block-level flex it fills the column, so
   flex-start puts it at the column's left edge while the section's own
   text-align:center goes on governing the heading and the copy. */
.tk-close .tk-label{ display: flex; justify-content: flex-start; text-align: left; }
.tk-close .tk-h{ margin-inline: auto; }
.tk-close .tk-p{ margin-inline: auto; text-align: center; }
.tk-close__cta{
  display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center;
  margin-top: clamp(1.8rem, 4vw, 2.6rem);
}
/* the coral button carries a real shadow here — it is the one element
   on the page allowed to shout, which is exactly why nothing else on
   the page is allowed to be coral */
.tk-close__cta .btn{
  font-weight: 700; padding: .92rem 1.7rem;
  box-shadow: 0 12px 28px rgba(226,96,74,.32);
}
.tk-btn2{
  display: inline-block; text-decoration: none;
  font-family: var(--display); font-weight: 600; font-size: .93rem;
  padding: calc(.92rem - 1.5px) calc(1.7rem - 1.5px);
  border: 1.5px solid var(--tk-line); border-radius: 999px;
  color: var(--tk-ink); background: var(--tk-panel);
  transition: border-color .3s ease, background .3s ease, transform .3s ease;
}
.tk-btn2:hover{ border-color: var(--tk-beam); background: var(--tk-beam-pale); transform: translateY(-2px); }

/* the beacon from the opening band, returning as pure light */
.tk-beacon{
  position: relative;
  width: clamp(3.6rem, 7vw, 5rem); aspect-ratio: 1;
  margin: 0 auto clamp(1.6rem, 3.5vw, 2.4rem);
}
.tk-beacon__core{
  position: absolute; inset: 36%;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #7FB4FF 38%, var(--tk-beam) 100%);
  box-shadow: 0 0 20px rgba(24,120,242,.5), 0 0 52px rgba(24,120,242,.28);
}
.tk-beacon i{
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(24,120,242,.42);
  animation: tk-ring 4.2s cubic-bezier(.2,.6,.4,1) infinite;
  animation-delay: var(--delay, 0s);
  opacity: 0;
}
@keyframes tk-ring{
  0%  { transform: scale(.34); opacity: 0; }
  16% { opacity: .85; }
  100%{ transform: scale(1.9); opacity: 0; }
}

/* ==================================================================
   14. Reveals

   Same `.is-in` contract as about.css, so one loop in tech.js drives
   both registers. Position-driven, never IntersectionObserver: an
   observer only fires while an element crosses its trigger band, so
   deep-linking into the middle of a page or flicking past a section
   fast can leave content invisible permanently. Asking "is it above
   the fold yet" on every frame cannot miss.
   ================================================================== */

.tk-words .w{
  display: inline-block; overflow: hidden; vertical-align: bottom;
  padding-bottom: .14em; margin-bottom: -.14em;
}
.tk-words .w__i{
  display: inline-block; transform: translateY(112%);
  transition: transform .86s cubic-bezier(.19,.76,.24,1);
  transition-delay: calc(var(--w,0) * 44ms);
}
.tk-words.is-in .w__i{ transform: none; }

.tk-rise{
  opacity: 0; transform: translateY(22px);
  transition: opacity .85s ease, transform .85s cubic-bezier(.22,.7,.3,1);
  transition-delay: calc(var(--d,0) * 90ms);
}
.tk-rise.is-in{ opacity: 1; transform: none; }

.tk-build{
  opacity: 0; transform: translateY(26px) scale(.985);
  transition: opacity .8s ease, transform .9s cubic-bezier(.22,.7,.3,1);
  transition-delay: calc(var(--d,0) * 110ms);
}
.tk-build.is-in{ opacity: 1; transform: none; }

/* ==================================================================
   15. Reduced motion

   Everything above is decoration over content that is already legible
   without it, so this can be blunt: stop all of it and show the end
   state. The counters in tech.js check the same query and print their
   final value directly.
   ================================================================== */

@media (prefers-reduced-motion: reduce){
  .tk-glow, .tk-engine__pulse, .tk-stage__dot::after, .tk-beacon i,
  .tk-spin, .tk-pulse, .tk-trace, .tk-send{ animation: none !important; }
  .tk-trace, .tk-send{ stroke-dashoffset: 0; }
  .tk-send{ stroke-dasharray: none; }
  .tk-words .w__i{ transform: none; transition: none; }
  .tk-rise, .tk-build{ opacity: 1; transform: none; transition: none; }
  .tk-ladder__bar{ transform: scaleY(1); transition: none; }
  .tk-quarter__bar{ transform: scaleX(1); transition: none; }
  .tk-panel:hover, .tk-go a:hover{ transform: none; }
}

/* ==================================================================
   16. Texture, transparency, and the cut-out objects

   Flat white is not a background, it is the absence of one. Three
   layers give the page a surface without adding a single image:

     .tk-tex     fine grain, drawn by an SVG turbulence filter
     .tk-aurora  soft blurred colour, well under the grain
     .tk-dots    a dot field instead of ruled lines

   They stack in that order and all three are optional per section.
   Everything here is CSS, so it is resolution-independent, weighs
   nothing, and cannot go out of sync with the palette.
   ================================================================== */

/* ---- grain -------------------------------------------------------
   feTurbulence rendered once by the browser and tiled. Kept very low:
   the job is to stop large white areas looking like a blank canvas,
   not to be visible as texture. `overlay` lets it darken and lighten,
   which reads as paper rather than as dirt sitting on top. */
.tk-tex{
  position: absolute; inset: 0;
  pointer-events: none; z-index: 1;
  opacity: .5;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

/* ---- aurora ------------------------------------------------------
   Two or three of these per section, placed off-centre and drifting
   on long timers. Blurred hard so no edge is ever findable — a
   gradient with a visible boundary reads as a mistake on white. */
.tk-aurora{
  position: absolute;
  width: var(--w, 40rem); height: var(--h, 30rem);
  left: var(--x, 50%); top: var(--y, 40%);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--c, rgba(24,120,242,.16));
  filter: blur(90px);
  opacity: var(--o, 1);
  pointer-events: none; z-index: 0;
  animation: tk-drift var(--dur, 26s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}
.tk-aurora--coral{ --c: rgba(226,96,74,.13); }
.tk-aurora--deep{  --c: rgba(11,94,196,.14); }
@keyframes tk-drift{
  0%,100%{ transform: translate(-50%,-50%) scale(1)    translate(0,0); }
  33%    { transform: translate(-50%,-50%) scale(1.15) translate(4%, -3%); }
  66%    { transform: translate(-50%,-50%) scale(.94)  translate(-3%, 4%); }
}

/* ---- dot field ---------------------------------------------------
   Softer than ruled lines and it does not fight the axonometric
   objects the way a grid does — two sets of straight lines behind a
   drawing in perspective read as a mistake. */
.tk-dots{
  position: absolute; inset: 0;
  --d: 26px;
  background-image: radial-gradient(circle at 1px 1px, rgba(24,120,242,.16) 1px, transparent 0);
  background-size: var(--d) var(--d);
  -webkit-mask-image: radial-gradient(110% 80% at 50% 10%, #000 0%, transparent 72%);
          mask-image: radial-gradient(110% 80% at 50% 10%, #000 0%, transparent 72%);
  pointer-events: none; z-index: 0;
}
.tk-dots--wide{ --d: 40px; }

/* ==================================================================
   17. Glass

   The transparency the page is asked for, done as a real material:
   a translucent white sheet with the ground blurred behind it. It
   only reads as glass when there is something underneath worth
   blurring, so a glass panel always wants an aurora behind it.
   ================================================================== */

.tk-glass{
  position: relative;
  background: rgba(255,255,255,.62);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
  border: 1px solid rgba(255,255,255,.9);
  border-radius: 20px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.9) inset,
    0 1px 2px rgba(12,46,92,.04),
    0 18px 40px -22px rgba(12,46,92,.28);
}
/* Safari and Firefox with backdrop-filter disabled fall back to a
   flat translucent white, which is fine — but on a plain white
   section that is invisible, so the border does the work instead. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))){
  .tk-glass{ background: rgba(255,255,255,.94); border-color: var(--tk-line); }
}

/* ==================================================================
   18. Objects — the transparent cut-outs

   Exploded axonometric renders on real alpha, dropped onto the page
   with no frame, exactly like the city in the opening band. The point
   of the cut-out is that the artwork sits ON the page rather than in
   a window cut into it; the moment you put a box round one it stops
   being part of the composition and becomes an illustration.

   The shadow is drawn in CSS rather than baked into the PNG, so it
   can be tuned per placement and never fights the ground it lands on.
   ================================================================== */

.tk-object{
  position: relative;
  display: block;
  width: 100%;
  filter: drop-shadow(0 26px 34px rgba(12,46,92,.16))
          drop-shadow(0 6px 12px rgba(12,46,92,.09));
  animation: tk-hover var(--dur, 9s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}
.tk-object img{ display: block; width: 100%; height: auto; }
@keyframes tk-hover{
  0%,100%{ transform: translateY(0)      rotate(0deg); }
  50%    { transform: translateY(-2.2%)  rotate(-.5deg); }
}

/* the pool of light an object stands in — sold separately from the
   drop-shadow because it belongs to the ground, not the object */
.tk-object__pool{
  position: absolute;
  left: 50%; bottom: 2%;
  width: 72%; height: 14%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(24,120,242,.16), transparent 68%);
  filter: blur(18px);
  z-index: -1;
}

/* ---- the split: copy on one side, object on the other ------------
   Mirrored between the problem and the solution so the two objects
   land on opposite sides and the eye is pushed across the page to
   compare them, which is the whole argument those two sections make. */
.tk-split{
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  gap: clamp(2rem, 6vw, 5.5rem);
  align-items: center;
  margin-top: clamp(2rem, 5vw, 3.5rem);
}
.tk-split--flip .tk-split__copy{ order: 2; }
.tk-split--flip .tk-split__fig{  order: 1; }
.tk-split__fig{ position: relative; }

/* Inside a split the column already sets the measure, so the global
   `max-width` on the headings has to come off — a 17ch cap inside a
   half-width column stacks a six-word headline into five lines. */
.tk-split__copy .tk-h,
.tk-split__copy .tk-lead{ max-width: none; }
/* and a step down in size: the full display scale is set for a headline
   running the whole measure, and in half of one it stacks five lines deep
   and overpowers the object it is supposed to be paired with */
.tk-split__copy .tk-h{ font-size: clamp(1.9rem, 3.5vw, 3.05rem); }
.tk-split__copy .tk-p{ max-width: 44ch; }
.tk-split__copy .tk-lead{ margin-top: clamp(.7rem, 1.6vw, 1rem); }
.tk-split__cap{
  margin: clamp(1rem, 2.4vw, 1.5rem) 0 0;
  font-family: var(--mono); font-size: .65rem; letter-spacing: .15em;
  text-transform: uppercase; color: var(--tk-ink-3);
  text-align: center; text-wrap: balance;
}
.tk-split__cap b{ color: var(--tk-beam); font-weight: 400; }

/* Phones: one column, and the object leads. It is the thing that
   explains the section fastest, and on a small screen a reader who
   scrolls past a wall of type never reaches it. */
@media (max-width: 900px){
  .tk-split{ grid-template-columns: 1fr; gap: clamp(1.8rem, 6vw, 2.6rem); }
  .tk-split__copy{ order: 2 !important; }
  .tk-split__fig{  order: 1 !important; }
  /* full width is too much presence for a phone — the type has to
     stay the loudest thing on the screen */
  .tk-object{ width: min(78%, 22rem); margin-inline: auto; }
}

/* ==================================================================
   19. Reduced motion, part two

   The block in section 15 cannot cover the components added after it,
   so this repeats the contract for them. Anything animated that gets
   added below this line needs adding here too — the check that caught
   the omission is worth keeping: with reduce on, no element on the
   page should report a running `animation-name`.
   ================================================================== */

@media (prefers-reduced-motion: reduce){
  .tk-aurora, .tk-object{ animation: none !important; }
  /* the float is decorative, but the drop-shadow is what separates a
     cut-out from the ground, so that stays */
  .tk-object{ transform: none; }
}

/* ==================================================================
   20. The projector band

   Section 01's visual: a projector throwing client products, each one
   dissolving into the next.

   It is NOT a video file, and that is deliberate. Built as layers —
   a cut-out of the rig, a beam drawn in CSS, and four cut-outs of the
   projected products cross-fading at the end of it — it gets three
   things a five-second clip cannot: a loop with no seam to hide,
   artwork that stays sharp at any pixel density, and a product set
   that can be reordered or added to without regenerating anything. It
   is also a fraction of the weight.

   EVERY position below is a percentage of the band's own box, and the
   box has a fixed aspect-ratio, so the lens, the beam and the thing
   the beam lands on stay locked together at every viewport instead of
   drifting apart. If the rig render is ever replaced, --lens-x/y and
   the beam polygon are what you re-measure.
   ================================================================== */

.tk-proj{
  position: relative;
  margin-top: clamp(2.6rem, 6vw, 4.5rem);
  /* the rig render's own ratio, so `contain` fills it exactly */
  aspect-ratio: 3168 / 1344;
  --lens-x:  39%;
  --lens-y:  40%;
  --stage-x: 71%;
  --stage-y: 34%;
  --stage-w: 21%;
  --cycle:   13s;
}

.tk-proj__rig{ position: absolute; inset: 0; }
.tk-proj__rig img{
  width: 100%; height: 100%; object-fit: contain;
  /* Fade the far end of the beam out. Two jobs: it hides where the
     background remover chewed the beam's soft lower edge into a smear
     (a translucent gradient is the worst case for matting), and it
     lets the beam dissolve instead of stopping at the frame edge. */
  -webkit-mask-image: linear-gradient(90deg, #000 58%, rgba(0,0,0,.55) 82%, transparent 99%);
          mask-image: linear-gradient(90deg, #000 58%, rgba(0,0,0,.55) 82%, transparent 99%);
}

/* ---- the beam ----------------------------------------------------
   A clip-path trapezoid running from the lens to the right edge,
   filled with a gradient that fades as it travels. Drawn rather than
   rendered so it can pulse in time with the product swap. */
.tk-proj__beam{
  position: absolute; inset: 0;
  pointer-events: none;
  clip-path: polygon(var(--lens-x) 27%, 100% 1%, 100% 61%, var(--lens-x) 53%);
  /* the rig render carries the beam itself; this only lifts it and gives
     it a pulse, so it stays weak enough never to read as a second beam */
  background: linear-gradient(100deg,
    rgba(24,120,242,.16) 0%,
    rgba(24,120,242,.10) 40%,
    rgba(24,120,242,.04) 72%,
    rgba(24,120,242,0)   100%);
  animation: tk-proj-beam var(--cycle) ease-in-out infinite;
}
@keyframes tk-proj-beam{
  0%,100%{ opacity: .88; }
  50%    { opacity: 1; }
}

/* dust drifting through the beam, clipped to the same trapezoid. One
   element with a travelling dot field, which is far cheaper than
   particles and reads identically at this size. */
/* Two elements, not one, and the reason matters: the clip lives on the
   outer box and the MOVEMENT lives on an oversized inner layer.

   The first version animated `background-position` on a single clipped
   element. That repaints the whole area every frame and took the page
   from 61fps to 31. A transform on an inner layer is composited
   instead — same drifting dust, no repaint, back to full frame rate. */
.tk-proj__dust{
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: hidden;
  clip-path: polygon(var(--lens-x) 27%, 100% 1%, 100% 61%, var(--lens-x) 53%);
  opacity: .55;
}
.tk-proj__dust i{
  position: absolute; inset: -35%;
  background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,.85) 1.4px, transparent 0);
  background-size: 46px 46px;
  animation: tk-proj-dust 26s linear infinite;
  will-change: transform;
}
@keyframes tk-proj-dust{ to{ transform: translate3d(320px, -90px, 0); } }

/* ---- the stage: where the product lands ------------------------- */
.tk-proj__stage{
  position: absolute;
  left: var(--stage-x); top: var(--stage-y);
  width: var(--stage-w); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.tk-proj__item{
  position: absolute; inset: 0;
  opacity: 0;
  /* Positive delays, one slot apart. At t=0 only item 0 has started,
     which is the correct opening state, and every cycle after is
     identical — so this needs no JS and no fill-mode juggling. */
  animation: tk-proj-cycle var(--cycle) ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * (var(--cycle) / 4));
}
.tk-proj__item img{
  width: 100%; height: 100%;
  object-fit: contain;
  /* The products carry real alpha, cut from each render's own sampled
     ground so the soft outer halo survives as partial transparency
     rather than ending at a hard edge — that halo is most of what
     sells them as projected light.

     `mix-blend-mode: multiply` was the obvious route and does not work
     here: this element is animated on opacity and transform, so it
     forms its own stacking context and has no page backdrop left to
     blend against. It rendered as a white box. */
}
@keyframes tk-proj-cycle{
  0%   { opacity: 0; transform: scale(.92) translateY(1.5%); }
  5%   { opacity: 1; transform: scale(1)   translateY(0); }
  21%  { opacity: 1; transform: scale(1)   translateY(0); }
  26%  { opacity: 0; transform: scale(1.07) translateY(-1.5%); }
  100% { opacity: 0; transform: scale(.92) translateY(1.5%); }
}

/* the beam brightening as each new product forms — one quarter-cycle
   pulse, so it reads as the machine doing the work */
.tk-proj__flash{
  position: absolute;
  left: var(--stage-x); top: var(--stage-y);
  width: calc(var(--stage-w) * 2.6); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(24,120,242,.26), rgba(24,120,242,0) 70%);
  pointer-events: none;
  animation: tk-proj-flash calc(var(--cycle) / 4) ease-in-out infinite;
}
@keyframes tk-proj-flash{
  0%,100%{ opacity: .3; transform: translate(-50%,-50%) scale(.9); }
  12%    { opacity: 1;  transform: translate(-50%,-50%) scale(1.08); }
  70%    { opacity: .4; transform: translate(-50%,-50%) scale(1); }
}

.tk-proj__cap{
  margin: clamp(1rem, 2.4vw, 1.6rem) 0 0;
  font-family: var(--mono); font-size: .65rem; letter-spacing: .15em;
  text-transform: uppercase; color: var(--tk-ink-3);
  text-align: center; text-wrap: balance;
}
.tk-proj__cap b{ color: var(--tk-beam); font-weight: 400; }

/* ---- phones ------------------------------------------------------
   A 2.36:1 band inside the text column is 148px tall on a 390px
   screen, which throws the composition away. So the band breaks OUT
   of the column to the full viewport width, and the rig is given more
   of it — the machine and the figures are the part that has to stay
   legible, and the beam can afford to be shorter. */
@media (max-width: 760px){
  .tk-proj{
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    /* The phone gets its own crop of the render, not a shrunk copy of
       the desktop frame: the wide version carries a lot of empty sky
       and empty floor, and trimming both lifts the composition about a
       fifth bigger at the same band width — the difference between the
       mannequins reading as figures and reading as specks.
       The crop moved the origin, so the lens and stage are re-measured
       into the new frame rather than inherited. */
    aspect-ratio: 2620 / 1274;
    --lens-x:  47.2%;
    --stage-x: 85.5%;
    --stage-y: 30.4%;
    --stage-w: 24%;
  }
  /* the beam is shorter in this crop, so it needs less fade */
  .tk-proj__rig img{
    -webkit-mask-image: linear-gradient(90deg, #000 68%, rgba(0,0,0,.6) 88%, transparent 100%);
            mask-image: linear-gradient(90deg, #000 68%, rgba(0,0,0,.6) 88%, transparent 100%);
  }
  .tk-proj__beam,
  .tk-proj__dust{
    clip-path: polygon(var(--lens-x) 24%, 100% 0%, 100% 58%, var(--lens-x) 52%);
  }
  .tk-proj__cap{ padding-inline: 1.4rem; }
}

/* ==================================================================
   21. Reduced motion, part three
   ================================================================== */

@media (prefers-reduced-motion: reduce){
  .tk-proj__beam, .tk-proj__dust, .tk-proj__flash{ animation: none !important; }
  .tk-proj__flash{ opacity: .4; }
  /* The products still cycle — the section's whole point is that the
     machine keeps producing, and freezing it on one would change what
     the page says. The movement comes off instead, so it reads as a
     slideshow rather than as motion. */
  @keyframes tk-proj-cycle{
    0%   { opacity: 0; transform: none; }
    6%   { opacity: 1; transform: none; }
    21%  { opacity: 1; transform: none; }
    27%  { opacity: 0; transform: none; }
    100% { opacity: 0; transform: none; }
  }
}

/* ==================================================================
   22. The statement — section 01

   The master's intro paragraph set AS the display element rather than
   chopped into a headline plus three bullets. Same words, one
   confident statement, with the three capabilities picked out inline
   so the page is still skimmable in two seconds.

   The three definitions drop to a quiet spec row underneath, which is
   where detail belongs once the statement has done the work.
   ================================================================== */

.tk-say{
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.45rem, 2.9vw, 2.45rem);
  line-height: 1.34; letter-spacing: -.028em;
  color: var(--tk-ink);
  margin: 0; max-width: 25ch;
  text-wrap: pretty;
}
/* cobalt, not coral — the accent stays on things that get clicked */
.tk-say em{ font-style: normal; color: var(--tk-beam); }

.tk-say__rule{
  height: 1px; background: var(--tk-line);
  margin: clamp(1.9rem, 4vw, 2.9rem) 0 clamp(1.3rem, 2.8vw, 1.9rem);
  max-width: 54rem;
}

.tk-specs{
  margin: 0; max-width: 54rem;
  display: grid;
  /* THREE, or ONE. Never auto-fit: at 600-900px it fitted exactly two
     columns and left "relentless execution" stranded alone on its own
     row, which reads as an afterthought rather than the third of three. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.2rem, 3vw, 2.4rem);
}
.tk-specs dt{
  font-family: var(--mono); font-size: .64rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--tk-beam); margin-bottom: .5rem;
}
.tk-specs dd{ margin: 0; font-size: .95rem; line-height: 1.55; color: var(--tk-ink-2); }
@media (max-width: 620px){ .tk-specs{ grid-template-columns: 1fr; } }

/* ==================================================================
   23. Duo — copy beside a scene

   For the sections whose copy is NARROW (the statement, the problem,
   the solution) the right half of the page is simply empty. Those
   sections become a real two-column layout so the illustration has a
   proper column to live in, rather than being pushed out into the page
   margin and cropped.

   The full-width sections — the five stages, the ledger, the measures
   strip, the link rows — cannot do this: their components already use
   the whole column. Those keep their margin scenes. Applying the
   margin rule to every section was the mistake; it is a constraint
   from one kind of section, not from all of them.
   ================================================================== */

/* ==================================================================
   THE ROUTE — sections 01 to 07 as one continuous journey.

   The opening is an aerial city. Everything below it stays inside that
   same city and keeps travelling through it, so the page reads as one
   place rather than a stack of unrelated pictures.

   The previous attempt failed on exactly that point: it scattered
   cut-out props around each section and hoped proximity would read as
   connection. It did not — it read as random objects. The fix is that
   the CONNECTION IS DRAWN IN CODE, not generated: a route line runs the
   whole length of the page, and every scene is anchored to it and bleeds
   to the page edge. Nothing floats in the margin unattached.
   ================================================================== */

/* ---- the route ---------------------------------------------------
   One line, the full height of the page, sitting in the left margin
   with the section numbers. Coded rather than drawn, so it is exact at
   every width and can never fall out of alignment with the art.
   ------------------------------------------------------------------ */
.ab-route{
  position: absolute; top: 0; bottom: 0;
  left: calc(50% - 560px + 1.25rem);
  width: 2px; z-index: 0; pointer-events: none;
  background: repeating-linear-gradient(180deg,
    rgba(47,111,208,.55) 0 9px, rgba(47,111,208,0) 9px 19px);
}
.ab-route i{
  position: absolute; left: 50%; width: 7px; height: 7px;
  margin-left: -3.5px; border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 0 4px rgba(226,96,74,.14);
  animation: ab-travel 14s linear infinite;
  animation-delay: var(--delay, 0s);
}
@keyframes ab-travel{
  0%   { top: -2%;  opacity: 0; }
  6%   { opacity: 1; }
  94%  { opacity: 1; }
  100% { top: 102%; opacity: 0; }
}

/* ---- two-column sections ------------------------------------------ */
.ab-duo{
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
  gap: clamp(1.8rem, 5vw, 4rem);
  align-items: center;
}
.ab-duo--flip .ab-duo__copy{ order: 2; }
.ab-duo--flip .ab-duo__art{  order: 1; }
.ab-duo__copy > * + *{ margin-top: clamp(.9rem, 2vw, 1.3rem); }
.ab-duo__copy .tk-p,
.ab-duo__copy .tk-say,
.ab-duo__copy .tk-lead{ max-width: none; }
/* .tk-h is sized for a FULL-WIDTH heading — 66px at 1440. Dropped into a
   half column it has about 560px to work with, which broke "Most businesses
   don't have a growth problem." across five lines. The measure was never the
   problem; the type size was. */
.ab-duo__copy .tk-h{
  font-size: clamp(1.7rem, 3vw, 2.6rem);
  max-width: 20ch;
}

/* ---- the scenes ---------------------------------------------------
   Each one runs off the side of the page. A scene that stops short of
   the edge leaves a strip of white beside it and reads as a picture
   dropped onto the page; one that runs off reads as a place the page
   is standing in.
   ------------------------------------------------------------------ */
.ab-art{ position: relative; display: block; }
.ab-art img{
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 22px 34px rgba(40,70,110,.10));
  animation: ab-drift var(--dur, 13s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
@keyframes ab-drift{
  0%,100%{ transform: translateY(0); }
  50%    { transform: translateY(-.9%); }
}
@media (min-width: 901px){
  .ab-art--right{ margin-right: calc(50% - 50vw); }
  .ab-art--left { margin-left:  calc(50% - 50vw); }
}
/* A PORTRAIT scene cannot bleed. Width is what bleeding adds, and on a tall
   image every extra pixel of width costs about 1.35 of height — the tower
   came out 700px tall beside a two-line heading and swamped the section. */
.ab-art--tall{ width: min(100%, 21rem); margin-inline: auto; }

/* a full-width scene, for the sections whose components already use the
   whole column and have no half to give away */
.ab-band{
  position: relative;
  margin-inline: calc(50% - 50vw);
  margin-top: clamp(1.5rem, 4vw, 3rem);
}
.ab-band img{
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 18px 26px rgba(40,70,110,.09));
}
/* A band that is not the section's main event stays contained. Full-bleed
   gives an image the weight of a hero; the gateways are a footnote to four
   links, not the point of the section. */
.ab-band--inset{
  width: min(100%, 54rem);
  margin-inline: auto;
}

/* The horizon skyline is gone. It was the page's floor when the closing
   section was type on white; with the park lawn there it was a second
   landscape showing through underneath the first. */
/* The mid-page horizons are gone. Held at 11% opacity they were meant to
   read as a distant floor, but landing behind a scene they read instead as
   a second image ghosted behind the first — a defect, not atmosphere. */
.ab-horizon img{ display: block; width: 100%; height: auto; }

/* ---- phones -------------------------------------------------------
   OVERLAPPED, not stacked.

   Turning two columns into two rows gives a phone the rhythm of a
   slideshow: picture, wall of text, picture, wall of text. Every
   section looks like the last one and nothing feels composed.

   The words come first and the scene sits under them, full width and
   fully inside the screen. An earlier version had the artwork rise into
   the type and run off one edge; it read well in the abstract, but in
   practice the tall part of a scene — a crane jib, a spire — landed on
   the last line of the paragraph, and the wash that kept the type
   readable left a hard edge across the sky. Clean separation, sized to
   the screen, reads as deliberate. Overlapping did not.
   ------------------------------------------------------------------ */
@media (max-width: 900px){
  .ab-duo{ display: block; position: relative; }

  .ab-duo__copy{ position: relative; z-index: 2; }
  .ab-duo__copy .tk-h{ max-width: 18ch; }
  /* NO SCRIM. It was opaque at its BOTTOM edge and then simply stopped,
     so it whited out the top of the artwork and left a hard horizontal
     line straight across the clouds — the "background cut off" that was
     visible on this section. With the artwork no longer rising into the
     type there is nothing to hide, and nothing to hide it with. */

  .ab-duo__art{
    position: relative; z-index: 0;
    /* SITS BELOW THE TYPE, and inside the screen.

       This was 116% wide and pulled up 2rem so it rose into the copy.
       On the workshop scene that put the crane's jib straight through
       "behind lasting growth", and at 116% the left-hand buildings were
       cropped off the edge of the phone. Both read as mistakes rather
       than as a layout. */
    margin-top: clamp(1.5rem, 5vw, 2.25rem);
    width: 100%;
  }
  .ab-art{ width: 100%; margin-inline: 0; }

  .ab-duo__art, .ab-duo--flip .ab-duo__art{ margin-left: 0; }

  /* ONE section reads better beside its heading than under it: a single
     tall tower next to two short lines. Stacked, it was a 400px-high
     building answering a two-line question. */
  .ab-duo--aside{
    display: grid;
    grid-template-columns: minmax(0, 1fr) 30%;
    gap: clamp(.9rem, 4vw, 1.6rem);
    align-items: center;
  }
  .ab-duo--aside .ab-duo__art{ margin-top: 0; }
  .ab-duo--aside .ab-art--tall{ width: 100%; }

  .ab-route{ display: none; }

  /* the full-width bands overlap what follows them the same way */
  .ab-band{ margin-inline: calc(50% - 50vw); margin-bottom: -7%; }
  .ab-band--inset{ width: 116%; margin-inline: -8%; margin-bottom: -5%; }
  .ab-band + *{ position: relative; z-index: 2; }
}

@media (prefers-reduced-motion: reduce){
  .ab-art img{ animation: none; }
  .ab-route i{ animation: none; opacity: 0; }
}

/* ==================================================================
   THE CLOSING SCENE — a park lawn.

   The opening image's language (its line, its palette, its small round
   characters) applied to a different setting, arranged unevenly around
   the invitation rather than drawn as a border.

   It is a COVER image anchored to the BOTTOM. The lawn lives along the
   foot of the drawing, so whatever the section is too short to show comes
   off the top, where there is only empty white. Anchoring it the other
   way would slice the lawn off and leave the words standing on nothing.
   ================================================================== */
main > section.tk-close{ position: relative; overflow: hidden; }

.ab-lawn{ position: absolute; inset: 0; z-index: 0; pointer-events: none; }
/* Full width, natural height, standing on the bottom edge.

   NOT object-fit: cover. Cover crops whichever axis does not fit, and on a
   narrow phone that axis was the WIDTH — it was taking 15% off the sides,
   straight through the tree. Sized by width instead, the drawing is always
   whole left to right, and a section too short to hold it simply clips the
   top, which is empty sky. */
.ab-lawn img{
  position: absolute; bottom: 0; left: 50%;
  transform: translateX(-50%);
  display: block; width: 100%; height: auto;
  /* Capped, and centred. Left to span the full viewport the drawing grew
     with it — at 2560 it wanted to be 1463px tall, so a section half that
     height clipped 48% of it and took the bench group with it. The scene
     surrounds a reading column of fixed width; it does not need to keep
     pace with the monitor. */
  max-width: 1700px;
}

main > section.tk-close .tk__in{
  position: relative; z-index: 2;
  /* width:100% is load-bearing. Making the section a flex column turned
     .wrap into a flex item, and .wrap's own `margin-inline: auto` cancels
     stretch — so it shrink-wrapped to its content (610px of a 1440px page)
     and centred itself, putting "07 / START" 255px right of where 01-06
     begin. Given a width, the auto margins centre the COLUMN again rather
     than the text inside it. */
  width: 100%;
}

/* The SECTION is proportioned to the ARTWORK, not the other way round.

   Left to padding alone the section came out at 2.2:1 against a 1.75:1
   drawing, so `cover` was cropping 22-36% of it — and on a phone it was
   cropping 30% off the SIDES, straight through the tree. Giving the
   section the artwork's own ratio leaves cover with almost nothing to
   take, and what it does take comes off the top, which is empty sky. */
main > section.tk-close{
  min-height: min(57vw, 60rem);          /* 100 / 1.75, the landscape cut */
  padding-top: clamp(2.5rem, 6vh, 4rem);
  padding-bottom: clamp(7rem, 18vh, 12rem);
  /* flex-START, not center. Centring the copy inside a 820px section
     pushed it down into the middle and opened a 340px hole between the
     last link of the section above and this one's label. The copy belongs
     at the top of the clearing; the lawn already occupies the bottom. */
  display: flex; flex-direction: column; justify-content: flex-start;
}
/* #explore sets its own padding because it is a .tk, not a .tk--tall, and
   its inherited values put it out of step with the rest: measured from the
   rendered ink, why→explore ran 249px against a 193px rhythm, and
   explore→start only 124px. These two numbers put both back on it. */
/* The "Explore our services" button sits in #solution's copy column, and
   the duo centres its two columns — so past a point the artwork, not the
   text, is the lowest ink, and the gap after it opened ~16px wider than
   the rhythm between 1280 and 1512. Above that the copy is taller again
   and it corrects itself, so the adjustment is bounded to that band. */
@media (min-width: 901px) and (max-width: 1650px){
  main > section#solution{ padding-bottom: calc(clamp(4.5rem, 10vh, 7rem) - 1rem); }
}

/* #why now ends on a button rather than the ledger's last line, so its
   last ink sits about 32px lower than it did and the gap to #explore
   closed to 161px against a 193px rhythm. The section gives that back. */
main > section#why{ padding-bottom: calc(clamp(4.5rem, 10vh, 7rem) + 2rem); }

main > section#explore{
  /* Expressed as an OFFSET from the tall sections' own padding, not as
     fixed rems. Its neighbours scale with viewport height, so fixed values
     only stayed in step at the one height they were tuned at — at 1920 the
     rhythm had already drifted from 193px to 204-229px. The two offsets
     absorb the fact that #why ends on a rule flush with its container
     while the others end on text with slack beneath it. */
  padding-top:    calc(clamp(4.5rem, 10vh, 7rem) - 1.75rem);
  padding-bottom: calc(clamp(4.5rem, 10vh, 7rem) + 1rem);
}

/* The narrow-desktop band, 901-1100px.

   Here the landscape cut is served but the centred copy is proportionally
   wide, so the lawn's tree reaches into it — at 901 the "Let's grow
   together" button clipped the canopy. Wider than this the copy occupies a
   smaller share of the page and clears the lawn on its own; narrower, the
   portrait cut takes over. Only this band needs the extra room. */
@media (min-width: 901px) and (max-width: 1100px){
  main > section.tk-close{ min-height: 92vw; }
}

@media (max-width: 900px){
  /* MATCH THE DESKTOP PROPORTION, not the desktop pixels.

     On a wide screen the drawing fills 87% of the section and comes up
     level with the copy. At 100% width on a phone the same drawing was
     only 33% of it, sitting in a band at the very bottom — which is why
     the section read as loose even though the dead space between copy and
     lawn was already down to 7px. The artwork is not too low; it is too
     small.

     Two moves, because enlarging alone would just make the section taller:
     the artwork is scaled past the screen edges (as it already is on
     desktop, where it spans the full 1440), and the closing type is
     tightened to give back the height that costs. */
  .ab-lawn img{ width: 134%; }

  main > section.tk-close .tk-h{ font-size: 2rem; }
  main > section.tk-close .tk-p{ margin-top: .7rem; font-size: .97rem; }
  main > section.tk-close .tk-close__cta{ margin-top: 1.25rem; gap: .6rem; }
  main > section.tk-close .tk-label{ margin-bottom: .8rem; }

  main > section.tk-close{
    /* 110vw pulls the lawn up until the second button TUCKS BEHIND the
       tree — deliberately, so the closing scene and the invitation share
       space instead of sitting in separate bands. Measured against the
       artwork's alpha: at 150vw nothing touched, at 116vw the button
       first meets the canopy, and the heading and paragraph stay
       completely clear at every value down to 108vw. */
    min-height: min(110vw, 40rem);
    padding-top: clamp(2rem, 5vh, 3rem);
    padding-bottom: clamp(3.5rem, 9vh, 5rem);
  }
  main > section#explore{
    padding-top:    calc(clamp(4.5rem, 10vh, 7rem) - 1.55rem);
    padding-bottom: calc(clamp(4.5rem, 10vh, 7rem) + 1.6rem);
  }
}

/* ------------------------------------------------------------------
   Inline calls to action, for the two places a section ends on a point
   the reader can act on. Deliberately only two: one after the solution,
   where the copy has just listed the services, and one after the five
   things we can be held to. The problem section does not get one — a
   button in the middle of describing someone's pain reads as a pitch —
   and Go deeper does not, because its four rows are already links.
   ------------------------------------------------------------------ */
.tk-more{ margin: clamp(1.4rem, 3vw, 2rem) 0 0; }
.tk-more--mid{ margin-top: clamp(2rem, 4vw, 2.8rem); }
.tk-more .btn{ box-shadow: 0 10px 24px rgba(226,96,74,.26); }
.tk-more .tk-btn2 span{
  display: inline-block; margin-left: .15rem;
  transition: transform .35s cubic-bezier(.22,.7,.3,1);
}
.tk-more .tk-btn2:hover span{ transform: translateX(4px); }
@media (prefers-reduced-motion: reduce){ .tk-more .tk-btn2 span{ transition: none; } }
