/* ============================================================
   Resonance — WO221, THE WHOLE PRODUCT IN FOUR PLACES. The shell's stylesheet.
   Matt's ruling, August 16 2026, after four rounds of mockups.

   THE SPECIFICATION IS THE MOCKUP. Every measurement, colour and word below is taken from
   'mockups/WO212 mobile - option A with account panel.html' (the phone, signed off) and
   'mockups/WO221 desktop - four sections.html' (the desktop), read line by line, and
   translated into this product's own palette variables rather than the mockup's hex codes —
   the mockup was drawn in isolation and had no access to assets/style.css, so its #E08A2B is
   this file's var(--orange) and its #B4451C is var(--orange-deep). A hex code copied out of a
   mockup is a second palette, and this product has one.

   NOTHING HERE APPLIES UNLESS assets/shell.js HAS PUT `rs-shell` ON <html>, and it only does
   that when SHELL_V2 is true AND the page is carrying the member strip. So:
     * every marketing page is untouched at every width, for ever;
     * account.html signed OUT is untouched, because its nav is the marketing list until
       nav-state.js swaps it;
     * SHELL_V2 false leaves this file inert — it is downloaded and matches nothing, which is
       the same cost a stylesheet for a feature that is off has always had here.

   dvh AND NEVER vh, AND env(safe-area-inset-bottom) — the order (b), verified against
   'mockups/WO212 mobile - browser vs installed, iOS vs Android.html'. `vh` on iOS Safari is
   the height of the window with the toolbar PRETENDING not to be there, so a bar positioned
   against it sits under the toolbar in the browser and floats above nothing in an installed
   app. `dvh` is the height that is actually there right now, and the safe-area inset is the
   space the browser (or the home indicator) is reserving. Together they are the one code path
   the order asks for: the bar drops into the space Safari's toolbar vacates when a member
   installs the app, and nothing branches on being installed.
   `100vh` is declared first as the fallback for a browser with no dvh, then overwritten.

   THE BREAKPOINT IS 840px, WHICH IS THE PRODUCT'S OWN. style.css collapses the nav there,
   member.css and network.css both hinge there, and WO212's rail/bar swap is there. A shell
   with its own breakpoint would be a second answer to "is this a phone".
   ============================================================ */

/* ============================================================
   (a) THE OLD STRIP AND THE OLD HAMBURGER GO OUT OF SIGHT — AND STAY IN THE DOCUMENT.
   ------------------------------------------------------------
   THIS IS THE LOAD-BEARING TRICK OF THE WHOLE ORDER, so it is written down rather than
   discovered. `<ul class="nav-links">` is not rebuilt, not emptied and not moved: it is the
   seven-item member strip exactly as it shipped, and it stays in the DOM because FOUR OTHER
   FILES FIND THEIR WORK THROUGH IT and none of them had to be edited:

     assets/member-nav.js  paints the five badge doors by href inside `.nav-links` (WO99's
                           reserved holds, WO184b's roll-up, WO215's start pill, the pulse).
     assets/member-nav.js  again — WO52's pre-publish gate shuts the four social doors there.
     assets/nav-state.js   repaints the strip on account.html when get-me settles (WO33 §4),
                           and smoke-auth compares its MEMBER array against network.html's
                           markup item for item.
     assets/site.js        the responsive drawer's toggle.

   So the shell MIRRORS that list rather than replacing it (assets/shell.js, §the mirror), and
   one poll, one gate and one strip go on being the only ones. `display:none` keeps it out of
   the tab order and out of the accessibility tree — a screen reader must not meet the same
   seven links twice — while leaving every element queryable and paintable, which is all any
   of the four readers above needs.

   THE HAMBURGER GOES WITH IT. WO212 put the footer's links into that drawer on the phone;
   this order's Account panel is where they live now, and the order is explicit that leaving
   both would be worse than either. network.js's v2Menu() is gated on the same constant so the
   items are never appended in the first place; this rule is the belt to that brace.
   ============================================================ */
.rs-shell .nav .nav-links,
.rs-shell .nav .nav-toggle { display: none !important; }

/* ============================================================
   (b) THE FOUR SECTIONS. Text tabs across the top on the phone; the top bar on the desktop.
   ------------------------------------------------------------
   ONE ELEMENT, TWO LAYOUTS, and no user-agent test anywhere in this order — the same
   discipline WO212 wrote into network.css for the rail and the bar. A rotation, a resize and a
   desktop browser dragged narrow all land in the right place because the stylesheet decides.
   ============================================================ */
.rsx-tabs { display: flex; align-items: center; gap: 6px; list-style: none;
  margin: 0; padding: 0; }
.rsx-tab { position: relative; display: block; padding: 9px 22px; border-radius: 999px;
  border: none; background: none; font: inherit; font-weight: 800; font-size: 1rem;
  color: var(--ink-soft); cursor: pointer; text-decoration: none;
  transition: background 0.2s, color 0.2s; }
.rsx-tab:hover { background: var(--cream-deep); color: var(--ink); text-decoration: none; }
/* THE CURRENT SECTION IS MARKED THREE WAYS AT ONCE — the class the eye reads, aria-current
   for a screen reader, and `data-rsx-cur` for the gates. WO212's own rule, kept: a "current"
   that exists only in a colour is not marked for everybody. */
.rsx-tab.cur { background: var(--ink); color: var(--orange); }
.rsx-tab.cur:hover { background: var(--ink); color: var(--orange); }
.rsx-tab:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px; }

/* THE SECTION'S ROLL-UP DOT. No number, ever — this is the fourth surface to carry Principle
   4's dot rather than a count, and it is deliberately the same disc WO184b gave the Network
   door and WO212 gave the per-view bar. A section is dotted when ANY door inside it has
   something; which door is the sub-navigation's business one level down. */
.rsx-dot { position: absolute; top: 5px; right: 9px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--orange-deep); }
.rsx-said { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; }

/* WO52's pre-publish gate, mirrored. Same treatment the strip's own shut doors wear — the
   link stays a link, keeps its place in the tab order, and answers Enter the way it answers a
   tap; it simply goes to the publish switch. */
.rsx-tab.rsx-shut, .rsx-subi.rsx-shut { opacity: .5; }

/* ============================================================
   (c) THE SUB-VIEWS: ICONS AND LABELS IN THE FLOATING BAR ON THE PHONE, THE LEFT RAIL ON
       THE DESKTOP.
   ------------------------------------------------------------
   "What is an icon in the phone's bottom bar is an icon plus a label in the left rail here"
   — the desktop mockup's own note. So it is ONE list of items rendered once, and the two
   layouts are two blocks of CSS over the same DOM.

   THE PHONE BAR NEVER SCROLLS AWAY (`position: fixed`) and sits above whatever the browser
   is reserving at the bottom (`env(safe-area-inset-bottom)`), lifted a constant 12px. The
   page makes room for it rather than letting it cover the last card.

   THE GEOMETRY IS WO212's, TO THE PIXEL. network.css's `.n-v2bar` is the bar Matt signed off
   and it is still the bar the Network section uses — this shell draws none of its own there.
   The three other sections' bars are the same 12px inset, the same 22px radius, the same
   blur, the same shadow, so a member moving between sections sees one bar that changed its
   contents rather than two bars that disagree.
   ============================================================ */
.rsx-sub { display: none; }
.rsx-subi { position: relative; display: flex; align-items: center; gap: 13px;
  width: 100%; text-align: left; padding: 12px 15px; margin-bottom: 3px;
  border: none; border-radius: 12px; background: none; font: inherit; font-size: 1rem;
  font-weight: 700; color: var(--ink-soft); cursor: pointer; text-decoration: none; }
.rsx-subi:hover { background: var(--cream-deep); text-decoration: none; }
.rsx-subi.cur { background: var(--white); box-shadow: inset 0 0 0 1px rgba(33,29,22,.12);
  color: var(--ink); }
.rsx-subi:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px; }
.rsx-ic { width: 22px; height: 22px; flex: none; stroke: currentColor; fill: none;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.rsx-subi .rsx-dot { position: static; margin-left: auto; width: 10px; height: 10px; }

/* the rail's two quiet groups — Account only, and only on the desktop. The panel's rules
   become the rail's groups: Profile and Settings on top, a rule, the four quiet links,
   a rule, Log out. */
.rsx-rule { height: 1px; background: rgba(33,29,22,.10); margin: 14px 10px; }
.rsx-quiet { display: block; padding: 9px 15px; border-radius: 11px; font-size: .93rem;
  font-weight: 600; color: var(--ink-soft); text-decoration: none; }
.rsx-quiet:hover { background: var(--cream-deep); text-decoration: none; }

/* ---------- the desktop: a fixed left rail, and the page moved over for it ----------
   THE RAIL IS FIXED RATHER THAN A COLUMN IN EVERY PAGE'S <main>. Eight pages have eight
   different layouts inside <main> and a shell that reached into each of them would be eight
   edits and eight ways to break a page this order was told not to rebuild. A fixed rail under
   the full-width top bar, with `main` and `footer` given the rail's width as padding, is the
   mockup's arrangement (the nav spans the whole screen above the rail) and touches no page's
   own markup at all.
   THE FOOTER STAYS ON THE PAGE EXACTLY AS IT IS TODAY on the desktop — the order says so
   twice — so it is moved over with the content and nothing else about it changes. */
/* ============================================================
   WO238 (2) — ONE LEFT COLUMN. THE RAIL IS ANCHORED TO THE PAGE'S WRAP, NOT TO THE WINDOW.
   ------------------------------------------------------------
   MATT WATCHED THE VERTICAL LINE MOVE AS HE SWITCHED TOP TABS. Measured at 1280 before this
   order: the line at x=323.5 under Network, at x=243.5 under Connect and Reports, and the
   content beginning at 350 under Network against 474 (Games), 394 (Messages), 424 (Fast
   Friends) and 494 (My Reports).

   THE GAMES-WIDTH QUESTION, ANSWERED FIRST BECAUSE THE ORDER SAYS TO. Connect's column is
   NOT narrow because the games need the width, and the measurement says so twice over. The
   two rails were already the SAME 244px with the same 1px border — nothing about the column
   differed. And far from protecting the games, the old arrangement was starving them: this
   rule used to add 264px of PADDING inside each page's own centred max-width box, so the
   games surface drew its content in 576px and My Reports in 536px while Network had 1096.
   Standardising on Network's geometry GIVES the games surface room (576 → about 800 at 1280)
   rather than taking it, so there was nothing to stop for and this item was carried out.

   WHAT CHANGES, AND IT IS TWO PROPERTIES. The rail's `left` becomes the left edge of the
   product's 1120px wrap — which is where WO212's in-flow Network rail has always started —
   and the room the page leaves for it becomes a MARGIN rather than padding eaten out of the
   page's own measure. Every page therefore keeps its own max-width (games 860, messages
   1020, Fast Friends 960, My Reports 820, profile 1040, forum 720) as its reading measure,
   exactly as `.n-v2main`'s 780 is Network's, and every one of them begins at the same x.

   THE FOUR NUMBERS ARE NOT HERE. They are in assets/style.css's :root as --rs-rail-w,
   --rs-rail-gap, --rs-wrap and --rs-rail-lane, and network.css reads the same ones, so the
   geometry has one home and cannot drift between the two stylesheets again.

   THE RAIL'S OWN INSET IS WO212's TOO. Its items used to be pushed 20px in from the left and
   stopped 14px short of the line; the Network rail sits flush left and stops 8px short, which
   is the "right-justified against the separator" Matt named. Same padding here now.

   THE FOOTER DOES NOT MOVE. WO212 and WO221 both wrote that the desktop footer stays exactly
   where it is, so its 264px is left as the literal it was and is deliberately NOT converted
   to the lane — the two selectors that shared this declaration are split for that reason and
   for no other. WO238 changes the footer's COLOUR and nothing about its position.
   ============================================================ */
@media (min-width: 841px) {
  .rs-shell .rsx-sub { display: block; position: fixed; left: var(--rs-rail-x); z-index: 40;
    top: var(--rsx-navh, 84px); bottom: 0; width: var(--rs-rail-w); overflow-y: auto;
    padding: 4px 8px 22px 0; border-right: 1px solid rgba(33,29,22,.10);
    background: var(--cream); }
  .rs-shell main { margin-left: var(--rs-rail-lane); margin-right: var(--rs-rail-x); }
  /* THE FOOTER KEEPS ITS OWN ARRANGEMENT AND ITS OWN CLEARANCE. WO212 and WO221 both wrote
     that the desktop footer stays exactly where it is, and WO238's item 1 changes only its
     colour — but the rail it has to clear is FIXED and now starts 80px further right at
     1280, so a literal 264px would leave the copyright line underneath it. 264 was never a
     free number: it is the rail's 244 plus 20px of clearance, and that is what is written
     here now. Below 1120px --rs-rail-x is 0 and this computes to 264px exactly, so at every
     width where the rail did not move, the footer does not move either. */
  .rs-shell body > footer {
    padding-left: calc(var(--rs-rail-x) + var(--rs-rail-w) + 20px); }
  /* AND THE PAGES WITH NO <main>. account.html predates the member shell and its content
     is a <header class="page-hero"> and a <section> directly under <body>; WO290 and WO292
     brought five more of that shape into the shell (how-meeting-works, safety, feedback,
     privacy, user-guide). The rail would sit over the page it is the rail FOR, so the bands
     are moved the same distance the mains are — less the 24px gutter their inner `.wrap`
     adds of its own, so the first word lands on the lane rather than 24px past it. */
  .rs-shell-nomain body > header, .rs-shell-nomain body > section {
    padding-left: calc(var(--rs-rail-lane) - var(--rs-wrap-gutter)); }
  /* the Network section draws its own rail (WO212, unchanged) — this shell draws none there,
     and the page keeps the width it has today.
     WO238 (2): THE MARGIN IS PUT BACK AS WELL AS THE PADDING. The lane above moves `main`
     over to make room for a FIXED rail; Network's rail is inside its own `main`, so moving
     that main would move the rail with it and the line would land 270px further right than
     every other tab — which is precisely the fault this item exists to end. `auto` on both
     sides is `.n-pagewrap`'s own `margin: 0 auto`, restored, so the wrap centres and the
     rail starts at the wrap's left edge: the geometry the other three now copy. */
  .rs-shell-ownsub main { padding-left: 0; margin-left: auto; margin-right: auto; }
  .rs-shell-ownsub > footer { padding-left: 0; }
}

/* ---------- the phone: the floating bar ---------- */
@media (max-width: 840px) {
  .rs-shell .nav .nav-inner { flex-wrap: wrap; }
  .rsx-tabs { width: 100%; gap: 4px; overflow-x: auto; padding: 4px 0 2px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .rsx-tabs::-webkit-scrollbar { display: none; }
  .rsx-tab { padding: 7px 14px; font-size: .86rem; white-space: nowrap; }
  .rsx-tab .rsx-dot { top: 2px; right: 4px; width: 7px; height: 7px; }

  .rs-shell .rsx-sub { display: flex; justify-content: space-around; gap: 4px;
    position: fixed; left: 12px; right: 12px; z-index: 60;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
    padding: 9px 4px; border-radius: 22px; border: 1px solid rgba(33,29,22,.12);
    background: rgba(255,253,248,.95); backdrop-filter: blur(12px);
    box-shadow: 0 8px 26px rgba(33,29,22,.15); }
  .rsx-subi { flex-direction: column; align-items: center; gap: 3px; width: auto;
    margin: 0; padding: 2px 6px; border-radius: 10px; text-align: center;
    font-size: .68rem; font-weight: 700; }
  .rsx-subi:hover { background: none; }
  .rsx-subi.cur { background: none; box-shadow: none; color: var(--orange-deep); }
  .rsx-subi .rsx-ic { width: 21px; height: 21px; }
  .rsx-subi .rsx-dot { position: absolute; top: -2px; right: 1px; margin: 0;
    width: 9px; height: 9px; }
  /* the rail's two groups are the PANEL's on the phone, so they are not drawn twice */
  .rs-shell .rsx-sub .rsx-rule, .rs-shell .rsx-sub .rsx-quiet { display: none; }

  /* the page makes room for the bar rather than letting it cover the last card */
  .rs-shell main { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 96px); }
  .rs-shell-nomain body { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 96px); }
  /* THE FOOTER'S LINKS ARE IN THE PANEL NOW, so the footer itself is not drawn on the phone.
     `display: none` and not a deletion: it is in the document for a desktop that narrows and
     comes back, and it is the SAME reasoning WO212 wrote for network.html alone — a footer
     under four independent views appears four times or never. What changed is that the links
     have somewhere better to be on every member page, not only on one. */
  .rs-shell body > footer { display: none; }
  /* dvh, never vh — the whole point of (b). */
  .rs-shell main { min-height: 100vh; min-height: 100dvh; }
}

/* ============================================================
   (d) ACCOUNT IS A SLIDING PANEL, NOT A PAGE — the phone.
   ------------------------------------------------------------
   THE MOCKUP'S OWN NUMBERS: 79% of the screen, a .28s slide on cubic-bezier(.22,.7,.28,1),
   the scrim fading over .26s beside it, and it SLIDES BACK on close rather than snapping
   shut. The transform runs in both directions because it is declared on the panel and only
   the class moves — there is no "closing" state to get wrong and no display toggle to fight
   with the transition.

   VISIBILITY IS DELAYED ON THE WAY OUT AND IMMEDIATE ON THE WAY IN (`transition: … visibility
   0s linear .26s` versus `visibility 0s`), which is what lets the panel finish travelling
   before it is taken out of the tree. A `display:none` here would snap.

   UNDER prefers-reduced-motion IT APPEARS WITHOUT TRAVELLING. Not "it does not open" and not
   "it opens instantly and the scrim still fades" — every transition on both elements is off,
   which is the order's word: it still works, it just does not travel.

   IT IS position: fixed AND SIZED IN dvh, so it covers the whole of what is actually on
   screen on a phone in a browser and in an installed app alike.
   ============================================================ */
.rsx-scrim { position: fixed; inset: 0; z-index: 200; background: rgba(20,18,15,0);
  visibility: hidden; transition: background .26s ease, visibility 0s linear .26s; }
.rsx-scrim.on { background: rgba(20,18,15,.36); visibility: visible;
  transition: background .26s ease, visibility 0s; }
.rsx-panel { position: absolute; top: 0; bottom: 0; left: 0; width: 79%; max-width: 420px;
  height: 100vh; height: 100dvh; overflow-y: auto; background: var(--cream);
  padding: 18px 16px calc(env(safe-area-inset-bottom, 0px) + 24px);
  box-shadow: 7px 0 30px rgba(33,29,22,.22);
  transform: translateX(-100%); transition: transform .28s cubic-bezier(.22,.7,.28,1); }
.rsx-scrim.on .rsx-panel { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) {
  .rsx-panel { transition: none; }
  .rsx-scrim, .rsx-scrim.on { transition: none; }
}
.rsx-ph { display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 20px; }
.rsx-phlg { display: flex; align-items: center; gap: 9px; font-family: var(--font-display);
  font-size: 1.3rem; font-weight: 600; }
.rsx-phlg img { width: 32px; height: 32px; border-radius: 50%; }
.rsx-x { background: none; border: none; font-size: 1.7rem; line-height: 1; cursor: pointer;
  color: var(--ink-soft); padding: 0 8px; min-width: 44px; min-height: 44px; }
.rsx-x:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px; border-radius: 10px; }
/* PROFILE and SETTINGS in the large weight, one under the other; a rule; the four quiet
   links; a rule; Log out. The order's list, in the order's order, in the order's weights. */
.rsx-big { display: block; padding: 12px 14px; border-radius: 12px; font-size: 1.12rem;
  font-weight: 800; color: var(--ink); text-decoration: none; margin-bottom: 4px;
  min-height: 44px; }
.rsx-big:hover { background: var(--cream-deep); text-decoration: none; }
/* WO99 #43's 44px floor travels WITH the links, exactly as WO212 made it travel into the
   drawer: a signed rule that is measured in a browser must not be left behind in the footer
   these links have just left. */
.rsx-panel .rsx-quiet { font-size: 1rem; min-height: 44px; display: flex; align-items: center; }
@media (min-width: 841px) { .rsx-scrim { display: none; } }

/* ============================================================
   (e) ADD TO YOUR HOME SCREEN — the Settings entry's own card.
   ------------------------------------------------------------
   THE MEMBER'S OWN PLATFORM LEADS AND THE OTHER IS BENEATH IT RATHER THAN HIDDEN (the order's
   word). So both blocks are in the document and one carries `.rsx-hs-lead`; nothing is behind
   a disclosure, because a member on an Android phone helping somebody with an iPhone should
   not have to find a triangle.
   ABSENT — NOT GREYED — WHEN ALREADY INSTALLED is done in assets/shell.js by not building the
   card at all. There is deliberately no `display:none` rule here for that state: a rule would
   be a card in the document that a member could find, and the order says absent.
   ============================================================ */
.rsx-hs { margin: 0 0 18px; }
.rsx-hs h3 { font-family: var(--font-display); font-size: 1.02rem; font-weight: 600;
  margin: 0 0 6px; }
.rsx-hs ol { margin: 0 0 4px 1.1rem; padding: 0; }
.rsx-hs li { margin-bottom: 6px; line-height: 1.55; }
.rsx-hs-other { margin-top: 18px; padding-top: 16px;
  border-top: 1px solid rgba(33,29,22,.09); }
.rsx-hs-other h3 { color: var(--ink-soft); }

/* ============================================================
   WO290 — THE FOLD, AND THE LINE FOR A DESKTOP.
   ------------------------------------------------------------
   WO290 ASKS FOR THE OTHER PLATFORM COLLAPSED BENEATH, and that supersedes the paragraph
   above it FOR THE ONE CASE WHERE THE PLATFORM IS KNOWN — a member whose phone was detected
   gets their own four taps and nothing else in the way. The earlier reasoning is not
   discarded: an UNKNOWN platform still gets both blocks open, iOS first, folded neither way,
   because that is the case the earlier note was actually about (nobody's phone was detected,
   so hiding one would be hiding the wrong one half the time). assets/shell.js decides which
   of the two shapes is built; both are drawn here.
   THE DISCLOSURE IS A LINE OF TEXT WITH A CHEVRON, not a button that looks like a button.
   It sits inside a card the account page already draws in this weight, and the group it
   opens is the same `.rsx-hs` block the lead one is — one set of type rules, not two.
   44px, because WO99 #43 is a signed rule and a disclosure is a tap target.
   ============================================================ */
.rsx-hs-fold { margin-top: 18px; padding-top: 4px; border-top: 1px solid rgba(33,29,22,.09); }
.rsx-hs-more { display: flex; align-items: center; gap: 8px; width: 100%;
  min-height: 44px; padding: 8px 0; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: .95rem; color: var(--ink-soft); text-align: left; }
.rsx-hs-more::after { content: ''; width: 7px; height: 7px; margin-left: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .15s ease; }
.rsx-hs-more[aria-expanded="true"]::after { transform: rotate(-135deg) translate(-2px, -2px); }
.rsx-hs-more:hover { color: var(--ink); }
.rsx-hs-more:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px;
  border-radius: 8px; }
.rsx-hs-body[hidden] { display: none; }
.rsx-hs-body { padding-top: 6px; }
.rsx-hs-body h3 { color: var(--ink-soft); }
/* the one sentence somebody on a laptop gets. It leads the two blocks, so it is spaced as a
   lead paragraph and not as a footnote. */
.rsx-hs-desktop { margin-bottom: 16px; }

/* ============================================================
   (f) SETTINGS — account.html, re-ordered under the constant.
   ------------------------------------------------------------
   There is no second settings page and no copied card. See assets/shell.js §Settings for the
   whole reasoning; all this stylesheet does is give the page its own title treatment when it
   is being read as Settings rather than as the account door.
   ============================================================ */
.rs-shell-settings .page-hero .kicker { color: var(--orange-deep); }

/* ============================================================
   (g) REQUEST A REPORT — the Reports section's fourth entry (WO221 (a1), route one).
   ------------------------------------------------------------
   THE PICKER IS A <select> AND THERE IS NOWHERE TO TYPE, which is the allow-list projection
   WO170 built for the games picker: the list is the member's greeted matches and connections,
   sent by the server, and a name that is not on it cannot be reached from here by any means.
   The two asks are two checkboxes because they are two consents — nothing here sends both
   under one word, and either may be sent alone.
   ============================================================ */
.rsx-req { background: var(--white); border: 1px solid rgba(33,29,22,.10);
  border-radius: 16px; padding: 20px 22px; max-width: 620px; }
.rsx-req h2 { font-family: var(--font-display); font-size: 1.25rem; margin: 0 0 8px; }
.rsx-req p { color: var(--ink-soft); font-size: .95rem; margin: 0 0 16px; line-height: 1.6; }
.rsx-req select { width: 100%; max-width: 460px; padding: 11px 12px; border-radius: 10px;
  border: 1px solid rgba(33,29,22,.16); font: inherit; background: var(--white); }
.rsx-req label { display: flex; gap: 10px; align-items: flex-start; margin: 14px 0;
  line-height: 1.5; cursor: pointer; }
.rsx-req label input { margin-top: 5px; flex: none; }
.rsx-reqfine { font-size: .86rem; color: var(--ink-soft); margin-top: 14px; }
.rsx-reqmsg { margin-top: 12px; min-height: 1.4em; }

/* ============================================================
   (h) THE THREE-STATE REPORT PILLS AT THE FOOT OF THE DARK CARD (WO221 (a1), route two).
   ------------------------------------------------------------
   They wear the mockup's outline treatment — a pill that is beside the primary Connect
   cluster rather than competing with it — and they are the SAME words WO209 already uses on
   its other surfaces, read out of network-render.js's constants rather than retyped.
   THERE IS NO DISABLED STATE IN THIS FILE. Every one of WO209's absences is structural: the
   pill is not built. A greyed report control has never existed in this product and must not
   start existing in a stylesheet.
   ============================================================ */
.n-repbtn { display: inline-block; background: transparent; border: 1px solid rgba(33,29,22,.22);
  color: var(--ink); padding: 9px 17px; border-radius: 999px; font: inherit;
  font-weight: 700; font-size: .88rem; cursor: pointer; text-decoration: none;
  margin-left: 6px; }
.n-repbtn:hover { border-color: var(--orange-deep); color: var(--orange-deep);
  text-decoration: none; }
.n-repbtn:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px; }

/* ============================================================
   (i) WO265 (Matt, August 16 2026) — THE BLUE, AND THE TAP THAT NEEDED TWO GOES.
   ------------------------------------------------------------
   MATT: "Blue is not a colour that should appear anywhere in the app and there is no reason
   for there to be an outline around the word Games here." He was right about where it came
   from as well: nobody wrote it.

   WHAT IT WAS, MEASURED RATHER THAN GUESSED. Every colour-carrying computed property on every
   element of this shell was read out of a real browser at 390px with touch, and exactly one
   value in the whole chrome was blue:

       -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4)

   which is #33B5E5 — the engine's own default tap highlight, the old Android ice blue. It is
   painted by the browser over whatever a finger touches, for as long as the finger is down,
   and on this bar the thing a finger touches is one icon-and-word block. Tap Games and a
   translucent blue box appears around Games. It appears on nothing else because nothing else
   in that bar is touched. THE PROPERTY IS INHERITED, so the whole of it is undone by naming
   the house's value once, on the root class this shell already puts on <html> — and the value
   named is the one games.css already uses over #page, so the product has ONE tap highlight
   rather than a second opinion about it.

   THE SECOND BLUE WAS A RING NOBODY DECLARED. `.rsx-tab`, `.rsx-subi`, `.rsx-x` and
   `.n-repbtn` above all restate :focus-visible in var(--ring); the Account panel's two link
   families did not, so they fell through to the browser's `outline: auto`, which WebKit draws
   in its own blue. They are given the shell's own ring below — the same three words, so the
   shell has one focus treatment and not five. NOTHING IS REMOVED: every control in this file
   answers a keyboard with a visible ring in the house palette, which is the only thing the
   colour was ever doing.

   RECORDED, NOT DONE HERE: network.css's `.n-v2bar` is the Network section's own bar and its
   items inherit the same default on that one page. The root rule below reaches them, because
   `rs-shell` is on <html> there too and the property is inherited — but if that stylesheet is
   ever given a tap highlight of its own it must be this value. In the to-do for that track.
   ============================================================ */
.rs-shell { -webkit-tap-highlight-color: rgba(181, 72, 0, .12); }
.rsx-big:focus-visible, .rsx-quiet:focus-visible { outline: 3px solid var(--ring);
  outline-offset: 2px; border-radius: 11px; }
/* AND THE LOGO, WHICH IS THE FIFTH THING IN THIS TOP BAR. `.nav-brand` belongs to
   assets/style.css and is shared with every marketing page, so it is not re-declared there by
   this order — it is given the shell's own ring HERE, under `.rs-shell`, which reaches it on a
   member page and touches nothing a visitor ever sees. Without it the one control in this bar
   that this file did not draw is the one control that still answers a keyboard in the
   browser's colour. */
.rs-shell .nav-brand:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px;
  border-radius: 10px; }

/* ------------------------------------------------------------
   AND THE FLASH THAT COMES WITH THE RESCUE HOLDS THE CONTROL STILL.
   assets/shell.js gives every tab and every bar item `data-flash`, which is what puts them
   inside site.js's one control-resolver and therefore inside WO100 Tier 0's dropped-click
   rescue — the whole of the fix for "the first tap does nothing at all". The shared keyframes
   that come with that opt-in scale a pressed control to 97%, and a target that moves under a
   finger mid-tap is the very fault being fixed here. So they are re-aimed for these two, the
   ring kept and the transform dropped — the same device style.css already uses to give dark
   grounds a cream ring, and WO120's own rule for the pulse: it animates box-shadow ONLY, so
   the geometry holds still under the finger and a mid-press tap hits what it aimed at.
   REDUCED MOTION KEEPS ITS STATE (Principle 19), in style.css's own value.
   ------------------------------------------------------------ */
@keyframes rsx-flash-kf {
  0%   { box-shadow: 0 0 0 0 rgba(217,142,31,.55); }
  35%  { box-shadow: 0 0 0 7px rgba(217,142,31,.30); }
  100% { box-shadow: 0 0 0 14px rgba(217,142,31,0); }
}
.rsx-tab.rs-flash, .rsx-subi.rs-flash { animation-name: rsx-flash-kf; }
@media (prefers-reduced-motion: reduce) {
  .rsx-tab.rs-flash, .rsx-subi.rs-flash { animation: none;
    box-shadow: 0 0 0 4px rgba(217,142,31,.45); }
}

/* ============================================================================
   WO291 (August 17 2026) — THE PRE-LOAD SHELL'S HEIGHT LAYER, IN ONE FILE
   ============================================================================
   THE ORDER: "the pre-load shells match the page." Six member pages carry an rs-skel shell
   drawn against a layout that has since moved, and the half of that fault a stylesheet owns is
   HEIGHT — a block that stands where a card will stand, at the height the card occupies, so the
   footer starts where it ends up and does not travel a screen when #page unhides.

   WHERE THE HEIGHTS USED TO LIVE, AND WHAT HAPPENED TO THEM.
     * assets/style.css, eight rules (`.rs-shell`, `.rs-shell-line`, `.rs-shell-sec`,
       `.rs-shell-sec h2`, `.rs-skel`, `.rs-skel i`, and the three sizes `i.tall` 132px,
       `i.row` 74px, `i.line` 20px, plus the sweep keyframes and the reduced-motion rule).
     * assets/network.css, six rules (`.rs-shell .rs-skel-cards` and its two breakpoints,
       `.rs-shell .rs-skel-cards i.tall` 246px, `.rs-shell .rs-skel i` display, and
       `.rs-shell .rs-skel i b`, the label treatment).
   THE THREE SIZES IN style.css ARE SUPERSEDED IN PLACE BY THIS BLOCK. They are not edited and
   not deleted — both of those files are outside this order's fence — so what stands there is
   still the shipped rule and is still what a page gets with this stylesheet absent. Everything
   below either restates a value this layer is deliberately keeping (so that a reader can see
   the whole table at once) or replaces one. `.rs-skel i.line` is the one outright replacement:
   20px was a rule of thumb and the three pages that use it stand it under a real paragraph.
   >>> THE CONSOLIDATION, WHEN SOMEBODY OWNS ALL THREE FILES IN ONE ORDER: delete the three size
   >>> rules from assets/style.css and the two size rules from assets/network.css, and this block
   >>> becomes the only place a shell block's height is written. It is one file's worth of work
   >>> and it is not this order's — style.css and network.css were out of fence tonight.

   WHY IT CASCADES, WHICH WAS CHECKED RATHER THAN ASSUMED.
     ORDER. assets/shell.css is the LAST stylesheet in the <head> of all six member pages
     (network, profile, my-reports, messages, fast-friends, games — verified line by line), so
     for equal specificity this file wins.
     SPECIFICITY. style.css's sizes are `.rs-skel i.tall` = (0,2,1). network.css's are
     `.rs-shell .rs-skel-cards i.tall` = (0,3,1). Everything below is written at (0,3,1) —
     `.rs-shell .rs-skel i.k-card`, `[data-shell-page="games"] .rs-skel i.k-card` — which beats
     style.css outright and ties network.css, and the tie is broken by document order in this
     file's favour. That is the minimum bump that does the job: no `!important`, no id selector,
     and nothing here that a page can only reach through assets/shell.js. `.rs-shell` in these
     selectors matches the shell DIV's own class (`<div id="boot" class="rs-shell">`), so the
     layer holds with SHELL_V2 false and with this script never running.
     THE ONE VALUE THAT HAD TO BE CARRIED FORWARD is network.css's 246px card, because the
     generic `i.tall` restated below would otherwise have won the tie against it and shrunk
     network.html's #boot cards by 114px each. It is restated at the bottom of the base table.

   `data-shell-page` IS THIS ORDER'S ONE NEW HOOK, and it is an attribute on the shell root in
   the six pages' markup rather than a class, so nothing that reads `className` on those
   elements — assets/network.js's #boot / #boot2 swap, every page's `$('boot').hidden` — sees
   anything new. A page with no such attribute gets the base table and nothing else.
   ============================================================================ */

/* ---------- the base table: one block shape per thing a member page draws ----------
   THE NEW SHAPES ARE PREFIXED `k-` AND THE THREE OLD ONES ARE NOT, which is not a tidiness
   preference: it was measured. The obvious names collide with real page classes — `.hero` in
   assets/style.css carries `min-height: 88vh`, and min-height beats height at ANY specificity,
   so a block written `<i class="hero">` drew 792px tall on a 900px desktop instead of 344px.
   `.card`, `.lead` and `.pill` are live classes in this tree too; those three lost the cascade
   rather than the geometry, but a shell block has no business standing in a namespace the pages
   are using. `tall`, `row` and `line` keep their bare names because they are already the shell's
   own vocabulary in assets/style.css and renaming them would be a change to markup this order
   did not need to touch. */
.rs-shell .rs-skel i.tall  { height: 132px; }   /* style.css's, restated, unchanged */
.rs-shell .rs-skel i.row   { height: 74px; }    /* style.css's, restated, unchanged */
.rs-shell .rs-skel i.line  { height: 44px; }    /* REPLACES style.css's 20px: it stands under a
                                                   real paragraph on three of the six pages */
.rs-shell .rs-skel i.k-hero  { height: 344px; }   /* .m-hero: 32px padding + 128px avatar + 20px
                                                   gap + the name block */
.rs-shell .rs-skel i.k-card  { height: 210px; }   /* a house .m-card / .mr-lead / .ff-card */
.rs-shell .rs-skel i.k-lead  { height: 96px; }    /* a page head's lead plus its caveat line */
.rs-shell .rs-skel i.k-pill  { height: 48px; }    /* a full-width .btn and the space under it */
.rs-shell .rs-skel i.k-list  { height: 170px; }   /* .m-listcard */
.rs-shell .rs-skel i.k-grid  { height: 300px; }   /* a .m-gallery run at 140px minimum cells */
.rs-shell .rs-skel i.k-game  { height: 180px; }   /* .mr-empty / .mr-game */
/* network.css's card height, carried forward so the tie above cannot cost it (see the note) */
.rs-shell .rs-skel-cards i.tall { height: 246px; }

/* ---------- the label treatment, for every page and not only the two that load network.css ----
   R1's rule is that a skeleton reading as "nobody is here" is worse than a spinner, so the first
   block of a shell says what is being looked for. The padding and the colour that make that
   legible were written in assets/network.css (WO92 #14), which only network.html and profile.html
   load — so games.html's own label has been drawing as bare bold text in the corner of a block
   since the day it was written. A rule about the shell belongs to the shell's stylesheet.
   THE TWO DECLARATIONS ARE network.css's OWN, character for character, so the two pages that
   load both files see no change at all. */
.rs-shell .rs-skel i { display: flex; align-items: flex-start; justify-content: flex-start; }
.rs-shell .rs-skel i b { font-weight: 500; font-size: .88rem; color: #8A8271;
  padding: 18px 20px; letter-spacing: .01em; }

/* ---------- per page, where the page's own rhythm is not the house one ---------- */

/* NETWORK — the four-view page's notification list. `.n-v2row` is a 42px avatar inside 10px/14px
   padding with a 1px border, and `.n-v2rowwrap` puts 9px under it. */
[data-shell-page="network"] .rs-skel { gap: 9px; }
[data-shell-page="network"] .rs-skel i.row { height: 64px; }

/* PROFILE — the publish card and the four content cards are taller than the house card, the
   lens cards are shorter, and the gallery is a grid. */
[data-shell-page="profile"] .rs-skel i.k-card { height: 230px; }
[data-shell-page="profile"] .rs-skel i.row  { height: 120px; }

/* MY REPORTS — the opening view is one lead, one dark card and one game card. */
[data-shell-page="reports"] .rs-skel i.k-card { height: 210px; }

/* MESSAGES — `.msg-row` is 12px/14px padding round a bold name and a .86rem preview, and
   `.msg-rows` sets the 10px gap. */
[data-shell-page="messages"] .rs-skel { gap: 10px; }
[data-shell-page="messages"] .rs-skel i.row { height: 70px; }

/* FAST FRIENDS — `.ff-row` is 12px/15px padding round a 42px face; `.ff-rows` sets 10px. */
[data-shell-page="ff"] .rs-skel { gap: 10px; }
[data-shell-page="ff"] .rs-skel i.row { height: 68px; }

/* GAMES — `.g-menuitem` is 18px/20px padding round a 1.15rem name, a blurb and a 44px foot;
   `.g-menulist` sets the 14px rhythm. */
[data-shell-page="games"] .rs-skel { gap: 14px; }
[data-shell-page="games"] .rs-skel i.k-card { height: 150px; }

/* ---------- 390px: the same content is taller, because it wraps ----------
   Every heading on these pages is a clamp() and every lead is a paragraph in a narrower column,
   so a block sized off a 1280px measurement under-reserves on a phone — which is the direction
   that puts the footer BACK where WO75 (A) found it. The four blocks that hold prose grow. */
@media (max-width: 680px) {
  .rs-shell .rs-skel i.k-lead { height: 132px; }
  .rs-shell .rs-skel i.line { height: 62px; }
  .rs-shell .rs-skel i.k-card { height: 240px; }
  .rs-shell .rs-skel i.k-grid { height: 420px; }
  [data-shell-page="profile"] .rs-skel i.k-card { height: 264px; }
  [data-shell-page="games"] .rs-skel i.k-card { height: 172px; }
  [data-shell-page="reports"] .rs-skel i.k-card { height: 236px; }
  /* WO304 (August 18 2026) — AND THE THREE THAT WERE MEASURED RATHER THAN REASONED ABOUT.
     These supersede the three lines directly above and they are written HERE, inside WO291's
     own phone block, rather than in a second 680px query of their own: WO221 §2 pins that this
     file carries exactly ONE query that is not the product's 840/841, and a stylesheet with two
     answers to "what is a phone" is the fault this whole order is about, in miniature.
     THEY ARE (0,4,1) AND THE RULES ABOVE ARE (0,3,1) — `.rs-shell` and `data-shell-page` are on
     the same element, the shell root's own div, so naming both raises the weight without a new
     hook. That is what lets WO304's unconditional desktop values sit LATER in this file and
     still lose here, which is the only ordering that can be right: the desktop rule must beat
     WO291's desktop rule, and the phone rule must beat them both.
     Measured at 390x844 against the real renderers on 18 August 2026 — see §WO304 below. */
  .rs-shell[data-shell-page="games"] .rs-skel i.k-card   { height: 204px; } /* .g-menuitem */
  .rs-shell[data-shell-page="profile"] .rs-skel i.k-card { height: 314px; } /* .m-card */
  .rs-shell[data-shell-page="reports"] .rs-skel i.k-card { height: 196px; } /* .mr-card */
}

/* ==================================================================================
   WO292 — THE USER GUIDE'S ANCHORS CLEAR THE STICKY BAR
   ----------------------------------------------------------------------------------
   Every heading on site/user-guide.html carries a stable id so that a mail, a card or a
   later surface can point at the part of the guide it means. style.css sets
   `html { scroll-behavior: smooth }` and `.nav` is `position: sticky; top: 0`, so a jump to
   `#network` lands the heading UNDER the bar and a reader arrives at a paragraph with no
   title over it — and on this page the bar is taller still for a member, because the shell
   puts the four tabs under the brand.

   scroll-margin-top IS THE WHOLE FIX and it is the right one: it moves where the browser
   stops, not where anything is drawn, so nothing shifts for a reader who never follows an
   anchor. The value is the shell's own measured bar height, `--rsx-navh`, which mount()
   republishes on every resize — with style.css's 84px as the fallback for a signed-out
   visitor, where the shell never mounts and the variable is never set.

   SCOPED TO ONE CLASS, `.ug-guide`, which nothing else in this tree wears. This stylesheet
   is loaded by every page that carries the member shell and a bare `h2[id]` rule here would
   reach account.html's settings cards and my-reports.js's section headings.
   ================================================================================== */
.ug-guide h2[id], .ug-guide h3[id] { scroll-margin-top: calc(var(--rsx-navh, 84px) + 18px); }

/* ==================================================================================
   WO304 (August 18 2026) — THE LOADING SCREENS TELL THE TRUTH: THE SHAPE LAYER
   ----------------------------------------------------------------------------------
   MATT, 17 AUGUST, WITH TWO SCREENSHOTS OF THE NETWORK PAGE A SECOND APART: "they should be
   recreated so they actually resemble what loads now — differently for mobile and desktop."
   WO291 made these shells say the right WORDS and said in writing that it could not make them
   the right SHAPE, because the desktop half needed width rules in stylesheets outside its
   fence. This is that half, and it is the last layer in the last stylesheet, so it needs
   nothing outside this file and no page's own sheet is touched.

   EVERY NUMBER BELOW WAS READ OFF THE RUNNING PRODUCT, not estimated. `build tools/
   _wo304-measure.mjs` serves the shipped site, answers the wire with the REAL netlify
   functions over the engine fixture, opens each of the six pages at 390x844 and 1280x900, and
   measures the LOADED page and then the SHELL in the same document at the same width. The
   table it printed is in WO304's to-do doc; the value beside each rule here is that table's
   own cell. The previous shells were built by eye, which is exactly how they came to describe
   a website that no longer exists, so no rule in this block may be changed without re-running
   that tool.

   WHAT THE MEASUREMENT FOUND, AND IT NARROWED THE ORDER RATHER THAN WIDENING IT.
     * THE MISSING RAIL AND THE WRONG COLUMN ARE THE NETWORK PAGE'S ALONE. Five of the six
       pages defer to the shell's own fixed rail (`.rsx-sub`, (c) above), which is mounted by
       assets/shell.js on <body> and is therefore ALREADY on the screen while #boot is — and
       `.rs-shell main { margin-left: var(--rs-rail-lane) }` already moves their shells over
       with their pages. Measured at 1280: rail 244px at x=80 and the column starting at 370 in
       BOTH states, on profile, my-reports, messages, fast-friends and games. Nothing to build.
       Network is the exception because its rail is WO212's own in-flow `.n-v2rail`, drawn by
       the renderer INSIDE #page — so while #boot2 stands there is no rail and no column, and
       the shell spread its rows across the whole 1096px measure at x=80 against the loaded
       page's 780px at x=350. That is the whole of "the page slides sideways", and (1) below is
       the whole of the fix.
     * THE COLUMN IS ALSO WRONG ON TWO PAGES IN A SECOND WAY, and it took the browser to see
       it: at 1280 the messages list is the LEFT PANE of a two-pane grid (`.msg-panes`,
       assets/messages.css: `320px minmax(0, 1fr)`) and a Fast Friends room list stops at 640
       (`.ff-rows`), while both shells drew 802 and 810. (3) below.
     * THE ROWS ARE SHORT EVERYWHERE, by between 2 and 55 pixels depending on the page and the
       width — and on the phone the notification row is nearly twice the height the shell drew,
       because `.n-v2row` wraps below 841. (2) below.

   THE TOKENS ARE WO238's AND THE LITERALS ARE NAMED WITH THEIR HOME. Everything that has a
   token uses it — `--rs-rail-w`, `--rs-rail-gap` — so the shell's rail and the page's rail
   cannot drift apart again, which is the fault WO238 wrote its :root block to end. Four numbers
   have no token: `.n-v2main`'s 780, `.msg-panes`' 320, `.ff-rows`' 640 and `.n-v2raili`'s
   height. Each is written below with the file and the rule it was copied from.
   >>> THE CONSOLIDATION, WHEN SOMEBODY OWNS ALL FOUR FILES IN ONE ORDER: lift 780, 320 and 640
   >>> beside --rs-rail-w in assets/style.css's :root as --rs-net-col, --rs-msg-list and
   >>> --rs-ff-col, and have network.css, messages.css, fast-friends.css and this block read
   >>> them. It is one file's worth of work and it is not this order's — those three sheets were
   >>> out of fence tonight, exactly as style.css and network.css were for WO291.

   THE ROW COUNTS ARE LEFT AS WO291 SET THEM, ON PURPOSE AND WITH THE ARITHMETIC WRITTEN DOWN.
   How many rows a member HAS is the payload's business and is unknowable before it lands; what
   a shell can honestly reserve is a screenful. Measured at 390, the number of rows that fit
   between the top of the list and the fold is 5 on network, 6 on messages, 1 on fast-friends
   and 1 on games — every one of them at or below the count the shell already draws with the
   heights below applied. Reserving more would put the footer further down than the page ends up,
   which is the same lie in the other direction.

   NO NEW TEXT (WO291 settled the words and its drift-guard still reads them out of the real
   renderers), NO NEW COLOUR (the hints in (4) are the placeholder ink at a second stop of the
   same alpha ramp style.css already uses), AND NO NEW ANIMATION — the rail's blocks wear
   `.rs-skel i`, which is WO75's existing sweep and its existing reduced-motion answer, so this
   order writes no keyframe and no transition anywhere.
   ================================================================================== */

/* ---------- (1) NETWORK: THE RAIL'S SPACE, AND THE COLUMN BESIDE IT ----------
   MEASURED, LOADED, AT 1280:  rail 244px at x=80 (= --rs-rail-x), the gap 26 (= --rs-rail-gap),
   `.n-v2main` at x=350 (= --rs-rail-lane) and 780 wide; the h1 at x=350.
   MEASURED, THE OLD SHELL, AT 1280:  no rail, the blocks 1096 wide at x=80, the h2 at x=80.
   AT 390 BOTH ARE 342 WIDE AT x=24 AND THERE IS NO RAIL EITHER SIDE — network.css hides
   `.n-v2rail` and unsets `.n-v2`'s flex below 841, and the lane below does the same, at the
   same breakpoint, which is the product's own (see this file's header).
   THE RAIL IS SPACE AND NOT A MENU: four plain blocks, no words and no icons, because what a
   member feels is the column not moving. `.n-v2raili` is a 22px icon on a 1rem line inside
   12px/15px padding with 3px under it — 52px and a 3px rhythm, and 12px of radius. */
[data-shell-page="network"] .rs-skel-rail { display: none; }
@media (min-width: 841px) {
  [data-shell-page="network"] .rs-skel-lane { display: flex; align-items: flex-start;
    gap: var(--rs-rail-gap); }
  [data-shell-page="network"] .rs-skel-rail { display: grid; gap: 3px; flex: none;
    width: var(--rs-rail-w); margin-top: 30px; padding: 4px 8px 0 0; }
  [data-shell-page="network"] .rs-skel.rs-skel-rail i { height: 52px; border-radius: 12px; }
  /* 780 is `.n-v2main`'s own max-width in assets/network.css — see the consolidation note */
  [data-shell-page="network"] .rs-skel-col { flex: 1; min-width: 0; max-width: 780px; }
}

/* ---------- (2) THE ROWS AND CARDS, AT THE HEIGHT THEY ARE ----------
   Each line carries the number the browser reported for the loaded page and the number this
   supersedes. These restate WO291's per-page table at the same specificity, later in the same
   file, which is the device WO291 itself used against assets/style.css: nothing is deleted and
   what stands above is still what a page gets with this block absent. */
[data-shell-page="network"] .rs-skel i.row   { height: 66px; }   /* .n-v2rowwrap @1280 · was 64 */
[data-shell-page="messages"] .rs-skel i.row  { height: 79px; }   /* .msg-row       · was 70 */
[data-shell-page="ff"] .rs-skel i.row        { height: 78px; }   /* .ff-row        · was 68 */
[data-shell-page="games"] .rs-skel i.k-card  { height: 177px; }  /* .g-menuitem @1280 · was 150 */
[data-shell-page="profile"] .rs-skel i.k-card { height: 238px; } /* .m-card @1280   · was 230 */
[data-shell-page="reports"] .rs-skel i.k-card { height: 188px; } /* .mr-card @1280  · was 210 */
/* AND THE RHYTHM BETWEEN THEM. Two of the six stand their cards 26px apart and not the house
   12 — my-reports (`.mr-*` margins) and profile (`.m-card` sections), measured at both widths.
   PROFILE HAS ONE SECTION THAT DISAGREES WITH ITS OWN PAGE and it is named rather than
   averaged: `.m-lensgrid` (assets/member.css) is a 14px grid, so the lens section's blocks
   carry `rs-skel-tight` in the markup and take that number instead. One gap cannot be two. */
[data-shell-page="reports"] .rs-skel { gap: 26px; }
[data-shell-page="profile"] .rs-skel { gap: 26px; }
[data-shell-page="profile"] .rs-skel-tight { gap: 14px; }

/* THE PHONE IS A DIFFERENT PAGE AND WAS MEASURED SEPARATELY, which is the order's own warning:
   "a shell built from the desktop's shape would be wrong there in a new way, which is how this
   drifted in the first place." Two fences are needed and they are not the same number.
     840 is the PRODUCT'S breakpoint and is where `.n-v2row` starts wrapping its action onto a
     second line (assets/network.css) — so the notification row's 119px begins there, not at 680.
     680 is the fence WO291's own phone block uses for the prose blocks — and THIS ORDER DOES
     NOT OPEN A SECOND ONE. WO221 §2 pins that this stylesheet carries exactly one query that
     is not the product's 840/841, and that it is the shell-height layer's; a second 680 block
     here would be a second answer to "what is a phone" in the one file that is not allowed to
     have one. So WO304's three phone cards are written INSIDE WO291's existing 680 block,
     above, at (0,4,1) — `.rs-shell[data-shell-page="…"]`, both on the shell root's own div —
     which beats the (0,3,1) rules here whatever the document order. Look for them there. */
@media (max-width: 840px) {
  [data-shell-page="network"] .rs-skel i.row { height: 119px; }  /* .n-v2rowwrap @390 · was 64 */
}

/* ---------- (3) THE TWO COLUMNS THAT ARE NARROWER THAN THEIR PAGE ----------
   MEASURED AT 1280: a `.msg-row` is 320 wide and an `.ff-row` is 640, inside mains that are 802
   and 810. Both shells drew the main. At 390 both pages are one column and both already agreed,
   so these are desktop-only and the phone is left exactly as it measured. */
@media (min-width: 841px) {
  /* 320 is `.msg-panes`' first grid track in assets/messages.css */
  [data-shell-page="messages"] .rs-skel { max-width: 320px; }
  /* 640 is `.ff-rows`' and `.ff-card`'s max-width in assets/fast-friends.css */
  [data-shell-page="ff"] .rs-skel { max-width: 640px; }
}

/* ---------- (4) THE HINT, WHICH IS A SHAPE AND NOT A DRAWING ----------
   The order's own limit: "Where a row has an obvious internal shape — a round face at one end,
   a dismiss at the other — the shell may hint at it with plain blocks. Hint, do not draw: a
   shell that looks finished is a shell somebody waits on."
   SO IT IS TWO PAGES AND NOT SIX. A notification row is a 42px face at the left inside 14px of
   padding, 13px of gap, and a 44px dismiss at the far right (`.n-v2row`, `.n-v2av`, `.n-v2x` in
   assets/network.css); a Fast Friends room row is a 34px disc inside 15px (`.ff-row`,
   `.ff-rowav`). A messages row has NO face — assets/messages.js draws `.msg-main` and a pill and
   nothing round — so it gets no disc, because a hint at a shape the page does not have is the
   fault this order exists to fix, in miniature.
   NO MARKUP AND NO NEW COLOUR: they are pseudo-elements on blocks that already exist, in the
   placeholder ink at .10 — one stop along the same rgba(33,29,22, …) ramp style.css's own
   `.rs-skel i` gradient runs from .05 to .09, so the shape reads against the block without a
   second colour entering the file. */
[data-shell-page="network"] .rs-skel i.row::before,
[data-shell-page="ff"] .rs-skel i.row::before {
  content: ''; flex: none; align-self: center; border-radius: 50%;
  background: rgba(33,29,22,.10);
}
[data-shell-page="network"] .rs-skel i.row::before { width: 42px; height: 42px;
  margin: 0 13px 0 14px; }
[data-shell-page="ff"] .rs-skel i.row::before { width: 34px; height: 34px;
  margin: 0 13px 0 15px; }
/* the dismiss, at the far right of a notification row and nowhere else */
[data-shell-page="network"] .rs-skel i.row::after {
  content: ''; flex: none; align-self: center; margin: 0 14px 0 auto;
  width: 20px; height: 20px; border-radius: 6px; background: rgba(33,29,22,.10);
}

/* ==================================================================================
   WO304 — AND THE BLUE RING, WHICH RIDES HERE RATHER THAN WAITING
   ----------------------------------------------------------------------------------
   MATT, 17 AUGUST: "a blue outline sits around the word Games on the games page and stays
   there." It is NOT the tap highlight WO265 measured and fixed in (i) above — that one shows
   only while a finger is down. This one persists, because assets/games.js moves keyboard focus
   to that heading after navigation and gives it `tabindex="-1"` so a screen reader announces
   the new page. That is correct and is not touched here.

   THREE ORDERS HAVE NOW RULED ON THE SAME ELEMENT AND THEY ARE RECONCILED HERE RATHER THAN
   LEFT TO THE CASCADE TO SETTLE.

     WO238 (2), assets/style.css: one focus treatment for the whole product, and
     `[tabindex]:not([tabindex="-1"]):focus-visible` — the programmatic targets are EXCLUDED BY
     NAME, because "a ring around a heading nobody tabbed to is a bug". True, and the cost of it
     is that those elements fall through to the user agent's `outline: auto`, which WebKit and
     Blink paint in the platform accent. On a phone that accent is blue. WO238 removed the
     house ring from the one place the browser was still drawing one of its own.

     WO298, assets/games.css: `.g-pagewrap [tabindex="-1"]:focus, …:focus-visible { outline:
     none }`. It measured the thing Matt was looking at — 358px of a 390px screen, ninety-two
     per cent of the width — and took the ring away entirely inside the games page's own main.
     THAT FILE IS NOT TOUCHED BY THIS ORDER: WO298 owns it this window, and two sessions in one
     file is how a night goes wrong.

     WO304, here: "every programmatically focused heading answers a keyboard with the house
     ring", and Matt's own walk asks to see "a burnt-orange ring… when you tab to it".

   THE RECONCILIATION WAS TRIED THE OTHER WAY FIRST AND THE BROWSER REFUSED IT, which is worth
   writing down because the idea is the obvious one and somebody will have it again. The split
   that looks right is :focus for a member who was MOVED here (no ring — WO298's measurement)
   against :focus-visible for a member who came on a KEYBOARD (the house ring — WO304's ruling).
   IT DOES NOT WORK, AND IT WAS MEASURED RATHER THAN REASONED ABOUT: built that way and driven
   in Chromium at 390 and 1280 by smoke-wo304 §7, the games heading came up `outline-style:
   solid` on a PLAIN ARRIVAL. :focus-visible matches a programmatic focus when the member has
   not yet interacted with the page — the selectors' own rule, and deliberately so, because on
   an untouched page the engine cannot know a keyboard user is not the one arriving. A first
   load is exactly the case Matt was looking at, so the split puts WO298's 358px-of-390 box
   back on the screen in orange. It was withdrawn.

   AND THE FACT UNDERNEATH IT, WHICH ALL THREE ORDERS HAD ALREADY WRITTEN DOWN SEPARATELY: an
   element with tabindex="-1" CANNOT BE REACHED BY TAB — that is the whole meaning of the value.
   WO238 said it ("a ring around a heading nobody tabbed to is a bug"), WO298 said it ("it takes
   nothing away from a keyboard, because tabindex='-1' is not tabbable"), and it means a ring on
   one of these headings can only ever be an ARRIVAL ring. There is no keyboard case to preserve,
   so "nothing is removed" is satisfied by removing it: every element a member can actually reach
   with Tab keeps WO238's ring in assets/style.css, untouched, and smoke-wo304 §7 tabs to one on
   the games page and reads it back to prove it.

   SO WHAT THIS ORDER ADDS IS THE GENERALISATION AND NOT A DIFFERENT ANSWER. WO298 fixed the
   heading Matt saw, inside `.g-pagewrap`, on one page. The same fault is live on every other
   member page — assets/messages.js, assets/my-reports.js, assets/network.js and assets/
   follow-up.js all give a heading tabindex="-1" and focus it — and none of them is inside
   `.g-pagewrap`. One rule under the shell's root class covers all of them at once, which is
   the order's own reason for putting it here rather than in games.css.
   >>> RECORDED FOR MATT, BECAUSE IT IS HIS SENTENCE THAT IS BEING READ NARROWLY: WO304 asks for
   >>> "a burnt-orange ring… when you tab to it". You cannot tab to it. If what he wants is a
   >>> ring on ARRIVAL — the product saying "you have been moved here" in its own colour rather
   >>> than the platform's — that is this rule's `outline: none` becoming the three words
   >>> `3px solid var(--ring)`, one line, and it reverses WO298's measurement rather than
   >>> extending it. It is his call and it is not taken here.

   IT IS SCOPED TO HEADINGS AND TO THE SHELL'S ROOT CLASS, deliberately and narrowly. `.rs-shell`
   is on <html> on every member page (assets/shell.js, SHELL_V2) and on the shell DIV besides, so
   one rule covers all eight pages at once. Naming the four heading levels keeps it off the page
   mounts and dialog surfaces that WO75, WO99 and WO246 also focus programmatically: those have
   their own rulings and this order does not reopen them. At (0,3,1) it out-specifies games.css's
   (0,3,0) on the games page, so the answer there is this block's and does not depend on which
   stylesheet the head happens to list last — and it is the SAME answer, so nothing about that
   page changes and smoke-wo298 reads exactly what it read before.
   ================================================================================== */
.rs-shell h1[tabindex="-1"]:focus, .rs-shell h2[tabindex="-1"]:focus,
.rs-shell h3[tabindex="-1"]:focus, .rs-shell h4[tabindex="-1"]:focus,
.rs-shell h1[tabindex="-1"]:focus-visible, .rs-shell h2[tabindex="-1"]:focus-visible,
.rs-shell h3[tabindex="-1"]:focus-visible, .rs-shell h4[tabindex="-1"]:focus-visible {
  outline: none; }
