:root {
  --stage: #14171c;
  --stage-soft: #1c2027;
  --ink: #f4f5f7;
  --ink-dim: #9aa2ae;
  --accent: #cf4b04;
  --bar: rgba(20, 23, 28, 0.82);
  --radius: 8px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--stage);
  color: var(--ink);
  font: 15px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  overscroll-behavior: none;
}

.app {
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* ---- stage ---- */

.stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  /* CSS transforms (the flip's rotateY) never affect layout size per spec --
     only paint. But a page rotating edge-on paints well outside its own box,
     and some browsers reserve scrollbar space for real overflow more eagerly
     than others, so a stray sub-pixel layout difference we haven't hit in
     testing could still show one. This is the standard guard other
     StPageFlip integrations ship: clip the stage so nothing in it, however
     it gets there, can ever grow the document's scrollable area. */
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, var(--stage-soft) 0%, var(--stage) 70%);
}

/* Zoom is a real size increase on #book (see setZoom() in viewer.js), not a
   CSS transform: scale() -- transforms don't create real layout overflow
   (the same fact that made the flip's rotation harmless to scrolling), so a
   scaled book would have nothing for this viewport to scroll to. Only this
   inner element scrolls; .stage stays clipped, so zoom can never reintroduce
   the document-level scrollbar bug. */
.zoom-viewport {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.zoom-viewport.is-zoomed {
  overflow: auto;
}

/* The flip engine clamps the book to this element's box, so it must carry a
   real width AND height. Without an explicit height it has nothing to clamp
   against and the spread overflows the viewport. */
#book {
  width: 100%;
  height: 100%;
  touch-action: pan-y;
}

/* StPageFlip injects its own <style> tag at runtime (perspective: 2000px on
   .stf__block) after this stylesheet loads, so a same-specificity override
   here would lose the cascade tie. #book raises specificity enough to win
   regardless of injection order.
   At our page size, 2000px is close enough to the page width that the far
   edge (the one swinging through Z around the spine) blows up in projected
   height as it passes edge-on near 90 degrees -- real perspective math, not
   a bug, but tuned for a smaller page than ours. Pushing the distance out
   flattens the foreshortening curve so the page rotates instead of bulging. */
#book .stf__block {
  perspective: 9000px;
}

/* StPageFlip writes inline transforms onto these; only paint them. */
.page {
  background: #fff;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}

.page img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Pages fade in as their bytes land, so a fast flip never shows a white slab. */
  opacity: 0;
  transition: opacity 0.25s ease;
}

.page img.is-ready { opacity: 1; }

/* Hotspots ride on the page as ordinary DOM. This is the whole reason we use
   StPageFlip's HTML render mode instead of its canvas mode: a <video> or an
   <a> cannot exist inside a canvas-drawn page. */
/* Invisible by default -- a real link doesn't announce itself with a
   permanent box, and a page can carry over a dozen of these (every real
   link the source PDF has). A light tint on hover/focus is the only
   affordance, same as an ordinary web link. The video hotspot's own
   opaque poster image already covers this box entirely when not
   playing, so this same rule serves both hotspot types. */
.hotspot {
  position: absolute;
  border: 0;
  padding: 0;
  border-radius: 4px;
  cursor: pointer;
  background: transparent;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.hotspot:hover,
.hotspot:focus-visible {
  background: rgba(207, 75, 4, 0.14);
  box-shadow: inset 0 0 0 1px rgba(207, 75, 4, 0.55);
}

/* Video hotspots swap their poster for a live iframe on click (see
   openVideo() in viewer.js), so once playing they should read as an
   embedded player, not a marked-up hotspot. */
.hotspot.is-playing {
  background: transparent;
  box-shadow: none;
  cursor: default;
}

.hotspot-poster {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background-color: #0b0d10;
  background-size: cover;
  background-position: center;
}

.hotspot-poster::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.28);
}

.hotspot-badge {
  position: relative;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 18px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  transition: transform 0.15s ease;
}

.hotspot-video:hover .hotspot-badge { transform: scale(1.08); }

.hotspot-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---- toolbar ---- */

.bar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: var(--bar);
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(8px);
}

.tool-group {
  display: flex;
  align-items: center;
  gap: 6px;
  position: relative;
}

.zoom-label {
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
  min-width: 40px;
  text-align: center;
  font-size: 13px;
}

.bar .spacer { flex: 1 1 auto; }

.bar .title {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 34vw;
}

button.tool,
a.tool {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border-radius: var(--radius);
  padding: 7px 11px;
  font: inherit;
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background 0.15s ease, border-color 0.15s ease;
}

button.tool:hover:not(:disabled),
a.tool:hover { background: rgba(255, 255, 255, 0.13); border-color: rgba(255, 255, 255, 0.24); }

button.tool:disabled { opacity: 0.35; cursor: default; }

button.tool:focus-visible,
a.tool:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.counter {
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
  min-width: 82px;
  text-align: center;
}

/* ---- loading + errors ---- */

.boot {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  gap: 14px;
  align-content: center;
  color: var(--ink-dim);
  transition: opacity 0.4s ease;
}

.boot.is-hidden { opacity: 0; pointer-events: none; }

.spinner {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 4px solid rgba(255, 255, 255, 0.14);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }

.toast {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 12px);
  background: rgba(0, 0, 0, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: 9px 14px;
  border-radius: var(--radius);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.toast.is-shown { opacity: 1; transform: translate(-50%, 0); }

/* ---- share popover ---- */

.share-group { position: relative; }

.popover {
  position: absolute;
  bottom: calc(100% + 10px);
  right: 0;
  width: 260px;
  background: #1a1e24;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Same [hidden]-vs-display tie as .panel above: without this the popover
   would render (and swallow clicks) from first paint, not just when opened. */
.popover[hidden] {
  display: none;
}

.popover-item {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink);
  text-align: left;
  padding: 9px 10px;
  border-radius: 6px;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
  display: block;
}

.popover-item:hover,
.popover-item:focus-visible { background: rgba(255, 255, 255, 0.08); outline: none; }

.popover-embed {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin-top: 4px;
  padding: 8px 10px 4px;
}

.popover-embed label {
  display: block;
  font-size: 12px;
  color: var(--ink-dim);
  margin-bottom: 6px;
}

.popover-embed-row {
  display: flex;
  gap: 6px;
}

.popover-embed-row input {
  flex: 1 1 auto;
  min-width: 0;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 6px;
  color: var(--ink-dim);
  font: 12px/1.2 ui-monospace, monospace;
  padding: 6px 8px;
}

/* ---- grid + search panels ---- */

.panel {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: rgba(11, 13, 16, 0.97);
  backdrop-filter: blur(6px);
}

/* [hidden] and .panel{display:flex} are equal specificity, so without this
   the later-loaded rule here would silently win the tie and the "closed"
   panel would stay laid out (and clickable) under whatever's turning pages. */
.panel[hidden] {
  display: none;
}

.panel-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.panel-head h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  flex: 1 1 auto;
}

.panel-head input[type="search"] {
  flex: 1 1 auto;
  min-width: 0;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  padding: 9px 12px;
}

.panel-head input[type="search"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.grid {
  flex: 1 1 auto;
  overflow: auto;
  padding: 16px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 14px;
  align-content: start;
}

.grid-item {
  appearance: none;
  border: 2px solid transparent;
  background: #fff;
  border-radius: 6px;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.grid-item:hover,
.grid-item:focus-visible { border-color: var(--accent); transform: translateY(-2px); outline: none; }

.grid-item img {
  display: block;
  width: 100%;
  aspect-ratio: var(--page-aspect, 0.77);
  object-fit: cover;
  background: #f4f4f5;
}

.grid-item span {
  font-size: 12px;
  color: var(--stage);
  background: #fff;
  padding: 5px 0;
  text-align: center;
}

.results {
  flex: 1 1 auto;
  overflow: auto;
  padding: 8px;
}

.result-item {
  appearance: none;
  width: 100%;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: transparent;
  color: var(--ink);
  text-align: left;
  padding: 12px 10px;
  cursor: pointer;
  font: inherit;
}

.result-item:hover,
.result-item:focus-visible { background: rgba(255, 255, 255, 0.06); outline: none; }

.result-item .result-page {
  display: block;
  font-size: 12px;
  color: var(--accent);
  font-weight: 600;
  margin-bottom: 3px;
}

.result-item mark {
  background: var(--accent);
  color: #fff;
  border-radius: 2px;
  padding: 0 1px;
}

.results .empty {
  color: var(--ink-dim);
  padding: 20px 10px;
  text-align: center;
}

@media (max-width: 640px) {
  .stage { padding: 12px 8px; }
  .bar { gap: 6px; padding: 8px 10px; }
  .bar .title { display: none; }
  button.tool, a.tool { padding: 8px 10px; }
  .tool .label { display: none; }
  .popover { width: min(90vw, 280px); right: -8px; }
  .panel-head h2 { font-size: 14px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 10px; padding: 10px; }
}

/* ---------- authoring mode (slice 5) ---------- */

.authoring-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  padding: 8px 16px;
  background: var(--accent);
  color: #fff;
  font: 13px/1.4 system-ui, sans-serif;
  text-align: center;
}

.authoring-form {
  position: fixed;
  z-index: 60;
  width: 260px;
  padding: 12px;
  border-radius: var(--radius);
  background: var(--bar);
  backdrop-filter: blur(8px);
  color: var(--ink);
  font: 13px/1.4 system-ui, sans-serif;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}

.authoring-meta {
  margin: 0 0 8px;
  color: var(--ink-dim);
  font-size: 12px;
}

.authoring-form input {
  display: block;
  width: 100%;
  margin-bottom: 8px;
  padding: 6px 8px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  background: var(--stage-soft);
  color: var(--ink);
  font: inherit;
  box-sizing: border-box;
}

.authoring-error {
  margin: 0 0 8px;
  color: #ff8a65;
  font-size: 12px;
}

.authoring-row {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.authoring-row button {
  padding: 6px 10px;
  border: none;
  border-radius: 4px;
  font: inherit;
  cursor: pointer;
}

.authoring-cancel {
  background: transparent;
  color: var(--ink-dim);
}

.authoring-place {
  background: var(--accent);
  color: #fff;
}
