/* desktop.css — the shared foundation for the Roccabox web version.
 * Oct 2026. Plan: memory/PICKUP_oct04_app_desktop_optimisation.md
 *
 * ── EVERY RULE IN THIS FILE IS SCOPED TO [data-rb-desktop] ──────────────────
 * That attribute is set by desktop-boot.js and only when the hostname, the width and the
 * not-native check all pass. Consequence: linking this file into a page changes NOTHING on
 * a phone, NOTHING in the native app, and NOTHING on app.roccabox.com. That is deliberate
 * and it is the property that makes this safe to roll out page by page.
 *
 * ── THE SCROLL CONTRACT (written before any layout rule, on purpose) ────────
 * 54 of 77 measured screens scroll an INNER element, not the document. A shell that assumes
 * the document scrolls breaks most of the app at once. So:
 *   1. The page owns the viewport height. html/body are 100% and do not scroll.
 *   2. Exactly ONE element in any column owns the scroll. Never two, never zero.
 *   3. Every flex/grid ancestor between the viewport and that scroller carries min-height:0
 *      (and min-width:0 across). Without it the pane refuses to shrink and the content is
 *      clipped instead of scrolled — the single most common bug in this kind of layout.
 *   4. Headers, toolbars and composers are layout ROWS inside their pane, not fixed overlays.
 *   5. position:fixed is measured against the VIEWPORT, not against a centred wrapper. Any
 *      fixed descendant of a pane must be re-anchored explicitly or it will escape.
 *
 * Good news found while building: lead-engine.css already gets this right for 15 pages
 * (`.le-scroller{flex:1;min-height:0;overflow-y:auto}`). This file follows that pattern
 * rather than inventing a competing one.
 */

/* ─────────────────────────────────────────────────────────────────────────────
   1. TOKENS. Everything else refers to these, so a later page cannot drift.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] {
  --rb-rail-w: 72px;          /* icon rail, WhatsApp Web runs ~3% of a wide screen */
  --rb-sidebar-w: 220px;      /* expanded nav */
  --rb-chatdock-w: 380px;     /* docked chat, ~30% at 1280 and comfortable at 1920 */
  --rb-read-max: 820px;       /* message + article measure. Capped ON PURPOSE: a one-line
                                 message stretched across 900px is unreadable. WhatsApp
                                 leaves empty wallpaper beside it and so do we. */
  --rb-content-max: 1240px;   /* general page content cap */
  --rb-gutter: 28px;
  --rb-radius: 14px;

  /* Desktop type scale. Denser than the phone for tabular data, because a mouse is precise
     and the eye is further away from a monitor than from a phone. */
  --rb-fs-xs: 12px;
  --rb-fs-sm: 13px;
  --rb-fs-base: 14.5px;
  --rb-fs-lg: 17px;
  --rb-fs-xl: 22px;

  --rb-row-h: 44px;           /* table row: tighter than a 56px phone tap target */
  --rb-focus: 0 0 0 2px rgba(201,150,26,.9), 0 0 0 4px rgba(201,150,26,.28);
}

/* ─────────────────────────────────────────────────────────────────────────────
   2. THE PAGE OWNS THE VIEWPORT. Rule 1 of the scroll contract.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop],
:root[data-rb-desktop] body {
  height: 100%;
  overflow: hidden;           /* the document never scrolls; a pane does */
}

:root[data-rb-desktop] body {
  display: flex;
  flex-direction: column;
  min-height: 0;              /* rule 3 */
}

/* ── 🚨 WHEN NOTHING ELSE SCROLLS, BODY MUST ──────────────────────────
   The rule directly above is an APP-SHELL pattern: the document never scrolls, an inner pane
   does. That is right for the pages that HAVE an inner pane — `.le-scroller`, `.wrap`,
   `.tab-panel`, `.main-scroll`. It is catastrophic for the pages that do not, because on those
   BODY was the scroller and `overflow:hidden` silently deletes it.

   MEASURED 5 Oct, not guessed (`.audit/scroll-probe.log`): agent-profile's content runs to
   3719px inside a 1080px viewport with no way to reach any of it; app-uploads 3205px;
   agent-info-form 2671px; compare 1571px; skill-shop 1447px. On app.roccabox.com every one of
   them scrolls normally. A screenshot cannot see this and the horizontal-overflow check
   cannot either — the page simply ends, and looks deliberate.

   `flex-shrink: 0` matters as much as the overflow. A flex column SQUASHES a tall child to
   fit instead of letting it run on: skill-shop's profile card was painted 42px tall when it
   needed 480, so the avatar and the name were sliced in half.

   Kept as a flex column rather than forced back to `display:block`, because a page may have
   asked for flex in its OWN stylesheet and we must not overrule that. Set by desktop-boot.js,
   which can see whether a scroller actually exists; CSS cannot. */
:root[data-rb-desktop] body.rb-body-scrolls {
  overflow-y: auto !important;
}
:root[data-rb-desktop] body.rb-body-scrolls > * {
  flex-shrink: 0;
}

/* Scrollbars come back. They are a desktop affordance and hiding them on a mouse-driven
   screen removes the only indication of how much more there is. */
:root[data-rb-desktop] * {
  scrollbar-width: thin;
  scrollbar-color: rgba(120,105,80,.42) transparent;
}
:root[data-rb-desktop] *::-webkit-scrollbar { width: 11px; height: 11px; }
:root[data-rb-desktop] *::-webkit-scrollbar-track { background: transparent; }
:root[data-rb-desktop] *::-webkit-scrollbar-thumb {
  background: rgba(120,105,80,.36); border-radius: 99px;
  border: 3px solid transparent; background-clip: content-box;
}
:root[data-rb-desktop] *::-webkit-scrollbar-thumb:hover { background: rgba(120,105,80,.58); background-clip: content-box; }

/* ─────────────────────────────────────────────────────────────────────────────
   3. THE SHELL. Rail, then the work area.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-shell {
  flex: 1;
  min-height: 0;              /* rule 3 */
  display: flex;
  align-items: stretch;
}

:root[data-rb-desktop] .rb-work {
  flex: 1;
  min-width: 0;               /* rule 3, across */
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ─────────────────────────────────────────────────────────────────────────────
   4. THE CONTENT COLUMN. This single rule is what stops 63 of 77 screens being a
      stretched phone. Pages opt in by carrying .rb-page on their scroller.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-page {
  flex: 1;
  min-height: 0;
  overflow-y: auto;           /* rule 2: this is THE scroller for the column */
  overscroll-behavior: contain;
}

:root[data-rb-desktop] .rb-page > .rb-inner,
:root[data-rb-desktop] .rb-page > .le-wrap {
  max-width: var(--rb-content-max);
  margin: 0 auto;
  padding: var(--rb-gutter) var(--rb-gutter) 64px;
  width: 100%;
}

/* ⚠️ The 14 pages that already carry a PHONE-width cap need width ADDED, not removed, and
   several of them set it as an INLINE style attribute which beats any stylesheet. This is
   the one place !important is correct: we are overriding an inline declaration, which is
   the only thing a stylesheet cannot otherwise reach. Scoped to desktop, so the phone keeps
   its cap exactly as it is. */
:root[data-rb-desktop] .rb-page > [style*="max-width"] {
  max-width: var(--rb-content-max) !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   5. READING MEASURE. For prose and messages. Capped on purpose.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-read { max-width: var(--rb-read-max); }

/* ─────────────────────────────────────────────────────────────────────────────
   6. COLLECTIONS. A list you work through becomes a real table.
      30 of 92 pages share this shape, so this block is the highest-leverage code here.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-collection {
  display: grid;
  grid-template-columns: var(--rb-collection-cols, 1fr);
  align-items: stretch;
  gap: 0;
  border: 1px solid var(--border, #e2dacb);
  border-radius: var(--rb-radius);
  overflow: hidden;
  background: var(--card, #fff);
}

/* The header stays put while the body scrolls. Sticky inside the scroll pane, which is why
   the pane has to be the scroller and not the document (contract rule 2). */
:root[data-rb-desktop] .rb-collection .rb-col-head {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--panel2, #f3eee4);
  font-size: var(--rb-fs-xs);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3, #6b6253);
  padding: 10px 14px;
  border-bottom: 1px solid var(--border, #e2dacb);
}

:root[data-rb-desktop] .rb-row {
  display: grid;
  grid-template-columns: inherit;
  align-items: center;
  min-height: var(--rb-row-h);
  padding: 7px 14px;
  border-bottom: 1px solid var(--border, #e2dacb);
  cursor: pointer;
  transition: background .09s;
}
:root[data-rb-desktop] .rb-row:last-child { border-bottom: 0; }
:root[data-rb-desktop] .rb-row:hover { background: rgba(201,150,26,.06); }
:root[data-rb-desktop] .rb-row[aria-selected="true"] {
  background: rgba(201,150,26,.13);
  box-shadow: inset 3px 0 0 var(--gold-deep, #8a6d1e);
}

/* ⛔ REVERSED 4 Oct 2026. This block used to hide row actions until hover, justified as
   "density". Codex reviewed the rendered page and called it correctly: an action you cannot
   SEE does not exist. At a glance the rows looked read-only, and anyone who does not think to
   hover never discovers they can act. Hiding a primary action is not density, it is a
   usability regression.
   Primary row actions are ALWAYS visible. Hover is for emphasis, never for revelation. */
:root[data-rb-desktop] .rb-row .rb-row-actions { opacity: 1; }
:root[data-rb-desktop] .rb-row:hover .rb-row-actions { filter: brightness(1.04); }

/* ─────────────────────────────────────────────────────────────────────────────
   7. MASTER + DETAIL. The list never disappears. This is the single biggest
      improvement available on a big screen: it removes a whole navigation step
      from work people repeat all day.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-split {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, var(--rb-split-list, 1fr)) minmax(0, var(--rb-split-detail, 1.3fr));
  gap: var(--rb-gutter);
  align-items: stretch;
}
/* minmax(0,…) above, not 1fr, because a 1fr grid track refuses to shrink below its content
   and the pane overflows instead of scrolling. Same family of bug as min-height:0. */

:root[data-rb-desktop] .rb-split > * { min-width: 0; min-height: 0; display: flex; flex-direction: column; }

/* Before anything is selected the detail side explains itself rather than sitting blank. */
:root[data-rb-desktop] .rb-detail-empty {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center; padding: 40px;
  color: var(--ink-3, #6b6253); font-size: var(--rb-fs-base);
}

/* ─────────────────────────────────────────────────────────────────────────────
   8. CARD GRIDS. Phone stacks one per row; a 1920 screen does not need that.
      auto-fit + minmax is what makes this adapt with no breakpoints of its own.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] .rb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--rb-card-min, 280px), 1fr));
  gap: 16px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   9. DESKTOP AFFORDANCES. Keyboard support is part of quality, not polish.
   ───────────────────────────────────────────────────────────────────────────*/
:root[data-rb-desktop] :focus-visible {
  outline: none;
  box-shadow: var(--rb-focus);
  border-radius: 8px;
}

/* A hidden pane must leave the tab order, or keyboard users tab into an invisible chat. */
:root[data-rb-desktop] [hidden],
:root[data-rb-desktop] [inert] { display: none !important; }

:root[data-rb-desktop] button,
:root[data-rb-desktop] a,
:root[data-rb-desktop] [role="button"] { transition: background .1s, color .1s, box-shadow .1s; }

/* Phone layouts size controls for a thumb. A mouse is precise, so desktop can be tighter and
   fit more on screen — which is the entire point of the extra width. */
:root[data-rb-desktop] .rb-dense button,
:root[data-rb-desktop] .rb-dense .btn { min-height: 34px; padding: 7px 13px; font-size: var(--rb-fs-sm); }

/* ─────────────────────────────────────────────────────────────────────────────
   10. PRINT. Fixed panes and inner scrollers both break printing today. Flatten
       everything back to document flow so a page prints as a document.
   ───────────────────────────────────────────────────────────────────────────*/
@media print {
  :root[data-rb-desktop],
  :root[data-rb-desktop] body { height: auto; overflow: visible; display: block; }
  :root[data-rb-desktop] .rb-shell,
  :root[data-rb-desktop] .rb-work,
  :root[data-rb-desktop] .rb-page { display: block; overflow: visible; height: auto; }
  :root[data-rb-desktop] .rb-rail,
  :root[data-rb-desktop] .rb-chatdock,
  :root[data-rb-desktop] .rb-row-actions { display: none !important; }
  :root[data-rb-desktop] .rb-split { display: block; }
}

/* Respect the system setting. Someone who has asked for less motion means it. */
@media (prefers-reduced-motion: reduce) {
  :root[data-rb-desktop] * { animation: none !important; transition: none !important; }
}

/* ═════════════════════════════════════════════════════════════════════════════
   11. NAVIGATION BESIDE THE WORK, not stacked above it.
   Codex, family review: "teach the foundation desktop composition ... reusable
   navigation-plus-content layouts. That carries the useful part of the WhatsApp Web /
   eM Client brief: navigation stays available while the work occupies the main area."
   Measured on lead-today: NINE full-width nav cards ate 660px of vertical space and pushed
   the actual lead table to y≈860, leaving three rows on a 1080px screen. On a phone a
   vertical stack of destinations is correct. On a monitor it is the single most wasteful
   thing the app does, and it repeats across the list family.
   ═══════════════════════════════════════════════════════════════════════════*/

:root[data-rb-desktop] .rb-withnav {
  display: grid;
  grid-template-columns: var(--rb-navcol, 232px) minmax(0, 1fr);
  gap: 26px;
  align-items: start;
}

/* the nav column sticks while the work scrolls — that is the whole point of moving it */
:root[data-rb-desktop] .rb-navcol {
  position: sticky;
  top: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--border, #e2dacb);
  border-radius: 12px;
  background: var(--card, #fff);
  overflow: hidden;
}

/* each destination becomes a compact row, not a full-width card with one line in it */
:root[data-rb-desktop] .rb-navcol > * {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  padding: 7px 11px;
  margin: 0;
  border: 0;
  border-radius: 8px;
  background: none;
  box-shadow: none;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink-2, #4a4134);
  text-align: left;
  cursor: pointer;
  transition: background .09s;
}
:root[data-rb-desktop] .rb-navcol > *:hover { background: rgba(201, 150, 26, .08); }
:root[data-rb-desktop] .rb-navcol > *[aria-current="page"],
:root[data-rb-desktop] .rb-navcol > *.rb-nav-active {
  background: rgba(201, 150, 26, .14);
  color: var(--ink, #1a1611);
  font-weight: 700;
}

/* the one-line description under each destination is phone furniture: on a 232px rail it
   wraps to three lines and buries the destination it is meant to explain. It becomes the
   tooltip instead, so nothing is lost. */
:root[data-rb-desktop] .rb-navcol .rb-nav-sub { display: none; }

/* the icon keeps its box so the labels line up */
:root[data-rb-desktop] .rb-navcol img,
:root[data-rb-desktop] .rb-navcol svg,
:root[data-rb-desktop] .rb-navcol .ico {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  font-size: 15px;
  line-height: 1;
}
/* the chevron pointing right is meaningless once these are a list */
:root[data-rb-desktop] .rb-navcol .rb-nav-chev { display: none; }

/* below 1280 the rail costs more than it returns */
@media (max-width: 1279px) {
  :root[data-rb-desktop] .rb-withnav { grid-template-columns: 1fr; gap: 16px; }
  :root[data-rb-desktop] .rb-navcol {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
  }
  :root[data-rb-desktop] .rb-navcol > * { min-height: 32px; font-size: 12.5px; }
}

/* ═════════════════════════════════════════════════════════════════════════════
   12. THE GENERIC PAGES — everything outside the lead-engine family.
   Those pages share NO stylesheet and use a different wrapper class each. These rules
   pair with desktop-generic.js, which measures the page and tags what it finds rather
   than relying on class names that do not exist.
   ═══════════════════════════════════════════════════════════════════════════*/

/* A phone width cap (measured: 340, 360, 400, 430, 480, 560, 600px across these pages) on a
   LAYOUT container is a phone decision. Lift it and centre the column. The adapter only tags
   containers — never a modal, a card or a toast — so this cannot shrink or stretch a widget
   that was meant to be narrow. */
:root[data-rb-desktop] .rb-lifted {
  max-width: var(--rb-content-max, 1240px) !important;
  margin-left: auto !important;
  margin-right: auto !important;
  width: 100%;
  padding-left: var(--rb-gutter);
  padding-right: var(--rb-gutter);
}

/* the page's own inner scroller keeps owning the scroll — the contract says exactly one */
:root[data-rb-desktop] .rb-scroller {
  overscroll-behavior: contain;
}

/* A stack of identical cards is right for a thumb and wasteful on a monitor. auto-fit means
   the count follows the width with no breakpoints of its own: three across at 1240, two at
   900, one when the cards would be squeezed. */
:root[data-rb-desktop] .rb-cardstack {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--rb-card-min, 330px), 1fr));
  gap: 12px;
  align-items: start;
}
/* the cards stop needing their own vertical rhythm once the grid owns the spacing */
:root[data-rb-desktop] .rb-cardstack > * { margin-top: 0 !important; margin-bottom: 0 !important; }

/* desktop type: the phone scale is sized for arm's length, a monitor is further away and
   shows far more at once, so secondary text can be smaller and must be darker */
:root[data-rb-desktop] .rb-lifted { font-size: var(--rb-fs-base, 14.5px); }

/* `.rb-lifted` must be able to GROW as well as be capped. On pages whose body is a flex
   column the blocks size to their content (640px on a 1920 screen), so they need an explicit
   basis or the cap alone changes nothing. */
:root[data-rb-desktop] .rb-lifted {
  flex: 1 1 auto;
  align-self: stretch;
  box-sizing: border-box;
}

/* Some pages cap <body> ITSELF to a phone width (measured: rental-available 640px,
   rental-inventory 680px, both with `margin: 0 auto`). Nothing that walks body's children can
   see that, and no child can grow past it. Lift the parent, and the column rules below it
   finally apply. */
:root[data-rb-desktop] body.rb-body-lifted {
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 100%;
  /* ⚠️ WITHOUT border-box this is a bug: `width:100%` plus the page's own 20px padding made
     body 1960px wide on a 1920 screen. That was the mysterious +40px horizontal overflow on
     upload-screenshots and privacy — one root cause for both symptoms. */
  box-sizing: border-box;
}

/* Once body's phone cap is lifted, body IS the content column on pages that put their content
   straight into it (no wrapper to centre). Padding rather than max-width, so anything
   measuring the viewport — a sticky bar, a toast — is unaffected. */
:root[data-rb-desktop] body.rb-body-lifted,
:root[data-rb-desktop] body.rb-body-column {
  padding-left: max(var(--rb-gutter), calc((100% - var(--rb-content-max, 1240px)) / 2)) !important;
  padding-right: max(var(--rb-gutter), calc((100% - var(--rb-content-max, 1240px)) / 2)) !important;
}
/* the page's own blocks then take the shared column, centred */
:root[data-rb-desktop] body.rb-body-lifted > .rb-lifted {
  max-width: var(--rb-content-max, 1240px) !important;
  margin-left: auto !important;
  margin-right: auto !important;
  width: 100%;
}

/* Pages that put their content straight into <body> with no container to cap. Body becomes
   the content column itself — padding rather than max-width on body, so nothing that measures
   the viewport (a sticky bar, a toast) is thrown off. */
:root[data-rb-desktop] body.rb-body-column {
  box-sizing: border-box;
  padding-left: max(var(--rb-gutter), calc((100% - var(--rb-content-max, 1240px)) / 2));
  padding-right: max(var(--rb-gutter), calc((100% - var(--rb-content-max, 1240px)) / 2));
}

/* A section heading inside a card grid spans every column, so the headings keep working and
   the cards flow beneath them. Without this, an interleaved heading would sit in a single
   grid cell looking like a broken card. */
:root[data-rb-desktop] .rb-cardstack > .rb-span-all { grid-column: 1 / -1; }

/* ═════════════════════════════════════════════════════════════════════════════
   13. THE DESKTOP SHELL — the floating phone bar becomes a labelled left sidebar.
   Codex, polish review: "Footer/navigation — a stranded phone pattern. Its four unlabelled
   icons lack an obvious current destination; the euro symbol is ambiguous. Move global
   navigation into a persistent left sidebar with labels and an active state."
   VERDICT: FIX - One shared desktop shell with labelled left navigation.

   This is CSS ONLY. `shared-nav.js` is untouched, so the phone and the native app keep the
   floating island exactly as it is. The buttons already carry `aria-label` ("Home", "Chat",
   "Email", "Casino"), so the labels come from `content: attr(aria-label)` — no markup change,
   nothing to keep in sync, and the labels can never drift from the controls.
   ═══════════════════════════════════════════════════════════════════════════*/

:root[data-rb-desktop] { --rb-navw: 216px; }

:root[data-rb-desktop] #rbSharedNav {
  position: fixed;
  left: 0; top: 0; bottom: 0; right: auto;
  width: var(--rb-navw);
  max-width: none;
  height: 100vh;
  margin: 0;
  padding: 16px 12px;
  border-radius: 0;
  border: 0;
  border-right: 1px solid var(--border, #e2dacb);
  box-shadow: none;
  background: var(--card, #fff);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  flex-direction: column;
  justify-content: flex-start;
  align-items: stretch;
  gap: 4px;
  overflow-y: auto;
}

/* each destination becomes a labelled row, not a naked circle */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item) {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 11px;
  width: 100%;
  padding: 8px 10px;
  border-radius: 10px;
  transition: background .09s;
}
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item):hover { background: rgba(201, 150, 26, .09); }
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item):focus-visible { box-shadow: var(--rb-focus); }

/* the icon keeps its colour identity but stops being a giant jewel */
/* ⚠️ MINE, and it was the cause of Dan's "the icons go slightly smaller on different pages".
   MEASURED: home's jewel coins are 22px of glyph in 11px of padding = **44px**, while this rule
   made every other page's coin 17 + 8 + 8 = **33px**. Same sidebar, two sizes, and you see it
   the moment you click off the home page.
   The coins are the brand, so the OTHER pages move to match HOME rather than the other way
   round. 6 destinations x 60px still sits comfortably in a 1080px rail. */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item) > svg {
  width: 22px; height: 22px;
  padding: 11px;
  filter: none;
  box-shadow: none;
  flex: 0 0 auto;
}

/* ⭐ the label, straight from the control's own aria-label — it cannot drift out of sync,
   and an unlabelled icon was Codex's specific complaint ("the euro symbol is ambiguous") */
/* WARNING, AND IT IS LITERAL, NOT TIDINESS: :not(.rb-sub-item) on every rule in this section.
   Dan, 11 Oct, with a photo: "I hope the drop-downs underneath Academy in the sidebar are not
   going to stay like that" - the five items read "Academy Academy", "Arena Arena",
   "Coaching Coaching", "Exam Exam", "Certificates Certifica...", clipped at the rail edge.
   CAUSE: an Academy submenu item is ALSO a <button> inside #rbSharedNav, so it collected the
   whole top-level coin treatment - the row layout, the 44px white jewel, and THIS rule, which
   reprints the control's own aria-label as a ::after. The item therefore rendered its label
   TWICE, side by side, because the inherited layout is a row.
   It never showed on the home page: index's rail is `#bottomNav .nav-tab`, and a sub-item
   carries no .nav-tab class - which is exactly why a home-page screenshot looked perfect and
   why comparing a page only with itself would never have caught it.
   The fix says what these rules always meant - a TOP-LEVEL destination - rather than
   out-specifying them from the submenu side and leaving the trap for the next control. */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)::after {
  content: attr(aria-label);
  font-size: 13.5px;
  font-weight: 650;
  color: var(--ink-2, #4a4134);
  letter-spacing: .005em;
  white-space: nowrap;
}

/* ── the content must never run underneath the navigation ─────────────────── */
/* Codex: "a content area whose scrolling never runs underneath navigation." */
/* ⚠️ AND the column must centre inside the space that is LEFT, not the whole screen.
   Measured by Codex on the first attempt: "roughly 90px between sidebar and content, versus
   430px beyond the content's right edge" — because the right padding was computed against
   100% of the viewport, which still included the 216px the sidebar had taken. One value,
   used on both sides, computed against the remaining width. */
:root[data-rb-desktop] body.rb-island {
  --rb-side: max(var(--rb-gutter), calc((100% - var(--rb-navw) - var(--rb-content-max, 1240px)) / 2));
  padding-left: calc(var(--rb-navw) + var(--rb-side)) !important;
  /* ⚠️ the island padding assumes body spans the window. A page that caps its OWN body has
     that padding eaten OUT of the cap instead of positioning it: token-usage carries
     `body { max-width: 1200px; margin: 0 auto }`, so 448 + 232 of padding left it 520px of
     content where it had 1152 before the nav arrived. MEASURED, and the only page of the 85
     where the cap had not already been lifted by the generic adapter — which is exactly why
     it belongs here, on the island rule itself, rather than being left to whichever adapter
     happens to run. Same treatment `rb-body-lifted` gives, applied wherever the island is.
     No `width` is set, so body stays auto-width and the padding cannot push it past the
     viewport — the +40px overflow trap from `width:100%` plus padding does not apply. */
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  box-sizing: border-box;
}
/* ⚠️ EVERY island page needs the matching right padding, not just the ones carrying a
   layout class. Before the nav went on all 85 pages this only ever applied to the
   `rb-body-lifted` / `rb-body-column` pages, because they were the only island pages there
   were. The 15 lead-engine pages have neither class — they centre their own `.le-wrap` — so
   they got the 448px LEFT padding and no right padding, and the whole board sat off-centre:
   MEASURED on lead-grabs at 1920, a 380px gap to the left of the content and 145px to the
   right. A left pad without its right partner is not a column, it is a shove. */
:root[data-rb-desktop] body.rb-island {
  padding-right: var(--rb-side) !important;
}

/* ── THE CURRENT DESTINATION ──────────────────────────────────────────────
   Codex: "No current destination. Serious for navigation across 85 pages. Use a pale gold
   background across the selected row, a 3px gold left marker and a darker, semibold label.
   Keep it visible after the pointer leaves. Coloured icons alone do not communicate
   selection." Set by desktop-boot.js from the URL. */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)[aria-current="page"] {
  background: rgba(201, 150, 26, .15);
  box-shadow: inset 3px 0 0 var(--gold-deep, #8a6d1e);
}
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)[aria-current="page"]::after {
  color: var(--ink, #1a1611);
  font-weight: 750;
}
/* hover must stay distinguishable from selection */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)[aria-current="page"]:hover {
  background: rgba(201, 150, 26, .2);
}

/* ── the sidebar should read as part of the page, not a separate product ──
   Codex: "The labels look more serif-like than the page typography. Use the same interface
   font, around 14px and medium weight. A warmer off-white surface would connect the sidebar
   better to the page." */
:root[data-rb-desktop] #rbSharedNav {
  background: #fbf8f2;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)::after {
  font-family: inherit;
  font-size: 14px;
  font-weight: 550;
}

/* ── ONE PAGE CONTAINER: the header shares the content's column ────────────
   Codex's #1: "Header alignment remains broken. The narrow, centred header floats above a
   different content column. Across all 85 pages: header and body share one container, width
   and gutters. Remove independent phone-width header caps."
   Body already provides the column, so a header only has to stop capping itself. */
/* ⚠️ The first attempt also forced `width:100%` and `margin:0`, which BROKE the header: on
   my-calls the title was centred by `margin:0 auto`, and removing that stretched it so the
   title was clipped behind the sidebar. Only the phone-width CAP needs lifting — the body
   already provides the column, and the header's own centring still works inside it. Change
   the one thing that is wrong, not everything nearby. */
:root[data-rb-desktop] body.rb-body-lifted > .page-header,
:root[data-rb-desktop] body.rb-body-column > .page-header,
:root[data-rb-desktop] .rb-lifted > .page-header,
:root[data-rb-desktop] .rb-lifted > .page-title,
:root[data-rb-desktop] .rb-lifted > .page-header-text,
:root[data-rb-desktop] .rb-lifted > header,
:root[data-rb-desktop] body > header,
:root[data-rb-desktop] .topbar,
:root[data-rb-desktop] .le-head,
:root[data-rb-desktop] .ac-header {
  max-width: none !important;
}

/* ── A FIXED HEADER IS NOT IN THE COLUMN, SO IT MUST BE PUT THERE ────────
   MEASURED on comms, my-calls and skill-shop:
     .page-header { position: fixed; left: 50%; transform: translateX(-50%); max-width: 430px }
   That bar is centred on the VIEWPORT and out of body flow, so body's padding — which is what
   builds the desktop content column — cannot reach it. Lifting only its max-width stretched it
   to 0-1920 and left its title at x=66, hidden behind the 216px sidebar (drift -410px).
   A fixed header has to be re-anchored: start where the sidebar ends, and indent its contents
   by the SAME gutter the body uses, so header text and page content share one left edge.
   `.rb-fixed-head` is set by desktop-boot.js, which can read the computed position; CSS cannot. */
:root[data-rb-desktop] body.rb-island .rb-fixed-head {
  left: var(--rb-navw) !important;
  right: 0 !important;
  width: auto !important;
  max-width: none !important;
  transform: none !important;
  padding-left: var(--rb-side, 28px) !important;
  padding-right: var(--rb-side, 28px) !important;
  box-sizing: border-box;
}
/* no sidebar on this page, so the bar spans the window and centres on the full width */
:root[data-rb-desktop] body:not(.rb-island) .rb-fixed-head {
  left: 0 !important;
  right: 0 !important;
  width: auto !important;
  max-width: none !important;
  transform: none !important;
  padding-left: max(var(--rb-gutter), calc((100vw - var(--rb-content-max, 1240px)) / 2)) !important;
  padding-right: max(var(--rb-gutter), calc((100vw - var(--rb-content-max, 1240px)) / 2)) !important;
  box-sizing: border-box;
}

/* the island used to reserve space at the BOTTOM for itself. On desktop it is on the left,
   so that reservation is dead space at the foot of every page. */
:root[data-rb-desktop] body.rb-island { padding-bottom: 0 !important; }

/* a narrow desktop window cannot afford 216px of chrome */
@media (max-width: 1151px) {
  :root[data-rb-desktop] { --rb-navw: 62px; }
  :root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item) { justify-content: center; padding: 8px 4px; }
  :root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)::after { display: none; }
}

@media print {
  :root[data-rb-desktop] #rbSharedNav { display: none !important; }
  :root[data-rb-desktop] body.rb-island { padding-left: 0 !important; }
}

/* ── the sidebar scrolls itself if it ever outgrows the window ──────────────
   Four destinations fit easily today. If the nav ever grows, it must not become a second
   place content gets stranded — which is the exact bug we just spent the night removing from
   the pages. desktop-boot.js checks this too: a sidebar that can scroll itself keeps its own
   wheel instead of forwarding it to the page. */
:root[data-rb-desktop] #rbSharedNav {
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ── the sidebar steps aside for a dialog ───────────────────────────
   Set by desktop-boot.js only while something is genuinely covering the screen. The nav is
   z-index 1000 and these pages' own dialogs run from 40 to 999, so without this the sidebar
   punches through the scrim and hides the dialog's left 216px. */
:root[data-rb-desktop] #rbSharedNav.rb-nav-under { z-index: 1 !important; }


/* ── THE TWO EXTRA DESTINATIONS, added by desktop-nav.js ──────────────────
   Dan: "Rock Casino should always be there, Academy should always be there, and the alarm one
   should be there if you've been given permission."
   Each coin needs its own colour or it inherits whatever ran last. Academy takes a violet that
   is not already in use; Office takes the same blue it already wears on the home page, so the
   alarm looks identical wherever you meet it. */
:root[data-rb-desktop] #rbSharedNav .rb-academy { --c1: #9B7BD4; --c2: #6B4FA8; --halo: rgba(107,79,168,.42); }
:root[data-rb-desktop] #rbSharedNav .rb-office  { --c1: #5B8DEF; --c2: #2F5FBF; --halo: rgba(47,95,191,.45); }

/* index's own nav builds its coins from `[data-tab]`, so the added ones need the same hooks */
:root[data-rb-desktop] body.nav-jewel #bottomNav .nav-tab[data-tab="casino"] { --c1: #3BA55D; --c2: #1E7A3C; --halo: rgba(30,122,60,.45); }
:root[data-rb-desktop] body.nav-jewel #bottomNav .nav-tab[data-rb-added="academy"] { --c1: #9B7BD4; --c2: #6B4FA8; --halo: rgba(107,79,168,.42); }
/* ── ACADEMY,
EXPANDED IN PLACE ────────────────────────────────────────────
   Dan: "it's expandable. If you click it,
it drops down and then you get all the options."
   It pushes the rail down rather than floating over it. A floating menu inside a fixed 216px
   rail has nowhere to go and would be clipped by its own parent,
and the rail already scrolls
   if it outgrows the window.

   ⭐ GEOMETRY,
MEASURED OFF THE RAIL ITSELF,
not guessed:
   the coins sit at x 22→66,
so their centre is 44px,
and every top-level LABEL starts at 78px.
   So the hairline is dropped at 44px — it falls out of the middle of the Academy coin — and the
   sub-item labels are brought back to 78px,
dead in line with Home,
Chat,
Email,
Casino and
   Office above them. The small glyph lives in the 56→72 gutter between the two. Nothing in the
   rail is left ragged,
and "Certificates" (the longest word,
~82px at this size) clears the
   126px it has with room to spare. */
:root[data-rb-desktop] .rb-sub {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 3px 0 9px 43px;          /* 43 + 1px border = the 44px coin centre */
  padding: 0;
  border-left: 1px solid rgba(201, 150, 26, .34);
  animation: rbSubIn .17s cubic-bezier(.2, .7, .3, 1) both;
}
:root[data-rb-desktop] #rbSharedNav .rb-sub[hidden],
:root[data-rb-desktop] #bottomNav .rb-sub[hidden],
:root[data-rb-desktop] .rb-sub[hidden] { display: none; }   /* beats display:flex */
@keyframes rbSubIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  :root[data-rb-desktop] .rb-sub { animation: none; }
}
:root[data-rb-desktop] #rbSharedNav .rb-sub-item,
:root[data-rb-desktop] #bottomNav .rb-sub-item,
:root[data-rb-desktop] .rb-sub-item {
  display: flex;
  /* WARNING: flex-direction is named EXPLICITLY. shared-nav.js injects
     `#rbSharedNav button{flex-direction:column;align-items:center}`, so leaving it unsaid does
     not mean "row" - it means "whatever the rail said", and the rail said column. MEASURED:
     glyph centred at x=123 sitting ON TOP of its own label at x=100, in a 147px item. */
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 7px 10px 7px 12px;      /* 43 + 1 + 12 = 56px → the glyph */
  border-radius: 0 9px 9px 0;      /* square against the hairline, round away from it */
  cursor: pointer;
  font-family: 'Plus Jakarta Sans', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .1px;
  color: rgba(60, 48, 28, .82);
  transition: background .12s ease, color .12s ease;
}
/* ⚠️ THE ID SELECTOR TRAP, measured not guessed. shared-nav.js injects its own
   <style> containing `#rbSharedNav svg{width:22px;padding:11px;box-sizing:content-box;
   border-radius:50%;stroke:#fff}` — a DESCENDANT rule, so it also caught these submenu
   glyphs and blew each one up into a 44px WHITE circle on a cream rail: invisible, and it
   shoved every label from x=88 out to x=121 where "Certificates" was cut off.
   MEASURED on my-calls and academy-exam before the fix: label x 121, clipped on all five.
   `#rbSharedNav .rb-sub-ico` is (1 id, 1 class) and beats their (1 id, 1 element), so the
   glyph is reclaimed properly rather than fought with !important. */
:root[data-rb-desktop] #rbSharedNav .rb-sub-ico,
:root[data-rb-desktop] #bottomNav .rb-sub-ico,
:root[data-rb-desktop] .rb-sub-ico {
  width: 16px; height: 16px; flex: 0 0 16px;   /* 56 + 16 + 6 = 78px → the label */
  box-sizing: border-box;
  padding: 0;
  border-radius: 0;
  background: none;
  stroke: currentColor;
  stroke-width: 1.7;
  fill: none;
  opacity: .62;
  transform: none;
  transition: opacity .12s ease;
}
/* ...and the :active scale they put on every svg in the rail must not jolt these either */
:root[data-rb-desktop] #rbSharedNav .rb-sub-item:active .rb-sub-ico { transform: none; }
:root[data-rb-desktop] #rbSharedNav .rb-sub-label,
:root[data-rb-desktop] #bottomNav .rb-sub-label,
:root[data-rb-desktop] .rb-sub-label {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
:root[data-rb-desktop] #rbSharedNav .rb-sub-item:hover,
:root[data-rb-desktop] #bottomNav .rb-sub-item:hover,
:root[data-rb-desktop] .rb-sub-item:hover {
  background: rgba(100, 72, 30, .075);
  color: var(--ink, #1a1611);
}
:root[data-rb-desktop] #rbSharedNav .rb-sub-item:hover .rb-sub-ico,
:root[data-rb-desktop] #bottomNav .rb-sub-item:hover .rb-sub-ico,
:root[data-rb-desktop] .rb-sub-item:hover .rb-sub-ico { opacity: .9; }
:root[data-rb-desktop] #rbSharedNav .rb-sub-item:focus-visible,
:root[data-rb-desktop] #bottomNav .rb-sub-item:focus-visible,
:root[data-rb-desktop] .rb-sub-item:focus-visible { outline: 2px solid var(--gold-deep, #8a6d1e); outline-offset: -2px; }
/* the page you are on,
same gold language as the rest of the app */
:root[data-rb-desktop] .rb-sub-item[aria-current="page"] {
  background: rgba(201, 150, 26, .17);
  box-shadow: inset 2px 0 0 var(--gold-deep, #8a6d1e);   /* lights up its piece of the hairline */
  font-weight: 750;
  color: var(--ink, #1a1611);
}
:root[data-rb-desktop] #rbSharedNav .rb-sub-item[aria-current="page"] .rb-sub-ico,
:root[data-rb-desktop] #bottomNav .rb-sub-item[aria-current="page"] .rb-sub-ico,
:root[data-rb-desktop] .rb-sub-item[aria-current="page"] .rb-sub-ico { opacity: 1; }

/* The chevron tells you it opens, and which way it is pointing: ▾ shut, ▴ open.
   It is a rotated '›' rather than a glyph of its own so it inherits the rail's own weight. */
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)[aria-expanded]::before,
:root[data-rb-desktop] #bottomNav .nav-tab[aria-expanded]::before {
  content: '\203A';
  position: absolute;
  right: 12px;
  font-size: 17px;
  line-height: 1;
  color: rgba(100, 72, 30, .55);
  transition: transform .18s ease, color .12s ease;
  transform: rotate(90deg);
}
:root[data-rb-desktop] #rbSharedNav button:not(.rb-sub-item)[aria-expanded="true"]::before,
:root[data-rb-desktop] #bottomNav .nav-tab[aria-expanded="true"]::before {
  transform: rotate(-90deg);
  color: var(--gold-deep, #8a6d1e);
}


/* ── WHEN THE GATE GOES OFF, THE DESKTOP FURNITURE GOES WITH IT ────────────────
   Codex, 11 Oct: "Desktop additions leak into the phone layout when the gate turns off."
   He is right about the mechanism. Drag a desktop window below 1024px and desktop-boot.js
   drops `data-rb-desktop`, which takes every desktop RULE away in one go - but the BUTTONS
   desktop-nav.js added are real DOM and simply stay, now wearing the phone island's styling,
   inside a 344px pill that was never sized for seven coins and an open submenu.
   Doing this in CSS rather than by tearing nodes out on resize is deliberate: it is exact, it
   is instant, it reverses itself the moment the window grows back, and it cannot half-run.
   It also covers anything added here in future, because it keys off the marker attribute
   rather than a list of names. The phone itself never had the gate on, so it never sees any
   of this either way. */
:root:not([data-rb-desktop]) .rb-sub,
:root:not([data-rb-desktop]) #rbSharedNav button[data-rb-added],
:root:not([data-rb-desktop]) #bottomNav .nav-tab[data-rb-added] { display: none !important; }

/* ── THE SUBMENU IN THE COLLAPSED RAIL (1024-1151px) ──────────────────────────
   Below 1151px the rail drops to 62px and the labels go, so the indented hairline layout
   above has nowhere to live: Codex measured the glyph landing at x=68 in a 62px rail, with
   the words further right again, i.e. off the edge. At this width the items become a column
   of plain glyphs, tucked under the Academy coin and tinted so they still read as "inside"
   something. The name is not lost - desktop-nav.js puts it on `title`, which is how the
   top-level coins keep their names at this width too. */
@media (max-width: 1151px) {
  :root[data-rb-desktop] #rbSharedNav .rb-sub,
  :root[data-rb-desktop] #bottomNav .rb-sub,
  :root[data-rb-desktop] .rb-sub {
    margin: 2px 0 6px 0;
    padding: 4px 0;
    border-left: 0;
    border-radius: 10px;
    align-items: center;
    background: rgba(201, 150, 26, .10);
  }
  :root[data-rb-desktop] #rbSharedNav .rb-sub-item,
  :root[data-rb-desktop] #bottomNav .rb-sub-item,
  :root[data-rb-desktop] .rb-sub-item {
    justify-content: center;
    padding: 7px 4px;
    border-radius: 8px;
    width: 40px;
    margin: 0 auto;
  }
  :root[data-rb-desktop] #rbSharedNav .rb-sub-label,
  :root[data-rb-desktop] #bottomNav .rb-sub-label,
  :root[data-rb-desktop] .rb-sub-label { display: none; }
  :root[data-rb-desktop] #rbSharedNav .rb-sub-item[aria-current="page"],
  :root[data-rb-desktop] #bottomNav .rb-sub-item[aria-current="page"],
  :root[data-rb-desktop] .rb-sub-item[aria-current="page"] { box-shadow: none; }
}
