/* ============================================================================
   shell.css — MarkIt  (task #817)
   The layoutTest floating-pane shell: unbroken chrome (title bar + status bar),
   an activity rail at 640+, and the view floating in a rounded pane inset by a
   gutter.

   ── CURATED, NOT WHOLESALE. AND NO kit.css. ──────────────────────────────
   Measured against THIS app before deciding (LinkIt's 24 was not assumed to
   carry over — MarkIt is worse). layoutTest's kit.css and MarkIt's app.css
   both write rules for 26 of the same classes:

     .btn (35 kit rules vs 17 MarkIt)  .icon (17 v 3)     .icon-btn (13 v 3)
     .switch (10 v 4)  .switch-track (10 v 3)  .check (11 v 2)
     .modal (9 v 1)    .segmented (8 v 1)      .toast (5 v 2)
     .danger (5 v 1)   .primary (5 v 4)        .ghost (3 v 3)
     .outline (3 v 2)  .danger-ghost (2 v 2)   .sel (2 v 1)
     .chart-bar (2 v 2) .combo-empty (2 v 1)   .field-grid (2 v 2)
     .fab (1 v 2)      .chart (1 v 1)          .field (1 v 1)
     .field-hint (1 v 1) .field-label (1 v 1)  .modal-open (1 v 1)
     .muted (1 v 2)    .stat-tile (1 v 1)

   Two of those are specific to this app and worse than they look. `.icon`
   carries SEVENTEEN kit rules and layoutTest's markup puts class="icon" on
   every SVG — MarkIt's icons.js stamps the same class on every icon it builds,
   so loading kit would resize and recolour every glyph in the app. And `.fab`
   is MarkIt's floating New-Match button, the primary phone action. Loading
   kit.css would put two stylesheets in a specificity fight over all of that.
   So kit.css is not loaded; app.css keeps every component rule, unchanged.

   layoutTest's shell.css collides on only FOUR classes — .brand, .brand-word,
   .danger and .toast-host — so it ports cleanly. This file is that port, and
   it deliberately defines none of those four: MarkIt's own rules stand.

   Deliberately left out (MarkIt is a single-view app with no content for
   them): pane tab strips, seams/resizable columns, the multi-pane ws-*
   layouts, side/inspector panes, pane-head/pane-foot/crumbs — AND the shell's
   own .bottomnav, because MarkIt already HAS a phone bottom nav
   (.mobile-tabbar, #197, built in app.js). Adding the shell's would have been
   a second, competing bottom surface. See the phone section below.

   Load order (index.html):
     reset.css -> theme.css -> shell-tokens.css -> app.css -> shell.css
   shell.css loads LAST so the frame selectors win; app.css still owns every
   component. Same arrangement as the AI Dashboard (#709-#714) and LinkIt (#816).

   ⚠️ NEW FILE — must be added to the SHELL array in service-worker.js or it
   404s offline. `npm run check:shell` (new here) reports it.
   ========================================================================= */

/* ── Frame ───────────────────────────────────────────────────────────────── */
/* reset.css already does box-sizing and html,body{height:100%}. Not repeated. */

body {
  margin: 0;
  background: var(--frame);       /* beats app.css's background: var(--bg) */
  overflow: hidden;               /* the PAGE never scrolls — the pane does */
  overscroll-behavior: none;      /* stops iOS rubber-banding the whole frame */
}

/* Skip link — first focusable element, jumps into the pane. */
.skip {
  position: fixed; top: -100px; left: var(--sp-2); z-index: 999;
  padding: 10px var(--sp-3); border-radius: var(--r-sm);
  background: var(--accent); color: var(--accent-ink);
  font-weight: 700; text-decoration: none;
  transition: top var(--dur-1) var(--ease-out);
}
.skip:focus { top: var(--sp-2); }

/* Title bar and status bar span BOTH columns — the structural reason nothing
   can cut the chrome. */
.app-frame {
  height: 100dvh;                 /* dvh, not vh — iOS/Android URL bar */
  display: grid;
  grid-template-columns: var(--rail-w) 1fr;
  grid-template-rows: var(--titlebar-h) 1fr var(--statusbar-h);
  grid-template-areas:
    "title  title"
    "rail   work"
    "status status";
  overflow: hidden;
  min-height: 0;
}
.titlebar  { grid-area: title;  z-index: var(--z-chrome); }
.rail      { grid-area: rail;   z-index: var(--z-rail); }
.workspace { grid-area: work;   min-width: 0; min-height: 0; display: flex; }
.statusbar { grid-area: status; z-index: var(--z-chrome); }

/* ── Title bar ───────────────────────────────────────────────────────────── */
/* This element no longer carries .app-header, so app.css's sticky blurred
   header rules do not apply. Its CHILDREN (.brand, .header-tools, .app-nav,
   .btn, .icon-btn, .install-pill) are still styled entirely by app.css —
   which is how the chrome ends up in MarkIt's green, not a second palette. */

.titlebar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-2);
  background: var(--frame);       /* no border — the frame tone separates */
  min-width: 0;
}
.tb-left { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }

/* The current screen name. Phone only — it fills the space the header nav
   already vacated at <=639 (app.css:429 hides .app-nav there), so the phone
   title bar gains a label instead of gaining chrome. */
.tb-screen {
  display: none; flex: 1; min-width: 0;
  font-weight: 700; font-size: .98rem; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The text nav stays in the title bar at 1024+. The rail is icon-only, and
   dropping MarkIt's four nav LABELS on desktop would be a legibility
   regression — layoutTest's own frame carries both too. */
.top-nav { display: none; }
@media (min-width: 1024px) { .top-nav { display: flex; } }

/* app.css gives .header-tools margin-left:auto, which still does the right
   thing here. Just stop it shrinking. */
.titlebar .header-tools { flex: none; }

/* ── Activity rail (tablet + desktop) ────────────────────────────────────── */
/* Built in js/app.js next to buildTabBar(), following MarkIt's own convention
   that "icons live in JS, so we build the bar here rather than in index.html". */

.rail {
  display: none;                  /* phone: off — .mobile-tabbar covers it */
  flex-direction: column; align-items: center;
  gap: 2px; padding: var(--sp-2) 0;
  background: var(--frame-2);     /* recessed tone separates it, no border */
  overflow: hidden;               /* the rail never scrolls — .rail-nav does */
}
@media (min-width: 640px) { .rail { display: flex; } }

/* The nav group scrolls if MarkIt ever grows past the rail's height; the
   pinned group below (Guide, Settings) always stays on screen. Without this
   the rail clips SILENTLY — no scrollbar, no fade, the items are just gone. */
.rail-nav {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.rail-nav::-webkit-scrollbar { display: none; }

.rail-item {
  position: relative;
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  border: 0; background: transparent; color: var(--ink-soft);
  border-radius: var(--r-sm); cursor: pointer; text-decoration: none;
  transition: color var(--dur-1), background var(--dur-1);
}
.rail-item .icon { width: 20px; height: 20px; }
.rail-item:hover { background: var(--frame); color: var(--ink); }
.rail-item.active { color: var(--accent); }
/* 2px accent bar on the left edge marks the current section. */
.rail-item.active::before {
  content: ""; position: absolute; inset: 8px auto 8px 0;
  width: 2px; border-radius: 0 2px 2px 0; background: var(--accent);
}
.rail-group {
  display: flex; flex-direction: column; gap: 2px; align-items: center; flex: none;
  padding-top: var(--sp-2); border-top: 1px solid var(--line); width: 44px;
}

/* Tooltip — rail items are icon-only, so the label has to be reachable.
   640-1023 is the only band where a nav label is not permanently visible; at
   1024+ the text nav is back in the title bar, and below 640 MarkIt's own tab
   bar carries full labels. */
.rail-item::after {
  content: attr(data-tip);
  position: absolute; left: calc(100% + 6px); top: 50%; transform: translateY(-50%);
  padding: 4px 8px; border-radius: var(--r-sm);
  background: var(--ink); color: var(--bg);
  font-weight: 600; font-size: 12px; line-height: 1; white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity var(--dur-2);
  z-index: var(--z-popover);
}
.rail-item:hover::after, .rail-item:focus-visible::after { opacity: 1; }

/* ── The pane ────────────────────────────────────────────────────────────── */
/* The gutter is the pane's margin, so the frame shows on all four edges and
   the pane reads as floating on the chrome. */

.pane {
  position: relative;
  flex: 1; min-width: 0;
  min-height: 0;                  /* load-bearing: without it the body won't scroll */
  margin: var(--gutter);
  display: flex; flex-direction: column;
  background: var(--pane);
  border-radius: var(--pane-radius);
  box-shadow: var(--shadow-1);
  overflow: hidden;               /* clips content into the radius */
  /* No `container-type: inline-size`, unlike layoutTest's .pane. MarkIt has
     ZERO @container rules, so a size container would be dead weight. (On
     LinkIt I measured what containment actually does to position:fixed
     children in current Chrome — nothing — so this is a simplification, not a
     bug fix. MarkIt's one absolutely-positioned popover, .combo-menu, is
     position:absolute inside its own relative wrapper and is unaffected
     either way.) */
}

/* The pane body is the ONLY scrolling region in the app. It carries no
   padding — MarkIt's own .app-main (max-width 70rem + its existing padding,
   including the 6.5rem phone reserve for the tab bar and FAB) sits inside it
   and keeps content spacing exactly as it was. */
.pane-body {
  flex: 1; min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;   /* pane scroll never chains to the frame */
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--surface-3) transparent;
}
.pane-body::-webkit-scrollbar { width: 10px; height: 10px; }
.pane-body::-webkit-scrollbar-thumb {
  background: var(--surface-3); border-radius: 99px;
  border: 3px solid var(--pane);  /* inset look — keeps the floating illusion */
}
.pane-body::-webkit-scrollbar-track { background: transparent; }
.pane-body:focus { outline: none; }

/* The page used to be the scroller, so app.css:250's modal lock (body.modal-open
   { overflow: hidden }) targeted the body. Now the pane is the scroller and has
   to be locked too, or the view scrolls behind an open modal or sheet. */
body.modal-open .pane-body { overflow: hidden; }

/* ── Status bar (tablet + desktop) ───────────────────────────────────────── */

.statusbar {
  display: none;                  /* phone: gone */
  align-items: stretch; gap: 2px;
  padding: 0 var(--sp-2);
  background: var(--frame);
  font-size: .74rem; color: var(--ink-soft);
  overflow: hidden;
}
@media (min-width: 640px) { .statusbar { display: flex; } }

.sb-item {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 0 var(--sp-2);
  border: 0; background: transparent; color: inherit; font: inherit;
  border-radius: var(--r-sm); white-space: nowrap; text-decoration: none;
  min-width: 0;
}
.sb-item.is-static { cursor: default; }
a.sb-item:hover, button.sb-item:hover { background: var(--surface-2); color: var(--ink); }
.sb-spacer { flex: 1; }
.sb-ctx-text { overflow: hidden; text-overflow: ellipsis; }
.sb-num { font-family: var(--font-num); font-variant-numeric: tabular-nums; }

/* ── Phone ───────────────────────────────────────────────────────────────── */
/* NO shell bottom nav here. MarkIt already replaces the header nav with its own
   .mobile-tabbar below 640 (app.css:429 + :437), and app.css:425 already
   reserves calc(6.5rem + safe-area) at the bottom of .app-main for that bar and
   the FAB above it. Both are position:fixed at BODY level — outside .app-frame —
   so they keep working unchanged over the pane. The result is that the phone
   layout is essentially UNCHANGED by this retrofit: same one-row header height,
   same tab bar, same FAB. The shell's gain on this app is at 640+, not on a
   phone. (Contrast LinkIt #816, whose header wrapped to two rows below 720 and
   which therefore genuinely gained a row back.) */

@media (max-width: 639px) {
  .titlebar .brand-word { font-size: 1.05rem; }
  .tb-screen { display: block; }
}

/* ── Re-basing app.css's sticky offsets on the pane ──────────────────────── */
/* Three rules in app.css pin something with a `top` measured against the OLD
   page: a ~54px sticky .app-header with the WINDOW as the scroller. The sticky
   containing block is now .pane-body, whose top edge already sits below the
   title bar — so an un-rebased offset leaves a hole above every pinned element.
   Re-based here rather than edited in app.css, so the whole retrofit can still
   be reverted by removing two <link> tags.
     app.css:397 .guide-toc (top:76px)  ·  :375 guide headings (scroll-margin)
     app.css:543 .bkt-pager (top:56px)  — the bracket round pager */

.pane-body .guide-toc { top: var(--sp-4); }
.pane-body .guide-toc {
  max-height: calc(100dvh - var(--titlebar-h) - var(--statusbar-h)
                   - (var(--gutter) * 2) - var(--sp-6));
}
.pane-body .guide h1, .pane-body .guide h2,
.pane-body .guide h3, .pane-body .guide h4 { scroll-margin-top: var(--sp-3); }
.pane-body .bkt-pager { top: 0; }
