/* ==========================================================================
   Payable — viewer.css. Every style the document viewer (js/viewer.js) needs.

   Split out of inline styles as part of the T1 viewer rebuild: the pane now
   has real states (rail shown/hidden, full screen, skeleton, dragging) and
   state styling as string-concatenated style attributes is how the old pane
   drifted. Loaded from index.html after app.css; it uses app.css's .btn
   family and nothing else from it.

   COLOUR RULE — same as app.css: every colour comes from tokens.css. No
   literal hex. Dark mode therefore works by construction (tokens.css swaps
   the custom properties under [data-theme="dark"]). The rgba(var(--*-rgb),α)
   form is the sanctioned token-derived translucency app.css already uses.

   MARKUP CONTRACT (owned by viewer.js — documented here so nobody reverse-
   engineers it):

   .viewerhost   The MOUNT invoice.js hands to mountViewer(). The viewer adds
                 this class itself and strips the mount's inline height —
                 answering the walkthrough's defining complaint ("puts the
                 invoice in a small box in the middle"): the pane takes the
                 full available column height and sticks while the right
                 column scrolls. Height is a custom property (--viewer-h) so
                 the keying lane's rebuilt layout can retune it without
                 touching this file.

   #viewerbig    A body-level host the pane MOVES INTO for full screen (both
                 the Fullscreen API path and the fixed-overlay maximize
                 fallback land here). On <body>, outside anything a screen
                 re-render wipes — that placement is what lets a data refresh
                 run underneath an open full-screen viewer. z-index sits above
                 the action bar (60) and below nothing that matters: the
                 shared #toasts/#popover/#modalwrap hosts come after it in the
                 DOM and stay on top.

   .docpane      The pane itself: .docbar (toolbar) / .docbody (.docrail +
                 .docport) / .docfoot. Inside .docport: .docstage (transform-
                 positioned; sized inline to the raster's natural pixels) with
                 .docimg, .docskel, and .evhost holding the .evbox buttons
                 (positioned inline in PERCENT — normalized evidence coords
                 are data, not styling). .docfail is the honest failure card;
                 .docparked is what's left in the inline mount while the pane
                 is off in #viewerbig.
   ========================================================================== */


/* ===== the mount ===== */
.viewerhost{
  position:sticky;top:8px;
  height:var(--viewer-h, calc(100vh - 150px));
  min-height:420px;
}
/* Single-column layouts (the invoice grid collapses under 1180px — app.css):
   a sticky viewport-height pane would bury the keying fields below the fold,
   so the pane becomes a normal block at a workable height. */
@media (max-width:1180px){
  .viewerhost{position:static;height:min(70vh, 640px);}
}

/* ===== full screen / maximize host ===== */
#viewerbig{display:none;}
#viewerbig.on{
  display:block;position:fixed;inset:0;z-index:70;
  background:var(--bg);
}
#viewerbig.on .docpane{height:100vh;border:0;border-radius:0;}

/* ===== the pane ===== */
.docpane{
  display:flex;flex-direction:column;height:100%;min-height:0;
  background:var(--surface);
}

/* toolbar */
.docbar{
  display:flex;align-items:center;gap:5px;flex-wrap:wrap;
  padding:6px 8px;border-bottom:1px solid var(--line);flex:0 0 auto;
}
.docbar .dspacer{flex:1 1 auto;}
.docbar .dsep{width:1px;align-self:stretch;background:var(--line);margin:3px 2px;}
.docbar .dpage{
  font-size:12px;color:var(--muted);min-width:82px;text-align:center;white-space:nowrap;
}
.docbar .dzoom{
  font-size:11px;color:var(--faint);font-family:var(--mono);
  min-width:44px;text-align:center;
}
/* The active fit mode (and an active full-screen toggle) is marked, so "which
   zoom am I in" is answered by looking, not by experimenting — the hh2 zoom
   fights started with a viewer that never said. */
.docbar .btn.on{
  background:var(--accent-soft);color:var(--accent-ink);
  box-shadow:inset 0 0 0 1px var(--accent);
}

/* Document-toolbar tools (T6) — caller-owned buttons (Notes / History /
   Mark up) rendered by the viewer on hh2's document strip. The badge is
   hh2's "(2)" count after the label; the alert dot is its red "(!)". A
   pressed toggle reuses .btn.on above. */
.dtools{display:inline-flex;align-items:center;gap:4px;}
.dtool .dtbadge{font-family:var(--mono);font-size:10.5px;font-weight:400;color:var(--muted);}
.dtool.on .dtbadge{color:inherit;}
.dtool .dtalert{display:inline-flex;align-items:center;justify-content:center;
  width:14px;height:14px;border-radius:50%;flex:none;
  background:var(--rej);color:var(--onaccent);font-size:10px;font-weight:800;}
:root[data-theme="dark"] .dtool .dtalert{color:var(--sidebar);}

/* body: rail + port */
.docbody{display:flex;flex:1 1 auto;min-height:0;}

/* ===== the thumbnail rail ===== */
.docrail{
  flex:0 0 78px;min-height:0;overflow-y:auto;overflow-x:hidden;
  border-right:1px solid var(--line);background:var(--surface-2);
  padding:6px;display:flex;flex-direction:column;gap:6px;
}
.docrail[hidden]{display:none;}
.thumb{
  position:relative;display:block;width:100%;flex:0 0 auto;
  border:1px solid var(--line);border-radius:4px;background:var(--surface);
  padding:0;cursor:pointer;overflow:hidden;
}
/* The tile is sized by aspect-ratio (inline, from the recorded page dims)
   BEFORE its image arrives — a rail that reflows as thumbnails land is
   layout shift, the S3 anti-pattern. */
.thumb img{
  display:block;width:100%;height:100%;object-fit:contain;
  background:var(--surface);
}
.thumb .thn{
  position:absolute;right:3px;bottom:3px;
  font-size:9.5px;line-height:14px;font-family:var(--mono);
  color:var(--tag-ink);background:var(--tag-bg);
  border-radius:3px;padding:0 4px;
}
.thumb:hover{border-color:var(--line-strong);}
.thumb.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--highlight-ring);}
.thumb.on .thn{background:var(--accent);color:var(--onaccent);}

/* ===== the port (the viewport the page moves inside) ===== */
.docport{
  position:relative;overflow:hidden;flex:1 1 auto;min-width:0;min-height:0;
  background:var(--canvas);cursor:grab;touch-action:none;outline:none;
}
.docport.dragging{cursor:grabbing;}
/* Keyboard reach (PgUp/PgDn/F) needs focus; say so quietly when the keyboard
   put it there, and not at all for a mouse click. */
.docport:focus-visible{box-shadow:inset 0 0 0 2px var(--highlight-ring);}

.docstage{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform;}
.docimg{
  display:block;user-select:none;background:var(--surface);
  box-shadow:0 1px 10px rgba(var(--shadow-rgb),.28);
}
.evhost{position:absolute;inset:0;}

/* ===== the loading skeleton ===== */
/* Covers the stage — which already holds its final footprint from the
   recorded page dims — so a loading page is a shimmering sheet in exactly
   the right place, never a blank white card and never a reflow (S3). */
.docskel{position:absolute;inset:0;}
.docskel[hidden]{display:none;}
.docskel{
  background:linear-gradient(100deg,
    var(--surface-2) 35%, var(--track-bg) 50%, var(--surface-2) 65%);
  background-size:220% 100%;
  animation:docshimmer 1.1s linear infinite;
}
@keyframes docshimmer{
  from{background-position:130% 0;}
  to{background-position:-90% 0;}
}
@media (prefers-reduced-motion:reduce){
  .docskel{animation:none;background:var(--surface-2);}
}

/* ===== evidence boxes ===== */
/* Position (left/top/width/height in %) is inline — it is the normalized
   evidence rectangle, data not design. Appearance lives here. */
.evbox{
  position:absolute;padding:0;border-radius:2px;cursor:pointer;
  border:1px solid rgba(var(--accent-rgb),.45);
  background:rgba(var(--accent-rgb),.07);
}
.evbox:hover{border-color:rgba(var(--accent-rgb),.85);}
.evbox.on{
  border:2px solid var(--attn);
  background:rgba(var(--accent-rgb),.20);
  box-shadow:0 0 0 3px var(--highlight-ring);
}

/* ===== the honest failure card ===== */
.docfail{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  padding:18px;
}
.docfail[hidden]{display:none;}
.docfail .dfcard{
  max-width:360px;text-align:left;
  background:var(--surface);border:1px solid var(--line);border-radius:10px;
  padding:14px 16px;font-size:13px;color:var(--ink);
}
.docfail .dfcard b{display:block;margin-bottom:4px;}
.docfail .dfwhy{font-size:12px;color:var(--muted);line-height:1.45;}
.docfail .dfbtns{margin-top:10px;display:flex;gap:8px;}

/* ===== footer ===== */
.docfoot{
  flex:0 0 auto;padding:5px 9px;border-top:1px solid var(--line);
  font-size:11px;color:var(--faint);min-height:24px;
}

/* ===== the annotation layer (T2 — js/annotate.js) ===== */
/* .antlayer sits INSIDE .docstage, after .evhost, so marks paint over the
   evidence boxes and inherit the stage transform: a strike is ink on the
   paper and must zoom/pan with it. Position rectangles are inline in PERCENT
   (normalized bboxes — data, not design), exactly like the evidence boxes.
   Font sizes in here are RASTER pixels on purpose: at the ~1275px-wide
   letter raster and a typical 50% fit they read at ~13px on screen, and they
   grow with the page under zoom the way handwriting on the scan would.
   The layer ships pointer-events:none — the viewer's pan/click behaviour is
   untouched until annotate.js arms a tool. */
.antlayer{position:absolute;inset:0;pointer-events:none;}
.antlayer.arm{pointer-events:auto;cursor:crosshair;}
.antlayer.arm-erase{pointer-events:auto;cursor:pointer;}

.antmark{position:absolute;box-sizing:border-box;pointer-events:none;}
/* the red-pen strike: a translucent box with a stroke through the middle */
.antstrike{
  border:2px solid rgba(var(--rej-rgb),.65);border-radius:3px;
  background:rgba(var(--rej-rgb),.07);
}
.antstrike::after{
  content:"";position:absolute;left:-1.5%;right:-1.5%;top:50%;
  border-top:4px solid var(--rej);
  transform:translateY(-50%) rotate(-1.4deg);
}
/* a draft being drawn — same ink, visibly not yet saved */
.antmark.antdraft{border-style:dashed;}
.antmark.antdraft::after{opacity:.55;}
/* a dropped note: a small red flag box; the words carry the meaning */
.antnote{
  border:2px solid rgba(var(--rej-rgb),.8);border-radius:3px;
  background:rgba(var(--rej-rgb),.35);
}
/* the written-in text (a note body, or a strike's corrected value): to the
   right of the mark, red pen on a paper-coloured veil so it stays legible
   over dense print */
.anttext{
  position:absolute;left:100%;top:-6px;margin-left:12px;
  font:700 26px var(--ui);line-height:1.25;color:var(--rej);
  background:rgba(var(--surface-rgb),.92);
  border:1px solid rgba(var(--rej-rgb),.45);border-radius:8px;
  padding:3px 10px;white-space:pre-wrap;max-width:460px;width:max-content;
}
/* eraser mode: only then are marks targets, and the target says so */
.antlayer.arm-erase .antmark{pointer-events:auto;cursor:pointer;}
.antlayer.arm-erase .antmark:hover{
  outline:4px dashed var(--rej);outline-offset:3px;
  background:rgba(var(--rej-rgb),.22);
}
/* the in-place text entry after a gesture (scales with the page, like the
   mark it belongs to) */
.antinput{position:absolute;pointer-events:auto;}
.antinput input{
  font:600 26px var(--ui);color:var(--rej);
  background:rgba(var(--surface-rgb),.96);
  border:2px dashed rgba(var(--rej-rgb),.7);border-radius:8px;
  padding:5px 12px;min-width:300px;outline:none;box-sizing:border-box;
}

/* ===== the mark-up chrome (tool buttons) ===== */
/* On the PORT, not the stage — buttons must not scale with the page. Inert
   when empty (read-only viewers get marks but no tools). */
.antchrome{
  position:absolute;top:8px;right:8px;z-index:5;
  display:flex;gap:6px;align-items:center;pointer-events:none;
}
.antchrome:empty{display:none;}
.antchrome>*{pointer-events:auto;}
.antbtn{
  border:1px solid var(--line-strong);border-radius:7px;cursor:pointer;
  background:var(--surface);color:var(--ink);
  font:600 11.5px var(--ui);padding:5px 9px;
  box-shadow:0 1px 4px rgba(var(--shadow-rgb),.18);
}
.antbtn:hover{border-color:var(--rej);}
.antbtn.on{
  background:var(--rej-bg);color:var(--rej);
  box-shadow:inset 0 0 0 1px var(--rej);
}
.anthint{
  font-size:10.5px;color:var(--muted);background:var(--surface);
  border:1px solid var(--line);border-radius:7px;padding:4px 8px;
  max-width:260px;line-height:1.35;
}
.anthint[hidden]{display:none;}

/* a standalone mount (annotate used over something that is not the viewer)
   needs a positioning context of its own */
.antmount{position:relative;}

/* ===== the parked card ===== */
/* What remains in the inline mount while the pane is off in #viewerbig — the
   hole in the layout explains itself instead of looking like a failed render. */
.docparked{
  display:flex;height:100%;align-items:center;justify-content:center;
  background:var(--surface-2);color:var(--muted);
  font-size:12.5px;line-height:1.5;text-align:center;padding:18px;
}
.docparked b{color:var(--ink);display:block;margin-bottom:3px;}
.docparked .dpsub{margin-bottom:10px;}
