/* ==========================================================================
   Shared Magnum course engine chrome, Momentum
   ==========================================================================
   Shared CSS for any Magnum course's module pages. RAMP UP (public/rampup-1/
   index.html through public/rampup-10/index.html) is this engine's first
   consumer; nothing below is specific to RAMP UP. Real cached file, linked
   with an absolute path (/assets/course.css) and never inlined into any
   course document: see the shell performance law, section 10 of
   docs/handoffs/BRIEF_2026-08-04_rampup-rebuild.md.

   Every selector below is namespaced .ru- so nothing bleeds into the shell's own
   header (#mn-*), breadcrumb (#mn-back-bar) or the dashboard.

   REBUILD, SECOND PASS: the first pass fixed the finish (tokens, real
   components) but kept a narrow ~980px centred column. Anric rejected that
   too - "you've abandoned all of that design... feel free to use the entire
   width of the page, stop squashing everything into the middle part." The
   dashboard (public/index.html) is a full-viewport four-zone grid: a fixed
   left rail, two flexible centre tracks and a fixed right-ish column, all
   inside a <main> with NO max-width (see app.css's own comment on that rule).
   This file now mirrors that shape: .ru-grid is the same idea as the
   dashboard's .shell-row--main - a fixed-width protocols rail on the left, a
   flexible centre column (video + workbook), a fixed-width right rail
   (a PROGRESS mirror only, as of 2026-08-08 - the right rail's own former
   04 SECTIONS jump list is gone, see .ru-rail-sections's own comment further
   down), collapsing to one stacked column at the same kind of breakpoint
   app.css uses (900px). See course-nav.js for what fills the left rail and
   the progress mirror, and course-workbook.css for the desktop-only
   suppression of the workbook's own in-panel progress bar (it stays in the
   DOM, fully wired, for JS scoping - see that file's own comment - only its
   on-screen duplicate in the right rail is new; the in-panel tab bar is no
   longer suppressed at any width, see .rw-tabs's own comment).

   Every color, border, radius, background and shadow below reads its value
   directly from assets/momentum.css's own --mom-* custom properties (linked
   in the <head> of every rampup-N/index.html, BEFORE this file, so this
   file's page-specific rules still win the cascade on any shared selector).
   No token is restated here as a hex/rgba literal.

   THE ONE EXCEPTION: --ru-font-head and --ru-font-body. momentum.css's own
   --mom-font-head / --mom-font-body-ops are CHOSEN FALLBACK stacks for a build
   that could not load real fonts - they never name Russo One or Inter, only
   system approximations. This shell already self-hosts both real faces (Russo
   One inline in the ported header, Inter as a real @font-face below), so the
   two font tokens below stay local, naming the real families with the same
   fallback stacks momentum.css uses after them. Deleting these two would
   silently drop every rampup heading back to a system font. A second, real
   Russo One @font-face is declared below (momentum.css's copy is a one-off
   base64 inline in the shell header, this is the real cached file every other
   ported tool font already uses) so browsers don't need the shell's inline copy
   to render this page's own headings correctly if ever loaded standalone.

   NO em dashes, NO italics, NO pill radii (999px/9999px/50% on any control).
   Radii below only ever read a real --mom-radius-* token (never a chosen
   pixel value) per Anric's direct rounding note. Mobile first: base rules
   target 375px, wider layout arrives via min-width media queries only.
   ========================================================================== */

:root {
  --ru-font-head: 'Russo One', 'Arial Narrow', 'Segoe UI', system-ui, -apple-system, sans-serif; /* real face; Russo One is also loaded shell-wide, see TEMPLATE.html's own @font-face */
  --ru-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; /* real face, self-hosted below */
}

/* Russo One, self-hosted as a real cacheable .woff2 (the same file and pattern
   every ported tool fragment already sets up per-page, e.g. public/genius/
   index.html), so the heading font resolves from a shared cached resource
   instead of relying only on the shell's one-off inline base64 copy. */
@font-face {
  font-family: 'Russo One';
  src: url('/assets/fonts/russo-one.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Inter, self-hosted as a real cacheable .woff2 (the same file and pattern
   every ported tool fragment already sets up per-page, e.g. public/genius/index.html): declared once
   here so all ten pages share one cached font resource instead of ten separate inline
   base64 blocks. Zero external requests, font-display: swap keeps text painting with the
   fallback stack immediately rather than blocking on the font. */
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-var-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ---- Page atmosphere -----------------------------------------------------
   Anric, 2026-08-06: "no depth anywhere on the page" - every numbered panel
   sat at essentially the same value as the page behind it. Measured and
   confirmed the actual cause: the shell's <body> is a flat opaque #08080c
   (see the old comment this block replaces) and .mom-panel's own surface
   token (--mom-bg-panel, rgba(8, 8, 12, 0.74)) is numerically almost that
   same colour, so a translucent panel over a flat page of the same colour
   paints as one flat colour - .mom-panel's real border, shadow and
   backdrop-blur (momentum.css section 3) have nothing behind them to
   separate from. The real dashboard (public/index.html) never has this
   problem because its <body class="mom-atmosphere"> carries a textured,
   gently glowing canvas (momentum.css section 8: a faint gold grid plus two
   soft radial glows) for its translucent panels to sit above. This is that
   exact recipe, the same gradients byte-for-byte, applied to a plain `body`
   selector instead: the shell's <body> tag itself is shared chrome (out of
   scope to hand-edit from this file), but its background and two new
   pseudo-elements are ordinary CSS this file already owns. Static, no
   animation, no new backdrop-filter added anywhere: .mom-atmosphere-decor's
   own drifting glow blobs and the slow-spinning gear texture are
   deliberately NOT ported here, per Anric's own instruction not to animate
   anything continuously on a page that already carries up to 152
   textareas. */
body {
  background: var(--mom-bg-page);
}
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(circle at 15% 10%, rgba(240, 193, 115, 0.16), transparent 45%),
    radial-gradient(circle at 85% 90%, rgba(220, 20, 60, 0.12), transparent 45%);
  filter: blur(60px);
  opacity: 0.6;
  pointer-events: none;
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(rgba(250, 189, 89, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(250, 189, 89, 0.06) 1px, transparent 1px);
  background-size: 60px 60px;
  pointer-events: none;
}

/* ---- Layout wrapper ------------------------------------------------------
   NO max-width, same as the dashboard's own <main> (app.css:
   "max-width removed so the grid can span the full viewport") - a fixed cap
   here is exactly the "squashed into the middle" defect this pass removes.
   Horizontal padding stays as a gutter, the same two space tokens the
   dashboard's own <main> uses. */
.ru-wrap {
  width: 100%;
  margin: 0 auto;
  padding: var(--mom-space-6) var(--mom-space-6) var(--mom-space-10);
  font-family: var(--ru-font-body);
  color: var(--mom-text);
  box-sizing: border-box;
}
.ru-wrap * {
  box-sizing: border-box;
}

/* ---- Anchor reset, whole course document ---------------------------------
   Anric, 2026-08-06: "Where is the weird blue underline coming from?" Root
   cause, confirmed with computed styles: momentum.css's own .mom-nav-item
   sets layout only, never color or text-decoration, because on the real
   dashboard those rows are plain DIVs - the rule never needed to fight the
   browser's own link defaults. course-nav.js renders the 01 MODULES rail
   rows AND the 05 PREVIOUS/NEXT tiles as real <a href> elements, so both
   fall back to the browser's own UA default link style (rgb(0, 0, 238),
   underlined) with nothing above to override it. Every other <a> below the
   shell chrome (a video-unsupported fallback link, any future course copy)
   has the same gap. :where(.ru-wrap) keeps this selector's own specificity
   at zero (the whole block resolves to a bare "a", "a:visited", etc.)
   DELIBERATELY, so a real, more specific link style elsewhere in the course
   chrome (.rw-resource-link, .mom-quicklink-tile - both already set their
   own color and text-decoration, a real class selector always outranks a
   bare type selector) still wins the cascade over this reset. This is a
   blanket DEFAULT for the course document, never a course-specific value,
   and it never touches anything above the shell chrome (the shell's own
   header/breadcrumb links keep whatever momentum.css or the shell already
   gives them - this rule is scoped to .ru-wrap, which only ever wraps the
   per-course content). */
:where(.ru-wrap) a {
  color: inherit;
  text-decoration: none;
}
:where(.ru-wrap) a:visited {
  color: inherit;
}
:where(.ru-wrap) a:hover,
:where(.ru-wrap) a:focus-visible {
  color: inherit;
  text-decoration: none;
}

/* ---- Heading block ---------------------------------------------------
   Full width, one row, no stray rule underneath (the old bottom border lived
   on the protocol strip, which has moved into the left rail - see below).
   .mom-h / .mom-label are momentum.css's own generic heading/micro-label
   treatments (section 2, the exact recipe .welcome-hello/.cm-title/.id-name
   already use), adopted here by class rather than restated. */
.ru-heading {
  margin-bottom: var(--mom-space-9);
}
.ru-proto-num {
  font-family: var(--mom-font-mono);
  font-size: var(--mom-text-xs);
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--mom-text-muted);
  margin: 0 0 8px;
}
.ru-brand {
  font-family: var(--ru-font-head);
  font-weight: 900;
  font-style: normal;
  font-size: 28px;
  letter-spacing: 1px;
  line-height: 1.2;
  margin: 0 0 8px;
  color: var(--mom-text);
  text-transform: uppercase;
}
.ru-brand .ru-tri {
  color: var(--mom-gold);
  padding: 0 2px;
  font-size: 0.7em;
  vertical-align: middle;
}
/* READABILITY, 2026-08-08. Becoming Unstoppable's subtitle is Lauralouise's
   real series description, a full sentence, not a short label like most
   other courses' subtitles - at 1.5px letter-spacing and full uppercase it
   rendered as one long tracked-out line, and at that tracking her plain
   hyphen ("Becoming Unstoppable - A 4 part strategy...") visually read as
   an em dash even though the character itself is a real hyphen (banned
   em dash is U+2014; hers is U+002D, untouched). Dropping the uppercase
   transform and cutting letter-spacing close to zero makes this read as
   prose instead of a tracked label, for every course's subtitle here (this
   class is shared, not Becoming-Unstoppable-specific) - none of the text
   itself changes, only how it is rendered. */
.ru-protocol-title {
  font-family: var(--mom-font-mono);
  font-size: 14px;
  letter-spacing: 0.2px;
  line-height: 1.5;
  color: var(--mom-gold);
  margin: 0;
}
/* ---- v2: welcome line, relocated from the workbook, 2026-08-08 -----------
   Anric: "you have 'Welcome to your identity revolution...' and right
   below it, after the tabs, 'The Identity Revolution.' ... the tabs need
   to go right on top." Two near-identical banners either side of the tab
   bar - only one survives inside 03 WORKBOOK (course-workbook.css already
   hides the per-section .rw-section-title repeat, "the active tab already
   names it"), and this is the OTHER one: .rw-banner's exact words, moved
   verbatim up next to the page heading so 03 WORKBOOK's own tabs can sit
   first with nothing above them. Quiet line, not a filled banner box - "no
   filled full page banner bars, headings are headings" - a thin top rule
   only, same idiom .rw-banner itself already used once demoted. Scoped to
   .ru-layout-v2 only: this markup exists on no other page. */
.ru-layout-v2 .ru-welcome-line {
  margin: 8px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--mom-border-faint);
  color: var(--mom-gold);
  font-family: var(--ru-font-body);
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
}

/* ---- The three-zone grid -----------------------------------------------
   Left rail (01 PROTOCOLS), flexible centre column (02 VIDEO + 03 WORKBOOK),
   right rail (PROGRESS mirror only, as of 2026-08-08 - see .ru-rail-sections's
   own comment further down for why 04 SECTIONS is gone). Fixed rail widths mirror the
   dashboard's own .shell-row--main first column (240px, app.css) rather
   than inventing a new one; the centre track is minmax(0, 1fr), same
   "flexible, never forces its neighbours narrower" pattern app.css uses for
   its own flexible columns. align-items: start (not stretch) because,
   unlike the dashboard's fixed-height row, this row's three columns hold
   naturally different amounts of content (a ten-row list vs. a full
   workbook) and should not be forced to equal height. */
.ru-grid {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr) 260px;
  gap: var(--mom-space-6);
  align-items: start;
  /* DENSITY PASS, 2026-08-07 (2): was --mom-space-9 (22px). Measured against the
     dashboard's own analogous row-to-row rhythm - main's own gap (app.css:142-148)
     and .notewell-col's own stacked-panel gap (app.css:381-386) both read
     --mom-space-6 (16px), not 22px. This row's gap to the 05 PREVIOUS/NEXT row
     below had no documented reason to run looser than that real benchmark, so it
     now matches it exactly. */
  margin-bottom: var(--mom-space-6);
}
.ru-center-col {
  display: flex;
  flex-direction: column;
  /* DENSITY PASS, 2026-08-07 (2): was --mom-space-9 (22px), the same undocumented
     drift as .ru-grid's margin-bottom above. This is the video-to-workbook gap
     BELOW 901px only (901px+ swaps to display:contents, see the media query
     further down, and the real desktop gap comes from .ru-grid's own gap plus
     .ru-panel-workbook's margin-top instead). .notewell-col (app.css:381-386) is
     the dashboard's real precedent for "two panels stacked in one column" and
     runs --mom-space-6 (16px), so this now matches it rather than a wider,
     unbenchmarked value. */
  gap: var(--mom-space-6);
  min-width: 0;
}
.ru-rail-right {
  display: flex;
  flex-direction: column;
  gap: var(--mom-space-6);
  min-width: 0;
}

/* ---- 03 WORKBOOK, full grid width, desktop only --------------------------
   Anric, 2026-08-06: "Box 03, the workbook... you're limiting yourself to
   the middle half of the whole page... feel free to use the entire width
   of the page, stop squashing everything into the middle part" - the same
   correction he already made once for RAMP UP's overall page column (see
   this file's own top-of-file comment), now applied to the workbook panel
   specifically. Grid-placement change, not a max-width removal: .rw itself
   never had a cap, the 60%-of-viewport look came entirely from 03 WORKBOOK
   living inside .ru-center-col, the middle 1fr track of the three-column
   grid above. Scoped to 901px+ (the same breakpoint course-workbook.css's
   own "Desktop rail takeover" already uses) so the <=900px stacked layout
   below is completely untouched - .ru-center-col there keeps behaving
   exactly as it always has, zero regression risk at 375px.

   display: contents on .ru-center-col removes ONLY its own box, not its
   children - 02 VIDEO and 03 WORKBOOK become direct items of THIS grid
   (.ru-grid), placeable independently, while 01 MODULES, the right rail and
   05's own row keep their existing markup untouched. 02 VIDEO stays pinned
   to the centre column exactly where it already was (same width, same
   1280px video cap - see course.css's own .ru-video-frame rule, untouched);
   03 WORKBOOK gets its own explicit full-width row underneath, spanning
   every column instead of sharing the centre one. */
@media (min-width: 901px) {
  .ru-center-col {
    display: contents;
  }
  .ru-rail-protocols {
    grid-column: 1;
    grid-row: 1;
  }
  .ru-panel-video {
    grid-column: 2;
    grid-row: 1;
  }
  .ru-rail-right {
    grid-column: 3;
    grid-row: 1;
  }
  .ru-panel-workbook {
  /* ADDED 2026-08-08. A grid item's default min-width is auto, so its widest
     unbreakable content can force its track wider than the viewport. The old
     .ru-center-col wrapper carried min-width: 0 and absorbed this; the
     .ru-layout-workbook-right structure has no such wrapper, and REAP's fuller
     workbook content then pushed a 375px viewport to 611px of scrollWidth.
     Generic and safe: this can only ever prevent overflow, never cause it. */
  min-width: 0;
    grid-column: 1 / -1;
    grid-row: 2;
    margin-top: var(--mom-space-3);
  }
}

/* ---- Left rail: 01 PROTOCOLS --------------------------------------------
   Real reuse of the dashboard's own PORTALS rail component (momentum.css
   section 11): .mom-portal-list / .mom-nav-item / .nav-icon / .nav-label,
   filled by course-nav.js the same way app.js fills #portal-list. The
   two-character badge is the protocol's own zero-padded number (01-10),
   not a letter code - this page is numbered throughout (PROTOCOL 01, 01
   VIDEO...) so a numeric badge reads as one consistent system rather than
   inventing ten separate two-letter abbreviations nothing else on the page
   uses. Current protocol reuses .mom-nav-item.is-active, the exact modifier
   the real portal rail uses for "the page you are on" - not a new class. */
.ru-rail-protocols .mom-portal-list {
  max-height: none;
}
/* BUG FIX (Anric, reported repeatedly across RAMP UP, REAP and now Becoming
   Unstoppable): "The modules on the left are cut off... 'Build the Machines'
   is only 'Build the Mac' or 'Harness Your'." Root cause: .nav-label
   (momentum.css section 11) is written for the DASHBOARD's own fixed-width
   PORTALS rail, where a single-line, ellipsis-truncated label is correct -
   every dashboard portal name is short by design. A course module title is
   member-authored prose ("BUILD THE MACHINE", "HARNESS YOUR POWER") with no
   such length guarantee, and the rail itself is only 240px (260px at
   1400px+) wide, so `white-space: nowrap` clips real words. This file
   already fixed the SAME defect below 900px (see that media query further
   down); the truncation was never fixed at desktop width, where the rail is
   just as narrow. Scoped to .ru-rail-protocols so the dashboard's own real
   PORTALS rail (a different element on a different page) keeps its correct
   single-line ellipsis behaviour - this never touches the shared .nav-label
   rule itself, only overrides it inside this one course-engine component,
   at every width, not just mobile. align-items: start on the row so a
   wrapped two-line title lines up with the top of its badge instead of
   centering awkwardly against it. */
/* DENSITY PASS, 2026-08-07: the wrap fix above stopped titles clipping, but
   Anric's next note was the wrap fix's own second half - "the label type is
   too large for a 240px rail even when wrapping... a two-line title still
   eats vertical space and looks clumsy." Measured before this pass: the
   longest live title anywhere in the two courses ("INTEGRATION MASTERY &
   2026 VISION") wrapped to a full THREE lines at the inherited 13px
   .nav-label size, in a rail that is only 240-260px wide. Sized down (not
   truncated - text-overflow stays clip/visible from the rule above, ellipsis
   is never reintroduced) so the same title now wraps to two tight lines
   instead of three. */
.ru-rail-protocols .nav-label {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  font-size: 11px;
  letter-spacing: 0.5px;
  line-height: 1.25;
}
.ru-rail-protocols .mom-nav-item {
  align-items: start;
  padding-top: 8px;
  padding-bottom: 8px;
}
.ru-rail-protocols .nav-icon {
  margin-top: 1px;
}

/* ---- Right rail: PROGRESS mirror, REMOVED 2026-08-08 ----------------------
   Anric, on the live player: "the progress bar should go, I don't think it
   adds any value" - this mirror is a live read-only copy of that same bar
   (course-workbook.css's own .rw-progress, see that file's matching
   comment), so it goes too. Same idiom this file already uses for the old
   04 SECTIONS shell just below (.ru-rail-sections's own comment): hidden,
   not deleted from any of the 26 already-shipped pages that carry this
   markup - course-nav.js's wireProgressMirror() still runs and still writes
   into it (harmless, nothing on screen reads it), only the on-screen panel
   is gone, so there is no dead space left where it was (display:none takes
   it out of .ru-rail-right's own flex flow entirely, gap included). */
.ru-progress-mirror {
  display: none;
  gap: 0;
  padding-top: var(--mom-space-4);
  padding-bottom: var(--mom-space-4);
}
.ru-progress-mirror-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--mom-border-faint);
}
.ru-progress-mirror-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--mom-radius-full);
  background: var(--mom-gold);
  box-shadow: 0 0 10px var(--mom-gold);
  flex-shrink: 0;
}
.ru-progress-mirror-label {
  color: var(--mom-gold);
  font-weight: 600;
}
.ru-progress-mirror-pct {
  margin-left: auto;
  color: var(--mom-gold);
  font-weight: 700;
}
.ru-progress-mirror-track {
  width: 100%;
  height: 10px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: var(--mom-radius-xs);
  overflow: hidden;
}
.ru-progress-mirror-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--mom-gold) 0%, var(--mom-gold-ops) 100%);
  border-radius: var(--mom-radius-xs);
  transition: width 0.3s ease;
  width: 0%;
}
.ru-progress-mirror-text {
  margin: 8px 0 0;
  font-family: var(--mom-font-mono);
  font-size: 11px;
  color: var(--mom-text-muted);
}

/* ---- Right rail: 04 SECTIONS, REMOVED 2026-08-08 --------------------------
   Anric, on the live player: "it's not clear that the sections on the far
   right belong to the notes down below." This used to be a second jump list
   duplicating the workbook's own top tab bar - the duplication itself was
   the bug. The real fix is in course-nav.js (which no longer builds this
   rail's contents at all - see its own comment) and course-workbook.css
   (.rw-tabs is now the full-width, numbered, always-visible replacement).

   This rule is the one exception to "never hide with display:none" in that
   fix: course-nav.js no longer builds any DOM into #ru-section-rail-list, so
   there is no "dead DOM that still gets built" here to worry about - the
   thing left behind is a purely static, permanently-empty markup shell
   (<nav class="ru-rail-sections"><div class="mom-section-label">04
   SECTIONS</div><div id="ru-section-rail-list"></div></nav>) baked into all
   26 already-shipped rampup-N/reap-N/unstoppable-N pages. Editing 26 shipped
   pages was out of scope for this pass (see this repo's own course-template
   standard, section 1, on module pages carrying their own copy of shell-
   adjacent markup), so the empty shell is collapsed here instead, in the one
   shared file every page already links. Anric's "04 simply no longer
   exists" holds visually either way; 05 PREVIOUS/NEXT is untouched and keeps
   its own number, per his explicit instruction not to renumber it. */
.ru-rail-sections {
  display: none;
}

/* ---- Numbered panels ----------------------------------------------------
   .mom-panel + .mom-section-label (momentum.css sections 3 and 4), the same
   idiom every dashboard panel uses - see public/index.html's 01 PORTALS
   through 08 QUICK LINKS. .mom-panel already carries its own shadow + top
   hairline (momentum.css section 3, --mom-shadow-panel + .mom-panel::before)
   which only reads once the page atmosphere above gives it something to sit
   above. The one exception below is 02 VIDEO: Anric, 2026-08-06, "it is the
   reason the member came," gets the dashboard's strongest raised-surface
   treatment (--mom-shadow-feature, momentum.css section 1 - the same token
   .capital-magnet uses for the one deliberately-raised feature card on
   public/index.html) in place of .mom-panel's own default. Every other rule
   below only sets this page's own vertical rhythm, unchanged. */
/* Anric, 2026-08-07: "the footer of navigation in box five... is absolute
   overkill, way too much." It is a navigation footer (two links), not a
   content panel, so it does not need .mom-panel's own default padding
   (sized for content-heavy panels like 03 WORKBOOK) or the section label's
   default bottom margin (sized for a label sitting above a tall body).
   Scoped to .ru-panel-prevnext only - the generic .mom-panel/.mom-section-
   label rules other panels on this page (and every other page in the
   product) still use are untouched. The two tiles themselves (.ru-prevnext-
   tile below) already are a compact two-tile row; this trims the chrome
   around them so the panel reads as a footer, not a fifth feature card. */
/* DENSITY PASS, 2026-08-07 (Anric, "the font is too big," said generally
   across the course chrome): momentum.css's own .mom-section-label is sized
   for the DASHBOARD's own panels (16px, --mom-text-lg, "panel headings
   15-17px" tier) - correct there, where a member sees each panel heading
   once. This page's numbered panels (01 MODULES, 02 VIDEO, 03 WORKBOOK, 05
   PREVIOUS/NEXT - 04 was SECTIONS, removed 2026-08-08, see
   .ru-rail-sections's own comment) are chrome around a workbook a
   member scrolls past dozens of times a module; the same 16px reads as
   loud, repeated shouting rather than a one-time orientation cue. Scoped to
   .ru-wrap so the real dashboard's own panels (a different page entirely)
   keep momentum.css's 16px, untouched. */
.ru-wrap .mom-section-label {
  font-size: 13px;
  margin-bottom: var(--mom-space-5);
  padding-bottom: var(--mom-space-3);
}
.ru-panel-prevnext {
  margin-top: 0;
  padding: var(--mom-space-5) var(--mom-space-6) var(--mom-space-6);
}
.ru-panel-prevnext .mom-section-label {
  margin-bottom: var(--mom-space-3);
  padding-bottom: var(--mom-space-2);
}

/* ---- 05 PREVIOUS/NEXT: Save/Download/Email host, PROMOTED TO BASE 2026-08-08
   See course-nav.js's renderFoot() own comment: this is the generic
   [data-rw-actions-host] every course page now carries, filled at runtime by
   course-workbook.js's buildInlineActions() with the same Save/Download/
   Email controls the old floating .rw-sticky-bar used to show (removed
   outright, see course-workbook.css's own comment). .rw-actions-inline
   (course-workbook.css) is built stacked/full-width by default for a NARROW
   host column (unstoppable-4's own left rail, its first consumer); 05 is a
   full-width footer panel, not a narrow rail, so it lays out as one row
   instead - degrades to wrapped/stacked on its own at narrow widths via
   flex-wrap, no extra breakpoint needed, same safety net .rw-actions (the
   page-authored actions block) already relies on.

   THREE ZONES IN ONE ROW, TRUE CENTER, promoted from page-specific to the
   base engine: Anric, looking live at REAP: "you have also messed up the
   Save/Download/Email function that should be sitting in the middle... on
   the left is the previous module, and the middle is the Save/Download/
   Email function. On the right is the next module." This exact three-zone
   grid already existed, correctly, but only for two experimental layout
   modifiers (.ru-layout-v2, rampup-1; .ru-layout-workbook-right,
   unstoppable-3 - see those rules further down, now redundant restatements
   of what's here, left in place rather than deleted mid-pass while another
   session is editing this same file). Every OTHER course page (every REAP
   lab, RAMP UP protocols 2-10, Becoming Unstoppable 1/2/4) never got it and
   still rendered the actions host stacked ABOVE the previous/next tiles -
   that stacked-above shape is the "messed up" placement he reported. Real
   CSS grid (1fr auto 1fr) on #ru-foot itself, not flex + justify-content:
   space-between, for the reason .ru-layout-v2's own original comment
   documents: lab 1 has no previous tile and lab 12 has no next tile, and a
   named grid column reserves that track's space whether or not a tile
   fills it, so the actions block (grid-column 2, justify-self: center)
   stays mathematically centered either way, never sliding left or right
   when a neighbour is missing. renderFoot() emits, in DOM order, the
   actions host div then a <nav class="ru-prevnext-grid"> wrapping the
   prev/next tiles as two siblings; display: contents dissolves that nav's
   own box so its two <a> tiles become direct grid items of #ru-foot
   alongside the actions div - three real columns: previous | actions |
   next. The old stacked-row styling (space-between within the actions row,
   a bottom rule under it) is gone: the actions row and the prevnext tiles
   now share one row, not two. */
.ru-foot-actions:empty {
  display: none;
}
#ru-foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--mom-space-5) var(--mom-space-6);
}
.ru-foot-actions {
  grid-column: 2;
  justify-self: center;
  margin-bottom: 0;
}
.ru-foot-actions .rw-actions-inline {
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
}
.ru-foot-actions .rw-actions-inline-buttons {
  flex-direction: row;
  flex-wrap: wrap;
}
.ru-foot-actions .rw-actions-inline-buttons .rw-btn {
  width: auto;
}
.ru-panel-video {
  box-shadow: var(--mom-shadow-feature);
}

/* ---- Video hero --------------------------------------------------------
   VIDEO CAP, CORRECTED 2026-08-08: the 720px cap below used to carry a
   comment claiming "the masters are not high quality and look bad blown up
   full width." Anric, looking at REAP live: "you're building a very large
   video container with a small video in it" - measured with ffprobe on the
   real source files rather than re-derived from the old comment, that
   premise was false for both courses. REAP lab masters are 1280x720
   (progressive, the video elements' own width/height attributes already say
   so - see e.g. public/reap-1/index.html's <video width="1280"
   height="720">). RAMP UP masters are 1920x1080, an even bigger native
   frame. A 720px box was showing a native 1280px master at 56 percent of
   its real size, inside a centre column now roughly 1050px wide - that gap
   was the empty space he was seeing, not a quality problem. Cap raised to
   1280px: REAP's masters render at their true native width without ever
   upscaling past it, and it is still a downscale for RAMP UP's 1920-wide
   masters, so neither course is ever blown up beyond its own source
   resolution. width: 100% (below) keeps this fully responsive - the video
   still shrinks to fit any column narrower than 1280px, including the
   375px mobile floor - only the previous artificial ceiling is gone. Ready
   to receive an <iframe> or <video>: keep that element's own width="1280"
   height="720" attributes when it is dropped in (explicit width/height per
   the shell performance law); aspect-ratio below handles the fluid scaling
   under the cap, and the absolute-fill rule scales the embedded element
   itself to match the box regardless of its own attributes. */
.ru-video-hero {
  position: relative;
  margin: 0;
}
/* Gentle static gold glow behind the frame so the player sits proud of the
   page, per Anric's "gradient background... makes that video pop and gives
   us a 3D look." Same radial-gradient recipe as the page atmosphere above
   (never a new colour), sized to bleed a little past the frame cap on
   every side, z-indexed under the frame itself. No blur filter beyond the
   gradient's own soft-stop falloff, no animation. */
.ru-video-hero::before {
  content: "";
  position: absolute;
  inset: -28px;
  z-index: 0;
  background: radial-gradient(circle at 50% 45%, rgba(240, 193, 115, 0.16), transparent 70%);
  pointer-events: none;
}
.ru-video-frame {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--mom-radius-lg);
  overflow: hidden;
  background: var(--mom-bg-inset);
  border: 1px solid var(--mom-border-soft);
  box-shadow: var(--mom-shadow-feature);
}
.ru-video-frame > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.ru-video-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  padding: 24px;
}
.ru-video-placeholder-icon {
  width: 44px;
  height: 44px;
  color: var(--mom-border-strong);
}
.ru-video-placeholder p {
  margin: 0;
  font-family: var(--mom-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mom-text-muted);
  max-width: 320px;
}

/* ---- Video content: pending state (2026-08-06, REAP Bootcamp build) -----
   GENERIC capability: for a course module whose video has not been
   supplied yet, not for any one course or lab. Never gains a course name,
   a lab/module number, or any course-specific string - that rule holds
   here the same as everywhere else in this file (see this file's own
   top-of-file comment). Markup contract, reused verbatim by every module
   in this state, on every course:
     <div class="ru-video-frame ru-video-pending">
       <p class="ru-video-pending-note">...</p>
     </div>
   The wrapping element keeps every real .ru-video-frame rule above (the
   1280px cap, aspect-ratio, radius, dark inset background, border, elevation
   shadow) - .ru-video-pending only adds the flex centering this text state
   needs, layered on top of the same box a real <video> would sit in later,
   so swapping in the real video when it ships is a content change only,
   never a structural one. The note text is centered directly rather than
   depending on the frame's own layout, because `.ru-video-frame > *` above
   absolutely fills every direct child to the frame's own box. No pill
   radii, no italics, matches every other Momentum surface. */
.ru-video-pending {
  background: var(--mom-bg-inset);
}
.ru-video-pending-note {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 24px;
  text-align: center;
  font-family: var(--ru-font-body);
  font-size: 14px;
  line-height: 1.6;
  color: var(--mom-text-muted);
}

/* ---- Video content: mp4 hero -------------------------------------------
   Native <video> for the nine direct GHL CDN masters. controls, preload=
   "none", playsinline; no autoplay, no loop, no muted-autoplay. preload=
   "none" is deliberate: nothing downloads until the member presses play.
   Fills .ru-video-frame via the `.ru-video-frame > *` absolute-fill rule
   above; the width/height attributes on the element itself stay in the
   markup as the browser sizing hint (explicit width/height, shell
   performance law, section 10 of the rebuild brief). */
.ru-video {
  display: block;
  width: 100%;
  height: 100%;
  background: #000;
}

/* ---- Video content: mp4 centre play overlay -----------------------------
   Anric, on the live page: "the video player should have a play icon in
   the middle of it, like a YouTube video. It's hard to find that small
   little play button." A native <video controls> hides its own play
   button inside the bottom control bar - a small target, easy to miss,
   worse on a two-hour recording where the obvious click target is the
   centre of the frame. REUSE, not a new design: this is the exact same
   .ru-yt-play visual protocol 7's YouTube facade already uses (gold icon
   panel, this file's own "YouTube click-to-load facade" section above),
   applied as an overlay sibling of a real <video> instead of standing in
   for one. Markup contract, one overlay per <video>, course-video.js's
   own header repeats this:
     <div class="ru-video-frame">
       <video class="ru-video" ...>...</video>
       <button type="button" class="ru-yt-play ru-video-play-overlay"
               aria-label="Play video: TITLE">...</button>
     </div>
   No extra positioning rule needed here: `.ru-video-frame > *` above
   already makes every direct child (the <video>, this button) an
   absolute-fill box inset:0 in exactly the same box, so the overlay sits
   pixel-for-pixel over the video with zero effect on the frame's own
   aspect-ratio or the panel's measured height - the DOM order (button
   after video) is what puts it on top, no z-index needed. Scoped by
   markup only, not by a page class or media query: only a page that ships
   this button gets this behaviour (rampup-1 today; course-video.js's own
   wireVideoPlayOverlays() is otherwise fully generic, so a two-part
   protocol like 3 or 6 can reuse it unchanged, one overlay per part). */
.ru-video-play-overlay {
  cursor: pointer;
}
.ru-video-play-overlay:hover,
.ru-video-play-overlay:focus-visible {
  background: linear-gradient(180deg, rgba(240, 193, 115, 0.14), transparent 60%), var(--mom-bg-inset);
}
/* Hidden for good after the member's first real play (course-video.js sets
   the [hidden] attribute once, on the video's own native "play" event,
   never re-shown on a later pause) - a real CSS rule is required to win
   over `.ru-yt-play { display: flex }` above, since the browser's own
   built-in `[hidden]{display:none}` UA rule is always lower precedence
   than anything in this stylesheet, tie or no tie. */
.ru-video-play-overlay[hidden] {
  display: none;
}

/* ---- Video content: two-part protocols (3 and 6) -----------------------
   Two independent frames stacked, Part 1 first, each labelled from the
   manifest. Not a carousel, not tabs: both fully present in the DOM and
   readable at 375px. Each part's own .ru-video-frame still respects the
   1280px cap above. */
.ru-video-hero-multi {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.ru-video-part-label {
  margin: 0 0 8px;
  max-width: 1280px;
  margin-left: auto;
  margin-right: auto;
  font-family: var(--mom-font-mono);
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--mom-gold);
  text-align: center;
}

/* ---- Video content: YouTube click-to-load facade (protocols 7) ---------
   No iframe on page load. A styled Momentum play panel stands in until the
   member taps it; public/assets/course-video.js swaps it for a
   youtube-nocookie.com iframe with autoplay=1 on click. Zero third party
   bytes before the tap: see course-video.js and section 10 of the rebuild
   brief for why this matters (a YouTube iframe pulls roughly a megabyte of
   third party JavaScript on load). Every instance still respects the
   1280px .ru-video-frame cap above, including the five embedded further
   down protocol 7's own workbook sections. */
.ru-yt-play {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 0;
  padding: 24px;
  border: none;
  background: linear-gradient(180deg, rgba(240, 193, 115, 0.08), transparent 60%), var(--mom-bg-inset);
  color: var(--mom-text);
  font-family: var(--ru-font-body);
  cursor: pointer;
  text-align: center;
}
.ru-yt-play:hover,
.ru-yt-play:focus-visible {
  background: linear-gradient(180deg, rgba(240, 193, 115, 0.14), transparent 60%), var(--mom-bg-inset);
}
.ru-yt-play-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: var(--mom-radius-lg);
  border: 1px solid var(--mom-border-strong);
  background: var(--mom-bg-inset);
}
.ru-yt-play-icon svg {
  width: 22px;
  height: 22px;
  fill: var(--mom-gold);
}
.ru-yt-play-title {
  font-family: var(--mom-font-mono);
  font-size: 13px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--mom-gold);
}
.ru-yt-facade iframe {
  border: 0;
}
.ru-video-note {
  max-width: 1280px;
  margin: 12px auto 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--mom-text-muted);
  text-align: center;
}

/* ---- Content tags, 02 VIDEO panel ---------------------------------------
   Static markup only, sourced verbatim from docs/rampup-sources/video-tags.json
   (Anric: without tags on screen a member can't tell what a video covers, and
   OrO's own search index was already reading this file with nothing on the
   page to show for it). One line summary above 3-5 chips built from that
   protocol's own real Momentum badge component (.mom-badge/.mom-badge--
   primary, momentum.css section 5 - squared 3px corners, never a pill) rather
   than a comma sentence or an invented pill shape. Sits directly under the
   video, inside the same 1280px column the frame itself is capped to, so it
   reads as part of the video, not a separate panel.

   DENSITY PASS, 2026-08-08: Anric, on the live REAP lab pages, "you're also
   still using too many lines for the text underneath the video container
   and the search tags." This is a caption, not a content panel - all five
   values below are pulled in one notch from the block's earlier spacing
   (16px top margin to 10px, 14px rule clearance to 10px, the summary's own
   1.6 line-height to 1.45, its 10px bottom margin to 6px, and the tag
   row's own 8px gap to 6px) so player, summary and tags read as one
   compact caption block instead of three visually separate stacked rows.
   Every tag stays - this tightens spacing only, never drops content. */
.ru-video-tags {
  max-width: 1280px;
  margin: 10px auto 0;
  padding-top: 10px;
  border-top: 1px solid var(--mom-border-faint);
}
.ru-video-summary {
  margin: 0 0 6px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mom-text-soft);
}
.ru-video-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* Compact chip size for this one tag row only (momentum.css's own .mom-badge
   default - 10.5px type, 3px/8px padding, 1.5 line-height - is already the
   product's smallest badge tier, but Anric asked for smaller still here
   specifically): trims padding and line-height further, scoped to
   .ru-video-tag-list so no other badge anywhere in the product (dashboard
   status chips, workbook tags, anywhere else .mom-badge is reused) is
   affected. Font-size held at the existing 10.5px floor - shrinking type
   further starts to fight legibility, the spacing around it was the actual
   excess. */
.ru-video-tag-list .mom-badge {
  padding: 2px 7px;
  line-height: 1.3;
}
/* ---- v2: meta tags at full PANEL width, 2026-08-08 ------------------------
   Anric: "for the meta tags, use the whole container so that we're not
   using so many lines. You can use the full width, not just the video
   width, but the actual container width... Make that a full-width line."
   The base rule above caps .ru-video-tags at the same 1280px the VIDEO
   frame is deliberately capped to (a video-quality decision, untouched -
   see .ru-video-frame's own comment) and centers it under that box. The
   video keeps its own cap; only the summary sentence and the tag chips
   below it are freed to span 02 VIDEO's real panel width instead, so they
   wrap to fewer lines. Scoped to .ru-layout-v2 - the base 1280px cap stays
   exactly as-is for every other course page (moot in practice once the
   panel itself is narrower than 1280px, which it always is). */
.ru-wrap.ru-layout-v2 .ru-video-tags {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

/* ---- Bottom row: PREVIOUS / NEXT ----------------------------------------
   Full width, "treated like the QUICK LINKS row" (Anric): same
   .mom-quicklinks-grid / .mom-quicklink-tile component the dashboard's own
   QUICK LINKS panel uses, real border/radius/hover-shimmer inherited as-is.
   .ru-prevnext-tile is a sizing modifier only (taller, two lines of text)
   because a previous/next link needs room for a protocol number and a full
   title where a quick-link only ever shows one short label - it does not
   touch color, border or radius, which stay exactly .mom-quicklink-tile's
   own. The old "All ten protocols" full list that used to live down here is
   gone: the left rail (01 PROTOCOLS) is now the one and only full list,
   never repeated.

   display: contents (was flex-wrap: wrap until 2026-08-08): #ru-foot itself
   is now the 3-column grid (previous | actions | next, see that rule's own
   comment above) and this <nav> is only ever a DOM wrapper around the two
   <a> tiles - dissolving its own box lets both tiles become direct grid
   items of #ru-foot, placed by the two rules just below, instead of laying
   themselves out inside a flex row of their own. */
.ru-prevnext-grid {
  display: contents;
}
.ru-prevnext-prev {
  grid-column: 1;
  justify-self: start;
}
.ru-prevnext-next {
  grid-column: 3;
  justify-self: end;
}
.ru-prevnext-tile {
  flex: 1 1 260px;
  min-height: 56px;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: var(--mom-space-4) var(--mom-space-5);
  text-align: left;
  text-transform: none;
}
.ru-prevnext-tile.ru-prevnext-next {
  align-items: flex-end;
  text-align: right;
}
.ru-prevnext-eyebrow {
  font-family: var(--mom-font-mono);
  font-size: 10px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mom-gold);
}
.ru-prevnext-title {
  font-family: var(--ru-font-body);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2px;
  text-transform: none;
  white-space: normal;
  color: var(--mom-text-body);
}

/* ---- Mobile / stacked layout, below 900px -------------------------------
   Same single-column stacking breakpoint the dashboard itself uses
   (app.css: "the real single-column stacking breakpoint... 900px, already
   used by every rule below"). Reading order at 375px: heading, video,
   workbook, protocol list, previous/next - the right rail's PROGRESS mirror
   is redundant with the workbook's own in-panel progress bar, which
   course-workbook.css keeps on screen at this same breakpoint, so the whole
   rail is hidden rather than duplicated. (The tab bar, .rw-tabs, is not part
   of this rail and is visible at every width - see its own comment in
   course-workbook.css.) */
@media (max-width: 900px) {
  /* ADDED 2026-08-08. Below 900px the grid is a single column, but a grid item's
     default min-width is auto, so the widest unbreakable content inside any panel
     can size the whole track wider than the viewport. Measured on reap-6 at 375px:
     every panel resolved to 590px and the document scrolled to 611px. Zeroing the
     minimum on the grid, its direct children and the left column lets the track
     obey the viewport and pushes the overflow back inside whichever component owns
     it, where the datagrid and table wrappers already scroll on their own. */
  .ru-grid,
  .ru-grid > *,
  .ru-col-left,
  .ru-col-left > * {
    min-width: 0;
    max-width: 100%;
  }

  .ru-grid {
    grid-template-columns: 1fr;
  }
  .ru-rail-protocols {
    order: 2;
  }
  .ru-center-col {
    order: 1;
  }
  .ru-rail-right {
    display: none;
  }
  /* .nav-label wrap (was mobile-only here) now lives as a base, always-on
     rule above (.ru-rail-protocols .nav-label) so a long title reads in
     full at desktop width too, not just below 900px - see that rule's own
     comment for the full "why". Nothing left to override at this
     breakpoint specifically. */
  /* 05 FOOTER stack, added 2026-08-08 alongside the base #ru-foot 3-column
     grid above: a 1fr/auto/1fr row grid does not wrap or stack on its own
     the way flex does, so without this override three items would squeeze
     into one illegible row at 375px instead of stacking sensibly. Explicit
     `order` on each of the three footer items keeps the same
     previous-actions-next reading order the desktop grid columns already
     give, since named grid-column placement (1/2/3) does not apply once
     the container collapses to a single column. Same pattern already
     proven at this exact breakpoint for .ru-layout-v2 and
     .ru-layout-workbook-right further down this file. */
  #ru-foot {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }
  .ru-foot-actions {
    grid-column: 1;
    order: 2;
  }
  .ru-prevnext-prev {
    grid-column: 1;
    justify-self: stretch;
    order: 1;
  }
  .ru-prevnext-next {
    grid-column: 1;
    justify-self: stretch;
    order: 3;
  }
}

@media (min-width: 600px) {
  .ru-brand {
    font-size: 32px;
  }
}

@media (min-width: 1400px) {
  .ru-grid {
    grid-template-columns: 260px minmax(0, 1fr) 280px;
  }
}

/* ---- LAYOUT EXPERIMENT: workbook-right (video moves under the modules,
   30/70 split, PREVIOUS/NEXT + actions compress into column one) ----------
   Anric, looking at public/unstoppable-3/index.html live, three instructions
   verbatim: "Move Card02 video to the left column underneath Card01, the
   modules." "Widen the page split between column one and column two so that
   column one is 30% of the width and column two is 70% of the width." "Put
   the save download email functionality into the footer so that it does not
   overlay any other layers." Replaces this page's earlier .ru-layout-notes-
   first experiment (workbook in the dominant centre panel, video sticky in a
   narrow right rail) - renamed rather than edited in place, because "notes-
   first" no longer describes what this class does. A GENERIC layout
   modifier, first proved out on exactly one page (public/unstoppable-3/
   index.html, which carries the class below on its own .ru-wrap, added
   below the TOOL CONTENT START marker like everything else on that page)
   then, once Anric picked it as the chosen template layout, rolled out the
   same way to unstoppable-1, 2 and 4 (each carries this same class on its
   own .ru-wrap too, below its own TOOL CONTENT START marker) so every RAMP
   UP/REAP page stays byte-for-byte unaffected: every selector here is
   gated behind .ru-wrap.ru-layout-workbook-right, never a bare .ru-panel-
   video/.ru-rail-protocols/.ru-rail-right/.ru-panel-workbook/.ru-col-left/
   .rw-actions-inline rule, and nothing here names a course or page.

   REVISED, 2026-08-08 (THIS PASS) - Anric's own executive decision,
   verbatim, REPLACES every earlier footer instruction below it: "Take that
   entire section and compress it into column one on the left so that the
   workbook content can scroll freely without the photo." Box 05 (the old
   .ru-panel-prevnext row, full width, below .ru-grid) is DELETED from
   unstoppable-3/index.html outright, not hidden - there is no element on
   this page below .ru-grid any more, MEASURED in-browser at every scroll
   position: nothing has a bounding box below both columns. #ru-foot (the
   same div course-nav.js's renderFoot() already fills by element id,
   unchanged in that file) now lives INSIDE .ru-col-left, stacked directly
   under 02 VIDEO's own panel - see that markup's own comment for the exact
   placement, and the "PREVIOUS/NEXT + ACTIONS, IN COLUMN ONE" rule block
   below for how it lays out in a 30%-wide column.

   THE MECHANISM (901px+ only; see the mobile note below for <=900px): a
   genuine single-row, two-column grid - 30% for the left column, 70% for
   03 WORKBOOK. 01 MODULES, 02 VIDEO and PREVIOUS/NEXT + actions now all
   stack together in that left column INSIDE ONE WRAPPER (.ru-col-left, this
   page's own markup, not this shared file - see its own comment there for
   the roam-room mechanism that keeps 02 VIDEO sticky with three stacked
   children instead of the two it used to hold). fr units, not fixed pixel
   or percentage tracks, so the 30/70 ratio holds at any viewport width this
   modifier applies to without a second breakpoint - fr also beats the base
   rule's own 1400px+ three-column override on specificity alone, so no
   separate 1400px+ rule is needed here, the same reasoning
   .ru-layout-two-column's own comment below already documents for its
   1fr/2fr split. MEASURED in-browser at 1280px width, build served locally:
   the two columns render at a genuine 30/70 split of .ru-grid's own content
   box (grid-template-columns resolved to 369.594px/862.398px, an exact 3:7
   ratio - fr distributes the space remaining after the column gap is
   already subtracted, which is what "a genuine 30/70 split" means for a
   grid with a nonzero gap).

   READING ORDER, no renumbering needed: left to right, top to bottom this is
   01 MODULES, 02 VIDEO, 03 WORKBOOK - already the order the page's own
   markup and badge text use.

   TOP ALIGNMENT, FIX 2, 2026-08-08 (THIS PASS): Anric, verbatim: "I'm
   confused why the Box 03 workbook has now moved down and is aligned on the
   same bar as the video instead of aligned at the top on the same line as
   01 modules." Root cause of the bug he saw: the EARLIER construction below
   this line (before this pass) placed .ru-rail-protocols (01 MODULES) on
   ITS OWN, alone in grid row 1, specifically to keep it OUT of the sticky
   video's row (see the STICKY VIDEO note just below for why that mattered)
   - and that exact placement is what pushed 03 WORKBOOK's own row down to
   row 2, level with 02 VIDEO instead of 01 MODULES. Fixed by removing
   .ru-rail-protocols' own grid-column/grid-row rule entirely: it is simply
   the first child of .ru-col-left now, and .ru-col-left (below) is placed
   as the WHOLE column-1 grid item, sharing the grid's one and only row with
   03 WORKBOOK - so column 1's top (01 MODULES) and column 2's top (03
   WORKBOOK) start at the exact same grid line BY CONSTRUCTION, not by
   tuning a margin to match it. VERIFIED in-browser, scrolled to the top:
   .ru-rail-protocols and .ru-panel-workbook's own getBoundingClientRect()
   .top values are identical.

   STICKY VIDEO, ROAM ROOM WITH THREE CHILDREN NOW, not two: Anric, "this is
   going to be a template... if you have an extensive workbook, the video
   stays in place, and the workbook can scroll so you can keep watching the
   video as you're answering the questions." Built at TEMPLATE scale, not
   just for this page's own 4-module/3-section course: REAP labs run up to
   12 modules and 9 sections. The construction THIS PASS REPLACES kept 01
   MODULES OUT of .ru-col-left's sticky mechanics by placing it as an
   independent grid item in its own row and dissolving .ru-col-left itself
   (display: contents) so only 02 VIDEO shared a row with 03 WORKBOOK - the
   exact thing FIX 2 above just undid, because excluding 01 MODULES from the
   shared row is what broke top alignment. This pass keeps ALL THREE of 01
   MODULES, 02 VIDEO and PREVIOUS/NEXT + actions inside .ru-col-left, NEVER
   dissolved (no display: contents at any width now - see that class's own
   rule below), and instead gives THE WRAPPER ITSELF real roam room:
   align-self: stretch (below) pulls .ru-col-left's own outer box up to
   match the grid row's real height, set by 03 WORKBOOK - by a wide margin
   the tallest single occupant of that row (one open workbook section, a
   POWER NUGGET plus two or three questions, several with textareas, runs
   comfortably taller than 01 MODULES + 02 VIDEO + PREVIOUS/NEXT + actions
   combined, MEASURED in-browser, every section on this page checked).
   .ru-col-left itself stays flex-direction: column with no flex-grow on any
   child, so the three real panels stack at their own natural heights at the
   TOP of that now-tall box, leaving genuine empty space below PREVIOUS/NEXT
   - and that empty space IS 02 VIDEO's roam room, because 02 VIDEO's sticky
   containing block is .ru-col-left itself, which really is that tall now
   (a stretched grid item's box is a real box, not just "the row is tall
   while the item inside stays short").

   THIS IS NOT the construction that failed for .ru-layout-two-column's own
   .ru-col-left-sticky (read that class's full comment below): that wrapper
   only got slack from align-self: stretch when 03 WORKBOOK was reliably
   TALLER than the wrapper's own natural sum, which measured FALSE for one
   short REAP section there (735px workbook vs. 893px wrapper) - stretch
   never had anything to add. Becoming Unstoppable's own sections run
   comfortably longer than this page's three-item left column even at their
   shortest, so the same mechanism that failed there is reliable here -
   VERIFIED IN-BROWSER after building (not assumed from the CSS alone):
   scrolled with a real page scroll at three separate scroll positions, 02
   VIDEO's own getBoundingClientRect().top held at the same pinned position
   (81px + one gap token, under the shell header) at every one of them while
   03 WORKBOOK kept scrolling past it, then released once .ru-col-left's own
   row ran out of height.

   OFFSET CLEARS THE SHELL HEADER: top: calc(81px + --mom-space-6) uses the
   same measured shell-header-height constant (#mn-bar, every course page's
   sticky top bar) .ru-layout-two-column's own sticky rule below already
   uses, plus one gap token of breathing room, so the pinned video is never
   hidden under the header. max-height + overflow-y: auto is the same safety
   valve that rule uses too, for the case 02 VIDEO's own panel (hero +
   summary + tags) is taller than the viewport has room for on a short
   screen: it scrolls internally instead of clipping or being pushed off the
   top edge under the header.

   PROGRESS MIRROR: .ru-rail-right (the PROGRESS mirror) is not part of this
   three-panel design and is hidden outright, the same substitution
   .ru-layout-v2 and .ru-layout-two-column below already make - the
   workbook's own real in-panel progress bar (.rw-progress, normally
   suppressed at 901px+ by course-workbook.css's "Desktop rail takeover"
   rule) is un-suppressed here instead, so a progress readout still exists
   on screen once the mirror is gone.

   PANEL WEIGHT: 03 WORKBOOK is now the widest single panel on the page (70%
   of .ru-grid), the ONLY thing in column two top to bottom, and gets the
   raised --mom-shadow-feature treatment that used to belong to 02 VIDEO in
   the base three-column layout; 02 VIDEO, now in the narrower 30% column
   alongside 01 MODULES and PREVIOUS/NEXT + actions, drops to the plainer
   --mom-shadow-panel treatment - the same "one dominant panel per layout"
   convention .ru-layout-notes-first used to apply, carried over unchanged.

   MOBILE, <=900px: below this floor .ru-col-left stays its own plain flex
   column (the unconditional rule further down, untouched) - 01 MODULES, 02
   VIDEO, then PREVIOUS/NEXT + actions, plain block stacking, no grid
   involved, no sticky - and .ru-panel-workbook is a plain sibling after it,
   so the base engine's own <=900px rule (grid-template-columns: 1fr, above)
   simply stacks the two in DOM source order: 01 MODULES, 02 VIDEO,
   PREVIOUS/NEXT + actions, then 03 WORKBOOK. 02 VIDEO is deliberately NEVER
   sticky below 901px (no position/top/max-height carries down): a short
   phone viewport has no spare vertical room for a pinned video beside a
   scrolling workbook the way a laptop does, so this page follows the same
   "stack, don't pin" choice course-workbook.css's own mobile rules already
   make for the in-panel progress bar. .ru-rail-right stays hidden by the
   base engine's own <=900px rule above, unchanged, not restated here. */
@media (min-width: 901px) {
  .ru-wrap.ru-layout-workbook-right .ru-grid {
    grid-template-columns: 3fr 7fr;
  }
  .ru-wrap.ru-layout-workbook-right .ru-panel-video {
    /* The sticky unit. position: sticky, not fixed: it pins only while its
       own containing block (.ru-col-left, stretched to real roam room by
       align-self: stretch, below) has height left to scroll through, then
       releases and scrolls away normally with the rest of the page - never
       a floating overlay. top clears the shell's own sticky #mn-bar header
       (measured 81px, the same constant .ru-layout-two-column's own sticky
       rule below uses) plus one gap token of breathing room. max-height +
       overflow-y: auto is the safety valve for a short viewport where this
       panel (hero + summary + tags) alone is taller than the room available
       under the header: it scrolls internally rather than clipping or being
       pushed off-screen. */
    position: sticky;
    top: calc(81px + var(--mom-space-6));
    max-height: calc(100vh - 81px - var(--mom-space-6) * 2);
    overflow-y: auto;
    box-shadow: var(--mom-shadow-panel);
  }
  .ru-wrap.ru-layout-workbook-right .ru-panel-workbook {
    /* grid-row: 1, sharing the grid's one and only row with .ru-col-left -
       see the TOP ALIGNMENT comment above (FIX 2) for why this is what
       makes 03 WORKBOOK start level with 01 MODULES rather than 02 VIDEO. */
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    box-shadow: var(--mom-shadow-feature);
  }
  .ru-wrap.ru-layout-workbook-right .ru-rail-right {
    display: none;
  }
  .ru-wrap.ru-layout-workbook-right .rw-progress {
    display: block;
  }
}
/* .ru-col-left (01 MODULES + 02 VIDEO + PREVIOUS/NEXT + actions, this
   page's own wrapper markup - see its own comment there): a plain flex
   column at EVERY width, below 901px AND at 901px+ alike - unlike the
   construction this pass replaces, this is never reset to display: contents
   at any width any more. See the STICKY VIDEO comment above for why:
   dissolving the wrapper is what used to keep 03 WORKBOOK from top-aligning
   with 01 MODULES (FIX 2), so this pass keeps the wrapper as one real box
   and gives THAT box the roam room instead (the rule immediately below). */
.ru-wrap.ru-layout-workbook-right .ru-col-left {
  display: flex;
  flex-direction: column;
  gap: var(--mom-space-6);
  min-width: 0;
}
/* THE ROAM ROOM FIX, 901px+ only: .ru-col-left becomes the entire column-1
   grid item (one implicit row, shared with 03 WORKBOOK in column 2) and
   align-self: stretch pulls its own outer box up to match that row's real
   height - set by 03 WORKBOOK, its tallest occupant - so 02 VIDEO's sticky
   containing block (this wrapper) genuinely has slack to roam into. See the
   LAYOUT EXPERIMENT comment above ("STICKY VIDEO, ROAM ROOM WITH THREE
   CHILDREN NOW") for the full mechanism and why this does not repeat the
   align-self: stretch failure documented on .ru-layout-two-column's own
   .ru-col-left-sticky, below. */
@media (min-width: 901px) {
  .ru-wrap.ru-layout-workbook-right .ru-col-left {
    grid-column: 1;
    grid-row: 1;
    align-self: stretch;
  }
}

/* ---- workbook-right: PREVIOUS/NEXT + actions, IN COLUMN ONE ---------------
   Anric's own executive decision, this pass, verbatim (REPLACES every
   earlier "box 05 footer, three zones in one row" instruction): "Take that
   entire section and compress it into column one on the left so that the
   workbook content can scroll freely without the photo." unstoppable-3/
   index.html's own .ru-panel-prevnext row (the old box 05, a full-width
   sibling below .ru-grid) is deleted outright; the SAME #ru-foot div
   (course-nav.js's renderFoot() still fills it by element id, unchanged in
   that file - see that function's own comment) now lives inside
   .ru-col-left instead, stacked directly under 02 VIDEO's own panel. ZERO
   NEW JS: renderFoot() still emits the actions host ([data-rw-actions-host],
   as .ru-foot-actions) then a <nav class="ru-prevnext-grid"> wrapping the
   prev/next tiles, exactly as it does for every other course page - only
   #ru-foot's OWN position in the DOM moved, and course-workbook.js's
   buildActions() (single decision point,
   document.querySelector('[data-rw-actions-host]'), "first host found
   wins") still finds this one, since it is still the only
   [data-rw-actions-host] on the page.

   STACKED, NOT A ROW: Anric's own brief for this pass anticipates this -
   "in the narrow left column, previous/next and the actions will need to
   stack vertically rather than sit in a row." CHOSEN ORDER, top to bottom:
   PREVIOUS, then the Save/Download/Email actions, then NEXT - the same
   reading order the old three-zone row already used left-to-right, kept so
   nothing about "what comes first" changes for a returning member. This
   stacked shape now applies at EVERY width (901px+ included, not just the
   old <=900px-only override it replaces): the footer lives in a 30%-wide
   column at every width now, not only below 900px, so there is no width
   where a wide three-zone row would ever fit. display: contents on
   .ru-prevnext-grid still dissolves its own box so the two <a> tiles become
   direct children of #ru-foot's single column, same idiom as every other
   layout in this file. */
.ru-wrap.ru-layout-workbook-right #ru-foot {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--mom-space-4);
  justify-items: stretch;
}
.ru-wrap.ru-layout-workbook-right .ru-foot-actions {
  grid-column: 1;
  order: 2;
  justify-self: center;
  margin-bottom: 0;
}
.ru-wrap.ru-layout-workbook-right .ru-foot-actions .rw-actions-inline {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
  justify-content: center;
}
.ru-wrap.ru-layout-workbook-right .ru-prevnext-grid {
  display: contents;
}
/* Stacked eyebrow-over-title, not the base engine's single-line row: that
   row shape (.ru-prevnext-tile's own base rule, above) is sized for a
   full-width footer bar, wide enough for an arrow, a protocol number and a
   full title side by side - MEASURED in-browser: cramped and wrapping
   awkwardly at 30% column width. flex-direction: column, both tiles
   left-aligned (the base engine's own .ru-prevnext-next right-alignment is
   reset here too), reads cleanly stacked in a narrow column instead. */
.ru-wrap.ru-layout-workbook-right .ru-prevnext-tile,
.ru-wrap.ru-layout-workbook-right .ru-prevnext-tile.ru-prevnext-next {
  flex: 0 0 auto;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
}
.ru-wrap.ru-layout-workbook-right .ru-prevnext-tile.ru-prevnext-next .ru-prevnext-title {
  text-align: left;
}
.ru-wrap.ru-layout-workbook-right .ru-prevnext-prev,
.ru-wrap.ru-layout-workbook-right .ru-prevnext-next {
  grid-column: 1;
  justify-self: stretch;
}
.ru-wrap.ru-layout-workbook-right .ru-prevnext-prev {
  order: 1;
}
.ru-wrap.ru-layout-workbook-right .ru-prevnext-next {
  order: 3;
}

/* .rw's own bottom padding (course-workbook.css) reserves clearance for the
   floating .rw-sticky-bar - dead space here, since this page never builds
   that bar (the footer host above always wins, see buildActions()). Same
   top/side padding, just no floating-bar allowance at the bottom - same
   reset .ru-layout-v2 and .ru-layout-two-column below already apply for the
   identical reason. */
.ru-wrap.ru-layout-workbook-right .rw {
  padding-bottom: 16px;
}
@media (min-width: 600px) {
  .ru-wrap.ru-layout-workbook-right .rw {
    padding-bottom: 22px;
  }
}

/* MOBILE STACK ORDER, FIXED 2026-08-09. Anric specified the phone order
   explicitly: modules, then video, then workbook. It was rendering video
   ABOVE modules on all four pages.
   Root cause, and it is a leak rather than a mistake in this layout: the
   base rule `.ru-rail-protocols { order: 2 }` inside the 900px block near
   the top of this file was written when the rail was a SIBLING of a
   separate centre column, where order 2 correctly pushed it below the
   video. This layout puts the rail INSIDE .ru-col-left alongside the
   video, so that same declaration now reorders the two against each other
   and inverts them. The rule is still correct for the layouts it was
   written for, so it is reset here rather than changed there.
   Explicit orders on all three children rather than resetting only the
   rail, so the intended sequence is stated once and cannot be inverted
   again by a future base rule landing on any one of them. */
@media (max-width: 900px) {
  /* .ru-col-left is dissolved so its three children become direct children
     of the single column grid alongside 03 WORKBOOK. Without this the
     column is a flex container and the workbook is its SIBLING, so the
     previous/next and actions block can only ever render ABOVE the
     workbook, which is not the reading order a member wants on a phone. */
  .ru-wrap.ru-layout-workbook-right .ru-col-left {
    display: contents;
  }
  .ru-wrap.ru-layout-workbook-right .ru-rail-protocols {
    order: 0;
  }
  .ru-wrap.ru-layout-workbook-right .ru-panel-video {
    order: 1;
  }
  .ru-wrap.ru-layout-workbook-right .ru-panel-workbook {
    order: 2;
  }
  .ru-wrap.ru-layout-workbook-right .ru-panel-prevnext {
    order: 3;
  }
}

/* ---- LAYOUT EXPERIMENT: v2 (protocols+progress left, video right,
   workbook full width below), 2026-08-08, FIFTH REVISION - EXECUTIVE
   DECISION --------------------------------------------------------------
   Anric's own spec, verbatim, for RAMP UP Protocol 1 specifically: "a page
   that is a 30/70 or 40/60 split, where: Column one, the protocols, can be
   a little wider. Column two is the video container. The progress bar can
   be underneath the protocols table of contents in column one on the left,
   freeing up the right-hand side of the page to be about the video. The
   lessons and the sections are in tabs down below at full width."

   FIFTH REVISION, Anric's own words, called an executive decision after six
   sessions failed to get the footer right: "take the previous next module
   and put it in column one underneath progress. Take the save download
   email function, make it the same width as the progress bar, and drop it
   into column one underneath progress. So column one will now be card 01,
   the protocols. Followed by the progress indicator, followed by the save
   download function, and followed by the previous next module. They
   should take no more room than the bottom of the video container." There
   is no longer a separate full-width footer card anywhere on this page:
   04 PREVIOUS/NEXT (with its Save/Download/Email host) has moved, in
   rampup-1/index.html itself, from a standalone row below .ru-grid to
   directly inside .ru-grid, right after PROGRESS - see that file's own
   "EXECUTIVE DECISION" comment. Column one is now FOUR stacked blocks -
   01 PROTOCOLS, PROGRESS, the actions host, the prevnext tile - sharing
   one grid column, so all four are guaranteed the same x and width with
   zero extra sizing rule. Column two is the video panel and nothing else.

   THIRD REVISION FIX (still current): the first two revisions left
   grid-template-columns correct (two tracks) but left the OLD <aside
   class="ru-rail-right"> and its <nav class="ru-rail-sections"> (04
   SECTIONS) sitting in rampup-1's own markup, merely display:none'd - dead
   DOM Anric kept finding and calling "column 3". Both are deleted from
   rampup-1/index.html outright (not hidden).

   A GENERIC layout modifier, applied to exactly one page
   (public/rampup-1/index.html carries the class below on its own .ru-wrap,
   same convention .ru-layout-workbook-right above already established) so
   rampup-2 through 10 and every REAP/Accelerator/Unstoppable page stay
   byte-for-byte unaffected: every selector here is gated behind
   .ru-wrap.ru-layout-v2, never a bare .ru-panel-video/.ru-rail-protocols/
   .ru-progress-mirror/.ru-panel-workbook/.ru-panel-prevnext/#ru-foot rule,
   and nothing here names a course or page. Anric approves before this
   rolls out to any other page; rollout is then only ever adding this one
   class, per his own instruction, never copying these rules. Every other
   page still carries the real <aside class="ru-rail-right"> and its own
   real full-width 04/05 PREVIOUS/NEXT footer panel, both untouched.

   THE MECHANISM (901px+; see the single mobile block at the bottom for
   <=900px): .ru-panel-video and .ru-panel-workbook are already direct
   items of .ru-grid at this width (the base .ru-center-col display:contents
   rule). .ru-rail-protocols, .ru-progress-mirror and .ru-panel-prevnext are
   direct grid children too (siblings of .ru-center-col in rampup-1's own
   markup) - .ru-panel-prevnext is then ITSELF dissolved (display: contents,
   see the section below) along with its #ru-foot host, so its two real
   children (.ru-foot-actions, the Save/Download/Email host; the prevnext
   tile - this page has no previous tile, module 1 of 10) become direct
   grid items in their own right, placed by the SAME named-area mechanism
   as 01 PROTOCOLS/PROGRESS. Five named rows, one column for all of them:
   protocols, progress, actions, prevnext, then workbook full width. Video
   spans the first four rows on the right, "owns the whole right side" at
   whatever height those four column-one blocks add up to - which is why
   the row sizing below was worked out backwards from the video's own
   measured height, not guessed forwards. */
@media (min-width: 901px) {
  .ru-wrap.ru-layout-v2 .ru-grid {
    /* SIXTH REVISION: Anric, on the live page: "the video and its container
       are too big in column two, and column one is too small... make
       column one bigger, including the fonts, and the video container
       somewhat smaller." Widened from 27%/280px floor to 35%/320px - the
       FOURTH REVISION above went the opposite direction for the opposite
       complaint (column one too wide, dead space in it); the four-block
       stack now fills evenly (see the row/label sizing below, worked out
       backwards from this new narrower video height) so there is no dead
       space left to trigger that complaint again at the new split. */
    grid-template-columns: minmax(320px, 35%) minmax(0, 1fr);
    grid-template-areas:
      "protocols video"
      "progress  video"
      "actions   video"
      "prevnext  video"
      "workbook  workbook";
    /* SIXTH REVISION: row-gap tightened two more real token steps, from
       --mom-space-3 (10px, FIFTH REVISION) to --mom-space-1 (4px, the
       floor of the scale) - the video panel is shorter now that its own
       track is narrower (16:9), so the gaps between blocks are what gets
       reclaimed, per Anric's own instruction ("there's plenty of open
       space between progress and the auto save function... absorb that")
       rather than shrinking the protocol rows again, which he had already
       twice called too small. Measured in-browser at 1280px, backwards
       from the new video height: with the type bump below also applied,
       --mom-space-1 plus one more token off actions/prevnext's own padding
       (see that rule's own comment) is what actually closes the gap
       between column one's own last bottom edge and the video's. */
    row-gap: var(--mom-space-1);
  }
  .ru-wrap.ru-layout-v2 .ru-rail-protocols {
    grid-area: protocols;
    /* Panel's own top/bottom padding (base .mom-panel: --mom-space-6/
       --mom-space-8, 16/20px, sized for a content panel) tightened to
       match the slim-bar padding PROGRESS/actions/prevnext already use
       below - part of the same height-budget pass as the row/label
       shrinks, not a separate decision. */
    padding-top: var(--mom-space-3);
    padding-bottom: var(--mom-space-3);
  }
  /* FIFTH REVISION, ROWS SHRUNK TO FIT (context, superseded by SIXTH just
     below on font-size only): Anric's own resolution to the height
     conflict back then (column one's four-block stack ran to roughly
     833px against a roughly 640px video panel) - "shrink the protocol
     rows to fit," never shrink the video and never add a scrollbar. The
     row's own height floor (.nav-icon stepped to 22px, row padding
     --mom-space-1 top/bottom, 2px inter-row margin) is UNCHANGED here and
     still what keeps all ten rows on screen with no inner scrollbar - only
     the label font-size below moves, because the 22px icon (not the
     label's own line height) is still what sets each row's height, so a
     one-step font bump costs nothing further down this file's own budget.
     See this module's own build verification for the current measured row
     height and column-one-vs-video comparison.

     SIXTH REVISION: Anric, twice now: "the protocol rows... too small,"
     then explicitly "increase the type in column one... 13 or 14 px."
     font-size steps UP from --mom-text-sm (11px, FIFTH REVISION) to
     --mom-text-md (14px) - verified in-browser at the new wider (35%)
     column: every one of the ten protocol titles still fits on a single
     line at this width (the wider column is what pays for the bump - see
     the grid-template-columns comment above), so the row height stays the
     icon-bound 31px measured before this change, and the label bump adds
     zero height to column one's own budget. */
  .ru-wrap.ru-layout-v2 .ru-rail-protocols .nav-label {
    font-size: var(--mom-text-md);
    line-height: 1.3;
  }
  .ru-wrap.ru-layout-v2 .ru-rail-protocols .nav-icon {
    width: 22px;
    height: 22px;
    font-size: 9px;
  }
  .ru-wrap.ru-layout-v2 .ru-rail-protocols .mom-nav-item {
    grid-template-columns: 22px 1fr auto;
    padding-top: var(--mom-space-1);
    padding-bottom: var(--mom-space-1);
    margin-bottom: 2px;
  }
  /* "01 PROTOCOLS" section label: same slim-header treatment PROGRESS's
     own head row already uses in spirit - margin-bottom/padding-bottom
     tightened one notch further than the shared .ru-wrap .mom-section-
     label rule (further up this file), scoped to this one rail only. */
  .ru-wrap.ru-layout-v2 .ru-rail-protocols .mom-section-label {
    margin-bottom: var(--mom-space-2);
    padding-bottom: var(--mom-space-1);
  }
  .ru-wrap.ru-layout-v2 .ru-progress-mirror {
    grid-area: progress;
    /* Overrides the base .ru-progress-mirror{display:none} (further up
       this file, still correct for every other course page, which keeps
       the old right-rail markup and hides it there) - block, not flex:
       this panel's own children (head/track/text) are already plain
       stacked block elements with their own margins, nothing here needs
       flex-direction. */
    display: block;
    min-width: 0;
  }
  .ru-wrap.ru-layout-v2 .ru-panel-video {
    grid-area: video;
  }
  .ru-wrap.ru-layout-v2 .ru-panel-workbook {
    grid-area: workbook;
    margin-top: var(--mom-space-3);
  }
  /* VIDEO, LARGER: the source's 1280px cap (.ru-video-frame, above,
     corrected 2026-08-08 - see that rule's own comment for the measured
     1280x720/1920x1080 masters behind it) exists because the centre column
     used to be shared with a right rail. Column two here is the widest
     single track on the page (roughly 60-70% of .ru-wrap, see
     grid-template-columns above) with nothing beside it, so the video is
     allowed to fill it edge to edge rather than sit inside a cap at all:
     real member benefit once the frame is the only thing in its column,
     never an upscale past either course's own native master resolution in
     practice (columns this wide rarely exceed 1920px). aspect-ratio: 16/9
     (base rule, untouched) keeps it a clean 16:9 box at whatever width
     that resolves to. */
  .ru-wrap.ru-layout-v2 .ru-video-frame {
    max-width: 100%;
  }
  /* Real in-panel progress bar (.rw-progress) stays suppressed at this
     width, same as the base engine (course-workbook.css's own "Desktop
     rail takeover" rule, unchanged) - the live mirror relocated into
     column one above is the on-screen progress indicator here, exactly the
     same relationship every other course page already has between these
     two elements, just repositioned. */
}
@media (min-width: 1400px) {
  .ru-wrap.ru-layout-v2 .ru-grid {
    /* SIXTH REVISION: same 2%-narrower-at-this-width relationship the
       FOURTH REVISION established (27% at 901px+, 25% at 1400px+), carried
       over onto the new wider base split: 35% at 901px+, 33% here. */
    grid-template-columns: minmax(340px, 33%) minmax(0, 1fr);
  }
}

/* ---- v2: Save/Download/Email + Previous/Next, IN COLUMN ONE, FIFTH
   REVISION - EXECUTIVE DECISION ---------------------------------------------
   Supersedes every earlier revision's "footer" placement (THREE ZONES IN
   ONE ROW, then card 04 SLIMMED - both still live in the base engine above
   the "LAYOUT EXPERIMENT: v2" comment, unchanged, for every other course
   page's own real full-width footer). Anric, ending six sessions of
   "you're not getting the footer right": there is no full-width footer
   card left on this page at all.

   .ru-panel-prevnext is still real markup (rampup-1/index.html's own
   comment on this section - it now sits inside .ru-grid, right after
   PROGRESS) but is dissolved here, display: contents, so it contributes no
   box, no padding, no border and no "04 PREVIOUS/NEXT" label of its own -
   its .mom-section-label is hidden outright rather than left as a stray
   unplaced grid item once its parent's box is gone. #ru-foot (the generic
   host renderFoot(), course-nav.js, already fills on every course page,
   unchanged) is dissolved the same way, for the same reason: its two real
   children - .ru-foot-actions (Save/Download/Email) and the prevnext
   tile(s) (.ru-prevnext-grid, the <nav> wrapping them, is ALREADY
   display:contents in the base engine above) - become direct items of
   .ru-grid, placed by named area exactly like 01 PROTOCOLS and PROGRESS,
   so all four column-one blocks share the same x and width with zero
   extra sizing rule. This page (module 1 of 10) never renders a
   .ru-prevnext-prev tile at all (course-nav.js's findByNumber(0) returns
   null) - only .ru-prevnext-next lands in the "prevnext" area; the same
   rule below also targets .ru-prevnext-prev so a later module reusing
   .ru-layout-v2 with both neighbours present does not silently land two
   overlapping tiles in one cell - that combined case is unverified until
   Anric approves reuse (see this file's own top-of-section comment) and
   would need its own follow-up pass, not assumed correct here.

   BLOCK CHROME: .ru-foot-actions and the prevnext tile carry no visual
   weight of their own once dissolved out of their old card. Matched here
   to 01 PROTOCOLS/PROGRESS's own .mom-panel recipe (momentum.css section
   3: --mom-bg-panel, --mom-border-soft, --mom-radius-panel,
   --mom-shadow-panel - real Momentum tokens, not the prevnext tile's own
   .mom-quicklink-tile look it would otherwise keep) so all four
   column-one blocks read as one consistent family of cards instead of two
   different chrome recipes stacked on top of each other. Padding is
   --mom-space-4/--mom-space-9 (12px/22px), the same tightened top/bottom
   PROGRESS itself already uses above, in place of .mom-panel's own taller
   default (sized for a content-heavy panel like 03 WORKBOOK) - "no more
   room than the bottom of the video container" needs every block slim,
   not just the protocol rows. */
.ru-wrap.ru-layout-v2 .ru-panel-prevnext {
  display: contents;
}
.ru-wrap.ru-layout-v2 .ru-panel-prevnext .mom-section-label {
  display: none;
}
.ru-wrap.ru-layout-v2 #ru-foot {
  display: contents;
}
.ru-wrap.ru-layout-v2 .ru-foot-actions,
.ru-wrap.ru-layout-v2 .ru-prevnext-prev,
.ru-wrap.ru-layout-v2 .ru-prevnext-next {
  position: relative;
  background: var(--mom-bg-panel);
  border: 1px solid var(--mom-border-soft);
  border-radius: var(--mom-radius-panel);
  box-shadow: var(--mom-shadow-panel);
  /* Vertical padding, SIXTH REVISION: tightened one more token, from
     --mom-space-3 (10px, FIFTH REVISION) to --mom-space-2 (8px) - the last
     few pixels of the new, shorter video-height budget (column one now
     bumped a whole font step instead, see the protocol rail's own
     comment) - measured in-browser as the last piece needed to bring the
     fourth block's own bottom edge level with the video panel's, once the
     row-gap above was already at its own token floor. Horizontal stays
     --mom-space-9, matching every other column-one block's own side
     padding. */
  padding: var(--mom-space-2) var(--mom-space-9);
  margin: 0;
  min-width: 0;
}
.ru-wrap.ru-layout-v2 .ru-foot-actions {
  grid-area: actions;
  /* Base .ru-foot-actions rule (further up this file) sets
     justify-self:center for the old wide single-row footer, where the
     actions block was one auto-sized item among three; here it is the
     entire width of column one, same as every other column-one block. */
  justify-self: stretch;
}
/* ROLLOUT, 2026-08-09 (protocols 2-10): the comment this rule used to carry
   flagged this exact gap - "a later module reusing .ru-layout-v2 with both
   neighbours present ... would need its own follow-up pass, not assumed
   correct here." Protocol 1 (module 1 of 10) only ever renders
   .ru-prevnext-next; protocol 10 only ever renders .ru-prevnext-prev - a
   single tile per grid-area was never wrong for either of those. Every
   protocol 2-9 renders BOTH tiles, and CSS grid does not stack two items
   sharing one grid-area, it overlaps them - confirmed here rather than
   assumed. Fix: .ru-prevnext-grid (renderFoot()'s own <nav>,
   course-nav.js), dissolved by the base engine's own
   ".ru-prevnext-grid{display:contents}" rule for the old single-row
   three-column footer, is UN-dissolved here and made the real "prevnext"
   grid-area occupant instead: a two-column sub-grid so both tiles sit side
   by side. .ru-prevnext-prev/.ru-prevnext-next no longer claim the
   grid-area themselves. A lone tile (protocol 1 or 10) simply lands in
   column 1 of this 1fr/1fr sub-grid; nothing sits in column 2, so it reads
   as a single tile exactly as before, unchanged for those two pages.
   SCOPED to 901px+ (measured in-browser 2026-08-09, consolidation pass):
   this selector's specificity beats the base ".ru-prevnext-grid{display:
   contents}" rule at every width, not just this desktop breakpoint. Left
   unscoped, it also fires under the <=900px mobile-stack block below,
   turning .ru-prevnext-grid into a live two-column grid there too - the
   mobile block's own prev/next grid-row:5/6 then resolve against THIS
   inner grid instead of the outer .ru-grid, collapsing both tiles to a
   sliver (46px measured at 375px) instead of the full-width stacked tiles
   the mobile block's comment assumes. Wrapping here restores exactly what
   the page-scoped duplicate this rule was consolidated from already had. */
@media (min-width: 901px) {
  .ru-wrap.ru-layout-v2 .ru-prevnext-grid {
    grid-area: prevnext;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--mom-space-2);
    min-width: 0;
  }
  .ru-wrap.ru-layout-v2 .ru-prevnext-prev,
  .ru-wrap.ru-layout-v2 .ru-prevnext-next {
    /* Base .ru-prevnext-prev/.ru-prevnext-next rules (further up this file)
       set grid-column:1/3 for the old three-column #ru-foot row (previous |
       actions | next); this sub-grid only ever has 2 explicit columns
       (grid-template-columns above), so the base grid-column:3 on
       .ru-prevnext-next would otherwise auto-create a phantom implicit
       third column and strand the tile off to the right of an empty gap -
       confirmed in-browser, not assumed. Explicit grid-column:1/2 here
       overrides that. Base also sets justify-self:start/end for the old
       row; not relevant here, each tile fills its own sub-grid column. */
    grid-column: unset;
    justify-self: stretch;
    min-height: 0;
  }
}
/* .rw's own bottom padding (course-workbook.css) used to reserve clearance
   for the floating .rw-sticky-bar; that bar is gone site-wide now (base
   engine, unchanged here), and this page never builds it either way (the
   Save/Download/Email host above always wins, see buildActions()) - a
   touch more bottom padding than the shared default reads calmer under
   the workbook's own last question regardless. */
.ru-wrap.ru-layout-v2 .rw {
  padding-bottom: 18px;
}
@media (min-width: 600px) {
  .ru-wrap.ru-layout-v2 .rw {
    padding-bottom: 26px;
  }
}

/* ---- v2: mobile stack, <=900px, FIFTH REVISION ----------------------------
   Anric's explicit order, restated for the executive decision: "heading,
   video, protocols, progress, actions, previous/next, workbook." (Was
   "heading, video, protocols, progress, workbook" before the footer moved
   into column one - the two new blocks slot in between progress and
   workbook, the same order they read in column one at 901px+.)
   .ru-center-col is forced to display:contents at EVERY width for this
   modifier (the base engine only does this at 901px+, see that rule
   above) so 02 VIDEO and 03 WORKBOOK become independently orderable grid
   items here too. .ru-panel-prevnext/#ru-foot are dissolved at every
   width (the rules directly above are not scoped to the 901px+ block), so
   .ru-foot-actions and the prevnext tile(s) are already direct .ru-grid
   items at this breakpoint too - plain `order` places them exactly like
   every other direct item here, no extra inner grid needed the way the
   old three-column #ru-foot needed one collapsed back to a single track.

   EXPLICIT grid-column: 1 AND grid-row: 1-6 on every single item below,
   not left to grid auto-placement/`order`, both measured necessary
   in-browser: six items reach this grid through TWO layers of dissolved
   (display: contents) ancestors (.ru-center-col for video/workbook;
   .ru-panel-prevnext then #ru-foot for actions/prevnext) at once, deeper
   nesting than the 901px+ desktop rule ever has to resolve (there every
   item is a direct or single-layer-dissolved child). Auto-placement
   across that many dissolved layers first produced a multi-column layout
   (real horizontal overflow at 375px) with only grid-template-columns set;
   adding grid-column: 1 to every item fixed the column but left `order`
   alone still not reliably sequencing these same six items into rows -
   actions/prevnext (order 4/5) rendered ABOVE protocols/progress (order
   2/3) instead of below them. Named grid-row (1: video, 2: protocols, 3:
   progress, 4: actions, 5: prevnext, 6: workbook) removes any remaining
   dependency on auto-placement for BOTH axes and is the combination
   actually verified in-browser to produce Anric's own listed order with
   zero horizontal overflow. */
@media (max-width: 900px) {
  .ru-wrap.ru-layout-v2 .ru-grid {
    grid-template-columns: 1fr;
  }
  .ru-wrap.ru-layout-v2 .ru-center-col {
    display: contents;
  }
  .ru-wrap.ru-layout-v2 .ru-panel-video {
    grid-column: 1;
    grid-row: 1;
    width: 100%;
  }
  .ru-wrap.ru-layout-v2 .ru-rail-protocols {
    grid-column: 1;
    grid-row: 2;
    width: 100%;
  }
  .ru-wrap.ru-layout-v2 .ru-progress-mirror {
    grid-column: 1;
    grid-row: 3;
    width: 100%;
    display: block;
  }
  .ru-wrap.ru-layout-v2 .ru-foot-actions {
    grid-column: 1;
    grid-row: 4;
    width: 100%;
  }
  /* ROLLOUT, 2026-08-09 (protocols 2-10): same "both tiles" gap as the
     901px+ fix above (see that rule's own comment), applied at this
     breakpoint. .ru-prevnext-grid stays display:contents here (this block
     never overrides it, only the 901px+ block above does), so
     .ru-prevnext-prev/.ru-prevnext-next are still direct .ru-grid items
     reachable by explicit grid-row - giving them SEPARATE rows (5 then 6,
     workbook pushed to 7) stacks them instead of overlapping. Protocol 1
     never places a row-5 item (no prev tile) and protocol 10 never places
     a row-6 item (no next tile) - an unused row number that nothing
     references is never created, so neither page gains any extra height
     from this change. */
  .ru-wrap.ru-layout-v2 .ru-prevnext-prev {
    grid-column: 1;
    grid-row: 5;
    width: 100%;
  }
  .ru-wrap.ru-layout-v2 .ru-prevnext-next {
    grid-column: 1;
    grid-row: 6;
    width: 100%;
  }
  .ru-wrap.ru-layout-v2 .ru-panel-workbook {
    grid-column: 1;
    grid-row: 7;
    width: 100%;
  }
}

/* ---- v2: workbook typography and box de-nesting, 2026-08-08 --------------
   Anric, on rampup-1 specifically, after seeing the layout fix above live:
   "I hate your type and layout because sometimes it's left-aligned, some
   things are centered. There are so many boxes." Listed, in the order he
   sees them opening any section tab: a full-width CENTERED welcome banner
   ("WELCOME TO YOUR IDENTITY REVOLUTION..."), the six section tabs, ANOTHER
   full-width CENTERED section-title banner ("EXPERIENCES - YOUR AUTHORITY
   TIMELINE"), a POWER NUGGET box, a numbered question badge, a heading, a
   label, then finally the textarea. Judged against public/index.html, his
   own bar: "the dashboard is dense and calm, with quiet headings and
   consistent alignment."

   THIRD REVISION FIX: the earlier two revisions demoted .rw-banner and
   .rw-section-title IN PLACE (quieter styling, still both present either
   side of the tab bar) - Anric's real ask was "the tabs need to go right
   on top... nothing above them." .rw-section-title was already hidden
   outright by course-workbook.css's own base engine rule (Fix 5, "the
   active tab already names it," applies to every course page already);
   .rw-banner's words are now relocated verbatim to .ru-heading, next to
   the page title (see that class's own comment further up this file) and
   deleted from inside .rw entirely, so .rw-tabs really is the first thing
   in the panel now - no .ru-layout-v2 override needed for either class any
   more, both selectors below are removed rather than left painting a now
   nonexistent (.rw-banner) or already-hidden (.rw-section-title) element.

   ONE alignment, held everywhere below: left. Nothing here is centered. */
.ru-layout-v2 .rw-nugget {
  margin-top: 10px;
}
/* .rw-question p / .rw-nugget p / .rw-card p already inherit left alignment
   (block-level default, never centered anywhere in this file) - nothing to
   override there. .rw-progress (the in-panel progress meta, centered in the
   base engine) is left as-is: it is a compact stat readout, not prose, and
   Anric's own list above never named it. */
/* "Pick ONE alignment and hold it. Left aligned" is a blanket rule, not
   only for the elements he named opening a tab - .rw-final (the closing
   "YOUR IDENTITY COMMITMENT" card), .rw-critical/.rw-formula (the closing
   formula box), and .rw-acf/.rw-acf-rings (the Five Rings of the ACF
   diagram, THIRD REVISION addition - Anric, this pass: "if you look at the
   five rings of your ACF, those things are centered, whereas the rest of
   the text is left-aligned... it's still very hard to read") are the
   centered blocks left on this page after the fixes above - the exact
   inconsistency he called out, twice now. Their own inline
   style="text-align:center" attributes (rampup-1's own markup, not this
   shared file) were already removed at the source in an earlier revision;
   these shared-engine rules handle the rest, which live in course-
   workbook.css and would otherwise keep painting centered for this page
   alone. .rw-acf-rings li also carries `margin: 5px auto` + `max-width:
   460px` in the base engine (course-workbook.css) - a second centering
   mechanism (block auto-centering) beyond text-align, reset here too so
   each ring runs the full left-aligned width of the diagram box like every
   other list on this page. */
.ru-layout-v2 .rw-final,
.ru-layout-v2 .rw-critical,
.ru-layout-v2 .rw-formula,
.ru-layout-v2 .rw-acf {
  text-align: left;
}
.ru-layout-v2 .rw-acf-rings li {
  margin: 5px 0;
  max-width: none;
}

/* ---- REAP: drop the right-rail PROGRESS mirror, widen 01 LABS, video
   moves right, 01/02 equal height, 2026-08-08 ----------------------------
   Anric's own spec, verbatim: "I would remove the third column, which is
   the progress column, because that will allow you to make the column 01
   for the labs a little wider. Put the video container on the right-hand
   side of the page, and then make sure that boxes 01 and 02 are the same
   height. That makes that page look cleaner, and then the sections down
   below can have the full width of the page."

   SCOPE: REAP only. Every selector below is gated behind
   .ru-grid:has(.rw[data-course="reap"]) rather than a bare .ru-grid/
   .ru-rail-protocols/.ru-panel-video/.ru-rail-right rule, so RAMP UP,
   Becoming Unstoppable and Accelerator (none of which carry
   [data-course="reap"] on their .rw root - see BUILD-NOTES.md's own
   per-course data-course convention, already present on all 12 shipped
   REAP pages with no markup change needed here) are byte-for-byte
   unaffected. :has() reads the real DOM, not the render tree, so this
   still matches even though .ru-center-col (an ancestor of .rw at this
   width) is display:contents (see the base 901px+ rule above) - display
   never changes what a selector can see, only what paints.

   THE PROGRESS COLUMN: .ru-rail-right (the PROGRESS mirror plus the
   already-empty .ru-rail-sections shell, see that class's own "REMOVED
   2026-08-08" comment above) is hidden outright for REAP rather than kept
   as a spacer - Anric's own "remove the third column" is explicit that the
   column itself should go, not just its visible content. The workbook's
   own real in-panel progress bar (.rw-progress) stays suppressed at this
   width by course-workbook.css's unchanged "Desktop rail takeover" rule
   (that rule targets 901px+ generally, this page included) - see the next
   rule below, which un-suppresses it again for REAP specifically, since
   with the mirror gone there is no on-screen progress indicator left
   without it.

   TWO COLUMNS, LABS WIDER: grid-template-columns drops from three tracks
   to two - 01 LABS gets an explicit, wider fixed track (was 240px/260px at
   1400px+, same as every other course; now 320px/340px, "a little wider",
   not the whole freed 260-280px + gap so the video track still visibly
   gains room too) and 02 VIDEO keeps the flexible minmax(0, 1fr) track,
   which is now the LAST column - "video on the right-hand side" falls out
   automatically once there is no third column after it, no grid-column
   reassignment needed for either .ru-rail-protocols or .ru-panel-video
   (both keep the same column/row placement the base 901px+ rule above
   already gives them: rail-protocols column 1, panel-video column 2).
   .ru-panel-workbook keeps the base rule's own grid-column: 1 / -1 (every
   column, whatever the current count), so "the sections down below have
   the full width of the page" holds automatically too - 1/-1 always
   spans to the last line, two columns or three.

   EQUAL HEIGHT: align-items: stretch (overriding the base .ru-grid's own
   align-items: start, chosen there specifically because the three-column
   layout's columns "hold naturally different amounts of content... should
   not be forced to equal height" - the opposite of what REAP now asks
   for). CSS Grid's own row-stretch is the mechanism the brief calls for:
   robust to content-length differences by construction, since it reads
   each row's own tallest participant at layout time rather than a fixed
   px guess either panel would drift out of sync with the moment a lab's
   own title list or video caption text changes length. Row 2 (the
   workbook) has exactly one item spanning every column, so stretching it
   is a no-op there - the row's height is already that one item's own
   height regardless of align-items. 01 LABS (.mom-panel) has no height of
   its own beyond its content; stretching just grows its bordered box to
   match 02 VIDEO's real height, leaving blank space inside the panel
   below a shorter lab list rather than clipping or scrolling a taller one
   - the same "bordered card, equal height" pattern grid stretch produces
   anywhere it is used, never a fixed px guess that would need
   re-tuning per lab. */
/* RETIRED 2026-08-08. This block gave REAP its own two-track grid (320px/340px
   labs, video second) for the "video on the right, workbook full width below"
   design. That design is superseded: every REAP lab now carries
   .ru-layout-workbook-right, the same modifier Becoming Unstoppable uses, which
   stacks 01 LABS, 02 VIDEO and the previous/next + actions row together in one
   30% left column with 03 WORKBOOK at 70% on the right.

   Why it had to go rather than just sit there: it is scoped by CONTENT,
   :has(.rw[data-course="reap"]), not by a .ru-wrap class, so it fired on every
   REAP page no matter which layout modifier the page asked for. Its specificity
   TIED with .ru-wrap.ru-layout-workbook-right .ru-grid and it appeared later in
   the file, so it silently won and held the split at 340px/1052px (24/76)
   instead of the intended 30/70. Measured: removing it resolves the grid to
   417.594px/974.398px, an exact 3:7.

   The lesson worth keeping: a content-scoped :has() rule cannot be overridden by
   a layout modifier class, because the modifier has no way to be more specific
   than something that matches on the content itself. Scope layout to the layout
   class, never to which course happens to be inside it.

   The .ru-rail-right suppression it also carried is not needed either: the
   modifier's own left column has no right rail to hide. */
