/* Shared sidebar styles — v2 "Otto's Quarter" rebuild (2026-05-14).
   ----------------------------------------------------------------------
   The rail is now: brand → nav → Otto's quarter (Otto + Ask Otto pill) →
   identity → utility footer. The bottom stack (Otto/identity/footer) is
   `position: absolute` anchored to the rail's bottom edge; the nav scrolls
   independently above it, capped by `max-height` to the safe area above
   Otto's zone (see `.ck-sb-nav`) so it scrolls instead of ever rendering
   underneath him. This sidesteps the nested flex+grid pin-to-bottom
   problem and gives Otto a permanent home.

   Blue Chips Mono: cyan #00ffff is the only accent. Otto retains his
   native cyan-head/purple-tentacle palette — the only color break in
   the rail, intentional, because he's the mascot.

   Typography: Inter everywhere (matches design invariant).

   Compat IDs preserved: #sbName, #sbNiche kept so existing legacy
   bootstrap code that calls document.getElementById('sbName').textContent
   still works without changes. */

/* ===== Tokens — single source of truth for every measurement =====
   Edit a value here and it propagates through every rule below. */
.ck-sidebar{
  /* Geometry */
  --rail-w: 260px;

  /* Vertical rhythm */
  --brand-h: 64px;
  --row-h-toplevel: 42px;
  --row-h-child: 34px;
  --row-pad-v: 11px;
  --row-pad-v-child: 8px;
  --row-pad-h: 20px;
  --row-pad-h-child-text: 50px;
  --group-gap: 22px;

  /* Bottom stack (absolute-positioned). Painted Otto + pill + identity
     + footer. The 120px Otto was briefly retired on 2026-05-19 and
     restored the same day — the rail felt visibly empty without him. */
  --otto-h: 120px;
  --otto-button-h: 34px;
  --otto-button-w: 152px;
  --otto-pad-character-button: 20px;
  --otto-pad-button-identity: 20px;
  --identity-h: 48px;
  --footer-h: 92px;
  /* reserved-bottom must clear the TOP of the otto quarter, which is:
     footer-h + identity-h + otto-pad-button-identity (the bottom anchor)
     + otto-button-h + otto-pad-character-button + otto-h (quarter content).
     At desktop that sum is 334px; using calc() so it auto-adjusts when the
     mobile media query overrides the component variables (no separate mobile
     override needed). 8px breathing room above the quarter. */
  --reserved-bottom: calc(var(--footer-h) + var(--identity-h) + var(--otto-pad-button-identity) + var(--otto-button-h) + var(--otto-pad-character-button) + var(--otto-h) + 8px);

  /* Color tokens — dual-theme, scoped to .ck-sidebar.
     Single-accent cyan: every glow / rail / hover surface resolves
     to #00ffff at varying alpha. No coral. */
  --ck-sb-bg: rgba(10, 10, 15, 0.75);
  /* Real-device Safari sometimes fails to composite backdrop-filter on
     this fixed-position mobile drawer, leaving raw ~0.75 alpha with no
     blur — a legible double-exposure over the page underneath. The
     mobile drawer media query below falls back to fully opaque so it
     reads solid regardless of whether blur composites — the glass
     look is desktop-only anyway (this token is mobile-drawer-only), so
     there's nothing lost by not leaving a translucency gap here. */
  --ck-sb-bg-mobile-solid: rgba(10, 10, 15, 1);
  --ck-sb-border: rgba(255, 255, 255, 0.08);
  --ck-sb-text: rgba(255, 255, 255, 0.78);
  --ck-sb-text-active: #ffffff;
  --ck-sb-text-meta: rgba(255, 255, 255, 0.55);
  --ck-sb-hover-bg: rgba(255, 255, 255, 0.04);
  --ck-sb-active-bg: rgba(0, 255, 255, 0.08);
  --ck-sb-active-glow-1: rgba(0, 255, 255, 0.65);
  --ck-sb-active-glow-2: rgba(0, 255, 255, 0.35);
  --ck-sb-active-glow-3: rgba(0, 255, 255, 0.18);
  --ck-sb-divider: rgba(255, 255, 255, 0.06);
  --ck-sb-identity-name: rgba(255, 255, 255, 0.92);
  --ck-sb-identity-meta: rgba(255, 255, 255, 0.55);
  /* Account switcher. The menu background is deliberately OPAQUE, not glass:
     it opens over the footer links, and a translucent panel let the text
     underneath print straight through it. */
  --ck-sb-menu-bg: #131722;
  --ck-sb-menu-border: rgba(255, 255, 255, 0.12);
  --ck-sb-menu-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
  --ck-sb-store-tag: rgba(255, 255, 255, 0.62);
  --ck-sb-store-current-bg: rgba(0, 255, 255, 0.10);
}
[data-theme="light"] .ck-sidebar{
  --ck-sb-bg: rgba(245, 250, 252, 0.75);
  --ck-sb-bg-mobile-solid: rgba(245, 250, 252, 1);
  --ck-sb-border: rgba(14, 31, 38, 0.10);
  --ck-sb-text: rgba(14, 31, 38, 0.72);
  --ck-sb-text-active: #0E1F26;
  --ck-sb-text-meta: rgba(14, 31, 38, 0.62);
  --ck-sb-hover-bg: rgba(14, 31, 38, 0.04);
  --ck-sb-active-bg: rgba(0, 200, 220, 0.10);
  --ck-sb-active-glow-1: rgba(0, 184, 200, 0.85);
  --ck-sb-active-glow-2: rgba(0, 184, 200, 0.45);
  --ck-sb-active-glow-3: rgba(0, 184, 200, 0.18);
  --ck-sb-divider: rgba(14, 31, 38, 0.08);
  --ck-sb-identity-name: #0E1F26;
  --ck-sb-identity-meta: rgba(14, 31, 38, 0.62);
  --ck-sb-menu-bg: #FFFFFF;
  --ck-sb-menu-border: rgba(14, 31, 38, 0.14);
  --ck-sb-menu-shadow: 0 12px 32px rgba(14, 31, 38, 0.16);
  /* 0.70, not the 0.62 metadata floor: this tag is 11px, so it is small text
     and owes the full 4.5:1, not the 3:1 large-text allowance. */
  --ck-sb-store-tag: rgba(14, 31, 38, 0.70);
  --ck-sb-store-current-bg: rgba(0, 184, 200, 0.14);
}

/* ===== Sidebar container =====
   Full viewport height (fixed) OR full parent height (when inside
   .ro-layout-sidebar). The bottom stack uses position: absolute, so
   .ck-sidebar must be a positioning context. */
.ck-sidebar{
  display:none;
  position:fixed; top:0; left:0; bottom:0;
  width: var(--rail-w);
  z-index:110;
  background: var(--ck-sb-bg);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  /* Forces its own GPU compositing layer — Safari has a known bug where
     backdrop-filter on a fixed element silently fails to composite
     without this, especially nested inside another positioned ancestor
     (here, .ro-layout-sidebar). See --ck-sb-bg-mobile-solid above for
     the belt-and-suspenders fallback if it still doesn't composite. */
  transform: translateZ(0);
  border-right: 1px solid var(--ck-sb-border);
  flex-direction: column;
  overflow: hidden;            /* nav handles its own overflow */
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  /* Inter stylistic alternates — single-storey g, refined r/l/i. Invisible
     at first glance, premium polish at second. Plus subpixel antialiasing
     for crisper rendering on the dark glass. */
  font-feature-settings: "cv11" 1, "ss03" 1, "ss01" 1, "cv05" 1;
  font-variant-ligatures: common-ligatures contextual;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
@media(min-width:768px){
  .ck-sidebar{ display:flex; }
}
.ck-sidebar.force-show{ display:flex; }

/* --reserved-bottom scales to whatever's actually anchored above
   identity/footer, so nav (whose max-height subtracts --reserved-bottom)
   never reserves more than it needs to and never overlaps what IS there.
   Three cases, :has()-driven — no JS class toggling needed, and each
   simply stops matching if sidebar.js's rendering changes:
     1. No quarter at all (hideOtto, e.g. embedded contexts) — only
        identity + footer need clearing.
     2. Pill-only quarter (current default, SHOW_SIDEBAR_MASCOT = false)
        — clear identity + footer + the pill's own height, not the full
        120px silhouette + its padding.
     3. Full quarter (SHOW_SIDEBAR_MASCOT = true) — the base token-block
        --reserved-bottom above already covers this; neither rule below
        matches so it's untouched. */
.ck-sidebar:not(:has(.ck-sb-otto-quarter)){
  --reserved-bottom: calc(var(--footer-h) + var(--identity-h) + var(--otto-pad-button-identity) + 8px);
}
.ck-sidebar:has(.ck-sb-otto-quarter--pill-only){
  --reserved-bottom: calc(var(--footer-h) + var(--identity-h) + var(--otto-pad-button-identity) + var(--otto-button-h) + 8px);
}

/* ===== Mobile nav backdrop — canonical, single definition =====
   Replaces 9-16 near-identical per-page copies (.gen-backdrop,
   .sh-backdrop, .pg-backdrop, .clb-backdrop, .home-backdrop,
   .set-backdrop, .al-backdrop, .pd-backdrop, .rch-backdrop, ...),
   auto-injected at body level by _ensureMobileNavShell() in sidebar.js
   so every consumer gets it for free and the "nested inside a
   backdrop-filter nav bar shrinks it to 64px" bug (found live on 2 of
   the 7 pages during the 2026-07 rollout) is now structurally
   impossible — this element is never authored inside any page's own
   markup, only ever body-appended by JS. */
.ck-mobile-backdrop{
  display:none;
  position:fixed; inset:0;
  background:rgba(0,0,0,0.7);
  z-index:109;                 /* one below .ck-sidebar's 110 */
  backdrop-filter:blur(2px);
  -webkit-backdrop-filter:blur(2px);
}
[data-theme="light"] .ck-mobile-backdrop{
  background:rgba(0,0,0,0.7);
}
@media(max-width:768px){
  .ck-mobile-backdrop.is-shown{ display:block; }
}

/* Canonical hamburger button — added 2026-07-07. Only the TOGGLE
   MECHANISM converged in the 2026-07 sweep above; the button's own visual
   style stayed page-local (see sidebar.js's _ensureMobileNavShell comment),
   so 6+ pages each hand-rolled their own off-brand look (page-local
   "--gen-surface"/"--gen-border"/"--gen-text"-style tokens instead of the
   shared cyan tokens) -- confirmed live: on mobile, this rendered as a
   plain black-on-white box sitting immediately next to Otto chat's real
   cyan-bordered header buttons, reading as "a third, broken Otto button"
   even though it's an unrelated, correctly-functioning sidebar toggle.
   Mirrors otto-dock.js's already-proven .otto-dock-iconbtn treatment so
   the two read as one consistent system instead of two.

   A page just needs `class="hamburger"` (or a legacy "*-hamburger" class,
   per sidebar.js's _hamburgers() matcher) on its toggle button -- no
   per-page CSS needed. Position/size match the pre-existing per-page
   convention (fixed, top-right, 40x40, z-index 115 -- one above
   .ck-sidebar's 110 so the button stays clickable over an open drawer). */
.hamburger{
  display:none;
  position:fixed; top:14px; right:14px; z-index:115;
  width:40px; height:40px;
  align-items:center; justify-content:center;
  background:transparent;
  border:1px solid var(--cyan-border);
  border-radius:10px;
  color:var(--cyan);
  cursor:pointer;
  transition:background .15s, border-color .15s;
}
.hamburger:hover{
  background:var(--cyan-bg-soft);
  border-color:var(--cyan-border-strong);
}
.hamburger:focus-visible{ outline:2px solid var(--cyan); outline-offset:2px; }
.hamburger svg{
  width:20px; height:20px;
  fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round;
}
@media(max-width:768px){
  .hamburger{ display:inline-flex; }
}

/* When the sidebar lives inside the .ro-layout shell, override the
   default fixed-positioning so it fills the sticky column. Use 100vh
   not 100% — the mount-div (#sidebarMount) between .ro-layout-sidebar
   and .ck-sidebar has no explicit height, so `height: 100%` cascades
   to 0/content-height. 100vh bypasses that and reaches the viewport
   directly. */
.ro-layout-sidebar .ck-sidebar,
.ro-layout-sidebar .sidebar {
  position: relative;
  top: auto; left: auto; bottom: auto;
  width: 100%;
  height: 100vh;
  z-index: auto;
}
/* display intentionally NOT set here — it's owned by the show rules
   (base .ck-sidebar{display:none}, the >=768px media query, and
   .force-show), same discipline as the mobile-drawer block below.
   Setting it here unconditionally would force the rail visible inside
   the .ro-layout shell at every width, bypassing the mobile collapse. */

/* ===== Brand row ===== */
.ck-sb-brand{
  flex: 0 0 auto;
  height: var(--brand-h);
  padding: 0 var(--row-pad-h);
  display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--ck-sb-border);
}
.ck-sb-brand-otto{ width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; }
.ck-sb-brand-otto svg{ width:30px; height:30px; }
.ck-sb-brand-name{
  font-size: 18px;
  font-weight: 800;
  color: var(--ck-sb-text-active);
  letter-spacing: -.025em;
  /* Use Inter Display sizing optical adjustments — automatic on
     modern browsers when this size triggers display optical. */
  font-optical-sizing: auto;
}

/* ===== Nav =====
   The bottom stack (Otto/identity/footer) is position:absolute, so it
   takes no flex space — `flex: 1 1 0` alone would let nav claim the
   FULL rail height, painting its own content underneath the mascot
   whenever nav's content grows taller than the old reserved-bottom
   *padding* (padding only adds blank trailing space after content, it
   doesn't shrink nav's box — a group that grows past that padding
   renders straight through it and under Otto). `max-height` here caps
   nav's actual box at "rail height minus the bottom stack's real
   footprint", so nav genuinely cannot extend into Otto's zone.
   Root-caused 2026-07-10 when the AI Intelligence group grew from 3 to
   7 permanently-expanded rows and started rendering under Otto on
   shorter viewports.

   `overflow: hidden`, not `auto` (changed 2026-07-10) — the explicit
   requirement is that every nav item is always visible, never hidden
   behind a scroll. sidebar.js's `_fitNavToHeight` (see
   `_bindNavAutoFit`) is what actually guarantees this: it measures
   `.ck-sb-nav-inner`'s natural height against this box's height and
   scales the content down via CSS transform by exactly enough to fit,
   every render/resize/group-toggle. `overflow: hidden` here is the
   backstop that makes that the ONLY mechanism — no scrollbar can ever
   quietly appear as a fallback if the JS math is ever slightly off, or
   before it's had its first tick to run (rare — see next: `visibility:
   hidden` on nav-inner until the JS below can measure + apply
   `.ck-sb-nav-fit-ready`, so the fit is never visibly witnessed
   mid-recalculation as a stray scrollbar or a one-frame overflow flash). */
.ck-sb-nav{
  flex: 1 1 0;
  min-height: 0;
  max-height: calc(100% - var(--brand-h) - var(--reserved-bottom));
  padding: 16px 0 16px 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.ck-sb-nav-inner{
  visibility: hidden;
  /* flex-shrink:0 is load-bearing, not cosmetic. .ck-sb-nav-inner is a
     flex item of `.ck-sb-nav` (flex column, height-capped by
     max-height). Without this, the DEFAULT flex-shrink:1 lets the
     browser shrink nav-inner's own layout box down to whatever fits
     `.ck-sb-nav`'s available height BEFORE _fitNavToHeight ever reads
     `scrollHeight` — so the "natural" height measurement silently
     under-reports (it measures an already-squeezed box), the computed
     scale comes out too generous, and the last row(s) render below the
     visible box's actual bottom edge despite the math on paper saying
     everything fit. flex-shrink:0 forces nav-inner to always report
     its TRUE, un-shrunk natural height — transform:scale (applied by
     the JS) is the only thing allowed to visually compress it. */
  flex-shrink: 0;
}
.ck-sb-nav-inner.ck-sb-nav-fit-ready{
  visibility: visible;
}

/* ===== Common row treatment ===== */
.ck-sb-item{
  position: relative;
  display: flex; align-items: center; gap: 14px;
  padding: var(--row-pad-v) var(--row-pad-h);
  font-size: 16.5px;
  font-weight: 600;
  letter-spacing: -.003em;
  color: var(--ck-sb-text);
  text-decoration: none;
  border: none; background: none;
  width: 100%;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background .15s, color .15s, letter-spacing .15s;
}
/* Tighten letter-spacing slightly on hover — almost imperceptible
   but feels like the type is "leaning in." */
.ck-sb-item:hover{
  letter-spacing: -.006em;
}
.ck-sb-item:hover{
  background: var(--ck-sb-hover-bg);
  color: var(--ck-sb-text-active);
}
.ck-sb-item:focus-visible{
  outline: 2px solid var(--ck-sb-active-glow-1);
  outline-offset: -2px;
}

.ck-sb-item .ck-sb-icon{
  flex-shrink: 0;
  width: 18px; height: 18px;
  color: currentColor;
  display: inline-flex; align-items: center; justify-content: center;
}
.ck-sb-item .ck-sb-icon svg{
  width: 18px; height: 18px;
  stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.ck-sb-item .ck-sb-label{
  flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Active state — 2px cyan rail + cyan-tinted gradient bg. */
.ck-sb-item.is-active{
  color: var(--ck-sb-text-active);
  background: linear-gradient(
    90deg,
    var(--ck-sb-active-bg) 0%,
    transparent 100%
  );
}
.ck-sb-item.is-active::before{
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--cyan);
  /* Outer cyan glow — the rail reads as illuminated, not painted on.
     Brightens slightly on hover-active. */
  box-shadow: 2px 0 14px var(--cyan-glow-soft);
  transition: box-shadow .2s ease;
}
.ck-sb-item.is-active:hover::before{
  box-shadow: 2px 0 18px var(--cyan-glow-strong);
}

/* Cross-document view transitions — the cyan rail glides between
   siblings on navigation. Already wired; preserve the naming. */
@view-transition { navigation: auto; }
.ck-sb-item.is-active::before{
  view-transition-name: ck-sb-active-rail;
}
::view-transition-old(ck-sb-active-rail),
::view-transition-new(ck-sb-active-rail){
  animation-duration: .32s;
  animation-timing-function: cubic-bezier(.2,.7,.2,1);
}

/* ===== Chapter group ===== */
.ck-sb-group{
  position: relative;
}
.ck-sb-group + .ck-sb-group,
.ck-sb-item + .ck-sb-group{
  margin-top: var(--group-gap);
}

/* Group header — two render modes:
     (1) Toggle-only (Otto group, if it returns): button-as-header
     (2) Hybrid (Content/Reach with .href): wrapper div + link + toggle */
.ck-sb-group-header{
  display: flex; align-items: stretch;
  width: 100%;
}
button.ck-sb-group-header{
  gap: 14px;
  align-items: center;
}
/* Section label typography — uppercase typographic marker, not a nav
   row. The chapter is an organizing label; the children below are
   the primary clickable surface. Linear / Stripe / Vercel pattern. */
.ck-sb-group-header .ck-sb-label{
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ck-sb-text-meta);
  /* Reset hover letter-spacing override from .ck-sb-item:hover —
     uppercase tracking should stay constant. */
}
.ck-sb-item.ck-sb-group-header:hover .ck-sb-label,
.ck-sb-group-header:hover .ck-sb-label{
  letter-spacing: .14em;
  color: var(--ck-sb-text-active);
}
/* NOTE: chapter headers stay visually identical regardless of whether
   one of their children is active. The child row's own cyan rail +
   lit tributary do all the active-state signaling; the parent header
   doesn't compete. AI STUDIO and AI INTELLIGENCE look the same in
   every state — uppercase typographic markers, end of story. */

.ck-sb-group-header .ck-sb-caret{
  width: 13px; height: 13px;
  stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
  opacity: .5;
  transform: rotate(0deg);
  transition: transform .25s cubic-bezier(.2,.7,.2,1), opacity .15s ease;
}
button.ck-sb-group-header .ck-sb-caret{
  margin-left: auto;
}
.ck-sb-group.is-open > .ck-sb-group-header .ck-sb-caret{
  transform: rotate(90deg);
  opacity: .85;
}

/* Chapter headers stay visually identical regardless of whether one of
   their children is active. The child row's own cyan rail + lit
   tributary do all the active-state signaling — the parent doesn't
   compete. AI STUDIO and AI INTELLIGENCE look the same in every state:
   quiet uppercase typographic markers. */

/* Hybrid header link + chevron toggle. */
.ck-sb-group-link{
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
}
.ck-sb-group-toggle{
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0;
  padding: 0 16px;
  margin: 0;
  color: var(--ck-sb-text);
  cursor: pointer;
  transition: background .15s, color .15s;
}
.ck-sb-group-toggle:hover{
  background: var(--ck-sb-hover-bg);
  color: var(--ck-sb-text-active);
}
.ck-sb-group-toggle:focus-visible{
  outline: 2px solid var(--ck-sb-active-glow-1);
  outline-offset: -2px;
}
/* Toggle stays the same color regardless of has-active-child — parent
   header never brightens (see above). */

/* Children collapse panel — grid-template-rows animation. */
.ck-sb-children{
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .28s cubic-bezier(.2,.7,.2,1);
}
.ck-sb-group.is-open > .ck-sb-children{
  grid-template-rows: 1fr;
}
.ck-sb-children > *{
  min-height: 0;
}
.ck-sb-children{ overflow: hidden; }

/* ===== Child destination row =====
   Tributary lines: a 1px cyan vertical line runs from the chapter
   header down through all children at left:34px, with a 12px horizontal
   stub branching into each child row at left:34px → 46px. Replaces
   the previous bullet dots. River → branches → leaves. Active child's
   line lights solid; siblings stay quiet. */
.ck-sb-child{
  padding: var(--row-pad-v-child) var(--row-pad-h) var(--row-pad-v-child) var(--row-pad-h-child-text);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.003em;
  color: var(--ck-sb-text);
  position: relative;
  gap: 10px;
}
/* Vertical tributary segment — one per child row, stacks into a
   continuous river line via the run of rows. Bolder + more visible at
   rest (2026-07-10, was 1px/18% — read as barely-there); the resting
   state is still quieter than hover/active, just no longer faint. */
.ck-sb-child::before{
  content: '';
  position: absolute;
  left: 34px; top: 0; bottom: 0;
  width: 2px;
  background: color-mix(in srgb, var(--ck-sb-active-glow-1) 50%, transparent);
  transition: background .2s ease, box-shadow .2s ease;
}
/* Last child gets a curved end-cap — the river terminates instead
   of bleeding into the next group. */
.ck-sb-child:last-child::before{
  bottom: 50%;
}
/* Horizontal tributary stub — branches from the river into the row. */
.ck-sb-child .ck-sb-bullet{
  position: absolute;
  left: 34px; top: 50%;
  width: 12px; height: 2px;
  background: color-mix(in srgb, var(--ck-sb-active-glow-1) 60%, transparent);
  border-radius: 0;
  transform: translateY(-1px);
  transition: background .2s ease, box-shadow .2s ease, width .2s ease;
}
/* Hover lights the row's stub + the segment above it. */
.ck-sb-child:hover::before,
.ck-sb-child:hover .ck-sb-bullet{
  background: color-mix(in srgb, var(--ck-sb-active-glow-1) 80%, transparent);
}
.ck-sb-child:hover .ck-sb-bullet{
  width: 16px;
}
/* Active row: full cyan tributary + glow. */
.ck-sb-child.is-active::before{
  background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan-glow-soft);
  display: block;  /* override the .ck-sb-item.is-active::before { display:none } from before */
}
.ck-sb-child.is-active .ck-sb-bullet{
  background: var(--cyan);
  width: 16px;
  box-shadow: 0 0 6px var(--cyan-glow-strong);
}
.ck-sb-child.is-active{
  color: var(--ck-sb-text-active);
}

/* "Soon" pill — quiet, no-action affordance. */
.ck-sb-soon-pill{
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 99px;
  background: color-mix(in srgb, var(--ck-sb-active-glow-1) 14%, transparent);
  color: color-mix(in srgb, var(--ck-sb-active-glow-1) 75%, var(--ck-sb-text));
  border: 1px solid color-mix(in srgb, var(--ck-sb-active-glow-1) 22%, transparent);
  margin-left: auto;
  white-space: nowrap;
}
.ck-sb-child.is-soon{ opacity: .82 }
.ck-sb-child.is-soon:hover{ opacity: 1 }

/* ===== Otto's quarter — Otto silhouette + Ask Otto pill button =====
   Absolute-positioned bottom stack. Sits above identity, which sits
   above the utility footer. Each anchored to its own bottom offset
   so the layout doesn't depend on flex calculations. */
/* Otto's quarter — 120px painted Otto sits above the compact "Ask Otto"
   pill. The pill opens the auto-mounted dock on the right; the painted
   Otto IS Otto on the rail — breathing, eye-tracking, hover-EXCITED.
   Briefly removed 2026-05-19 (PR #591) and restored same-day after the
   rail felt visibly empty. */
.ck-sb-otto-quarter{
  position: absolute;
  left: 0; right: 0;
  bottom: calc(var(--footer-h) + var(--identity-h) + var(--otto-pad-button-identity));
  display: flex; flex-direction: column; align-items: center;
  pointer-events: none;       /* let clicks fall through to buttons */
}
.ck-sb-otto-quarter > *{ pointer-events: auto; position: relative; z-index: 1; }
/* Cyan underglow — soft radial gradient painted beneath Otto. Pulses
   with his breathing so he reads as lit from below, anchored in cyan
   light. */
.ck-sb-otto-quarter::before{
  content: '';
  position: absolute;
  left: 50%;
  top: calc(var(--otto-h) * 0.65);
  width: 200px;
  height: 120px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, var(--cyan-bg-soft) 0%, transparent 65%);
  pointer-events: none;
  z-index: 0;
  animation: ck-sb-otto-underglow 4s ease-in-out infinite alternate;
}
@keyframes ck-sb-otto-underglow{
  from { opacity: 0.7; }
  to   { opacity: 1.0; }
}
/* Pill-only quarter (no painted silhouette above it) — the underglow is
   sized/positioned to sit under the 120px mascot; with no mascot there
   it would just read as a stray blur blob under a small button. */
.ck-sb-otto-quarter--pill-only::before{ display: none; }

/* Painted Otto — 120px SVG button, breathing, hover-lift. */
.ck-sb-otto{
  width: var(--otto-h);
  height: var(--otto-h);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  margin-bottom: var(--otto-pad-character-button);
  animation: ck-sb-otto-breathe 4s ease-in-out infinite alternate;
  transition: transform .2s cubic-bezier(.2,.7,.2,1);
  background: transparent;
  border: 0;
  padding: 0;
  outline: none;
}
.ck-sb-otto:focus-visible{
  outline: 2px solid var(--cyan);
  outline-offset: 4px;
  border-radius: 8px;
}
.ck-sb-otto svg{ width: 100%; height: 100%; display: block; }
.ck-sb-otto:hover{ transform: translateY(-2px); }
.ck-sb-otto:hover svg .otto-arm{
  filter: drop-shadow(0 0 8px var(--cyan-glow));
}
@keyframes ck-sb-otto-breathe{
  from { transform: scale(1.00); }
  to   { transform: scale(1.02); }
}
/* When the pill is hovered, Otto perks up — breathing speeds 4s → 2s. */
.ck-sb-otto-quarter:has(.ck-sb-otto-cta:hover) .ck-sb-otto{
  animation-duration: 2s;
}
@media (prefers-reduced-motion: reduce){
  .ck-sb-otto,
  .ck-sb-otto-quarter::before { animation: none; }
}

/* Ask Otto pill — Blue Chips Mono cyan border + thin label + a small
   right-pointing arrow that hints at the dock's location on the right
   side of the page. Dot is a 6px cyan circle (analogue to the dock's
   collapsed-strip glow). */
.ck-sb-otto-cta{
  height: var(--otto-button-h);
  min-width: var(--otto-button-w);
  padding: 0 14px;
  border-radius: 999px;
  border: 1.5px solid var(--cyan-border-strong);
  background: transparent;
  color: var(--cyan);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .015em;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px;
  transition: background .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease, transform .15s ease;
}
.ck-sb-otto-cta-dot{
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 6px var(--cyan-border-strong);
  flex-shrink: 0;
}
.ck-sb-otto-cta-label{ line-height: 1; }
.ck-sb-otto-cta-arrow{
  font-size: 14px;
  line-height: 1;
  color: var(--cyan-text-action);
  transition: transform .18s ease;
}
.ck-sb-otto-cta:hover{
  background: var(--cyan-bg-soft);
  border-color: var(--cyan);
  box-shadow: 0 0 14px var(--cyan-glow-soft);
}
.ck-sb-otto-cta:hover .ck-sb-otto-cta-arrow{
  transform: translateX(2px);
}
.ck-sb-otto-cta:focus-visible{
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
}
.ck-sb-otto-cta:active{
  transform: translateY(1px);
}

/* ===== Identity block — absolute, above the utility footer ===== */
.ck-sb-identity{
  position: absolute;
  left: 0; right: 0;
  bottom: var(--footer-h);
  height: var(--identity-h);
  padding: 12px var(--row-pad-h);
  border-top: 1px solid var(--ck-sb-border);
  box-sizing: border-box;
}
.ck-sb-identity-name{
  font-size: 14px;
  font-weight: 600;
  color: var(--ck-sb-identity-name);
  letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The niche goes italic — handwritten, personal moment. Signals
   "this is YOU, your store." Single typographic break from the
   otherwise-roman ladder of the rail. */
.ck-sb-identity-meta{
  font-size: 12px;
  font-weight: 400;
  font-style: italic;
  color: var(--ck-sb-identity-meta);
  margin-top: 3px;
  letter-spacing: -.005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ===== Account switcher =====
   Shipped 2026-08-06 with full markup, working JS, ARIA menu roles and its
   own unit test file — and no CSS at all. Every class below matched zero
   rules, so the trigger fell back to a browser-default grey button (white
   text on it measured 1.15:1, against a 4.5:1 requirement) and the menu
   rendered unpositioned, printing account names on top of the Privacy/Terms
   row: "Matthew Gorenswitch", "mattcurrent". This is the control that
   decides which store a merchant is operating on.
   scripts/check-unstyled-classes.js exists to make that class of miss
   impossible to ship again. */

/* The identity block is already position:absolute; make it the positioning
   context so the menu can anchor to it. */
.ck-sb-identity--switcher{
  position: absolute;
  display: block;
  padding: 0;
}
.ck-sb-store-trigger{
  appearance: none;
  -webkit-appearance: none;
  display: block;
  width: 100%;
  margin: 0;
  padding: 12px var(--row-pad-h);
  background: none;
  border: 0;
  border-radius: 10px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  box-sizing: border-box;
  transition: background .15s ease;
}
.ck-sb-store-trigger:hover{ background: var(--ck-sb-hover-bg); }
.ck-sb-store-trigger:focus-visible{
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
}
/* Leave room for the chevron so a long store name never runs under it. */
.ck-sb-store-trigger .ck-sb-identity-name,
.ck-sb-store-trigger .ck-sb-identity-meta{ padding-right: 18px; }

.ck-sb-store-chevron{
  position: absolute;
  right: var(--row-pad-h);
  top: 50%;
  transform: translateY(-50%);
  font-size: 10px;
  line-height: 1;
  color: var(--ck-sb-identity-meta);
  transition: transform .15s ease;
}
.ck-sb-store-trigger[aria-expanded="true"] .ck-sb-store-chevron{
  transform: translateY(-50%) rotate(180deg);
}

/* Opens UPWARD: the identity block sits directly above the footer, so a
   downward menu would fall off the bottom of the rail. */
.ck-sb-store-menu{
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: calc(100% + 6px);
  z-index: 10;
  padding: 6px;
  background: var(--ck-sb-menu-bg);
  border: 1px solid var(--ck-sb-menu-border);
  border-radius: 12px;
  box-shadow: var(--ck-sb-menu-shadow);
  max-height: 320px;
  overflow-y: auto;
  box-sizing: border-box;
}
.ck-sb-store-menu[hidden]{ display: none; }

.ck-sb-store-row{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 36px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease;
}
.ck-sb-store-row:hover{ background: var(--ck-sb-hover-bg); }
.ck-sb-store-row:focus-visible{
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
}
.ck-sb-store-row--current{ background: var(--ck-sb-store-current-bg); }

.ck-sb-store-row-name{
  font-size: 14px;
  font-weight: 600;
  color: var(--ck-sb-identity-name);
  letter-spacing: -.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* 11px is the floor for a label, and a label at that size owes weight 600
   (THEME_RULES rule 4). flex-shrink:0 keeps "current" from being squeezed
   into the name — the collision that made this read "mattcurrent". */
.ck-sb-store-row-tag{
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ck-sb-store-tag);
  white-space: nowrap;
}
.ck-sb-store-row--add{
  display: block;
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--ck-sb-divider);
  border-radius: 0 0 8px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--cyan-text-action);
}

/* Collapse the identity block when both fields are empty — kills the
   stray dash + phantom border under Sign Out on pages that don't
   pass name/niche. */
.ck-sb-identity:has(> .ck-sb-identity-name:empty):has(> .ck-sb-identity-meta:empty){
  display: none;
}
/* When identity is collapsed, the Otto quarter slides down to its
   slot — Otto + button anchor 24px above the footer instead. */
.ck-sidebar:has(.ck-sb-identity:has(> .ck-sb-identity-name:empty):has(> .ck-sb-identity-meta:empty)) .ck-sb-otto-quarter{
  bottom: calc(var(--footer-h) + var(--otto-pad-button-identity));
}

/* ===== Utility footer — Settings + Sign Out as icons ===== */
.ck-sb-utility-footer{
  position: absolute;
  left: 0; right: 0;
  bottom: 0;
  height: var(--footer-h);
  padding: 10px 24px;
  display: flex; flex-direction: column; align-items: stretch; justify-content: center; gap: 8px;
  border-top: 1px solid var(--ck-sb-border);
  box-sizing: border-box;
}
.ck-sb-foot-icons{
  display: flex; align-items: center; justify-content: space-between;
}
/* Policy links — Privacy / Terms / Support. Uses the same meta/active text
   tokens as the icon row so both themes stay AA-readable. */
.ck-sb-policy{
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; line-height: 1;
}
.ck-sb-policy-link{
  color: var(--ck-sb-text-meta);
  text-decoration: none;
  transition: color .15s ease;
}
.ck-sb-policy-link:hover{ color: var(--ck-sb-text-active); }
.ck-sb-policy-link:focus-visible{
  outline: 2px solid var(--ck-sb-active-glow-1);
  outline-offset: 2px; border-radius: 4px;
}
.ck-sb-policy-sep{ color: var(--ck-sb-text-meta); font-size: 12px; }
.ck-sb-foot-icon{
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: 8px;
  background: transparent;
  border: 0;
  color: var(--ck-sb-text-meta);
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease, color .15s ease;
  position: relative;
}
.ck-sb-foot-icon svg{
  width: 18px; height: 18px;
  stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.ck-sb-foot-icon:hover{
  background: var(--ck-sb-hover-bg);
  color: var(--ck-sb-text-active);
}
.ck-sb-foot-icon:focus-visible{
  outline: 2px solid var(--ck-sb-active-glow-1);
  outline-offset: 2px;
}
/* Tooltip on hover. */
.ck-sb-foot-icon[data-tip]::after{
  content: attr(data-tip);
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%) translateX(-4px);
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-family: 'Inter', sans-serif;
  font-size: 11.5px;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s ease, transform .15s ease;
  z-index: 200;
}
.ck-sb-foot-icon:hover[data-tip]::after,
.ck-sb-foot-icon:focus-visible[data-tip]::after{
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Theme toggle — button holds both sun + moon SVGs stacked; CSS shows
   the one that represents the action you can take. Dark mode shows the
   sun (= "switch to light"), light mode shows the moon (= "switch to
   dark"). Default behavior treats "no data-theme attribute" as dark. */
.ck-sb-theme-toggle .ck-sb-theme-sun,
.ck-sb-theme-toggle .ck-sb-theme-moon{ display: none; }
.ck-sb-theme-toggle .ck-sb-theme-sun{ display: inline-block; }
[data-theme="light"] .ck-sb-theme-toggle .ck-sb-theme-sun{ display: none; }
[data-theme="light"] .ck-sb-theme-toggle .ck-sb-theme-moon{ display: inline-block; }

/* ===== Divider (only used inside chapter children, if needed) ===== */
.ck-sb-divider{
  height: 1px;
  background: var(--ck-sb-divider);
  margin: 10px var(--row-pad-h);
}

/* ===== Mobile drawer — slightly larger touch target on the pill ===== */
@media (max-width: 768px) {
  .ck-sidebar{
    --rail-w: 280px;
    --row-h-toplevel: 52px;
    --row-h-child: 44px;
    --row-pad-v: 16px;
    --row-pad-v-child: 12px;
    --otto-h: 80px;
    --otto-button-h: 40px;
    --otto-button-w: 176px;
    --otto-pad-character-button: 16px;
    --otto-pad-button-identity: 16px;
    --identity-h: 56px;
    --footer-h: 104px;
    /* --reserved-bottom intentionally NOT overridden here.
       The calc() in the default block uses var() references that resolve
       to the overridden mobile values above, so it auto-computes the
       correct mobile reserved height (312px + 8px = 320px) without a
       separate hardcoded override that could drift out of sync. */
    width: var(--rail-w);
    background: var(--ck-sb-bg-mobile-solid);
    /* Three-zone flex column: fixed header, scrolling nav, pinned footer.
       (flex-direction:column + overflow:hidden already come from the base
       .ck-sidebar rule; display is owned by the show rules, don't set it
       here or the drawer would force-show on mobile.)
       height:100dvh + bottom:auto: the base rule sets `bottom:0`, and on iOS
       Safari a fixed element with top + bottom + height ALL set is
       over-constrained — it mis-sizes, leaving a white band below the drawer
       and throwing off the flex chain (rows stretch, lower items pushed off
       screen). Anchor at top with an explicit dvh height and release bottom so
       there's exactly one height source; the solid bg then fills the full
       dvh, including down through the safe-area region. */
    height: 100dvh;
    bottom: auto;

    /* ===== Proportional scale — ONE knob controls the whole drawer =====
       Everything below derives from --nav-row-h so proportions stay locked at
       any size. 37px is the largest value that fits the ~745px iPhone small-
       viewport exactly; we ship 36px for a deliberate safety buffer (~16px)
       so shorter devices (SE, older models, a few px under 745) still fit with
       no scroll — a hair of row height is invisible, a stray scrollbar isn't.
       All 13 children stay expanded, labels ≥ ~12.5px. Change this one value
       and rows, fonts, icons, the ⓘ glyph, connector stroke, and child indent
       all move together. */
    --nav-row-h: 36px;
    --nav-child-h:      calc(var(--nav-row-h) * 0.86);   /* ~32 child row */
    --nav-font:         calc(var(--nav-row-h) * 0.35);   /* ~13 label */
    --nav-section-font: calc(var(--nav-row-h) * 0.30);   /* ~11 section header */
    --nav-icon:         calc(var(--nav-row-h) * 0.41);   /* ~15 left icon */
    --nav-info:         calc(var(--nav-row-h) * 0.35);   /* ~13 ⓘ glyph */
    --nav-connector:    max(1px, calc(var(--nav-row-h) * 0.055)); /* ~2 connector stroke */
    --nav-indent:       calc(var(--nav-row-h) * 0.92);   /* ~34 connector x-position */
  }
  .ck-sb-brand{ height: var(--brand-h); }
  .ck-sb-brand-name{ font-size: 17px; }
  .ck-sb-foot-icon{ width: 40px; height: 40px; }
  .ck-sb-foot-icon svg{ width: 22px; height: 22px; }

  /* Zone 1 — header (brand): fixed, doesn't scroll. */
  .ck-sb-brand{ flex: 0 0 auto; }

  /* Zone 2 — nav: takes the slack and scrolls. Undo the desktop
     reserved-bottom cap + the transform-fit (sidebar.js bails on mobile) so
     the menu scrolls natively instead of being shrunk to fit. Connector
     lines, ⓘ icons, spacing, weights and the active treatment are unchanged. */
  .ck-sb-nav{
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Pack rows from the top at natural height — never distribute slack. */
    justify-content: flex-start;
  }
  .ck-sb-nav-inner{ transform: none !important; width: auto !important; }

  /* Zone 3 — footer (Option C): only the theme/settings/logout icon row is
     pinned. The Ask Ollie pill (redundant with the on-page dock), the
     name/niche identity line, and the Privacy/Terms/Support row are NON-nav
     chrome — removed from the drawer to make room for all 13 children at a
     readable size. Privacy/Terms/Support move to the Settings page (reachable
     via the footer gear) to stay compliant. Desktop keeps all of them (this is
     scoped to the mobile drawer only). */
  .ck-sb-otto-quarter,
  .ck-sb-identity,
  .ck-sb-policy{ display: none; }
  .ck-sb-utility-footer{
    position: static;
    left: auto; right: auto; bottom: auto;
    flex: 0 0 auto;
    height: auto;
    padding-bottom: calc(10px + env(safe-area-inset-bottom)); /* clear the iOS URL bar / home indicator */
  }

  /* Nav padding trimmed to give the fit a little headroom. */
  .ck-sb-nav{ padding: 8px 0; }

  /* ===== Rows sit at the proportional height, content vertically centered =====
     Explicit height (not min-height) + flex-shrink:0 (set below) is deterministic
     in the flex-start scroll column — rows can neither grow nor shrink. Vertical
     padding is zeroed because the height now owns the row size. */
  .ck-sb-item{
    flex-shrink: 0;
    height: var(--nav-row-h);
    min-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    font-size: var(--nav-font);
    -webkit-tap-highlight-color: transparent;
  }
  .ck-sb-item:active{ background: var(--ck-sb-hover-bg); }
  .ck-sb-child{
    height: var(--nav-child-h);
    padding-left: calc(var(--nav-indent) + 16px);   /* text clears the connector */
    font-size: var(--nav-font);
  }
  .ck-sb-group-header,
  .ck-sb-group-header .ck-sb-group-link{ height: var(--nav-child-h); }
  .ck-sb-group-header .ck-sb-label{ font-size: var(--nav-section-font); }
  /* Left icon + connector stroke + indent all derive from the same knob. */
  .ck-sb-item .ck-sb-icon,
  .ck-sb-item .ck-sb-icon svg{ width: var(--nav-icon); height: var(--nav-icon); }
  .ck-sb-child::before{ left: var(--nav-indent); width: var(--nav-connector); }
  .ck-sb-child .ck-sb-bullet{ left: var(--nav-indent); height: var(--nav-connector); }
  /* Tighten the two group gaps (just air — recovers a little vertical budget). */
  .ck-sb-group,
  .ck-sb-item + .ck-sb-group{ margin-top: 12px; }

  /* ===== ⓘ hint — visual only, zero tap surface inside a 37px row =====
     The glyph is pulled 12px in from the right edge (out of the thumb's landing
     zone), sized off the same knob, and made non-interactive so the WHOLE row is
     one tap target that navigates. Tooltip access moves to a 400ms long-press on
     the row (sidebar.js) — long-press never conflicts with tap. sidebar.js also
     strips role/tabindex from these glyphs on mobile so there is no nested
     interactive element inside the row's <a>. */
  .ck-sidebar .hover-hint-anchor,
  .ck-sidebar .hover-hint-icon{
    pointer-events: none;
    margin-right: 12px;
  }
  .ck-sidebar .hover-hint-icon svg{ width: var(--nav-info); height: var(--nav-info); }
}

/* ===== Tablet collapse — 64px icon column =====
   Identity hidden, labels hidden, pill hidden (the dock on the right
   is the entry point at this viewport). Footer stacks vertically. */
.ck-sidebar.tablet-collapse{
  --rail-w: 64px;
  width: 64px;
}
.ck-sidebar.tablet-collapse .ck-sb-label,
.ck-sidebar.tablet-collapse .ck-sb-brand-name,
.ck-sidebar.tablet-collapse .ck-sb-identity,
.ck-sidebar.tablet-collapse .ck-sb-caret,
.ck-sidebar.tablet-collapse .ck-sb-soon-pill,
.ck-sidebar.tablet-collapse .ck-sb-children,
.ck-sidebar.tablet-collapse .ck-sb-otto-quarter{ display: none; }

.ck-sidebar.tablet-collapse .ck-sb-brand{
  padding: 16px 0;
  justify-content: center;
}
.ck-sidebar.tablet-collapse .ck-sb-item{
  justify-content: center;
  padding: 12px 0;
}
.ck-sidebar.tablet-collapse .ck-sb-item .ck-sb-icon{ margin: 0; }
.ck-sidebar.tablet-collapse .ck-sb-child{ padding: 0; }
.ck-sidebar.tablet-collapse .ck-sb-divider{ margin: 10px 12px; }

.ck-sidebar.tablet-collapse .ck-sb-utility-footer{
  flex-direction: column;
  height: auto;
  padding: 10px 0;
  gap: 8px;
  justify-content: center;
}

/* ===== Layout offset compatibility =========================
   Consuming pages set `margin-left: 260px` on content wrappers at
   >=768px. The fixed sidebar width is 260px so layout offsets line up. */
