/* ── /blog/ SIDELOAD — the drawer chrome (light DOM) ───────────────────────
   Niko, 2026-07-31: *"the sideloader is not working AT ALL"*, then — of the
   first attempt — *"100% not back"*. The mechanism was right and the LOOK was
   wrong: a full-width panel that took the list's place in the flow is visually
   indistinguishable from a normal navigation, so the feature read as missing.

   THIS IS THE ORIGINAL PRE-PHASE-4 READER, restored: a drawer that slides in
   from the RIGHT over the still-visible, dimmed, blurred list. Recovered
   verbatim from `git show 9300cba^:blog/index.html` (.reader-bg / .reader /
   .reader-header, lines 525–560, mobile override ~897) and renamed to the
   sl- prefix. Every value below is that file's value.

   Token check (all present, nothing substituted):
     --bg-elevated, --border, --text-dim  → /assets/site.css (theme blocks)
     --orange, --orange-subtle,
     --ease-out-expo, --spring            → blog/index.html :root

   The contract is unchanged:
     JS off / crawler  → the card is an <a href="/article/<slug>">, nothing here
                         ever runs, and /blog/ is byte-identical to what it was.
     JS on             → assets/blog-sideload.js intercepts the click, fetches
                         that same URL, and slides the article in.

   The ARTICLE's own styling is NOT here and must never be copied here: the
   article subtree is mounted in a shadow root together with the <style> block
   the /article/<slug> page itself shipped, so the drawer inherits whatever that
   page renders today. See the bridge comment in blog-sideload.js.
   ──────────────────────────────────────────────────────────────────────── */

/* ── The scrim ────────────────────────────────────────────────────────────
   The list stays in the document, visible, dimmed and blurred behind this.
   It is NEVER display:none — seeing the list you came from is the whole
   difference between a drawer and a page load. Clicking it closes, through
   history.back() like every other way out. */
.sl-bg {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(0,0,0,0.6);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease;
  cursor: pointer;
}
.sl-bg.open { opacity: 1; pointer-events: auto; }

/* ── The drawer ───────────────────────────────────────────────────────────
   z-index 201 clears the fixed site nav (z-index 50, its open burger menu 60),
   so the drawer is genuinely on top of the page rather than inside it. */
.sl-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 201;
  width: min(660px, 100vw);
  background: var(--bg-elevated);
  transform: translateX(100%);
  transition: transform 0.45s var(--ease-out-expo), background-color 0.4s;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* The drawer is its own scrolling surface; a flick past its end must not
     hand the scroll to the list underneath. */
  overscroll-behavior: contain;
  box-shadow: -24px 0 60px rgba(0,0,0,0.28);
}
.sl-drawer.open { transform: translateX(0); }
.sl-drawer:focus { outline: none; }
.sl-drawer:focus-visible { outline: 2px solid var(--orange); outline-offset: -4px; }

/* ── The header — sticky, blurred, and the reader's whole control surface ──
   Left to right, exactly the original bar (9300cba^ :1115-1135):

     [ progress ][ N min left ]              [ A− ][ A+ ][ Share ▾ ][ ✕ ]

   Niko, after using the live drawer: *"there is no completeness progress bar or
   estimated reading time. none of the features in the original sideloader. i
   want it exactly like it was!"*. Every rule below is that file's rule — the
   header itself (:546-553), its round 36px buttons (:554-564), the share pill
   (:568-585) and the progress group (:587-606) — renamed to the sl- prefix.

   The Share control is NOT reimplemented here: /assets/share.css owns the
   component and /assets/share.js owns the behaviour (menu toggle, copy, native
   sheet, auto-hiding Share… where navigator.share is absent). This file only
   supplies PLACEMENT, which is what share.css's own comment says a page may do
   — the same move the books overlay makes with .bo-share-top. */
.sl-header {
  position: sticky; top: 0; z-index: 5;
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px;
  padding: 14px 24px;
  padding-top: max(14px, env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg-elevated) 92%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  transition: background 0.3s;
  /* The status line is a full-width child on its own row; it is `hidden` until
     the print button has something to say, so the bar is one row in the state
     the reader normally sees it in. */
  flex-wrap: wrap;
}
.sl-actions { display: flex; align-items: center; gap: 8px; flex: none; }

/* The round buttons — close and the two type controls share one chrome, as
   `.reader-header button` did. */
.sl-close, .sl-type {
  background: var(--orange-subtle); border: none;
  color: var(--text); width: 36px; height: 36px;
  border-radius: 50%; font-size: 1.1rem;
  cursor: pointer; transition: all 0.2s var(--spring);
  display: flex; align-items: center; justify-content: center;
  flex: none;
  font-family: inherit; line-height: 1;
}
.sl-close:hover, .sl-type:hover { background: var(--orange); color: #000; transform: scale(1.08); }
.sl-close:focus-visible, .sl-type:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.sl-type { font-size: 0.9rem; font-weight: 700; }
/* A -/+ that cannot move any further says so instead of pretending. */
.sl-type[disabled] { opacity: 0.4; cursor: default; }
.sl-type[disabled]:hover { background: var(--orange-subtle); color: var(--text); transform: none; }

/* Share — the shared .share-btn base reset from a round overlay pin to a
   labelled pill in a header bar. Placement only; no colour, icon or behaviour
   is restated. */
.sl-share.share-btn {
  position: static; inset: auto; z-index: auto;
  width: auto; height: 36px; padding: 0 14px; gap: 7px; border-radius: 999px;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  background: var(--orange-subtle); color: var(--text);
  font-family: inherit; font-size: .8rem; font-weight: 600;
}
.sl-share.share-btn:hover { background: var(--orange); color: #000; transform: none; }
.sl-share.share-btn svg { width: 15px; height: 15px; }
/* The menu is share.css's; it only needs to sit above the sticky header and
   clear of the drawer's own scrolling edge. */
.sl-header .share-menu { z-index: 6; }

/* ── Reading progress + ETA ───────────────────────────────────────────────
   The bar fills as THE DRAWER scrolls — the drawer is the scrolling surface,
   so this is the same measurement the original made on `.reader`. */
.sl-progress-wrap {
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 auto; min-width: 0; margin-right: 12px;
}
.sl-progress-bar {
  width: 120px; height: 4px;
  flex: 0 1 120px; min-width: 36px;
  background: var(--border); border-radius: 2px;
  overflow: hidden;
}
.sl-progress-fill {
  height: 100%; width: 0%;
  background: var(--orange);
  border-radius: 2px;
  transition: width 0.15s linear;
}
.sl-progress-eta {
  font-size: 0.65rem; color: var(--text-dim);
  white-space: nowrap;
}

/* ── The print status line ────────────────────────────────────────────────
   The print button fetches; it never navigates. So whatever happens — building,
   saved, failed — has to be said HERE, on the drawer the reader is still
   looking at, with the list still behind it. role="status" so it is announced
   as well as shown. */
.sl-note {
  flex: 1 1 100%;
  margin-top: 8px;
  font-size: 0.72rem; font-weight: 600;
  color: var(--text-secondary);
}
.sl-note.err { color: var(--orange-text); }

/* ── Content ──────────────────────────────────────────────────────────────
   Mirrors the old .reader-article padding. The COLUMN is not set here: the
   shadow host carries the article page's own main{max-width:880px} through
   the bridge in blog-sideload.js, so this only supplies the gutters. */
.sl-host { display: block; padding: 16px 28px 80px; }

/* Placeholder while /article/<slug> is in flight. A click must never look like
   nothing happened. */
.sl-loading {
  padding: 48px 28px;
  color: var(--text-secondary);
  font-size: 0.95rem;
}

/* Reduced motion: the drawer still arrives, it just does not travel. The
   scrim still fades — an opacity change is not vestibular motion. */
@media (prefers-reduced-motion: reduce) {
  .sl-drawer { transition: none; }
}

/* The page behind, while the drawer is open. `inert` + aria-hidden are set in
   JS (correct for a11y); this is what stops the LIST scrolling under the
   drawer without hiding it. body{top:-<scrollY>px} is set in JS so the list
   stays exactly where the reader left it; close() puts the scroll back. */
body.sl-locked {
  position: fixed;
  left: 0; right: 0; width: 100%;
  overflow: hidden;
}

@media (max-width: 768px) and (orientation: portrait) {
  .sl-drawer { width: 100vw; }
  .sl-header { padding: 12px 14px; padding-top: max(12px, env(safe-area-inset-top)); }
  .sl-host { padding: 12px 14px 72px; }
  .sl-loading { padding: 40px 14px; }
}

/* Narrow phones — the original's rule verbatim (9300cba^ :903-912): the ETA and
   the Share label go, the icons and the bar stay, and the header keeps to ONE
   uncrowded row. Below 480 the drawer is the full viewport, so the viewport
   width IS the drawer width and this is a measurement of the right thing.
   These two `display:none`s are the only ones in this file and both name a
   .sl- control in the drawer's own chrome — the LIST is never hidden, which is
   what test/blog-sideload.test.mjs enforces per rule block. */
@media (max-width: 480px) and (orientation: portrait) {
  .sl-progress-eta { display: none; }
  .sl-share.share-btn { width: 36px; padding: 0; }
  .sl-share.share-btn span { display: none; }
}

/* NOTHING for landscape: landscape on a phone is the FULL desktop layout
   (standing rule), which is what the rules above already are. */
