/* DESIGN
   ------
   * This stylesheet controls the entire visual experience of the
   * reader and the drop zone.
   *
   * I chose a warm dark palette (amber on near-black) instead of the
   * typical cold blue-black because extended reading requires comfort.
   * Pure black (#000) with pure white text causes halation (glowing
   * edges around letters) on OLED screens. The warm greys (#0a0806,
   * #1a1510) and cream text (#f5efe2) reduce this while maintaining
   * high contrast.
   *
   * The design system uses CSS custom properties (:root tokens) for
   * every color, spacing value, radius, and z-index. This ensures
   * visual consistency and makes theme changes a matter of updating
   * the :root block without touching any component.
   *
   * Key CSS decisions:
   * - IBM Plex Sans: warm and open proportions that complement the
   *   amber palette. Technical enough for a developer tool but not
   *   cold like Inter or geometric like Roboto
   * - Spacing scale on 4px base (Refactoring UI methodology)
   * - Selection color is standard blue (Jakob's Law: the user expects
   *   blue selection, not amber). Amber is only for UI elements
   * - Focus mode: toolbar transitions with opacity + translateY.
   *   Scroll does NOT interrupt focus mode (reading is the primary action)
   * - Mobile: pointer:coarse queries instead of width breakpoints so
   *   tablets and foldables get the right treatment regardless of
   *   screen size
   * - Safari flex selection fix: display:flex + align-items:flex-start
   *   on .text-layer forces WebKit to shrink-wrap line divs to their
   *   content width, preventing selection highlight from extending to
   *   the page edge
   *
   * The stylesheet follows this flow:
   *
   * 1. RESET (lines 66-74)
   * 2. DESIGN TOKENS (lines 77-171)
   * 3. BASE (lines 174-194)
   * 4. PAGE TRANSITION (lines 197-217)
   * 5. DROP ZONE (lines 220-566)
   *    Includes: veil transition layers, wordmark, tagline,
   *    browse button, focus styles, high contrast
   * 6. TOOLBAR (lines 569-788)
   *    Floating pill, navigation, zoom, dark mode toggle, filename
   * 7. READER LAYOUT (lines 791-798)
   * 8. VIEWPORT (lines 801-833)
   * 9. PAGE CONTAINER (lines 836-871)
   * 10. DARK MODE FILTER (lines 874-889)
   * 11. TEXT LAYER (lines 892-998)
   *     Selection, multi-column flex wrapper, OCR image regions,
   *     vertical OCR layer
   * 12. LINK ANNOTATIONS (lines 1001-1020)
   * 13. PAGE NUMBER LABEL (lines 1023-1027)
   * 14. ERROR BANNER (lines 1030-1089)
   * 15. EXPORT PROGRESS (lines 1092-1149)
   * 16. OCR LOADING INDICATOR (lines 1152-1248)
   * 17. ACCESSIBILITY (lines 1251-1284)
   *     prefers-reduced-motion, prefers-contrast, focus-visible
   * 18. UTILITIES (lines 1287-1305)
   * 19. MOBILE LANDSCAPE (lines 1308-1336)
   * 20. APP SHELL LOADER (lines 1339-1373)
*/


/* --- RESET --- */

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}


/* --- DESIGN TOKENS --- */

:root {
  /* Warm dark palette (from landing page design system) */
  --bg-deep: #0a0806;          /* App background, very dark warm */
  --bg-surface: #1a1510;       /* Cards, elevated surfaces */
  --bg-elevated: #241e18;      /* Hover states, toolbar */
  --text-primary: #f5efe2;     /* Cream, not pure white */
  --text-secondary: #9a8878;   /* Warm grey */
  --text-muted: #6b5d50;       /* Very subtle */
  --border: rgba(212, 163, 115, 0.08);
  --accent: #D4A373;           /* Amber */
  --accent-hover: #deb48a;
  --accent-active: #ba8d5e;
  --accent-ghost: rgba(212, 163, 115, 0.04);
  --accent-subtle: rgba(212, 163, 115, 0.08);
  --accent-border: rgba(212, 163, 115, 0.1);
  --accent-highlight: rgba(212, 163, 115, 0.14);
  --accent-border-mid: rgba(212, 163, 115, 0.25);
  --accent-focus: rgba(212, 163, 115, 0.6);
  --selection: rgba(107, 138, 205, 0.3);
  --page-canvas-bg: #1e1e1e;
  --error-text: #e8a0a0;
  --veil-layer-mid: #110e0b;
  --drag-over-bg: #161210;
  --text-on-accent: #2a1f1a;
  --shadow-page: 0 2px 16px rgba(0, 0, 0, 0.3);
  --shadow-overlay: 0 4px 24px rgba(0, 0, 0, 0.5);
  --radius-pill: 50px;
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius: 8px;
  --radius-sm: 4px;
  --radius-xs: 2px;
  --tracking-tight: -0.01em;
  --transition: 200ms ease;

  /* Spacing scale (4px base) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 32px;
  --space-9: 36px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* Typography scale */
  --text-2xs: 11px;
  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 14px;
  --text-md: 15px;
  --text-lg: 16px;
  --text-xl: 17px;
  --text-2xl: 18px;
  --text-3xl: 20px;

  /* Font weights */
  --font-regular: 400;
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;

  /* Line heights */
  --leading-none: 1;
  --leading-tight: 1.2;
  --leading-snug: 1.4;
  --leading-normal: 1.6;
  --leading-relaxed: 1.7;

  /* Durations and easing */
  --duration-fast: 0.2s;
  --duration-medium: 0.3s;
  --duration-slow: 0.4s;
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);

  --toolbar-height: var(--space-12);

  /* Z-index layers */
  --z-viewport: 0;
  --z-veil-layer: 1;
  --z-drop-border: 4;
  --z-drop-content: 5;
  --z-toolbar: 50;
  --z-banner: 60;
  --z-drop-zone: 100;
  --z-drop-about: 101;
  --z-loader: 200;
  --z-transition: 999;
}


/* --- BASE --- */

html {
  background: var(--bg-deep);
}

/*
 * Font stack: IBM Plex Sans is the primary (loaded from Google Fonts).
 * If it fails (offline on first visit, CDN down), the fallbacks ensure
 * the user sees their OS native font instead of a generic serif:
 * -apple-system (Safari), BlinkMacSystemFont (Chrome on Mac),
 * Segoe UI (Windows), system-ui (universal), sans-serif (last resort)
 */
body {
  font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: var(--bg-deep);
  color: var(--text-primary);
  height: 100vh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}


/* --- PAGE TRANSITION --- */

.page-transition-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-transition);
  background: var(--bg-elevated);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.page-transition-overlay.active {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .page-transition-overlay {
    transition: none;
    opacity: 0 !important;
  }
}


/* --- DROP ZONE --- */

#drop-zone {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-12) 0;
  overflow-y: auto;
  cursor: pointer;
  z-index: var(--z-drop-zone);
  -webkit-tap-highlight-color: transparent;
}

@media (pointer: coarse) {
  #drop-zone { cursor: default; }
}

/*
 * Drag-over feedback (Jakob's Law): the dashed border is a universal
 * pattern that every user recognizes as "drop here". The top veil layer
 * lightens subtly to acknowledge the drag. On touch devices (pointer:
 * coarse) the dashed border is hidden because drag-and-drop doesn't
 * exist on mobile
 */
#drop-zone.drag-over .veil-layer-1 {
  background: var(--drag-over-bg);
}

#drop-zone::after {
  content: none;
}
@media (pointer: fine) {
  #drop-zone::after {
    content: '';
    position: absolute;
    inset: 64px 48px 48px;
    border: 1.5px dashed rgba(212, 163, 115, 0.25);
    border-radius: var(--radius-lg);
    pointer-events: none;
    z-index: 4;
    transition: border-color 0.3s ease;
  }
}

#drop-zone.drag-over::after {
  border-color: rgba(212, 163, 115, 0.4);
}


/* --- VEIL TRANSITION LAYERS --- */

/*
 * Three panels that slide right when a PDF loads, creating a
 * parallax curtain-opening effect. Each layer is a different shade
 * of the warm palette, moving at a different speed. The reader is
 * already rendering behind them so the transition masks load time
 */

.veil-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: translateX(0);
  will-change: transform;
}

.veil-layer-1 {
  background: var(--bg-elevated);
  z-index: 3;
  transition: background 0.3s ease, transform 0.7s var(--ease-smooth);
}

.veil-layer-2 {
  background: var(--veil-layer-mid);
  z-index: 2;
  transition: transform 0.85s var(--ease-smooth);
}

.veil-layer-3 {
  background: var(--bg-surface);
  z-index: 1;
  transition: transform 1s var(--ease-smooth);
}

/* When opening (PDF loaded): layers slide right at different speeds */
#drop-zone.veil-opening .veil-layer-1 {
  transform: translateX(100%);
}
#drop-zone.veil-opening .veil-layer-2 {
  transform: translateX(100%);
}
#drop-zone.veil-opening .veil-layer-3 {
  transform: translateX(100%);
}

/* veil opening: let clicks through to the reader underneath */
#drop-zone.veil-opening {
  pointer-events: none;
}

/* Content fades out as veil opens */
#drop-zone.veil-opening .drop-hero,
#drop-zone.veil-opening .drop-about {
  opacity: 0;
  transition: opacity 0.3s ease;
}
#drop-zone.veil-opening::after {
  opacity: 0;
  transition: opacity 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  .veil-layer { transition: none; }
  #drop-zone.veil-opening .drop-hero,
  #drop-zone.veil-opening .drop-about,
  #drop-zone.veil-opening::after {
    transition: none;
  }
}


/* --- WORDMARK --- */

.drop-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  user-select: none;
  z-index: 5;
  position: relative;
  margin-top: -5vh;
}
@media (min-width: 700px) {
  .drop-hero { margin-top: -8vh; }
}

.drop-wordmark {
  position: relative;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 72px;
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
  color: var(--accent);
  transition: opacity 0.4s ease;
}
@media (min-width: 700px) {
  .drop-wordmark { font-size: 96px; }
}



.drop-tagline {
  font-size: var(--text-base);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-tight);
  margin-top: var(--space-2);
}
/* Touch devices (phones, tablets, foldables): short tagline */
.drop-tagline-desktop { display: none; }
.drop-tagline-mobile { display: block; }
/* Mouse devices only: full tagline */
@media (pointer: fine) {
  .drop-tagline { font-size: var(--text-xl); }
  .drop-tagline-desktop { display: block; }
  .drop-tagline-mobile { display: none; }
}

/* Primary CTA, mobile only. Same style as landing page .cta-btn */
.drop-browse-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-7);
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: var(--font-semibold);
  border: none;
  background: var(--accent);
  color: var(--text-on-accent);
  cursor: pointer;
  transition: background 0.2s, transform 0.15s;
  margin-top: var(--space-9);
}
.drop-browse-btn:hover { background: var(--accent-hover); }
.drop-browse-btn:active {
  background: var(--accent-active);
  transform: scale(0.97);
}
/* Hide on mouse devices, "click anywhere" replaces the button */
@media (pointer: fine) {
  .drop-browse-btn { display: none; }
}

.drop-resume-section {
  margin-top: 56px;
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-md);
  border: 1px solid var(--accent-border);
  background: var(--accent-ghost);
  cursor: pointer;
  text-align: center;
  transition: background 0.2s, border-color 0.2s, transform 0.15s;
  max-width: 340px;
  min-width: 260px;
  width: calc(100% - 40px);
  -webkit-tap-highlight-color: transparent;
}
@media (min-width: 700px) {
  .drop-resume-section {
    margin-top: 88px;
    max-width: 500px;
    width: auto;
    padding: var(--space-8) var(--space-10);
  }
  .drop-resume-label { font-size: var(--text-lg); }
  .drop-resume-filename { font-size: var(--text-3xl); }
  .drop-resume-page { font-size: var(--text-base); }
}
@media (hover: hover) {
  .drop-resume-section:hover {
    background: var(--accent-subtle);
    border-color: var(--accent-border-mid);
  }
}
.drop-resume-section:active {
  background: var(--accent-border);
  border-color: var(--accent-border-mid);
  transform: scale(0.98);
}
.drop-resume-label {
  font-size: var(--text-base);
  color: var(--text-secondary);
  margin-bottom: var(--space-2);
}
.drop-resume-filename {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--text-primary);
  word-break: break-word;
  line-height: var(--leading-snug);
}
.drop-resume-page {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin-top: var(--space-2);
}
.drop-alt-action {
  margin-top: var(--space-4);
  font-size: var(--text-base);
  color: var(--text-secondary);
  cursor: pointer;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-md);
  border: 1px solid var(--accent-border);
  background: var(--accent-ghost);
  transition: background 0.2s, border-color 0.2s;
  -webkit-tap-highlight-color: transparent;
}
.drop-alt-action:active {
  background: var(--accent-border);
  border-color: var(--accent-border-mid);
  transform: scale(0.98);
}
@media (hover: hover) {
  .drop-alt-action:hover {
    background: var(--accent-subtle);
    border-color: var(--accent-border-mid);
  }
}
@media (min-width: 700px) {
  .drop-alt-action {
    font-size: var(--text-lg);
    padding: var(--space-4) var(--space-8);
  }
}


/* --- WHAT IS VEIL LINK --- */

.drop-about {
  position: fixed;
  top: 16px;
  left: 20px;
  font-size: var(--text-base);
  color: var(--text-secondary);
  text-decoration: none;
  transition: color var(--transition);
  z-index: var(--z-drop-about);
  padding: var(--space-2) var(--space-1);
}
.drop-about:hover {
  color: var(--accent);
}
@media (min-width: 700px) {
  .drop-about { left: 48px; }
}


/* --- FOCUS STYLES --- */

#drop-zone:focus-visible {
  outline: none;
}
#drop-zone:focus-visible::after {
  border-color: var(--accent-focus) !important;
  content: '' !important;
  position: absolute !important;
  inset: 64px 48px 48px !important;
  border: 1.5px dashed rgba(212, 163, 115, 0.5) !important;
  border-radius: var(--radius-lg) !important;
  pointer-events: none !important;
  z-index: 4 !important;
}
.drop-about:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
.drop-browse-btn:focus-visible,
.drop-resume-section:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 3px;
}


/* --- DROP ZONE HIGH CONTRAST --- */

@media (prefers-contrast: more) {
  .drop-tagline { color: var(--text-primary); }
  .drop-resume-label { color: var(--text-primary); }
  .drop-resume-page { color: var(--text-secondary); }
  .drop-alt-action { color: var(--text-secondary); }
  .drop-about { color: var(--text-primary); }
  .drop-resume-section {
    border-color: rgba(212, 163, 115, 0.3);
  }
  #drop-zone::after {
    border-color: var(--accent-focus) !important;
  }
}


/* --- TOOLBAR --- */

#toolbar {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  touch-action: manipulation;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--bg-deep);
  border: 1px solid var(--border);
  z-index: var(--z-toolbar);
  transition: opacity 0.4s ease, transform 0.4s ease;
  user-select: none;
}

@media (min-width: 700px) {
  #toolbar {
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
  }
}

/*
 * Focus mode: the toolbar fades out and slides up after 1.5 seconds
 * of inactivity (2.5s on mobile). Scroll does NOT interrupt focus
 * mode because reading (scrolling through pages) is the primary
 * action and the toolbar should not keep reappearing while the
 * user is reading. The toolbar returns on mouse near the top edge
 * (desktop) or tap in the top zone (mobile)
 */
#toolbar.toolbar-hidden {
  opacity: 0;
  transform: translateX(-50%) translateY(-20px);
  pointer-events: none;
}

.toolbar-logo {
  display: flex;
  align-items: center;
  text-decoration: none;
  margin: calc(var(--space-1) * -1);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  transition: opacity 0.1s ease;
}
.toolbar-logo:hover { opacity: 0.7; }

/* Double-layer wordmark, shared between reader toolbar and landing navbar */
.nav-wordmark {
  position: relative;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: var(--text-base);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
  color: var(--accent);
}
@media (min-width: 700px) {
  .nav-wordmark { font-size: var(--text-lg); }
}

.toolbar-divider {
  width: 1px;
  height: 16px;
  background: var(--accent-border);
  flex-shrink: 0;
}

.toolbar-filename {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.toolbar-zoom-level {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  min-width: 36px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  user-select: none;
  display: none;
}
@media (min-width: 700px) {
  .toolbar-zoom-level { display: inline; }
}

/*
 * Hide filename and its adjacent divider on small screens.
 * The browser tab title already shows "veil - document.pdf"
 */
@media (max-width: 699px) {
  .toolbar-filename,
  .toolbar-filename-divider {
    display: none;
  }
}

.toolbar-nav {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

#page-info {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  min-width: 48px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  transition: background var(--transition);
}
@media (hover: hover) {
  #page-info:hover {
    background: var(--accent-subtle);
  }
}
#page-info:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 2px;
}
@media (min-width: 700px) {
  #page-info {
    font-size: var(--text-xs);
    min-width: 56px;
  }
}

#page-input {
  width: 36px;
  font-size: var(--text-2xs);
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--text-primary);
  background: var(--accent-border);
  border: 1px solid var(--accent-border-mid);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-1);
  outline: none;
}
#page-input:focus-visible {
  border-color: var(--accent-focus);
  box-shadow: 0 0 0 2px var(--accent-border-mid);
}
@media (min-width: 700px) {
  #page-input { font-size: var(--text-xs); }
}

#toolbar button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
  flex-shrink: 0;
}
@media (min-width: 700px) {
  #toolbar button {
    width: 32px;
    height: 32px;
  }
}

@media (hover: hover) {
  #toolbar button:hover:not(:disabled) {
    background: var(--accent-subtle);
    color: var(--text-primary);
  }
}

#toolbar button:active:not(:disabled) {
  background: var(--accent-highlight);
}

#toolbar button:disabled {
  opacity: 0.25;
  cursor: default;
}

#toolbar button:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 2px;
}

.toolbar-logo:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 2px;
  opacity: 1;
}


#toolbar button.toggle-active {
  color: var(--accent);
}

@media (hover: hover) {
  #toolbar button.toggle-active:hover {
    color: var(--accent-hover);
  }
}


/* --- READER LAYOUT --- */

#reader {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background: var(--bg-deep);
}


/* --- VIEWPORT --- */

#viewport {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
  /* Keep viewport below the fixed toolbar in stacking order.
     Without this, overflow:auto can create an implicit stacking
     context that blocks pointer events on the toolbar. */
  z-index: var(--z-viewport);

  /* Native scrollbar, visible on desktop and Android */
  scrollbar-width: thin;
  scrollbar-color: rgba(212, 163, 115, 0.25) transparent;
}

#viewport::-webkit-scrollbar {
  width: 6px;
}

#viewport::-webkit-scrollbar-track {
  background: transparent;
}

#viewport::-webkit-scrollbar-thumb {
  background: rgba(212, 163, 115, 0.25);
  border-radius: 3px;
}

#viewport::-webkit-scrollbar-thumb:hover {
  background: rgba(212, 163, 115, 0.4);
}


/* --- PAGE CONTAINER --- */

/*
 * The dark background (#1e1e1e) on both page-container and page-canvas
 * prevents a white flash when pages are evicted and re-rendered during
 * scroll. Without it, the canvas backing store is released (width=0)
 * and the browser shows the default transparent/white background for a
 * frame before the new render completes
 */
.page-container {
  position: relative;
  box-shadow: var(--shadow-page);
  border-radius: var(--radius-xs);
  line-height: 0;
  flex-shrink: 0;
  background: var(--page-canvas-bg);
}

.page-canvas {
  display: block;
  border-radius: var(--radius-xs);
  background: var(--page-canvas-bg);
}

.page-overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  border-radius: var(--radius-xs);
  display: none;
}

.page-overlay.overlay-visible {
  display: block;
}


/* --- DARK MODE FILTER --- */

/*
 * I chose 0.86 instead of 1.0 for the inversion strength because
 * full inversion produces harsh pure black (#000) and pure white
 * (#fff) which are uncomfortable for extended reading. At 0.86,
 * a white PDF background becomes a soft dark grey (~#242424) and
 * black text becomes an off-white (~#dbdbdb). The hue-rotate(180deg)
 * corrects the color shift that invert alone would cause.
 *
 * This filter is GPU-accelerated (applied by the browser's compositor,
 * not by JavaScript) so it costs zero main-thread time
 */
.page-canvas.dark-active {
  filter: invert(0.86) hue-rotate(180deg);
}


/* --- TEXT LAYER --- */

/*
 * The text layer sits on top of the canvas with invisible text
 * (color: transparent) positioned exactly over the rendered words.
 * The user sees the canvas but selects the invisible spans.
 *
 * I use display:flex + align-items:flex-start on the text layer
 * so each .text-line div shrinks to its content width. Without
 * this, Safari desktop extends the selection highlight to the
 * full page width because block-level divs inherit the parent's
 * width and WebKit paints selection on the entire block box.
 *
 * pointer-events: none on .text-line and auto on spans ensures
 * touch devices target the actual text spans, not the wrapper div.
 * This is a hardening measure for iOS selection behavior.
 *
 * white-space: pre on spans preserves trailing spaces that CSS
 * would normally collapse inside inline-block elements. Without
 * it, "the " followed by "quick" would copy as "thequick" because
 * the space at the end of the inline-block gets eaten
 */
.text-layer {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  line-height: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/*
 * Multi-column layout: flex-row wrapper keeps columns side by side
 * entirely in flow. No position:absolute, so the browser produces
 * smooth unbroken selection across header and columns.
 */
.columns-wrapper {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  width: 100%;
}

.text-column {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex-shrink: 0;
}

.text-line {
  white-space: nowrap;
  box-sizing: border-box;
  pointer-events: none;
}

.text-layer span {
  pointer-events: auto;
}

.text-layer span {
  color: transparent;
  font-family: sans-serif;
  vertical-align: top;
  box-sizing: border-box;
  white-space: pre;
}

/*
 * Selection color is standard blue, not amber. Jakob's Law: the user
 * expects blue selection because every other app uses blue. Amber
 * is reserved for UI elements (buttons, borders, accents). Using
 * amber for selection would feel "wrong" even if it matched the palette
 */
.text-layer span::selection,
.text-layer br::selection,
.text-line::selection {
  background: var(--selection);
}

/*
 * Darker selection for text inside images. Images typically have
 * light/white backgrounds where the standard selection is too
 * faint to see
 */
.ocr-image-region span::selection {
  background: rgba(107, 138, 205, 0.35);
}

/* Vertical OCR layer */
.vertical-ocr-layer {
  pointer-events: none;
}

.vertical-ocr-layer .ocr-image-region-rotated {
  pointer-events: none;
}

.vertical-ocr-layer .ocr-image-region-rotated span {
  pointer-events: none;
}

.ocr-image-region {
  pointer-events: auto;
}


/* --- LINK ANNOTATIONS --- */

.link-annot {
  display: block;
  border-radius: var(--radius-xs);
  cursor: pointer;
  user-select: none;
  text-decoration: none;
  transition: background var(--transition);
}

.link-annot:hover {
  background: rgba(212, 163, 115, 0.12);
}

.link-annot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  background: rgba(212, 163, 115, 0.12);
}


/* --- PAGE NUMBER LABEL --- */

.page-label {
  display: none;
}


/* --- ERROR BANNER --- */

#error-banner,
#info-banner {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  backdrop-filter: blur(12px);
  border-radius: var(--radius-pill);
  z-index: var(--z-banner);
  box-shadow: var(--shadow-overlay);
  max-width: 90vw;
}

#error-banner {
  background: rgba(42, 26, 26, 0.9);
  border: 1px solid rgba(200, 100, 100, 0.15);
}

#info-banner {
  background: rgba(42, 31, 26, 0.9);
  border: 1px solid var(--accent-border);
  transition: opacity 0.4s ease;
}

#error-message {
  font-size: var(--text-sm);
  color: var(--error-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#info-message {
  font-size: var(--text-sm);
  color: var(--accent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#error-dismiss {
  background: none;
  border: none;
  color: var(--error-text);
  font-size: var(--text-2xl);
  cursor: pointer;
  padding: 0 var(--space-1);
  line-height: 1;
  opacity: 0.7;
}

#error-dismiss:hover {
  opacity: 1;
}


/* --- EXPORT PROGRESS --- */

#export-progress {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  background: rgba(26, 21, 16, 0.9);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  z-index: var(--z-toolbar);
  box-shadow: var(--shadow-overlay);
}

.export-progress-bar {
  width: 200px;
  height: 4px;
  background: var(--accent-border);
  border-radius: var(--radius-xs);
  overflow: hidden;
}

.export-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  border-radius: var(--radius-xs);
  transition: width 200ms ease;
}


.export-progress-text {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

#export-cancel {
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: var(--text-3xl);
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
  line-height: 1;
  opacity: 0.6;
  transition: opacity var(--transition);
}

#export-cancel:hover {
  opacity: 1;
}


/* --- OCR LOADING INDICATOR --- */

/*
 * A warm amber light sweeps along the perimeter of a page or image
 * when the user tries to select text before OCR finishes. The key
 * UX insight: I show this only on-demand (when the user actually
 * tries to interact), not automatically. If the OCR finishes before
 * the user touches the page, they never see a loading indicator at
 * all. The system works silently in the background.
 *
 * The technique uses @property to register --ocr-angle as an
 * animatable custom property. This is the only way to smoothly
 * rotate a CSS gradient without JavaScript animation frames.
 * The conic-gradient creates a moving highlight, and mask-composite
 * (below) subtracts the content box to leave only a thin perimeter
 * ring of light
 */

@property --ocr-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

@keyframes ocr-sweep {
  to { --ocr-angle: 360deg; }
}

.ocr-loading::before {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: var(--radius-sm);
  background: conic-gradient(
    from var(--ocr-angle),
    transparent 0%,
    #C8894A 6%,
    #D4A373 12%,
    #C8894A 18%,
    transparent 24%
  );
  /* Mask trick: the gradient fills the entire area, but the mask
     subtracts the content box, leaving only a thin perimeter ring.
     The padding controls the ring thickness */
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  mask-composite: exclude;
  padding: var(--space-1);
  animation: ocr-sweep 3s linear infinite;
  z-index: 12;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.6s ease;
}

/* Full-page OCR (scanned docs): subtler to avoid distraction during reading */
.page-container.ocr-loading::before {
  opacity: 0.45;
}

/* Image OCR: thicker line + dark shadow for visibility on white backgrounds */
div.ocr-loading:not(.page-container)::before {
  padding: var(--space-1);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.5), inset 0 0 5px rgba(0, 0, 0, 0.15);
}

/* Completion flash: solid amber border holds 300ms, then fades out */
.ocr-loading.ocr-done::before {
  background: var(--accent);
  opacity: 0;
  transition: opacity 0.6s ease 0.3s;
}

/* Respect user motion preferences */
@media (prefers-reduced-motion: reduce) {
  .ocr-loading::before {
    animation: none;
    background: conic-gradient(
      from 0deg,
      rgba(212, 163, 115, 0.3) 0%,
      rgba(212, 163, 115, 0.3) 100%
    );
  }
}

/* Respect user motion preferences, toolbar, banners */
@media (prefers-reduced-motion: reduce) {
  #toolbar { transition: none; }
  #info-banner { transition: none; }
  .export-progress-fill { transition: none; }
  .link-annot { transition: none; }
}


/* --- ACCESSIBILITY --- */

@media (prefers-contrast: more) {
  #toolbar {
    border-color: var(--accent-border-mid);
  }
  .toolbar-divider {
    background: rgba(212, 163, 115, 0.25);
  }
  .toolbar-filename {
    color: var(--text-primary);
  }
  #page-info {
    color: var(--text-primary);
  }
  #toolbar button {
    color: var(--text-primary);
  }
  #toolbar button:disabled {
    opacity: 0.4;
  }
  #error-banner {
    border-color: rgba(200, 100, 100, 0.4);
  }
  #info-banner {
    border-color: rgba(212, 163, 115, 0.35);
  }
  .export-progress-text {
    color: var(--text-primary);
  }
  #viewport {
    scrollbar-color: rgba(212, 163, 115, 0.45) transparent;
  }
}


/* --- UTILITIES --- */

/*
 * Visually hidden but accessible, required for iOS Safari which
 * refuses to open file pickers for inputs with the HTML hidden
 * attribute. The input stays in the layout (technically visible
 * to WebKit) but is invisible and takes no space
 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* --- MOBILE LANDSCAPE --- */

/*
 * On phone screens held sideways, the viewport is very short
 * (~350px) but wide. Fit-to-page would shrink text to illegible
 * size. Instead, I fit to width and let the user scroll vertically
 * within each page, turning landscape into a natural magnifier.
 *
 * Tighter padding and reduced gap maximize the precious vertical
 * space. The toolbar is completely hidden in phone landscape
 * (see app.js isPhoneLandscape)
 */

/* Phone landscape: compact shadow */
@media (pointer: coarse) and (orientation: landscape) and (max-height: 500px) {
  .page-container {
    box-shadow: 0 1px 8px rgba(0, 0, 0, 0.3);
  }
}

/*
 * Tablet landscape: same fit-to-width rendering as phone,
 * but toolbar stays visible and more vertical space available
 */
@media (pointer: coarse) and (orientation: landscape) and (min-height: 501px) {
  .page-container {
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
  }
}


/* --- APP SHELL LOADER --- */

/*
 * Shown while IndexedDB deserializes the saved PDF on return
 * visits. Hardcoded in HTML for instant display from precache
 */

#app-loader {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-deep);
  z-index: var(--z-loader);
}

.app-loader-wordmark {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 48px;
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--accent);
  animation: loader-pulse 1.5s ease-in-out infinite;
}


@keyframes loader-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

[hidden] {
  display: none !important;
}