/* About page — about/index.html. Design node 382:68036 in the current file
   (2026-09-09), the client's own frame at 1:1 (nav links 20, wordmark 152,
   so its numbers ARE design units — none of the 0.937 scaling the blog nodes
   needed). Read with `get_design_context` + `disableCodeConnect: true`,
   which got through where `get_metadata` failed; the sections below the
   frame's beliefs table (the statement, the team, the close) are not in the
   frame and are this build's own.

   Frame, measured:
     hero      1222 tall, -96 under the panel; gradient 206.7deg #349ff7 30.8%
               -> #bbd3fd 67.6%; headline 120 centred at top 234 (built at
               Display/XL 104 — the ladder's top; see .rdk-abt-hero__title);
               "Since" pill at top 177, 2u white/20% border, 8/16, radius 59,
               brand 17.4; scene image 1842.411 x 1473.928 at (-168.35, -47.58),
               cover, bottom-anchored; leaves 204.578 x 171.54 at -16.98deg
               and 43.21deg
     collage   white panel 1552 tall, radius 96; headline 46 on 667 at top
               511, body 18 on 633 at top 720; nine photos, each with its own
               box, radius and tilt (the markup carries them)
     beliefs   the frame's table is replaced — see the section below

   Everything is in --u; the phone block at the end is straight px. Prefix
   `.rdk-abt-` (the homepage's team wall already owns `.rdk-about`). */

/* ============================================================
   0. shared bits
   ============================================================ */
/* The services page's label: Redonk Avant Garde at 20 in green, sentence
   case. */
.rdk-abt__eyebrow {
  margin: 0 0 calc(24 * var(--u));
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(20 * var(--u));
  line-height: 1.2;
  letter-spacing: calc(-0.2 * var(--u));
  color: var(--rdk-green);
}

/* A RIG is the element that carries a CSS rotation (or mirror) and sits
   between the wrapper GSAP positions and the img an entrance animates. GSAP
   clears the standalone `rotate` / `scale` on any element whose transform it
   takes over, so the rotation has to live on an element GSAP never touches —
   the services page's arrangement, and the hero DONK's. */
.rdk-abt__rig {
  display: block;
  width: 100%;
  height: 100%;
  rotate: var(--rot, 0deg);
  scale: var(--sx, 1) var(--sy, 1);
}

/* The flocked services icons carry a fill adjustment in Figma that the
   exports do not — the services page measured `saturate(1.8)
   brightness(0.92)` against four of them, and the same objects are used
   here. The leaf and Texas are fitted separately below. */
.rdk-abt__rig--flocked {
  filter: saturate(1.8) brightness(0.92);
}

/* `<picture>` is inline by default and has no height of its own, so an
   img inside it cannot resolve `height: 100%` — it falls to `auto` and the
   image keeps its intrinsic aspect instead of filling the rig's box. The
   hero leaf serves a phone crop through one; make the wrapper the box. */
.rdk-abt__rig picture {
  display: block;
  width: 100%;
  height: 100%;
}
.rdk-abt__rig img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  will-change: transform;
}

/* ============================================================
   1. hero
   ============================================================ */
/* STICKY, like every other hero: it pins and the white panel slides up over
   it, shoulders revealing the sky. At least a screenful tall so the panel
   never shows in the landing view; the extra opens up as sky ABOVE the scene,
   which is bottom-anchored. */
.rdk-abt-hero {
  position: sticky;
  top: 0;
  z-index: 0;
  height: max(calc(1222 * var(--u)), 100svh);
  background: linear-gradient(206.7deg, #349ff7 30.8%, #bbd3fd 67.6%);
  overflow: clip;
  color: var(--rdk-white);
}

/* THE SCENE IS NODE `841:103802` ("image 128"), WHICH REPLACED IMAGE 40 ON
   2026-09-16 — a new picture AND a new box. It was a 1719.777 x 1262.135
   landscape parked at the hero's foot; it is now 1842.411 x 1473.928 at
   (-168.35, -47.58), i.e. it covers essentially the whole hero, and it has
   the Redonkuverse furniture in it. Its box bottom lands at 1426.348, which
   is 204.348 below the hero's designed 1222.
   Anchored to the BOTTOM so a taller viewport pushes it down with the panel
   rather than up into the headline — the same reason as before.
   THE SKY IS TRANSPARENT and `.rdk-abt-hero`'s gradient paints it, which is
   what lets the white panel's shoulders notch into real sky. The artwork's
   opaque ink starts 524.9 down the hero, well clear of the headline's
   ~234..430, so `z-index: 2` still only covers the type on scroll. */
.rdk-abt-hero__scene {
  position: absolute;
  /* Above the text (client, 2026-09-10): on scroll the scene rises and
     passes in front of the headline while the headline sinks. */
  z-index: 2;
  /* NODE 1038:95406 (2026-09-24, "hero-scene-people_v2", with DONK):
     1802.809 x 1452.263 at (-74.4, -98.12), so its bottom is 132.143 below
     the hero's 1222. The comment above describes the previous image. */
  left: calc(-74.4 * var(--u));
  /* THE HEADS STAY WHERE THE DESIGN PUTS THEM ON A WIDE WINDOW (client,
     2026-09-25). Past the width floor below (~1680 wide) the scene has to
     grow to fill the window, and bottom-anchored all of that growth went
     UP: at 1920 the people rose ~106 into the headline. This pushes the
     share of the growth that lies below the heads (1 - 0.3531, the head
     tops' height in the artwork, measured off its alpha) down past the
     hero's foot instead, where the grass is clipped. At the design width
     the extra is 0, so 1600 is untouched. 1.24137 is the asset's aspect. */
  --scene-w: max(calc(1802.809 * var(--u)), calc(100vw + 74.4 * var(--u) + 12px));
  bottom: calc(-132.143 * var(--u) - (var(--scene-w) / 1.24137 - 1452.263 * var(--u)) * 0.6469);
  /* THE FRAME'S 1842.411, OR THE WINDOW — WHICHEVER IS WIDER (client,
     2026-09-10: "needs to be full-width at all times... if the browser is
     too wide it cuts off on the right"). `--u` is capped at 1px, so past a
     1600 window the frame's width stops growing while the window does not,
     and the scene's right edge walked inland. The floor is the window plus
     the 168.35 it starts left of the panel, so no window shape can reveal
     the edge. The 12px is rounding slack: the floor is otherwise EXACT,
     and measured at 2560 it covered the right edge with 0 to spare, which
     one sub-pixel rounding the wrong way would turn into a sliver of bare
     gradient. Bottom-anchored, so the extra opens up sky rather than
     moving the hills. */
  width: var(--scene-w);
  pointer-events: none;
  will-change: transform;
}

/* NO FILL FILTER ANY MORE (2026-09-16). The client re-graded this image in
   Figma and exported it with the adjustment BAKED IN, so the old fitted
   `saturate(1.5) brightness(0.8)` — which approximated the previous grade
   off a raw export, and landed 9/255 from it — is both wrong and
   unnecessary. Measured: the delivered PNG matches Figma's own render at
   0.48/255 (resampling noise) where the unadjusted raw is 12.95 away.
   Do not reintroduce a filter here without re-fitting it; and prefer
   asking for a baked export, which is exact, costs no per-frame
   compositing on a full-bleed image, and survives the next re-grade. */
.rdk-abt-hero__scene-img {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  will-change: transform;
}

/* THE HERO'S TWO LEAVES ARE OUT (client, 2026-09-16) — markup, both
   breakpoints' rules and their entrance and ticker in js/about-page.js all
   went together, the work hero's own 2026-09-02 precedent. Node 453:50492
   still draws them (image 92 at 347/-53 rotated -16.98deg and image 93 at
   1419/200 at 43.21deg, both 204.578 x 171.54) and the phone frame
   585:4596 draws one; this is a deliberate deviation from both. The
   collage panel's `.rdk-abt-since__leaf` is a DIFFERENT object and stays,
   which is what still uses `leaf.webp`; `leaf-mobile.webp` is now
   unreferenced. */

.rdk-abt-hero__text {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(177 * var(--u));
  /* The headline's lines are chosen by measuring against THIS box (see
     js/about-page.js hero()), so the inset is what keeps the type off the
     window's edge once the headline stops scaling with `--u`. */
  padding: 0 32px;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  will-change: transform, opacity;
}

/* Node 382:68039: 2u white at 20%, 8/16, radius 59, brand 17.425 / 0.94. */
.rdk-abt-hero__since {
  display: inline-flex;
  align-items: center;
  margin: 0 0 calc(28 * var(--u));
  padding: calc(8 * var(--u)) calc(16 * var(--u));
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(17.425 * var(--u));
  line-height: 0.94;
  letter-spacing: calc(-0.35 * var(--u));
  border: calc(2 * var(--u)) solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
}

/* DISPLAY/XL, NOT THE FRAME'S 120. Node 382:68038 sets this at 120 / 0.94 /
   -4.8 (-4%), a size that exists nowhere else on the site — the ladder in
   tokens.css tops out at Display/XL 104, which is what the work and services
   heroes use. Built at 104 with the token's -5% so the page stays on the
   ladder; raising it to 120 is one line here if the client wants the frame's
   scale, and it fits (1259 wide at 120 against a 1600 frame). */
/* The narrow set's two extra breaks live in the markup and are switched
   off here; the mobile block turns them on. The headline's own designed
   break (node 453:50492, between the two sentences) is an unclassed <br>
   and is in both sets, so it is never toggled. */
.rdk-abt-hero__title-mbreak { display: none; }

/* THE HEADLINE DOES NOT SCALE WITH `--u` (client, 2026-09-10: "maybe not
   scale the headline proportionally? It starts looking really bad at
   narrower screens before the mobile layout takes effect"). A flat 104px
   from 768 up; when its two designed lines no longer fit the block, JS
   lays the four-line version instead — the SAME version the phone uses,
   so the tablet range reads as the design rather than as a shrunk
   desktop. `width: 100%` so the block's width is the
   measurement and the box is not shrink-to-fit. No `max-width` and no
   `text-wrap: balance`: the lines are explicit elements now. */
.rdk-abt-hero__title {
  width: 100%;
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: 104px;
  line-height: 0.94;
  letter-spacing: -5.2px;
}
.rdk-abt-hero__line { display: block; }

/* ============================================================
   2. the collage — "We've been here since 2002"
   ============================================================
   THE PANEL PINS AND THE PHOTOS BURST OUT (client, 2026-09-09, after
   lassie.ai/company): the section is a screen plus a stretch of scroll, the
   white panel is sticky for all of it, and one number — `--p` on the collage,
   scrubbed by js/about-page.js — drives every tile from "at the headline's
   centre, scale 0" to the frame's own resting place. The tiles derive their
   transforms in CSS from --p, so GSAP never touches a tile's transform and
   the hover (on the inner card) cannot be killed by it. --p defaults to 1:
   with no JS the collage is simply the frame.

   `--cu` is the collage's own unit. The frame's arrangement is 1600 wide and
   ~1300 tall around its centre, which does not fit a 900-tall window at --u,
   so it scales by the shorter of the two: at 1600 x 900 a tile is 0.65 of its
   frame size, and the outer tiles bleed off the panel's edges exactly as the
   frame has them bleeding off its own. */
/* NO PIN, AND NO SCROLL BUDGET (client, 2026-09-10: "there's a weird
   scroll interaction happening. When I get to this section and I scroll
   the page doesn't move until I scroll for a bit... I don't want to
   hijack or use the scroll like this any more"). The section used to be
   100svh + 130vh with the panel stuck to the top, and every one of those
   130vh was spent driving the burst. Now that the photos play themselves
   in, that budget bought nothing at all — it was a viewport and a third
   of scrolling with the page apparently frozen. The section is simply as
   tall as its panel and scrolls past like any other. */
.rdk-abt-since {
  position: relative;
  z-index: 1;
  margin-top: calc(-96 * var(--u));
}

/* `position: relative` IS LOAD-BEARING, AND NOT FOR PLACEMENT. It is what
   makes this panel the containing block for `.rdk-abt-since__collage`,
   which is `position: absolute` — and an absolutely positioned box is only
   clipped by ancestors that sit BETWEEN it and its containing block. Take
   the position off and `overflow: clip` here stops applying to the photos
   entirely: their containing block becomes `.rdk-abt-since` instead, so
   they paint straight over the hero above. That is exactly what happened
   when the sticky pin was removed on 2026-09-10 — the pin was doing this
   job as a side effect, and dropping it silently un-clipped the whole
   cloud (client: "the image here should not be showing outside of the
   white section"). Nothing about the pin's removal LOOKED like it touched
   clipping. */
.rdk-abt-since__panel {
  position: relative;
  /* THE HEIGHT IS A PLAIN NUMBER OF DESIGN UNITS, NOT A SHARE OF THE WINDOW
     (client, 2026-09-16: "I dont think we should have the height of that
     section defined by the viewport height. Can we just set a height?").
     There WAS a reason and it stopped being true: the panel used to PIN and
     be scrubbed, so 100svh was what made it fill the screen while pinned.
     The pin came out on 2026-09-10 and the height stayed behind — nothing
     has needed the section to be exactly one screen since.
     900 is chosen so the design width renders IDENTICALLY: at `--u` 1 the
     panel is 900px, which is what a 900-tall window gave before. What
     changes is everywhere else — the section now scales with WIDTH like the
     rest of the site, instead of growing on a tall monitor and shrinking on
     a short one. `--panel-h` is the same value named for the bottom clamp,
     which is written against the panel's own height. */
  --panel-u: 1295;
  height: var(--panel-h);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--rdk-white);
  border-radius: calc(96 * var(--u)) calc(96 * var(--u)) 0 0;
  overflow: clip;
  color: var(--rdk-dark);
  /* THE CLOUD'S SCALE IS INDEPENDENT OF THE PANEL'S HEIGHT (client,
     2026-09-16: "I'm trying to adjust the height and its scaling the
     photos"). These were `min(--u, --panel-h / …)` — the cloud FITTED to
     the panel — which is why the Section height slider resized the
     photographs. They are plain multiples of `--u` now: how tall the
     section is and how big the cloud is are two decisions, and `--tile-k`
     is the one that means size.
     0.652 and 0.5625 are 900/1380 and 900/1600, i.e. exactly what the 900
     panel was giving, so nothing moved when this changed. The old `min()`
     also capped the cloud on a short window; it no longer needs to, since
     the panel no longer shrinks with the window either and the bottom
     clamp still keeps every tile inside it. */
  --cu: calc(var(--u) * 0.652);
  /* THE CLOUD IS SPREAD SIDEWAYS PAST THE PANEL'S EDGES (client,
     2026-09-10: "the photos do not go far enough to the edges. They are
     behind the text and too close, making it too hard to read. The images
     should bleed off the edges"). SIZE stays on `--cu`, which is fitted to
     the window's HEIGHT — and that is the whole cause: on a 900-tall
     window `--cu` is 0.65, so the arrangement was drawn at two thirds and
     huddled around the headline. `--cux` puts the horizontal placement
     back on `--u`, so the arrangement is drawn at the frame's own full
     width and the outer photos bleed off the edges. The tiles keep their
     `--cu` size, so they bleed rather than grow.
     THE SPREAD IS CAPPED BY THE LEFTMOST PHOTO, not by taste: the frame's
     own arrangement already runs to its edges (centres 45..1469 of 1600),
     so a multiplier much over 1 carries the outer tiles clean off the
     panel — at 1.38 four of the nine were entirely invisible, at 1.08 the
     left photo was a 26px strip, and at 1.05 the client still read it as
     "traveling too far out... need to see most of the image". At 1 the
     left photo is ~30% cropped and 70% on the panel. NOTE a rotated
     tile's rect is wider than its box, so measure the rect and not
     `--w * --cu` when re-tuning. */
  --cux: var(--u);
  /* THE FOUR KNOBS THE COMPOSITION IS TUNED WITH (client, 2026-09-10: "if
     it's easier you can give me controls to fine-tune" — `?tune` opens
     js/about-page-tuner.js, which writes exactly these). `--spread-x`
     multiplies every x offset from the centre; UP and DOWN are separate
     because the client wanted the top photos higher without dropping the
     bottom ones into the panel's foot, where the megaphone Donk's head
     comes up. `--tile-k` scales the tiles about their own centres. */
  /* NINE PER-TILE NUDGES (client, 2026-09-16: "give me controls per image
     like we did with the thumbs"). Numbered in MARKUP order, which is the
     order they are drawn; 8 and 9 are the two flocked objects. Bound by
     `data-tile` and not by any class, the same reasoning as the slop
     thumbs: a class says what a tile IS, not which one it is. */
  --n1-x: -61; --n1-y: -238; --n1-k: 1.19; --n1-r: 0;   /* desk */
  --n2-x: -27; --n2-y: -59; --n2-k: 1.48; --n2-r: 0;   /* shop */
  --n3-x: 62; --n3-y: 0; --n3-k: 1.21; --n3-r: 0;   /* conference */
  --n4-x: 0; --n4-y: 0; --n4-k: 1.27; --n4-r: 0;   /* vr */
  --n5-x: 102; --n5-y: 1; --n5-k: 1.34; --n5-r: 0;   /* trex */
  --n6-x: 26; --n6-y: 170; --n6-k: 1.15; --n6-r: 0;   /* flamingo */
  --n7-x: 99; --n7-y: 38; --n7-k: 1.13; --n7-r: 0;   /* red sweater */
  --n8-x: -73; --n8-y: -109; --n8-k: 1.19; --n8-r: 0;   /* leaf */
  --n9-x: -114; --n9-y: -22; --n9-k: 1; --n9-r: 0;   /* Texas */
  --spread-x: 0.89;
  --spread-up: 1.38;
  --spread-down: 1.37;
  --tile-k: 1.3;
  /* The panel's own height, named so the bottom clamp below can be written
     as a LENGTH — the clamp feeds `translate` as well as `top`, and a `%`
     there would resolve against the tile's own box instead of the panel's. */
  --panel-h: calc(var(--panel-u) * var(--u));
  /* THESE FOUR ARE THE CLIENT'S OWN TUNING PASS (2026-09-10), pasted from
     the panel's Copy button. Reading them: the cloud is pulled IN a touch
     sideways (0.9), spread further both up and down, and the photos are
     38% bigger. The measured trade-off that set the previous defaults
     still holds and is why the top photo crops — share of that photo left
     on the panel at 1.4 / 1.5 / 1.6 / 1.8 of `--spread-up` was
     77 / 67 / 56 / 35%. The client wants that one cut ("the top photo
     should be cut off") and the bottom row whole, which the clamp below
     is what guarantees. */
  /* The cloud is spread a little less tall than it is scaled, so the lowest
     photos sit ~90 clear of the panel's foot — the megaphone Donk's head
     pokes up into that band (see .rdk-abt-beliefs). */
  --cuy: calc(var(--u) * 0.5625);
}

.rdk-abt-since__collage {
  --p: 1;
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* A tile: positioned by its CENTRE (--x/--y in the frame's 1600 x 1552, taken
   against the composition's centre at 800, 600), sized in --cu, tilted by
   --rot, and waiting out --d of the burst before it moves. Three derived
   numbers:
     --pt   this tile's own 0..1, --p with its delay removed
     --ex   how far past 1 --p has gone: the slow drift outward after landing
   The translate carries the tile from the centre to home over --pt, then
   outward by 15% of that distance over --ex; the scale comes up from 0; the
   rotation unwinds an extra 40deg on the way in. */
.rdk-abt-tile {
  --pt: clamp(0, (var(--p) - var(--d, 0)) / (1 - var(--d, 0)), 1);
  --ex: max(0, var(--p) - 1);
  /* POSITION and SIZE take separate units. On desktop both are --cu; the
     phone SPREADS the cloud (--cux / --cuy) further than it scales the tiles,
     because a 26px headline on a 375 screen is five lines tall and the
     photos have to clear it. --mx / --my let the phone move one tile
     outright (the leaf, which otherwise lands on the first line). */
  /* `--nx` / `--ny` ARE THE TUNER'S PER-TILE NUDGE, and they fold in HERE
     rather than into `translate` for two reasons: the drag already owns
     `--dx`/`--dy` there and would overwrite them, and folding them into the
     designed centre means a nudge goes through the spread knobs and the
     bottom clamp exactly as `--x`/`--y` do — so a tile moved down still
     cannot be pushed through the panel's foot. */
  --px: calc(var(--mx, var(--x)) + var(--nx, 0));
  --py: calc(var(--my, var(--y)) + var(--ny, 0));
/* The offset from the composition's centre, once, with the spread knobs
     folded in — everything else here is expressed against these two. The
     vertical splits at the centre line (`min(0, …)` is the part above it,
     `max(0, …)` the part below) so UP and DOWN can be spread by different
     amounts in one declaration. */
  /* `--nk` and `--nr` are the tuner's per-tile SIZE and ROTATION, beside
     `--nx`/`--ny`. `--nr` arrives as a bare number and is given its unit
     here, because the panel writes plain numbers. */
  --rotn: calc(var(--rot, 0deg) + var(--nr, 0) * 1deg);
  --tw: calc(var(--w) * var(--cu) * var(--tile-k, 1) * var(--nk, 1));
  --th: calc(var(--h) * var(--cu) * var(--tile-k, 1) * var(--nk, 1));
  /* THE CLAMP HAS TO USE THE ROTATED EXTENT, NOT THE BOX. Every tile is
     tilted, so what the panel's edge actually meets is
     `w * |sin| + h * |cos|` — for Texas at 16deg that is 460 against a box
     of 371, which is exactly how much a box-based clamp let through
     (measured: Texas reached 945 in a 900 panel). `abs()` is newer than
     the trig functions, so the absolute value is taken as
     `max(x, -1 * x)`. */
  /* THE CLAMP HAS TO LEAVE ROOM FOR THE DROP SHADOW TOO (client,
     2026-09-16: the flamingo's "is being cut off by the section below").
     `--rh` is the artwork's own rotated extent and stops the CARD landing
     past the panel's foot — but the card casts `0 18cu 48cu`, which reaches
     another 66 below it, and the panel is `overflow: clip`. Offset plus
     blur is the conservative reach; the objects have no shadow and set this
     to 0. */
  --shade: calc(66 * var(--cu));
  --sinr: max(sin(var(--rotn)), -1 * sin(var(--rotn)));
  --cosr: max(cos(var(--rotn)), -1 * cos(var(--rotn)));
  --rh: calc(var(--tw) * var(--sinr) + var(--th) * var(--cosr));
  --offx: calc((var(--px) - 800) * var(--cux, var(--cu)) * var(--spread-x, 1));
  --offy-raw: calc(
    min(0, var(--py) - 600) * var(--cuy, var(--cu)) * var(--spread-up, 1) +
    max(0, var(--py) - 600) * var(--cuy, var(--cu)) * var(--spread-down, 1));
  /* THE TOP MAY CROP, THE BOTTOM MAY NOT (client, 2026-09-10: "the top
     photo should be cut off and the bottom photos should not be"). The
     downward offset is capped so a tile's bottom edge lands inside the
     panel; upward offsets are negative, so `min()` passes them straight
     through and the top photo goes on cropping as asked. The 12 is a
     hair of air so a rotated tile's corner does not touch the edge —
     its rect is taller than its box. Raising `--spread-down` past the
     cap therefore stops moving the lowest photos, which is the intended
     behaviour and not the slider sticking. */
  /* THE CAP IS DIVIDED BY THE DRIFT, or the drift walks straight through
     it: after landing, `translate` adds `--offy * 0.15 * --ex` on top of
     the placement, which at the burst's final `--ex` of 0.35 is another
     5.25% down — measured, that put the lowest photo 4px past the panel
     with an otherwise exact clamp. Dividing here makes the clamp hold for
     every value `--ex` passes through. */
  --offy: min(var(--offy-raw),
    calc((var(--panel-h, 100svh) / 2 - var(--rh) / 2 - 12px - var(--shade, 0px))
         / (1 + 0.15 * var(--ex))));
  position: absolute;
  left: calc(50% + var(--offx));
  top: calc(50% + var(--offy));
  width: var(--tw);
  height: var(--th);
  margin: calc(var(--th) / -2) 0 0 calc(var(--tw) / -2);
  translate:
    calc(var(--offx) * -1 * (1 - var(--pt)) + var(--offx) * 0.15 * var(--ex) + var(--dx, 0px))
    calc(var(--offy) * -1 * (1 - var(--pt)) + var(--offy) * 0.15 * var(--ex) + var(--dy, 0px));
  rotate: calc(var(--rotn) + (1 - var(--pt)) * 40deg);
  scale: var(--pt);
  pointer-events: auto;
  will-change: translate, scale, rotate;
}

/* Bound by `data-tile`, OUTSIDE the rule above — the nine were first
   written inside it, which is invalid CSS: the parser salvages what it
   can and the nudges simply never arrived, with nothing in the console
   to say so. A nested selector needs CSS Nesting, which this project
   does not use (see the combined media queries in the About mobile
   block for the same decision). */
.rdk-abt-tile[data-tile="1"] { --nx: var(--n1-x); --ny: var(--n1-y); --nk: var(--n1-k); --nr: var(--n1-r); }
.rdk-abt-tile[data-tile="2"] { --nx: var(--n2-x); --ny: var(--n2-y); --nk: var(--n2-k); --nr: var(--n2-r); }
.rdk-abt-tile[data-tile="3"] { --nx: var(--n3-x); --ny: var(--n3-y); --nk: var(--n3-k); --nr: var(--n3-r); }
.rdk-abt-tile[data-tile="4"] { --nx: var(--n4-x); --ny: var(--n4-y); --nk: var(--n4-k); --nr: var(--n4-r); }
.rdk-abt-tile[data-tile="5"] { --nx: var(--n5-x); --ny: var(--n5-y); --nk: var(--n5-k); --nr: var(--n5-r); }
.rdk-abt-tile[data-tile="6"] { --nx: var(--n6-x); --ny: var(--n6-y); --nk: var(--n6-k); --nr: var(--n6-r); }
.rdk-abt-tile[data-tile="7"] { --nx: var(--n7-x); --ny: var(--n7-y); --nk: var(--n7-k); --nr: var(--n7-r); }
.rdk-abt-tile[data-tile="8"] { --nx: var(--n8-x); --ny: var(--n8-y); --nk: var(--n8-k); --nr: var(--n8-r); }
.rdk-abt-tile[data-tile="9"] { --nx: var(--n9-x); --ny: var(--n9-y); --nk: var(--n9-k); --nr: var(--n9-r); }

/* THE PHOTOS CAN BE PICKED UP AND THROWN (client, 2026-09-10: "can the user
   move the images around? Maybe throw them"). `--dx` / `--dy` are the drag's
   offset in px, a separate term in the tile's own translate — so it composes
   with the burst and with the card's hover instead of fighting them. It has
   to be a custom property and NOT a GSAP x/y: GSAP writes `translate: none`
   inline the moment it takes an element's transform over, which would delete
   the burst outright (the documented trap, and this is the element that
   would hit it). */
@media (hover: hover) and (pointer: fine) {
  .rdk-abt-tile { cursor: grab; }
  .rdk-abt-tile.is-held { cursor: grabbing; z-index: 4; }
  /* Held or thrown, the card drops its hover straighten — the reader is
     moving the photo, not pointing at it. */
  .rdk-abt-tile.is-held .rdk-abt-tile__card { transition: none; }
}

/* The white card with the photo cover-cropped inside — the frame's 20-ish
   radii, and a soft lift. The hover lives HERE, on the inner element, so it
   composes with the tile's own transform: it straightens (cancelling the
   tile's tilt) and grows a touch. */
.rdk-abt-tile__card {
  width: 100%;
  height: 100%;
  border-radius: calc(var(--r, 20) * var(--cu));
  overflow: clip;
  background: var(--rdk-off-white);
  box-shadow: 0 calc(18 * var(--cu)) calc(48 * var(--cu)) rgba(0, 20, 7, 0.14);
  transition: rotate 0.55s cubic-bezier(0.34, 1.3, 0.64, 1), scale 0.55s cubic-bezier(0.34, 1.3, 0.64, 1);
}

.rdk-abt-tile__card img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--ox, 50%) var(--oy, 50%);
}

@media (hover: hover) and (pointer: fine) {
  .rdk-abt-tile:not(.rdk-abt-tile--object):hover .rdk-abt-tile__card {
    rotate: calc(-1 * var(--rot));
    scale: 1.06;
  }
}

/* The two flocked objects ride the same burst with no card around them; the
   rig inside is what js/about-page.js pulls toward the cursor. */
/* The objects take the pointer as well, so the leaf and Texas can be
   picked up and thrown like the photos (client, 2026-09-10). Their
   cursor-pull rig is a CHILD, so it composes with the drag rather than
   fighting it. */
.rdk-abt-tile--object { pointer-events: auto; }
.rdk-abt-tile--object { --shade: 0px; }   /* no shadow, so no room needed */
.rdk-abt-tile--object .rdk-abt-tile__card {
  background: none;
  box-shadow: none;
  overflow: visible;
  border-radius: 0;
}
.rdk-abt-tile--object .rdk-abt__rig { will-change: transform; }
.rdk-abt-since__leaf .rdk-abt__rig { filter: saturate(1.4); }
/* Texas: fitted against the render's (68,189,6) — the raw is (132,182,27). */
.rdk-abt-since__texas .rdk-abt__rig { filter: saturate(2.2) brightness(0.8); }

.rdk-abt-since__text {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Heading/XL — the frame's 46 / 1 on a 667 measure, in the tracking ramp's
   -2.5%. The frame's ink is #00291b, which is not a token; --rdk-dark
   (#002300) is the nearest and is what the services names use. */
.rdk-abt-since__title {
  /* js/about-page.js splits this into lines and wraps each in a mask; the
     words rise up out of the mask, so each line's box must clip. */
  /* Display/L (frame 453:50490, 2026-09-10; it was 72 for a day). The
     sentence that used to follow it is the body's lede. */
  width: calc(900 * var(--u));
  max-width: 100%;
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(88 * var(--du));
  line-height: 1;
  letter-spacing: calc(-3.52 * var(--du));
  color: var(--rdk-dark);
}

.rdk-abt-since__body {
  width: calc(677 * var(--u));
  max-width: 100%;
  margin: calc(28 * var(--u)) 0 0;
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-l);
  line-height: var(--rdk-body-lh);
  letter-spacing: var(--rdk-body-track);
  font-feature-settings: "ss03" 1, "ss02" 1;
  color: var(--rdk-black-green);
  opacity: 0.9;
}

/* The masks js/about-page.js wraps each line of the title in. The 0.12em of
   padding is what keeps a descender ("g", "p") from being clipped on the
   way up; the negative margin gives it back so the line pitch is unchanged. */
.rdk-abt-since__line {
  display: block;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
  overflow: clip;
}

.rdk-abt-since__year {
  display: inline-block;
  min-width: 2.3em;
  text-align: left;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   3. what we believe (frame 453:50490, 2026-09-10)
   ============================================================
   White, continuous with the collage panel above (no shoulders — same
   ground). 88 top / 168 bottom / 144 sides; the title at x 208 (64 inside)
   on two lines; the grid 1312 wide, 32 gaps; the megaphone Donk 500 x 690
   standing on the grid's top edge at x 846. The eight-way exploration this
   replaces is in git history at 24ede27. */
.rdk-abt-beliefs {
  position: relative;
  z-index: 2;
  /* 160 of white under the last two cards before the next section starts
     (client, 2026-09-10). The slop panel rides 96 UP over this section, so
     the padding has to be 160 + 96 for the gap the reader sees to be 160. */
  padding: calc(88 * var(--u)) calc(144 * var(--u)) calc(256 * var(--u));
  background: var(--rdk-white);
  color: var(--rdk-black-green);
}

.rdk-abt-beliefs__inner {
  display: flex;
  flex-direction: column;
  gap: calc(72 * var(--u));
}

/* Display/L, two lines at x 64 inside the section. */
.rdk-abt-beliefs__title {
  margin: 0;
  padding-left: calc(64 * var(--u));
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(88 * var(--du));
  line-height: 0.94;
  letter-spacing: calc(-3.52 * var(--du));
  color: var(--rdk-black-green);
}

.rdk-abt-beliefs__wrap { position: relative; }

/* HE HIDES BEHIND THE YELLOW CARD (client, 2026-09-10: "shouldn't see his
   whole body, maybe have him pop up from behind it"). x 846 in the frame =
   702 into the grid; 240 of his 690 sit behind the card, so the card's top
   edge cuts him about the knees, and js pops him up from fully behind it as
   the grid arrives. BELOW the grid in z (the grid is 1), above the section.
   Where the frame stands him on the card at full height, that put his head
   40% up our viewport-tall collage panel and over its copy; this way his
   head reaches ~125 into the panel's empty foot with the frame's own 88 of
   section padding kept. Wrapper (GSAP pull + drift + pop) > img. */
/* HE IS MASK-REVEALED FROM BEHIND THE YELLOW CARD (client, 2026-09-10:
   "you can see him before the card animates into place"). The 240 of him
   that overlaps the grid used to be hidden by the card itself — which is
   nothing at all while the card is still at opacity 0 on its way in, so he
   slid up in plain sight. The MASK is a static box, positioned in the
   layout and never touched by GSAP, clipped at exactly the grid's top
   edge; the float and the rise both happen inside it. It has to be the
   OUTER element: put the clip on the element GSAP floats and the mask's
   edge drifts with him, opening a sliver against the card. */
.rdk-abt-beliefs__donk-mask {
  position: absolute;
  left: calc(702 * var(--u));
  bottom: calc(100% - 240 * var(--u));
  z-index: 0;
  width: calc(500 * var(--u));
  clip-path: inset(-50% -50% calc(240 * var(--u)) -50%);
  pointer-events: none;
}

.rdk-abt-beliefs__donk {
  position: relative;
  width: 100%;
  pointer-events: none;
  will-change: transform;
}

.rdk-abt-beliefs__donk img {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  will-change: transform;
}

.rdk-abt-beliefs__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(32 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
}

/* THE FOUR TINTS ARE THE FRAME'S OWN LITERALS — teal, yellow, mint, green —
   none of them a token, and the first three are new to the site. Kept here
   rather than in tokens.css until they are used anywhere else. */
.rdk-abt-belief {
  --tint: var(--rdk-green);
  display: flex;
  flex-direction: column;
  gap: calc(24 * var(--u));
  padding: calc(80 * var(--u)) calc(96 * var(--u)) calc(80 * var(--u)) calc(72 * var(--u));
  background: var(--tint);
  border-radius: calc(64 * var(--u));
  color: var(--rdk-black-green);
  /* The hover lift (client, 2026-09-10): the standalone `translate`, which
     GSAP never touches here — the entrance animates `y`/opacity on the
     same element but with clearProps, so nothing inline survives it. */
  transition: translate 0.5s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.5s ease;
}

.rdk-abt-belief--teal   { --tint: #7dccd7; }
.rdk-abt-belief--yellow { --tint: #fae14b; }
.rdk-abt-belief--mint   { --tint: #51ce98; }
.rdk-abt-belief--green  { --tint: #40d640; }

@media (hover: hover) {
  .rdk-abt-belief:hover {
    translate: 0 calc(-10 * var(--u));
    box-shadow: 0 calc(28 * var(--u)) calc(56 * var(--u)) rgba(0, 20, 7, 0.14);
  }
}

/* Heading/XL: 46 / 1 on the ramp's -2.5% (the frame writes -1.38, which is
   -3%; the ladder wins). */
.rdk-abt-belief__title {
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(46 * var(--du));
  line-height: 1;
  letter-spacing: calc(-1.15 * var(--du));
}

.rdk-abt-belief__body {
  margin: 0;
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-m);
  line-height: var(--rdk-body-lh);
  letter-spacing: var(--rdk-body-track);
  font-feature-settings: "ss03" 1, "ss02" 1;
  opacity: 0.9;
}

/* ============================================================
   4. agency life in the era of AI slop (nodes 501:77035, 531:4786)
   ============================================================
   The blue panel rides 96 up over the white with 96 shoulders; 1249 tall in
   the frame and clipped. The gradient is sampled off the render: (52,159,247)
   at the top to (119,185,250) at the foot. Text block at top 139, 40 gaps. */
/* THE SIX NUMBERS THE BELT IS TUNED BY live here, on the section, so
   js/slop-tuner.js can drive them by writing one element (client,
   2026-09-16: "give me some tune controls… it's a little off and I think
   that would be the easiest way to refine"). Everything below reads them;
   nothing else hard-codes these values. Keep `js/slop-tuner.js`'s `DEF` in
   step or its Reset restores a look the site no longer ships. */
.rdk-abt-slop {
  position: relative;
  z-index: 3;
  margin-top: calc(-96 * var(--u));
  background: var(--rdk-white);
  --slop-panel-h: 1268;   /* the panel, before the team panel's 96 overlap */
  --slop-belt-top: 587;   /* the belt's top edge inside the panel */
  --slop-belt-h: 788;     /* node 840:103480's own frame height, scaled */
  --slop-tile-w: 583;     /* a screenshot's width */
  --slop-thumb-w: 333;    /* a thumbs-down's width; its height follows */
  /* Multiplies every x, so the row opens and closes. Back to a neutral 1
     for node 979:115653's row (2026-09-21): the client's 0.985 was tuned
     against the old ten-tile row, whose gaps were proportionally twice as
     wide, and re-applying it here closed them to 20px. At 1 the drawn gap
     is 619.4 - 583 = 36.4, which IS the node's own 80-on-1280. */
  --slop-pitch: 1;
  /* EVERY THUMB IS PLACED ON ITS OWN (client, 2026-09-16: "I really want
     to be able to control the position of each thumb to get it perfect").
     Numbered 1..6 in BELT ORDER — left to right, alternating top and
     bottom — and `data-thumb` on the <li> is what binds them. These
     replace the group nudges outright, which were only ever a coarser way
     of saying the same thing. These are the CLIENT'S OWN placement pass
     (2026-09-16) — not the node's, and not derived from anything: each was
     put where it looked right against the screenshots either side of it.
     Negative lifts. */
  /* THE HORIZONTAL NUDGES ARE ZEROED FOR NODE 979:115653's ROW (2026-09-21)
     and the vertical ones are not. The client's set — dx 126 / 178 / 36 /
     146 / 0 / 0 — was hand-placement against the OLD ten-tile row, and it is
     an offset from wherever that row's base put a thumb, not from anything
     the new row has: carried over, thumbs 2, 4 and 6 landed 100-250 off a
     gap, i.e. squarely over a screenshot. Each `--x` in the markup now seats
     its thumb on a gap centre, which is the composition's own rule. The
     DY values still describe how high or low a thumb rides and are the
     client's own, so they stand. Re-do the dx by eye in `?tune`. */
  --slop-t1-dx: 0; --slop-t1-dy: -44;   /* top */
  --slop-t2-dx: 0; --slop-t2-dy: 37;    /* bottom */
  --slop-t3-dx: 0; --slop-t3-dy: 30;    /* top */
  --slop-t4-dx: 0; --slop-t4-dy: 40;    /* bottom */
  --slop-t5-dx: 0; --slop-t5-dy: 30;    /* top */
  --slop-t6-dx: 0; --slop-t6-dy: 0;     /* bottom */
}

.rdk-abt-slop__panel {
  position: relative;
  /* The belt ends at 700 + 788; the +96 is the team panel riding up over
     the foot. Grew from 1249 when the belt became node 840:103480's full
     frame — the thumbs need the room the screenshots alone did not. */
  height: calc((var(--slop-panel-h) + 96) * var(--u));
  border-radius: calc(96 * var(--u)) calc(96 * var(--u)) 0 0;
  background: linear-gradient(180deg, #349ff7 0%, #4aa6f8 45%, #77b9fa 100%);
  overflow: clip;
  color: var(--rdk-white);
}

.rdk-abt-slop__text {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(139 * var(--u));
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(40 * var(--u));
  text-align: center;
  pointer-events: none;
}

/* The box above is the full width of the panel and ignores the pointer so the
   belt can be grabbed through the empty space either side of the copy. The
   COPY itself must not: with it transparent too, the words could not be
   selected or copied, and inspecting them hit the panel or the belt behind
   instead (client, 2026-09-24: WhatFont kept reporting 16px, weight 400 —
   the panel's defaults, not the paragraph's). */
.rdk-abt-slop__text > * { pointer-events: auto; }
.rdk-abt-slop__text a { pointer-events: auto; }

/* The hero's "Since" pill: 2 white at 20%, 8 / 16, brand 17.425. */
.rdk-abt-slop__pill {
  display: inline-flex;
  margin: 0;
  padding: calc(8 * var(--u)) calc(16 * var(--u));
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(17.425 * var(--u));
  line-height: 0.94;
  letter-spacing: calc(-0.35 * var(--u));
  border: calc(2 * var(--u)) solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
}

/* Display/L on 898. */
.rdk-abt-slop__title {
  width: calc(898 * var(--u));
  max-width: 100%;
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(88 * var(--du));
  line-height: 1;
  letter-spacing: calc(-3.52 * var(--du));
}

/* The standfirst step on 692, two paragraphs a line apart — the same step as
   the 2002 and team intros, which is the point: every headline intro on this
   page is 20 at the design width, and only the belief cards take 18
   (client, 2026-09-24, after trying 18 here). */
.rdk-abt-slop__body {
  width: calc(692 * var(--u));
  max-width: 100%;
  margin: 0;
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-l);
  line-height: var(--rdk-body-lh);
  letter-spacing: var(--rdk-body-track);
  font-feature-settings: "ss03" 1, "ss02" 1;
  opacity: 0.9;
}

.rdk-abt-slop__body p { margin: 0; }
.rdk-abt-slop__body p + p { margin-top: calc(28 * var(--u)); }

/* ---------- the belt ----------
   Items are ABSOLUTE in the track, at the frame's own coordinates from the
   belt's origin (`--x` / `--y`, the belt's top being the panel's 598), so they
   overlap exactly as the frame has them and DOM order is the stacking
   order. `--period` on the track is the width of one pass; js clones the
   items one period along for the loop, sizes the track, and drives it.
   `--bu` is the belt's unit — --u on desktop, a flat 0.42px on the phone. */
/* THE BELT IS NODE 840:103480'S FRAME, SCALED. Its 578 tall becomes 788 at
   the belt's own 576/422.493 = 1.3633, the tiles sit at the node's 127
   (=173) inside it, and the thumbs run from -26 to 895 — so the panel
   clips them top and bottom exactly as the node's frame does. `top: 700`
   is what puts the highest thumb 35 clear of the copy's last line, which
   is more than `AVOID.gap` (28), so the duck never fires on it and the
   designed composition survives. */
.rdk-abt-slop__belt {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--slop-belt-top) * var(--u));
  height: calc(var(--slop-belt-h) * var(--u));
  overflow: visible;
  --bu: var(--u);
  --belt-p: 0;
}

/* THREE LAYERS, AND THEY ARE A PAINT ORDER — node 840:103480 puts three
   thumbs behind the screenshots and three in front. They ran at three
   different SPEEDS for a few hours on 2026-09-16 (a parallax the client
   asked for and then took back out: "I really want to be able to control
   the position of each thumb to get it perfect", and a drifting layer is
   the one thing that makes that impossible). All three now share one
   position, so the tracks earn their keep as z-order alone. */
.rdk-abt-slop__track {
  position: absolute;
  inset: 0;
  height: 100%;
  width: calc(var(--period) * var(--bu));
  margin: 0;
  padding: 0;
  list-style: none;
  will-change: transform;
  z-index: 1;
}

.rdk-abt-slop__track--back { z-index: 0; }
/* The front layer holds only the thumbs, which already ignore the pointer,
   yet as a full-size sheet over the copy it caught every click on the
   second paragraph. Transparent to the pointer, a grab still reaches the
   screenshot layer underneath, so the belt drags exactly as before. */
.rdk-abt-slop__track--front { z-index: 2; pointer-events: none; }

.rdk-abt-slop__track > li {
  position: absolute;
  /* `--slop-pitch` multiplies x only — js multiplies the loop's period by
     the same number, so the wrap follows the spacing and cannot tear.
     `--dx`/`--dy` are a per-KIND nudge; only the thumbs set them. */
  left: calc((var(--x, 0) * var(--slop-pitch) + var(--dx, 0)) * var(--bu));
  top: calc((var(--y, 0) + var(--dy, 0)) * var(--bu));
}

/* A shot: the node's 576 wide box at 855/510, radius 16, five blue shadow
   layers verbatim; the caption 14 under it.
   NO TILT AND NO Y SCATTER since 2026-09-16 (client: "the positioning needs
   to be as I designed"). Node 840:103480 draws a FLAT, LEVEL, evenly
   spaced row, and that is load-bearing rather than cosmetic: the thumbs
   are placed to straddle the GAPS between tiles, so a tile rotated 5deg
   or dropped 30 puts a thumb over a screenshot's middle instead of in the
   gap beside it. The earlier scatter came from node 564:46499 and this
   node supersedes it. */
.rdk-abt-slop__shot {
  width: calc(var(--w, var(--slop-tile-w)) * var(--bu));
}

/* The <figure> is load-bearing even with one child: js/about-page.js writes
   the wave and the duck's `y` on it, the li carrying the position. */
.rdk-abt-slop__shot figure {
  margin: 0;
}

.rdk-abt-slop__shot img {
  display: block;
  width: 100%;
  /* ALL NINE ARE ONE SHAPE (node 979:115653, 2026-09-21): every frame is
     1280 x 764, so there is no per-item `--w` / `--ar` any more. `--ar` is
     kept as a hook in case a future set is mixed again. */
  aspect-ratio: var(--ar, 1280 / 764);
  height: auto;
  max-width: none;
  object-fit: cover;
  border-radius: calc(16 * var(--bu));
  background: var(--rdk-white);
  box-shadow:
    0 calc(308 * var(--bu)) calc(86 * var(--bu)) rgba(10, 62, 117, 0),
    0 calc(197 * var(--bu)) calc(79 * var(--bu)) rgba(10, 62, 117, 0.01),
    0 calc(111 * var(--bu)) calc(66 * var(--bu)) rgba(10, 62, 117, 0.05),
    0 calc(49 * var(--bu)) calc(49 * var(--bu)) rgba(10, 62, 117, 0.08),
    0 calc(12 * var(--bu)) calc(27 * var(--bu)) rgba(10, 62, 117, 0.1);
  pointer-events: none;
}

/* THE NINE ARE REDONK'S OWN PARODY SITES (node 979:115653, 2026-09-21),
   not screenshots of real ones — which is why there is no attribution under
   them any more. Each is a vector frame rendered at its natural 1280 x 764
   and converted at q86 (drift under 1/255, all fully opaque — nothing to
   edge-extend). Corners are SQUARE in the files and rounded here, the
   handoff rule. */

/* A THUMBS-DOWN: ONE asset (node 840:103480 draws all six from the same
   fill), turned by `--turn` and flipped by `--flip` per instance — on the
   img, so the li's position is untouched. Exactly the arrangement the four
   slop piles had before them.
   THE ORDER OF `rotate` AND `scale` MATTERS AND IT MATCHES THE NODE BY
   LUCK OF THE SPEC, NOT BY COINCIDENCE. Standalone properties always apply
   translate -> rotate -> scale, i.e. R(t)·S; Tailwind's shorthand in the
   node builds `rotate(...) ... scaleY(...)`, which is the same product in
   the same order. Had they been the other way round every flipped
   instance would need its angle NEGATED, since S·R(t) = R(-t)·S.
   `pointer-events: none` so the belt's drag is never started on one and
   these never take a cursor. */
.rdk-abt-slop__thumb {
  width: calc(var(--slop-thumb-w) * var(--bu));
  /* 503.8 / 506.9 — the art's own aspect, so one slider resizes it. */
  height: calc(var(--slop-thumb-w) * 0.99388 * var(--bu));
  pointer-events: none;
}

/* Bound by `data-thumb`, not by layer or by --up/--down: those say where a
   thumb sits and which way it paints, neither of which is an identity.
   `--up` / `--down` stay because js still reads them for the ink maths. */
.rdk-abt-slop__thumb[data-thumb="1"] { --dx: var(--slop-t1-dx); --dy: var(--slop-t1-dy); }
.rdk-abt-slop__thumb[data-thumb="2"] { --dx: var(--slop-t2-dx); --dy: var(--slop-t2-dy); }
.rdk-abt-slop__thumb[data-thumb="3"] { --dx: var(--slop-t3-dx); --dy: var(--slop-t3-dy); }
.rdk-abt-slop__thumb[data-thumb="4"] { --dx: var(--slop-t4-dx); --dy: var(--slop-t4-dy); }
.rdk-abt-slop__thumb[data-thumb="5"] { --dx: var(--slop-t5-dx); --dy: var(--slop-t5-dy); }
.rdk-abt-slop__thumb[data-thumb="6"] { --dx: var(--slop-t6-dx); --dy: var(--slop-t6-dy); }

.rdk-abt-slop__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  rotate: var(--turn, 0deg);
  scale: 1 var(--flip, 1);
  will-change: transform;
}

/* THE ATTRIBUTIONS ARE PLAIN TEXT, NOT LINKS (client, 2026-09-16: "don't
   want to take users off of our site"). The underline went with the <a> —
   on a run that cannot be clicked it only promises that it can. The source
   is still named, which is what the credit is for. */

/* The belt loops AND is draggable (client, 2026-09-16). `is-draggable` is
   added by js once it has wired the pointer handlers, so a no-JS or
   reduced-motion reader is never shown a grab cursor for something that
   will not move. The drag adds into the loop tween's own modifier, so the
   belt is not a scroller here and only the cursor says otherwise. */
/* `pan-y` is what lets a thumb swipe the belt WITHOUT eating the page's
   vertical scroll: the browser keeps every vertical pan and hands us the
   horizontal one. Without it a horizontal drag either does nothing (the
   browser claims the gesture) or the JS has to cancel touches it cannot yet
   classify, which is how a section swallows a scroll that was passing
   through. On `.is-draggable`, so it only applies once the drag is wired. */
.rdk-abt-slop__belt.is-draggable { cursor: grab; touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.rdk-abt-slop__belt.is-draggable.is-dragging { cursor: grabbing; }

/* THE FOUR SLOP PILES ARE OUT (client, 2026-09-16) — the `__pile` rules
   and the four <li>s went together, and `slop-swirl.webp` is now
   unreferenced. Node 564:46499 still draws them, so this is a deliberate
   deviation from the frame. The four screenshots were already evenly
   spaced between them (gaps 644 / 643 / 684 / 679 across the wrap), so
   `--period` is untouched. */


/* ============================================================
   5. the people
   ============================================================ */
.rdk-abt-team {
  position: relative;
  z-index: 3;
  /* Rides 96 up over the statement so its rounded corners sit on the
     statement's ground, not on the sticky hero — the blue that was peeking
     through the notches (client, 2026-09-09). The statement pads 96 extra
     at the foot to pay for it. */
  margin-top: calc(-96 * var(--u));
}

.rdk-abt-team__panel {
  padding: calc(160 * var(--u)) calc(88 * var(--u)) calc(200 * var(--u));
  background: var(--rdk-white);
  border-radius: calc(96 * var(--u)) calc(96 * var(--u)) 0 0;
  color: var(--rdk-dark);
}

/* The cybersecurity section's row: title left, paragraph right. */
.rdk-abt-team__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: calc(88 * var(--u));
}

.rdk-abt-team__title {
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(88 * var(--du));
  line-height: 1;
  letter-spacing: calc(-3.52 * var(--du));
  color: var(--rdk-dark);
}

.rdk-abt-team__text {
  width: calc(560 * var(--u));
  flex: none;
  margin: 0 0 calc(8 * var(--u));
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-l);
  line-height: var(--rdk-body-lh);
  letter-spacing: var(--rdk-body-track);
  font-feature-settings: "ss03" 1, "ss02" 1;
  color: var(--rdk-black-green);
  opacity: 0.85;
}

/* THREE ACROSS, THE MIDDLE COLUMN DROPPED (client, 2026-09-09: larger).
   Node 470:63777 is a 672 x 893 card (3:4): sky gradient behind, the person
   in the flocked green world, a dark green multiply gradient over the foot
   and the NAME on the picture at Display/XL with the role under it. Three
   across is 458.7 a card at 1600, i.e. the node x 0.683: radius 40, name 71
   (built at Display/M 72), the name block 42 in from the left and 36 up from
   the bottom. The node's 14.5 white border is dropped: the panel is white,
   so it would be invisible. */
.rdk-abt-team__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(48 * var(--u)) calc(24 * var(--u));
  margin: calc(104 * var(--u)) 0 0;
  padding: 0;
  list-style: none;
}

.rdk-abt-team__grid { --align: 1; }

/* The middle column starts 64 down and ALIGNS as the grid scrolls up
   (client, 2026-09-10): `--align` is scrubbed 1 -> 0 by js/about-page.js. */
.rdk-abt-person:nth-child(3n + 2) {
  margin-top: calc(64 * var(--u) * var(--align, 1));
}

.rdk-abt-person__btn {
  /* The name block is absolute against THIS box. */
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  text-align: left;
  color: var(--rdk-white);
  cursor: pointer;
  border-radius: calc(40 * var(--u));
}

.rdk-abt-person__btn:focus-visible {
  outline: 3px solid var(--rdk-green);
  outline-offset: 6px;
}

/* The card. The photo fills it; the gradient sits over the foot (the node's
   192.8deg, transparent to #0b5d03 at 82%, multiply, 80%); the text sits on
   top of both. */
.rdk-abt-person__photo {
  position: relative;
  display: block;
  aspect-ratio: 672 / 893;
  border-radius: calc(40 * var(--u));
  overflow: clip;
  background: linear-gradient(233.2deg, #349ff7 30.9%, #bbd3fd 66.9%);
}

.rdk-abt-person__photo img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 50% 30%;
  transition: scale 1.4s cubic-bezier(0.22, 1, 0.36, 1), filter 0.5s ease;
}

.rdk-abt-person__photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(192.8deg, rgba(11, 93, 3, 0) 45%, rgba(11, 93, 3, 0.8) 90%);
  mix-blend-mode: multiply;
}

.rdk-abt-person__btn:hover .rdk-abt-person__photo img,
.rdk-abt-person__btn:focus-visible .rdk-abt-person__photo img {
  scale: 1.05;
}

/* STAND-INS. Two of the nine — Phill and Marjorie — are still the old
   site's square headshots, waiting for their Redonkuverse versions: they
   wear the green duotone at rest (grayscale under multiplied green — the
   same treatment as the first pass) so the set reads as one thing, and go
   to colour on hover. The other seven carry no [data-placeholder] and take
   none of this. */
.rdk-abt-person[data-placeholder] .rdk-abt-person__photo { background: var(--rdk-green); }

.rdk-abt-person[data-placeholder] .rdk-abt-person__photo img {
  filter: grayscale(1) contrast(1.08);
}

.rdk-abt-person[data-placeholder] .rdk-abt-person__photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--rdk-green);
  mix-blend-mode: multiply;
  transition: opacity 0.5s ease;
}

.rdk-abt-person[data-placeholder] .rdk-abt-person__btn:hover .rdk-abt-person__photo img,
.rdk-abt-person[data-placeholder] .rdk-abt-person__btn:focus-visible .rdk-abt-person__photo img {
  filter: none;
}

.rdk-abt-person[data-placeholder] .rdk-abt-person__btn:hover .rdk-abt-person__photo::before,
.rdk-abt-person[data-placeholder] .rdk-abt-person__btn:focus-visible .rdk-abt-person__photo::before {
  opacity: 0;
}

/* The name block: node's 61.5 / 659.5 in 893, i.e. 31 in and 26 up at this
   scale, first name at 51 / 0.94 / -5% with the role under it. */
.rdk-abt-person__text {
  position: absolute;
  left: calc(42 * var(--u));
  right: calc(32 * var(--u));
  bottom: calc(36 * var(--u));
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  color: var(--rdk-white);
}

.rdk-abt-person__first {
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(72 * var(--du));
  line-height: 0.94;
  letter-spacing: calc(-2.47 * var(--du));
}

/* A card with no portrait yet: the sky alone, and the multiply gradient
   kept so the name still sits on something. */

.rdk-abt-person__role {
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-s);
  line-height: 1.4;
  letter-spacing: var(--rdk-body-track);
  opacity: 0.85;
}

/* THE GHOST: a fixed copy of the pressed card's photo that js flies from
   the card's box to the DIALOG's box, then into its photo slot (and back),
   so the picture is what becomes the dialog. IT LIVES INSIDE THE <dialog>:
   a modal dialog is in the top layer, which paints over every z-index in
   the document, so a ghost appended to <body> flew invisibly under the
   backdrop for one pass (2026-09-10 — "make the animation smoother" was
   an animation nobody could see). */
.rdk-abt-bio__ghost {
  position: fixed;
  z-index: 2;
  overflow: clip;
  pointer-events: none;
  background: var(--rdk-green);
  will-change: left, top, width, height;
}

.rdk-abt-bio__ghost img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 50% 30%;
}

.rdk-abt-person__photo.is-ghosted { visibility: hidden; }
.rdk-abt-bio__photo.is-ghosted img { opacity: 0; }

/* ============================================================
   6. the bio dialog
   ============================================================
   A native <dialog>: showModal() supplies the focus trap and Escape, and
   ::backdrop the scrim. The panel is the contact dialog's dark green at the
   About tile's radius; js/about-page.js animates the panel in and out and
   toggles `is-open` so the backdrop can transition. */
.rdk-abt-bio {
  /* A LARGE chunk of the screen, not the whole of it (client, 2026-09-10):
     1280 wide, the portrait 480 at 3:4 with the name at Display/L. WHITE
     (client, same day: "try a white background") — the team panel's own
     ground, so the dialog reads as a card lifted off it. */
  width: min(calc(1280 * var(--u)), calc(100% - 48px));
  max-width: none;
  max-height: none;
  margin: auto;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--rdk-black-green);
  overflow: visible;
}

.rdk-abt-bio::backdrop {
  background: rgba(0, 20, 7, 0.82);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.rdk-abt-bio.is-open::backdrop { opacity: 1; }

.rdk-abt-bio__panel {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(72 * var(--u));
  padding: calc(64 * var(--u));
  max-height: calc(100svh - 48px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--rdk-white);
  border-radius: calc(40 * var(--u));
  box-shadow: 0 40px 120px rgba(0, 20, 7, 0.3);
  will-change: clip-path;
}

/* THE PANEL TAKES THE OPENING FOCUS, AND DRAWS NOTHING FOR IT (client,
   2026-09-20: "remove the green outline that is showing up around the close
   button"). js/about-page.js used to focus the CLOSE BUTTON on open, and a
   PROGRAMMATIC focus is one browsers may treat as `:focus-visible` -- iOS
   Safari does, Chromium with a mouse does not, which is why this only ever
   showed on a phone and cannot be reproduced in the browser pane. (Verified
   the negative there: a real click opens the dialog with the close button as
   `document.activeElement`, `:focus` matching and `:focus-visible` NOT.)

   So the ring was right and firing at the wrong moment; the fix is the
   moment, not the ring. Focus lands on the panel instead -- `tabindex="-1"`
   in the markup, never in the tab order, only ever focused by that one call
   -- so no CONTROL is focused on open and nothing is drawn. Tab still reaches
   the close button and still rings it green, which is the point of keeping
   it.

   Suppressing the indicator is only acceptable because this is a container a
   keyboard can never land on by itself, and the dialog announces itself
   through its own `aria-labelledby`. Do not copy this onto anything a reader
   can actually focus. */
.rdk-abt-bio__panel:focus,
.rdk-abt-bio__panel:focus-visible { outline: none; }

.rdk-abt-bio__close,
.rdk-abt-bio__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(56 * var(--u));
  height: calc(56 * var(--u));
  padding: 0;
  color: var(--rdk-black-green);
  border: calc(2 * var(--u)) solid rgba(0, 20, 7, 0.2);
  border-radius: 999px;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease, scale 0.25s ease;
}

.rdk-abt-bio__close:hover,
.rdk-abt-bio__close:focus-visible,
.rdk-abt-bio__arrow:hover,
.rdk-abt-bio__arrow:focus-visible {
  color: var(--rdk-white);
  background: var(--rdk-black-green);
  border-color: var(--rdk-black-green);
}

.rdk-abt-bio__close:focus-visible,
.rdk-abt-bio__arrow:focus-visible {
  outline: 3px solid var(--rdk-green);
  outline-offset: 3px;
}

/* THE SAME BUTTON AS THE PHONE'S, IN THE DARK (client, 2026-09-17: "use the
   same close button for desktop, but make it the dark color"). It was the
   56 ring at 20% that the prev/next arrows still wear; this is the contact
   dialog's rounded square instead, so the two dialogs on this site dismiss
   the same way and only the colour changes by surface — lime on the contact
   panel, white over the phone's photo, dark here on white.

   RADIUS 18 HOLDS THE PHONE'S PROPORTION rather than borrowing the contact
   dialog's literal 16: that button is 52 where this one is 56, and 14/44 on
   the phone scales to 17.8 at 56. One shape across this dialog's two
   breakpoints matters more than matching another component's number.

   The ring and the fill-on-hover go with it — the resting state is already
   the colour the old hover filled to, so the hover becomes the contact
   dialog's own nudge. `:hover` and `:focus-visible` still share a rule with
   the arrows above; those are `rdk-sr` and never drawn, so only this button
   changes on screen. */
.rdk-abt-bio__close {
  position: absolute;
  top: calc(24 * var(--u));
  right: calc(24 * var(--u));
  color: var(--rdk-white);
  background: var(--rdk-black-green);
  border: 0;
  border-radius: calc(18 * var(--u));
}

.rdk-abt-bio__close:hover,
.rdk-abt-bio__close:focus-visible {
  color: var(--rdk-white);
  background: var(--rdk-black-green);
  scale: 1.08;
}

.rdk-abt-bio__close svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); }
.rdk-abt-bio__arrow svg { width: calc(11 * var(--u)); height: calc(17.8 * var(--u)); }
.rdk-abt-bio__arrow--prev svg { scale: -1 1; }

.rdk-abt-bio__photo {
  flex: none;
  width: calc(480 * var(--u));
  aspect-ratio: 3 / 4;
  border-radius: calc(32 * var(--u));
  overflow: clip;
  background: var(--rdk-green);
}

.rdk-abt-bio__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%; /* the card's and the ghost's framing, so the hand-over is seamless */
}

.rdk-abt-bio__text {
  flex: 1 1 auto;
  min-width: 0;
}

/* Display/L. */
.rdk-abt-bio__name {
  margin: 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(88 * var(--du));
  line-height: 1;
  letter-spacing: calc(-3.52 * var(--du));
}

.rdk-abt-bio__role {
  margin: calc(12 * var(--u)) 0 0;
  font-family: var(--rdk-font-brand);
  font-weight: 700;
  font-size: calc(20 * var(--u));
  line-height: 1.2;
  letter-spacing: calc(-0.2 * var(--u));
  color: var(--rdk-green);
}

/* The live site's full paragraph (2026-09-10), so body-m on a 560 measure
   rather than the one-liner's standfirst step. */
.rdk-abt-bio__copy {
  max-width: calc(560 * var(--u));
  margin: calc(28 * var(--u)) 0 0;
  font-family: var(--rdk-font-body);
  font-weight: var(--rdk-body-weight);
  font-size: var(--rdk-body-m);
  line-height: var(--rdk-body-lh);
  letter-spacing: var(--rdk-body-track);
  font-feature-settings: "ss03" 1, "ss02" 1;
  opacity: 0.85;
}

/* The nav is `rdk-sr` in the markup — prev / next exist for the keyboard
   and screen readers and are not drawn (client, 2026-09-10). */
.rdk-abt-bio__nav { display: flex; gap: calc(12 * var(--u)); }

/* ============================================================
   7. the footer, on this page (node 453:50555)
   ============================================================
   THE SHARED FOOTER IS DISPLAY/XL 104 AND THIS FRAME'S IS DISPLAY/L 88 —
   a longer heading, and the client asked for the frame's type here
   (2026-09-10). Scoped to `body.rdk-abt`, so every other page's footer is
   untouched; worth a decision if a second page ever wants it. The block
   is 1130 wide for the heading, 32 heading-to-blurb (the shared 32), 55 to
   the button (the shared 40 + 16 pad), and the button pads 56 a side for
   the longer label. */
body.rdk-abt .rdk-footer__inner { width: calc(1130 * var(--u)); gap: calc(55 * var(--u)); padding-top: calc(56 * var(--u)); }
body.rdk-abt .rdk-footer__heading {
  width: 100%;
  font-size: calc(88 * var(--du));
  line-height: 1;
  letter-spacing: calc(-3.52 * var(--du));
}
body.rdk-abt .rdk-footer__blurb { width: auto; }
body.rdk-abt .rdk-footer__btn { padding: 0 calc(56 * var(--u)); }

/* The dialog is 1280 wide with the photo flying into it; a 560-wide
   drawer down the right edge was a second option for one pass and a
   full-screen takeover a third. The client picked this one (2026-09-10).

/* ============================================================
   reduced motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .rdk-abt-tile__card,
  .rdk-abt-person__photo img,
  .rdk-abt-person__photo::before,
  .rdk-abt-bio::backdrop { transition: none; }
}

/* ============================================================
   MOBILE — straight px. The frame is desktop only; the phone arrangement
   follows the other pages' phone frames (hero 100svh cap, 32 radii, 20
   insets, 12 for full-bleed cards).
   ============================================================ */
@media (max-width: 767px) {
  /* ---------- hero: NODE 585:4596, THE PHONE'S OWN FRAME ----------
     (client, 2026-09-10). The mobile hero was invented until now — a
     shrunk-down desktop with a 36px headline and both leaves floating in
     the sky. The frame is a different composition: the headline is the
     screen, at 61 over four hard-broken lines, with the pill centred above
     it and the landscape a wide panorama along the foot.

     `--mu` is the frame's own unit, `100vw / 390`, so every number below IS
     the number in Figma. It is NOT capped at 1px the way `--u` is: the
     artwork has to keep growing on a wider phone or the landscape stops
     reaching the edges. The two TYPE sizes are capped instead, with
     `min()` at the point of use — 61px at the design's own width, smaller
     on a 360 or 320 screen where four lines of it would not fit, and never
     larger.

     THE HERO IS THE FRAME'S 927, NOT THE WINDOW'S HEIGHT. The frame is a
     738-tall viewport looking at a 927-tall hero, so the landscape runs
     off the bottom of the first screen and the white panel does not
     arrive until 927. Sized to the window instead (one pass, 2026-09-10)
     the panel's shoulder rode up into the grass at 706 of a 738 window —
     the frame shows green to the very edge. `max()` against 100svh only
     matters on a window TALLER than 927mu, where the scene drops to the
     hero's foot rather than leaving a band of gradient under the grass. */
  .rdk-abt-hero {
    --mu: calc(100vw / 390);
    /* FIXED, not `max(..., 100svh)` (client, 2026-09-17: "I think it makes
       more sense to have a fixed height for mobile"). 927 is the node's own
       hero div; the 738 frame it sits in is a CROP, and 927 is what keeps the
       hero filling the screen on a phone taller than 738 — at 738 an 844-tall
       phone would show 106px of the collage panel at rest, which the comp
       does not. The `max` only ever bound on a phone taller than 2.377x its
       width, which is rare; dropping it makes the height say what it means. */
    height: calc(927 * var(--mu));
  }

  /* The frame's 648 x 475 box at left -129 / top 452, bleeding off BOTH
     edges (1.66 screens wide) and ending exactly on the hero's 927 foot —
     so it is anchored to that foot (`bottom: 0`), which IS top 452 at the
     frame's height and keeps the grass on the foot if the hero is ever
     taller. It was `bottom: -189` under a window-height hero, which put
     the hills at the frame's place only on a 738 window and lower on
     every taller phone. Positioned with `left`, never `translate`:
     js/about-page.js moves this element for the parallax and GSAP clears
     the standalone `translate` the moment it takes a transform over. */
  .rdk-abt-hero__scene {
    /* NODE 842:103804 — 841.627 x 673.302 at (-210.53, 183.07), against the
       hero's own 927. It was 648 x 475 at (-129, bottom 0), i.e. 30% narrower
       and sitting 269 lower, which is the "sizing is off" of the report.
       TOP-anchored, because the hero is fixed now: within a 927 box the
       node's 183.07 is exact, and bottom-anchoring would only re-derive the
       same number. Its bottom lands at 856.4, so 70 of grass sits below the
       frame's 738 crop and the hills never run out.
       Aspect 841.627/673.302 = 1.2499 IS the asset's 2400 x 1920, so this is
       the picture's own shape rather than a crop — `object-fit` has nothing
       to do here, and it is left in place only because it costs nothing. */
    /* NODE 1038:95408 (2026-09-24): 737.499 x 594.096 at (-189.75, 205.75),
       the same image and aspect as the desktop's. Supersedes the numbers
       in the comment above. */
    left: calc(-189.75 * var(--mu));
    top: calc(205.75 * var(--mu));
    bottom: auto;
    width: calc(737.499 * var(--mu));
    height: calc(594.096 * var(--mu));
    margin-left: 0;
  }

  /* The box is 1.364 wide against the asset's 1.25, so the scene is
     CROPPED to it rather than letterboxed, anchored to its bottom — it
     keeps the furniture, the hills and the grass and loses sky off the
     top, which is transparent anyway. The phone frame (`585:4596`) was
     drawn against the OLD image 40 and the client has not re-cut it, so
     this box is the frame's and the crop inside it is ours; measured at
     390 it loses 8.4% off the top, all of it sky. */
  .rdk-abt-hero__scene-img {
    height: 100%;
    object-fit: cover;
    object-position: 50% 100%;
  }

  /* The frame's "hero copy" block: top 92 with 24 of its own top padding,
     20 at the sides, 20 between the pill and the headline. */
  .rdk-abt-hero__text {
    top: calc(116 * var(--mu));
    padding: 0 calc(20 * var(--mu));
  }

  /* The pill is the DESKTOP's, 1:1 — the frame gives it the same 17.425 /
     8 / 16 / 2 the 1600 frame does, so the phone only restates it in `--mu`
     because `--u` collapses here. It was 13px before. */
  .rdk-abt-hero__since {
    margin-bottom: calc(20 * var(--mu));
    padding: calc(8 * var(--mu)) calc(16 * var(--mu));
    font-size: min(17.425px, calc(17.425 * var(--mu)));
    letter-spacing: calc(-0.3485 * var(--mu));
    border-width: calc(2 * var(--mu));
  }

  /* 56, NOT the old copy's 61, AND THE PHONE LINES ARE INVENTED — node
     453:50492 is desktop only and node 585:4596's four lines were fitted
     to "A quarter-century of Redonkulousness." The new copy's longest
     narrow line is "Still Thinking", 5.52 units of font-size, and the
     measure is `100vw - 64` — which shrinks FASTER than the type does,
     since 64 of it is fixed padding. So the size is solved at the
     NARROWEST phone, not at the frame's 390: 5.52 * (k * vw/390) <= 0.8vw
     gives k <= 56.5. At 61 it overflowed a 320 screen by 21px.
     Tracking holds the phone frame's own -3% (the desktop node's is -5%;
     that inconsistency is the design's and each breakpoint keeps its
     own). With JS the lines are laid by measurement instead
     (js/about-page.js hero()). */
  .rdk-abt-hero__title {
    /* THE FRAME'S OWN 61 / -1.8, AND THE 56 IT REPLACES WAS A MISCALCULATION
       (2026-09-16). That pass rejected 61 as overflowing a 320 screen, on
       `5.52 * k * vw/390 <= 0.8vw` — but 0.8vw is the measure under the
       DESKTOP rule's fixed `padding: 0 32px`, and this block overrides it to
       `20 * --mu`, which is proportional. The measure is a constant 89.7% of
       the viewport at every phone width, not 80% at 320. Measured at 320:
       the text block is 287 and the longest line, "Still Thinking", is 277
       at 61 — 10px clear. Solve against the padding that actually applies.
       The cap covers 390-767, where `--mu` exceeds 1 and an uncapped 61 would
       draw 120px on a 767 screen. The TRACKING is capped with it, which it
       was not before: the size stopped at 56 while the tracking ran on to
       -3.24, so the two came apart across that range. */
    font-size: min(61px, calc(61 * var(--mu)));
    letter-spacing: max(-1.8px, calc(-1.8 * var(--mu)));
  }
  .rdk-abt-hero__title-mbreak { display: inline; }

  /* ---------- collage ---------- */
  .rdk-abt-since {
    margin-top: -32px;
  }

  /* Tiles at ~0.3 of the frame, spread across 1.33 screens of width and
     1.4 of height so the outer ones bleed off the edges as the frame's do
     and none of them lands on the copy (~240px tall, centred). Measured at
     375 x 812: every photo clears the text block. */
  .rdk-abt-since__panel {
    border-radius: 32px 32px 0 0;
    /* THE CLOUD MUST NOT BE MEASURED IN `svh`, AND A REAL PHONE IS WHAT
       PROVED IT (client, 2026-09-17, with a screenshot from an iPhone:
       "copy is being hidden by images... second image is what it should
       look like").

       `--cuy` was `100svh / 1100`, and the nine photo positions above were
       hand-placed in the `?tune` phone frame, which is 390 x 844 — the whole
       SCREEN. Safari's bars take ~140 of that, so a real device hands the
       page nearer 700, the cloud's vertical spread shrank by 17%, and the
       photos closed in on the type. Measured: at 375 x 812 no photo crosses
       the copy and the worst gap is 1px; at 390 x 700, FOUR cross it and the
       worst overlap is -62px. This file already warned that an `svh` section
       wants checking on real hardware; this is that warning coming true.

       SO THE CLOUD IS WIDTH-BASED NOW, which is the call the DESKTOP already
       made and recorded: how tall the section is and how big the cloud is are
       two decisions, and tying the second to the first is what breaks it.
       `100vw / 508.3` IS the tuned `844 / 1100` at the 390 the client tuned
       at — the arrangement is unchanged at that width and merely stops
       depending on browser chrome.

       THE BOX STILL FILLS THE SCREEN, BUT IT MAY NOT BE SHORTER THAN THE
       CLOUD. `--panel-h` feeds the bottom clamp, so leaving it at `100svh`
       would just move the failure: on a 700 viewport the clamp would haul the
       lowest photos up onto the copy instead. The floor is the tuning frame's
       own aspect, 844/390, so on a phone with chrome the section runs a little
       past the fold and is scrolled through — which costs nothing, the section
       having stopped pinning on 2026-09-10.

       `--cu`'s `svh` term is LEFT ALONE deliberately: in portrait it never
       binds (it would need an aspect under 1.4), and in landscape it is what
       correctly shrinks the photos. It is the vertical SPREAD that was
       wrong, not the size.

       AND BOTH CARRY A FLOOR AT THE TUNED 390, because the cloud scales with
       WIDTH while the phone's type is stated in px and does not. So the gap
       closes as the screen narrows: measured at 375 it was 1px, on a device
       that really exists (SE, 13 mini) and 1px from the bug just reported.
       Floored, a narrow phone keeps the 390 arrangement while `--cu` goes on
       shrinking the photos with the width, which only opens the gap further.
       At 390 the floor and the expression are the same number, so nothing
       moves at the width the client tuned at. */
    /* 800, DOWN FROM 844, BECAUSE THE COPY BLOCK GOT SHORTER (client's own
       read, 2026-09-17: "the headline could be two lines... this would
       require less height from the entire section, correct?" — correct, and
       measured). Two headline lines instead of three took the block 327 ->
       283, and with that slack the type stays clear at every floor tested
       down to 720. 800 keeps ~40px of margin over that and cuts the
       over-scroll on a phone with browser chrome from 144px to 100. */
    --panel-h: max(100svh, 800px);
    height: var(--panel-h);
    --cu: min(calc(100vw / 1250), calc(100svh / 1750));
    --cux: calc(100vw / 1200);
    --cuy: max(calc(100vw / 508.3), 0.7673px);
    /* THE PHONE HAS ITS OWN FOUR KNOBS. The desktop's are a desktop tuning
       pass (the client's, 2026-09-10) and the phone has its own arrangement
       with its own derived units — leaving `--tile-k: 1.38` to inherit made
       every phone photo 38% larger than that composition was built for.
       `?tune` drives THESE on a phone-width window (js/about-page-tuner.js
       keeps a separate set per breakpoint); paste its Copy block here. The
       bottom clamp still applies.
       THESE ARE THE CLIENT'S OWN PHONE PASS (2026-09-16, pasted from the
       panel's Copy): the cloud pulled in above and below the type and the
       photos 47% bigger. Keep `DEF_PHONE` in js/about-page-tuner.js in
       step. */
    --spread-x: 1;
    --spread-up: 0.93;
    --spread-down: 0.96;
    --tile-k: 1.47;
    /* AND ITS OWN NINE — the client's phone pass, 2026-09-16, pasted from
       the panel's Copy with the preview frame up. Hand-placed by eye
       against this arrangement, so there is no rule to re-apply if the
       spreads or the panel move; they want re-doing in `?tune`.
       The nudges were defined once, so until 2026-09-16 the phone silently
       carried the DESKTOP's hand-placement (`--n1-x: -61`, `--n1-k: 1.19`,
       measured live at 390) on top of its own spread. The two arrangements
       are different enough that a desktop correction is not a phone one —
       the same call the four above already made. `?tune` drives these at
       phone width, or through the panel's Phone preview frame. */
    --n1-x: -102; --n1-y: -42; --n1-k: 1; --n1-r: 0;
    --n2-x: -275; --n2-y: 16; --n2-k: 1.62; --n2-r: 4;
    --n3-x: -222; --n3-y: -219; --n3-k: 0.99; --n3-r: 0;
    --n5-x: 188; --n5-y: -46; --n5-k: 1.5; --n5-r: 0;
    --n6-x: 17; --n6-y: 0; --n6-k: 0.88; --n6-r: 0;
    --n7-x: -63; --n7-y: -56; --n7-k: 1.02; --n7-r: -1;
    --n8-x: 0; --n8-y: 82; --n8-k: 1.21; --n8-r: 0;
    --n9-x: -250; --n9-y: 0; --n9-k: 1.07; --n9-r: 3.5;
  }

  /* EIGHT PHOTOS ON THE PHONE, NOT NINE (client, 2026-09-16). The VR tile
     is the one the phone has no room for: at this spread it sat at x -125
     to +5, i.e. a 5px sliver at the panel's left edge, where every other
     tile reads at 68-100%. Bleeding off an edge is the design; being a
     sliver is not. So it has no `--n4-*` above — a hidden tile has no
     placement — and its four rows are `desk: true` in the tuner, or the
     phone panel would carry sliders that move nothing.
     The same call the homepage wall already makes (`:nth-child(5)`), and
     the About hero's second leaf. Un-hiding it is this rule plus a `--n4-*`
     line; it needs a real placement, not 0. */
  .rdk-abt-tile[data-tile="4"] { display: none; }

  .rdk-abt-since__leaf { --mx: 300; --my: 200; }

  /* 12, NOT 20, AND THE HEADLINE IS WHY (client, 2026-09-17: "we can take up
     more of the width... the headline could be two lines"). Exactly right, and
     the margin was SEVEN PIXELS: the block is 360 wide, so 20 of padding left
     the type 320 content, and "We've been here" measures 327 at the phone's
     44px. It missed a two-line split by 7 and fell to three. At 12 the content
     is 336 and it breaks "We've been here / since 2002." as drawn.
     This is the cause the `--cuy` work above was treating as a symptom: a
     shorter copy block is what gives the photos room, rather than spreading
     the cloud further to dodge a block that did not need to be that tall. */
  .rdk-abt-since__text { padding: 0 12px; }

  /* THE SAME SIZE AS "WHAT WE BELIEVE" (client, 2026-09-10) — 44 / -1.76,
     the phone's step for a section title on this page. It was 32 for the
     first pass. */
  .rdk-abt-since__title {
    width: 100%;
    max-width: none;
    font-size: 44px;
    letter-spacing: -1.76px;
  }

  /* 336 to match the headline's new content box — 19.8em at 17px, inside the
     ~21em the rest of the site's body copy runs at. Takes the paragraph from
     seven lines to six. */
  .rdk-abt-since__body { width: 100%; max-width: 336px; margin-top: 16px; }

  /* ---------- beliefs ---------- */
  .rdk-abt-beliefs { padding: 64px 12px 72px; }
  .rdk-abt-beliefs__inner { gap: 32px; }
  /* Two lines here too, so Donk can stand to the right of the title —
     on one line "What we believe" runs the full width and under him. */
  .rdk-abt-beliefs__title { padding-left: 8px; font-size: 44px; letter-spacing: -1.76px; }
  /* Donk shrinks to the top-right corner of the grid, still on its edge:
     120 wide is 166 tall, which clears the two-line title's top by ~50
     inside the section's 64 of top padding. */
  /* 160, up from 150 (client, 2026-09-17: "make Donk just a bit larger").
     HE IS ANCHORED BY HIS BOTTOM, so growing him grows him UPWARD — and he
     already starts above the section title. The section is `overflow:
     visible`, so there is no clip to catch him: measured at 375, 170 puts his
     head exactly on the section's top edge and 180 puts it 10px over, onto
     the collage panel above. 160 leaves 11px.
     THE HIDDEN PORTION SCALES WITH HIM, 50 -> 53, so the share of him behind
     the yellow card stays at the 24% it was rather than shrinking as he
     grows — the "pop up from behind it" the 2026-09-10 pass is built on. The
     two 53s are one number: the mask's bottom edge and the clip's bottom
     inset have to land on the same line or a sliver opens against the card. */
  .rdk-abt-beliefs__donk-mask { left: auto; right: 0; bottom: calc(100% - 53px); width: 160px; clip-path: inset(-50% -50% 53px -50%); }
  .rdk-abt-beliefs__grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  /* Taller cards (client, 2026-09-10: "make the cards taller / more top and
     bottom padding") — 52 / 56 against the first pass's 32 / 36. */
  .rdk-abt-belief { gap: 14px; padding: 52px 24px 56px; border-radius: 28px; }
  .rdk-abt-belief__title { font-size: 30px; letter-spacing: -0.75px; }

  /* ---------- slop ---------- */
  .rdk-abt-slop { margin-top: -32px; }
  .rdk-abt-slop__panel { height: auto; padding: 72px 0 0; border-radius: 32px 32px 0 0; }
  .rdk-abt-slop__text { position: static; gap: 20px; padding: 0 20px; }
  .rdk-abt-slop__pill { padding: 7px 12px; font-size: 13px; letter-spacing: -0.26px; border-width: 1.5px; }
  .rdk-abt-slop__title { width: 100%; font-size: 40px; letter-spacing: -1.6px; }
  /* THE DESIGN'S BREAK IS RIGHT HERE TOO, so it is NOT hidden (client,
     2026-09-16: "weird line-breaks"). It was, and that cost twice over: the
     natural wrap under the body's inherited `text-wrap: pretty` is
     "What hasn't / changed, and / what has.", which splits the clause; and
     a hidden <br> is still a line break to SplitText, which is what put
     "and" alone on a line. Shown, the phone reads "What hasn't /
     changed, / and what has." — three lines, the clause intact, and the
     same break the desktop draws. */
  .rdk-abt-slop__body { width: 100%; }
  .rdk-abt-slop__body p + p { margin-top: 16px; }
  /* NOTHING IS CUT AT THE TOP HERE (client, 2026-09-16), and the trade is
     worth stating. At `--bu: 0.42` the composition spans 394px — the top
     thumbs' ink reaches 48 above the belt's origin and the lowest reaches
     46 below it — against a 300 box, so `overflow: clip` was cropping BOTH
     ends. `overflow-x` alone keeps the horizontal loop hidden while letting
     the top show: **`clip` is the one overflow value that does not force
     the other axis to `auto`**, so this stays out of scroll-container
     territory (the services marquee's fix, same reason).
     The BOTTOM is still cut, by the panel rather than by the belt — the
     belt's foot IS the panel's foot and the panel clips — which is what the
     frame draws.
     `margin-top` is 60 against 40 because the belt's BOX has to sit lower
     for its CONTENT to sit higher: the thumbs now start 12 below the copy
     where the box used to start 40 below it with 48 of empty cropped space
     under that. The band reads ~16 higher; the tile row lands ~20 lower,
     which is the 48 of uncovered thumb having to go somewhere.
     DO NOT close this gap further: the duck does not fire on a phone (the
     copy is entirely above the belt, so no item ever overlaps it), and if
     the belt did reach the copy every item would be under it horizontally
     and get pushed down permanently. */
  .rdk-abt-slop {
    /* THE PHONE'S OWN VALUES FOR THE BELT KNOBS, IN px RATHER THAN DESIGN
       UNITS — the desktop multiplies these by `--u`, the phone block below
       by 1px, so the same property name means a different thing per
       breakpoint. That is deliberate and it is why js/slop-tuner.js keeps a
       separate set per breakpoint, exactly as the collage panel does.
       BEFORE 2026-09-16 THE PHONE HARDCODED ALL THREE, so `Belt top`,
       `Belt height` and `Section height` were live on the desktop and
       silently inert on the phone — the client reported the panel as "not
       working on mobile" twice, and this was the second half of it.
       THESE THREE ARE THE ONLY ONES THE PHONE DECLARES, and that is
       deliberate. The client's pass (2026-09-16) also carried the tile and
       thumb widths, the pitch and the twelve per-thumb offsets — every one
       of them IDENTICAL to the desktop's, because they are all multiplied
       by `--bu` on the way to the screen and so stay proportional at any
       belt scale. Restating them here would be a second copy of the same
       number, which is the drift this file keeps recording. If a per-thumb
       offset ever genuinely needs to differ on the phone, add THAT one. */
    --slop-belt-top: 15;   /* px: the gap above the belt's box */
    --slop-belt-h: 326;    /* px: the box, which is also the section's tail */
    --slop-belt-u: 0.4;    /* px per belt unit — the composition's scale */
  }

  .rdk-abt-slop__belt {
    position: relative;
    top: auto;
    margin-top: calc(var(--slop-belt-top) * 1px);
    height: calc(var(--slop-belt-h) * 1px);
    overflow-x: clip;
    overflow-y: visible;
    /* Read live by `unit()` in js/about-page.js every frame, so the loop's
       wrap follows it and this is safe to drag at runtime. */
    --bu: calc(var(--slop-belt-u) * 1px);
  }

  /* ---------- footer, this page ---------- */
  body.rdk-abt .rdk-footer__inner { width: auto; gap: 24px; }
  /* 34 is the largest size at which "doing the thinking." fits a 335
     measure, so the heading breaks "Still here. Still / doing the thinking."
     rather than three lines with "thinking." stranded (client: no weird
     breaks on mobile). */
  body.rdk-abt .rdk-footer__heading { font-size: 34px; letter-spacing: -1.36px; text-wrap: balance; }
  .rdk-abt-footer-break { display: none; }
  body.rdk-abt .rdk-footer__btn { padding: 16px 40px; }

  /* ---------- team ---------- */
  /* THE SHARED EYEBROW HAS TO BE RESTATED IN px, like every other label on
     this page. At `20 * var(--u)` it rendered **4.875px** at 390 — the
     collapsing-unit trap this project documents, and reported as "comically
     small" (client, 2026-09-16). It is the page's only `.rdk-abt__eyebrow`
     ("The people", over the team grid), so it had no mobile block of its
     own to be caught by. 16 against the 44 title beside it: the designed
     ratio is 20/88, which would give 10 and is under the site's own floor
     for a small label on a phone. */
  .rdk-abt__eyebrow { margin-bottom: 16px; font-size: 16px; letter-spacing: -0.16px; }

  .rdk-abt-team { margin-top: -32px; }
  .rdk-abt-team__panel { padding: 72px 20px 96px; border-radius: 32px 32px 0 0; }
  .rdk-abt-team__head { flex-direction: column; align-items: stretch; gap: 20px; }
  .rdk-abt-team__title { font-size: 44px; letter-spacing: -1.76px; }
  .rdk-abt-team__text { width: 100%; margin: 0; }

  .rdk-abt-team__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin-top: 48px;
  }

  .rdk-abt-person:nth-child(3n + 2) { margin-top: 0; }
  .rdk-abt-person:nth-child(2n) { margin-top: 28px; }

  .rdk-abt-person__btn { border-radius: 16px; }
  .rdk-abt-person__photo { border-radius: 16px; }
  .rdk-abt-person__text { left: 14px; right: 12px; bottom: 12px; gap: 4px; }
  .rdk-abt-person__first { font-size: 26px; letter-spacing: -1.3px; }
  .rdk-abt-team__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rdk-abt-person__role { font-size: 12px; }

  /* ---------- dialog ---------- */
  /* THE PANEL STACKS (client, 2026-09-17: "the mobile overlay has major
     issues. Can you put the image at the top. Maybe change the ratio to
     3.5:3. And then put the text underneath it?").

     IT NEVER LEFT THE DESKTOP ROW, which is the whole fault and not a
     matter of tuning. The block below overrode the photo's width and the
     type sizes but not `flex-direction`, so the panel stayed a two-column
     flex with `align-items: center`: a 140px portrait floating halfway down
     the card, and the copy squeezed into the ~180px left over — measured at
     390, a 22-line paragraph in a column narrower than the photo beside it.
     Column plus `stretch` is what fixes it; the photo and the type sizes
     were never the problem.

     3.5 / 3 IS THE CLIENT'S RATIO, not the desktop's 3 / 4 — landscape, so
     the portrait reads as a header band across the top rather than as a
     tall card competing with the text under it. At a 326 content measure
     that draws 326 x 279. */
  /* MOST OF THE VIEWPORT, NOT AS TALL AS ITS CONTENT HAPPENS TO BE (client,
     2026-09-17). 12 all round, mirroring the 24 the width already gives up,
     so a short bio and a long one open at the same size and only the copy
     inside differs. The panel fills it and scrolls.

     `dvh`, NOT `svh` (client, 2026-09-20: "extra space at the top and bottom
     that I dont love"). `100svh` is the SMALL viewport -- the height with the
     browser's chrome fully EXPANDED -- so on a phone whose chrome has
     collapsed (which it has, because the reader scrolled down to the team to
     get here) the dialog is short of the visible area by the chrome's height,
     and `margin: auto` splits that shortfall evenly above and below it. On an
     iPhone 14 Pro that is ~70px at each end of a dialog meant to BE the
     screen. `dvh` is the CURRENT viewport, so it fills what is actually
     visible.

     IT CANNOT THRASH HERE, which is the usual objection to `dvh`: the page's
     scroll is locked while the dialog is open, so the chrome cannot change
     state under it and the value is fixed for the dialog's whole life.
     Safari and Chrome shipped `dvh` and `svh` together, so the swap costs no
     support. */
  .rdk-abt-bio {
    width: calc(100% - 24px);
    height: calc(100dvh - 24px);
  }
  /* THE PHOTO IS FIXED AND ONLY THE COPY SCROLLS (client, 2026-09-17: "fix
     the image and just scroll the text"). The scroll moves OFF the panel and
     onto the text, which is what lets the photo and the close button stay
     put — the panel was the scroller, so everything in it travelled.
     `min-height: 0` on the text is what makes that scroll possible at all: a
     flex item's `auto` minimum is its content, so without it the text block
     simply grows to fit the bio and nothing ever overflows. Same property
     that was needed for the photo's ratio, for the same underlying reason. */
  .rdk-abt-bio__panel {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 12px;
    border-radius: 24px;
    height: 100%;
    max-height: none;
    overflow: hidden;
  }
  /* THE SCROLL NARROWS TO THE BIO ITSELF (client, 2026-09-17: "try also
     fixing the name and title, and then having just the bio copy clipped
     when you scroll"). The photo, the name and the role are all frame now;
     the paragraph is the only thing that moves.

     SO THE TEXT BLOCK STOPS BEING THE SCROLLER AND BECOMES A COLUMN, and
     the scroll moves down one level onto the copy. `min-height: 0` is
     needed at BOTH levels and for the same reason each time — a flex item's
     `auto` minimum is its content, so without it the text block refuses to
     be shorter than name + role + the whole bio, and the copy inside it
     never overflows either. It is the third time this property has been
     load-bearing in this dialog. */
  .rdk-abt-bio__photo { flex: none; }
  .rdk-abt-bio__text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  .rdk-abt-bio__name,
  .rdk-abt-bio__role { flex: none; }
  .rdk-abt-bio__copy {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* THE LIME SQUARE FROM THE CONTACT DIALOG (client: "a green close button
     similar to what we use on the lets talk dialog") — css/contact.css's
     own phone values, 44 square at a 14 radius with a 16 glyph, lime on
     `--rdk-dark`. It drops the ring entirely; the fill carries it now.

     STICKY, NOT ABSOLUTE, AND THAT IS THE "FIX IT IN THE CORNER" PART. The
     panel is the scroll container, so an absolutely positioned child scrolls
     away with the copy — at this height there is a lot of copy to scroll.
     Sticky pins it against the panel's own top edge instead. It is the FIRST
     child, so `align-self: flex-end` puts it right and the negative margin
     takes its 44 plus the 12 gap back out of the flow, letting the photo
     start at the top with the button over its corner. */
  /* INSET INTO THE PHOTO, WITH THE SAME GAP ON BOTH SIDES (client): the
     photo starts at the panel's 12 padding and the button sits 12 inside
     that, so 24 from the panel's own edge and an even 12 from the photo's
     top and right. WHITE now rather than lime — it reads as lifted off the
     image instead of as an accent on it.

     BACK TO `absolute`, WHICH IS ONLY POSSIBLE BECAUSE THE PANEL NO LONGER
     SCROLLS. It was sticky for exactly that reason; with the scroll moved
     onto the text block the panel is a static frame again and absolute
     pins the button against it for free. */
  .rdk-abt-bio__close {
    position: absolute;
    top: 24px;
    right: 24px;
    width: 44px;
    height: 44px;
    color: var(--rdk-black-green);
    background: var(--rdk-white);
    border: 0;
    border-radius: 14px;
  }
  .rdk-abt-bio__close svg { width: 16px; height: 16px; }

  /* The copy sits 8 inside the photo's edge rather than flush to it, so the
     image reads as the card's header band and the text as set within it. */
  .rdk-abt-bio__text { padding: 8px; }
  /* `min-height: 0` IS WHAT MAKES THE RATIO BIND, and without it the
     declaration is silently ignored. The photo is a flex item, so its
     `min-height: auto` resolves to a CONTENT-based floor — and the content
     is an `<img>` at `height: 100%` whose intrinsic 1344 x 1792 is 3 / 4.
     That floor outranks `aspect-ratio`, so the box drew 311 x 415 (the
     asset's ratio) while `getComputedStyle` cheerfully reported
     `aspect-ratio: 3.5 / 3`. Checking the declaration would have said it
     worked; only the box says otherwise.
     Invisible on the desktop rule above because ITS 3 / 4 happens to match
     the asset — the bug has always been there and needed a ratio that
     disagreed to surface it. */
  .rdk-abt-bio__photo {
    width: 100%;
    aspect-ratio: 3.5 / 3;
    min-height: 0;
    border-radius: 16px;
  }
  /* TOP-ALIGNED, NOT THE DESKTOP'S 30% (client: the top of the head is
     getting clipped). A 3 / 4 portrait in a 3.5 / 3 window loses 35.7% of
     its height, so 30% starts the crop 10.7% down the picture — and
     measured across the set the heads start between 5.0% and 11.2% down
     (the 1344 x 1792 Redonkuverse portraits at 8.0 to 11.2, the two square
     placeholders at 5.0 and 5.7). So that one value clipped four of the
     nine and grazed two more. 0 is the only value that clears every one of
     them, and it is what a portrait crop wants anyway: the head near the
     top, the body filling the frame.
     THE GHOST TAKES IT TOO, AND THAT IS NOT OPTIONAL. js/about-page.js
     flies a copy of the card's photo into this slot and the two share a
     framing so the hand-over is seamless — change one and the picture
     JUMPS 47px on landing, which is the whole 10.7% of source height
     resolved in a 280-tall box. The CARD is left alone: its own box is
     672 / 893 against a 3 / 4 asset, a 0.33% vertical crop, so 30% there
     is a 0.3px offset and the ghost's departure is seamless either way. */
  .rdk-abt-bio__photo img,
  .rdk-abt-bio__ghost img { object-position: 50% 0; }
  /* 40, up from 32 (client: "use a larger headline for the name"). Tracking
     stays the dialog's own -4%, which is also what the phone's case-study
     title uses at 46 — the mobile type carries its own designed values
     rather than the desktop ladder's per-size percentages. */
  .rdk-abt-bio__name { font-size: 40px; letter-spacing: -1.6px; }
  /* DOWN A STEP TO body-s, 15px on a phone (client: "is there a smaller size
     we can use on mobile?"). It was body-m at 17, which was never wrong —
     it is the site's running-prose size and the project, services and blog
     pages all use it. This is a step ON the scale, not a size invented for
     this one dialog; body-s is what the cards, tiles and excerpts take. */
  .rdk-abt-bio__copy { max-width: none; font-size: var(--rdk-body-s); }
  .rdk-abt-bio__role { margin-top: 6px; font-size: 15px; letter-spacing: -0.15px; }
  .rdk-abt-bio__copy { margin-top: 14px; }
}

/* ============================================================
   THE NAV'S PILLS ARE KNOCKED OUT OF THE HERO, AS ON THE PROJECT PAGES
   (client, 2026-09-10: "fix the button in the nav so the text is the colour
   of the background like on the other pages"). Same build as
   css/project.css, whose header carries the reasoning: the label is #000
   and the BLEND goes on the nav (it resolves against the nav's own stacking
   context, so on the pill it would blend against nothing), `screen` being a
   no-op on the white pill and the identity on black. Only on the landing
   view and never with the menu open, for the reasons recorded there.

   The ink rules are deliberately (0,1,0) — this file loads after nav.css so
   they beat its default, and `.rdk-nav--on-light .rdk-nav__cta` (0,2,0)
   still wins over the white sections, where the pill inverts to green with a
   white label. Scope them to `body.rdk-abt` and that inversion is lost.

   ON THE RECORD: the hero's blue behind the pill is #349ff7, 2.8:1 against
   the white — under the 3:1 the project pages hold the 20px CTA to, and well
   under the 4.5:1 the 15px Menu needs. The client chose it over the black
   with that in view; this file is loaded only here, so it is one block to
   take back out. */
/* ---------- AND ONE STEP BELOW THE TUNED 390 ----------
   The photos scale with WIDTH (`--cu` is `100vw / 1250`) while the phone's
   type is stated in px and does not, so as the screen narrows the copy grows
   relative to the cloud and the gap closes from the inside. Measured at
   320 x 650 with the floor alone: the copy was still crossed by 12px.

   0.84 is measured, not picked — at 320 it clears by 11px, and past about
   0.88 the bottom clamp binds and the gap stops improving, so there is
   nothing to be had by going further. Below 390 only, so the width the
   client hand-placed the nine photos at is untouched.

   A COMBINED QUERY, NOT ONE NESTED IN THE PHONE BLOCK: `@media` inside
   `@media` is CSS Nesting, which wants Safari 17.2, and this is tested on
   real iPhones. The same call the phone's short-screen steps already make. */
@media (max-width: 389px) {
  .rdk-abt-since__panel { --cuy: 0.84px; }
}


@media (min-width: 768px) {
  .rdk-nav__cta { color: #000; }
  body.rdk-abt .rdk-nav--at-top:not(.rdk-nav--menu-open) { mix-blend-mode: screen; }
}
@media (max-width: 767px) {
  .rdk-nav__menu { color: #000; }
  body.rdk-abt .rdk-nav--at-top:not(.rdk-nav--menu-open) { mix-blend-mode: screen; }
}

/* ============================================================
   TABLET PORTRAIT — THE HERO IS NODE 888:104683 (client, 2026-09-17:
   "the hero looks horrible... headline is too big, label kicker is too
   small, image isn't big enough. See the design")

   ALL THREE COMPLAINTS ARE ONE CAUSE, AND IT IS THE COLLAPSING UNIT. The
   kicker and the scene were still sized in `--u`, which is `100vw / 1600`:
   at 768 that is 0.48, so a 17.425 pill rendered **8.4px** and the 1842.411
   scene rendered 884 where the design wants 1116. The headline was the
   opposite — a FLAT 104px, deliberately off `--u` since 2026-09-10, so it
   did not shrink with the frame and read as enormous beside them.

   THE NODE IS AN iPad PORTRAIT FRAME AT 1:1 — 768 x 1024 — so `--tu` is
   `100vw / 768` and every number below is the node's own, exactly the
   arrangement the phone block makes with `--mu`. Verified 1:1 rather than
   assumed: the headline's cap height measures 63-64px off the render, which
   at this face's 0.711 cap ratio is 88, and cap-top to cap-top is 88.3 over
   three gaps, i.e. leading 1.0. The chrome agrees too.

   THE TYPE IS FLAT AND THE ARTWORK SCALES, which is the split this page
   already makes. Scaling the headline with the frame would undo the fix the
   client asked for on 2026-09-10 and hand back 117px at a 1024 tablet —
   larger than the 104 being complained about here. The scene is artwork and
   has to keep bleeding off both edges at every width, so it takes `--tu`.

   IT IS DISPLAY/L, ONE RUNG DOWN FROM THE DESKTOP'S DISPLAY/XL, and it
   carries that rung's own tracking: 88 / 1.0 / -3.52 (-4%) against the
   desktop's 104 / 0.94 / -5.2 (-5%). On the ladder, not beside it.

   `max-width` ON THE TITLE IS LOAD-BEARING, NOT DECORATION. `fits()` in
   js/about-page.js measures the wide line set against `title.clientWidth`
   and lays the narrow set only when it does not fit. The node pins the
   paragraph to 672.66 in a 704 content box — narrower than it needs to be —
   which is what forces "Still Thinking Ahead." to break. Without it the
   headline would hold three lines from about 820 upward and stop matching
   the comp. */
@media (min-width: 768px) and (orientation: portrait) {
  .rdk-abt-hero {
    --tu: calc(100vw / 768);
  }

  .rdk-abt-hero__text {
    top: 141px;
  }

  /* The container is a flex column with no gap in the node, so the pill's
     desktop `28 * --u` bottom margin comes off. */
  .rdk-abt-hero__since {
    /* 24 under the pill (client, 2026-09-24); the node has none and it read
       as the pill sitting on the headline. */
    margin-bottom: 24px;
    padding: 8px 16px;
    font-size: 17.425px;
    line-height: 0.94;
    letter-spacing: -0.3485px;
    border-width: 2px;
    border-radius: 59px;
  }

  /* DISPLAY/XL ON THE LADDER, NOT A FLAT 88 (client, 2026-09-17: "the
     headline font size seems huge. Is it consistent with other pages?" —
     it was not). Measured across every page at 820 portrait, the SECTION
     headlines are consistent everywhere at 59.8 (`88 * var(--du)`: the case
     studies' title, the blog hero, the pricing and services section titles,
     the contact dialog). The HEROES are 70.7 on work and pricing, 59.8 on
     the blog and 56 on services — and this one was **88**, a flat px from
     node 888:104683's 768 frame, i.e. 24% past the largest headline
     anywhere else on the site.
     It was also wrong WITHIN this page: 88 over the sections' 59.8 is a
     1.47 step where the desktop's 104 over 88 is 1.18. On the ladder at
     `104 * var(--du)` it is 70.72 here — the same rung, and the same
     rendered size, as the work and pricing heroes — and the step is the
     desktop's 1.18 again.
     IT ALSO LANDS THE DESIGN'S OWN TWO-LINE BREAK. `fits()` measures the
     wide set against the title's width, and at 70.72 "Still Thinking
     Ahead." finally fits the node's 672.66, so the headline reads as node
     453:50492 draws it — "24 Years of Digital. / Still Thinking Ahead." —
     rather than in the tablet node's four.
     THE COST IS SKY: the copy block ends at 319 against 529 before, so
     there is ~210 more blue above the hills. The block stays at the node's
     141 from the top rather than being pushed down to close it, because
     that is what the node states and the gap is a consequence of the size.
     The flat 88 is one line away if the four-line hero is wanted back. */
  /* FOUR LINES, AND THE MEASURE IS WHAT DOES IT (client, 2026-09-17: "wrap
     onto 4 lines like on tablet. We have the realestate to fill"). Nothing
     forces a break directly: `layTitle()` in js/about-page.js lays the WIDE
     set when it fits `title.clientWidth` and the NARROW set when it does
     not, so the measure IS the decision — which is the mechanism the node
     already relied on, pinning its paragraph narrower than the words need.
     Dropping to Display/XL let the wide set fit again and the headline went
     to two, so the measure has to come down with the type.

     IN `em`, NOT px, AND THAT IS THE WHOLE POINT. `calc(672.66em / 88)` is
     the node's measure over the node's font size — 672.66 at 88, and the
     node's PROPORTION at any other size. So the four-line break is decided
     the same way at every width instead of at one: `--du` is pinned at 0.68
     from 768 to about 1088 and then grows with `--u`, and the measure grows
     with it. Same expression as the body measures below.

     IT IS NOT A KNIFE EDGE, which matters because a wrong answer here is a
     silently different headline. Measured at 70.72: the wide set's longest
     line ("Still Thinking Ahead.") is **605** and the narrow set's ("Still
     Thinking") is **371**, so anything from 372 to 604 gives four lines.
     The node's ratio lands on **540.5** — 64 clear of flipping back to two
     and 169 clear of the narrow set wrapping inside itself. */
  /* ONE STEP UP, 104 -> 120 (client, 2026-09-24: "make the headline
     bigger"), 81.6 on a touch tablet against the 70.7 above. The measure is
     in em so it grows with the type and the four lines hold: at 120 the
     narrow set's longest line is ~428 and the wide set's ~698 against a
     measure of ~624. Tracking kept at the same -5%. */
  .rdk-abt-hero__title {
    max-width: calc(672.66em / 88);
    font-size: calc(120 * var(--du));
    line-height: 0.94;
    letter-spacing: calc(-6 * var(--du));
  }

  /* 1116 x 893 at (-197, 229) in a 1024-tall frame. Only the WIDTH is stated:
     the node's box is aspect 1.2497 and the asset is 2400 x 1920, i.e. 1.25 —
     the same — so the box is the picture's own shape and not a crop, and the
     img's `height: auto` lands on 893 by itself. Bottom-anchored, as the
     desktop and phone both are, so a hero taller than the frame opens sky
     above the hills rather than moving them: 229 from the top IS -98 from the
     bottom at 1024. */
  .rdk-abt-hero__scene {
    left: calc(-197 * var(--tu));
    bottom: calc(-98 * var(--tu));
    width: calc(1116 * var(--tu));
  }

  /* ---------- THE BIO DIALOG STACKS HERE TOO (client, 2026-09-17) ----------
     It was taking the DESKTOP dialog, and at this width that is the
     "type floored, its measure not" trap in its worst form on the site.
     `--u` is 0.48 at 768, so the panel drew 614 x 704 and the copy's
     `560 * --u` measure collapsed to 269px — while the body scale's touch
     floor held the type at 16px. Measured: **16.8em, 32 characters a line**,
     against the desktop's 61. Nothing was proportionally wrong; the measure
     simply stopped scaling with the type it was drawn for.

     So it takes the phone's stacked treatment — photo as a 3.5 / 3 header
     band, text beneath, the scroll on the bio paragraph alone — at a
     tablet's own sizes rather than a 390-frame's literals. Same split the
     footer already makes: the portrait query joins the treatment, and the
     numbers that a phone value gets wrong on an 820 screen are restated.

     THE MEASURE IS IN THE TYPE'S OWN UNITS, WHICH IS THE WHOLE POINT.
     `34em` is ~68 characters at whatever the floor resolves the body size
     to, so it cannot come apart from the type the way `560 * --u` did.
     Same fix, and the same reasoning, as the case-study description's
     `calc(418em / 20)` on this breakpoint.

     640 RATHER THAN THE PHONE'S FULL BLEED. A phone is edge to edge because
     there is no room to be anything else; a tablet has room, and the client
     has already ruled out a full-screen dialog for this component. 640 is
     also what keeps the measure honest at 1024 portrait, where a panel sized
     to the viewport would run the copy out past 80 characters. */
  .rdk-abt-bio {
    width: min(640px, 100% - 48px);
    /* `dvh` for the reason the phone block sets out at length. The 900 cap is
       untouched and is usually still what binds here. */
    height: min(calc(100dvh - 48px), 900px);
  }

  .rdk-abt-bio__panel {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    padding: 16px;
    border-radius: 28px;
    height: 100%;
    max-height: none;
    overflow: hidden;
  }

  /* `min-height: 0` at both levels, for the reason the phone block sets out
     at length: a flex item's automatic minimum is its CONTENT, so without it
     the photo ignores its declared ratio and the text block refuses to be
     shorter than the whole bio. */
  .rdk-abt-bio__photo {
    flex: none;
    width: 100%;
    aspect-ratio: 3.5 / 3;
    min-height: 0;
    border-radius: 20px;
  }

  /* Top-aligned, and THE GHOST WITH IT — the slot is landscape here too, so
     the same 47px hand-over jump applies if the two come apart. */
  .rdk-abt-bio__photo img,
  .rdk-abt-bio__ghost img { object-position: 50% 0; }

  .rdk-abt-bio__text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    padding: 8px;
  }

  .rdk-abt-bio__name,
  .rdk-abt-bio__role { flex: none; }

  /* THE ROLE HAS NO FLOOR AND THE NAME DOES — a pre-existing fault this
     layout only made visible. The name is `88 * --du`, which holds at 0.68
     on a touch tablet; the role is `20 * --u`, which collapses to **9.6px**
     at 768. That is a 6.2 : 1 step under the name where the desktop's is 4.4
     and the phone's 2.7 — the same collapsing-unit trap the About eyebrow
     hit at 4.875px. The rule was simply never moved when `--du` came in.
     Floored to the phone's own designed 15 rather than a new number, and as
     a `max()` so it may only ever RAISE: `20 * --u` reaches 15 at about
     1200, so the floor releases itself as the window widens instead of
     pinning the size. A LANDSCAPE touch tablet under ~1088 has the same
     fault and is left alone here — that breakpoint still takes the desktop
     dialog, so it wants deciding as a whole rather than patching one rule. */
  .rdk-abt-bio__role {
    margin-top: 6px;
    font-size: max(15px, calc(20 * var(--u)));
    letter-spacing: -0.15px;
  }

  .rdk-abt-bio__copy {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    max-width: 34em;
    margin-top: 16px;
  }

  /* Inset into the photo, white, as the phone has it. 48 rather than the
     phone's 44 — a close button is a TOUCH TARGET, so it is sized absolutely
     and not as a share of a panel twice the width; 44 is the floor and 48 is
     the comfortable size at this scale. The radius and the glyph hold the
     phone's 14/44 and 16/44 proportions at 48. */
  .rdk-abt-bio__close {
    position: absolute;
    top: 32px;
    right: 32px;
    width: 48px;
    height: 48px;
    color: var(--rdk-black-green);
    background: var(--rdk-white);
    border: 0;
    border-radius: 15px;
  }

  .rdk-abt-bio__close svg { width: 17px; height: 17px; }

  /* The base rule's hover fills the button DARK, which is right when the
     resting state is already dark on white and wrong for a white button
     sitting on a photograph — it would invert on contact. A tablet has no
     hover, but `:focus-visible` still fires for a keyboard, and this query
     also catches a tall narrow DESKTOP window, which does. */
  .rdk-abt-bio__close:hover,
  .rdk-abt-bio__close:focus-visible {
    color: var(--rdk-black-green);
    background: var(--rdk-white);
  }
}

/* ============================================================
   TABLET PORTRAIT — THE PAGE BODY (client, 2026-09-17)

   FIVE COMPLAINTS, ONE CAUSE, AND IT IS THE HALF-FINISHED `--du` PASS.
   2026-09-16 floored the DISPLAY TYPE on a touch tablet (`--du` at 0.68)
   and the BODY scale with it (16-17px), and stopped there — every measure,
   inset, gap and absolute offset on this page is still plain `--u`, which
   at 820 is 0.5125. So the type is drawn at 68% of design while the box it
   sits in is drawn at 51%, and the two are 33% out of step. Every symptom
   the client listed falls out of that one ratio:

     - a measure too narrow for its type (the "since" body at 21.7em where
       the design is 33.9, the slop body at 22.2 where the design is 34.6);
     - a label that never got a floor at all (the slop pill at 8.9px);
     - furniture too big beside the type (the beliefs' 144u side padding);
     - an absolute offset that no longer clears the copy above it (the
       belt's top, which the taller floored copy runs straight through);
     - a two-column head that cannot hold either column (the team's).

   THE ANSWER IS THE ONE THIS PROJECT ALREADY USES — PUT THE MEASURE IN THE
   TYPE'S OWN UNITS. `calc(677em / 20)` is the node's measure over the node's
   font size, so it is 677px wherever the type is still `--u`-scaled (i.e. it
   reproduces the design EXACTLY at every desktop width) and it follows the
   floor up here. Same expression and the same reasoning as the case-study
   description's `calc(418em / 20)` and the bio copy's `34em`.

   THE DISPLAY MEASURES GO THROUGH `em` TOO, which works because those
   elements' own font-size is `88 * var(--du)`: `calc(898em / 88)` is the
   node's 898 over the node's 88. Nothing here is a number anyone chose.
   ============================================================ */
@media (min-width: 768px) and (orientation: portrait) {

  /* ---------- 1. "We've been here since 2002." ---------- */
  /* THE PHOTOS WERE ON THE WORDS BECAUSE THE WORDS GREW AND THE CLOUD DID
     NOT. The type block is floored, so it occupies far more of the panel
     than the design gives it, while the collage is placed and sized in
     plain `--u` and keeps drawing the desktop arrangement at half scale —
     i.e. a bigger target in a tighter cloud. Two levers, and they are
     genuinely separate (css/about-page.css is explicit that how tall the
     section is and how big the cloud is are two decisions):

       - `--panel-u` is the ROOM. 1295 renders 664 at 820, which is barely
         taller than the type block itself once the copy is unwrapped.
       - the four spread knobs are WHERE THE PHOTOS GO. They are pulled out
         sideways and pushed apart vertically to open the channel the type
         needs, and `--tile-k` comes down because a photo drawn at the
         desktop's 1.3 is, relative to floored type, half as far away again
         as the design has it.

     These are this breakpoint's own set, exactly as the phone block keeps
     its own — a desktop correction is not a tablet one. */
  /* THE CLOUD IS THE DESKTOP'S, RECONSTRUCTED — not a tablet arrangement
     (client, 2026-09-17: "images should be larger and positioned similar to
     desktop"). A first pass shrank the photos to 0.95 and spread them to
     clear the type, which read as a different, sparser composition; measured
     against the desktop's own tile centres as shares of the panel, it was
     3.4% / 3.2% off in x / y at 0.74 of the designed relative size.
     THE DESKTOP VALUES TRANSFER ALMOST UNCHANGED, and the arithmetic says
     why: a tile's SIZE rides `--cu` (0.652 x --u) and its horizontal place
     `--cux` (1.05 x --u), both scaling by 0.5125 at 820, while the panel is
     805 against the desktop's 1585 — a ratio of 0.508. Those are the same
     number to within 1%, so `--spread-x` and `--tile-k` are simply the
     desktop's. Only the VERTICAL differs, because the panel is taller than
     the desktop's in proportion (0.975 against 0.817), so the y spreads take
     that ratio: 1.38 x 1.206 = 1.66, 1.37 x 1.206 = 1.65. Nothing here was
     chosen by eye.
     Measured after: tile size back to **1.01 of the desktop's** relative
     size, centres within **1.7% / 2.8%** of the desktop's shares, type ink
     covered **0%**, worst tile 76% on the panel. */
  .rdk-abt-since__panel {
    --panel-u: 1560;
    --spread-x: 0.89;
    --spread-up: 1.66;
    --spread-down: 1.65;
    --tile-k: 1.3;
    /* THE LEAF IS THE ONE TILE THAT STILL HAS TO MOVE, and it is the only
       departure from the desktop's set. It sits BESIDE the headline rather
       than above or below it, so no amount of spread takes it sideways —
       the type band is 541 wide in an 805 panel and the channel either side
       is 132. Lifted on its own; its `--n8-x` is the design's.
       -240 rather than -210 because 768 is the tight case: the panel
       narrows while the type block does not (its measures are in the
       type's own units), so the channel either side closes from 132 to
       106 and the leaf's foot caught the headline there. Measured at 768,
       ink covered 0.33% -> 0.09%, and the leaf is still 75% on the panel. */
    --n8-y: -240;
  }

  /* The node's own measures, in the type's units. 900/88 and 677/20. */
  .rdk-abt-since__title { width: calc(900em / 88); }
  .rdk-abt-since__body { width: calc(677em / 20); }

  /* ---------- 2. "What we believe" ---------- */
  /* THE SIDE PADDING DROPS TO THE PAGE'S OWN CONTENT INSET, 88u (client:
     "too much padding on left and right"). 144u is 9% of the width at any
     width, so it is not proportionally wrong — it is wrong against FLOORED
     TYPE, which is 33% bigger here than the margin was drawn for.
     88 rather than a number chosen to look right: `.rdk-abt-team__panel`
     below already insets 88u, so the two white panels finally share one
     content line instead of missing each other by 30px. The title keeps its
     own 64u indent, which is the design's and is a relationship to the
     cards rather than to the page edge. */
  .rdk-abt-beliefs {
    padding-left: calc(88 * var(--u));
    padding-right: calc(88 * var(--u));
  }

  /* ---------- 3. "Agency life in the era of AI slop" ---------- */
  /* THE KICKER IS THE HERO PILL'S SIZE, FLAT. At `17.425 * var(--u)` it
     drew **8.9px** — the collapsing-unit trap again, and the reason it was
     missed is that it is the one label on the page that is not an
     `.rdk-abt__eyebrow`. It is stated flat rather than floored because the
     hero's pill directly above it on the same page at this same breakpoint
     is already a flat 17.425 (node 888:104683's own 1:1 value), and these
     two are one component: they have to read the same. The padding, the
     tracking and the ring go flat with it, or a 17px label sits in an 8px
     box. */
  .rdk-abt-slop__pill {
    padding: 8px 16px;
    font-size: 17.425px;
    letter-spacing: -0.35px;
    border-width: 2px;
  }

  .rdk-abt-slop__title { width: calc(898em / 88); }
  .rdk-abt-slop__body { width: calc(692em / 20); }

  /* THE BELT GOES UNDER THE COPY, AND IT HAS TO DO IT BY FLOW RATHER THAN
     BY A NUMBER. The panel places the copy and the belt as two ABSOLUTE
     boxes at `139 * var(--u)` and `587 * var(--u)`, which works only while
     the copy's height scales with `--u` too. Floored, the copy is a fixed
     ~356px tall at every portrait width while the belt's top goes on
     shrinking — so the screenshots ran straight through the paragraph, and
     WORSE THE NARROWER THE TABLET: measured, the first item sat 59 BELOW
     the copy at 820 and 76 ABOVE it at 768. Any pair of numbers big enough
     for 768 would open a hole at 1024.
     So the panel becomes a flow column — the phone's own arrangement, for
     the same underlying reason — and "underneath" is then true by
     construction at every width instead of being two constants to keep in
     step with type they cannot see. The absolute `top` becomes the panel's
     padding, and the belt's own top becomes a margin.
     `--slop-panel-h` is inert here, exactly as it is on the phone: the
     panel is content-sized, so `--slop-belt-h` is the section-height lever.
     The other two knobs stay live and stay in `--u`, so js/slop-tuner.js's
     desktop set still drives them. */
  .rdk-abt-slop {
    --slop-belt-top: 96;   /* the gap between the copy's foot and the belt */
    --slop-belt-h: 681;    /* the band a desktop reader actually sees of the
                              788 box: 1268 visible foot less the 587 top */
  }

  .rdk-abt-slop__panel {
    height: auto;
    /* The copy's own `top` and the 96 the team panel rides up over the
       foot, both now paid as padding. */
    padding: calc(139 * var(--u)) 0 calc(96 * var(--u));
  }

  .rdk-abt-slop__text { position: static; }

  .rdk-abt-slop__belt {
    position: relative;
    top: auto;
    margin-top: calc(var(--slop-belt-top) * var(--u));
    height: calc(var(--slop-belt-h) * var(--u));
  }

  /* ---------- 4. "The people" ---------- */
  /* THE SHARED EYEBROW GOES ON `--du`, WHICH IS WHERE THE 2026-09-16 PASS
     SHOULD HAVE PUT IT. It is Redonk Avant Garde — display type — so it
     belongs to the display unit by the same argument as everything else
     that moved then; it was missed because it is a label and the pass went
     through the size ladder. At `20 * var(--u)` it drew **10.25px** at 820
     against a 59.84 title beside it, a 5.8 : 1 step where the design's is
     4.4. On `--du` it is 13.6 and the step is the design's exactly, and the
     floor releases itself at about 1470 where `--u` overtakes 0.68.
     AND THEN FLOORED AT 15, one step past the ratio. `20 * var(--du)` alone
     is 13.6 here — the design's proportion exactly — but it is under this
     page's own floor for a small label at this breakpoint, which the bio
     role was given on 2026-09-17 for the same reason on the same day. The
     client has now reported this rule as "way too small" twice (the phone
     got its own 16px on 2026-09-16), so it errs the way they are pointing.
     As a `max()` it may only ever RAISE, and it releases itself at about
     1100 where the scaled value overtakes it. It is the page's only
     `.rdk-abt__eyebrow`, so nothing else moves with it. */
  .rdk-abt__eyebrow {
    font-size: max(15px, calc(20 * var(--du)));
    letter-spacing: max(-0.15px, calc(-0.2 * var(--du)));
  }

  /* THE HEAD STACKS, AND IT IS FORCED RATHER THAN PREFERRED. Two columns
     need `334 + 45 + 416` = 795 to hold "No handoffs." on one line AND give
     the paragraph a readable 26em; at 768 the panel has **669**. So there is
     no portrait width at which both columns work, and a rule that changed
     behaviour halfway up the range would be worse than one answer for all
     of it. Measured before: the title sat at **334 in a 334 column** — the
     knife edge this project already has a lesson about — with the paragraph
     at 16.8em over 8 lines. Stacked, the title has 669-910 against a 334
     need and the paragraph gets the node's own measure.
     Gap 40 rather than the desktop's 88: that 88 was the space BETWEEN two
     columns, and vertically it would read as a hole under the headline. */
  .rdk-abt-team__head {
    flex-direction: column;
    align-items: stretch;
    gap: calc(40 * var(--u));
  }

  .rdk-abt-team__text {
    width: calc(560em / 20);
    max-width: 100%;
    margin: 0;
  }

  /* TWO UP (client: "lets try 2-up on the team bios"). The third column was
     drawing a 210-wide card at 768 — the name inside it is `--du`-floored,
     so it was 26px type in a card sized for 16. The phone already made this
     call at its own width; the offsets have to move with the columns, or
     the middle-of-three stagger lands on a different card in a grid of two.
     `--align` is still what js/about-page.js scrubs, so the aligning-as-it-
     rises behaviour carries over unchanged. */
  .rdk-abt-team__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .rdk-abt-person:nth-child(3n + 2) { margin-top: 0; }
  .rdk-abt-person:nth-child(2n) {
    margin-top: calc(64 * var(--u) * var(--align, 1));
  }

  /* ---------- 5. the footer CTA ---------- */
  /* IT WAS A 579-WIDE BOX PINNED TO THE LEFT OF AN 805 BAND, so the copy
     inside it was centred on the wrong centre (client: "the footer CTA text
     is not centered"). css/footer.css hands tablet portrait the stacked
     mobile footer, whose `.rdk-footer__inner` is `position: static;
     width: 100%` — but THIS page overrides that width to `1130 * var(--u)`
     for its own longer heading, at (0,2,0), which beats it. The phone block
     already releases it; the portrait block never did, because the footer's
     own portrait pass went through css/footer.css and this override lives
     here. A static block box with a stated width does not centre itself. */
  body.rdk-abt .rdk-footer__inner { width: auto; }
}
