/* Camera to PDF. Scanner styles only; the kit supplies tokens, buttons, cards,
   nav, hero, disclosure and footer. Anything here that looks reusable belongs in
   tsw-kit instead, once a second site wants it. */

/* Accent tokens, per colour scheme.
 *
 * No single teal clears 4.5:1 as small text on both a white and a near-black
 * background: #0f766e is 5.47 on white and 3.58 on black, #0d9488 is the other
 * way round. The ink therefore differs by scheme, and both values clear.
 *
 * Lighthouse caught this where axe did not, because the two ran in different
 * colour schemes. A contrast ratio has to be checked against the background it
 * is actually painted on.
 */
:root {
  color-scheme: light dark;
  --tsw-accent-bg: #0f766e;
  --tsw-accent-on: #ffffff;
  --tsw-accent-ink: #0f766e;
  --tsw-accent-soft: #ccfbf1;
}

@media (prefers-color-scheme: dark) {
  :root {
    --tsw-accent-ink: #0d9488;
    --tsw-accent-soft: #134e4a;
  }
}

/* theme.css resets every canvas to height:auto, which fights a preview that has
   to keep a fixed aspect box. */
video,
canvas {
  height: auto;
  max-height: 60vh;
  object-fit: contain;
}

.tsw-grid {
  display: grid;
  gap: var(--tsw-space-lg);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.tsw-resolution {
  align-items: baseline;
  background: var(--tsw-surface-2);
  border: 1px solid var(--tsw-border);
  border-left-width: 4px;
  border-radius: var(--tsw-radius-md);
  display: flex;
  flex-wrap: wrap;
  gap: var(--tsw-space-xs) var(--tsw-space-sm);
  margin-block: var(--tsw-space-md);
  padding: var(--tsw-space-sm) var(--tsw-space-md);
}

.tsw-resolution[data-level="full"] { border-left-color: var(--tsw-ok-ink); }
.tsw-resolution[data-level="ok"] { border-left-color: var(--tsw-tech-ink); }
.tsw-resolution[data-level="low"] { border-left-color: var(--tsw-warn-ink); }

.tsw-note--warn {
  border-left: 4px solid var(--tsw-warn-ink);
  padding-left: var(--tsw-space-md);
}

.tsw-stage {
  background: var(--tsw-bg-sunken);
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-lg);
  margin-block: var(--tsw-space-md);
  overflow: hidden;
  padding: var(--tsw-space-md);
}

.tsw-stage video {
  background: var(--tsw-overlay);
  border-radius: var(--tsw-radius-md);
  display: none;
  width: 100%;
}

.tsw-stage[data-active="true"] video { display: block; }

.tsw-strip {
  display: grid;
  gap: var(--tsw-space-md);
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  list-style: none;
  margin-block: var(--tsw-space-md);
  padding: 0;
}

.tsw-scan-page {
  background: var(--tsw-surface);
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-md);
  display: flex;
  flex-direction: column;
  gap: var(--tsw-space-2xs);
  padding: var(--tsw-space-sm);
  position: relative;
}

.tsw-scan-page__thumb {
  background: var(--tsw-bg-sunken);
  border-radius: var(--tsw-radius-xs);
  display: block;
  transform: rotate(var(--page-turn, 0deg));
  width: 100%;
}

.tsw-scan-page__number {
  background: var(--tsw-accent-bg);
  border-radius: var(--tsw-radius-full);
  color: var(--tsw-accent-on);
  font-family: var(--tsw-font-mono);
  font-size: var(--tsw-text-xs);
  inset-block-start: var(--tsw-space-2xs);
  inset-inline-start: var(--tsw-space-2xs);
  line-height: 1.8;
  min-inline-size: 1.6rem;
  position: absolute;
  text-align: center;
}

.tsw-scan-page__size { color: var(--tsw-text-faint); font-size: var(--tsw-text-2xs); }

.tsw-scan-page__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tsw-space-3xs);
}

.tsw-scan-page__actions .tsw-btn { flex: 1 1 auto; }

.tsw-options {
  display: grid;
  gap: var(--tsw-space-md);
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  margin-block: var(--tsw-space-lg);
}

/* The kit's form styles are scoped to form[is="tsw-form"], which this is not:
   it never submits anywhere, so it carries no form machinery. */
.tsw-field { display: flex; flex-direction: column; gap: var(--tsw-space-3xs); }
.tsw-field label { color: var(--tsw-text-muted); font-size: var(--tsw-text-sm); }
.tsw-field select,
.tsw-field input[type="text"],
.tsw-field input[type="number"] {
  background: var(--tsw-surface);
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-sm);
  color: var(--tsw-text);
  font: inherit;
  padding: var(--tsw-space-xs) var(--tsw-space-sm);
}

.tsw-field--check { flex-direction: row; gap: var(--tsw-space-sm); }
.tsw-field--check input { margin-block-start: 0.25em; }
.tsw-field--check label { color: var(--tsw-text); font-size: var(--tsw-text-sm); }

.tsw-status {
  color: var(--tsw-text-muted);
  min-block-size: 1.5em;
}

.tsw-status[data-tone="error"] { color: var(--tsw-danger-ink); }

.tsw-pill-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tsw-space-xs);
  list-style: none;
  padding: 0;
}

.tsw-pill-list li {
  background: var(--tsw-surface-2);
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-full);
  font-size: var(--tsw-text-sm);
  padding: var(--tsw-space-3xs) var(--tsw-md);
}

.tsw-use-case dl {
  display: grid;
  gap: var(--tsw-space-xs) var(--tsw-space-md);
  grid-template-columns: max-content 1fr;
}

.tsw-use-case dt { color: var(--tsw-text-muted); font-size: var(--tsw-text-sm); }
.tsw-use-case dd { margin: 0; }

/* House ad.
 *
 * A promotion for our own work, not a network ad. Two rules it has to keep:
 *
 * 1. It must not look like a button. Google's publisher policies prohibit ads
 *    implemented in a way that might be mistaken for navigation or download
 *    links, and the done screen puts this above "Scan another document". The
 *    link is therefore deliberately unstyled as a button.
 * 2. It must be labelled. A promotional block that reads as editorial content
 *    is the other half of the same policy problem.
 *
 * When AdSense is wired in, this markup is what gets replaced by the network's
 * unit. Keeping the label means the block is still distinguishable.
 */
.tsw-ad {
  background: var(--tsw-surface-2);
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-lg);
  margin-block: var(--tsw-space-2xl);
  padding: var(--tsw-space-md) var(--tsw-space-lg);
}

.tsw-ad__label {
  color: var(--tsw-text-faint);
  font-family: var(--tsw-font-mono);
  font-size: var(--tsw-text-2xs);
  letter-spacing: 0.08em;
  margin: 0 0 var(--tsw-space-3xs);
  text-transform: uppercase;
}

.tsw-ad__body {
  color: var(--tsw-text-muted);
  font-size: var(--tsw-text-sm);
  margin: 0;
  max-width: 46rem;
}

.tsw-ad__body a {
  color: var(--tsw-accent-ink);
  text-underline-offset: 0.2em;
  white-space: nowrap;
}

/* House ads must not use .tsw-btn, or they read as app controls. This asserts
   it, so the mistake is caught in review rather than by AdSense. */
.tsw-ad :is(a, button) {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: underline;
}

/* The scanner: a full-screen layer, not a section.
 *
 * Two things here are load-bearing and were found the hard way.
 *
 * 1. `viewport-fit=cover` in the viewport meta is what makes env(safe-area-inset-*)
 *    return anything at all. Without it the insets are 0px and a full-screen dialog
 *    sits under the notch and the home indicator.
 *
 * 2. `100dvh`, never `100vh` or `100lvh`. With viewport-fit=cover and Safari's UI
 *    set to "Top", those report wrong heights while the safe-area values stay at
 *    zero, so there is nothing to correct with. WebKit #315945, open since May 2026.
 *    `100svh` is the documented-safe fallback.
 */

.tsw-launch {
  margin-block: var(--tsw-space-lg);
  max-width: 42rem;
}

.tsw-launch__copy {
  color: var(--tsw-text-muted);
}

.tsw-scanner {
  border: 0;
  height: 100vh;
  height: 100svh;
  height: 100dvh;
  inset: 0;
  margin: 0;
  max-height: none;
  max-width: none;
  padding: 0;
  width: 100%;
}

.tsw-scanner::backdrop {
  background: var(--tsw-overlay);
}

.tsw-scanner__frame {
  background: var(--tsw-bg);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  padding-block-start: env(safe-area-inset-top, 0px);
}

.tsw-scanner__bar {
  align-items: center;
  border-block-end: 1px solid var(--tsw-border);
  display: grid;
  gap: var(--tsw-space-sm);
  grid-template-columns: 2.75rem 1fr auto;
  padding: var(--tsw-space-xs) var(--tsw-space-sm);
  padding-inline: max(var(--tsw-space-sm), env(safe-area-inset-left, 0px));
  padding-inline-end: max(var(--tsw-space-sm), env(safe-area-inset-right, 0px));
}

.tsw-scanner__title {
  font-weight: 600;
  margin: 0;
  text-align: center;
}

.tsw-scanner__count {
  color: var(--tsw-text-muted);
  font-size: var(--tsw-text-sm);
  margin: 0;
}

.tsw-iconbtn {
  align-items: center;
  background: none;
  border: 1px solid var(--tsw-border);
  border-radius: var(--tsw-radius-full);
  color: inherit;
  cursor: pointer;
  display: inline-flex;
  height: 2.75rem;
  justify-content: center;
  padding: 0;
  width: 2.75rem;
}

.tsw-scanner__pane {
  min-height: 0;
  overflow-y: auto;
  padding: var(--tsw-space-sm);
  padding-inline: max(var(--tsw-space-sm), env(safe-area-inset-left, 0px));
  padding-inline-end: max(var(--tsw-space-sm), env(safe-area-inset-right, 0px));
}

/* Capture --------------------------------------------------------------- */

.tsw-viewfinder {
  align-items: center;
  background: #000;
  border-radius: var(--tsw-radius-md);
  display: flex;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
  position: relative;
}

.tsw-viewfinder video {
  display: block;
  max-height: 100%;
  object-fit: contain;
  width: 100%;
}

/* A rectangle to align the page with. Moving the work to whoever is already
   aiming the camera gets most of the benefit of edge detection for a fraction of
   the complexity, and it degrades to "line it up yourself" on any surface. */
.tsw-guide {
  border: 2px solid rgb(255 255 255 / 0.85);
  border-radius: var(--tsw-radius-xs);
  inset: 12%;
  pointer-events: none;
  position: absolute;
  transition: border-color 160ms linear;
}

.tsw-guide[data-steady="true"] {
  border-color: var(--tsw-accent-ink);
}

.tsw-guide__corner {
  border: 3px solid rgb(255 255 255 / 0.95);
  height: 1.5rem;
  position: absolute;
  width: 1.5rem;
}

.tsw-guide__corner--tl { border-inline-end: 0; border-block-end: 0; inset-block-start: -2px; inset-inline-start: -2px; }
.tsw-guide__corner--tr { border-inline-start: 0; border-block-end: 0; inset-block-start: -2px; inset-inline-end: -2px; }
.tsw-guide__corner--bl { border-inline-end: 0; border-block-start: 0; inset-block-end: -2px; inset-inline-start: -2px; }
.tsw-guide__corner--br { border-inline-start: 0; border-block-start: 0; inset-block-end: -2px; inset-inline-end: -2px; }

/* Controls -------------------------------------------------------------- */

.tsw-scanner__actions {
  background: var(--tsw-surface);
  border-block-start: 1px solid var(--tsw-border);
  padding-block: var(--tsw-space-sm);
  padding-block-end: calc(var(--tsw-space-sm) + env(safe-area-inset-bottom, 0px));
  padding-inline: max(var(--tsw-space-sm), env(safe-area-inset-left, 0px));
  padding-inline-end: max(var(--tsw-space-sm), env(safe-area-inset-right, 0px));
}

.tsw-scanner__row {
  align-items: center;
  display: flex;
  gap: var(--tsw-space-sm);
  justify-content: center;
  margin: 0;
}

.tsw-scanner__row[hidden] {
  display: none;
}

/* The shutter is a real button, wide enough to hit, and never adjacent to an ad.
   An ad near a shutter is the single most likely way to earn an invalid-click
   strike, which is why the done screen is the only pane carrying one. */
.tsw-shutter {
  background: var(--tsw-surface-3);
  border: 3px solid var(--tsw-border-strong);
  border-radius: var(--tsw-radius-full);
  cursor: pointer;
  flex: 1 1 auto;
  height: 3.5rem;
  max-width: 22rem;
}

.tsw-shutter:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* Review ---------------------------------------------------------------- */

.tsw-scanner__total {
  font-size: var(--tsw-text-sm);
}

/* Done ------------------------------------------------------------------ */

.tsw-done {
  display: flex;
  flex-direction: column;
  gap: var(--tsw-space-md);
  margin-inline: auto;
  max-width: 32rem;
  padding-block: var(--tsw-space-lg);
  text-align: center;
}

.tsw-done .tsw-ad {
  margin-block-start: var(--tsw-space-md);
  text-align: start;
}

/* On a wide screen the scanner is a centred column rather than edge to edge, so
   the shutter stays reachable and the preview is not absurdly large. */
@media (min-width: 48rem) {
  .tsw-scanner__frame {
    margin-inline: auto;
    max-width: 44rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tsw-guide { transition: none; }
}
