/* ============================================================
   Rulebase composition.
   ------------------------------------------------------------
   This is not the Distrify page restyled. It is the Distrify
   content laid out the way rulebase.com lays out its own page,
   section for section:

     1  hero            dark, split 52/48, nav inside it,
                        floating product card over a textured
                        right panel, video promo pinned bottom
     2  trust bar       greige, left label + logo chips
     3  features        a 278px rail of the four platform
                        modules on the left, a 3-col grid of
                        preview cards for the selected one
     4  social proof    big quote + hard numbers + attribution
     5  workforce       greige, two tabs, 2-up text/mock
     6  pull quote      one sentence, 120px of air either side
     7  compliance      dark, four guardrail cards
     8  integrations    logo rows, "runs on your stack"
     9  closing CTA     headline left, body + action right
    10  footer          brand statement left, link columns right

   Type, color, spacing, radii and shadows come from
   theme.css, which holds their real token values.
   ============================================================ */

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--c-canvas);
  color: var(--c-ink);
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  line-height: var(--t-body-lh);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; }
::selection { background: var(--c-ink); color: var(--c-canvas); }
:focus-visible { outline: 2px solid var(--c-ink); outline-offset: 3px; }

/* Keyboard users get past the navigation in one Tab. Off-screen
   until focused, so it costs sighted users nothing. */
.rb-skip { position: absolute; left: 12px; top: -48px; z-index: 200; padding: 10px 14px; background: var(--c-ink); color: #F7F7F4; border-radius: 6px; font-size: 14px; text-decoration: none; }
.rb-skip:focus { top: 12px; }

/* Rulebase pads sections by --section-x 100px, not a max-width
   container. The content simply spans the viewport inset.

   The inset is a variable because things inside a wrap sometimes
   need to undo it: the library's search bar runs full width of the
   section and pulls itself back out by exactly this much. Three
   breakpoints set it, and it must stay the only place the number
   lives, or a full-bleed child silently misses the edge at one
   width and nobody notices. */
/* The whole ladder in one place. It used to live in five rules
   across two files, and two of them disagreed: site.css set 40px
   below 1100 while pages.css set 56px below 1180, and since
   pages.css loads second the 40px rule had never once applied.
   Everything that carries the gutter now reads this variable, so
   there is one number per width and a full-bleed child can undo
   it with calc(var(--wrap-x) * -1) and land on the edge at every
   width rather than at most of them. */
:root { --wrap-x: 100px; }
@media (max-width: 1180px) { :root { --wrap-x: 56px; } }
@media (max-width: 900px)  { :root { --wrap-x: 24px; } }
@media (min-width: 1513px) { :root { --wrap-x: max(100px, 50% - 656px); } }

.rb-wrap { padding-left: var(--wrap-x); padding-right: var(--wrap-x); }

.rb-sec { padding-top: 120px; }
.rb-sec-tight { padding-top: 80px; }

/* ---------------------------------------------------------- */
/* Type                                                        */
/* ---------------------------------------------------------- */

.rb-display {         /* live: 60px / 56px / -1.8px */
  font-family: var(--f-display);
  font-size: clamp(36px, 4.4vw, 60px);
  font-weight: 400;
  line-height: 0.9334;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.rb-h2 {              /* live: 60px / 60px / -1.2px */
  font-family: var(--f-display);
  font-size: clamp(30px, 4.2vw, 60px);
  font-weight: 400;
  line-height: 1.0;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.rb-h3 {              /* --text-lg 40 / --leading-lg 44 */
  font-family: var(--f-display);
  font-size: clamp(26px, 2.8vw, 40px);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.rb-h4 {              /* --text-sm 28 / --leading-sm 36 */
  font-family: var(--f-display);
  font-size: 28px;
  font-weight: 400;
  line-height: 1.285;
  letter-spacing: -0.02em;
}
.rb-lead {            /* --text-sm2 16 / --leading-sm2 26 */
  font-size: 16px;
  line-height: 1.625;
  letter-spacing: -0.0056em;
  color: var(--c-ink-3);
  text-wrap: pretty;
}
.rb-body {            /* --text-body 14 / --leading-body 20 */
  font-size: 14px;
  line-height: 1.43;
  letter-spacing: -0.0064em;
  color: var(--c-ink-3);
  text-wrap: pretty;
}
.rb-tag {             /* --text-tag 11 / --tracking-tag 1px */
  font-size: 11px;
  line-height: 1.45;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--c-ink-4);
}
.rb-serif { font-family: 'STK Bureau Serif', Georgia, serif; font-style: italic; }

/* ---------------------------------------------------------- */
/* Buttons: small, quiet, Hedvig, 4px radius                   */
/* ---------------------------------------------------------- */

.rb-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--f-cta);
  font-size: 14px;
  font-weight: 400;
  line-height: 24px;
  padding: 6px 14px;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 160ms var(--ease), color 160ms var(--ease);
}
.rb-btn-light { background-color: #FFFFFF; color: #1A1716; }
.rb-btn-light:hover { background-color: var(--c-on-accent); }
.rb-btn-dark { background-color: #474440; color: #F7F7F4; }
.rb-btn-dark:hover { background-color: #565249; }
.rb-btn-line { border-color: var(--c-line-strong); color: var(--c-ink); }
.rb-btn-line:hover { background-color: var(--c-surface-soft); }
.rb-btn-lg { padding: 14px 22px; }

/* ---------------------------------------------------------- */
/* 1. Hero: split 52/48, dark left, textured right             */
/* ---------------------------------------------------------- */

.rb-hero {
  position: relative;
  background: var(--c-dark);
  color: var(--c-on-dark);
  display: grid;
  grid-template-columns: 52% 48%;
  min-height: 820px;
}

.rb-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  /* The bar itself animates, not this wrapper — a transform here
     would make the fixed sheet inside it resolve against the
     header instead of the viewport. */
  pointer-events: none;
}
.rb-header > * { pointer-events: auto; }

.rb-nav {
  position: relative;
  z-index: 3;
  height: 72px;
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 0 100px;
}
.rb-logo {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--f-display);
  font-size: 20px;
  font-weight: 400;
  letter-spacing: -0.03em;
  color: #F7F7F4;
  margin-right: 24px;
}
.rb-logo i { width: 6px; height: 6px; border-radius: 50%; background: #F7F7F4; display: inline-block; }
/* The mark sits a touch taller than the cap height and takes the
   text colour, so one markup serves both grounds. */
.rb-logo .rb-logo-mark { height: 1.5em; width: auto; fill: currentColor; display: block; flex: none; }

/* The same lockup on light ground — the footer. It used to carry
   its colours as inline styles on two separate copies of the
   markup, which is why the two drifted. */
.rb-logo-ink { color: var(--c-ink); font-size: 19px; }
/* A customer chip that links to the customer's site. Same box as
   the plain chip; the cursor is the only tell. */
a.rb-chip { text-decoration: none; color: inherit; }
a.rb-chip:hover img { opacity: .75; }
/* Logo above, one short line below it that says the customer's
   webshop runs on Distrify and opens that shop. */
.rb-chip-stack { flex: none; display: inline-flex; flex-direction: column; align-items: center; gap: 6px; }
.rb-chip-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px 3px 8px;
  border-radius: 100px;
  border: 1px solid var(--c-line);
  background: var(--c-surface);
  font-family: var(--f-body);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: .01em;
  color: var(--c-ink-2);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
/* The live dot: this shop is running, on Distrify, now. */
.rb-chip-tag::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--c-ok, #3F7D53); flex: none; }
.rb-chip-tag::after { content: '\2197'; font-size: 10px; color: var(--c-ink-4); }
.rb-chip-tag--story::after { content: '\2192'; }
.rb-chip-tag:hover { background: var(--c-ink); border-color: var(--c-ink); color: #F7F7F4; }
.rb-chip-tag:hover::after { color: #F7F7F4; }

/* A link into a page the release hides keeps its element and its
   text and loses its href (js/scope.js). It must not invite a click. */
a[data-unlinked] { cursor: default; }
a[data-unlinked]:hover { text-decoration: none; }
.rb-logo-ink i { background: var(--c-ink); }
.rb-nav-links { display: flex; align-items: center; gap: 28px; font-size: 15px; color: rgba(247,247,244,.82); }
/* Only the links sitting on the bar itself. Unscoped, this also
   matched every .rb-menu-item — they are anchors inside
   .rb-nav-links too — so hovering an entry in the dropdown turned
   its label white on a near-white panel. */
.rb-nav-links > a:hover { color: #FFFFFF; }
.rb-nav .rb-btn { margin-left: auto; }

/* ---------------------------------------------------------- */
/* Mega menus                                                  */
/* ------------------------------------------------------------
   DS 2.0 drew these as tinted tiles with Lucide icons on a dark
   card. This system has no saturated colour to spend on a menu,
   so the panel is the page's own greige surface with a hairline
   ring, and the hierarchy is type: the label in ink, the
   description in ink-3. Nothing in here is coloured.

   The panel is shown off the button's `aria-expanded` and the
   `hidden` attribute rather than a class, so the state a screen
   reader hears cannot drift from the state on screen. */

.rb-navitem { position: relative; display: flex; align-items: center; }
.rb-navbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.rb-navbtn:hover { color: #FFFFFF; }
.rb-caret { transition: transform var(--dur-base) var(--ease); opacity: .6; }
.rb-navbtn[aria-expanded='true'] { color: #FFFFFF; }
.rb-navbtn[aria-expanded='true'] .rb-caret { transform: rotate(180deg); }

/* The panel hangs from the nav row. The 14px offset is the gap
   the pointer has to cross, which is why wireNav gives the
   close a 140ms grace period rather than firing on pointerleave. */
.rb-menu {
  position: absolute;
  top: calc(100% + 14px);
  left: -20px;
  z-index: 40;
  padding-top: 4px;
}
.rb-menu[hidden] { display: none; }

/* The dropdown is cut from the same stone as the floating bar.
   Not conditional on .is-float the way the bar is: the bar at the
   top of the page is transparent and belongs to the hero behind
   it, but this panel is always a light object standing on top of
   the page, so it is always an object that can be made of
   something.

   Zoomed well past the bar's crop — the panel is roughly 640
   wide against the image's 2400, so `cover` shows a sixth of the
   slab and the veining comes through large and soft rather than
   as the fine tracery the 60px bar shows. Same stone, read at
   the distance the surface asks for. */
.rb-menu-card {
  background-color: var(--c-canvas);
  background-image:
    linear-gradient(rgba(243, 241, 237, .18), rgba(243, 241, 237, .18)),
    url('../assets/marble-nav.webp');
  background-size: auto, cover;
  /* Not centred. The panel is tall enough that `cover` scales by
     height and only about a quarter of the slab's width shows —
     and the middle quarter of this particular slab is its
     cleanest passage, so centring it produced a blank card. 8%
     lands on the veining at the left of the stone. */
  background-position: center, 8% center;
  border-radius: var(--r-card);
  box-shadow: var(--sh-3);
  padding: 10px;
  min-width: 332px;
  animation: rb-menu-in 160ms var(--ease) both;
}
.rb-menu-split {
  display: grid;
  grid-template-columns: 332px 300px;
  gap: 10px;
  min-width: 0;
}
@keyframes rb-menu-in { from { opacity: 0; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .rb-menu-card { animation: none; } }

.rb-menu-col { display: flex; flex-direction: column; }
.rb-menu-item {
  display: block;
  padding: 11px 14px;
  border-radius: var(--r-tile);
  color: var(--c-ink);
  transition: background-color var(--dur-fast) var(--ease);
}
/* Light with no edge to it.
   ---------------------------------------------------------------
   Three things were wrong with the obvious answer here, in order.
   A dark tint over the stone killed the veining and left a grey
   rectangle stuck to the panel. A rule down the left edge was
   --c-accent, which in this theme is near black — a mark this
   brand makes nowhere. And a flat white fill, which is what
   replaced them, has a hard boundary: measured on the rendered
   panel, the row's top and bottom edges were an eleven-level step
   running straight across a textured ground, which reads as a
   drawn line rather than as a lit row.

   A flat white plate, which is where this started. The soft
   radial that replaced it in between was chasing the wrong fault:
   the line under the row was never the fill's edge, it was a 1px
   ::after in pages.css that had leaked in from the bar. With that
   scoped away the plate is safe again — and it is the better
   answer, because a radial is brightest at one end and fades
   across the row, so the highlight was uneven along its own
   length. A plate is the same everywhere it covers. */

.rb-menu-item:hover { background-color: rgba(255, 255, 255, .55); }
/* Where you already are: the same lift as a hover, held on. No
   colour change on the label — the light is doing the work, and a
   second signal on top of it only competes with it. */
.rb-menu-item[aria-current='page'] { background-color: rgba(255, 255, 255, .55); }

.rb-menu-t { display: block; font-size: 14.5px; line-height: 1.35; letter-spacing: -0.006em; }
/* Not --c-ink-3. At 12.5px these descriptions need 4.5:1, and
   ink-3 gives 3.66 on the plain canvas — it was already under the
   line before the stone went in, and the stone's darkest passage
   takes it to 3.34. #1E1E1EAC is the lightest value that clears
   AA on both grounds. The hierarchy against the label above it is
   carried by size, which is what was doing the work anyway. */
.rb-menu-d { display: block; margin-top: 2px; font-size: 12.5px; line-height: 1.4; color: #1E1E1EAC; }

/* The promo column is the one dark thing in the menu, which is
   what makes it read as a push rather than a seventh link. */
.rb-menu-promo {
  display: flex;
  flex-direction: column;
  background: var(--c-dark);
  color: var(--c-on-dark);
  border-radius: var(--r-tile);
  padding: 20px 20px 18px;
}
.rb-menu-promo-t { font-family: var(--f-display); font-size: 19px; line-height: 1.15; letter-spacing: -0.02em; }
.rb-menu-promo-d { margin-top: 10px; font-size: 13px; line-height: 1.5; color: var(--c-on-dark-2); }
.rb-menu-promo-cta {
  margin-top: auto;
  padding-top: 20px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}
.rb-menu-promo svg { transition: transform var(--dur-base) var(--ease); }
.rb-menu-promo:hover svg { transform: translateX(3px); }

/* Below 900px `.rb-nav-links` is hidden altogether, so the panels
   go with it. The breakpoint has to be the same number in both
   places: at 1080 the buttons were still on screen while their
   panels were not, so a click did nothing. */
@media (max-width: 900px) { .rb-menu { display: none; } }

.rb-hero-left {
  position: relative;
  z-index: 2;
  padding: 152px 60px 56px 100px;
  display: flex;
  flex-direction: column;
}
.rb-hero-h1 { color: #F7F7F4; max-width: 12ch; }
.rb-hero-body { margin-top: 26px; max-width: 46ch; color: rgba(247,247,244,.72); font-size: 16px; line-height: 1.625; }
.rb-hero-cta { margin-top: 34px; display: flex; gap: 12px; }

/* Word-by-word reveal, the way their h1 animates in.

   The mask is what makes the rise read, and at 0.9334 leading it
   is shorter than the glyphs: 56px of line box against 66px of
   ink at 60px type, so `overflow: hidden` was cutting 10px off
   every descender — the g in "digital", the y in "your".

   --desc gives the mask that room back, and the negative margin
   spends it outside the line box so the line spacing is
   untouched. Both are in em, so the whole thing holds across the
   clamp.

   The start offset then has to clear the taller mask, not the
   word: 0.2em of padding on 0.9334 leading makes the mask ~121%
   of the word's height, so 102% would have left the ascenders
   peeking into the padding before the animation began. */
.rb-word {
  --desc: 0.2em;
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: var(--desc);
  margin-bottom: calc(var(--desc) * -1);
}
.rb-word > span {
  display: inline-block;
  transform: translateY(130%);
  animation: rb-rise 760ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes rb-rise { to { transform: none; } }

/* Video promo pinned to the bottom of the dark half. */
.rb-hero-mini {
  margin-top: auto;
  padding-top: 64px;
  display: flex;
  gap: 20px;
  align-items: flex-start;
  max-width: 460px;
}
.rb-mini-thumb {
  flex: none;
  width: 132px; height: 74px;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
  background: linear-gradient(120deg, #4a4642, #6d675f 45%, #3b3835);
}
.rb-mini-thumb::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 24% 58%, rgba(255,255,255,.30) 0 12px, transparent 13px),
    radial-gradient(circle at 50% 52%, rgba(255,255,255,.26) 0 13px, transparent 14px),
    radial-gradient(circle at 76% 58%, rgba(255,255,255,.22) 0 12px, transparent 13px);
}
.rb-mini-text { font-size: 13.5px; line-height: 1.5; color: rgba(247,247,244,.68); }
.rb-mini-link {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 10px; font-size: 13.5px; color: #F7F7F4;
}

/* Right half: the plaster panel with a floating product card. */
.rb-hero-right {
  position: relative;
  overflow: hidden;
  margin-top: var(--rb-hero-inset, 0px);
}
/* Warm carved plaster, in the spirit of their stone photograph.
   Built from overlapping soft radial lobes rather than a
   repeating pattern — anything periodic reads as a sunburst or
   a stripe, which is exactly the wrong texture. */
.rb-plaster {
  position: absolute; inset: 0;
  background-color: #D8D2C7;
  background-image:
    radial-gradient(58% 44% at 30% 22%, rgba(255,255,255,.85), rgba(255,255,255,0) 62%),
    radial-gradient(46% 38% at 72% 34%, rgba(255,255,255,.55), rgba(255,255,255,0) 66%),
    radial-gradient(52% 40% at 58% 68%, rgba(148,136,118,.42), rgba(148,136,118,0) 64%),
    radial-gradient(40% 34% at 22% 78%, rgba(255,255,255,.5), rgba(255,255,255,0) 68%),
    radial-gradient(44% 36% at 88% 84%, rgba(120,109,94,.38), rgba(120,109,94,0) 66%),
    linear-gradient(152deg, #E7E2D8 0%, #D2CBBE 52%, #BFB7A8 100%);
}
/* The hero surface: the photograph, on its own layer above the
   plaster rather than as a background on it, because the blurred
   lobes in .rb-plaster::after would otherwise sit on top of the
   picture and muddy it.

   The panel is portrait and every one of these pictures is
   landscape, so the fit is a zoom rather than a fit-to-frame:
   `auto 150%` scales the picture to 150% of the panel height and
   crops the rest, which puts the carved component field across
   the whole panel and leaves the slab edge and the studio ground
   outside it. Shown whole, the board became a product shot; this
   is the diffuse surface the panel is actually for.

   Pick per page with `data-hero` on <body>; the sets are below.
   Without it a page gets the marble.                            */

/* The sculpted hand. A dark photograph, so it needs neither the
   tone layer nor the nav scrim — measured off the file at the
   panel geometry, it is already #C1B09E behind the card (a
   2.11:1 step against white, the reference's range) and #48433B
   under the nav (9.14:1 against cream). */
body[data-hero='hand'] {
  --rb-hero-img: url('../assets/hero-hand.webp');
  --rb-hero-fit: cover;
  --rb-hero-pos: 47% 46%;
  --rb-hero-tone: transparent;
  --rb-hero-wash: 0;
  /* A 60px dissolve at the cut edge and nothing more. The lobe
     mask feathered half the panel and read as a milky smear over
     the hand; this one only softens the column where the
     photograph is cut, and since the ground is now the same tone
     as the photograph's own, the edge simply is not there. The
     fingertips start further in than 60px at every width. */
  --rb-hero-mask: linear-gradient(90deg, transparent 0, #000 60px);
}
/* One ground behind both halves.
   ---------------------------------------------------------------
   The photograph's backdrop is a warm grey-beige with a soft
   vignette, and the hero used to stand it beside a black column,
   so the seam ran the full height of the page. The hero now takes
   the photograph's own tone, measured on the column where the
   panel cuts it (the vignette is darker at the picture's far
   left, which the crop never shows). Cream type on it is 8.9:1.
   The plaster under the picture has to go: with the edge
   dissolved it would show through the first 60px as a light
   stripe. */
body[data-hero='hand'] .rb-hero { background: #4B4640; }
body[data-hero='hand'] .rb-plaster { display: none; }
/* The card as a pane rather than a plate: white at 78% with the
   hand softly diffused through it, a hairline that is barely
   there and a shadow that is mostly spread. The foot gives up
   its own white so the whole card is one surface; the rules
   between rows go to a low-alpha ink so they read on whatever
   shows through. Position, size, radius and content unchanged. */
body[data-hero='hand'] .rb-float-card {
  background: rgba(255, 255, 255, .78);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  /* The hairline is an inset ring, not a border, so the card's box
     stays the size it was. */
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .55),
    0 1px 1px rgba(26, 23, 22, .04),
    0 14px 36px rgba(26, 23, 22, .10);
}
body[data-hero='hand'] .rb-float-foot { background: transparent; }
body[data-hero='hand'] .rb-float-row,
body[data-hero='hand'] .rb-float-item,
body[data-hero='hand'] .rb-float-foot { border-top-color: rgba(30, 30, 30, .09); }
/* Stacked, the cut edge is the panel's top, not its left. */
@media (max-width: 900px) {
  body[data-hero='hand'] { --rb-hero-mask: linear-gradient(180deg, transparent 0, #000 60px); }
}
/* The panel is a still photograph here, so nothing in it moves.
   The spinner on the card was the only motion and it sat next to
   a line about a sync that has already happened. */
body[data-hero='hand'] .rb-float-foot .rb-spinner { display: none; }
body[data-hero='hand'] .rb-float-foot { gap: 0; }

/* The carved slab, for pages whose subject is the catalog rather
   than a person using it. Positioned so the carved half sits in
   the panel and the plain half runs off the left edge into the
   dark, which is where the words are. */
body[data-hero='slab'] {
  --rb-hero-img: url('../assets/library/pcb-slab-2400.webp');
  /* Closer than cover, but not pressed against the surface. At
     cover the whole slab sits in a white sweep and reads as a
     product shot, so what you notice is the object rather than
     what is carved into it. At 210% it was a texture and the
     component shapes stopped being readable as components. 140%
     keeps a run of packages and traces in frame with room around
     them. */
  --rb-hero-fit: auto 140%;
  --rb-hero-pos: 62% 48%;
  --rb-hero-tone: transparent;
  --rb-hero-wash: 0;
  --rb-hero-mask: none;
}
body[data-hero='slab'] .rb-float-foot .rb-spinner { display: none; }
body[data-hero='slab'] .rb-float-foot { gap: 0; }

/* The first warm circuit relief, kept for comparison. */
body[data-hero='board'] {
  --rb-hero-img: url('../assets/hero-board.webp');
  --rb-hero-fit: cover;
  --rb-hero-pos: 58% 50%;
  --rb-hero-tone: transparent;
}

/* ------------------------------------------------------------
   Cut-out mode — how the reference actually does it.

   Their hero has no seam because `stone-bg` is a PNG with an
   alpha channel at a FIXED pixel size (1371x1436), centred in a
   panel whose width is a percentage. The dark ground runs behind
   it and the stone's broken edge is the only boundary. At 1440
   the picture is wider than the panel, so it fills and reads as
   a split; past roughly 1700 the panel outgrows it and the
   silhouette detaches. That behaviour is not scripted — it falls
   out of fixed image against percentage panel.

   So: fixed size, no CSS mask, no tone layer and no scrim, since
   all three of those assume an opaque rectangle. --rb-hero-fit
   is the knob that decides at which width the silhouette breaks
   free; larger means later.
   ------------------------------------------------------------ */
body[data-hero='cutout'] {
  --rb-hero-img: url('../assets/hero-cutout.webp');
  /* The reference's stone is about twice its panel in both
     directions, so roughly half the width and half the height is
     in frame: you read a fragment of a larger mass, not an object
     sitting in space. A 940px board was fully visible top to
     bottom, which is what made it read as a product shot.

     1950px is the native width of the file — as large as it can
     go before upscaling — and leaves 35% of the width and 75% of
     the height in frame at 1440. The position puts the broken
     bottom-left corner inside the panel, so the dark ground runs
     along two edges and the mass carries off the top and right. */
  --rb-hero-fit: 1950px auto;
  --rb-hero-pos: 12% 88%;
  --rb-hero-tone: transparent;
  --rb-hero-wash: 0;
  --rb-hero-mask: none;
  --rb-hero-blur: 0px;
}
/* The plaster is the fallback surface for an opaque photograph.
   Under a cut-out it is what the alpha reveals, so the panel
   went light and the seam came back. Hiding it lets .rb-hero's
   own dark ground run behind the object, which is the whole
   point of the mode. */
body[data-hero='cutout'] .rb-plaster { display: none; }
.rb-board {
  position: absolute;
  inset: 0;
  z-index: 1;
}
/* The picture and its tone sit here; the nav scrim stays in
   ::after on the exact panel box, because that is what the nav's
   legibility is measured against.

   --rb-hero-tone is what separates the float card from the
   picture now that nothing is blurred. The reference gives its
   card no shadow at all — its blocks are flat white with a 4px
   radius — and relies purely on a tonal step: its stone means
   #C0B8A6, so white on it is a visible ~1.9:1. Our crop of the
   marble sits at #E9E5DF behind the card, which is 1.14:1, so
   the card had nothing to stand on once the blur came off.

   A warm 32% overlay lands the panel on the reference's own
   tone. It is a correction for this picture being brighter and
   cooler than the reference's limestone — generate one already
   at #C0B8A6 and this goes to `transparent`.

   --rb-hero-blur stays as a variable but is 0. When it is set,
   the over-scan keeps the blurred edge fade outside
   .rb-hero-right, which clips it. */
.rb-board::before {
  content: '';
  position: absolute;
  inset: calc(var(--rb-hero-blur, 0px) * -4);
  background-color: var(--rb-hero-bg, transparent);
  /* Tone first in the stack, so it paints over the picture. */
  background-image:
    linear-gradient(var(--rb-hero-tone, rgba(107, 90, 63, .28)),
                    var(--rb-hero-tone, rgba(107, 90, 63, .28))),
    var(--rb-hero-img, url('../assets/hero-marble.webp'));
  background-size: auto, var(--rb-hero-fit, auto 150%);
  background-position: 0 0, var(--rb-hero-pos, 44% 58%);
  background-repeat: no-repeat, no-repeat;
  filter: blur(var(--rb-hero-blur, 0px));

  /* The reference has no seam down the middle of its hero: its
     stone is a cut-out with an alpha channel, so the dark ground
     runs behind it and the stone's own broken edge is the only
     boundary. On a wide viewport the panel outgrows the picture
     and the silhouette detaches completely.

     Ours is an opaque photograph, so its left edge would land as
     a ruled vertical line at 52%. These lobes dissolve it: solid
     where the picture matters, falling away irregularly toward
     the dark half. Three offset radials rather than one, because
     a single ellipse reads as an ellipse.

     Drop a real cut-out in and set --rb-hero-mask: none — the
     alpha then does this properly and at any width. */
  -webkit-mask-image: var(--rb-hero-mask, var(--rb-mask-lobes));
          mask-image: var(--rb-hero-mask, var(--rb-mask-lobes));
  -webkit-mask-composite: source-over;
          mask-composite: add;
}

:root {
  --rb-mask-lobes:
    radial-gradient(92% 86% at 97% 46%, #000 38%, rgba(0,0,0,.88) 60%, transparent 93%),
    radial-gradient(46% 40% at 78% 12%, #000 22%, transparent 78%),
    radial-gradient(42% 38% at 84% 88%, #000 20%, transparent 76%);
}
/* A scrim for the nav band, and nothing else.

   The reference needs none: its own stone is light (mean #C0B8A6,
   white text on it is 1.84:1) but its nav links all sit inside
   the dark 52%, so they never touch it. Ours has six links and
   they do — by 29px at 1440 and 113px at 1280, which tightening
   the gaps cannot close.

   An earlier pass solved that with a corner vignette across the
   whole panel. It worked, and it darkened the picture, which is
   the opposite of what this surface is for. Confining it to the
   top ~130px keeps the panel at its natural brightness and only
   pays where the links actually land. */
.rb-board::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--rb-hero-scrim-h, 130px);
  opacity: var(--rb-hero-wash, 1);
  background: linear-gradient(to bottom,
    rgba(26, 23, 22, .68) 0%,
    rgba(26, 23, 22, .34) 46%,
    rgba(26, 23, 22, 0) 100%);
}

/* A second, softer pass of lobes offset from the first gives the
   surface its shallow carved depth. */
.rb-plaster::after {
  content: '';
  position: absolute; inset: -14%;
  background:
    radial-gradient(30% 26% at 44% 40%, rgba(255,255,255,.5), transparent 70%),
    radial-gradient(26% 22% at 64% 56%, rgba(104,94,80,.26), transparent 72%),
    radial-gradient(22% 20% at 34% 62%, rgba(255,255,255,.44), transparent 70%),
    radial-gradient(28% 24% at 78% 24%, rgba(112,102,88,.2), transparent 74%);
  filter: blur(14px);
}

/* Floated across the middle of the panel, the way the reference
   floats its chat card. It moved to the foot while the panel
   held a subject that could be covered; a diffuse surface has
   nothing to protect, so it is back. */
.rb-float-card {
  position: absolute;
  z-index: 2;
  right: 56px;
  /* Centred on the copy beside it, not on the panel.
     ------------------------------------------------------------
     At 46% the card's middle sat about 150px below the middle of
     the headline-to-button block on the left, so the two halves
     of the hero read as though they had been set independently.
     28% puts the two centres on the same line. */
  top: 28%;
  width: 420px;
  max-width: calc(100% - 80px);
  background: #FFFFFF;
  border-radius: 4px;
  box-shadow: var(--sh-2);
  overflow: hidden;
}
.rb-float-head { display: flex; align-items: center; gap: 12px; padding: 16px 18px; }
.rb-avatar {
  width: 34px; height: 34px; border-radius: 4px; flex: none;
  background: linear-gradient(135deg, #8a8175, #5d564c);
}
.rb-float-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-top: 1px solid #E8E5E3;
  font-size: 14px;
}
.rb-float-foot {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px;
  border-top: 1px solid #E8E5E3;
  background: #FFFFFF;
  font-size: 14px;
  color: var(--c-ink-3);
}
.rb-spinner {
  width: 18px; height: 18px; flex: none;
  border-radius: 4px;
  background: #1A1716;
  position: relative;
}
.rb-spinner::after {
  content: '';
  position: absolute; inset: 5px;
  border: 1.5px solid rgba(255,255,255,.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: rb-spin 900ms linear infinite;
}
@keyframes rb-spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------- */
/* Dot-matrix icons, Rulebase reading                          */
/* ------------------------------------------------------------
   Rulebase carries no saturated color anywhere, so the glyph
   hierarchy has to come from weight rather than hue: the field
   sits back at 55% ink and the emphasis dots stay solid.
   Radius is pulled in slightly to suit the softer surfaces. */

.di { display: block; }
/* Ink, not a grey. The reference draws its icons in the same
   black as the text beside them and lets the plate carry the
   contrast; ours were a light grey on a light plate, which read
   as a placeholder rather than as a mark. */
.di-rulebase circle { fill: currentColor; }
.di-rulebase .di-off { opacity: .55; }
.di-rulebase .di-on  { opacity: 1; }

/* Tile the glyphs sit on, matching --tile-bg and --radius-sm. */
.rb-glyph {
  flex: none;
  width: 40px; height: 40px;
  border-radius: 6px;
  background: var(--c-surface-warm);
  color: var(--c-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color 160ms var(--ease);
}
/* When the class lands on the <svg> itself (js/page.js draws it
   that way) the size argument is dead — CSS stretches the artwork
   to the full 40px plate and it sits there edge to edge. The
   reference keeps a wide margin: artwork about 40% of the plate.
   Padding on the svg root gives the drawing its own content box
   back, so the plate reads as a plate. */
svg.rb-glyph { padding: 11px; box-sizing: border-box; }
.rb-card:hover .rb-glyph { background: var(--c-surface-soft); }
.rb-glyph-sm { width: 34px; height: 34px; }
.rb-glyph-dark { background: rgba(247,247,244,.08); color: #F7F7F4; }

/* ---------------------------------------------------------- */
/* 2. Trust bar                                                */
/* ---------------------------------------------------------- */

.rb-trust {
  background: var(--c-canvas);
  padding: 28px 100px;
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: center;
  gap: 40px;
}
.rb-trust-label { font-size: 14px; line-height: 1.43; color: var(--c-ink-3); max-width: 24ch; }
.rb-trust-rail {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.rb-trust-track {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  width: max-content;
  /* The duration here is only a fallback for a rail that renders
     before its script runs; pace() in components.js replaces it
     with one derived from the track's real width, so every rail
     moves at the same px/s regardless of how many logos it holds. */
  animation: rb-marquee 46s linear infinite;
}
.rb-trust-track:hover { animation-play-state: paused; }
@keyframes rb-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* Measured off their `trust-logo-pill`: a 6% wash of #545252
   rather than a filled tile, 51px tall, 6px radius, 12/16
   padding, and the mark itself at 24px and full strength. Ours
   was a solid --c-surface-soft box with the logo greyed to 70%,
   which read as a row of grey cards with something faint inside
   them. */
.rb-chip {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  height: 51px; padding: 12px 16px;
  border-radius: 6px;
  background: #5452520f;
  font-family: var(--f-display);
  font-size: 20px;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--c-ink);
  white-space: nowrap;
}

/* ---------------------------------------------------------- */
/* 3. Features                                                 */
/* ---------------------------------------------------------- */

.rb-feature-tabs { display: flex; gap: 60px; margin-top: 44px; border-bottom: 1px solid var(--c-line); }
.rb-feature-tab {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: none; border: none; padding: 0 0 16px;
  font-size: 16px; line-height: 1.625; color: var(--c-ink-4);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 160ms var(--ease), border-color 160ms var(--ease), opacity 160ms var(--ease);
}
.rb-feature-tab .di { opacity: .45; transition: opacity 160ms var(--ease); }
.rb-feature-tab[aria-selected='true'] { color: var(--c-ink); border-bottom-color: var(--c-ink); }
.rb-feature-tab[aria-selected='true'] .di { opacity: 1; }

.rb-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 32px;
  align-items: center;
  margin-top: 48px;
}
.rb-panel {
  background: var(--c-surface-soft);
  border-radius: 12px;
  padding: 40px;
}
.rb-card-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 40px 10px;
  margin-top: 56px;
}
.rb-card {
  background: var(--c-surface);
  border-radius: 12px;
  padding: 24px;
  box-shadow: var(--sh-2);   /* their --shadow-card */
}
.rb-card-num {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--c-ink-4);
}

/* Product mock, Rulebase flavour: white, 12px radius, hairline rows. */
.rb-mock { background: #FFFFFF; border-radius: 12px; box-shadow: var(--sh-2); overflow: hidden; }
.rb-mock-head {
  padding: 14px 18px;
  border-bottom: 1px solid #E8E5E3;
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; color: var(--c-ink-3);
}
.rb-mock-row {
  display: grid;
  grid-template-columns: minmax(0,1fr) auto auto;
  gap: 14px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid #F0EEEC;
  font-size: 14px;
}
.rb-mock-row:last-child { border-bottom: 0; }
.rb-mock-pn { font-family: var(--f-mono); font-size: 12.5px; }
.rb-pill {
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .04em;
  padding: 4px 10px; border-radius: 100px;
  background: var(--c-surface-soft); color: var(--c-ink-3);
}
.rb-pill-ok   { background: #E2EDE5; color: #2F6B45; }
.rb-pill-warn { background: #F6E7DA; color: #A6521A; }
.rb-bar { height: 8px; border-radius: 100px; background: #E8E5E3; overflow: hidden; }
.rb-bar span { display: block; height: 100%; background: #1A1716; border-radius: 100px; }

/* ---------------------------------------------------------- */
/* 4. Social proof                                             */
/* ---------------------------------------------------------- */

.rb-social {
  display: grid;
  grid-template-columns: minmax(0, 471px) minmax(0, 558px);
  gap: 80px 120px;
  align-items: start;
  margin-top: 56px;
}
.rb-quote-lg { font-family: var(--f-display); font-size: 28px; font-weight: 400; line-height: 1.285; letter-spacing: -0.02em; text-wrap: pretty; }
.rb-stats { display: flex; gap: 60px; margin-top: 40px; }
.rb-stat-n { font-family: var(--f-display); font-size: 40px; font-weight: 400; line-height: 1.1; letter-spacing: -0.02em; }
.rb-stat-l { font-size: 14px; line-height: 1.43; color: var(--c-ink-4); margin-top: 6px; max-width: 18ch; }
.rb-attrib { display: flex; align-items: center; gap: 12px; margin-top: 40px; }
/* The Telcona illustration beside the quote: a marble plate the
   size of the old revenue mock, the tile render centred on it. */
.rb-proof-flow { margin-top: 56px; }

/* Three nodes on two wires: customer's ERP, Distrify, the tool. */
.rb-link3 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(80px, .9fr) auto minmax(80px, .9fr) minmax(0, 1fr);
  align-items: start; gap: 0;
}
.rb-link3-node { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.rb-link3-logo {
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 300px; height: 120px; padding: 0 32px; box-sizing: border-box;
  background: var(--c-surface); border: 1px solid var(--c-line); border-radius: 14px;
  box-shadow: var(--sh-3, 0 8px 24px rgba(0,0,0,.06));
}
.rb-link3-logo img { max-width: 100%; max-height: 34px; width: auto; height: auto; }
.rb-link3-sub { font-size: 13px; line-height: 1.4; color: var(--c-ink-4); max-width: 22ch; }
.rb-link3-hub { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.rb-link3-mark {
  display: flex; align-items: center; justify-content: center;
  width: 120px; height: 120px; border-radius: 50%;
  background: var(--c-dark); box-shadow: 0 18px 40px rgba(0,0,0,.22);
}
.rb-link3-mark .rb-logo-mark { width: 48px; height: 60px; display: block; }
.rb-link3-mark .rb-logo-mark path { fill: #F7F7F4; }
.rb-link3-hub .rb-link3-sub { color: var(--c-ink); font-weight: 500; }
.rb-link3-wire { position: relative; height: 120px; }
.rb-link3-wire::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--c-line-strong); }
.rb-link3-wire b {
  position: absolute; left: 50%; top: calc(50% + 12px); transform: translateX(-50%);
  font-family: var(--f-mono); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--c-ink-4); white-space: nowrap; font-weight: 400;
}
.rb-link3-dot { position: absolute; top: calc(50% - 4px); width: 8px; height: 8px; border-radius: 50%; background: var(--c-ink); }
.rb-link3-dot.is-in   { animation: rb-link3-r 4s linear infinite; }
.rb-link3-dot.is-out  { animation: rb-link3-l 4s linear infinite; }
.rb-link3-dot.is-back { background: var(--c-ok); animation: rb-link3-r 4s linear infinite 2s; }
@keyframes rb-link3-r { 0% { left: 0; opacity: 0; } 8% { opacity: 1; } 42% { left: calc(100% - 8px); opacity: 1; } 50%, 100% { left: calc(100% - 8px); opacity: 0; } }
@keyframes rb-link3-l { 0% { left: calc(100% - 8px); opacity: 0; } 8% { opacity: 1; } 42% { left: 0; opacity: 1; } 50%, 100% { left: 0; opacity: 0; } }
.rb-link3-cap { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 36px; font-size: 15px; color: var(--c-ink-2); }
.rb-link3-cap i { width: 8px; height: 8px; border-radius: 50%; background: var(--c-ok); animation: rb-fa-pulse-dot 1.8s ease-out infinite; }
@media (max-width: 760px) {
  /* Stacked: logo, wire, hub, wire, logo. The compact variant's
     selectors are repeated here so this rule wins on specificity. */
  .rb-link3, .rb-link3-col .rb-link3 { grid-template-columns: 1fr; gap: 14px; justify-items: center; }
  .rb-link3-col .rb-link3-logo { width: 200px; height: 68px; }
  .rb-link3-col .rb-link3-sub { max-width: 30ch; }
  .rb-link3-col .rb-link3-cap { text-align: center; }
  .rb-link3-wire { height: 60px; width: 1px; }
  .rb-link3-wire::before { left: 0; right: auto; top: 0; bottom: 0; width: 1px; height: auto; }
  .rb-link3-dot { display: none; }
  .rb-link3-wire b { top: 50%; transform: translate(-50%, -50%); background: var(--c-canvas); padding: 0 6px; }
}
@media (prefers-reduced-motion: reduce) { .rb-link3-dot, .rb-link3-cap i { animation: none; } }
/* The Telcona diagram beside the quote: half the size of a full
   width one, so it sits at the quote's height. */
.rb-link3-col { align-self: center; }
.rb-link3-col .rb-link3 { grid-template-columns: minmax(0, 1fr) minmax(36px, .5fr) auto minmax(36px, .5fr) minmax(0, 1fr); }
.rb-link3-col .rb-link3-logo { height: 76px; padding: 0 18px; border-radius: 10px; }
.rb-link3-col .rb-link3-logo img { max-height: 24px; }
.rb-link3-col .rb-link3-mark { width: 76px; height: 76px; }
.rb-link3-col .rb-link3-mark .rb-logo-mark { width: 30px; height: 38px; }
.rb-link3-col .rb-link3-wire { height: 76px; }
.rb-link3-col .rb-link3-wire b { display: none; }  /* no room at this size; the captions say it */
.rb-link3-col .rb-link3-sub { font-size: 12px; }
.rb-link3-col .rb-link3-cap { margin-top: 24px; font-size: 14px; color: var(--c-ink-3); }
.rb-avatar-lg { width: 56px; height: 56px; border-radius: 6px; overflow: hidden; background: var(--c-surface-warm); }
.rb-avatar-lg img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* ---------------------------------------------------------- */
/* 5. Workforce band                                           */
/* ---------------------------------------------------------- */

.rb-band-soft { background: var(--c-canvas); padding-bottom: 120px; }

/* ---------------------------------------------------------- */
/* 6. Pull quote                                               */
/* ---------------------------------------------------------- */

.rb-pull { padding: 120px 100px; }
.rb-pull p {
  font-family: var(--f-display);
  font-size: clamp(26px, 3vw, 40px);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.02em;
  max-width: 22ch;
  text-wrap: balance;
}
.rb-pull footer { margin-top: 32px; font-size: 14px; color: var(--c-ink-4); }
/* The wide pull: one statement set across the measure.
   ---------------------------------------------------------------
   The 22ch cap is right for a sentence that stands beside empty
   canvas by design; the franchised page's line is a full-width
   claim under a full-width card, and capped it left two thirds
   of the band empty. The sentence is 1235px at 40px, so it only
   fits one line where the measure is 1312px: from the 1513px
   step up, where the cap comes off. Below that it is two lines,
   and the break has to land on the full stop or it looks like an
   accident. 30ch takes the first sentence (680px) and refuses
   the first word of the second (815px), and `pretty` rather
   than the base `balance` fills the first line greedily —
   balanced, the evenest split is mid-sentence. The block is
   three fifths of the measure: wider than the column it was,
   short of the band. The emphasis keeps its band under the
   word, drawn thin: a 0.16em bar under 40px type was a
   highlighter, 0.05em is a hairline. */
.rb-pull-wide p { max-width: 30ch; text-wrap: pretty; }
@media (min-width: 1513px) { .rb-pull-wide p { max-width: none; } }
:root .rb-pull-wide p .rb-serif { background-size: 100% 0.05em; }

/* ---------------------------------------------------------- */
/* 7. Compliance band, dark                                    */
/* ---------------------------------------------------------- */

.rb-dark { background: var(--c-dark); color: var(--c-on-dark); padding: 100px; }
.rb-dark .rb-lead, .rb-dark .rb-body { color: rgba(247,247,244,.66); }
.rb-dark .rb-tag { color: rgba(247,247,244,.5); }
.rb-guards { display: flex; gap: 20px; margin-top: 56px; }

/* ---------------------------------------------------------- */
/* 8. Why now: four pressures, each with its chart             */
/* ---------------------------------------------------------- */
.rb-now-eyebrow { color: rgba(247,247,244,.55); }
.rb-now-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 64px; align-items: start;
}
.rb-now-media { position: sticky; top: 96px; min-width: 0; }
.rb-now-media .rb-scrub { width: 100%; height: auto; display: block; margin-top: 28px; }
/* The cards pile up: each one sticks under the header and the
   next slides over it, a step lower so the pile reads as a pile.
   Opaque, so the card underneath does not show through. */
.rb-now-grid { display: grid; grid-template-columns: 1fr; gap: 28vh; padding-bottom: 12vh; }
.rb-now-card { position: sticky; top: calc(96px + var(--i, 0) * 16px); min-height: 620px; }
/* Equal heights: a taller card underneath would otherwise peek out
   below a shorter one on top of the pile. */
.rb-now-card:nth-child(1) { --i: 0; }
.rb-now-card:nth-child(2) { --i: 1; }
.rb-now-card:nth-child(3) { --i: 2; }
.rb-now-card:nth-child(4) { --i: 3; }
.rb-now-card {
  background: var(--c-dark-2);
  box-shadow: 0 -18px 40px rgba(0,0,0,.35);
  border: 1px solid rgba(247,247,244,.1);
  border-radius: 12px;
  padding: 32px 30px 26px;
  display: flex; flex-direction: column;
}
.rb-now-n { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: rgba(247,247,244,.5); }
.rb-now-card h3 { margin-top: 14px; font-family: var(--f-display); font-size: 26px; font-weight: 400; line-height: 1.15; letter-spacing: -0.02em; max-width: 22ch; text-wrap: pretty; }
.rb-now-card > p { margin-top: 14px; font-size: 15px; line-height: 1.55; color: rgba(247,247,244,.66); max-width: 58ch; }
.rb-now-card footer { margin-top: 18px; font-size: 12px; line-height: 1.5; color: rgba(247,247,244,.38); }
.rb-now-chart { margin: 28px 0 0; padding: 22px 22px 18px; border-radius: 8px; background: rgba(247,247,244,.04); border: 1px solid rgba(247,247,244,.08); }
.rb-now-chart figcaption { margin-top: 14px; font-size: 12px; color: rgba(247,247,244,.5); }

/* Bars: two columns, the highlighted one in cream. Height comes
   from --h (0..1); it grows when the card scrolls into view. */
.rb-now-bars { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: end; }
.rb-now-bars figcaption { grid-column: 1 / -1; }
.rb-now-bar { display: flex; flex-direction: column; align-items: stretch; gap: 8px; height: 170px; justify-content: flex-end; }
.rb-now-bar i {
  display: block; height: calc(120px * var(--h)); border-radius: 3px 3px 0 0;
  background: rgba(247,247,244,.28);
  transform-origin: bottom; transform: scaleY(0);
  transition: transform 900ms var(--ease);
}
.rb-now-bar.is-hi i { background: #F7F7F4; }
.is-in .rb-now-bar i { transform: scaleY(1); }
.is-in .rb-now-bar:nth-child(2) i { transition-delay: 160ms; }
.rb-now-bar-v { font-family: var(--f-display); font-size: 28px; letter-spacing: -0.02em; line-height: 1; }
.rb-now-bar.is-hi .rb-now-bar-v { color: #F7F7F4; }
.rb-now-bar:not(.is-hi) .rb-now-bar-v { color: rgba(247,247,244,.6); }
.rb-now-bar-l { font-size: 13px; color: rgba(247,247,244,.6); }

/* Matrix: who is on which channel. */
.rb-now-matrix { display: flex; flex-direction: column; gap: 10px; }
.rb-now-mx-head, .rb-now-mx-row { display: grid; grid-template-columns: 1.5fr repeat(4, 1fr); align-items: center; gap: 8px; }
.rb-now-mx-head span { font-size: 11px; letter-spacing: .6px; text-transform: uppercase; color: rgba(247,247,244,.45); text-align: center; }
.rb-now-mx-head span:first-child { text-align: left; }
.rb-now-mx-row { padding: 10px 0; border-top: 1px solid rgba(247,247,244,.08); }
.rb-now-mx-row span { font-size: 13px; color: rgba(247,247,244,.7); }
.rb-now-mx-row b { justify-self: center; width: 22px; height: 22px; border-radius: 50%; border: 1px solid rgba(247,247,244,.18); position: relative; opacity: 0; transform: scale(.6); transition: opacity 500ms var(--ease), transform 500ms var(--ease); }
.rb-now-mx-row b.on { background: rgba(247,247,244,.9); border-color: transparent; }
.rb-now-mx-row b.on::after { content: ''; position: absolute; left: 7px; top: 4px; width: 5px; height: 9px; border: solid var(--c-dark); border-width: 0 1.6px 1.6px 0; transform: rotate(45deg); }
.rb-now-mx-row b:not(.on)::after { content: ''; position: absolute; left: 6px; top: 10px; width: 9px; height: 1px; background: rgba(247,247,244,.3); }
.rb-now-mx-row.is-hi span { color: #F7F7F4; }
.rb-now-mx-row.is-hi b.on { background: var(--c-ok); }
.rb-now-mx-row.is-hi b.on::after { border-color: #F7F7F4; }
.is-in .rb-now-mx-row b { opacity: 1; transform: none; }
.is-in .rb-now-mx-row b:nth-of-type(2) { transition-delay: 90ms; }
.is-in .rb-now-mx-row b:nth-of-type(3) { transition-delay: 180ms; }
.is-in .rb-now-mx-row b:nth-of-type(4) { transition-delay: 270ms; }
.is-in .rb-now-mx-row:nth-child(4) b { transition-delay: 500ms; }

/* Timeline: four points on one line, the last one lit. */
.rb-now-tl { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; padding-top: 18px; }
.rb-now-tl::before { content: ''; position: absolute; left: 6px; right: 6px; top: 23px; height: 1px; background: rgba(247,247,244,.18); }
.rb-now-tl-p { display: flex; flex-direction: column; gap: 8px; opacity: 0; transform: translateY(6px); transition: opacity 500ms var(--ease), transform 500ms var(--ease); }
.rb-now-tl-p i { display: block; width: 11px; height: 11px; border-radius: 50%; background: var(--c-dark); border: 1px solid rgba(247,247,244,.6); box-sizing: border-box; }
.rb-now-tl-p.is-hi i { background: #F7F7F4; border-color: #F7F7F4; box-shadow: 0 0 0 4px rgba(247,247,244,.14); }
.rb-now-tl-p b { font-weight: 500; font-size: 13px; color: #F7F7F4; margin-top: 4px; }
.rb-now-tl-p span { font-size: 12.5px; line-height: 1.45; color: rgba(247,247,244,.6); }
.is-in .rb-now-tl-p { opacity: 1; transform: none; }
.is-in .rb-now-tl-p:nth-child(2) { transition-delay: 140ms; }
.is-in .rb-now-tl-p:nth-child(3) { transition-delay: 280ms; }
.is-in .rb-now-tl-p:nth-child(4) { transition-delay: 420ms; }

@media (max-width: 900px) {
  .rb-now-layout { grid-template-columns: 1fr; gap: 32px; }
  .rb-now-media { position: static; }
  /* No scrubbed clip on a phone: nothing is pinned there, and the
     first frame of the clip is black. */
  .rb-now-media .rb-scrub { display: none; }
  .rb-now-grid { gap: 20px; padding-bottom: 0; min-width: 0; }
  /* min-width: 0 on every grid child: a grid item defaults to
     min-width auto and its min-content (the matrix head, the bar
     values) pushed the whole column past the viewport. */
  .rb-now-media, .rb-now-card { min-width: 0; }
  .rb-now-card { position: static; min-height: 0; padding: 26px 22px 22px; overflow: hidden; }
  .rb-now-card h3 { font-size: 22px; }
  .rb-now-chart { padding: 16px 14px 14px; }
  .rb-now-mx-head span { font-size: 9.5px; letter-spacing: .3px; }
  .rb-now-mx-head, .rb-now-mx-row { grid-template-columns: 1.3fr repeat(4, 1fr); gap: 4px; }
  .rb-now-mx-row span { font-size: 12px; }
  .rb-now-bar-v { font-size: 22px; }
  .rb-now-tl { grid-template-columns: 1fr 1fr; row-gap: 22px; }
  .rb-now-tl::before { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .rb-now-bar i, .rb-now-mx-row b, .rb-now-tl-p { transition: none; transform: none; opacity: 1; }
}
.rb-guard {
  flex: 1;
  background: rgba(247,247,244,.05);
  border: 1px solid rgba(247,247,244,.1);
  border-radius: 12px;
  padding: 28px 24px;
  min-height: 210px;
  display: flex;
  flex-direction: column;
}
.rb-guard h3 { font-family: var(--f-display); font-size: 20px; font-weight: 400; letter-spacing: -0.02em; }
.rb-guard p { margin-top: 12px; font-size: 14px; line-height: 1.5; color: rgba(247,247,244,.6); }

/* ---------------------------------------------------------- */
/* 8. Integrations                                             */
/* ---------------------------------------------------------- */

.rb-int-rows { display: flex; flex-direction: column; gap: 12px; margin-top: 56px; }
.rb-int-row {
  display: flex; gap: 12px; width: max-content;
  animation: rb-marquee 60s linear infinite;
}
.rb-int-row.rev { animation-direction: reverse; animation-duration: 74s; }
.rb-int-mask {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.rb-int-cell {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  height: 68px; min-width: 168px; padding: 0 26px;
  border: 1px solid var(--c-line);
  border-radius: 12px;
  background: var(--c-surface);
  font-size: 15px;
  color: var(--c-ink-3);
  white-space: nowrap;
  text-decoration: none;
  transition: border-color 160ms var(--ease), color 160ms var(--ease);
}
/* The cells are links now, so they have to behave like them. */
a.rb-int-cell:hover { border-color: var(--c-line-strong); color: var(--c-ink); }
.rb-int-cell img {
  height: 22px; width: auto; max-width: 132px;
  object-fit: contain;
}
.rb-int-cell img[data-tall] { height: 32px; max-width: 150px; }
/* The three that are ours carry no wordmark, so they say their
   name — and say it in the ink the logos are drawn in, or they
   read as the odd ones out rather than as part of the row. */
.rb-int-word { color: var(--c-ink-2); display: inline-flex; align-items: center; gap: 10px; }
.rb-int-glyph { flex: none; }

/* The stack section is a split: ERP half above, channel half below.
   The lower statement sits bottom-right, mirroring the upper one. */
.rb-stack-split { padding: 36px 0; }
.rb-stack-split span { display: block; height: 1px; background: var(--c-line); }
.rb-int-rows-below { margin-top: 0; }
.rb-stack-below { display: flex; flex-direction: column; align-items: flex-end; text-align: right; margin-top: 56px; }
.rb-stack-below .rb-h2, .rb-stack-below .rb-lead { text-align: right; }
@media (max-width: 900px) {
  .rb-stack-below { align-items: flex-start; text-align: left; }
  .rb-stack-below .rb-h2, .rb-stack-below .rb-lead { text-align: left; }
}

/* ---------------------------------------------------------- */
/* 9. Closing CTA                                              */
/* ---------------------------------------------------------- */

.rb-catch {
  display: grid;
  grid-template-columns: minmax(0, 652px) minmax(0, 363px);
  gap: 115px;
  align-items: start;
  padding: 120px 100px;
}
.rb-form { display: flex; flex-direction: column; gap: 10px; margin-top: 24px; }
.rb-input {
  font-family: var(--f-body);
  font-size: 14px;
  padding: 12px 14px;
  border: 1px solid var(--c-line-strong);
  border-radius: 4px;
  background: var(--c-surface);
  color: var(--c-ink);
}
.rb-input::placeholder { color: var(--c-ink-4); }

/* ---------------------------------------------------------- */
/* 10. Footer                                                  */
/* ---------------------------------------------------------- */

.rb-footer { padding: 64px 100px 40px; border-top: 1px solid var(--c-line); }
.rb-footer-top { display: grid; grid-template-columns: minmax(0, 603px) minmax(0, 637px); gap: 40px; }
.rb-footer-blurb { margin-top: 18px; max-width: 34ch; }
.rb-footer-cols { display: flex; flex-wrap: wrap; gap: 32px 72px; }
.rb-footer-h { font-size: 14px; font-weight: 500; margin-bottom: 14px; font-family: inherit; letter-spacing: normal; line-height: inherit; }
.rb-footer-col a { display: block; font-size: 14px; line-height: 2; color: var(--c-ink-3); }
.rb-footer-col a:hover { color: var(--c-ink); }
.rb-footer-bar {
  margin-top: 56px; padding-top: 24px;
  border-top: 1px solid var(--c-line);
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 16px;
  font-size: 13px; color: var(--c-ink-4);
}

/* ---------------------------------------------------------- */
/* Responsive                                                  */
/* ---------------------------------------------------------- */

@media (max-width: 1100px) {
  .rb-wrap, .rb-trust, .rb-dark, .rb-pull, .rb-catch, .rb-footer {
    padding-left: var(--wrap-x); padding-right: var(--wrap-x);
  }
  .rb-nav { padding: 0 40px; }
  .rb-hero-left { padding: 140px 40px 48px; }
  .rb-guards { flex-wrap: wrap; }
  .rb-guard { flex: 1 1 240px; }
}
@media (max-width: 900px) {
  .rb-hero { grid-template-columns: 1fr; min-height: 0; }
  /* Phone: no stone picture, only the live request feed, in the
     flow of the dark hero and full width. The image was cropped
     to a corner and the card sat off centre on it. */
  .rb-hero-right { height: auto; overflow: visible; padding: 0 24px 44px; margin-top: 0; }
  body .rb-hero-right .rb-plaster, body .rb-hero-right .rb-board, body .rb-hero-right > video { display: none !important; }
  .rb-hero-right::before, .rb-hero-right::after { display: none !important; }
  .rb-float-card { position: static; width: 100%; max-width: none; margin: 0; }
  .rb-trust { grid-template-columns: 1fr; gap: 20px; }
  .rb-split, .rb-social, .rb-catch, .rb-footer-top { grid-template-columns: 1fr !important; gap: 40px; }
  .rb-card-grid { grid-template-columns: 1fr 1fr; }
  .rb-sec { padding-top: 72px; }
  .rb-dark, .rb-pull, .rb-catch { padding-top: 72px; padding-bottom: 72px; }
  .rb-nav-links { display: none; }
  .rb-stats { gap: 32px; }
}
@media (max-width: 620px) {
  .rb-card-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .rb-word > span { animation: none; transform: none; }
  .rb-trust-track, .rb-int-row, .rb-spinner::after { animation: none; }
  html { scroll-behavior: auto; }
}

/* ---------------------------------------------------------- */
/* Sales channels page                                         */
/* ---------------------------------------------------------- */

.rb-group { margin-bottom: 64px; }
.rb-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--c-line);
}
.rb-group-head h2 {
  font-family: var(--f-display);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.285;
}
.rb-group-note { font-size: 14px; line-height: 1.43; color: var(--c-ink-4); max-width: 460px; text-align: right; }

.rb-ch-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px 10px; margin-top: 24px; }
.rb-ch-card {
  display: flex;
  flex-direction: column;
  background: var(--c-surface);
  border-radius: 12px;
  padding: 24px;
  box-shadow: var(--sh-2);
  transition: box-shadow 180ms var(--ease), transform 180ms var(--ease);
}
.rb-ch-card:hover { box-shadow: var(--sh-3); transform: translateY(-2px); }
.rb-ch-mark {
  width: 40px; height: 40px;
  border-radius: 4px;
  background: var(--c-surface-warm);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--f-mono);
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--c-ink-3);
}
/* A logo mark needs room and no tile: the tinted square was there
   to give a two-letter monogram a body, and behind a real logo it
   reads as a second, competing box. */
.rb-ch-mark-logo {
  width: auto;
  min-width: 40px;
  max-width: 116px;
  background: none;
  justify-content: flex-start;
}
.rb-ch-mark-logo img {
  max-height: 26px;
  max-width: 116px;
  width: auto;
  object-fit: contain;
}

.rb-ch-name {
  font-family: var(--f-display);
  font-size: 20px;
  font-weight: 400;
  letter-spacing: -0.02em;
  margin-top: 18px;
  overflow-wrap: anywhere;
}
.rb-ch-pill {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  line-height: 1.45;
  letter-spacing: 1px;
  text-transform: uppercase;
  border-radius: 100px;
  padding: 3px 10px;
  margin-top: 10px;
  align-self: flex-start;
}
/* Rulebase carries no accent colour, so status is weight and
   fill, not hue: live is solid ink, the rest are outlined. */
.rb-ch-pill-live { background: var(--c-dark); color: var(--c-on-dark); }
.rb-ch-pill-soon { border: 1px solid var(--c-line-strong); color: var(--c-ink-4); }
.rb-ch-pill-compatible { border: 1px solid var(--c-line-strong); color: var(--c-ink-4); }
.rb-ch-desc { font-size: 14px; line-height: 1.43; color: var(--c-ink-3); margin-top: 14px; text-wrap: pretty; }
.rb-ch-cta {
  margin-top: auto;
  padding-top: 20px;
  display: flex; align-items: center; gap: 7px;
  font-family: var(--f-cta);
  font-size: 14px;
  color: var(--c-ink);
}
.rb-ch-go { opacity: 0; transform: translateX(-4px); color: var(--c-ink-4); transition: opacity 180ms, transform 180ms; }
.rb-ch-card:hover .rb-ch-go { opacity: 1; transform: none; }

/* Hero card on the plaster panel, channel flavour */
.rb-float-list { display: flex; flex-direction: column; }
.rb-float-item {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px;
  border-top: 1px solid #E8E5E3;
  font-size: 14px;
}

/* Flow diagram, Rulebase reading: ink on their dark brown,
   no accent colour — the active path is cream, not chartreuse. */
.rb-flow {
  --fl-line: rgba(247, 247, 244, 0.14);
  --fl-route: rgba(247, 247, 244, 0.42);
  --fl-pulse: #F7F7F4;
  --fl-accent: #F7F7F4;
  --fl-label: rgba(247, 247, 244, 0.55);
  --fl-label-font: var(--f-mono);
  --fl-cust-bg: rgba(247, 247, 244, 0.06);
  --fl-cust-border: rgba(247, 247, 244, 0.16);
  --fl-cust-fg: #F7F7F4;
  --fl-node-bg: #FFFFFF;
  --fl-node-border: #D9D7D5;
  --fl-node-fg: #1E1E1E;
  --fl-node-font: var(--f-display);
  --fl-node-radius: 12px;
  --fl-node-shadow: 0 2px 6px rgba(0, 0, 0, 0.28);
  --fl-hub-bg: #FFFFFF;
  --fl-hub-border: #FFFFFF;
  --fl-hub-fg: #1E1E1E;
  --fl-hub-radius: 12px;
  --fl-hub-mark-font: var(--f-display);
  --fl-hub-shadow: 0 12px 32px rgba(0, 0, 0, 0.36);
  --fl-glyph-radius: 4px;
  --fl-glyph-bg: #E4E1DF;
  --fl-halo-glow: rgba(247, 247, 244, 0.12);
  --fl-payload-bg: rgba(247, 247, 244, 0.08);
  --fl-modules-radius: 12px;
}
.rb-flow .fl-hub-mark i { background: #1E1E1E; }

@media (max-width: 1100px) { .rb-ch-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px) {
  .rb-ch-grid { grid-template-columns: 1fr; }
  .rb-group-head { flex-direction: column; gap: 10px; }
  .rb-group-note { text-align: left; }
}

/* ---------------------------------------------------------- */
/* Franchised distributors page                                */
/* ---------------------------------------------------------- */

.rb-fs { padding-top: 120px; }
.rb-fs-split { display: flex; gap: 64px; align-items: center; }
.rb-fs-split > * { flex: 1 1 0; min-width: 0; }
.rb-fs-split[data-flip='true'] { flex-direction: row-reverse; }

.rb-fs-bullets { list-style: none; padding: 0; margin: 28px 0 0; display: grid; gap: 14px; }
.rb-fs-bullets li { display: flex; gap: 14px; align-items: center; font-size: 16px; line-height: 1.625; color: var(--c-ink-3); }

/* Rulebase frames product shots the same way it frames cards:
   white, 12px, the three-layer card shadow, no browser chrome
   dots — their mocks are quieter than that. */
.rb-fs-frame {
  background: #FFFFFF;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--sh-2);
}
.rb-fs-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid #E8E5E3;
  font-size: 13px;
  color: var(--c-ink-3);
}
.rb-fs-shot { min-height: 340px; display: flex; flex-direction: column; }

.rb-gap-card {
  background: var(--c-surface);
  border-radius: 12px;
  padding: 30px;
  box-shadow: var(--sh-2);
  transition: box-shadow 180ms var(--ease), transform 180ms var(--ease);
}
.rb-gap-card:hover { box-shadow: var(--sh-3); transform: translateY(-2px); }

/* Webshop / API mocks in Rulebase clothing */
.rb-ws-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto auto;
  gap: 14px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid #F0EEEC;
  font-size: 13px;
}
.rb-ws-row:last-child { border-bottom: 0; }
.rb-api-code {
  background: var(--c-dark);
  color: #F7F7F4;
  padding: 18px;
  font-family: var(--f-mono);
  font-size: 12.5px;
  line-height: 1.75;
  flex: 1;
}
.rb-api-code .k { color: #FFFFFF; font-weight: 600; }
.rb-api-code .c { opacity: .5; }

.rb-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; padding: 18px; }
.rb-kpi { border-radius: 4px; background: var(--c-surface-warm); padding: 12px; }
.rb-kpi-l { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--c-ink-4); }
.rb-kpi-v { font-family: var(--f-display); font-size: 22px; line-height: 1; letter-spacing: -0.02em; margin-top: 8px; }
.rb-chart { display: flex; align-items: flex-end; gap: 5px; height: 120px; padding: 0 18px 18px; }
.rb-chart span { flex: 1; background: var(--c-dark); border-radius: 2px 2px 0 0; opacity: .82; }
.rb-chart span.hi { opacity: 1; }

@media (max-width: 900px) {
  .rb-fs-split { flex-direction: column !important; gap: 40px !important; }
  .rb-fs { padding-top: 72px; }
  .rb-fs-shot { min-height: 240px; }
  .rb-kpis { grid-template-columns: 1fr 1fr; }
}

/* ---------------------------------------------------------- */
/* Features — the real Rulebase structure                      */
/* ------------------------------------------------------------
   Not a tab bar. Measured off their own markup:

     h2                     margin-bottom 48px
     body                   flex, gap 32, align-items flex-start
       rail                 width 278, flex-shrink 0
         item               border-top 1px, padding 16px 0;
                            first has neither, last adds a bottom
         label              14 / 20 / 500, tracking -.09px,
                            opacity .5 until selected
         desc               grid-template-rows 0fr → 1fr,
                            opacity 0 → 1, margin-top 0 → 6px
       panels               flex 1, min-width 0
         panel              grid repeat(3,1fr),
                            column-gap 10, row-gap 40
         preview            height 398
         caption            below the preview on the page
                            background — no frame, no shadow    */

.rb-fsec-title { width: 100%; margin-bottom: 48px; }

.rb-fsec-body { display: flex; gap: 32px; align-items: flex-start; }

.rb-frail { width: 278px; flex-shrink: 0; }
.rb-frail-item {
  cursor: pointer;
  border-top: 1px solid var(--c-line);
  padding: 16px 0;
}
.rb-frail-item:first-child { border-top: 0; padding-top: 0; }
.rb-frail-item:last-child { border-bottom: 1px solid var(--c-line); }

.rb-frail-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--f-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: -0.0064em;
  color: var(--c-ink);
  opacity: .5;
  transition: opacity 200ms var(--ease);
}
.rb-frail-item[aria-selected='true'] .rb-frail-label { opacity: 1; }
.rb-frail-item:hover .rb-frail-label { opacity: .8; }
.rb-frail-item[aria-selected='true']:hover .rb-frail-label { opacity: 1; }

/* The 0fr → 1fr reveal, which is how theirs animates: the row
   track collapses to nothing without needing a measured height. */
.rb-frail-desc {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  margin-top: 0;
  max-width: 278px;
  font-size: 14px;
  line-height: 1.43;
  letter-spacing: -0.0064em;
  color: var(--c-ink-3);
  text-wrap: pretty;
  transition: grid-template-rows 300ms var(--ease), opacity 250ms var(--ease), margin-top 300ms var(--ease);
}
.rb-frail-desc > span { min-height: 0; display: block; overflow: hidden; }
.rb-frail-item[aria-selected='true'] .rb-frail-desc {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: 6px;
}

.rb-fpanels { flex: 1; min-width: 0; }
/* One row, scrolled sideways. The cards are wide enough to read
   and the row runs off the right edge of the page on purpose: a
   cut card says there is more, a neat grid says this is all. */
.rb-fpanel {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 0;
  margin-right: calc(-1 * var(--wrap-x));
  padding: 0 var(--wrap-x) 12px 0;
  scrollbar-width: thin;
  scrollbar-color: var(--c-line-strong) transparent;
}
.rb-fpanel::-webkit-scrollbar { height: 6px; }
.rb-fpanel::-webkit-scrollbar-thumb { background: var(--c-line-strong); border-radius: 3px; }
.rb-fpanel::-webkit-scrollbar-track { background: transparent; }
.rb-fpanel[hidden] { display: none; }
/* A panel of renders runs two to a row, and its stages are taller
   so the render shows near its native size. */

.rb-fcard { display: flex; flex-direction: column; flex: 0 0 420px; scroll-snap-align: start; }

/* The preview is the card. There is no frame around it and the
   caption sits on the page background underneath. */
.rb-fstage {
  /* 320, not the reference's 398. The card is about 330 wide, so
     that height made it a portrait box and pushed the caption —
     the sentence that says what the module does — below the fold. */
  height: 380px;
  /* The ground is a carved subject, set per module by
     features.js as --rb-ground. It went through the plain Carrara
     first, which could not work: that render has no subject in
     it, so at any crop and any wash it reads as a tinted panel.
     Two other things were hiding it and only measuring the card
     found them — the wash was far too heavy, and the panel left
     the picture nothing but a 24px frame to show through. */
  background-color: var(--c-surface-warm);
  /* background-image is set inline per card by features.js — see
     the note there for why it cannot come through a variable. */
  background-size: auto, cover;
  background-position: center, center 40%;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* The panel starts low and runs off the foot, so the stone above
     it is a field rather than a border: a third of the card in one
     piece instead of a hairline nobody can see. */
  /* 118, not 84. These are product shots, not the abstract
     textures the reference uses, so a shallow strip shows a slice
     of an object rather than the object — and a slice of anything
     reads as wallpaper. At 118 the carved part is recognisable
     and the panel still has room for its head and three rows
     before it runs off the foot. */
  padding: 118px 22px 0;
}
/* A still fills its stage. The 118px of head-room above exists so
   a floating mock can run off the foot; a render is already a
   whole composition and only gets smaller for the trouble. */
.rb-fstage.is-still { padding: 0; position: relative; }
/* The hover clip sits exactly where the still is drawn: same width
   factor as the poster layer, centred, invisible until it plays. */
/* Pixel-exact placement, no percentages: the render is 940px, shown
   at 470 by 404, and centred with integer margins. A translate(-50%)
   landed the layer on a half pixel (-212.8px) and the whole video
   was resampled through that offset — that, not the file, was the
   blur. */
.rb-fstill-poster, .rb-fstill-clip {
  position: absolute; left: 50%; top: 50%;
  width: 470px; height: 404px; max-width: none;
  margin: -202px 0 0 -235px;
  pointer-events: none;
  transition: opacity 260ms var(--ease);
}
/* The clip is a VP9 WebM with a real alpha channel (rendered with
   --transparent in distrify-motion), so it sits on the marble the
   way the poster does. No blend mode: multiply was tried against an
   opaque render and it turned the white cards inside the drawing
   see-through. */
.rb-fstill-clip { opacity: 0; }
.rb-fstage.is-playing .rb-fstill-clip { opacity: 1; }
.rb-fstage.is-playing .rb-fstill-poster { opacity: 0; }

.rb-fstage.is-dark {
  background: var(--c-dark);
  color: #F7F7F4;
  padding: 24px;
  gap: 8px;
}
.rb-fstage.is-dark .rb-fr-sub { color: rgba(247, 247, 244, .5); }

/* Their light previews are a tinted surface with a piece of
   product UI floating on it, running off the bottom edge rather
   than sitting centred in the box. Reproducing that is what
   fills 398px without inventing density: the panel is the
   surface, and the rows are the top of a screenshot. */
.rb-fscene {
  flex: 1;
  min-height: 0;
  background: var(--c-surface);
  border-radius: 6px 6px 0 0;
  box-shadow: var(--sh-2);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.rb-fscene-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--c-line);
  font-size: 11.5px;
  color: var(--c-ink-3);
  flex: none;
}
.rb-fscene-body {
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  overflow: hidden;
}
/* Inside the white panel the rows invert: warm pills on white,
   rather than white pills on warm. */
.rb-fscene .rb-fr { background: var(--c-surface-warm); }
.rb-fscene .rb-fbar { background: var(--c-surface); }

.rb-fcap { padding: 16px 2px 0; }
.rb-fcap h3 {
  font-family: var(--f-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: -0.0064em;
  color: var(--c-ink);
  margin-bottom: 4px;
  text-wrap: pretty;
}
.rb-fcap p {
  font-size: 14px;
  line-height: 1.43;
  letter-spacing: -0.0064em;
  color: var(--c-ink);
  opacity: .5;
  text-wrap: pretty;
}

/* Code on a dark stage needs no box of its own. */
.rb-fplain {
  font-family: var(--f-mono);
  font-size: 11.5px;
  line-height: 1.8;
  color: #F7F7F4;
}
.rb-fplain .c { color: rgba(247, 247, 244, .45); }
.rb-fplain .k { color: #F7F7F4; }

/* -- Shared fragments used inside the stages ---------------- */
.rb-fr {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--c-surface);
  border-radius: 4px;
  padding: 9px 11px;
  font-size: 12px;
}
.rb-fr-pn { font-family: var(--f-mono); font-size: 11.5px; }
.rb-fr-sub { color: var(--c-ink-4); font-size: 11px; }
.rb-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; display: inline-block; }
.rb-dot-ok { background: #3F7D53; } .rb-dot-warn { background: #C08A3E; }
.rb-dot-bad { background: var(--c-bad); } .rb-dot-off { background: var(--c-ink-4); }

.rb-fnum { font-family: var(--f-display); font-size: 34px; line-height: 1; letter-spacing: -0.025em; }
.rb-fbar { height: 8px; border-radius: 100px; background: var(--c-surface-warm); overflow: hidden; }
.rb-fbar span { display: block; height: 100%; background: var(--c-dark); border-radius: 100px; }
.rb-fchart { display: flex; align-items: flex-end; gap: 4px; flex: 1; }
.rb-fchart span { flex: 1; background: var(--c-dark); border-radius: 2px 2px 0 0; opacity: .8; }
.rb-fchart span.hi { opacity: 1; }
.rb-fcode {
  background: var(--c-dark); color: #F7F7F4;
  border-radius: 4px; padding: 12px;
  font-family: var(--f-mono); font-size: 11px; line-height: 1.7;
  flex: 1; overflow: hidden;
}
.rb-fcode .k { color: #FFFFFF; font-weight: 600; }
.rb-fcode .c { opacity: .5; }
.rb-fchip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--c-surface); border-radius: 100px;
  padding: 5px 10px; font-size: 11px;
}

@media (max-width: 1240px) {
  .rb-fcard { flex-basis: 380px; }
  .rb-frail { width: 220px; }
}

/* Their own narrow variant turns the rail into a horizontal
   strip and drops the descriptions: white-space nowrap, a 2px
   bottom rule instead of the hairline between rows. */
@media (max-width: 900px) {
  .rb-fsec-body { display: block; }
  .rb-frail {
    width: auto;
    display: flex;
    gap: 28px;
    overflow-x: auto;
    border-bottom: 1px solid var(--c-line);
    margin-bottom: 32px;
  }
  .rb-frail-item,
  .rb-frail-item:first-child,
  .rb-frail-item:last-child {
    flex: none;
    white-space: nowrap;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: 8px 0;
  }
  .rb-frail-item[aria-selected='true'] { border-bottom-color: var(--c-ink); }
  .rb-frail-desc { display: none; }
  .rb-fcard { flex-basis: 82vw; }
  .rb-fstage { height: 320px; }
}

/* ---------------------------------------------------------- */
/* Problem scroll — the pinned narrative                       */
/* ------------------------------------------------------------
   A tall dark section whose inner panel sticks at the top for
   its whole height. The statement and the card underneath swap
   as you pass through it.                                     */

.rb-problem { background: var(--c-dark); color: var(--c-on-dark); position: relative; }
/* Two columns while pinned: the scrubbed clip on the left, the
   statement and its card on the right. The section is 320vh, so
   there is roughly two and a bit viewports of scroll to spend on
   three beats and one pass of the video. */
.rb-problem-sticky {
  position: sticky;
  top: 0;
  min-height: 100vh;
  /* `position: sticky` makes this a stacking context, so the
     video's mix-blend-mode composites against THIS element's
     backdrop — not the section's. With nothing painted here that
     backdrop is transparent, screen leaves the source untouched,
     and the clip's black stayed a visible rectangle. Painting
     the dark ground inside the same context is what gives the
     blend something to resolve against. */
  background: var(--c-dark);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 460px);
  align-items: center;
  gap: 80px;
  padding: 80px 100px;
}
.rb-problem-media { min-width: 0; }
.rb-scrub {
  display: block;
  width: 100%;
  height: auto;
  /* The clip's ground is pure black; screen resolves black to
     the backdrop exactly, so the dark section runs behind it
     without an alpha channel. An all-keyframe H.264 is what
     makes scrubbing smooth, and H.264 has no alpha to give. */
  mix-blend-mode: screen;
}
.rb-problem-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 32px;
  min-width: 0;
}
.rb-problem-text {
  font-family: var(--f-display);
  font-size: clamp(28px, 3.4vw, 46px);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.025em;
  max-width: 18ch;
  color: #F7F7F4;
  text-wrap: pretty;
}
.rb-problem-text .dim { color: rgba(247, 247, 244, .38); }
.rb-beat { animation: rb-beat-in 420ms var(--ease) both; }
@keyframes rb-beat-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

.rb-problem-card {
  align-self: stretch;
  width: 100%;
  background: #FFFFFF;
  color: var(--c-ink);
  border-radius: 4px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, .38);
  overflow: hidden;
}
.rb-pc-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 16px; border-bottom: 1px solid #E8E5E3;
  font-size: 13px; color: var(--c-ink-3);
}
.rb-pc-body { padding: 16px; display: flex; flex-direction: column; gap: 10px; }

/* Progress rail showing where you are in the narrative */
.rb-beats { display: flex; gap: 6px; }
.rb-beats i {
  width: 30px; height: 2px; display: block;
  background: rgba(247, 247, 244, .22);
  transition: background 300ms var(--ease);
}
.rb-beats i.on { background: #F7F7F4; }

@media (max-width: 900px) {
  .rb-problem-sticky {
    position: static; min-height: 0;
    grid-template-columns: 1fr;
    padding: 72px 40px; gap: 28px;
  }
  /* Nothing to scrub against once the section stops pinning. */
  .rb-scrub { max-width: 520px; }
  .rb-problem { padding-bottom: 0; }
}

/* 24px and opacity 1, as theirs are. Greyscale stays: their
   marks are already black wordmarks, ours carry brand colour —
   teal, two blues — and this design system has no chroma
   anywhere else. Desaturating is what keeps the row quiet; the
   0.7 opacity on top of it was what made it weak. */
/* No filter. The treatment is baked into the file by
   tools/logos.py — customers are flattened to one ink, partners
   keep their brand colour — and a `grayscale(1)` here could not
   tell the two sets apart. It used to decolour everything, which
   is fine for a customer rail and wrong for a partner one, where
   a grey SAP or Octopart stops being recognisable.

   Partner marks run wider than customer wordmarks, so they get
   more room; both are capped by height, which is what keeps a
   rail of mixed aspect ratios on one optical line. */
.rb-chip img {
  height: 24px;
  width: auto;
  max-width: 128px;
  object-fit: contain;
}
/* A logo set over two lines needs the height of two lines. At the
   single-line 24px each word in Atlantik's mark lands at about
   10px and the rail is a row of grey smudges. */
.rb-chip img[data-tall] { height: 34px; max-width: 150px; }
.rb-trust-track[data-set='partners'] .rb-chip img,
.rb-trust-track[data-set='erp'] .rb-chip img,
.rb-trust-track[data-set='marketplaces'] .rb-chip img,
.rb-trust-track[data-set='rfq'] .rb-chip img { max-width: 150px; }

/* ============================================================
   Wide viewports — the centred measure
   ------------------------------------------------------------
   Below 1513px Rulebase runs a flat 100px inset. Above it the
   gutter becomes `max(100px, 50% - 656px)`, which caps the
   measure at 1312px and centres it. The two meet exactly at the
   breakpoint: at 1513px, 50% - 656px = 100.5px, so nothing
   jumps.

   Copied verbatim from their @media (min-width: 1513px), which
   applies it to the nav, trust bar, every section and the
   footer. Without it a 2560px screen stretched our sections to
   2360px of measure while theirs held at 1312.

   `50%` resolves against the containing block, which is the
   viewport for everything here EXCEPT the hero's left column —
   that one is a 52% grid track, so a percentage there would
   halve again. It gets 50vw instead.
   ============================================================ */

@media (min-width: 1513px) {
  .rb-wrap,
  .rb-nav,
  .rb-trust,
  .rb-pull,
  .rb-dark,
  .rb-catch,
  .rb-footer,
  .rb-problem-sticky {
    padding-left: var(--wrap-x);
    padding-right: var(--wrap-x);
  }

  /* Grid tracks, not full-width boxes. */
  .rb-hero-left { padding-left: max(100px, 50vw - 656px); }

}

/* The float card is pinned to the right of the hero panel, which
   is the viewport edge, so it never sat on the same line as the
   rest: 56px against everything else's 100px, and once the
   centred measure came in it was stranded outside it entirely.

   One expression from the desktop split upward puts its edge on
   the footer's and the Get Started button's at every width. `vw`
   rather than `%`, because the panel is a 48% grid track.

   Not below 1181px. The panel is 48% of the viewport, so it can
   only hold a 420px card at a 100px inset from 1083px up, and
   below 1180 the gutter is 56px anyway — which the card's own
   56px already matches. */
@media (min-width: 1181px) {
  .rb-float-card { right: max(100px, 50vw - 656px); }
}

/* ============================================================
   Demand feed — the hero's animated card
   ------------------------------------------------------------
   Their chat card is not one panel but two white blocks with a
   4px gap: the message list, then a strip underneath carrying a
   shimmering "working on it" line. Measured off it:

     block      #fff, radius 4, padding 8px 12px 12px
     row        flex, space-between, align flex-start, gap 8
     row text   14 / 21
     row time   14 / 21, rgba(0,0,0,.2), nowrap, no shrink
     strip      #fff, radius 4, margin-top 4, padding 12, gap 8
     strip text 14px, rgba(0,0,0,.5)
     shimmer    gradient over the glyphs, 2.2s linear infinite

   Scoped to #demand-feed so the cards on the channels and
   franchised pages keep the older single-panel treatment.
   ============================================================ */

#demand-feed { background: none; box-shadow: none; overflow: visible; }

.rb-feed-block {
  background: #FFFFFF;
  border-radius: 4px;
  box-shadow: var(--sh-2);
  padding: 8px 12px 12px;
  overflow: hidden;
}
.rb-feed-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0 10px;
  font-size: 14px;
  letter-spacing: -0.0064em;
  color: #1E1E1E;
}
.rb-feed-live {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: rgba(0, 0, 0, .35);
}
.rb-feed-live i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--c-ok);
  animation: rb-feed-pulse 1.8s var(--ease) infinite;
}
@keyframes rb-feed-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .25 } }

/* Rows stack from the bottom, so an arriving one pushes the
   oldest up and out of the clip rather than jumping the block. */
.rb-feed-rows {
  height: 132px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 9px;
  overflow: hidden;
  /* The departing row dissolves instead of being sliced in half
     at the clip, which read as a rendering fault. One row's
     height of fade is enough to carry it out. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 24px);
          mask-image: linear-gradient(to bottom, transparent 0, #000 24px);
}
/* Alignment is held by fixed heights rather than by baselines:
   the chip, the label and the state column are all 21px tall and
   centred, so a taller glyph or a longer channel name cannot
   nudge the line. `nowrap` keeps a row one line — a wrapped one
   would break the 132px stack the block is measured for. */
.rb-feed-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 21px;
  font-size: 14px;
  line-height: 21px;
  letter-spacing: -0.0064em;
  color: #1E1E1E;
  animation: rb-feed-in 420ms var(--ease) both;
}
.rb-feed-text {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  white-space: nowrap;
}
.rb-feed-what { flex: none; }
@keyframes rb-feed-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
/* Everything but the newest sits back, the way their older
   messages do. */
.rb-feed-row:not(:last-child) { color: rgba(30, 30, 30, .45); }
/* The channel is the point of the line, so it carries the
   weight and a hairline chip; the count and the verb around it
   stay quiet. */
.rb-feed-src {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 21px;
  padding: 0 9px 0 7px;
  border: 1px solid var(--c-line);
  border-radius: 100px;
  font-weight: 500;
  color: #1E1E1E;
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rb-feed-src svg {
  width: 13px; height: 13px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.15;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .75;
}
.rb-feed-row:not(:last-child) .rb-feed-src { border-color: rgba(0,0,0,.07); color: inherit; }

/* Right column: working, then done. Sized once so the row never
   reflows when one swaps for the other. */
.rb-feed-state {
  position: relative;
  flex: none;
  width: 18px; height: 21px;
}
/* Centred by margin:auto inside a filled inset, NOT by a
   translate. `rb-spin` animates `transform`, which overrode a
   centring translate outright and dropped the spinner half its
   own size down and to the right. Leaving transform free means
   the rotation and the check's scale both have it to themselves. */
.rb-feed-state > * {
  position: absolute;
  inset: 0;
  margin: auto;
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
}
.rb-feed-spin {
  width: 14px; height: 14px;
  border: 1.5px solid rgba(0, 0, 0, .14);
  border-top-color: rgba(0, 0, 0, .5);
  border-radius: 50%;
  animation: rb-spin 900ms linear infinite;
}
.rb-feed-check { width: 14px; height: 14px; opacity: 0; transform: scale(.6); }
.rb-feed-check path { stroke: var(--c-ok); stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }

.rb-feed-row[data-done='true'] .rb-feed-spin  { opacity: 0; animation: none; transform: scale(.6); }
.rb-feed-row[data-done='true'] .rb-feed-check { opacity: 1; transform: scale(1); }

.rb-feed-strip {
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px;
  background: #FFFFFF;
  border-radius: 4px;
  box-shadow: var(--sh-2);
  font-size: 14px;
  letter-spacing: -0.0064em;
}
.rb-feed-strip .rb-spinner { flex: none; }
.rb-feed-total { margin-left: auto; color: rgba(0, 0, 0, .35); white-space: nowrap; }

/* The glyphs carry the gradient, so the text itself shimmers. */
.rb-shimmer {
  background: linear-gradient(90deg, rgba(0,0,0,.9) 30%, rgba(0,0,0,.3) 50%, rgba(0,0,0,.9) 70%) 0 0 / 200% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  animation: rb-shimmer 2.2s linear infinite;
}
@keyframes rb-shimmer { 0% { background-position: 150% 0; } 100% { background-position: -150% 0; } }

@media (prefers-reduced-motion: reduce) {
  .rb-feed-row { animation: none; }
  .rb-feed-spin { animation: none; }
  .rb-shimmer { animation: none; color: rgba(0,0,0,.55); background: none; }
  .rb-feed-live i { animation: none; }
}

/* ============================================================
   Hero video
   ------------------------------------------------------------
   The animated board replaces the still in cut-out mode. VP9 in
   WebM carries a real alpha channel, so the dark hero shows
   through exactly as it does behind the still image — no blend
   mode and no keying.

   Positioned by the same rule the still uses. CSS background
   positioning resolves an offset of P x (container - image), so
   an element reproduces it with calc((100% - W) * P). That keeps
   the framing identical as the panel widens: more of the board
   comes in from the left, top and bottom stay put.

   1930px is chosen so the board lands the same width on screen
   as it did as a still: the still ran 1950px wide with the board
   filling 88.8% of it, the video's board fills 89.8% of its
   frame, and 1930 x 0.898 matches 1950 x 0.888.
   ============================================================ */

.rb-hero-video {
  position: absolute;
  z-index: 1;
  width: var(--rb-video-w, 1930px);
  height: auto;
  left: calc((100% - var(--rb-video-w, 1930px)) * var(--rb-video-x, 0.12));
  top: calc((100% - (var(--rb-video-w, 1930px) / 1.742)) * var(--rb-video-y, 0.88));
  pointer-events: none;
  display: none;
}
/* The still is what the landing hero shows.
   --------------------------------------------------------------
   There was a VP9 clip with a real alpha channel here, switched
   against the still by `data-hero-media` on <html>. The clip is
   still in assets/ but nothing loads it, and there is no attribute
   any more — the still is simply the hero.

   To go back: restore the <video> in index.html and swap the two
   rules below. The two renders are not the same shape — the still
   is 1.792 and the clip 1.742, and the board sits differently in
   each frame — so the still keeps its own crop rather than being
   forced into the video's box. Swapping changes the framing
   slightly, which is honest: they are two different renders. */
body[data-hero='cutout'] .rb-hero-video { display: none; }
body[data-hero='cutout'] .rb-board { display: block; }

/* Motion off, or the still chosen: the poster is the clip's last
   frame, so holding the image is the picture the animation would
   have settled on anyway. */
@media (prefers-reduced-motion: reduce) {
  .rb-hero-video { display: none; }
  body[data-hero='cutout'] .rb-board { display: block; }
}

@media (max-width: 900px) {
  .rb-hero-video { --rb-video-w: 760px; --rb-video-x: 0.5; --rb-video-y: 0.5; }
}

/* ============================================================
   Mobile navigation
   ------------------------------------------------------------
   Below 900px the desktop row is hidden. Until this existed the
   site had twenty nav links in the DOM and no way to reach any of
   them on a phone, which is the difference between a comparison
   build and a working site.

   The sheet is dark because the nav sits inside a dark hero on
   every page — opening it should feel like the header growing,
   not like a different surface arriving.
   ============================================================ */

.rb-burger {
  display: none;
  width: 44px; height: 44px;           /* the tap target, not the icon */
  margin-left: 14px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  position: relative;
  flex: none;
}
.rb-burger i {
  position: absolute;
  left: 11px;
  width: 22px; height: 1.5px;
  background: var(--c-on-dark);
  transition: transform var(--dur-base) var(--ease), opacity var(--dur-fast) var(--ease);
}
.rb-burger i:nth-child(1) { top: 18px; }
.rb-burger i:nth-child(2) { top: 25px; }
.rb-burger[aria-expanded='true'] i:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.rb-burger[aria-expanded='true'] i:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

.rb-sheet {
  position: fixed;
  inset: 72px 0 0;                     /* below the nav row */
  z-index: 60;
  background: var(--c-dark);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  animation: rb-sheet-in 180ms var(--ease) both;
}
.rb-sheet[hidden] { display: none; }
@keyframes rb-sheet-in { from { opacity: 0; transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) { .rb-sheet { animation: none; } }

/* The page behind a sheet must not scroll — a menu you can scroll
   the article through reads as broken. */
.rb-locked, .rb-locked body { overflow: hidden; }

.rb-sheet-inner { padding: 8px 24px 48px; }
.rb-sheet-group { padding: 18px 0; border-bottom: 1px solid var(--c-line-dark); }
.rb-sheet-group:last-of-type { border-bottom: 0; }
.rb-sheet-h {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: rgba(247, 247, 244, .48);
  margin-bottom: 10px;
}
/* 48px minimum so a thumb hits the link and not the gap. */
.rb-sheet-group a {
  display: block;
  padding: 11px 0;
  min-height: 48px;
  color: var(--c-on-dark);
}
.rb-sheet-group a span { display: block; font-size: 17px; line-height: 1.3; letter-spacing: -0.01em; }
.rb-sheet-group a small { display: block; margin-top: 3px; font-size: 13px; color: var(--c-on-dark-2); }
.rb-sheet-solo span { font-family: var(--f-display); font-size: 21px; }
.rb-sheet-cta { padding-top: 26px; }
.rb-sheet-cta .rb-btn { width: 100%; justify-content: center; }

@media (max-width: 900px) {
  .rb-nav { justify-content: space-between; padding: 0 24px; gap: 12px; }
  /* The CTA stays, compact: wordmark (about 110px), a small pill
     and the burger fit a 375px screen with room to spare, and the
     demo button is the one thing the header is for. */
  .rb-nav > .rb-btn { display: inline-flex; margin-left: auto; height: 36px; padding: 0 14px; font-size: 13px; border-radius: 10px; }
  /* The burger reads as a control, not two hairlines: a bordered
     pill the size of the CTA, two 2px bars inside. */
  .rb-burger {
    display: block; width: 44px; height: 36px; margin-left: 0;
    border: 1px solid rgba(247, 247, 244, .28); border-radius: 10px;
  }
  .rb-burger i { left: 12px; width: 20px; height: 2px; border-radius: 2px; }
  .rb-burger i:nth-child(1) { top: 13px; }
  .rb-burger i:nth-child(2) { top: 21px; }
  .rb-burger[aria-expanded='true'] i:nth-child(1) { transform: translateY(4px) rotate(45deg); }
  .rb-burger[aria-expanded='true'] i:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }
  .rb-header.is-float .rb-burger { border-color: var(--c-line-strong); }
  /* The hero copy starts closer under the bar and aligns with the
     wordmark instead of sitting 40px in. */
  .rb-hero-left { padding: 104px 24px 40px; }
}

/* Also at narrow widths, not only on a coarse pointer: a phone
   emulator and a small desktop window are the same layout, and a
   target that only grows for a finger is untestable in the one
   place it is easiest to check. */
@media (pointer: coarse), (max-width: 900px) {
  /* The wordmark is the way home from every page, so it gets a
     real target rather than the height of its own glyphs. */
  .rb-logo { min-height: 44px; display: inline-flex; align-items: center; }
  .rb-nav-links a, .rb-navbtn { min-height: 44px; display: inline-flex; align-items: center; }
  /* The default button is 36px tall by design — small and quiet
     is the point. That is under the 44px a finger needs, so on a
     touch device it grows to 44 without changing its type or its
     horizontal padding. The look is unchanged; only the target
     is bigger. */
  .rb-btn { min-height: 44px; }
}


/* ============================================================
   The floating header
   ------------------------------------------------------------
   Transparent over the hero at the top; past 24px of scroll it
   contracts into a pill. Rebuilt from the DS 2.0 header in this
   system's tokens: canvas rather than white, the greige hairline,
   and the same 260ms curve.

   Every property that moves is listed explicitly. `transition:
   all` here would also animate the colour flip of twenty child
   links and cost more than it buys.
   ============================================================ */

.rb-nav {
  /* width and max-width start as explicit lengths, not `auto` and
     `none`: a transition cannot interpolate from either, which is
     why the bar used to snap to the pill while everything else
     eased. 100% to 1140px interpolates as a calc() mix. */
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  transition:
    height    340ms var(--ease),
    margin    340ms var(--ease),
    max-width 340ms var(--ease),
    width     340ms var(--ease),
    padding   340ms var(--ease),
    background-color 340ms var(--ease),
    border-radius 340ms var(--ease),
    box-shadow 340ms var(--ease);
  border: 1px solid transparent;
  background-color: transparent;
}
/* The marble lives on a layer of its own so it can fade in with
   the pill instead of appearing on the first frame. */
.rb-nav::before {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  background-image:
    linear-gradient(rgba(243, 241, 237, .28), rgba(243, 241, 237, .28)),
    url('../assets/marble-nav.webp');
  background-size: auto, cover;
  background-position: center, center;
  opacity: 0;
  transition: opacity 340ms var(--ease);
}
.rb-header.is-float .rb-nav::before { opacity: 1; }
/* Everything that flips from cream to ink eases at the same pace
   as the bar around it. */
.rb-logo, .rb-nav-links, .rb-navbtn, .rb-nav-links > a { transition: color 340ms var(--ease); }
.rb-burger i { transition: background-color 340ms var(--ease); }

/* Stone, but only once it has left the top of the page.
   ------------------------------------------------------------
   At rest the bar is transparent over the hero and belongs to the
   image behind it. Contracted into the pill it becomes an object
   in its own right, and that object is cut from the same marble
   as everything else the brand shows.

   The image is a band cropped from the Carrara macro render, and
   the thin wash over it only settles the tone toward the canvas
   colour and guards the contrast if a darker slab ever replaces
   it. Real stone needs very little: three synthetic textures were
   tried first and every one read as grey smears or as a contour
   map, because drawn veins have a constant width and no crystal
   under them.

   Measured on the composited bar rather than judged by eye: 20
   grey levels of stone across the bar, worst-case text contrast
   8.6:1 — past AAA with the ink at its 88% alpha.

   background-color is still declared: it is what shows during the
   260ms contraction, and what remains if the image 404s. */
.rb-header.is-float .rb-nav {
  height: 60px;
  margin: 10px auto 0;
  max-width: 1140px;
  width: calc(100% - 24px);
  padding-left: 20px;
  padding-right: 12px;
  background-color: var(--c-canvas);
  /* The marble itself is on .rb-nav::before, so it can fade. */
  border-color: var(--c-line);
  border-radius: 18px;
  box-shadow: 0 1px 2px rgba(26, 23, 22, .04), 0 8px 24px rgba(26, 23, 22, .07);
}

/* On the pill the ground is light, so everything that was cream
   over the dark hero has to become ink. */
.rb-header.is-float .rb-logo { color: var(--c-ink); }
.rb-header.is-float .rb-logo i { background: var(--c-ink); }
.rb-header.is-float .rb-nav-links { color: var(--c-ink-2); }
/* Direct children only, like the rule on the bar above. Reaching
   every anchor inside .rb-nav-links also caught the dropdown, and
   the aria-current line then repainted the entry you are standing
   on back to ink — cancelling the brand red the moment the header
   contracted. */
.rb-header.is-float .rb-nav-links > a:hover,
.rb-header.is-float .rb-navbtn:hover,
.rb-header.is-float .rb-navbtn[aria-expanded='true'] { color: var(--c-ink); }
.rb-header.is-float .rb-nav-links > a[aria-current='page'],
.rb-header.is-float .rb-navbtn[aria-current='page'] { color: var(--c-ink); }
.rb-header.is-float .rb-burger i { background: var(--c-ink); }

/* The menu hangs from a shorter bar now. */
.rb-header.is-float .rb-menu { top: calc(100% + 8px); }

@media (max-width: 900px) {
  .rb-header.is-float .rb-nav {
    height: 64px;
    width: calc(100% - 16px);
    border-radius: 16px;
    padding-left: 16px;
    padding-right: 4px;
  }
  /* The sheet drops from the bar's real bottom edge, which moves
     when the bar contracts. */
  .rb-header.is-float .rb-sheet { top: 74px; }
}

@media (prefers-reduced-motion: reduce) {
  .rb-nav, .rb-nav::before, .rb-logo, .rb-nav-links, .rb-navbtn, .rb-nav-links > a, .rb-burger i { transition: none; }
}


/* Every page carries the shorthand its readers use, and the house
   rule is that each term stands beside its plain-language meaning
   at least once on the page. The leads do that where they use the
   term; this line is the floor underneath, so no page ships a
   term without its meaning somewhere on it. Small and muted on
   purpose: it is a footnote, not a section. */
.rb-footer-gloss {
  display: flex; flex-wrap: wrap; gap: 6px 22px;
  margin: 48px 0 0; padding: 18px 0 0;
  border-top: 1px solid var(--c-line);
  font-size: 12.5px; line-height: 1.5; color: var(--c-ink-3);
}
/* Ink, not the pale tones: the footer is light. The first version
   was coloured for a dark ground and vanished on the real one. */
.rb-footer-gloss b { font-weight: 500; color: var(--c-ink); margin-right: 6px; }

/* The hero's small second line without a thumbnail. The thumb was a
   grey box standing in for a video that was never made; with it gone
   the text just sits under the CTA, and the link is a link. */
.rb-hero-mini-plain { grid-template-columns: 1fr; }
.rb-hero-mini-plain a.rb-mini-link { color: inherit; text-decoration: none; }
.rb-hero-mini-plain a.rb-mini-link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Tap floor for the two links that measured 28px on a phone. */
.rb-hero-mini-plain a.rb-mini-link, .rb-crumb a { display: inline-flex; align-items: center; min-height: 44px; }

/* A plain text link under a quote or paragraph: underlined, ink. */
.rb-textlink { font-size: 14px; color: var(--c-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--c-line-strong); }
.rb-textlink:hover { text-decoration-color: currentColor; }
/* The flow was drawn for the dark partner hero; on the light
   homepage its connector labels and rails need ink, not cream. */
.rb-proof-flow .rb-fa-leg-label, .rb-proof-flow .rb-fa-leg-t { color: var(--c-ink-4); }
.rb-proof-flow .rb-fa-rail { background: var(--c-line-strong); }
/* The clip's ground is black and mix-blend-mode: screen resolves
   it against THIS stacking context (sticky), so the column must
   carry the section's dark itself. */
.rb-now-media { background: var(--c-dark); }

/* Phone: the Telcona diagram stacks. Placed last and written with
   the column selector, so it outranks the compact-variant rules
   above regardless of order. */
@media (max-width: 760px) {
  .rb-social .rb-link3-col .rb-link3 { grid-template-columns: 1fr; gap: 14px; justify-items: center; }
  .rb-social .rb-link3-col .rb-link3-wire { height: 40px; width: 1px; }
  .rb-social .rb-link3-col .rb-link3-wire::before { left: 0; right: auto; top: 0; bottom: 0; width: 1px; height: auto; }
  .rb-social .rb-link3-col .rb-link3-logo { width: 200px; max-width: 100%; height: 68px; }
  .rb-social .rb-link3-col .rb-link3-sub { max-width: 30ch; }
  .rb-social .rb-link3-col .rb-link3-cap { text-align: center; }
}

/* Phone: three-up card grids go to one column; the webshop mock
   drops its manufacturer column so part, price and stock keep
   their room. */
@media (max-width: 600px) {
  .rb-card-grid { grid-template-columns: 1fr !important; }
  .rb-ws-row { grid-template-columns: minmax(0, 1fr) auto auto; }
  .rb-ws-row > :nth-child(2) { display: none; }
}
