/* ib-rail.css — the universal sidebar. The ONLY sidebar.
 *
 * Shown on every surface EXCEPT /admin, /embed and the auth screens. Guides and
 * /account get it too; app.js's ProtocolSidebar and the account's own rail are gone.
 * Desktop-only: appears at >=1024px and reserves a 280px left gutter via
 * `html.ib-rail-on body { padding-left: 280px }`.
 * Signed-out visitors get the SAME column, minus the saved-data lists.
 *
 * Built + populated by ib-rail.js. This sheet is <link>ed directly by all 188 static
 * shells and by app/layout.tsx — it is NOT injected at runtime any more. That
 * mattered: while ib-nav.js injected it, the gutter was not reserved until the sheet
 * arrived, so the page painted full-width and then jumped 280px right as a grey rail
 * appeared. The pre-paint gate in each shell adds html.ib-rail-on before first paint;
 * this sheet has to be render-blocking for that class to mean anything.
 */

/* ── Shared rail glass-card surface. One recipe consumed by .ib-uni-card and
   .ib-uni-signin-card (identical dark + light glass). Light grad/border are
   overridden in the block below; the blur is theme-
   independent. The dark box-shadow is shared via --ib-rail-card-shadow and is
   intentionally NOT overridden for light on .ib-uni-signin-card (it keeps the
   dark shadow there, matching prior behaviour); .ib-uni-card sets its own light
   box-shadow. ── */
:root {
  --ib-rail-card-grad: linear-gradient(135deg, rgba(255,255,255,0.1), rgba(255,255,255,0.035));
  --ib-rail-card-border: 1px solid rgba(255,255,255,0.13);
  --ib-rail-card-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 6px 18px rgba(0,0,0,0.3);
}

/* Hidden by default; only reveal + reserve space on desktop when the rail is "on"
   (ib-rail.js adds .ib-rail-on to <html> for SIGNED-IN users on non-excluded paths;
   signed-out visitors get .ib-rail-guest instead — no reserved column, just the slim
   .ib-uni-tab edge affordance). */
.ib-uni-rail { display: none; }
.ib-uni-tab { display: none; }
/* ib-rail.js adds .ib-rail-live to <html> at EVERY width once the rail is built:
   a fixed column at >=1024px, an off-canvas drawer below it. .ib-rail-on is the
   narrower claim — "reserve the 280px gutter" — and stays desktop-only. */
html.ib-rail-live .ib-uni-rail { display: flex; }

/* ── mobile + tablet: the SAME rail, presented as an off-canvas drawer ──
   Below 1024px there is no gutter; the rail slides in over the page behind a scrim.
   The blueprint's 70px tablet icon rail is deliberately not implemented: 768-1023px
   previously showed NO rail, so a squeezed icon strip there would be a downgrade from
   the full sidebar this gives them. */
@media (max-width: 1023px) {
  html.ib-rail-live .ib-uni-rail {
    width: 300px;
    max-width: 86vw;
    z-index: 400;                /* over the scrim (399) and the sticky nav (100) */
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.26s cubic-bezier(0.4,0,0.2,1), visibility 0.26s;
  }
  html.ib-rail-open .ib-uni-rail { transform: translateX(0); visibility: visible; }
  html.ib-rail-live .ib-uni-scrim,
  html.ib-rail-live .ib-uni-burger,
  html.ib-rail-live .ib-uni-mpfp { display: flex; }
  /* Open: the burger becomes the drawer's close X inside it; the fixed avatar would just
     float over the scrim, so hide it while the drawer is open. */
  html.ib-rail-open .ib-uni-mpfp { display: none; }
  /* The `html.ib-rail-live .ib-hamburger { display:none !important }` rule that used to
     live here is gone with the nav markup. It existed only to out-shout app.js:11652's
     injected `.ib-nav--drawer .ib-hamburger{display:flex!important}`. The nav survives
     on the surfaces ib-rail.js excludes (/admin, /embed, auth), and on those the rail is
     never live — so the two never meet and no override is needed. */
}
/* Desktop: no drawer chrome at all. */
@media (min-width: 1024px) {
  .ib-uni-scrim, .ib-uni-burger, .ib-uni-mpfp { display: none; }
}

.ib-uni-scrim {
  display: none;
  position: fixed; inset: 0; z-index: 399;
  background: rgba(0,0,0,0.42);
  opacity: 0; pointer-events: none;
  transition: opacity 0.26s ease;
}
html.ib-rail-open .ib-uni-scrim {
  opacity: 1; pointer-events: auto;
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.ib-uni-burger {
  display: none;
  position: fixed; top: 2px; left: 10px; z-index: 401;
  width: 40px; height: 40px; padding: 0;
  align-items: center; justify-content: center;
  border-radius: 10px;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(20,20,23,0.85);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: var(--ib-fg);
  cursor: pointer;
}
.ib-uni-burger svg { width: 20px; height: 20px; }
/* Open: the button becomes the drawer's close affordance and STAYS on the LEFT (top-left) —
   the drawer header reads close · logo · home, so the close anchors the left edge instead of
   jumping across to the right. */
html.ib-rail-open .ib-uni-burger { left: 10px; }
.ib-uni-burger { background: rgba(250,250,252,0.92); border-color: rgba(0,0,0,0.12); color: #1a1a1e; }

/* ── Mobile identity: a fixed avatar pinned top-right, the burger's twin ──
   Same 40px pill, same fixed top offset, opposite corner. Stays on screen as the page
   scrolls (position:fixed), so the burger + avatar read as a persistent header pair. */
.ib-uni-mpfp {
  display: none;
  position: fixed; top: 2px; right: 10px; z-index: 401;
  width: 40px; height: 40px; padding: 0;
  align-items: center; justify-content: center;
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(20,20,23,0.85);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: var(--ib-fg);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.ib-uni-mpfp img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ib-uni-mpfp svg { width: 20px; height: 20px; }
/* Signed-in avatars use the account accent gradient (matches the drawer profile av). */
.ib-uni-mpfp:not(.ib-uni-mpfp-guest) { background: linear-gradient(135deg, #2a3f3d, #16201f); border-color: rgba(255,255,255,0.06); }
.ib-uni-mpfp-txt { font-weight: 800; font-size: 15px; color: var(--ib-cta-accent); }
.ib-uni-mpfp-guest { color: rgba(var(--ib-fg-rgb),0.7); }
.ib-uni-mpfp-guest { background: rgba(250,250,252,0.92); border-color: rgba(0,0,0,0.12); color: rgba(20,20,28,0.65); }

/* Mobile: the floating nav chrome (burger + avatar) rides the html.ib-nav-hidden signal that
   ib-nav.js toggles on scroll — sliding up out of the way while you read the page and returning
   on scroll-up. Overlay + blur already live on these pills; auto-hiding + the smaller reserved
   top gap (see html.ib-rail-live body below) is what reclaims the screen. */
.ib-uni-burger, .ib-uni-mpfp { transition: transform 0.28s ease, opacity 0.28s ease; }
html.ib-nav-hidden .ib-uni-burger,
html.ib-nav-hidden .ib-uni-mpfp { opacity: 0; transform: translateY(-160%); pointer-events: none; }
/* Never hide the burger while the drawer is open — it is the close affordance then. */
html.ib-rail-open .ib-uni-burger { opacity: 1; transform: none; pointer-events: auto; }

/* 1024px, not 1200px. The rail used to need 1200px, which left 768–1199px with no
   rail at all once app.js's .ib-proto-rail was deleted (that one was hidden only by
   html.ib-rail-on, so it rendered in exactly that band — the "old sidebar keeps
   coming back" bug). Below 1024px the protocols live in the mobile nav drawer,
   which ib-rail.js also fills. Keep this in lock-step with ib-rail.js's DESKTOP
   query, layout.tsx's pre-paint gate, and the ib-rail-gate script in all 40 shells:
   if the JS gate and this media query disagree, the rail paints without its gutter
   and overlaps the page. */
@media (min-width: 1024px) {
  /* ── Pre-paint rail placeholder ──────────────────────────────────────────────
     The gate script adds html.ib-rail-on before first paint, but the rail element
     itself doesn't exist until ib-rail.js has loaded and run. Without this, the
     reserved 280px gutter paints as the page canvas (#fafafb) and then a grey rail
     with the logo pops into it — the "white flash on the sidebar when refreshing".
     This pseudo-element fills the gutter with the rail's own colour immediately, so
     the real rail (z-index 80) lands on an identical surface at z-index 79.
     The light palette is unconditional, so the placeholder matches immediately. */
  html.ib-rail-on::before {
    content: '';
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: 252px;
    z-index: 79;
    pointer-events: none;
    background: rgba(213,214,221,0.94);
    border-right: 1px solid rgba(0,0,0,0.1);
  }

  html.ib-rail-on .ib-uni-rail { display: flex; }
  /* Reserve the gutter on <body> (present on every surface). #ib-app only exists on
     Next routes — static calculator/home pages have no such wrapper, so padding it
     left the fixed rail overlapping their content. Fixed nodes (backdrop, the rail
     itself, chat FAB) ignore body padding, so only the page content shifts right. */
  html.ib-rail-on body { padding-left: 252px; }
  html.ib-rail-guest .ib-uni-tab { display: inline-flex; }
}

/* ── Mini rail: icons only ────────────────────────────────────────────────────────
   The homepage's first impression for a SIGNED-OUT visitor. The rail starts as a
   68px icon strip — brand, sign-in, search, the three calculator groups, Guides, and
   the standalone destinations — and any click inside it expands to the full 280px
   column (ib-rail.js: expandRail). Desktop only: below 1024px the rail is already an
   off-canvas drawer, so there is nothing to minimise.

   Set BEFORE first paint by the homepage's ib-rail-gate script (same place ib-rail-on
   is set), so the 68px gutter is the page's first layout and nothing shifts. The class
   is authoritative — ib-rail.js recomputes it on every evaluate() and the class guard
   re-asserts it through React hydration.

   Everything below is presentation only: the markup is identical to the full rail, so
   expanding is a single class removal with no re-render. */
@media (min-width: 1024px) {
  html.ib-rail-mini.ib-rail-on::before { width: 61px; }
  html.ib-rail-mini.ib-rail-on body { padding-left: 61px; }
  html.ib-rail-mini .ib-uni-rail { width: 68px; cursor: pointer; }

  /* Text, chrome and every list body: gone. What survives is exactly the glyphs. */
  html.ib-rail-mini .ib-rail-brand-text,
  html.ib-rail-mini .ib-uni-prof-meta,
  html.ib-rail-mini .ib-uni-badges,
  html.ib-rail-mini .ib-uni-seg,
  html.ib-rail-mini .ib-uni-search-in,
  html.ib-rail-mini .ib-uni-filter,
  html.ib-rail-mini .ib-uni-chips,
  html.ib-rail-mini .ib-uni-eyebrow,
  html.ib-rail-mini .ib-uni-acc-lbl,
  html.ib-rail-mini .ib-uni-acc-chev,
  html.ib-rail-mini .ib-uni-acc-body,
  html.ib-rail-mini .ib-uni-row > span:not(.ib-uni-row-ic),
  html.ib-rail-mini .ib-uni-foot,
  /* Home goes with the wordmark: in the strip ANY click expands the rail (ib-rail.js
     onMiniClick), so a link there could not do its own job. What survives is the glyphs
     — plus the fold tab, which is not in the rail at all (see .ib-uni-fold). */
  html.ib-rail-mini .ib-uni-headbtn,
  html.ib-rail-mini .ib-uni-nores { display: none; }

  /* The persisted tab is per-visitor (ib_rail_tab_v1), so a guest can land here with
     Saved showing — which for a guest is one sign-in card and nothing to make an icon
     of. Mini always shows Explore; the segmented control comes back on expand. */
  html.ib-rail-mini .ib-uni-pane[data-ib-pane="explore"] { display: flex; }
  html.ib-rail-mini .ib-uni-pane[data-ib-pane="saved"] { display: none; }

  html.ib-rail-mini .ib-uni-head { padding: 10px 8px 8px; }
  html.ib-rail-mini .ib-rail-brand { justify-content: center; padding: 6px 0 12px; }
  /* 68px cannot hold the avatar and the gear side by side — they collided and spilled
     past the strip. In the strip the head is a single column: logo, then avatar, then
     gear, and everything below simply follows. */
  html.ib-rail-mini .ib-uni-id { margin: 0; flex-direction: column; align-items: center; gap: 6px; }
  html.ib-rail-mini .ib-uni-prof { flex: 0 0 auto; padding: 4px; }
  html.ib-rail-mini .ib-uni-prof-av { width: 38px; height: 38px; }
  html.ib-rail-mini .ib-uni-gear { margin: 0; }

  /* The search field collapses to its own icon, sized to match the rows below it. */
  html.ib-rail-mini .ib-uni-tools { margin: 10px 0 6px; }
  html.ib-rail-mini .ib-uni-search {
    justify-content: center; margin: 0; height: 38px;
    border-radius: 9px;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.1);
  }
  html.ib-rail-mini .ib-uni-search-ic { position: static; }
  html.ib-rail-mini .ib-uni-search {
    background: rgba(255,255,255,0.7);
    border-color: rgba(0,0,0,0.1);
  }

  /* Nothing scrolls in a strip of eight icons; overflow would only give it a scrollbar. */
  html.ib-rail-mini .ib-uni-scroll { padding: 4px 8px 20px; overflow-y: hidden; }
  html.ib-rail-mini .ib-uni-acc-hd,
  html.ib-rail-mini .ib-uni-row { justify-content: center; gap: 0; padding: 11px 0; }
  html.ib-rail-mini .ib-uni-rows { margin-top: 10px; }
}

/* ── Rail brand (the original nav logo — icon + wordmark — moved to the rail top) ──
   The brand shares its row with Collapse + Home, right-aligned so they land in the
   same 32px column as the settings gear in the identity row directly below. */
/* padding-right reserves the fold button's column: the button is a body-level fixed
   element (it must escape the rail's overflow — see below), so it takes no space of its
   own and Home would otherwise sit underneath it. */
.ib-uni-brandrow { display: flex; align-items: center; gap: 2px; padding-right: 34px; }
.ib-uni-brandrow .ib-rail-brand { flex: 1 1 auto; min-width: 0; }
/* Mobile drawer header only: close (the burger, top-left) · logo (centred) · home (right,
   a pill sized like the close). Desktop is unchanged. */
@media (max-width: 1023px) {
  .ib-uni-brandrow { padding-left: 50px; padding-right: 0; }
  .ib-uni-brandrow .ib-rail-brand { justify-content: center; }
  .ib-uni-brandrow .ib-uni-home {
    box-sizing: border-box;
    /* The rail carries zoom:0.9, so in-rail content renders 0.9x; the close (burger) is a
       body-level sibling and is NOT zoomed. 49 * 0.9 ≈ 44, so the home renders the same size
       as the 44px close. */
    width: 49px; height: 49px; min-width: 49px; min-height: 49px; border-radius: 11px;
    border: 1px solid rgba(255,255,255,0.1);
    background: rgba(20,20,23,0.85);
  }
  .ib-uni-brandrow .ib-uni-home svg { width: 22px; height: 22px; }
  .ib-uni-brandrow .ib-uni-home { background: rgba(250,250,252,0.92); border-color: rgba(0,0,0,0.12); }
}

/* ── The fold button ──────────────────────────────────────────────────────────────
   ONE element in both states, and a SIBLING of the rail, not a child of it. The rail
   sets backdrop-filter, which makes it the containing block for fixed descendants and
   lets its overflow:hidden clip them — so nothing inside the rail can stick out past
   its edge. Sitting on <body> instead, the button is free to be:

     expanded  — hard right of the brand row, in the gear's column (left: 232px)
     collapsed — a lug CUT FROM the 68px strip: same surface, same hairline, sitting over
                 the rail's right border so there is no seam, with the chevron flipped to
                 point the way it will move

   Because only its coordinates change (the icon does the flipping), the two states are
   one transition: it slides across to its new position on click. */
/* Fold-icon hover wobble — a quick oscillation on mouse-over. The left chevron wobbles
   around its CURRENT facing (var(--fold-rot) preserves the collapsed 180° flip); the right
   pencil has no base rotation so it wobbles around 0. */
@keyframes ib-uni-fold-wobble {
  0%, 100% { transform: rotate(var(--fold-rot, 0deg)) scale(1); }
  20% { transform: rotate(calc(var(--fold-rot, 0deg) - 22deg)) scale(1.28); }
  50% { transform: rotate(calc(var(--fold-rot, 0deg) + 16deg)) scale(1.28); }
  75% { transform: rotate(calc(var(--fold-rot, 0deg) - 9deg)) scale(1.18); }
}
@keyframes ib-erail-pencil-wobble {
  0%, 100% { transform: rotate(0deg) scale(1); }
  20% { transform: rotate(-22deg) scale(1.28); }
  50% { transform: rotate(16deg) scale(1.28); }
  75% { transform: rotate(-9deg) scale(1.18); }
}
.ib-uni-fold { display: none; }
@media (min-width: 1024px) {
  html.ib-rail-on .ib-uni-fold {
    --fold-rot: 0deg;
    /* The rail overrides --ib-cta-accent to navy at ITS scope. The fold button is a body-
       level sibling, so it inherits nothing from the rail and would resolve the global
       teal — a colour the sidebar never uses. Restate the token here (light overrides it
       to the true brand navy in the theme block below). */
    --ib-cta-accent: #6d8cff;
    display: flex; align-items: center; justify-content: center;
    /* ONE protruding lug in BOTH states: it sits PROUD of the rail's right edge (252px
       expanded, 61px collapsed), a tab cut from the rail, never embedded in it. Only
       `left` and the icon flip change between states. */
    position: fixed; top: 5px; left: 251px;
    width: 23px; height: 33px; padding: 0;
    z-index: 81;                 /* the rail is 80 — the tab sits over its edge */
    background: rgba(9,9,11,0.72);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    border: 1px solid rgba(255,255,255,0.06); border-left: none;
    border-radius: 0 9px 9px 0;
    /* Shadow onto the PAGE only: offset right (+12) with a tight blur + negative spread so
       the penumbra can't reach back left across the rail's own face. */
    box-shadow: 12px 0 16px -6px rgba(0,0,0,0.5);
    color: rgba(var(--ib-fg-rgb),0.82);
    cursor: pointer;
    /* NO position transition. The rail collapses/expands INSTANTLY (it has no width
       transition), so the lug must snap with it. Animating `left`/`width` on its own is
       exactly what detached the tab from the edge and lagged it back — the "disconnect".
       Only hover feedback transitions; the icon still flips (see the svg rule below). */
    transition: background 0.2s ease, color 0.15s ease, border-color 0.2s ease;
  }
  /* The ICON flips, never the button. Rotating the box mirrored its geometry too — the
     right-only corner radius and the dropped left border ended up on the wrong side, so
     the tab pointed away from the rail it is supposed to be cut from. */
  html.ib-rail-on .ib-uni-fold svg {
    width: 15px; height: 15px; margin-left: 2px;
    transform: rotate(var(--fold-rot));
    transition: transform 0.42s cubic-bezier(0.34, 1.4, 0.64, 1);
  }
  @media (prefers-reduced-motion: reduce) {
    html.ib-rail-on .ib-uni-fold svg { transition: none; }
    html.ib-rail-on .ib-uni-fold:hover svg { animation: none; }
  }
  html.ib-rail-on .ib-uni-fold:hover { color: var(--ib-cta-accent); }
  /* Hover tints + wobbles the ICON only, never the surface (tinting the tab's own
     background reopens the seam the lug hides). No glow/shadow — the same treatment as
     the right-hand EDIT tab: icon wobbles and changes colour, nothing more. */
  html.ib-rail-on .ib-uni-fold:hover svg { animation: ib-uni-fold-wobble 0.6s ease infinite; }
  html.ib-rail-on .ib-uni-fold svg { transition: transform 0.42s cubic-bezier(0.34, 1.4, 0.64, 1); }

  /* Collapsed: the SAME lug as the base rule, just slid to the mini strip's edge (61px)
     with the icon flipped to point outward. Everything else — size, surface, blur, glow —
     is inherited, so the two states are one handle in two places, not two buttons. */
  html.ib-rail-on.ib-rail-mini .ib-uni-fold { --fold-rot: 180deg; left: 60px; }

  /* The rail's outer glow. It is what makes the collapsed strip + its lug read as one
     raised piece of chrome over the page, rather than a flat band with a button stuck to
     it. Same shadow on both, so the silhouette is continuous. */
  html.ib-rail-on .ib-uni-rail { box-shadow: 5px 0 22px -6px rgba(0,0,0,0.5); }

  @media (prefers-reduced-motion: reduce) {
    html.ib-rail-on .ib-uni-fold { transition: background 0.2s ease, color 0.15s ease; }
  }
}
/* Same box, colour and press as .ib-uni-gear — one head-button shape, three call sites. */
.ib-uni-headbtn {
  flex-shrink: 0; width: 32px; height: 32px; margin-bottom: 8px;
  display: flex; align-items: center; justify-content: center;
  border: none; background: none; padding: 0; cursor: pointer; border-radius: 8px;
  color: rgba(var(--ib-fg-rgb),0.82);
  transition: color 0.15s ease, transform 0.15s ease;
}
.ib-uni-headbtn svg { width: 18px; height: 18px; }
.ib-uni-headbtn:hover { color: var(--ib-cta-accent); }
.ib-uni-headbtn:active { transform: scale(0.94); }
/* Home icon (operator request): on hover it grows to 1.10 and wobbles continuously. Rotate +
   scale share the transform property, so they're baked into one keyframe. */
@keyframes ib-uni-home-wobble {
  0%, 100% { transform: scale(1.10) rotate(-7deg); }
  50%      { transform: scale(1.10) rotate(7deg); }
}
.ib-uni-home:hover svg { animation: ib-uni-home-wobble 0.5s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .ib-uni-home:hover svg { animation: none; transform: scale(1.10); }
}
/* Desktop: Home sits inline at the end of the brand row (44px button / 24px glyph), and the
   settings gear lines up directly beneath it in the identity row (Home's right edge is inset
   34px by the brand row to clear the fold button, and Home is 12px wider than the 32px gear,
   so shift the gear left by 34 + (44-32)/2 = 40px). Plus a little breathing room below the
   badge strip. Brand row + identity row keep their base horizontal layout. */
@media (min-width: 1024px) {
  .ib-uni-home { width: 44px; height: 44px; }
  .ib-uni-home svg { width: 24px; height: 24px; }
  /* Home + gear sit flush to the right content edge (16px from the rail edge, mirroring the
     logo's left inset). The old 34px brand-row inset just left dead space on the right, since
     the fold tab hangs OFF the rail's edge (left:251) and never overlaps the content. The gear
     keeps a 6px right margin so its centre lines up under the wider 44px Home. */
  .ib-uni-brandrow { padding-right: 0; }
  .ib-uni-gear { margin-right: 6px; }
  .ib-uni-head .ib-uni-badges { justify-content: center; padding: 8px 0 10px; }
}
.ib-rail-brand { display: flex; align-items: center; gap: 10px; padding: 2px 0 10px; text-decoration: none; }
.ib-rail-brand svg { flex-shrink: 0; }
.ib-rail-brand-text { font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; font-size: 20px; font-weight: 500; color: var(--white); letter-spacing: -0.01em; }
.ib-rail-brand-text strong { color: var(--ib-cta-accent); font-weight: 500; }

/* ── The top nav is gone ──────────────────────────────────────────────────────────
   Two rule sets lived here to make the rail and the nav coexist, and both are now
   removed rather than left inert:

   1. `html.ib-rail-on .ib-nav .ib-brand { display: none }` hid the nav's duplicate
      logo once the rail showed its own.
   2. The T8 treatment (>=1200px) made the nav transparent and lifted .ib-calc-title
      out of flow — `position:absolute; top:12px` — so the page title sat inside the
      nav band. With no nav band the title landed on top of the calculator's first
      control. It goes back into normal flow, where it was below 1200px.

   The nav still renders on the surfaces ib-rail.js excludes (/admin, /embed, the auth
   screens), which is why ib-nav.css survives. Nothing here should reference it. ── */

/* The nav's 48px of in-flow height was reserved as padding so its removal shifted no
   content. With no bar to fill it, that read as a dead band across the top of every
   page. Reclaimed, less a small breathing gap so the page H1 does not sit flush against
   the viewport edge. Below 1024px the fixed hamburger (top:2px + 40px tall) still has
   to be cleared, or it sits on the page's first control. */
html.ib-rail-live body { padding-top: 8px; }
/* Mobile: only a small top gap now — the nav chrome OVERLAYS the page (it auto-hides on
   scroll, see .ib-uni-burger/.ib-uni-mpfp above) instead of reserving a 56px band, giving the
   content that vertical space back. */
@media (max-width: 1023px) { html.ib-rail-live body { padding-top: 12px; } }

/* The rail itself never scrolls: it is a fixed header (.ib-uni-head) stacked on an
   independently scrolling pane area (.ib-uni-scroll). Overflow lives on the scroller,
   not here, so brand / identity / segmented control stay pinned. */
.ib-uni-rail {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 280px;
  /* Operator request: the whole rail — and every component inside it — renders 10%
     smaller. `zoom` shrinks the 280px width to 252px AND scales every inner px (fonts,
     icons, padding, gaps) in one move; `transform:scale` can't be used because the rail
     is a full-height fixed column (top:0;bottom:0) and scaling would leave a gap at the
     bottom. The reserved gutter + pre-paint placeholder are set to the matching 252px
     (mini: 61px), and the sibling fold button is repositioned to the narrower edge. */
  zoom: 0.9;
  z-index: 80;                 /* under the sticky nav (100) + drawers, over content */
  flex-direction: column;
  gap: 0;
  padding: 0;
  overflow: hidden;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  border-right: 1px solid rgba(255,255,255,0.06);
  background: rgba(9,9,11,0.72);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  /* Navy is the sidebar's accent, not teal. Pure navy is invisible on the near-black
     rail, so dark uses a legible periwinkle-navy; the porcelain rail (see the light block
     below) uses the true brand navy. Overriding these two tokens at the rail scope
     recolours every active link, pill, trail, chip, tab and CTA in one place. */
  --ib-cta-accent: #6d8cff;
  --ib-teal-rgb: 109,140,255;
}

/* ── fixed header ── */
.ib-uni-head { flex-shrink: 0; padding: 10px 16px 12px; }

/* ── independently scrolling pane area ── */
.ib-uni-scroll {
  flex: 1 1 auto;
  min-height: 0;               /* without this the flex child refuses to shrink and scroll */
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px 16px 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.16) transparent;
}
.ib-uni-scroll::-webkit-scrollbar { width: 7px; }
.ib-uni-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.14); border-radius: 4px; }
.ib-uni-scroll::-webkit-scrollbar-track { background: transparent; }

/* Panes fill the scroller so .ib-uni-foot's margin-top:auto pins the footer links to
   the bottom even when the Explore list is short. */
.ib-uni-pane { display: flex; flex-direction: column; min-height: 100%; }
.ib-uni-pane[hidden] { display: none; }

/* ── identity row: avatar + greeting | settings gear ──
   The negative side margins let the profile's hover surface bleed to the header's
   padding edge, so the avatar stays optically aligned with the brand mark above it. */
.ib-uni-id { display: flex; align-items: center; gap: 4px; margin: 0 0 0 -6px; }
.ib-uni-id .ib-uni-prof { flex: 1; }
/* The profile is a link to /account/ — it must read as one. */
.ib-uni-prof {
  padding: 6px; border-radius: 10px;
  transition: background 0.15s ease;
}
/* The identity row's CONTENT reacts, not the box: a subtle background tint + the sub-text
   brightening. No scale on hover and no press-in on click — the container never transforms. */
.ib-uni-prof:hover { background: rgba(255,255,255,0.07); }
.ib-uni-prof:hover .ib-uni-prof-sub { color: rgba(var(--ib-fg-rgb),0.7); }
.ib-uni-gear {
  flex-shrink: 0; width: 32px; height: 32px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  /* 0.5 measured ~2.6:1 against the rail — under the 3:1 floor for a meaningful icon. */
  color: rgba(var(--ib-fg-rgb),0.82);
  transition: color 0.15s ease, transform 0.15s ease;
}
.ib-uni-gear svg { width: 18px; height: 18px; }
/* No container behind it. The gear keeps spinning for as long as the pointer stays over
   it. Only the SVG spins (inside the static 32px box), so a rotating square can never
   sweep past the rail's overflow edge and get clipped. Presses in on click. */
@keyframes ib-gear-spin { to { transform: rotate(360deg); } }
.ib-uni-gear:hover { color: var(--ib-cta-accent); }
.ib-uni-gear:hover svg { animation: ib-gear-spin 2.4s linear infinite; }
.ib-uni-gear:active { transform: scale(0.94); }
.ib-uni-prof-av-guest { color: rgba(var(--ib-fg-rgb),0.55); }
.ib-uni-prof-av-guest svg { width: 20px; height: 20px; }

/* ── badge showcase: a row of medallions beneath the profile ──
   Moved off the dashboard body into the rail. Each medallion links to the Badges tab.
   Colour/fill/glow are set inline per badge (tier accent vs muted-locked); this only
   owns layout + the hover lift. */
.ib-uni-badges { display: flex; align-items: center; gap: 7px; padding: 8px 0 2px 2px; }
.ib-uni-badge-lnk {
  display: inline-flex; line-height: 0; text-decoration: none; border-radius: 50%;
  transition: transform 0.15s ease;
}
.ib-uni-badge-lnk:hover { transform: translateY(-1px) scale(1.08); }
.ib-uni-badge-lnk:active { transform: scale(0.96); }
.ib-uni-badge {
  width: 26px; height: 26px; box-sizing: border-box; border-radius: 50%;
  border: 1.5px solid; display: grid; place-items: center;
  /* Locked default (earned badges override colour/fill/glow inline). Dark theme. */
  color: rgba(var(--ib-fg-rgb), 0.42);
  border-color: rgba(255,255,255,0.14);
  background: rgba(255,255,255,0.04);
}
.ib-uni-badge svg { width: 13px; height: 13px; }
/* The rail themes via explicit light overrides rather than flipping --ib-fg-rgb, so the
   locked medallion needs its own light values to stay legible on the porcelain rail. */
.ib-uni-badge:not(.is-earned) {
  color: rgba(20,20,28,0.42);
  border-color: rgba(0,0,0,0.12);
  background: rgba(0,0,0,0.03);
}

/* ── segmented control (Explore | Saved Doses) ──
   Uses the site's CANONICAL .ib-seg / .ib-seg-pill / .ib-seg-btn from ib-shell.css.
   The private .ib-uni-seg* copy that used to live here is gone: the component was
   hoisted out of ib-calc.css (which app.js injects, so it was absent on guides,
   /account and /community) into ib-shell.css, which every surface links.

   Only two rail-specific things remain. Spacing. And the active colour: on a
   calculator ib-calc.css forces navy via `[data-theme="light"].ib-calc-page ...
   { color:#001D5C!important }`, but that rule is page-scoped, so off a calculator the
   same control would resolve --accent-numeral and come out deep teal. Restating it
   here keeps the sidebar's toggle identical on every page. Light matches the
   calculator's navy exactly; dark keeps brand teal, as the calculators do. */
.ib-uni-seg { margin-top: 12px; }
/* The two tabs were crammed against each other (the shared chip padding is 9px/4px,
   sized for a calculator's narrow unit toggle). In the rail they get room to breathe.
   Scoped to .ib-uni-seg: the canonical control in ib-shell.css is untouched. */
.ib-uni-seg .ib-seg-btn { padding: 10px 14px; }
.ib-uni-rail .ib-seg-btn.ib-seg-active { color: #001D5C; }

/* ── Explore: search ── */
.ib-uni-search { position: relative; display: flex; align-items: center; margin-bottom: 16px; }
.ib-uni-search-ic {
  position: absolute; left: 10px; display: flex; pointer-events: none;
  color: rgba(var(--ib-fg-rgb),0.4);
}
.ib-uni-search-ic svg { width: 15px; height: 15px; }
.ib-uni-search-in {
  width: 100%; box-sizing: border-box;
  padding: 9px 10px 9px 32px; border-radius: 9px;
  font-family: inherit; font-size: 12.5px; color: var(--ib-fg);
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.1);
  outline: none;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.ib-uni-search-in::placeholder { color: rgba(var(--ib-fg-rgb),0.38); }
.ib-uni-search-in:focus { border-color: var(--ib-cta-accent); background: rgba(255,255,255,0.08); }
.ib-uni-search-in::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* ── Explore/Saved: the search + filter-toggle row, and the chip row it reveals ──
   toolsHTML() lays the search box and the filter button in one flex row; the chip row
   sits below and shows only while the filter is open. These BASE (dark) rules were
   missing — only the overrides existed — so the button and chips
   rendered as unstyled default controls and the "filter" read as broken. Light values
   live in the theme block near the bottom of this sheet. */
/* The row sits close to the list it filters — search and the nav links below it read
   as one block, so the gap is small (was 14px, which floated the search away from it). */
.ib-uni-tools { display: flex; align-items: stretch; gap: 8px; margin-bottom: 6px; }
/* Search sheds its own bottom margin inside the row; the row owns the spacing. */
.ib-uni-tools .ib-uni-search { flex: 1 1 auto; margin-bottom: 0; }
/* Filter toggle: a soft square that matches the search field's height and radius, with
   no outline of its own until it is hovered or on. The bordered-box look it replaces
   read as a 2010 form control sitting next to a modern input. */
.ib-uni-filter {
  flex-shrink: 0; width: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 10px; cursor: pointer;
  color: rgba(var(--ib-fg-rgb),0.55);
  background: rgba(255,255,255,0.05);
  border: 1px solid transparent;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.ib-uni-filter svg { width: 17px; height: 17px; }
.ib-uni-filter:hover { color: var(--ib-fg); background: rgba(255,255,255,0.09); }
/* On: filled, not outlined — the state reads from the fill, one indicator. */
.ib-uni-filter.on {
  color: var(--ib-cta-accent);
  background: rgba(var(--ib-teal-rgb),0.14);
  border-color: transparent;
}
/* The chip row pushes the list down when it opens (it is a real block in the header,
   never an overlay), so it needs its own air above and below — the old -2px top margin
   pulled it up against the search field. */
.ib-uni-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 10px; }
.ib-uni-chips[hidden] { display: none; }
/* Chips are toggles, not buttons: flat fills, no borders, weight carries the state. */
.ib-uni-chip {
  font-family: inherit; font-size: 11.5px; font-weight: 500; cursor: pointer;
  padding: 6px 12px; border-radius: 999px;
  color: rgba(var(--ib-fg-rgb),0.6);
  background: rgba(255,255,255,0.06);
  border: none;
  transition: color 0.15s ease, background 0.15s ease;
}
.ib-uni-chip:hover { color: var(--ib-fg); background: rgba(255,255,255,0.1); }
.ib-uni-chip.on { color: var(--ib-cta-accent); background: rgba(var(--ib-teal-rgb),0.14); font-weight: 600; }

/* ── Explore: calculator accordions ── */
/* 6px, not 2px: the headers used to be transparent, so a hairline gap was invisible. Now the
   current group carries a filled container, and at 2px its tint reads as touching the next
   header. This is the breathing room that keeps them as separate objects. */
.ib-uni-accs { display: flex; flex-direction: column; gap: 6px; }
.ib-uni-acc[hidden] { display: none; }
.ib-uni-acc-hd {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 8px; border: none; background: transparent; cursor: pointer;
  border-radius: 9px; text-align: left;
  font-family: inherit; font-size: 13px; font-weight: 600;
  color: rgba(var(--ib-fg-rgb),0.82);
  transition: background 0.14s ease, color 0.14s ease;
}
.ib-uni-acc-hd:hover { background: rgba(255,255,255,0.06); color: var(--ib-fg); }
.ib-uni-acc-ic { flex-shrink: 0; display: flex; color: rgba(var(--ib-fg-rgb),0.5); transform-origin: center; transition: transform 0.18s ease, color 0.14s ease; }
.ib-uni-acc-ic svg { width: 17px; height: 17px; }
/* Hover energy lives in the ICON, not the container: the header button carries .ib-no-lift
   so it never transforms or shadows (the text still brightens via .ib-uni-acc-hd:hover); the
   icon grows and does a quick wobble instead, settling at the enlarged size while hovered. */
.ib-uni-acc-hd:hover .ib-uni-acc-ic { transform: scale(1.18); animation: ib-ic-wobble 0.5s ease; }
@keyframes ib-ic-wobble {
  0%   { transform: scale(1.18) rotate(0deg); }
  20%  { transform: scale(1.2) rotate(-10deg); }
  40%  { transform: scale(1.2) rotate(8deg); }
  60%  { transform: scale(1.2) rotate(-5deg); }
  80%  { transform: scale(1.2) rotate(3deg); }
  100% { transform: scale(1.18) rotate(0deg); }
}
/* `>` throughout: guide families nest inside the Guides accordion, and a descendant
   selector would style (and, for the body below, EXPAND) every family the moment its
   parent opened. */
.ib-uni-acc.open > .ib-uni-acc-hd .ib-uni-acc-ic { color: var(--ib-cta-accent); }
/* The group HOLDING the current calculator wears the same active treatment as the
   calculator's own link — accent ink on the navy tint (see .ib-uni-link.on). Without it the
   header sits inert while its child is lit, so the trail from group → page reads as two
   unrelated states instead of one selection. `.has-active` is set by ib-rail.js from
   activeGroupKey(); `.open` is a separate axis (a group can be open without being current). */
.ib-uni-acc.has-active > .ib-uni-acc-hd {
  color: var(--ib-cta-accent);
  background: rgba(var(--ib-teal-rgb),0.1);
}
.ib-uni-acc.has-active > .ib-uni-acc-hd .ib-uni-acc-ic { color: var(--ib-cta-accent); }
.ib-uni-acc-lbl { flex: 1; min-width: 0; }
.ib-uni-acc-chev { flex-shrink: 0; display: flex; color: rgba(var(--ib-fg-rgb),0.35); transition: transform 0.2s ease; }
.ib-uni-acc-chev svg { width: 15px; height: 15px; }
.ib-uni-acc.open > .ib-uni-acc-hd .ib-uni-acc-chev { transform: rotate(180deg); }
/* Collapse via grid-template-rows 0fr→1fr so the body animates from its own height —
   no hard-coded max-height guess that clips a longer group.
   The body MUST have exactly one grid child (.ib-uni-acc-list). `grid-template-rows`
   sizes only the first track; extra children auto-place into implicit `auto` rows and
   stay fully visible, so a bare list of links never collapses. */
.ib-uni-acc-body {
  display: grid; grid-template-rows: 0fr; overflow: hidden;
  transition: grid-template-rows 0.22s cubic-bezier(0.4,0,0.2,1);
}
.ib-uni-acc.open > .ib-uni-acc-body { grid-template-rows: 1fr; }
.ib-uni-acc-list { min-height: 0; overflow: hidden; }
/* setCat() snaps to the final expanded layout to measure it, then restores. Suppress the
   transition for that beat, or the snap-back animates and the real open never plays.
   The footer's margin-top:auto is zeroed for the same beat: it absorbs every pixel of
   free space, so with it on, the pane reports exactly 100% and the spacer measures as
   though it contributed nothing. */
.ib-uni-measuring .ib-uni-acc-body { transition: none; }
.ib-uni-measuring .ib-uni-foot { margin-top: 0; }

.ib-uni-link {
  display: block; padding: 7px 8px 7px 35px; border-radius: 8px;
  font-size: 12.5px; text-decoration: none;
  color: rgba(var(--ib-fg-rgb),0.62);
  transition: background 0.14s ease, color 0.14s ease;
}
/* Hover/active fill is drawn as an inset ::after pill on the tree links (see the tree rules)
   so it starts at the branch; the link's own full-width background would cover the gutter. */
.ib-uni-link:hover { color: var(--ib-fg); }
.ib-uni-link[hidden] { display: none; }
/* "You are here" — high contrast on the active link, per the blueprint. The highlight
   background is drawn as an inset pill on ::after (see the tree rules below) so it starts
   at the branch and never overlaps the tree gutter. */
.ib-uni-link.on { color: var(--ib-cta-accent); font-weight: 600; }
/* Hover reacts on the WORD, not the row: the label span scales up (no shadow/glow), while
   the link container (its pill + connector) stays still. The span is inline-block so the
   transform applies; left-center origin keeps it aligned to the tree branch, not drifting. */
.ib-uni-link-t { display: inline-block; transform-origin: left center; transition: transform 0.16s ease; }
.ib-uni-link:hover .ib-uni-link-t { transform: scale(1.08); }

/* ── Guides: a nested directory TREE with connecting track lines ─────────────────
   Three levels — Guides & Articles (L1) → family sub-menus (L2) → articles (L3) —
   joined by recessed grey "tracks": clean single-stroke lines down the sidebar. Each
   elbow is one continuous curved stroke into the spine. The active article lights its
   OWN branch to the accent. Vertical spines: L1 at x=17px (under the Guides book icon),
   L2 at x=34px (under the family headers). Labels are the hub's own headings — full
   sentences — so family headers wrap and align to the top line.
   --ib-tree = the L1 track; --ib-tree-lite = the fainter L2 track (children recede). */
:root {
  --ib-tree: rgba(255,255,255,0.08);
  --ib-tree-lite: rgba(255,255,255,0.09);
}
:root {
  --ib-tree: rgba(0,0,0,0.09);
  --ib-tree-lite: rgba(0,0,0,0.10);
}
/* The Guides directory — the sitemap — fills its tracks with brand navy, so the article
   tree reads as its own map, set apart from the grey calculator groups. Pure navy is
   invisible on the near-black rail, so dark lifts it to a legible periwinkle-navy; the
   porcelain rail uses the true brand navy. Scoped to the Guides accordion, these custom
   properties inherit down to every spine, elbow and sub-track inside it. */
.ib-uni-acc[data-ib-acc="guides"] {
  --ib-tree: rgba(96,128,240,0.6);
  --ib-tree-lite: rgba(96,128,240,0.36);
}
.ib-uni-acc[data-ib-acc="guides"] {
  --ib-tree: rgba(0,29,92,0.62);
  --ib-tree-lite: rgba(0,29,92,0.4);
}

.ib-uni-fams { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.ib-uni-sub[hidden] { display: none; }

/* L1 vertical spine — one continuous track down every OPEN group's list: the three
   calculator groups (Steroid / Peptide / Hormone Tools) AND Guides. It stays clipped
   while the group is collapsed (the 0fr grid body hides it), so it only shows when open.
   In Guides it runs past "All guides" and the family headers, alongside an expanded
   family's articles too (file-tree style; those get their own indented L2 track). */
/* padding-top opens a gap between the (highlighted) group header and its first child;
   it lives inside the collapsible list so it only shows when the group is open. The spine
   top below is nudged by the same amount so the track still starts at the first elbow. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list { position: relative; padding-top: 7px; }
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list::before {
  content: ''; position: absolute; left: 17px; top: 11px; bottom: 8px; width: 2px;
  border-radius: 1px; background: var(--ib-tree);
}
/* L1 elbows — a short horizontal branch from the spine to each direct calculator link,
   each guide family, and the Guides "All guides" row. Calculator links are single-line
   (elbow centred at 15px); the wrapping family headers/rows meet their first line (17px). */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link,
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row,
.ib-uni-sub { position: relative; }
/* Each elbow is a single hairline branch that curves UP out of the spine into the row —
   border-bottom + a bottom-left radius only, NO border-left. Drawing a vertical here would
   lie on top of the continuous spine, and two semi-transparent greys stacked read as a
   darker blob at every intersection. With only the curve, the branch meets the spine as one
   clean, even-weight stroke. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link::before,
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row::before,
.ib-uni-sub::before {
  content: ''; position: absolute; left: 17px; width: 13px; height: 10px;
  border-bottom: 2px solid var(--ib-tree);
  border-bottom-left-radius: 9px;
  transition: border-color 0.16s ease, filter 0.16s ease;
}
/* Hover: the row's own connecting branch lights to the accent — colour only, NO glow
   (the drop-shadow bloom was the container "glow" we're removing; the hover shadow now
   lives on the label word via .ib-uni-link-t). */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link:hover::before,
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row:hover::before,
.ib-uni-sub .ib-uni-link:hover::before {
  border-color: var(--ib-cta-accent);
}
/* Calculator group elbows are STRAIGHT (right-angle), not curved: the horizontal branch
   meets the vertical spine with no fillet. (Guides / sub-family elbows keep their curve.)
   This wins over the shared base radius above and also straightens the active-link corner,
   which inherits its radius from this same selector. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link::before { top: 5px; border-bottom-left-radius: 0; }
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row::before,
.ib-uni-sub::before { top: 7px; }
/* Active calculator link: the "you-are-here trail". One tall stroke whose left border
   runs UP the spine — clipped by the list's overflow:hidden, so it starts at the top of
   the open group — and whose bottom curves into the active row (the same fillet as every
   other elbow). This traces the whole path to the active item in the accent. The bottom
   sits where the normal elbow's bottom sits (top 5 + height 10 = 15), so only the run
   above it is added. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link.on::before {
  top: -9999px; height: calc(9999px + 15px);
  border-left: 2px solid var(--ib-cta-accent);
  border-bottom-color: var(--ib-cta-accent);
}
/* One inset highlight pill for BOTH hover and active, beginning right at the branch (x29)
   so the elbow leads into it and it never covers the tree gutter. z-index:-1 keeps it behind
   the link's own text AND behind the elbow stroke, so the line reads straight into the word. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link::after {
  content: ''; position: absolute; z-index: -1;
  left: 29px; right: 0; top: 0; bottom: 0;
  border-radius: 8px; background: transparent;
  transition: background 0.14s ease;
}
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link:hover::after { background: transparent; }
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link.on::after { background: rgba(var(--ib-teal-rgb),0.1); }
.ib-uni-sub > .ib-uni-acc-hd {
  align-items: flex-start;
  padding-left: 34px;
  font-size: 12.5px; font-weight: 600;
  color: rgba(var(--ib-fg-rgb),0.72);
}
.ib-uni-sub > .ib-uni-acc-hd .ib-uni-acc-lbl { white-space: normal; line-height: 1.3; }
.ib-uni-sub > .ib-uni-acc-hd .ib-uni-acc-chev { margin-top: 1px; }
.ib-uni-sub.open > .ib-uni-acc-hd { color: var(--ib-fg); }
/* "All guides", inside the Guides body, aligns with the family headers. */
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row { padding-left: 34px; font-size: 12.5px; }
.ib-uni-acc[data-ib-acc="guides"] .ib-uni-row .ib-uni-row-ic { display: none; }

/* L2 sub-track + L3 elbows — per open family, one indent deeper and fainter, so the
   article branches recede beneath their category. */
.ib-uni-sub .ib-uni-acc-list { position: relative; }
.ib-uni-sub.open > .ib-uni-acc-body > .ib-uni-acc-list::before {
  content: ''; position: absolute; left: 34px; top: 0; bottom: 7px; width: 2px;
  border-radius: 1px; background: var(--ib-tree-lite);
}
.ib-uni-sub .ib-uni-link {
  position: relative;
  padding-left: 46px;
  font-size: 11.5px;                  /* smaller than the category headers */
  color: rgba(var(--ib-fg-rgb),0.5);  /* and lighter, so they do not compete */
}
.ib-uni-sub .ib-uni-link::before {
  content: ''; position: absolute; left: 34px; top: 5px; width: 12px; height: 10px;
  border-bottom: 2px solid var(--ib-tree-lite);
  border-bottom-left-radius: 9px;
  transition: border-color 0.16s ease, filter 0.16s ease;
}
/* Active article: accent text (kept) + the same you-are-here trail up the L2 sub-track,
   clipped by the sub-list's overflow, and an inset highlight pill (fix 4). */
.ib-uni-sub .ib-uni-link.on { color: var(--ib-cta-accent); }
.ib-uni-sub .ib-uni-link.on::before {
  top: -9999px; height: calc(9999px + 15px);
  border-left: 2px solid var(--ib-cta-accent);
  border-bottom-color: var(--ib-cta-accent);
}
.ib-uni-sub .ib-uni-link::after {
  content: ''; position: absolute; z-index: -1;
  left: 44px; right: 0; top: 0; bottom: 0;
  border-radius: 8px; background: transparent;
  transition: background 0.14s ease;
}
.ib-uni-sub .ib-uni-link:hover::after { background: transparent; }
.ib-uni-sub .ib-uni-link.on::after { background: rgba(var(--ib-teal-rgb),0.1); }

.ib-uni-nores { padding: 10px 8px; font-size: 12px; color: rgba(var(--ib-fg-rgb),0.5); }
/* While filtering every group is force-expanded, so the chevrons stop implying a toggle. */
.is-filtering .ib-uni-acc-chev { opacity: 0; }

/* ── Explore: standalone destinations ── */
.ib-uni-rows { display: flex; flex-direction: column; gap: 2px; margin-top: 14px; }
.ib-uni-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 8px; border-radius: 9px;
  font-size: 13px; font-weight: 600; text-decoration: none;
  color: rgba(var(--ib-fg-rgb),0.82);
  transition: background 0.14s ease, color 0.14s ease;
}
.ib-uni-row:hover { background: rgba(255,255,255,0.06); color: var(--ib-fg); }
.ib-uni-row.on { color: var(--ib-cta-accent); background: rgba(var(--ib-teal-rgb),0.1); }
.ib-uni-row-ic { flex-shrink: 0; display: flex; color: rgba(var(--ib-fg-rgb),0.5); transform-origin: center; transition: transform 0.18s ease, color 0.14s ease; }
.ib-uni-row.on .ib-uni-row-ic { color: var(--ib-cta-accent); }
.ib-uni-row-ic svg { width: 17px; height: 17px; }
/* Same icon grow + wobble on the direct Pages rows (Home, Reviews, …). Rows are <a>, so
   they never carried the button-lift; only the icon animates, text still brightens. */
.ib-uni-row:hover .ib-uni-row-ic { transform: scale(1.18); animation: ib-ic-wobble 0.5s ease; }

/* ── Explore: footer links, pushed to the bottom ── */
/* Legal / chrome links, pinned to the bottom (margin-top:auto). A wrapping flex row
   left them ragged — three on one line, the orphan on the next. Two even columns give
   the block an edge to align to, and a hairline separates it from the nav above. */
.ib-uni-foot {
  margin-top: auto; padding-top: 14px; margin-bottom: 2px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 7px 10px;
  border-top: 1px solid rgba(255,255,255,0.07);
}
.ib-uni-foot-a {
  font-size: 11px; text-decoration: none; line-height: 1.2;
  color: rgba(var(--ib-fg-rgb),0.42);
  transition: color 0.14s ease;
}
.ib-uni-foot-a:hover { color: var(--ib-fg); }

/* Scroll room below the footer so an opened accordion header can reach the top of the
   pane. Zero by default; ib-rail.js sets an inline pixel height (measured geometry). */
.ib-uni-spacer { flex-shrink: 0; height: 0; }

/* profile header */
.ib-uni-prof { display: flex; align-items: center; gap: 11px; min-width: 0; text-decoration: none; }
.ib-uni-prof-av { width: 44px; height: 44px; border-radius: 8px; overflow: hidden; flex-shrink: 0; background: linear-gradient(135deg, #2a3f3d, #16201f); border: 1px solid rgba(255,255,255,0.06); display: flex; align-items: center; justify-content: center; color: var(--ib-cta-accent); font-weight: 800; font-size: 15px; }
.ib-uni-prof-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ib-uni-prof-meta { min-width: 0; display: flex; flex-direction: column; }
.ib-uni-prof-name { display: block; font-weight: 700; font-size: 15px; color: var(--ib-fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-uni-prof-sub { display: block; font-size: 12px; color: rgba(var(--ib-fg-rgb),0.5); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* section eyebrow */
/* 0.25 measured 2.02:1 on the night rail and 0.35 gave 2.14:1 on the porcelain one — the
   worst contrast in either surface, on the text that NAMES each section of the rail. 10px is
   nowhere near large-text territory. Raised to clear AA. */
.ib-uni-eyebrow { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: rgba(var(--ib-fg-rgb),0.62); margin-bottom: 11px; }

.ib-uni-list { display: flex; flex-direction: column; gap: 10px; }

/* protocol list mirrored into the mobile nav drawer ([data-ib-proto-slot]) */
.ib-uni-drawer { display: flex; flex-direction: column; }

/* Protocol card — recessed grey, matching the calculator input wells. No colour wash. */
.ib-uni-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 11px 12px;
  border-radius: 12px;
  cursor: pointer;
  overflow: hidden;
  text-decoration: none;
  background: #27272e;
  border: 1.5px solid rgba(255,255,255,0.08);
  box-shadow: none;
  transition: transform 0.14s ease, border-color 0.16s ease, box-shadow 0.18s ease, background 0.16s ease;
}
/* Hover: darker background, bright teal border + a teal glow. The glow is INSET (drawn
   inside the card) so the rail's overflow-x:hidden can never clip it, plus a small outer
   halo. Not gated behind @media(hover:hover) so it always applies where :hover fires. */
.ib-uni-card:hover { background: #1e1e24; border-color: #0fbcad; box-shadow: inset 0 0 0 1.5px rgba(15,188,173,0.6), inset 0 0 20px rgba(15,188,173,0.32), 0 0 16px 2px rgba(15,188,173,0.5); }
.ib-uni-card:hover { background: #e7e7ee; }
/* Click / active: navy border + navy text, grows to 1.02, glow + shadow off. */
.ib-uni-card:active, .ib-uni-card.active { transform: scale(1.02); border-color: #001D5C; box-shadow: none; }
.ib-uni-card:active .ib-uni-card-nick, .ib-uni-card.active .ib-uni-card-nick,
.ib-uni-card:active .ib-uni-card-chem, .ib-uni-card.active .ib-uni-card-chem,
.ib-uni-card:active .ib-uni-card-dose, .ib-uni-card.active .ib-uni-card-dose { color: #001D5C; }
/* Protocol cards fit their content, so a protocol with no distinct chemical subtitle
   (2-tier: nickname + dose) rendered shorter than a 3-tier one (nickname + chemical +
   dose) — the deck read as mismatched. Reserve the full 3-tier height so every saved
   card is the same size; the shorter body just centres (align-items:center). */
.ib-uni-card-proto { min-height: 72px; }

/* Sideways category strip on the left, between two vertical rules, white background.
   The label is an absolutely-positioned, rotated span so the glyphs stay upright. */
.ib-uni-cat {
  position: relative; flex-shrink: 0; align-self: stretch;
  width: 21px;
  margin: -11px 3px -11px -12px;
  background: #ffffff;
  border-left: 1px solid rgba(0,0,0,0.16); border-right: 1px solid rgba(0,0,0,0.16);
  box-shadow: 2px 0 6px rgba(0,0,0,0.14);
}
.ib-uni-cat > span {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(-90deg);
  white-space: nowrap;
  font-size: 8.5px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: #001D5C;
}

/* Compound glyph — per-compound colour (set inline). Rotates on hover, spins + glows
   in its own colour on click/active. */
.ib-uni-ic { position: relative; width: 30px; height: 30px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; transition: transform 0.35s cubic-bezier(0.34,1.35,0.6,1), filter 0.2s ease; }
/* Hover: the syringe spins round to face to the right. */
@media (hover: hover) { .ib-uni-card:hover .ib-uni-ic { transform: rotate(135deg); } }
/* Active (its action menu is open): a full spin + a glow in its own colour. */
.ib-uni-card:active .ib-uni-ic, .ib-uni-card.active .ib-uni-ic { transform: rotate(360deg); filter: drop-shadow(0 0 5px currentColor) drop-shadow(0 0 9px currentColor); }
.ib-uni-ic svg { width: 25px; height: 25px; }
.ib-uni-ic-vial svg { width: auto; height: 28px; }

.ib-uni-card-body { position: relative; display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; text-align: center; }
/* 3-tier protocol text: nickname (top, strongest) → chemical name → dose line. Navy. */
.ib-uni-card-nick { font-size: 14px; font-weight: 700; letter-spacing: -0.01em; color: #001D5C; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-uni-card-chem { font-size: 11px; font-weight: 500; color: rgba(0,29,92,0.75); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-uni-card-dose { font-size: 10.5px; margin-top: 1px; color: rgba(0,29,92,0.62); font-variant-numeric: tabular-nums; display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
.ib-uni-card-dose.is-single { justify-content: center; }
/* each dose segment (volume / dose / routine); clips rather than overflows the card. */
.ib-uni-dp { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* unit measurements (ml / mg / ×/wk) — a few sizes smaller than the numbers. */
.ib-uni-du { font-size: 0.66em; font-weight: 500; opacity: 0.75; margin-left: 0.5px; }
/* legacy label/meta pair (cycles + vials) */
.ib-uni-card-label { font-size: 13.5px; font-weight: 600; color: var(--ib-fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-uni-card-meta { font-size: 11px; color: rgba(var(--ib-fg-rgb),0.5); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-uni-card-chev { position: relative; font-size: 15px; color: rgba(var(--ib-fg-rgb),0.25); flex-shrink: 0; }

/* cycle-plotter tick box — coloured to the card's accent (--cc); glows when on */
.ib-uni-check { position: relative; width: 20px; height: 20px; border-radius: 6px; flex-shrink: 0; border: 1.5px solid var(--cc, #0fbcad); background: transparent; transition: background 0.15s ease, box-shadow 0.15s ease; }
.ib-uni-check.on { background: var(--cc, #0fbcad); box-shadow: 0 0 11px -1px var(--cc, #0fbcad); }
.ib-uni-check.on::after { content: ''; position: absolute; left: 6px; top: 2.5px; width: 5px; height: 9px; border: solid #0e0e10; border-width: 0 2px 2px 0; transform: rotate(45deg); }

/* + New protocol CTA */
.ib-uni-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 12px;
  font-size: 12px;
  /* Theme-aware readable text (dark on light, light on dark) — much darker than the
     previous faint teal on the porcelain rail. */
  color: var(--white);
  text-decoration: none;
  background: linear-gradient(140deg, rgba(var(--ib-teal-rgb),0.05), rgba(var(--ib-teal-rgb),0.015));
  border: 1px solid rgba(var(--ib-teal-rgb),0.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
  border-radius: 8px;
  padding: 9px 12px;
  text-align: center;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.ib-uni-cta:hover { background: linear-gradient(140deg, rgba(var(--ib-teal-rgb),0.1), rgba(var(--ib-teal-rgb),0.04)); border-color: rgba(var(--ib-teal-rgb),0.4); }

/* empty / signed-out states */
.ib-uni-empty { font-size: 12px; color: rgba(var(--ib-fg-rgb),0.5); line-height: 1.5; margin-bottom: 12px; }
.ib-uni-signin-card {
  display: block;
  text-decoration: none;
  border-radius: 13px;
  padding: 16px 15px;
  background: var(--ib-rail-card-grad);
  /* Opaque dark anchor (Night token) under the white-alpha glass gradient: without
     it the dark surface is whatever composites behind the card, which can read as
     near-white next to the near-white text. The light theme's `background:`
     shorthand override resets this to transparent, so light is untouched. */
  background-color: #121113;
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: var(--ib-rail-card-border);
  box-shadow: var(--ib-rail-card-shadow);
}
.ib-uni-signin-title { font-size: 14px; font-weight: 700; color: var(--ib-fg); margin-bottom: 5px; }
/* 0.66 alpha (not 0.5): composited over the dark glass card, 0.5 measured ~4.1:1 —
   under WCAG AA 4.5:1 for this 11.5px text. 0.66 measures ~7:1. */
.ib-uni-signin-sub { font-size: 11.5px; color: rgba(var(--ib-fg-rgb),0.66); line-height: 1.5; margin-bottom: 12px; }
.ib-uni-signin-btn { display: inline-block; font-size: 12px; font-weight: 600; color: var(--ib-cta-accent); background: linear-gradient(140deg, rgba(var(--ib-teal-rgb),0.14), rgba(var(--ib-teal-rgb),0.06)); border: 1px solid rgba(var(--ib-teal-rgb),0.4); border-radius: 8px; padding: 8px 14px; }

/* Signed-out slim edge affordance — replaces the full rail column for guests
   (html.ib-rail-guest; desktop-only via the media block above). One quiet line +
   sign-in link, fixed to the left edge; claims no layout space. */
.ib-uni-tab {
  position: fixed;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 80;                 /* same layer as the rail: under nav, over content */
  align-items: center;
  writing-mode: vertical-rl;
  padding: 14px 8px;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 12px;             /* site-wide >=12px text floor */
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: rgba(var(--ib-fg-rgb),0.72);
  background: rgba(20,20,23,0.85);
  border: 1px solid rgba(255,255,255,0.12);
  border-left: none;
  border-radius: 0 8px 8px 0;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.ib-uni-tab:hover { color: var(--ib-cta-accent); border-color: rgba(var(--ib-teal-rgb),0.4); }

/* ── light theme ── */
/* Light values for the shared rail glass-card surface (see :root). Consumed by
   .ib-uni-card and .ib-uni-signin-card. */
:root {
  --ib-rail-card-grad: linear-gradient(135deg, rgba(255,255,255,0.75), rgba(255,255,255,0.45));
  --ib-rail-card-border: 1px solid rgba(0,0,0,0.1);
}
.ib-uni-rail { background: rgba(213,214,221,0.94); border-right-color: rgba(0,0,0,0.1); --ib-cta-accent: #001D5C; --ib-teal-rgb: 0,29,92; }
.ib-uni-scroll { scrollbar-color: rgba(0,0,0,0.2) transparent; }
.ib-uni-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.18); }

/* New rail chrome is built from white-alpha, which disappears on the porcelain rail —
   every surface, border and hover below is restated against a dark ink. */
/* --ib-fg-rgb is the DARK foreground; this sheet always restates light explicitly.
   Without this the gear rendered near-white on the porcelain rail — 1.21:1. */
.ib-uni-gear,
.ib-uni-headbtn { color: rgba(20,20,28,0.82); }
/* Teal Deep — brand teal is ~2.2:1 on the porcelain rail (same call as the gear). */
.ib-uni-headbtn:hover { color: #001D5C; }
html.ib-rail-on .ib-uni-fold { color: rgba(20,20,28,0.82); --ib-cta-accent: #001D5C; }
html.ib-rail-on .ib-uni-fold:hover { color: #001D5C; }
/* The folded tab carries the RAIL's porcelain surface and hairline, not a white card's —
   it is a lug on the rail, so it has to be the same material, hover included: the fill
   does not change, only the icon tints + wobbles (see the .ib-uni-fold:hover svg rule). */
html.ib-rail-on .ib-uni-fold,
html.ib-rail-on .ib-uni-fold:hover {
  background: rgba(213,214,221,0.94);
  border-color: rgba(0,0,0,0.1);
  border-left: none;
}
/* Porcelain takes a far softer glow than the near-black rail — the dark base value reads
   as a smudge on it. */
html.ib-rail-on .ib-uni-rail {
  box-shadow: 5px 0 20px -8px rgba(0,0,0,0.22);
}
/* The lug's shadow is offset onto the PAGE side only, never back across the rail face. */
html.ib-rail-on .ib-uni-fold {
  box-shadow: 12px 0 16px -6px rgba(0,0,0,0.22);
}
.ib-uni-prof:hover { background: rgba(0,0,0,0.05); }
.ib-uni-prof:hover .ib-uni-prof-sub { color: rgba(20,20,28,0.72); }
/* Teal Deep — brand teal is ~2.2:1 on the porcelain rail. */
.ib-uni-gear:hover { color: #001D5C; }
.ib-uni-filter { background: rgba(255,255,255,0.7); border-color: transparent; color: rgba(20,20,28,0.6); }
.ib-uni-filter:hover { color: #001233; background: #ffffff; }
/* Teal Deep: brand teal is ~2.2:1 on the porcelain rail. */
.ib-uni-filter.on { color: #001D5C; background: rgba(var(--ib-teal-rgb),0.14); border-color: transparent; }
.ib-uni-chip { background: rgba(20,20,28,0.05); color: rgba(20,20,28,0.6); }
.ib-uni-chip:hover { color: #001233; background: rgba(20,20,28,0.09); }
.ib-uni-chip.on { color: #001D5C; background: rgba(var(--ib-teal-rgb),0.14); }
.ib-uni-search-in { background: rgba(255,255,255,0.7); border-color: rgba(0,0,0,0.12); color: #1a1a1e; }
.ib-uni-search-in:focus { background: #ffffff; border-color: var(--ib-cta-accent); }
.ib-uni-search-in::placeholder { color: rgba(20,20,28,0.42); }
.ib-uni-search-ic { color: rgba(20,20,28,0.45); }
.ib-uni-acc-hd { color: rgba(20,20,28,0.86); }
.ib-uni-sub > .ib-uni-acc-hd { color: rgba(20,20,28,0.74); }
.ib-uni-sub.open > .ib-uni-acc-hd { color: #001233; }
.ib-uni-acc-hd:hover { background: rgba(0,0,0,0.05); color: #001233; }
.ib-uni-acc-ic, .ib-uni-row-ic { color: rgba(20,20,28,0.5); }
.ib-uni-acc-chev { color: rgba(20,20,28,0.38); }
/* Brand teal is ~2.2:1 on the porcelain rail; Teal Deep measures ~5.5:1 (see the
   .ib-uni-signin-btn note below). Active links + open group icons use it. */
.ib-uni-acc.open > .ib-uni-acc-hd .ib-uni-acc-ic,
.ib-uni-row.on .ib-uni-row-ic { color: #001D5C; }
/* The current calculator's parent group — same navy + tint the active link gets on light. */
.ib-uni-acc.has-active > .ib-uni-acc-hd {
  color: #001D5C;
  background: rgba(var(--ib-teal-rgb),0.12);
}
.ib-uni-acc.has-active > .ib-uni-acc-hd .ib-uni-acc-ic { color: #001D5C; }
.ib-uni-link { color: rgba(20,20,28,0.66); }
.ib-uni-link:hover { color: #001233; }
.ib-uni-link.on { color: #001D5C; }
/* Inset highlight pills (fix 4) sit a touch stronger on the porcelain rail. */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link:hover::after,
.ib-uni-sub .ib-uni-link:hover::after { background: transparent; }
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link.on::after,
.ib-uni-sub .ib-uni-link.on::after { background: rgba(var(--ib-teal-rgb),0.12); }
/* Guide-tree articles recede on the porcelain rail (0.5), but the active one must still
   win the accent — both need the extra .ib-uni-sub class to beat the rules above. */
.ib-uni-sub .ib-uni-link { color: rgba(20,20,28,0.5); }
.ib-uni-sub .ib-uni-link.on { color: #001D5C; }
.ib-uni-sub .ib-uni-link.on::before { border-color: #001D5C; }
/* Active calculator link's branch, deep-teal on the porcelain rail (matches the text). */
.ib-uni-acc[data-ib-acc] > .ib-uni-acc-body > .ib-uni-acc-list > .ib-uni-link.on::before { border-color: #001D5C; }
.ib-uni-row { color: rgba(20,20,28,0.86); }
.ib-uni-row:hover { background: rgba(0,0,0,0.05); color: #001233; }
.ib-uni-row.on { color: #001D5C; background: rgba(var(--ib-teal-rgb),0.12); }
.ib-uni-nores { color: rgba(20,20,28,0.6); }
/* 0.55 (not 0.42): on the porcelain rail 0.42 measures ~3.2:1 for 11.5px text. */
.ib-uni-foot { border-top-color: rgba(0,0,0,0.09); }
.ib-uni-foot-a { color: rgba(20,20,28,0.55); }
.ib-uni-foot-a:hover { color: #001233; }
.ib-uni-prof-name { color: #1a1a1e; }
.ib-uni-prof-sub { color: rgba(20,20,28,0.55); }
.ib-uni-eyebrow { color: rgba(20,20,28,0.68); }
.ib-uni-card { background: #f8f8fb; border-color: rgba(0,0,0,0.10); box-shadow: none; }
.ib-uni-card-label { color: #1a1a1e; }
.ib-uni-card-meta { color: rgba(20,20,28,0.55); }
.ib-uni-card-chev { color: rgba(20,20,28,0.3); }
.ib-uni-card-nick { color: #001D5C; }
.ib-uni-card-chem { color: rgba(0,29,92,0.75); }
.ib-uni-card-dose { color: rgba(0,29,92,0.62); }
/* 0.7 alpha (not 0.55): composited over the white signin card this small text
   was 4.0:1 — just under WCAG AA 4.5:1. 0.7 measures ~6.7:1. */
.ib-uni-empty, .ib-uni-signin-sub { color: rgba(20,20,28,0.7); }
.ib-uni-signin-card { background: var(--ib-rail-card-grad); border: var(--ib-rail-card-border); }
.ib-uni-signin-title { color: #1a1a1e; }
/* Teal Deep (teal-press ramp): brand teal #0fbcad is ~2.2:1 on the white glass
   card — #001D5C measures ~5.5:1 for this 12px label. */
.ib-uni-signin-btn { color: #001D5C; }
/* + New protocol CTA: super-dark navy label on the porcelain rail (matches the
   TRT field headers), instead of the faint teal. */
.ib-uni-cta { color: #001233; }
.ib-uni-tab { color: rgba(20,20,28,0.72); background: rgba(250,250,252,0.92); border-color: rgba(0,0,0,0.12); }
.ib-uni-tab:hover { color: #001D5C; border-color: rgba(var(--ib-teal-rgb),0.5); }

/* ── Quick-edit popover (rename / recolour / delete a protocol) ───────────────────
   These 19 rules were a JavaScript string in ib-rail.js, injected into <head> as a
   <style> element by ensurePeStyle(). Same class names, same values, moved verbatim.
   app.js's in-calc protocol rail opens the same popover via window.__ibProtoEdit, so
   it consumes these too.
   Dark is the base here, matching the rest of this sheet. */
.ib-pe-back { position: fixed; inset: 0; z-index: 10050; background: rgba(0,0,0,0.55); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); display: flex; align-items: center; justify-content: center; padding: 20px; font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif; }
.ib-pe-card { width: 100%; max-width: 300px; background: #161618; border: 1px solid rgba(255,255,255,0.13); border-radius: 14px; box-shadow: 0 20px 60px rgba(0,0,0,0.5); padding: 18px; color: #fff; }
.ib-pe-card { background: #fff; border-color: rgba(0,0,0,0.1); color: #1a1a1e; }
.ib-pe-title { font-size: 14px; font-weight: 700; margin: 0 0 12px; }
.ib-pe-lbl { display: block; font-size: 10px; letter-spacing: 0.07em; text-transform: uppercase; opacity: 0.5; margin: 0 0 6px; }
/* Was style="margin-top:14px" on the colour label — the only spacing that differed. */
.ib-pe-lbl.is-spaced { margin-top: 14px; }
.ib-pe-input { width: 100%; box-sizing: border-box; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.16); border-radius: 8px; padding: 9px 11px; color: inherit; font-size: 14px; font-family: inherit; outline: none; }
.ib-pe-input { background: rgba(0,0,0,0.04); border-color: rgba(0,0,0,0.14); }
.ib-pe-input:focus { border-color: #0fbcad; }
.ib-pe-row { display: flex; gap: 8px; margin-top: 14px; }
.ib-pe-btn { flex: 1; border-radius: 8px; padding: 9px 12px; font-size: 13px; font-weight: 600; font-family: inherit; cursor: pointer; border: 1px solid transparent; }
.ib-pe-save { background: #0fbcad; color: #fff; }
.ib-pe-cancel { background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.16); color: inherit; }
.ib-pe-cancel { background: rgba(0,0,0,0.05); border-color: rgba(0,0,0,0.12); }
.ib-pe-del { margin-top: 10px; width: 100%; background: transparent; border: 1px solid rgba(248,113,113,0.4); color: #f87171; border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 600; font-family: inherit; cursor: pointer; }
.ib-pe-del.confirm { background: rgba(248,113,113,0.14); }

/* action menu (load / plotter / edit) */
.ib-pe-act { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.12); border-radius: 10px; padding: 12px 14px; margin-top: 8px; font-size: 14px; font-weight: 600; font-family: inherit; color: inherit; cursor: pointer; transition: background 0.14s, border-color 0.14s; }
.ib-pe-act:hover { background: rgba(15,188,173,0.12); border-color: rgba(15,188,173,0.4); }
.ib-pe-act { background: rgba(0,0,0,0.03); border-color: rgba(0,0,0,0.1); }
.ib-pe-act:hover { background: rgba(15,188,173,0.1); border-color: rgba(15,188,173,0.4); }
.ib-pe-act svg { width: 17px; height: 17px; flex-shrink: 0; opacity: 0.8; }

/* colour swatches (edit panel). The swatch colour is DATA — a --sw payload, not a
   background declaration; the sheet cannot know the palette entry a button carries. */
.ib-pe-sw { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 2px; }
.ib-pe-swatch { width: 24px; height: 24px; border-radius: 50%; border: none; cursor: pointer; padding: 0; outline: 2px solid transparent; outline-offset: 2px; transition: outline-color 0.12s; background: var(--sw); }
.ib-pe-swatch.sel { outline-color: #0fbcad; }

/* The protocol card's compound glyph takes its per-compound accent as a --cc payload,
   like .ib-uni-check does. It was style="color:<hex>". */
.ib-uni-ic { color: var(--cc); }

/* ═══════════ TOUCH TARGETS — 44px ═══════════════════════════════════════════════
   PRODUCT.md sets 44px on mobile. The rail is on every page, and none of its rows or
   controls met it — measured at 390px: .ib-uni-foot-a 13px (!), .ib-uni-link 28px,
   .ib-uni-headbtn 32px, .ib-uni-row 33px, .ib-uni-acc-hd / .ib-uni-filter /
   .ib-uni-search-in 34px, .ib-uni-burger / .ib-uni-mpfp 40px.

   The 188 guide links live inside collapsed accordions, so they are not tappable until
   opened — but they ARE rows in a scrolling drawer once they are, and a 44px row is the
   normal mobile pattern. The drawer gets taller; it already scrolls.

   NOT raised: inline links inside prose. Target-size rules exempt them, and inflating a link
   in the middle of a sentence would wreck the line box for no accessibility gain.

   min-height, never height: nothing already larger is shrunk. `pointer: coarse` = the primary
   input is a finger (a touchscreen laptop reports `fine`, so desktop is untouched). */
@media (pointer: coarse), (max-width: 767px) {
  .ib-uni-link,
  .ib-uni-row,
  .ib-uni-acc-hd,
  .ib-uni-foot-a { min-height: 44px; display: flex; align-items: center; }
  .ib-uni-headbtn,
  .ib-uni-filter { min-width: 44px; min-height: 44px; }
  /* .ib-uni-burger / .ib-uni-mpfp intentionally stay at their 40px base so the
     floating burger + avatar/EDIT pill are all the same size (per request). */
  .ib-uni-search-in { min-height: 44px; }
  .ib-uni-chip { min-height: 44px; }
}

/* ═════════════════════════════════════════════════════════════════════════════
   RIGHT-HAND "EDIT PROTOCOLS" RAIL (ib-erail.js)

   Folded into this shared rail sheet (was public/ib-erail.css) so both rails' styles
   live in one place — ib-rail.css is already loaded on every surface the edit rail can
   appear on (calculator pages + /account). Off-canvas: position:fixed + translateX(100%)
   until .open, so it never participates in layout — no gutter, no pre-paint gate, zero
   CLS. Fold tab + scrim are body-level siblings. Theme-aware (dark default; light is the
   design primary). z-index sits just above the account log drawer (.ib-lograil 600/601);
   a "one right panel at a time" bus keeps them from overlapping.
   ═════════════════════════════════════════════════════════════════════════════ */

/* ── fold tab — always attached to the rail's leading edge ─────────────────────────
   Closed: sits at the 36px collapsed strip's front (right:36px). Open: rides out to the
   panel's left edge (288px, see .ib-erail-open below). The `right` transition keeps it glued
   to the rail edge as it slides. */
.ib-erail-fold {
  position: fixed;
  right: 36px;
  /* Near the top, just below the sticky nav (48px) — no vertical-centre transform, so the
     tab never fights the button hover reaction (see .ib-no-lift on the element). */
  top: calc(var(--ib-nav-h, 48px) + 20px);
  z-index: 612;                      /* above the rail panel (611) so the peeking sliver never covers the fold */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 11px 7px;
  border: 1px solid rgba(255,255,255,0.08);
  border-right: none;
  border-radius: 9px 0 0 9px;
  /* The SAME opaque surface + hairline as the .ib-erail panel (no blur — the panel is
     opaque now), so the tab reads as a lug cut from the rail, not a separate floating
     pill. border-right:none drops the seam where it meets the panel's own left border. */
  background: #101013;
  color: rgba(255,255,255,0.82);
  cursor: pointer;
  font: 600 9.5px 'Inter', -apple-system, sans-serif;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  /* Shadow onto the PAGE only: offset left (−12) with a tight blur + negative spread so
     the penumbra can't reach back right across the panel when the rail is open. */
  box-shadow: -12px 0 16px -6px rgba(0,0,0,0.5);
  /* `right` is animated so the tab rides the panel's edge as it slides in/out (same
     duration + easing as the panel's transform), staying attached to the rail. */
  transition: right 0.28s cubic-bezier(0.4, 0, 0.2, 1), color 0.15s, background 0.15s;
}
/* Desktop: raise the tab to the same level as the left rail's collapse lug (.ib-uni-fold,
   top:12px) so both fold controls sit on one line. Mobile keeps the +20px-below-nav offset
   above — there is no left lug on mobile, and 12px would tuck under the mobile sticky nav. */
/* Desktop, every page: the fold sits at the very top and is compact — a small tab-height
   lug, not a tall pill. (Mobile keeps the larger below-nav fold in the base rule above.) */
@media (min-width: 1024px) {
  .ib-erail-fold { top: 0; padding: 4px 5px; gap: 2px; font-size: 7.5px; letter-spacing: -0.3px; }
  .ib-erail-fold svg { width: 12px; height: 12px; }
}
/* Hover lights the label/icon, never the surface — the fill stays the rail's, so the seam
   the lug hides doesn't reappear on hover. The pencil also wobbles on mouse-over. */
/* Same hover treatment as the left rail's fold lug: icon wobbles + tints to the brand
   accent, no glow/shadow. (#6d8cff dark / #001D5C light — the .ib-uni-fold accents.) */
.ib-erail-fold:hover { color: #6d8cff; }
.ib-erail-fold:hover svg { animation: ib-erail-pencil-wobble 0.6s ease infinite; }
@media (prefers-reduced-motion: reduce) { .ib-erail-fold:hover svg { animation: none; } }
.ib-erail-fold-lbl { writing-mode: vertical-rl; transform: rotate(180deg); }
.ib-erail-fold {
  /* Pure white on light pages — the fill plus a very faint border/shadow so the small pill
     doesn't read grey. */
  background: #ffffff;
  border-color: rgba(0,0,0,0.05);
  color: #2a2a30;
  box-shadow: -8px 0 14px -8px rgba(0,0,0,0.08);
}
.ib-erail-fold:hover { color: #001D5C; }
/* Hidden while the panel is open. */
/* Open: the tab stays attached — it rides out to the panel's left edge instead of hiding,
   so it's always a visible handle (a click toggles the rail shut). Panel is 288px wide
   (340px under 1024px), so the tab sits exactly at its outer edge. */
.ib-erail-open .ib-erail-fold { right: min(288px, 100vw); }
@media (max-width: 1023px) { .ib-erail-open .ib-erail-fold { right: min(340px, 100vw); } }

/* ── scrim ──────────────────────────────────────────────────────────────────────── */
.ib-erail-scrim {
  position: fixed;
  inset: 0;
  z-index: 610;
  background: rgba(8,8,10,0.42);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.26s;
}
.ib-erail-scrim.open { opacity: 1; pointer-events: auto; }
/* Desktop: the panel slides over content but the page stays readable/scrollable beside
   it, so no scrim there (mirrors the plotter EditRail's desktop behaviour). */
@media (min-width: 1024px) { .ib-erail-scrim { display: none; } }

/* ── the panel ──────────────────────────────────────────────────────────────────── */
.ib-erail {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 611;
  width: min(288px, 100vw);
  display: flex;
  flex-direction: column;
  /* Not fully off-canvas: when shut, a 36px strip stays out — the collapsed icon rail (one
     small teal initials badge per card; see the .ib-erail:not(.open) block below). Opening
     slides the full panel in. */
  transform: translateX(calc(100% - 36px));
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  border-left: 1px solid rgba(255,255,255,0.08);
  /* Opaque, NO backdrop-filter: the panel is a fixed, transform-animated layer, and a
     backdrop blur on it forced the whole subtree (cards, text, syringe) into a composited
     bitmap that downsampled on HiDPI — that was the "pixelated" look. The background was
     already 92% opaque, so the glass was barely visible; solid fixes the blur outright. */
  background: #101013;
  color: rgba(255,255,255,0.92);
  box-shadow: -6px 0 22px -2px rgba(0,0,0,0.5);
  --erail-line: rgba(255,255,255,0.1);
  --erail-mut: rgba(255,255,255,0.52);
  --erail-inp-bg: rgba(255,255,255,0.05);
}
.ib-erail.open { transform: translateX(0); }
@media (max-width: 1023px) {
  .ib-erail { width: min(340px, 100vw); }
  /* Mobile: no peeking strip — the panel folds fully off-canvas when shut. */
  .ib-erail:not(.open) { transform: translateX(100%); }

  /* The top-right profile avatar is replaced by an EDIT button that opens this rail. Hide the
     avatar and reshape the erail fold into a top-right corner pill — the burger's twin in the
     opposite corner (drop the vertical "EDIT" label; the pencil alone reads as the button,
     matching the hamburger). */
  html.ib-rail-live.ib-erail-live .ib-uni-mpfp { display: none; }
  .ib-erail-fold {
    top: 2px; right: 10px;
    width: 40px; height: 40px; padding: 0; gap: 0;
    border-radius: 10px;
    border: 1px solid rgba(255,255,255,0.1);
    background: rgba(20,20,23,0.85);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    color: var(--ib-fg);
    box-shadow: none;
    transition: transform 0.28s ease, opacity 0.28s ease;
  }
  .ib-erail-fold svg { width: 20px; height: 20px; }
  .ib-erail-fold-lbl { display: none; }
  .ib-erail-fold { background: rgba(250,250,252,0.92); border-color: rgba(0,0,0,0.12); color: #1a1a1e; box-shadow: none; }
  /* Open: the drawer's own X + scrim close it, so the corner pill steps out of the way. */
  html.ib-erail-open .ib-erail-fold { display: none; }
  /* Auto-hides on scroll, like the burger it now pairs with. */
  html.ib-nav-hidden .ib-erail-fold { opacity: 0; transform: translateY(-160%); pointer-events: none; }
}
.ib-erail {
  border-left-color: rgba(0,0,0,0.1);
  background: #f9f9fb;
  color: #1a1a20;
  box-shadow: -6px 0 20px -2px rgba(0,0,0,0.20);
  --erail-line: rgba(0,0,0,0.1);
  --erail-mut: rgba(20,20,28,0.55);
  --erail-inp-bg: rgba(0,0,0,0.03);
}

/* header */
.ib-erail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 16px 13px;
  border-bottom: 1px solid var(--erail-line);
  flex: 0 0 auto;
}
.ib-erail-title { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.ib-erail-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: none; border-radius: 8px;
  background: none; color: var(--erail-mut); cursor: pointer;
}
.ib-erail-x:hover { background: var(--erail-inp-bg); color: inherit; }

.ib-erail-scroll { flex: 1 1 auto; overflow-y: auto; padding: 14px 16px 32px; }

.ib-erail-eyebrow {
  font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--erail-mut); margin: 2px 0 12px;
}
.ib-erail-empty { font-size: 13px; line-height: 1.5; color: var(--erail-mut); margin-bottom: 14px; }

/* signed-out CTA */
.ib-erail-signin {
  display: block; text-decoration: none; color: inherit;
  padding: 16px; border-radius: 13px;
  border: 1px solid var(--erail-line); background: var(--erail-inp-bg);
}
.ib-erail-signin-t { font-size: 15px; font-weight: 700; margin-bottom: 5px; }
.ib-erail-signin-s { font-size: 12.5px; line-height: 1.45; color: var(--erail-mut); margin-bottom: 12px; }
.ib-erail-signin-btn {
  display: inline-block; padding: 8px 15px; border-radius: 8px;
  background: #0fbcad; color: #04211f; font-size: 12.5px; font-weight: 700;
}

/* ── protocol cards ─────────────────────────────────────────────────────────────── */
.ib-erail-list { display: flex; flex-direction: column; gap: 9px; }
/* Editor cards wear the universal rail's saved-dose card look (.ib-uni-card): a recessed
   grey well (lighter than the rail), a sideways category strip, 3-tier navy body text and
   the angled syringe on the right. The card head reuses the .ib-uni-* classes so the two
   rails render identically; only the well + interaction states are restated here because
   the head is a <button> that expands rather than a bare link. */
.ib-erail-card {
  /* Card shape aligned to the cycle-plotter card (.cp-erail-card): 8px radius, 1px hairline
     and a soft lift shadow (shows on the light rail; invisibly subtle on the dark one). */
  position: relative;
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 8px;
  background: #27272e;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20,20,28,0.06), 0 4px 12px -5px rgba(20,20,28,0.16);
  transition: transform 0.14s ease, border-color 0.16s ease, box-shadow 0.18s ease, background 0.16s ease;
}
.ib-erail-card { background: #ffffff; border-color: rgba(0,0,0,0.10); }
/* The sideways category strip is filled in the card's own compound colour (the same colour
   as the syringe), with black label text on top. */
.ib-erail-card .ib-uni-cat { background: var(--c); }
.ib-erail-card .ib-uni-cat > span { color: #000; }
/* Match the plotter card's slightly smaller syringe. */
.ib-erail-card .ib-uni-ic { width: 26px; height: 26px; }
.ib-erail-card .ib-uni-ic svg { width: 22px; height: 22px; }
/* Hover (collapsed cards): the whole card lifts and scales, while the compound-colour
   border supplies the state change without a glow. */
.ib-erail-card:not(.is-open):hover {
  background: #1e1e24; border-color: var(--c);
  transform: scale(1.1); z-index: 2;
  box-shadow: 0 1px 2px rgba(20,20,28,0.06), 0 4px 12px -5px rgba(20,20,28,0.16);
}
.ib-erail-card:not(.is-open):hover { background: #e7e7ee; }
/* Open card = a clean form. The collapsed-state chrome — the sideways category strip, the
   condensed nickname/chem/dose summary and the syringe — is all for the collapsed card, so it is
   hidden here; the head shrinks to just the collapse chevron in the top-right and the form fills
   the container from the top. The whole container border then wears the compound's own colour —
   the identity the strip carried while collapsed — so an open card is still read at a glance. */
.ib-erail-card.is-open { border-color: var(--c); }
/* Open cards retain the slight scale response but do not glow on hover. */
.ib-erail-card.is-open:hover {
  transform: scale(1.02); z-index: 2;
  box-shadow: 0 1px 2px rgba(20,20,28,0.06), 0 4px 12px -5px rgba(20,20,28,0.16);
}
.ib-erail-card.is-open .ib-uni-cat,
.ib-erail-card.is-open .ib-uni-card-body,
.ib-erail-card.is-open .ib-uni-ic { display: none; }
/* Open card: the collapse chevron becomes a 44px tap target pinned to the top-right
   corner and taken OUT of flow, so the form (Nick Name first) sits right at the top
   with no wasted header band. */
.ib-erail-card.is-open .ib-erail-card-head {
  position: absolute; top: 0; right: 0; z-index: 3;
  width: 44px; height: 44px; min-height: 0;
  padding: 0; gap: 0; justify-content: center; align-items: center;
}
.ib-erail-card.is-open .ib-erail-card-chev { width: 22px; height: 22px; }
.ib-erail-card.is-open .ib-erail-card-chev svg { width: 22px; height: 22px; }
.ib-erail-card.is-open .ib-erail-card-body { border-top: none; margin-top: 0; padding-top: 8px; position: relative; }
/* Keep the first field (Nick Name) clear of the corner chevron. Only cards that HAVE a
   head chevron ([data-erail-cardid] protocol / [data-vial-cardid] vial) — not the
   headless add-vial card. */
.ib-erail-card[data-erail-cardid].is-open .ib-erail-card-body > .ib-erail-field:first-child,
.ib-erail-card[data-vial-cardid].is-open .ib-erail-card-body > .ib-erail-field:first-child { padding-right: 44px; }
/* Open protocol cards keep the collapsed strip's colour as a full-height bar on the left
   (minus the rotated tag text) so the identity "line" continues all the way down. Scoped
   to protocol cards ([data-erail-cardid]) — vial + add-vial cards have no category strip. */
.ib-erail-card[data-erail-cardid].is-open::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 21px;
  background: var(--c);
  border-right: 1px solid rgba(0,0,0,0.16);
  /* Shadow falls onto the white card interior to the right of the stripe (the stripe
     itself stays flat), giving the interior a recessed inner-shadow edge. */
  box-shadow: 4px 0 8px rgba(0,0,0,0.32);
  pointer-events: none;
}
/* Push the form clear of the bar so fields never sit under it. */
.ib-erail-card[data-erail-cardid].is-open .ib-erail-card-body { padding-left: 31px; }
/* Collapsed hover spins the syringe to face right. */
@media (hover: hover) { .ib-erail-card:not(.is-open):hover .ib-uni-ic { transform: rotate(135deg); } }
.ib-erail-card-head {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 11px 12px; border: none; background: none; color: inherit;
  cursor: pointer; text-align: left;
}
/* Collapsed chevron: a 26px box / 21px glyph on the LEFT (matches the cycle-plotter card). */
.ib-erail-card-chev {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--erail-mut); flex: 0 0 auto;
  width: 26px; height: 26px; border-radius: 7px;
  transition: transform 0.2s, background 0.15s ease;
}
.ib-erail-card-chev svg { width: 21px; height: 21px; }
.ib-erail-card:not(.is-open):hover .ib-erail-card-chev { background: var(--erail-inp-bg); }
.ib-erail-card.is-open .ib-erail-card-chev { transform: rotate(180deg); }

/* ── Round initials badge — the COLLAPSED card's icon (e.g. "TP"). Hidden in the open rail;
   shown centred in the ~54px collapsed strip. White fill + the compound colour (var(--c) on
   the card) as ring/text so it stays legible on any compound colour. ─────────────────────── */
.ib-erail-abbr {
  display: none;
  flex: 0 0 auto;
  width: 22px; height: 22px; border-radius: 50%;
  align-items: center; justify-content: center;
  background: #ffffff;
  /* All teal, regardless of compound colour. */
  border: 1.5px solid #0fbcad;
  color: #0a7d73;
  font: 800 7.5px 'Inter', -apple-system, sans-serif;
  letter-spacing: 0.01em;
  box-shadow: 0 1px 3px rgba(0,0,0,0.16);
}

/* ── Collapsed rail = the slim icon strip. Hide the header + every card part EXCEPT the round
   badge, which centres in the strip. The full panel slides in on open (see .ib-erail.open). */
.ib-erail:not(.open) .ib-erail-head { display: none; }
.ib-erail:not(.open) .ib-erail-scroll { width: 36px; padding: 8px 0 16px; overflow-x: hidden; scrollbar-width: none; }
.ib-erail:not(.open) .ib-erail-scroll::-webkit-scrollbar { display: none; }
.ib-erail:not(.open) .ib-erail-card { margin-bottom: 6px; }
.ib-erail:not(.open) .ib-erail-card-head { padding: 5px 0; gap: 0; justify-content: center; }
.ib-erail:not(.open) .ib-uni-cat,
.ib-erail:not(.open) .ib-uni-card-body,
.ib-erail:not(.open) .ib-uni-ic,
.ib-erail:not(.open) .ib-erail-card-chev,
.ib-erail:not(.open) .ib-erail-card-body { display: none; }
.ib-erail:not(.open) .ib-erail-abbr { display: flex; margin: 0 auto; }
/* The folded rail keeps a teal hover border, without a glow. */
.ib-erail:not(.open) .ib-erail-card:hover { border-color: #0fbcad; transform: none; box-shadow: 0 1px 2px rgba(20,20,28,0.06), 0 4px 12px -5px rgba(20,20,28,0.16); }
.ib-erail-card-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.ib-erail-card-titles { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.ib-erail-card-name { font-size: 13.5px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ib-erail-card-sum { font-size: 11.5px; color: var(--erail-mut); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── card body / fields ─────────────────────────────────────────────────────────── */
.ib-erail-card-body {
  display: flex; flex-direction: column; gap: 11px;
  padding: 4px 12px 14px;
  border-top: 1px solid var(--erail-line);
  margin-top: 2px;
}
.ib-erail-field { display: flex; flex-direction: column; gap: 5px; }
.ib-erail-lbl {
  font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--erail-mut);
}
.ib-erail-inp {
  width: 100%; box-sizing: border-box;
  padding: 9px 11px; border-radius: 8px;
  border: 1px solid var(--erail-line);
  background: var(--erail-inp-bg);
  color: inherit; font: 500 14px 'Inter', -apple-system, sans-serif;
  outline: none;
}
.ib-erail-inp:focus { border-color: #0fbcad; }
select.ib-erail-inp { cursor: pointer; -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; padding-right: 30px;
}
.ib-erail-inp[type="date"] { color-scheme: dark; }
.ib-erail-inp[type="date"] { color-scheme: light; }

/* number + trailing unit inside the box */
.ib-erail-numwrap { position: relative; display: block; }
.ib-erail-num { padding-right: 54px; -moz-appearance: textfield; }
.ib-erail-num::-webkit-outer-spin-button,
.ib-erail-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ib-erail-unit {
  position: absolute; right: 11px; top: 50%; transform: translateY(-50%);
  font-size: 12px; font-weight: 600; color: var(--erail-mut); pointer-events: none;
}

/* active switch + start date share a row; labels sit on top of each (flex-start). */
.ib-erail-row2 { display: flex; align-items: flex-start; gap: 10px; }
.ib-erail-active { flex: 0 0 auto; }
/* min-width:0 lets the date field shrink below the native date input's intrinsic
   width — without it the picker overflows the card on the right. */
.ib-erail-date { flex: 1 1 auto; min-width: 0; }
.ib-erail-inp[type="date"] { min-width: 0; max-width: 100%; }
/* iOS-style sliding switch: a pill track with a knob that slides right when on. */
.ib-erail-toggle {
  position: relative; align-self: flex-start; flex: 0 0 auto;
  width: 46px; height: 26px; padding: 0;
  border-radius: 999px;
  border: 1px solid var(--erail-line); background: var(--erail-inp-bg);
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.ib-erail-toggle-dot {
  position: absolute; top: 50%; left: 3px; transform: translateY(-50%);
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--erail-mut);
  transition: transform 0.18s ease, background 0.18s ease;
}
.ib-erail-toggle.on { border-color: #0fbcad; background: #0fbcad; }
.ib-erail-toggle.on .ib-erail-toggle-dot { background: #fff; transform: translate(20px, -50%); }

.ib-erail-note {
  font-size: 11.5px; line-height: 1.45; color: var(--erail-mut);
  padding: 8px 10px; border-radius: 8px; background: var(--erail-inp-bg);
}
.ib-erail-open {
  display: inline-block; margin-top: 2px;
  font-size: 12.5px; font-weight: 600; color: #0fbcad; text-decoration: none;
  /* Button-safe resets so the same class looks identical on <a> and <button>. */
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: inherit; text-align: left;
}
.ib-erail-open:hover { text-decoration: underline; }

/* "Edit in calculator" — the navy conversion-CTA style (matches the calc Save CTA:
   deep navy #001D5C, white label), full width at the bottom of an open calc-page card. */
.ib-erail-editcta {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; margin-top: 6px;
  height: 40px; padding: 0 16px;
  background: #001D5C; border: 1px solid #001D5C; border-radius: 6px;
  color: #fff; cursor: pointer;
  font: 600 13px 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: -0.01em;
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.ib-erail-editcta:hover { background: #0e3893; border-color: #0e3893; box-shadow: 0 4px 14px -4px rgba(0,29,92,0.6); }
.ib-erail-editcta:active { transform: scale(0.99); }

/* ── vial-editor mode ───────────────────────────────────────────────────────────── */
/* colour swatches */
.ib-erail-swatches { display: flex; flex-wrap: wrap; gap: 7px; }
.ib-erail-swatch {
  width: 24px; height: 24px; border-radius: 50%; border: 2px solid transparent;
  cursor: pointer; padding: 0; outline: none; box-shadow: 0 0 0 1px var(--erail-line);
}
.ib-erail-swatch.on { border-color: var(--erail-inp-bg); box-shadow: 0 0 0 2px currentColor; }
.ib-erail-swatch:focus-visible { box-shadow: 0 0 0 2px #0fbcad; }

/* Compact colour trigger — current colour + chevron; opens the floating popover below. */
.ib-erail-colorbtn {
  display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
  padding: 6px 10px; border-radius: 8px;
  border: 1px solid var(--erail-line); background: var(--erail-inp-bg);
  color: var(--erail-mut); cursor: pointer;
}
.ib-erail-colorbtn-dot { width: 18px; height: 18px; border-radius: 50%; box-shadow: 0 0 0 1px var(--erail-line); }
.ib-erail-colorbtn-chev { display: inline-flex; width: 13px; height: 13px; }
.ib-erail-colorbtn-chev svg { width: 13px; height: 13px; }
/* Floating swatch popover (appended to <body>). */
.ib-erail-colorpop {
  position: fixed; z-index: 100000;
  padding: 10px; border-radius: 10px;
  background: #27272e; border: 1px solid rgba(255,255,255,0.1);
  box-shadow: 0 12px 32px rgba(0,0,0,0.5);
}
.ib-erail-colorpop {
  background: #fff; border-color: rgba(0,0,0,0.12);
  box-shadow: 0 12px 32px rgba(0,0,0,0.22);
}
.ib-erail-colorpop .ib-erail-swatches { width: 132px; }

/* vials-on-hand stepper */
.ib-erail-stepper { display: flex; align-items: stretch; gap: 0; }
.ib-erail-step {
  width: 38px; flex: 0 0 auto; border: 1px solid var(--erail-line); background: var(--erail-inp-bg);
  color: inherit; font-size: 18px; line-height: 1; cursor: pointer;
}
.ib-erail-step:first-of-type { border-radius: 8px 0 0 8px; border-right: none; }
.ib-erail-step:last-of-type { border-radius: 0 8px 8px 0; border-left: none; }
.ib-erail-stepnum { border-radius: 0 !important; text-align: center; -moz-appearance: textfield; min-width: 0; }
.ib-erail-stepnum::-webkit-outer-spin-button,
.ib-erail-stepnum::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* remaining readout */
.ib-erail-remain {
  font-size: 12.5px; color: var(--erail-mut);
  padding: 10px 12px; border-radius: 9px; background: var(--erail-inp-bg); border: 1px solid var(--erail-line);
}
.ib-erail-remain-big { font-size: 16px; font-weight: 700; color: rgba(255,255,255,0.92); }
.ib-erail-remain-big { color: #1a1a20; }

/* pull history */
.ib-erail-pulls { border-top: 1px solid var(--erail-line); padding-top: 10px; }
.ib-erail-pulls-h { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--erail-mut); margin-bottom: 7px; }
.ib-erail-pulls-note { font-size: 12px; color: var(--erail-mut); }
.ib-erail-pull-list { display: flex; flex-direction: column; gap: 4px; max-height: 168px; overflow-y: auto; }
.ib-erail-pull { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; }
.ib-erail-pull-d { font-variant-numeric: tabular-nums; min-width: 92px; }
.ib-erail-pull-m { color: var(--erail-mut); min-width: 54px; }
.ib-erail-pull-s { color: var(--erail-mut); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* remove + add + save/cancel */
.ib-erail-remove {
  align-self: flex-start; margin-top: 2px; padding: 7px 12px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, #f87171 45%, transparent); background: none;
  color: #ef5f5f; font-size: 12px; font-weight: 600; cursor: pointer;
}
.ib-erail-remove:hover { background: rgba(248,113,113,0.1); }
.ib-erail-addcard {
  display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 9px;
  padding: 12px; border-radius: 12px; border: 1px dashed var(--erail-line); background: none;
  color: var(--erail-mut); font-size: 13px; font-weight: 600; cursor: pointer;
}
.ib-erail-addcard:hover { color: inherit; border-color: color-mix(in srgb, #0fbcad 50%, transparent); }
.ib-erail-addplus { font-size: 17px; line-height: 1; }
.ib-erail-addbtns { display: flex; gap: 8px; margin-top: 2px; }
.ib-erail-savebtn {
  padding: 9px 15px; border-radius: 8px; border: none; background: #0fbcad; color: #04211f;
  font-size: 13px; font-weight: 700; cursor: pointer;
}
.ib-erail-cancelbtn {
  padding: 9px 13px; border-radius: 8px; border: 1px solid var(--erail-line); background: none;
  color: var(--erail-mut); font-size: 13px; cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .ib-erail, .ib-erail-scrim, .ib-erail-card-chev { transition: none; }
}

/* ── Shared rail-card cell sizing (BOTH rails) ──────────────────────────────────────
   One height for every input cell in either the Edit-protocols rail (.ib-erail-*) or the
   cycle-plotter rail (.cp-erail-*, which loads this same injected sheet), so the two cannot
   drift: 44px on mobile/touch, 38px on desktop, with the vertical padding stripped so the value
   sits centred. The cycle-plotter sheet reads the very same --ib-railcell-h. */
:root { --ib-railcell-h: 44px; }
@media (min-width: 1024px) { :root { --ib-railcell-h: 38px; } }
.ib-erail-inp,
.ib-erail-step, .ib-erail-stepnum,
.ib-erail-remove,
.ib-erail-savebtn, .ib-erail-cancelbtn { height: var(--ib-railcell-h); padding-top: 0; padding-bottom: 0; }

/* ── Desktop: a denser card interior (operator) ─────────────────────────────────────
   The cell HEIGHT is the shared value above; on desktop the summary text and the spacing tighten
   too. Scoped to .ib-erail-card so the left-hand universal rail (shared .ib-uni-* classes) is
   untouched. */
@media (min-width: 1024px) {
  .ib-erail-card-head { padding: 7px 9px; gap: 8px; }
  .ib-erail-card .ib-uni-card-nick { font-size: 12px; }
  .ib-erail-card .ib-uni-card-chem { font-size: 9.5px; }
  .ib-erail-card .ib-uni-card-dose { font-size: 9.5px; }
  .ib-erail-card .ib-uni-ic { width: 24px; height: 24px; }
  .ib-erail-card .ib-uni-ic svg { width: 20px; height: 20px; }
  .ib-erail-card .ib-uni-cat { width: 17px; }
  .ib-erail-card .ib-uni-cat > span { font-size: 7.5px; }
  /* Desktop strip is 17px → match the open card's left identity bar + form offset. */
  .ib-erail-card[data-erail-cardid].is-open::before { width: 17px; }
  .ib-erail-card[data-erail-cardid].is-open .ib-erail-card-body { padding-left: 25px; }

  .ib-erail-card-body { gap: 8px; padding: 3px 9px 11px; }
  .ib-erail-field { gap: 4px; }
  .ib-erail-lbl { font-size: 9.5px; }
  .ib-erail-inp { padding-left: 10px; padding-right: 10px; border-radius: 7px; font-size: 13px; }
  select.ib-erail-inp { background-position: right 9px center; padding-right: 26px; }
  .ib-erail-num { padding-right: 46px; }
  .ib-erail-unit { font-size: 11px; right: 10px; }
  .ib-erail-row2 { gap: 8px; }
  .ib-erail-note { font-size: 10.5px; padding: 6px 9px; }
  .ib-erail-open { font-size: 11.5px; }

  .ib-erail-swatch { width: 21px; height: 21px; }
  .ib-erail-step { width: 38px; font-size: 15px; }
  .ib-erail-remain { font-size: 11.5px; padding: 8px 10px; }
  .ib-erail-remain-big { font-size: 14px; }
  .ib-erail-pulls-h { font-size: 10px; }
  .ib-erail-pull { font-size: 11.5px; }
  .ib-erail-pull-d { min-width: 82px; }
  .ib-erail-remove { padding-left: 12px; padding-right: 12px; font-size: 11px; }
  .ib-erail-savebtn, .ib-erail-cancelbtn { padding-left: 14px; padding-right: 14px; font-size: 12px; }
}

/* ── Calculator/dashboard Editor parity with the Cycle Plotter ───────────────
   The two editors keep their own markup and open-form controls, but the rail shell and
   COLLAPSED protocol summaries now share the plotter's geometry. The desktop zoom is the
   plotter's exact 320px × .75 treatment (240px rendered). Open-card form rules above remain
   untouched; only the rail scale naturally applies to them as part of the shell. */
@media (min-width: 1024px) {
  .ib-erail {
    width: 320px;
    zoom: 0.75;
    background: rgba(255,255,255,0.94);
    border-left-color: rgba(0,0,0,0.10);
    box-shadow: -18px 0 40px -14px rgba(20,20,28,0.20);
  }
  .ib-erail-fold { right: 27px; }
  .ib-erail-open .ib-erail-fold { right: 240px; }

  .ib-erail-head { padding: 14px 16px; }
  .ib-erail-title { font-size: 14px; letter-spacing: 0; }
  .ib-erail-scroll { padding: 14px 16px 20px; }

  .ib-erail-card:not(.is-open) {
    padding: 6px 10px;
    background: #fff;
    border-color: var(--erail-line);
    box-shadow: 0 1px 2px rgba(20,20,28,0.06), 0 4px 12px -5px rgba(20,20,28,0.16);
  }
  .ib-erail-card:not(.is-open) .ib-erail-card-head {
    min-height: 44px;
    padding: 0;
    gap: 7px;
  }
  .ib-erail-card:not(.is-open) .ib-uni-cat {
    margin: -6px 3px -6px -10px;
    width: 21px;
  }
  .ib-erail-card:not(.is-open) .ib-uni-card-nick,
  .ib-erail-card:not(.is-open) .ib-erail-card-name { font-size: 13px; font-weight: 700; }
  .ib-erail-card:not(.is-open) .ib-uni-card-chem,
  .ib-erail-card:not(.is-open) .ib-uni-card-dose,
  .ib-erail-card:not(.is-open) .ib-erail-card-sum { font-size: 11px; }
  .ib-erail-card:not(.is-open) .ib-uni-ic { width: 26px; height: 26px; }
  .ib-erail-card:not(.is-open) .ib-uni-ic svg { width: 22px; height: 22px; }
  .ib-erail-card:not(.is-open):hover {
    background: #fff;
    border-color: var(--c);
    transform: scale(1.02);
  }
}

/* (The per-page fold sizing that used to live here is now merged into the global base rules
   above — the folds render identically on every page.) */

/* ── Profile hover popup: a Log out button under the rail profile row ───────────────────
   .ib-uni-prof-wrap is the hover target and the flex:1 item in .ib-uni-id, so the profile
   still fills the row beside the gear. The menu opens downward on hover/focus; a transparent
   padding-top bridges the gap so the pointer reaches the button without the menu closing. */
.ib-uni-prof-wrap { position: relative; min-width: 0; display: flex; }
.ib-uni-id .ib-uni-prof-wrap { flex: 1; }
.ib-uni-prof-menu {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 60;
  min-width: 150px; padding-top: 6px;
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
  pointer-events: none;
}
.ib-uni-prof-wrap:hover .ib-uni-prof-menu,
.ib-uni-prof-wrap:focus-within .ib-uni-prof-menu {
  opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto;
}
.ib-uni-prof-logout {
  display: flex; align-items: center; gap: 9px; width: 100%; box-sizing: border-box;
  padding: 10px 12px; border-radius: 10px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600; text-align: left;
  color: #ff6b6b; background: rgba(22,22,26,0.98);
  border: 1px solid rgba(255,255,255,0.1);
  box-shadow: 0 10px 28px rgba(0,0,0,0.34);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: background .14s ease, border-color .14s ease, transform .1s ease;
}
.ib-uni-prof-logout svg { width: 17px; height: 17px; flex-shrink: 0; }
.ib-uni-prof-logout:hover { background: rgba(229,72,77,0.16); border-color: rgba(229,72,77,0.5); }
.ib-uni-prof-logout:active { transform: scale(0.98); }
/* Mini (collapsed desktop) rail: the id row is centred + column, so don't let the wrapper
   grow, and centre the popup under the avatar. */
html.ib-rail-mini .ib-uni-prof-wrap { flex: 0 0 auto; }
html.ib-rail-mini .ib-uni-prof-menu { left: 50%; right: auto; transform: translate(-50%, -4px); }
html.ib-rail-mini .ib-uni-prof-wrap:hover .ib-uni-prof-menu,
html.ib-rail-mini .ib-uni-prof-wrap:focus-within .ib-uni-prof-menu { transform: translate(-50%, 0); }
/* Light theme */
.ib-uni-prof-logout {
  color: #d13438; background: #ffffff;
  border-color: rgba(0,0,0,0.12); box-shadow: 0 10px 28px rgba(0,0,0,0.16);
}
.ib-uni-prof-logout:hover { background: rgba(209,52,56,0.08); border-color: rgba(209,52,56,0.4); }
