/* ============================================================
   OCCAM site — RESPONSIVE COMPOSITION LAYER (converged baseline, 21 Sep 2026)
   Loads after occam-base.css and each page's own <style>. Same tokens, same
   ladders, same named rules; only how the page composes at a width changes.
   HOME BASELINE (owner, 21 Sep): D1 ruled stack + the D3 spine bar (bottom
   section rail w/ prev/next arrows, on every page that has a desktop spine)
   + the D5 habit disclosures. Header = the standard one. Footer = F3.
   ALL PAGES LOCKED 21 Sep PM: pricing = tier switch (VIP default) + reel kept;
   community = captioned capture + quotes rail w/ arrows; login = the card (as web);
   privacy = the document + the bar. No option prefixes remain.
   `100svh` is a canvas hook: unset in production = 100svh.
   ============================================================ */

/* ---- viewport-relative heights, canvas-safe (identical values in production) ---- */
.scene-hero { min-height: 100svh; }
#hero { min-height: calc(100svh - 65px); }
body:has(> .login-main) { min-height: 100svh; }

/* a tap flashes the site's violet, not the browser's default cyan or grey (cyan is the one hue the
   system forbids). One rule for every width: touch reaches desktop too (iPads in landscape are
   1024–1366), and a mouse never draws it */
html { -webkit-tap-highlight-color: var(--accent-soft); }

/* ============================================================
   PHONE FOUNDATIONS — every direction (target 393, floor 360)
   ============================================================ */
@media (max-width: 767px) {
  .wrap { padding-inline: calc(20px + env(safe-area-inset-left, 0px)) calc(20px + env(safe-area-inset-right, 0px)); }
  .occ-brand-word { white-space: nowrap; }
  /* the header's three controls sit 10 apart, the ladder's step and the desktop value (8 was on no rung) */
  [data-site-nav-header] .occ-header-actions { gap: 10px; }
  /* h2/h3 split a word only when it would otherwise run past the line, as the h1 already does;
     break-word never changes how a box is sized, so every heading lays out exactly as before */
  .gs h2, .gs h3 { overflow-wrap: break-word; }
  /* the hero is content-height on a phone unless a direction pins the fold (D2) */
  .scene-hero, #hero { min-height: 0; }
  .scene-hero { padding-block: 0; }
  #hero .gs-hero-in { padding-block: 56px 40px; }
  .gs-lead { margin-top: 18px; }
  .gs-note { margin-top: 12px; }
  /* habits: three ruled rows */
  .razor { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
  .razor-rule + .razor-rule::before { display: none; }
  .razor-rule + .razor-rule { border-top: 1px solid var(--app-border); padding-top: 22px; margin-top: 22px; }
  /* running text keeps the site's 56ch measure (the tablet cap): unchanged at 360–470, where the
     column is narrower, but on big phones and foldables lines ran 100–130 characters */
  .razor-rule > p { max-width: 56ch; }
  .gs-habits { padding-block: 40px; }
  /* product row: single column, DOM order (directions re-area it) */
  .gs-product-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
  .gs-product-row > .gs-product, .gs-product-row > .gs-caption, .gs-product-row > .gs-tally { grid-area: auto; max-width: none; margin-inline: 0; }
  .gs-product { max-width: none; }
  .gs-product-row > .gs-caption { margin-top: 26px; }
  .gs-caption .gs-shot-note { max-width: 56ch; }
  /* at 150% zoom the two tags stop fitting one line: "Live today" drops under the name
     instead of pushing the page sideways (nothing changes at normal zoom) */
  .gs-shot-tags { flex-wrap: wrap; }
  /* the tally as a data row: figure over label, hairline-ruled, left-argued */
  .gs-product-row > .gs-tally { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; margin: 26px 0 0; padding-block: 18px; border-block: 1px solid var(--app-border); text-align: left; justify-content: stretch; }
  .gs-tally > div { padding-inline: 0 12px; }
  .gs-tally > div + div { border-top: 0; padding-top: 0; border-left: 1px solid var(--app-border); padding-left: 12px; }
  .gs-tally dd { font-size: 23px; }
  /* the ask: statement, one primary, one quiet alternative — full width, stacked */
  .gs-ask { flex-direction: column; align-items: stretch; gap: 26px; }
  .gs-ask-say h2 { max-width: none; }
  .gs-ask-say p { max-width: 56ch; }
  .gs-ask-act { justify-items: stretch; width: 100%; gap: 2px; }
  .btn-discord-lg, .gs-ask-act .occ-btn { width: 100%; justify-content: center; }
  .gs-ask-alt { justify-content: center; }
  /* product updates: field and button as two controls, no box around the pair */
  #join .gs-close-card > .gs-form { margin-top: 40px; }
  .gs-form .wl-row { flex-direction: column; gap: 10px; border: 0; border-radius: 0; background: none; box-shadow: none; padding: 0; max-width: none; }
  .gs-form .wl-row:focus-within { outline: none; }
  .gs-form .wl-input { width: 100%; height: 48px; flex: 0 0 auto; padding-inline: 16px; font-size: 16px; border: 1px solid var(--control-border); border-radius: var(--r-field); background: var(--input-surface-bg); box-shadow: var(--control-shadow); }
  .gs-form .wl-input:focus { border-color: var(--field-border-focus); background: var(--input-focus-bg); outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: none; }
  /* a rejected address turns the field's edge full-strength red, focused or not, as login's do */
  .gs-form .wl-input[aria-invalid="true"], .gs-form .wl-input[aria-invalid="true"]:focus { border-color: var(--brand-red); }
  .gs-form .occ-btn { width: 100%; height: 44px; }
  /* the status line is reserved (the Reserved Line Rule): a message lands in it and nothing moves.
     The scene gives the same 32px back, so the page is no taller at rest. :has() keeps the
     give-back on the landing's close; pricing's close is #join too and has no status line. */
  #join .wl-status, #join .wl-status:empty { margin: 12px 0 0; min-height: 20px; line-height: 20px; }
  #join.scene-join:has(.wl-status) { padding-bottom: 24px; }
  /* footer — LOCKED F3 (owner, 21 Sep): centred colophon. Line 1 "© 2026 ⟨glyph⟩" (wordmark
     hidden, the glyph is brand.js's currentColor SVG so it follows the theme); line 2 the three
     links at 44px; line 3 the disclaimer in the strip's own label face, Archivo 11/600, as at
     768+ (owner, 24 Sep: it is a sentence, and sentences aren't mono). Tablet+ keeps the
     one-line strip. */
  .occ-footer .gs-foot-in { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 0; padding-block: 26px calc(26px + env(safe-area-inset-bottom, 0px)); text-align: center; }
  .occ-footer .gs-foot-brand { order: 1; gap: 10px; min-height: 22px; }
  /* line 1 centres on its ink: the brand link keeps its 44px tap box but lends 12px to each side,
     so "© 2026 ⟨glyph⟩" sits on the axis the links and the disclaimer share */
  .occ-footer .gs-foot-brand .occ-brand { justify-content: center; margin-inline: -12px; }
  /* hidden from sight only: with the glyph aria-hidden, the wordmark is this link's only name */
  .occ-footer .gs-foot-brand .occ-brand-word { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .occ-footer .gs-foot-brand .occ-brand-glyph { width: 20px; height: 20px; }
  .occ-footer .gs-foot-in ul { order: 2; gap: 26px; justify-content: center; margin-top: 4px; }
  .occ-footer .gs-foot-in > span:last-child { order: 3; padding-top: 2px; }
  /* drawer: honours the notch, closes at 44 */
  .site-nav-drawer { width: min(82vw, 360px); padding-right: env(safe-area-inset-right, 0px); }
  /* the group label sits on the rows' box edge, one text edge for this depth */
  .site-nav-group-label { margin-inline: 0; }
  /* the current page's row takes the theme's current-row fill (--nav-current-bg, occam-base.css):
     the chip fill it had sat 1.01:1 on the panel, so the current page was marked by ink alone */
  .site-nav-row[aria-current="page"] { background: var(--nav-current-bg); }
  .site-nav-scroll { padding-top: 64px; }
  /* premise pages (community / pricing / privacy) — the statement, not a void; movements at the phone rung */
  .u3 .mvt { padding-block: 64px; }
  #privacy.scene, #terms.scene, #legal.scene { padding-block: 64px; }
  .u3 .mvt#u3-room, #premise.scene { padding-top: 56px; }
  .premise h1, .u3 .premise h1 { max-width: none; }
  .premise .lead, .u3 .premise .lead { max-width: 56ch; }
  .u3 .capture { margin-top: 26px; }
  /* privacy: the inline "write to us" link takes the site's text-link ring, not the browser's */
  .doc a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-mini, 8px); }
  /* login */
  .login-topbar { padding: 12px calc(20px + env(safe-area-inset-right, 0px)) 0 calc(20px + env(safe-area-inset-left, 0px)); }
  .login-main { padding: 18px 0 40px; }
  .login-grid { padding-inline: calc(20px + env(safe-area-inset-left, 0px)) calc(20px + env(safe-area-inset-right, 0px)); gap: 26px; }
  .login-aside { padding-bottom: 0; }
}
/* press is scale .97 (DESIGN.md); the shared rules shrink these to .92–.98. Motion-OK readers
   only, so every reduced-motion rule (login's oauth-btn: transform none) keeps winning */
@media (max-width: 767px) and (prefers-reduced-motion: no-preference) {
  .theme-toggle:active, .occ-btn-discord:active, .occ-btn-accent:active, .btn-discord-lg:active { transform: scale(0.97); }
  .oauth-btn:active { transform: translateY(-1px) scale(0.97); }
  .pw-eye:active { transform: translateY(-50%) scale(0.97); }
}
/* under 320, which a phone reaches only zoomed (150% on a 393 phone is 262): signed in, the glyph's
   44px box, the four 44px circles, their gaps and the 20 gutters came to 302, so the header ran
   20px past the screen. Here only, the header's gutters take the 12 rung, every gap in it closes
   to 8, and the brand lends the 7px of air each side of its 30px glyph to the gutter and the gap,
   keeping its 44px tap box (as the footer's brand does): 12 + 30 + 4 × (8 + 44) + 12 = 262.
   Since 25 Sep the phone header has three circles (the avatar lives in the drawer), so this
   now leaves room to spare; the steps stay so the header doesn't shift under zoom. */
@media (max-width: 319px) {
  [data-site-nav-header] .occ-header-inner { gap: 8px; padding-inline: calc(12px + env(safe-area-inset-left, 0px)) calc(12px + env(safe-area-inset-right, 0px)); }
  [data-site-nav-header] .occ-header-actions { gap: 8px; }
  [data-site-nav-header] .occ-brand { justify-content: center; margin-inline: -7px; }
}

/* rails (community b quotes) — a set of peers as one horizontal snap track, one item per swipe, the next peeking */
[data-rail] { display: flex; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch; margin-inline: calc(-20px - env(safe-area-inset-left, 0px)) calc(-20px - env(safe-area-inset-right, 0px)); padding-inline: calc(20px + env(safe-area-inset-left, 0px)) calc(20px + env(safe-area-inset-right, 0px)); scroll-padding-inline: calc(20px + env(safe-area-inset-left, 0px)); }
[data-rail]::-webkit-scrollbar { display: none; }
[data-rail]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-mini); }
[data-rail] > * { flex: 0 0 var(--rail-slide, 82%); min-width: 0; scroll-snap-align: start; }
.rail-bar { display: grid; grid-template-columns: 44px minmax(0, 1fr) 44px; align-items: center; gap: 12px; padding-top: 18px; }
.rail-arrow { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: var(--r-pill); border: 1px solid var(--app-border); background: transparent; color: var(--text-secondary); transition: border-color var(--transition-base), color var(--transition-base), opacity var(--transition-base); }
.rail-arrow svg { width: 17px; height: 17px; }
.rail-arrow:hover { border-color: var(--app-border-strong); color: var(--text-primary); }
.rail-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rail-arrow[disabled] { opacity: 0.45; pointer-events: none; }
.rail-ticks { display: flex; align-items: center; justify-content: center; gap: 12px; }
.rail-ticks span { width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--text-muted); transition: background-color var(--transition-base), transform var(--transition-base); }
.rail-ticks span.on { background: var(--accent); transform: scale(calc(9 / 7)); }
@media (prefers-reduced-motion: reduce) { [data-rail] { scroll-behavior: auto; } .rail-ticks span, .rail-arrow { transition: none; } }

/* ============================================================
   HOME · RULED STACK (baseline) — the honest single column. Tally leads the
   exhibit as a data row; the capture keeps its phone overhang at scale;
   everything else stacks on hairlines.
   ============================================================ */
@media (max-width: 767px) {
  .gs-product-row { grid-template-areas: "tally" "product" "caption"; }
  .gs-product-row > .gs-tally { grid-area: tally; margin: 0 0 26px; }
  .gs-product-row > .gs-product { grid-area: product; }
  .gs-product-row > .gs-caption { grid-area: caption; }
  /* the exhibit: composition preserved, scaled — the phone hangs off the window's corner */
  .gs-product { position: relative; margin-bottom: 40px; }
  .gs-product .gs-shot-phone { display: block; position: absolute; right: -6px; bottom: -30px; width: 34%; margin: 0; }
}

/* ============================================================
   ONE HOME FOR THE ACCOUNT (owner, 25 Sep). Wherever the menu button is the way in —
   phones, tablets, and touch screens up to 1320 — the account lives only at the drawer's
   foot: avatar · name · email · provider, then Member dashboard and Sign out as 44px rows.
   The header carries no avatar and no Sign in there: the avatar opened the same drawer as
   the menu button on phones, and on tablets a dropdown repeated the drawer's dashboard row.
   With a mouse from 1024, and on any screen from 1321, the header's avatar (or Sign in) is
   the account's one door, opening the panel in account-menu.js; the drawer, where it still
   opens (to 1320), carries pages and sections only. html.js: without JavaScript there is no
   drawer, so the header keeps its controls. No Discord inside the drawer at any width.
   ============================================================ */
.site-nav-account { display: none; padding: 0 0 4px; }
@media (max-width: 1023px), (max-width: 1320px) and (hover: none), (max-width: 1320px) and (pointer: coarse) {
  html.js [data-site-nav-header] .occ-account,
  html.js [data-site-nav-header] .occ-session-actions { display: none !important; }
  body[data-session-state="ready"] .site-nav-account[data-session-signed-in]:not([hidden]) { display: block; }
  .site-nav-cta .site-nav-session[data-session-signed-out] { flex-direction: row; }
  .site-nav-cta .site-nav-session[data-session-signed-out] .occ-btn { flex: 1 1 auto; }
  /* the identity reads as the panel's does (owner, 25 Sep): the name 14/600 at normal tracking,
     then the email and the status line in the caption role, Archivo 12/1.5, secondary ink,
     sentence case (they were muted, and the status mono uppercase). The email wraps, first
     after its "@" (member-session.js puts a <wbr> there), instead of ending in an ellipsis, and
     the avatar holds the top beside the name as the lines grow. Sides of 12 put the avatar's left edge on the rows'
     text: the foot bar's 16 + 12 = 28 from the drawer's edge, as each row's 16 + its own 12 (it
     sat at 16 + 4 = 20). "VIP member" takes --vip from occam-base.css, whose two-attribute rule
     outweighs the one class here. */
  .site-nav-account-identity { display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px 12px; }
  .site-nav-account-identity .occ-account-avatar { width: 40px; height: 40px; flex: 0 0 auto; font-size: 12px; }
  /* one shrinking track, so a long email wraps inside the column instead of spilling past it on
     a 320 phone; the lines stack as the panel's do: name and email together, the status 10 under */
  .site-nav-account-copy { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; min-width: 0; }
  .site-nav-account-name { font-size: 14px; font-weight: 600; line-height: 1.5; color: var(--text-primary); overflow-wrap: anywhere; }
  .site-nav-account-email, .site-nav-account-provider { font: 400 12px/1.5 var(--font-sans); color: var(--text-secondary); }
  .site-nav-account-email { overflow-wrap: break-word; }
  .site-nav-account-provider { margin-top: 10px; }
  .site-nav-account .site-nav-row { width: 100%; text-align: left; }
  /* Member dashboard is a row like Sign out and the pages above it (owner, 25 Sep): left-aligned
     on their text edge, no ring and no fill at rest, where it was the foot bar's centred, ringed
     control. Scoped to the account group, so the foot bar's own dashboard is untouched. The resting
     `background: none` ties .site-nav-row's hover and focus fill at two classes and loads
     later, so that fill is restated, and the current page's fill after it, which holds on hover as it
     does on every other row. */
  .site-nav-account .site-nav-dashboard { justify-content: flex-start; border: 0; background: none; }
  .site-nav-account .site-nav-dashboard:hover, .site-nav-account .site-nav-dashboard:focus-visible { background-color: var(--control-surface-hover-bg); }
  .site-nav-account .site-nav-dashboard[aria-current="page"] { background: var(--nav-current-bg); }
  .site-nav-account .site-nav-signout { color: var(--text-secondary); }
  .site-nav-account .site-nav-signout:hover, .site-nav-account .site-nav-signout:focus-visible { color: var(--brand-red, var(--text-primary)); }
  /* the sign-out failure line (occam-base.css) under Sign out, on the rows' 12px text inset */
  .site-nav-account .occ-account-status { padding: 0 12px; }
  /* the foot bar's own dashboard row gives way to the account group, which carries it */
  body[data-session-state="ready"] .site-nav-cta .site-nav-session[data-session-signed-in] { display: none !important; }
}
/* a mouse at 1024–1320: the drawer still opens for pages and sections, and the header's avatar
   or Sign in already holds the account, so the foot bar has nothing to add */
@media (min-width: 1024px) and (max-width: 1320px) and (hover: hover) and (pointer: fine) {
  .site-nav-cta { display: none; }
}

/* ============================================================
   SPINE BAR (baseline) — the desktop section spine returns on phones as a
   bottom bar: glass because it floats; prev/next arrows at the ends jump one
   section (the old OCCAM "get there immediately" move) and read as the way to
   reach stops that don't fit; between them one chip per scene, the accent fill
   travelling along the bar's top hairline exactly as it travels down the
   desktop rail. The drawer keeps Pages + session (sections live on the bar);
   the header's reading-progress hairline moves to the bar. Pages without a
   desktop spine (login) get no bar.
   ============================================================ */
.spine-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60; display: none; padding: 0 calc(6px + env(safe-area-inset-right, 0px)) env(safe-area-inset-bottom, 0px) calc(6px + env(safe-area-inset-left, 0px)); background-color: var(--shell-bg); background-image: var(--rim-light); backdrop-filter: blur(var(--blur-shell)); -webkit-backdrop-filter: blur(var(--blur-shell)); border-top: 1px solid var(--app-border); transition: transform var(--transition-base); }
.spine-bar::after { content: ""; position: absolute; left: 0; top: -1px; width: 100%; height: 1px; background: var(--accent); transform-origin: 0 50%; transform: scaleX(var(--rail-p, 0)); transition: transform var(--transition-base); }
.spine-bar-row { display: flex; align-items: stretch; height: 56px; }
.spine-bar-chips { display: flex; flex: 1 1 auto; min-width: 0; align-items: stretch; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; scroll-behavior: smooth; }
.spine-bar-chips::-webkit-scrollbar { display: none; }
.spine-bar-chip { flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-width: max-content; min-height: 44px; padding: 0 8px; border-radius: var(--r-pill); font-family: var(--font-sans); font-size: 11px; font-weight: 600; letter-spacing: var(--tracking-label, 0.1em); text-transform: uppercase; color: var(--text-secondary); white-space: nowrap; scroll-snap-align: center; transition: color var(--transition-base); }
.spine-bar-chip::before { content: ""; width: 7px; height: 7px; flex: 0 0 auto; border-radius: var(--r-pill); background: var(--text-muted); transition: background-color var(--transition-base), transform var(--transition-base); }
.spine-bar-chip.is-current { color: var(--text-primary); }
.spine-bar-chip.is-current::before { background: var(--accent); transform: scale(calc(9 / 7)); }
.spine-bar-arrow { flex: 0 0 44px; display: inline-flex; align-items: center; justify-content: center; min-height: 44px; border-radius: var(--r-pill); color: var(--text-secondary); transition: color var(--transition-base), opacity var(--transition-base); }
.spine-bar-arrow svg { width: 16px; height: 16px; }
.spine-bar-arrow[disabled] { opacity: 0.45; pointer-events: none; }
.spine-bar-arrow:hover, .spine-bar-chip:hover { color: var(--text-primary); }
.spine-bar-chip:focus-visible, .spine-bar-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.spine-bar--dense .spine-bar-chip::before { display: none; }
.spine-bar--dense .spine-bar-chip { letter-spacing: 0.06em; }
.site-nav-layer.is-open ~ .spine-bar { transform: translateY(100%); transition: transform var(--transition-fast); } /* exits take the fast step */
@media (max-width: 767px) {
  .spine-bar { display: block; }
  body.has-spine-bar { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  /* the bar already stands on the home-indicator inset, so the footer above it doesn't count it again */
  body.has-spine-bar .occ-footer .gs-foot-in { padding-bottom: 26px; }
  body.has-spine-bar .gs-progress { display: none; }
  body.has-spine-bar .site-nav-scenes { display: none; }
  /* keyboard focus never lands under the bar: its 57px plus 7px of air (the capsule reserves its own in site-rail.css) */
  html:has(> body.has-spine-bar) { scroll-padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) { .spine-bar, .spine-bar::after, .spine-bar-chip, .spine-bar-chip::before, .spine-bar-arrow { transition: none; } .spine-bar-chips { scroll-behavior: auto; } }

/* ============================================================
   DISCLOSURE ROWS (baseline, owner 21 Sep) — every ruled list of heading + body on a
   phone folds the same way the home habits do: the heading is a 56px row with a
   chevron, the first row open, the rest closed; the body (and its mono tag) hides.
   Applies to the home habits (.razor-rule), the community rooms and the pricing
   answers (.manifest > li). Less scroll fatigue, nothing removed.
   ============================================================ */
@media (max-width: 767px) {
  .gs-habits { padding-block: 12px; }
  .razor-rule + .razor-rule { padding-top: 0; margin-top: 0; }
  .razor-rule h2, .manifest > li > h2 { margin: 0; }
  .razor-toggle { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 0; font: inherit; letter-spacing: inherit; color: inherit; text-align: left; border-radius: var(--r-mini); }
  .razor-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .razor-toggle svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--text-muted); transition: transform var(--transition-base); }
  .razor-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
  .razor-rule > p { margin: -6px 0 18px; }
  .razor-rule > p[hidden], .manifest > li > p[hidden], .manifest > li > span[hidden] { display: none !important; }
  /* manifests: the row is the heading; the body and tag drop under it when open */
  .manifest.is-disclosure > li { display: block; padding-block: 0; }
  .manifest.is-disclosure > li > p { margin: -6px 0 18px; }
  .manifest.is-disclosure > li > span:not([hidden]) { display: block; margin: -4px 0 18px; }
}
/* O2 (23 Sep) — phones rotate across 767 (iPhone landscape = 852), so rows built on a phone can
   meet the tablet composition without a reload. The chevron is sized and the heading label reset
   at EVERY width (an unsized inline SVG renders 300×150; `.u3 .rooms span` would restyle the
   label as a tag); at 768+ the toggle reads as the plain heading and every body shows. */
.razor-toggle svg { width: 16px; height: 16px; flex: 0 0 auto; }
.manifest .razor-toggle > .razor-toggle-label, .u3 .rooms .razor-toggle > .razor-toggle-label, .razor-rule .razor-toggle > .razor-toggle-label { font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; margin: 0; display: inline; grid-column: auto; grid-row: auto; align-self: center; white-space: normal; text-wrap: pretty; }
@media (min-width: 768px) {
  .razor-toggle { cursor: default; pointer-events: none; }
  .razor-toggle svg { display: none; }
  .razor-rule > p[hidden], .manifest > li > p[hidden] { display: block !important; }
  .manifest > li > span[hidden] { display: inline !important; }
  /* a quotes rail built on a phone: the page's own grid wins at 768+; drop the snap + the bar */
  [data-rail] { scroll-snap-type: none; }
  .rail-bar { display: none; }
}

/* ============================================================
   PAGE PAIRS (393)
   ============================================================ */
/* pricing (baseline, owner 21 Sep) — the toolkit reel stays a reel: one slide at a
   time, the web's arrows + counter under it, swipe or tap. Tiers: OPEN pair below. */
@media (max-width: 767px) {
  .tier-note, .tier-bridge { text-align: left; padding-top: 26px; }
  .reel-slide { gap: 18px; }
  .reel-bar { margin-top: 26px; }
  .answers { margin-top: 48px; }
  /* "What VIP unlocks." reads from the left edge like every other head on the phone page
     (owner, 24 Sep); centred, its paragraph was the page's one ragged left edge */
  #toolkit .gs-sec { text-align: left; margin-inline: 0; }
  #toolkit .gs-sec > p { margin-inline: 0; }
}
/* pricing tiers (LOCKED b) — a segmented switch, Community · VIP, shows one tier at a time,
   VIP selected by default (the page's job is the paid tier); switching rides tab-slide X.
   Control geometry = the site's pill vocabulary (--r-pill · --control-surface-bg ·
   --control-shadow · --chip-surface-hover-bg). The selected pill carries the control ring
   (Impeccable phone pass): its fill alone sat 1.03–1.09:1 off the track, so the plan on
   screen read by hue only; the ring is 3.3–3.4:1 in both themes. */
.tier-switch { display: none; padding: 4px; border: 1px solid var(--app-border); border-radius: var(--r-pill); background: var(--control-surface-bg); box-shadow: var(--control-shadow); margin-bottom: 8px; }
.tier-switch button { flex: 1 1 0; min-height: 40px; border-radius: var(--r-pill); font-family: var(--font-sans); font-size: 13px; font-weight: 600; letter-spacing: 0.01em; color: var(--text-secondary); text-align: center; transition: color var(--transition-base), background-color var(--transition-base); }
.tier-switch button[aria-selected="true"] { color: var(--text-primary); background: var(--chip-surface-hover-bg); box-shadow: inset 0 0 0 1px var(--control-border), var(--control-shadow); }
.tier-switch button[data-tier="vip"][aria-selected="true"] { color: var(--vip); }
.tier-switch button:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
@keyframes tier-in { from { opacity: 0; transform: translateX(var(--tab-dx, 16px)); } }
@media (max-width: 767px) {
  .tier-switch { display: flex; }
  /* a 44px touch target without a taller switch: the hit area reaches 2px into the track's padding */
  .tier-switch button { position: relative; }
  .tier-switch button::after { content: ""; position: absolute; inset: -2px 0; }
  .c-pricing .tier[hidden] { display: none; }
  .c-pricing .tier { border-top: 0; padding-top: 18px; }
  .c-pricing .tier.tab-in { animation: tier-in var(--transition-base) both; }
}
@media (prefers-reduced-motion: reduce) { .c-pricing .tier.tab-in { animation: none; } }
/* community (LOCKED b) — the captioned capture: no frame, the note and Play under the video;
   quotes on a swipe rail with arrows + centred ticks under it; the proof chip centred as on web */
@media (max-width: 767px) {
  .u3 .capture { display: flex; flex-direction: column; border: 0; border-radius: 0; background: none; overflow: visible; }
  .u3 .capture-vid { border: 1px solid var(--app-border); border-radius: var(--r-field); }
  .u3 .capture-head { order: 2; border: 0; padding-inline: 0; margin-top: 8px; min-height: 44px; }
  .u3 .capture-toggle { min-height: 44px; padding-inline: 12px 0; }
  .u3 .capture-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .u3 .quotes { --rail-slide: 84%; display: flex; }
  .u3 .quotes > figure { padding-right: 20px; }
  .u3 .quotes > figure + figure { border-top: 0; padding-top: 0; margin-top: 0; border-left: 1px solid var(--app-border); padding-left: 20px; }
  .u3 .quotes blockquote { max-width: 56ch; }
  .u3 .quotes-more { margin-top: 40px; justify-content: center; }
  /* at 150% zoom the rating chip breaks onto two lines instead of pushing the page sideways */
  .gs-footer-proof { white-space: normal; }
  /* the room dividers take the site hairline, not the page's scaffolding --rule */
  .u3 .rooms { --manifest-rule: var(--app-border); }
}
/* control rings (phone pass): a control a person has to find takes --control-border, as the
   theme and Discord circles do; these four still wore the divider hairline (1.16–1.24:1) */
@media (max-width: 767px) {
  .site-nav-close, .rail-arrow, .reel-btn, .reel-btn[aria-disabled="true"]:hover { border-color: var(--control-border); }
}
/* hover is a mouse state. A touch phone or tablet keeps :hover on whatever was tapped last, so a
   lift, ring or ink change stayed on until the next tap. Each control shows its resting look
   instead; :active is left alone, so a press still reads, and keyboard focus keeps its own ring.
   Every width with no hover, not just through 1023: an iPad in landscape is 1024–1366 and just as
   sticky. The capsule's chips and arrows are locked and not listed. */
@media (hover: none) {
  .theme-toggle:hover:not(:active) { transform: none; color: var(--text-secondary); border-color: var(--control-border); }
  .occ-btn-discord:hover:not(:active) { transform: none; color: var(--text-secondary); border-color: var(--control-border); background-color: var(--control-surface-bg); }
  .occ-btn-ghost:hover:not(:active) { transform: none; border-color: var(--control-border); background-color: var(--control-surface-bg); }
  .occ-btn-accent:hover:not(:active) { transform: none; }
  .btn-discord-lg:hover:not(:active) { transform: none; box-shadow: var(--control-shadow); }
  .btn-vip:hover:not(:active) { filter: none; }
  .oauth-btn:hover:not(:active) { transform: none; border-color: var(--control-border); background: var(--control-surface-bg); }
  .pw-eye:hover:not(:active) { color: var(--text-muted); background: none; }
  .rail-arrow:hover:not(:active), .reel-btn:hover:not(:active) { border-color: var(--control-border); color: var(--text-secondary); }
  .spine-bar-arrow:hover:not(:active), .spine-bar-chip:not(.is-current):hover:not(:active) { color: var(--text-secondary); }
  .u3 .capture-toggle:hover:not(:active) { color: var(--capture-ink); }
}
/* ============================================================
   TABLET — 768 to 1023 (portrait tablet, small landscape). Composed, not squeezed:
   the fold is pinned again, the three habits hold three ruled columns, the ask
   holds its row, the tally lies down as a row under the exhibit.
   ============================================================ */
@media (min-width: 768px) and (max-width: 1023px) {
  .wrap { padding-inline: calc(32px + env(safe-area-inset-left, 0px)) calc(32px + env(safe-area-inset-right, 0px)); }
  .scene-hero { min-height: 100svh; padding-block: 96px 72px; }
  #hero { min-height: calc(100svh - 65px); padding-block: 0; }
  #hero .gs-hero-in { padding-block: 56px; }
  .razor { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 40px; }
  .razor-rule + .razor-rule { border-top: 0; padding-top: 0; margin-top: 0; }
  .razor-rule + .razor-rule::before { display: block; left: -20px; }
  /* the habits band on the ladder (48 was on no rung; desktop is 56) — it still ends on the fold */
  .gs-habits { padding-block: 56px; }
  .gs-product-row { display: grid; grid-template-columns: minmax(0, 1fr); }
  .gs-product-row > .gs-product, .gs-product-row > .gs-caption, .gs-product-row > .gs-tally { grid-area: auto; max-width: 760px; margin-inline: 0; }
  .gs-product { margin-bottom: 18px; }
  .gs-shot-phone { right: 0; width: 186px; bottom: -30px; }
  .gs-product-row > .gs-caption { margin-top: 26px; }
  /* the tally sits 40 under the caption, the rung nearest desktop's 36 (32 was on no rung) */
  .gs-product-row > .gs-tally { display: grid; grid-template-columns: repeat(3, auto); justify-content: start; gap: 0; margin: 40px 0 0; padding-block: 18px; border-block: 1px solid var(--app-border); text-align: left; }
  .gs-tally > div { padding-inline: 0 40px; }
  .gs-tally > div + div { border-top: 0; padding-top: 0; border-left: 1px solid var(--app-border); padding-left: 40px; }
  .gs-ask { flex-direction: row; align-items: flex-end; gap: 40px; }
  .gs-ask-act { justify-items: center; width: auto; }
  .btn-discord-lg { width: auto; }
  #join .gs-close-card > .gs-form .wl-row { max-width: 560px; }
  /* community: quotes as three ruled rows, rooms with the tag on its own line */
  .u3 .quotes { grid-template-columns: 1fr; column-gap: 0; }
  .u3 .quotes > figure + figure::before { display: none; }
  .u3 .quotes > figure + figure { border-top: 1px solid var(--app-border); padding-top: 26px; margin-top: 26px; }
  .u3 .quotes blockquote { max-width: 56ch; }
  .u3 .offer { flex-direction: row; align-items: center; }
  .u3 .offer .btn-discord-lg { width: auto; }
  /* pricing: two tiers side by side hold from 768 */
  .answers > li { grid-template-columns: minmax(0, 260px) minmax(0, 1fr); }
  .reel-slide { grid-template-columns: 1fr; gap: 26px; }
  /* login: the card keeps the page's own 40px padding, desktop's (the 32 here was on no rung) */

  /* ---- tablet pass (25 Sep): the phone pass's fixes, carried to 768–1023. The ones the owner
     carried on to desktop live in the blocks after this one, by the range they hold for ---- */
  /* h2/h3 split a word only when it would otherwise run past its column (pricing's 260px answer
     column); break-word never changes how a box is sized, so English copy lays out as before */
  .gs h2, .gs h3 { overflow-wrap: break-word; }
  /* a phone turned sideways lands here, and only in landscape are its side insets non-zero:
     the skip link, the drawer and the login page stand clear of the notch */
  .skip-link { left: calc(12px + env(safe-area-inset-left, 0px)); }
  .site-nav-drawer { padding-right: env(safe-area-inset-right, 0px); }
  .site-nav-close { margin-right: env(safe-area-inset-right, 0px); }
  .login-topbar, .login-grid { padding-inline: calc(32px + env(safe-area-inset-left, 0px)) calc(32px + env(safe-area-inset-right, 0px)); }
  /* header: the circles sit 10 apart, the ladder's step (768–860 had 8) */
  [data-site-nav-header] .occ-header-actions { gap: 10px; }
  /* community: Play/Pause's word lines up with the note's 12.7px inset (the button's end padding
     now hangs into the bar's padding instead of pushing the word in, and stays inside the button
     so its ring clears the word) */
  .u3 .capture-toggle { margin-inline-end: -0.5rem; }
  /* each quote's name sits 18 under it, nearer it than the next row's rule (from 1024 the quotes
     stand in three columns with no rule between rows, and keep their own spacing) */
  .u3 .quotes .who { margin-top: 18px; }
  /* pricing: "What VIP unlocks." reads from the left edge, as it does from 861 and on phones;
     the VIP list's long item wraps as a pair, not a lone "reviews" */
  #toolkit .gs-sec { text-align: left; margin-inline: 0; }
  #toolkit .gs-sec > p { margin-inline: 0; }
  .tier li { text-wrap: pretty; }
  /* a phone turned sideways: the disclosure headings it built keep the heading's tracking (the
     button's default letter-spacing reset it to normal) */
  .razor-toggle { letter-spacing: inherit; }
  /* login: the recovery links inside alerts ("Resend verification email") get a 44px tap area,
     as on phones; nothing moves */
  .alert .link-btn { position: relative; }
  .alert .link-btn::after { content: ""; position: absolute; inset: -13px -8px; }
}
/* ============================================================
   768 AND UP — the tablet pass's fixes the owner carried to desktop (25 Sep). None of them
   leans on the tablet composition, so each holds at every width from 768.
   ============================================================ */
@media (min-width: 768px) {
  /* control rings: a control a person has to find takes --control-border, as the theme, Discord
     and menu circles do. These wore the divider hairline (1.16–1.24:1). The initials avatar keeps
     its accent ring, which its :has() rule holds on specificity. */
  .site-nav-close, .reel-btn, .reel-btn[aria-disabled="true"]:hover, .site-nav-dashboard, .occ-account-trigger { border-color: var(--control-border); }
  /* home sign-up: the field's outline is the control ring (it was 1.2:1 while the button inside it
     read 3.2:1); the field draws one focus ring, the row's, not a second one inside it; and the
     close card stops clipping the rings of the field and the Discord button on its edges
     (nothing overflows it, so its geometry is unchanged) */
  #join .gs-close-card { overflow: visible; }
  .gs-form .wl-row { border-color: var(--control-border); }
  .gs-form .wl-input:focus { outline: none; }
  /* the status line is reserved (the Reserved Line Rule), as on phones: a message lands in it and
     nothing moves; the scene gives the same 32px back, so the page is no taller at rest. The close's
     bottom is .scene-join's 56 at every width from 768 (a tall viewport's 152 is top padding, and
     .scene-join holds its own top there too), so the give-back is 24 throughout */
  #join .wl-status, #join .wl-status:empty { margin: 12px 0 0; min-height: 20px; line-height: 20px; }
  #join.scene-join:has(.wl-status) { padding-bottom: 24px; }
  /* community: Play/Pause takes the site's violet ring, drawn inside the button because the capture
     frame clips anything above it; the room rules take the site hairline */
  .u3 .capture-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-mini); }
  .u3 .rooms { --manifest-rule: var(--app-border); }
  /* "All 34 reviews" belongs to the reviews: 72 above it, 96 below (at 120 above it read as the
     next section's) */
  .u3 .quotes-more { margin-top: 72px; }
  /* room rows on the manifest rhythm pricing's answers keep: 20 / 10 / 10 / 20 (the note carried
     the browser's default paragraph margins) */
  .u3 .rooms p { margin: 0; }
  .u3 .rooms { --manifest-gap: 10px 40px; }
  .u3 .rooms span { margin-top: 0; }
  /* privacy: the inline "write to us" link takes the site's text-link ring, not the browser's */
  .doc a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-mini, 8px); }
}
/* the menu drawer's range, 768–1320 (from 1321 there is no burger and no drawer), carried from the
   tablet pass to all of it (owner, 25 Sep) */
@media (min-width: 768px) and (max-width: 1320px) {
  /* the menu and close icons match the 16px theme and Discord icons beside them */
  .site-nav-burger svg, .site-nav-close svg { width: 16px; height: 16px; }
  /* drawer: the group label on the rows' box edge, one text edge for this depth; the current
     page takes the theme's current-row fill, as on phones */
  .site-nav-group-label { margin-inline: 0; }
  .site-nav-row[aria-current="page"] { background: var(--nav-current-bg); }
}
/* the section capsule's range, 768–1459 (site-rail.css): keyboard focus stops 8px short of the
   capsule, as it does above the phone bar. site-rail.css (locked) reserves 76px, its offset plus its
   height, with no air; :root outranks its html:has() rule, which loads later, so the locked file
   stays untouched */
@media (min-width: 768px) and (max-width: 1459px) {
  :root:has(> body.has-spine-capsule) { scroll-padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }
}
/* login 861–1023: the two tracks yield instead of squeezing the form (the measured 861–990 defect).
   Below 861 the page's own rule is single-track — slot above the card — and stays that way.
   The side column's inset takes the gap's own 6vw, so the divider sits centred between them. */
@media (min-width: 861px) and (max-width: 1023px) {
  .login-grid { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: clamp(32px, 6vw, 72px); }
  .login-aside { padding-inline-start: clamp(32px, 6vw, 72px); }
}
/* 768–860: the line over the card is 40 from it, the grid's gap (its 8px bottom padding made 48) */
@media (min-width: 768px) and (max-width: 860px) {
  .login-aside { padding-bottom: 0; }
}
/* login's 44px text links (login.html, ≤860 or touch) become overlays, as on phones: "Forgot
   password?" keeps its 44px tap area without making a 44px-tall row, so the Password label sits over
   its field as close as Email's does; "Create an account" takes a normal word space before it */
@media (min-width: 768px) and (max-width: 860px), (min-width: 768px) and (max-width: 1023px) and (pointer: coarse) {
  .field-row .link-btn { min-height: 0; position: relative; }
  .field-row .link-btn::after { content: ""; position: absolute; inset: -13px -4px; }
  .login-foot .link-btn { padding-inline: 0; margin-inline-end: 0; }
}
/* 861 and up on touch (phones turned sideways, Android tablets, iPads in landscape at 1024–1366):
   the header's page links take the 44px tap height every other header control already has on a
   coarse pointer */
@media (min-width: 861px) and (pointer: coarse) {
  .occ-nav a { display: inline-flex; align-items: center; min-height: 44px; }
}
/* 861–1320 with a mouse, wherever the menu circle shows: it is 38px inside its 44px box, so the box
   hangs 3px out on each side of it; the gaps now read 10/10/10 and the circle ends on the 32px
   gutter */
@media (min-width: 861px) and (max-width: 1320px) and (pointer: fine) {
  .site-nav-burger { margin-inline: -3px; }
}
/* the measure cap, one number for every running-text component (was 52 / 56 / 50ch across three
   rules); privacy's lead joins it, so the lead and body share one edge as they do at 1024 */
@media (min-width: 768px) and (max-width: 1023px) {
  .razor-rule > p, .gs-sec > p, .reel-say p, .answers p, .u3 .rooms p, .doc p, .doc > p.lead, .login-say, .gs-ask-say p, .tier-note, .tier-bridge { max-width: 56ch; }
}
