/**
 * css/shell/chrome.css
 * The persistent frame of the mobile shell: top app bar, reader quick-action
 * bar, bottom progress bar and bottom tab bar — plus the rules that take the
 * ORIGINAL page chrome (header, footer, old sheet nav) out of the picture.
 *
 * Nothing here moves a DOM node. The original markup stays exactly where it
 * is so every getElementById() in the engine keeps resolving; this file only
 * decides what is painted. That is what makes the whole shell reversible by
 * removing one class from <body>.
 *
 * Dependencies: css/shell/tokens.css (all custom properties).
 */

/* Shell-only elements are invisible until the shell is switched on, so they
   can sit in index.html without ever showing up on desktop. */
.ts-appbar,
.ts-quickbar,
.ts-tabbar,
.ts-progress,
.ts-screen { display: none; }

body.ts-shell {
  background: var(--ts-bg);
  /* Reserve the fixed bars' space. Each edge reads a single token. */
  padding-top: calc(var(--ts-appbar-h) + var(--ts-quickbar-h) + env(safe-area-inset-top, 0px));
  padding-bottom: var(--ts-bottom-reserve);
}

/* Original chrome the shell replaces. Kept in the DOM, never painted. */
body.ts-shell > header,
body.ts-shell > footer,
body.ts-shell .mnav-tabbar,
body.ts-shell .mnav-backdrop,
body.ts-shell .mnav-sheet-head,
body.ts-shell .mnav-export-btn,
body.ts-shell .mnav-delete-btn,
body.ts-shell .canvas-restore-btn { display: none !important; }

/* ============================================================
   TOP APP BAR
   ============================================================ */
body.ts-shell .ts-appbar {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  position: fixed;
  top: 0; left: 0; right: 0;
  height: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
  padding: env(safe-area-inset-top, 0px) 0.75rem 0;
  background: var(--ts-bg);
  z-index: 8000;
}

.ts-appbar-logo {
  width: 2rem; height: 2rem;
  object-fit: contain;
  flex: none;
}

.ts-appbar-titles {
  flex: 1 1 auto;
  min-width: 0;           /* lets the doc name ellipsis instead of pushing */
  line-height: 1.15;
}
.ts-appbar-title {
  display: block;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--ts-accent-text);
  letter-spacing: -0.01em;
}
.ts-appbar-sub {
  display: block;
  font-size: 0.8125rem;
  color: var(--ts-text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ts-appbar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem; height: 2.5rem;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 0.5rem;
  background: transparent;
  color: var(--ts-text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ts-appbar-btn:active { background: var(--ts-surface-2); }
.ts-appbar-btn svg { width: 1.5rem; height: 1.5rem; }

/* ============================================================
   QUICK ACTION BAR (reader only)
   ============================================================ */
body.ts-shell .ts-quickbar {
  display: flex;
  position: fixed;
  top: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
  left: 0; right: 0;
  height: var(--ts-quickbar-h);
  background: var(--ts-bg);
  border-bottom: 1px solid var(--ts-border-soft);
  z-index: 8000;
}
/* The quick bar is about the document — pointless on the other screens. */
body.ts-shell:not([data-ts-screen="reader"]) .ts-quickbar { display: none; }
body.ts-shell:not([data-ts-screen="reader"]) {
  padding-top: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
}

.ts-quick-btn {
  /* Icon-only, so an equal share is honest now: there is no label to cut
     short and every action gets the same tap area. */
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ts-text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
body.ts-shell .ts-quickbar > * + * { border-left: 1px solid var(--ts-border-soft); }
.ts-quick-btn:active { background: var(--ts-surface-2); }
/* One icon size for the whole bar — undo and redo included, which otherwise
   size themselves to their button and come out noticeably larger. */
.ts-quick-btn svg,
.ts-quick-undo .ts-zoom-step svg { width: 1.375rem; height: 1.375rem; flex: none; }
/* Each quick action keeps the accent its control uses elsewhere in the app. */
.ts-quick-btn[data-act="highlights"] svg { color: #eab308; }

/* How many highlights the document has, on the Highlights button: the pen on
   its own read as "edit", and the Highlights & Notes window was taken to be
   gone. Accent fill with its own ink, so it follows the app's colour. */
.ts-quick-btn[data-act="highlights"] { position: relative; }
.ts-quick-badge {
  position: absolute;
  top: 0.35rem;
  right: 0.3rem;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.28rem;
  border-radius: 999px;
  background: var(--ts-accent);
  color: var(--ts-accent-ink);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.1rem;
  text-align: center;
  pointer-events: none;
  box-sizing: border-box;
}

/* ---- zoom stepper -------------------------------------------------------
   Three controls in one quick-bar slot: smaller, the current level, larger.
   The level doubles as a reset, which is why it is a button too. */
.ts-quick-zoom {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.125rem;
  min-width: 0;
}

/* Undo and redo, as a pair sharing one slot of the bar. */
.ts-quick-undo {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.125rem;
  min-width: 0;
}
.ts-quick-undo .ts-zoom-step:disabled {
  opacity: 0.32;
  pointer-events: none;
}

.ts-zoom-step {
  flex: none;
  /* Comfortably past the 44px touch-target guideline in height, while staying
     narrow enough that the four bar items still fit a 384px screen. */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 100%;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ts-text);
  font-size: 1.375rem;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ts-zoom-step:active { background: var(--ts-surface-2); }

.ts-zoom-level {
  flex: none;
  min-width: 3rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ts-text);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;   /* the width must not jitter per step */
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ============================================================
   READING PROGRESS (sits directly on top of the tab bar)
   ============================================================ */
body.ts-shell .ts-progress {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  position: fixed;
  left: 0; right: 0;
  bottom: var(--ts-bottom-reserve);
  padding: 0 0.5rem 0.375rem;
  background: var(--ts-bg);
  z-index: 8000;
  pointer-events: none;   /* purely an indicator; never eats a tap */
}
body.ts-shell:not([data-ts-screen="reader"]) .ts-progress { display: none; }

.ts-progress-track {
  flex: 1 1 auto;
  height: var(--ts-progress-h);
  border-radius: 999px;
  background: var(--ts-track);
  overflow: hidden;
}
.ts-progress-bar {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--ts-accent);
  transition: width 0.15s linear;
}
.ts-progress-pct {
  flex: none;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ts-accent-text);
  min-width: 2.5rem;
  text-align: right;
}

/* ============================================================
   BOTTOM TAB BAR
   ============================================================ */
body.ts-shell .ts-tabbar {
  display: flex;
  /* Icons sit at the TOP of the tall reserved box; the remainder below them
     is gesture-zone clearance that still belongs to this element, so the
     strip under the tabs is bar, not bare canvas. */
  align-items: flex-start;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: var(--ts-bottom-reserve);
  background: var(--ts-bg);
  border-top: 1px solid var(--ts-border-soft);
  z-index: 8001;
}

.ts-tab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  height: var(--ts-tabbar-content-h);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ts-text-dim);
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ts-tab svg { width: 1.5rem; height: 1.5rem; }
.ts-tab.active { color: var(--ts-accent-text); }

/* ============================================================
   SCREEN OVERLAYS (Listen / Format / Display / Library)

   Deliberately overlays rather than a swap of the reader's contents: the
   real #previewWrapper stays laid out underneath at all times, so zoom
   measurement, read-along scroll-into-view and the reading-position tracker
   keep working while another screen is on top. `overscroll-behavior:
   contain` stops a fling inside a screen from chaining to the body — the
   body is the app's scroll container on mobile and must not be tampered
   with (no overflow:hidden here, ever).
   ============================================================ */
body.ts-shell .ts-screen {
  display: none;
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 7900;
  background: var(--ts-bg);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px) + 0.5rem)
           var(--ts-pad)
           calc(var(--ts-bottom-reserve) + 1rem);
}
/* Every screen host is display:none by default (above), so a new screen is not
   visible until its id is added here — the router and the tab will both work
   and the panel will still be blank. */
body.ts-shell[data-ts-screen="listen"]     #tsScreenListen,
body.ts-shell[data-ts-screen="transcribe"] #tsScreenTranscribe,
body.ts-shell[data-ts-screen="format"]     #tsScreenFormat,
body.ts-shell[data-ts-screen="display"]    #tsScreenDisplay,
body.ts-shell[data-ts-screen="library"]    #tsScreenLibrary,
/* Reached from the kebab menu, not the tab bar (js/shell/screen-tools.js and
   js/shell/screen-ai.js, which create these two hosts themselves). */
body.ts-shell[data-ts-screen="tools"]      #tsScreenTools,
body.ts-shell[data-ts-screen="ai"]         #tsScreenAi { display: block; }

/* ============================================================
   APP MODALS OVER THE SHELL

   The app's modals (User Guide, Help, Terms, the plan manager) cover the
   whole viewport, tab bar included. If one opens and its close button is
   missed — or it opens unexpectedly — the reader is trapped with no visible
   way back. Stopping the overlay above the tab bar keeps the shell's own
   navigation reachable at all times; shell.js additionally closes any open
   modal when a tab is tapped.
   ============================================================ */
body.ts-shell .modal-overlay {
  /* Below the app bar, above the tab bar. The app bar paints over anything
     that starts at top:0, and what it was covering was the modal's own header
     — the row carrying the close button. That is the whole reason a modal
     felt inescapable: its only exit was underneath the bar. */
  top: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
  bottom: var(--ts-bottom-reserve);
}

/* Keep the modal's own close button reachable however far its body is
   scrolled. Harmless if .modal-content is not the scrolling element — sticky
   simply has no effect then. */
body.ts-shell .modal-content .modal-header {
  position: sticky;
  top: 0;
  z-index: 2;
  background: inherit;
}

/* ============================================================
   BACK TO MENU, AND MODALS THAT FIT

   js/shell/menu.js puts a "Back to menu" button on every page the menu
   opens: above the Tools and AI tools lists, on Feature switches, and in the
   header of the guide, FAQ, terms, privacy, contact and plan windows.

   The windows were centred in the space between the app bar and the tab bar
   but allowed to be taller than it (max-height 85vh against a space of about
   80vh), so their top ran under the app bar and their bottom under the tab
   bar: "the writing at the top and right at the bottom has been cut off"
   (2026-09-25). They now stop short of both.
   ============================================================ */
body.ts-shell .ts-menu-back {
  flex: none;
  min-height: 2.25rem;
  padding: 0 0.75rem;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ts-text);
  background: var(--ts-surface);
  border: 1px solid var(--ts-border);
  border-radius: 999px;
  cursor: pointer;
}
body.ts-shell .ts-menu-back-bar {
  display: flex;
  padding: 0 0 0.75rem;
}
body.ts-shell .ts-menu-back-bar[hidden] { display: none; }

body.ts-shell .modal-content,
body.ts-shell .upgrade-modal-content {
  max-height: calc(100% - 1rem);
}
body.ts-shell .modal-header { gap: 0.5rem; }
body.ts-shell .modal-header .modal-title { flex: 1; min-width: 0; }

/* The User Guide's tables were as wide as their widest words, so with a
   larger phone text size the last column ran off the right-hand edge. Fixed
   layout keeps them to the window's width and lets the words wrap. */
body.ts-shell .modal-body table.ug-tbl { table-layout: fixed; width: 100%; }
body.ts-shell .modal-body table.ug-tbl th:first-child,
body.ts-shell .modal-body table.ug-tbl td:first-child { width: 40%; }
body.ts-shell .modal-body table.ug-tbl th,
body.ts-shell .modal-body table.ug-tbl td { overflow-wrap: anywhere; }
body.ts-shell .modal-body .ug-badge { white-space: normal; }

/* The sticky header stuck below the window's top padding, so scrolled text
   showed through above it. Pull it up over the padding (1.25rem on phones,
   styles-core.css) so it covers the whole top of the window. */
body.ts-shell .modal-content .modal-header {
  top: -1.25rem;
  margin-top: -1.25rem;
  padding-top: 1.25rem;
}
