/**
 * css/shell/reader.css
 * The Reader screen: the real document canvas, full-bleed on a warm page,
 * with every other control that lives inside #outputPanel hidden away (those
 * controls reappear, restyled, on the Listen / Format / Display screens).
 *
 * The single most important rule in this file is what it does NOT do: it
 * never moves, clones or rebuilds #previewWrapper / #outputContent. That
 * subtree is where formatting, highlights, read-along and reading-position
 * tracking all operate, so the shell shows the original node and nothing
 * else.
 *
 * Also here: the Import screen, which is the app's ORIGINAL .input-panel
 * (template picker, upload area, URL fetch, textarea, Shift My Text) simply
 * repositioned as a full-screen layer. Same nodes, same handlers.
 *
 * Dependencies: css/shell/tokens.css, css/shell/chrome.css.
 */

/* ============================================================
   READER — the document canvas
   ============================================================ */

/* #mainContainer becomes a plain full-width column; its own grid/gap rules
   from the desktop stylesheet would otherwise fight the full-bleed page. */
body.ts-shell #mainContainer {
  display: block;
  max-width: 100%;
  margin: 0;
  padding: 0;
  gap: 0;
}

/* Everything inside the output panel except the canvas itself is surfaced
   through the shell's own screens instead. Hidden, never removed — the
   engine still reads and writes these controls. */
body.ts-shell #outputHeader,
body.ts-shell #readingStatsSection,
body.ts-shell #outputTogglesBar,
body.ts-shell #bionicSliderContainer,
body.ts-shell #alignCustomizeRow,
body.ts-shell #zoomControls,
body.ts-shell #ttsPanel,
body.ts-shell #outputStats,
/* Compare view has no control on mobile (see js/shell/screen-display.js).
   Hidden here as well so that if anything ever switches the engine's compare
   mode on, the shell cannot end up painting the desktop two-pane layout. */
body.ts-shell #compareContainer { display: none !important; }

/* toggleCompare() hides the canvas with an inline style when it turns compare
   on. Nothing in the shell can reach it any more, but if it were ever set the
   reader would go permanently blank with no visible way back — so keep the
   canvas painted regardless. */
body.ts-shell #outputPanel.visible #previewWrapper { display: block !important; }

/* Scoped to .visible on purpose: the base stylesheet keeps .output-panel
   display:none until a document has actually been shifted, and the shell
   must not override that — an unconditional display here would paint an
   empty canvas over the empty state. */
body.ts-shell #outputPanel.visible {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

/* Full-bleed warm page. The wrapper keeps its natural height (the BODY is
   the scroll container on mobile — never give this an inner scroll). */
body.ts-shell #previewWrapper {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--ts-page);
  max-height: none !important;
  min-height: calc(100vh - var(--ts-appbar-h) - var(--ts-quickbar-h) - var(--ts-bottom-reserve));
  box-shadow: none;
}
body.ts-shell #previewContainer {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--ts-page);
  box-shadow: none;
  max-width: 100%;
  min-height: auto !important;
}
/* Transparent, NOT the page colour: the page colour belongs to
   #previewContainer, which is also what FocusTools tints (it adds
   .overlay-blue and friends there). Painting the warm page on this element
   too would sit an opaque layer on top of the tint and the reading overlays
   would silently stop working. */
body.ts-shell #outputContent {
  background: transparent;
  color: var(--ts-page-ink);
  padding: 1.25rem 1.25rem 2.5rem !important;
  box-sizing: border-box;
  min-height: auto !important;
}

/* The app's own dark-reading-page mode still wins — it sets its colours on
   #outputContent directly, so only the surrounding chrome needs to follow. */
body.ts-shell #outputContent.dark-output-on,
body.ts-shell:has(#outputContent.dark-output-on) #previewWrapper,
body.ts-shell:has(#outputContent.dark-output-on) #previewContainer {
  background: #14161a;
}

/* ============================================================
   READER — empty state (no document open yet)
   ============================================================ */
body.ts-shell .ts-empty { display: none; }
/* .output-panel only carries .visible once a document has been shifted. */
body.ts-shell:not(:has(#outputPanel.visible)) .ts-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.75rem;
  min-height: calc(100vh - var(--ts-appbar-h) - var(--ts-quickbar-h) - var(--ts-bottom-reserve));
  padding: 2rem 1.5rem;
}
/* With no document there is nothing to copy, highlight, zoom or focus. */
body.ts-shell:not(:has(#outputPanel.visible)) .ts-quickbar,
body.ts-shell:not(:has(#outputPanel.visible)) .ts-progress { display: none; }

/* THE EMPTY READER FITS THE SCREEN, AND DOES NOT SCROLL.

   The empty state is appended to the END of <body>, after #mainContainer,
   and with no document #mainContainer is still a full screen tall and
   blank. So the empty state began below the fold: a first screen of nothing,
   and the one button that does anything -- Import a document -- about 430px
   further down, found only by someone who thought to scroll a page that
   looked empty. Reported 2026-09-23 with two screenshots of exactly that.

   On the Reader with no document it is now a fixed layer from the bottom of
   the app bar to the top of the tab bar, content centred in what is actually
   visible, and the page behind it does not scroll. Scoped to the Reader, so
   it never shows through on Listen, Format or the rest.

   LAYER 800, AND WHY NOT HIGHER. It has to be above the page it covers
   (<main> is 10, nothing in it is above 200) and below everything that must
   still appear over an empty Reader: the study timer pill (900), the
   dictation pill (950), the help menu (1000) and every popup window (2000,
   #modalContainer is a direct child of <body>). It was 7800 at first, and
   that hid every popup on the empty Reader -- the upgrade window, Plan &
   Licence from the menu -- behind this panel. Found 2026-09-24 when a
   screenshot showed the Reader where an upgrade window should have been. */
body.ts-shell[data-ts-screen="reader"]:not(:has(#outputPanel.visible)) .ts-empty {
  position: fixed;
  top: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
  bottom: var(--ts-bottom-reserve);
  left: 0;
  right: 0;
  z-index: 800;
  min-height: 0;
  /* A touch above true centre: the optical middle of a screen sits higher
     than the measured one, and the button is what the eye should land on. */
  padding: 1.5rem 1.5rem 3.5rem;
  background: var(--ts-bg);
  overflow: hidden;
}
/* The page itself must not scroll. Two separate rules, not one list: the
   <html> half cannot say "no visible output panel" as :not(:has(...))
   inside its own :has() -- :has() does not nest, and ONE invalid selector
   throws away the whole rule, body half included. Chained :has() is valid.
   !important because css/mobile.css forces body { overflow-y: auto
   !important } so a document can always be scrolled; that stays true the
   moment a document is open, since these rules then stop matching. */
html:has(body.ts-shell[data-ts-screen="reader"]):has(#outputPanel:not(.visible)) {
  overflow: hidden !important;
  overscroll-behavior: none;
}
body.ts-shell[data-ts-screen="reader"]:not(:has(#outputPanel.visible)) {
  overflow: hidden !important;
  overscroll-behavior: none;
}
body.ts-shell:not(:has(#outputPanel.visible))[data-ts-screen="reader"] {
  padding-top: calc(var(--ts-appbar-h) + env(safe-area-inset-top, 0px));
}

.ts-empty-icon {
  width: 3.5rem; height: 3.5rem;
  color: var(--ts-text-faint);
}
.ts-empty-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--ts-text);
}
.ts-empty-text {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--ts-text-dim);
  max-width: 22rem;
}
.ts-empty-btn {
  margin-top: 0.5rem;
  padding: 0.875rem 1.75rem;
  border: 0;
  border-radius: var(--ts-radius-sm);
  background: var(--ts-accent);
  color: var(--ts-accent-ink);
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

/* ============================================================
   IMPORT SCREEN — the original .input-panel, repositioned

   Shown from the app bar's new-document button and from the empty state.
   Every child is the app's own markup with its own onclick handlers, so
   template selection, file upload, OCR, URL fetch and "Shift My Text" all
   behave exactly as they do on desktop.
   ============================================================ */
body.ts-shell .input-panel {
  display: none;
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 7950;
  margin: 0;
  border: 0;
  border-radius: 0;
  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.75rem)
           var(--ts-pad)
           calc(var(--ts-bottom-reserve) + 1rem);
}
body.ts-shell[data-ts-screen="import"] .input-panel { display: block; }

/* The library launcher is replaced by the Library tab. */
body.ts-shell #libraryLauncher { display: none !important; }

/* ============================================================
   PASTE-YOUR-OWN-TEXT

   styles-core.css hides .input-area (the raw textarea plus Load Sample /
   Clear) everywhere with a top-level `display: none`, and the previous mobile
   nav deliberately left it out too. The result on a phone is that there is no
   way to paste text at all: "Shift My Text" has nothing to act on, so it
   appears to do nothing and the reader shows its empty state.

   The desktop app offers this, the markup already exists and every handler is
   wired, so the Import screen simply shows it. Import-screen only — the
   textarea has no business being visible anywhere else.
   ============================================================ */
body.ts-shell[data-ts-screen="import"] .input-area {
  display: flex !important;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1rem;
}
body.ts-shell[data-ts-screen="import"] .input-area .textarea-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
body.ts-shell[data-ts-screen="import"] #inputText {
  width: 100%;
  box-sizing: border-box;
  min-height: 9rem;
  padding: 0.875rem;
  border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-sm);
  background: var(--ts-surface);
  color: var(--ts-text);
  /* 16px minimum or Android Chrome zooms the page on focus. */
  font-size: 1rem;
  line-height: 1.5;
  font-family: inherit;
  resize: vertical;
}
body.ts-shell[data-ts-screen="import"] #inputText::placeholder {
  color: var(--ts-text-faint);
}
body.ts-shell[data-ts-screen="import"] .input-area .input-stats {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--ts-text-dim);
}
