:root {
  --bg: #0a0f0a;
  --bg-rgb: 10, 15, 10;
  --panel-bg: #0f1a10;
  --grid: #1a2e1c;
  --accent: #3ef27a;
  --accent-rgb: 62, 242, 122;
  --text: #d6ffe0;
  --text-dim: #6b9a78;
  --orange: #ffb347;
  --orange-rgb: 255, 179, 71;
  --red: #ff5d5d;
  --font: 'IBM Plex Mono', monospace;
}
* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  overflow-x: hidden;
}
.app {
  max-width: 520px;
  margin: 0 auto;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* viewport-fit=cover lets the page draw under a notch/dynamic island/status bar —
     env(safe-area-inset-*) reserves room for it instead of letting the header sit
     underneath, and falls back to the plain value on anything that doesn't support it. */
  padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right))
    max(14px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

/* Everything between the header and the footer. flex:1 + min-height:0 lets this
   shrink below its content's natural height on short viewports instead of
   overflowing .app. The pages-bar/stage/hint-text inside keep their normal top
   position and size (unaffected) — .controls-area below is the nested flex:1 child
   that actually centers the buttons in whatever space is left under the stage. */
.scan-area {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Wraps the button rows (and the result panel) so they center vertically in the
   space between the stage/hint-text above and the footer below, instead of either
   sitting flush under the stage (default) or flush against the footer. Nested
   flex:1 inside .scan-area, not on .scan-area itself, specifically so the stage
   above stays exactly where it was — only this block's contents get repositioned. */
.controls-area {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Spacing between whichever of this block's children are visible together
     (#live-controls + #live-controls-secondary) — using gap here instead of a
     margin on the children themselves, so a leading/trailing margin doesn't throw
     off the centering above (a margin on the first or last visible child would
     count on one side only, making the leftover space split unevenly). 18px here
     matches #live-controls' own 18px column gap exactly (measured edge-to-edge,
     shutter-bottom to gallery-btn-top vs. switch-cam-right to shutter-left) —
     picked to make the vertical gap under the shutter match the horizontal gaps
     beside it, so the 4 buttons read as evenly spaced in both directions instead
     of tightly packed on top with a much smaller gap below. */
  gap: 18px;
}

.app-footer {
  flex: none;
  margin-top: 9px;
  text-align: center;
}
.app-footer a {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.62rem;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.app-footer a:hover { color: var(--accent); }
.app-footer svg { width: 12px; height: 12px; }
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
}
.brand-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
header h1 {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 2px;
  color: var(--accent);
  margin: 0;
}
#status-pill {
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 4px;
  border: 1px solid var(--grid);
  background: var(--panel-bg);
  color: var(--text-dim);
  transition: color .2s, border-color .2s, background-color .2s;
}
#status-pill.locked {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.1);
}
#status-pill.searching {
  color: var(--orange);
  border-color: var(--orange);
  background: rgba(var(--orange-rgb), 0.1);
}

.stage {
  position: relative;
  /* Full container width on tall-enough screens (min() picks 100% there), but shrinks
     proportionally — width AND height together, aspect-ratio intact — once the
     viewport is short enough that a full-width 3:4 box wouldn't leave room for
     everything below it (header, hint text, controls, and the pages-bar when a
     multi-page session is active). A plain `max-height` here would just crop the
     video instead of shrinking the box, since width would stay pinned at 100% —
     confirmed empirically, not assumed. 52dvh trims a little even on a ~844px-tall
     phone (~14px narrower than full width, harmless), but is the value that keeps
     ~20px of clearance below the controls at the shortest realistic viewport
     (iPhone SE-class, 667px tall, with the pages-bar showing) — measured via
     Playwright, not eyeballed. A less aggressive factor left that case overflowing. */
  width: min(100%, calc(52dvh * 0.75));
  aspect-ratio: 3 / 4;
  margin: 0 auto;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--grid);
}
video, canvas.layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
video { transform: scaleX(1); }
#overlay { pointer-events: none; }

.corner-hint {
  position: absolute;
  inset: 10%;
  border-radius: 4px;
  pointer-events: none;
  opacity: 0.35;
}
.corner-hint span {
  position: absolute;
  width: 22px; height: 22px;
  border-color: var(--text-dim);
  border-style: solid;
  border-width: 0;
}
.corner-hint .tl { top:0; left:0; border-top-width:2px; border-left-width:2px; }
.corner-hint .tr { top:0; right:0; border-top-width:2px; border-right-width:2px; }
.corner-hint .bl { bottom:0; left:0; border-bottom-width:2px; border-left-width:2px; }
.corner-hint .br { bottom:0; right:0; border-bottom-width:2px; border-right-width:2px; }

.sweep {
  position: absolute;
  left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  top: 0;
  opacity: 0;
  animation: sweep 2.6s ease-in-out infinite;
}
#stage-live.searching .sweep { opacity: 0.8; }
@keyframes sweep {
  0% { top: 6%; opacity: 0; }
  15% { opacity: .8; }
  50% { top: 94%; opacity: .8; }
  65% { opacity: 0; }
  100% { top: 6%; opacity: 0; }
}

.controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 18px;
}
/* Grid instead of flex here specifically so #shutter stays dead-center regardless of
   how many icon buttons end up on each side — the two 1fr columns are always equal
   width, which a plain flex row can't guarantee once the two sides hold different
   numbers of buttons (or even just to stay correct if that changes again later). */
#live-controls {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 18px;
}
.controls-side {
  display: flex;
  gap: 18px;
}
#live-controls .controls-side:first-child { justify-content: flex-end; }
#live-controls .controls-side:last-child { justify-content: flex-start; }

/* Gallery button lives on its own row, centered under the shutter, rather than
   grouped with the other icon buttons — keeps live-controls symmetric (1 button each
   side) instead of lopsided. */
.controls-secondary {
  display: flex;
  justify-content: center;
}
button {
  font-family: inherit;
  border: none;
  cursor: pointer;
  color: var(--text);
  transition: transform .12s ease, opacity .12s ease, border-color .15s ease, color .15s ease, background-color .15s ease;
}
button:active { transform: scale(0.96); }
button:disabled { opacity: 0.35; cursor: not-allowed; }

#shutter {
  width: 68px; height: 68px;
  border-radius: 50%;
  background: var(--panel-bg);
  border: 3px solid var(--accent);
  position: relative;
}
#shutter::after{
  content: "";
  position: absolute; inset: 8px;
  border-radius: 50%;
  background: var(--grid);
  transition: background .15s;
}
#shutter.ready::after { background: var(--accent); }

#adjust-confirm {
  width: 68px; height: 68px;
  border-radius: 50%;
  background: var(--accent);
  border: 3px solid var(--accent);
  color: #06170a;
  display: flex; align-items: center; justify-content: center;
}
#adjust-confirm svg { width: 28px; height: 28px; display: block; }
#adjust-overlay { touch-action: none; cursor: grab; }
#adjust-magnifier {
  position: absolute;
  width: 120px; height: 120px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
  display: none;
  pointer-events: none;
  z-index: 5;
}

.icon-btn {
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--panel-bg);
  border: 1px solid var(--text-dim);
  color: var(--text-dim);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.1rem;
}
.icon-btn svg { width: 1.1em; height: 1.1em; display: block; }
.icon-btn:hover { border-color: var(--accent); color: var(--accent); }

.hint-text {
  text-align: center;
  color: var(--text-dim);
  /* 0.58rem + no letter-spacing is the largest size that keeps all three hint
     messages (js/detection.js) on a single line at every tested width down to
     320px — confirmed empirically: letter-spacing alone was enough to push the
     longest message ("Apunta a un documento...") onto 2 lines as small as
     0.72rem, but removing it let sizes as large as ~0.66rem still fit at 375px+
     (just not at 320px). Don't reintroduce letter-spacing here without re-checking
     — it costs more single-line headroom than font-size itself does. */
  font-size: 0.58rem;
  margin-top: 6px;
  /* Fixed at exactly the (now single-line, ~13px) rendered height, same reasoning
     as before this size change: a min-height would let the box grow if a message
     ever did wrap, and #controls-area centering in the space below would visibly
     shift the buttons every time that happened (see the v0.15.3 note in
     CLAUDE.md). Centering a shorter message inside this fixed box (instead of
     leaving it top-aligned) is what display:flex + align-items:center is for. */
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Result view */
.result-panel {
  display: none;
  flex-direction: column;
  gap: 14px;
}
.result-panel.visible { display: flex; }
#stage-live.hidden, #stage-adjust.hidden { display: none; }

#result-canvas-wrap {
  background: var(--panel-bg);
  border: 1px solid var(--grid);
  border-radius: 8px;
  padding: 10px;
  display: flex;
  justify-content: center;
}
#result-canvas-wrap canvas {
  max-width: 100%;
  max-height: 44dvh;
  border-radius: 4px;
}

.mode-toggle {
  display: flex;
  background: var(--panel-bg);
  border: 1px solid var(--grid);
  border-radius: 6px;
  padding: 3px;
  gap: 3px;
}
.mode-toggle button {
  flex: 1;
  background: transparent;
  padding: 8px 0;
  border-radius: 4px;
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.mode-toggle button.active {
  background: var(--accent);
  color: #06170a;
  font-weight: 600;
}

.result-actions {
  display: flex;
  gap: 8px;
}
.result-actions button {
  flex: 1;
  padding: 13px 0;
  border-radius: 4px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.3px;
}
#retake-btn, #adjust-again-btn {
  background: var(--panel-bg);
  border: 1px solid var(--grid);
  color: var(--text);
}
#retake-btn:hover, #adjust-again-btn:hover { border-color: var(--accent); }
#add-page-btn, #download-btn { background: var(--accent); border: 1px solid var(--accent); color: #06170a; }

#loading-overlay {
  position: fixed; inset: 0;
  background: var(--bg);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 12px;
  font-size: 0.85rem;
  color: var(--text-dim);
  z-index: 20;
}
#loading-overlay.hidden { display: none; }
.spinner {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 2px solid var(--grid);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

#camera-priming {
  position: fixed; inset: 0;
  background: var(--bg);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 14px;
  padding: 32px;
  text-align: center;
  z-index: 20;
}
#camera-priming.hidden { display: none; }
.priming-icon { width: 56px; height: 56px; color: var(--accent); }
#camera-priming h2 {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--text);
  margin: 0;
}
#camera-priming p {
  font-size: 0.82rem;
  color: var(--text-dim);
  max-width: 320px;
  line-height: 1.5;
  margin: 0;
}
#camera-priming-btn {
  margin-top: 6px;
  padding: 13px 32px;
  border-radius: 4px;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #06170a;
  font-size: 0.88rem;
  font-weight: 600;
}
.priming-error { color: var(--red); }

.update-banner {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  display: none;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 16px max(10px, env(safe-area-inset-bottom));
  background: var(--panel-bg);
  border-top: 1px solid var(--accent);
  color: var(--text);
  font-size: 0.8rem;
}
.update-banner:not([hidden]) { display: flex; }
.update-banner button {
  padding: 6px 16px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  background: var(--accent);
  color: #06170a;
  font-size: 0.78rem;
  font-weight: 600;
  flex-shrink: 0;
}

/* Multi-page session bar: shown whenever state.pages has at least one saved page,
   regardless of which of the three stages (live/adjust/result) is currently active —
   unlike stage-specific controls, it's a sibling of all three, not toggled by ui.js. */
.pages-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  /* fit-content + centered instead of stretching the full .app width — with
     typically just a couple of small thumbnails plus the count/button, a
     full-width bar left a large empty gap in the middle. max-width caps it back
     to 100% for the rare case of many thumbnails pushing past the container. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 8px;
  background: var(--panel-bg);
  border: 1px solid var(--grid);
  border-radius: 8px;
}
.pages-bar.hidden { display: none; }
.pages-thumbs {
  display: flex;
  gap: 5px;
  overflow-x: auto;
  /* Caps how wide the thumbnail strip alone can grow before scrolling internally,
     so a many-page session scrolls its thumbnails instead of stretching the whole
     bar (and therefore the empty gap next to it) edge-to-edge again. */
  max-width: 160px;
}
.page-thumb {
  position: relative;
  flex: none;
  width: 22px;
  height: 30px;
  border-radius: 3px;
  overflow: hidden;
  border: 1px solid var(--grid);
}
.page-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.page-thumb-remove {
  position: absolute;
  top: 0; right: 0;
  width: 14px; height: 14px;
  background: rgba(10, 15, 10, 0.85);
  color: var(--red);
  font-size: 10px;
  line-height: 1;
  border-radius: 0 0 0 4px;
  padding: 0;
}
.pages-bar-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  flex: none;
}
#pages-count {
  font-size: 0.64rem;
  color: var(--text-dim);
  white-space: nowrap;
}
#finish-pdf-btn {
  padding: 4px 10px;
  border-radius: 4px;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #06170a;
  font-size: 0.68rem;
  font-weight: 600;
  white-space: nowrap;
}
