:root {
  --bg: #f1f4f9;
  --surface: #ffffff;
  --surface-2: #f7f9fc;
  --border: #dfe5ee;
  --text: #12202f;
  --muted: #5d6b7c;
  --accent: #1f6feb;
  --accent-dark: #1550b3;
  --accent-soft: #e7f0ff;
  --success: #16794c;
  --success-soft: #e2f6ec;
  --warn: #8a5a00;
  --warn-soft: #fdf3dd;
  --danger: #b3261e;
  --danger-soft: #fdecea;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(18, 32, 47, .06), 0 8px 24px rgba(18, 32, 47, .06);
}

* { box-sizing: border-box; }

html, body { margin: 0; }

body {
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

h1, h2, h3 { line-height: 1.25; margin: 0 0 .5rem; }
h1 { font-size: 1.3rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }

code, pre, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

.muted { color: var(--muted); }
.small { font-size: .82rem; }
.nowrap { white-space: nowrap; }
.hidden { display: none !important; }

/* ---------- layout ---------- */

.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
  position: sticky;
  top: 0;
  z-index: 20;
}

.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; letter-spacing: -.01em; }
.brand-mark {
  width: 26px; height: 26px; border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), #7aa7f5);
  display: grid; place-items: center; color: #fff; font-size: 14px; font-weight: 800;
  box-shadow: 0 1px 3px rgba(18, 32, 47, .18);
  /* The one flourish on the mark: a single shine as the page opens, then it
     behaves itself. `overflow: hidden` keeps the sweep inside the tile. */
  position: relative; overflow: hidden;
}
.brand-mark::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 25%, rgba(255, 255, 255, .55) 50%, transparent 75%);
  transform: translateX(-120%);
  animation: brand-shine 1.4s ease-out .3s 1 both;
}
@keyframes brand-shine { to { transform: translateX(120%); } }

.brand-mark-lg { width: 42px; height: 42px; border-radius: 12px; font-size: 21px; }
.spacer { flex: 1; }

.wrap { max-width: 1080px; margin: 0 auto; padding: 22px 20px 60px; }
.wrap-narrow { max-width: 720px; }

.grid { display: grid; gap: 16px; }
@media (min-width: 860px) { .grid-2 { grid-template-columns: 1fr 1fr; } .grid-3 { grid-template-columns: repeat(3, 1fr); } }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
  /* The topbar stays stuck to the top of the window, so a card scrolled to the top
     of the viewport — the details panel, from the Details button — has to leave room
     for it, or its own heading and Close button land underneath. */
  scroll-margin-top: 84px;
}
.card > h2 { margin-bottom: 4px; }
.card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.card-head h2 { margin: 0; }

/* ---------- forms ---------- */

label { display: block; font-size: .85rem; font-weight: 600; color: #33414f; margin: 12px 0 5px; }
/* Every text-ish control shares one look. `search` has to be listed too: a
   browser gives it its own collapsed, chrome-coloured appearance otherwise. */
input[type="text"], input[type="email"], input[type="number"], input[type="file"],
input[type="search"], textarea, select {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: #fff;
  font: inherit;
  color: inherit;
}

/* The list search draws its own Clear button, so the WebKit one is suppressed. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}
textarea { resize: vertical; min-height: 74px; }
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }

/* The result of checking the chosen file, shown under the file input. */
.field-note { margin: 6px 0 0; font-size: .82rem; }
.field-note.ok { color: var(--success); }
.field-note.error { color: var(--danger); }

button {
  font: inherit;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
}
button:hover { background: #eef2f8; }
button:disabled { opacity: .55; cursor: not-allowed; }
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.primary:hover { background: var(--accent-dark); }
button.danger { color: var(--danger); border-color: #f0c9c5; background: var(--danger-soft); }
button.ghost { background: transparent; border-color: transparent; color: var(--muted); padding: 6px 8px; }
button.ghost:hover { background: #eef2f8; color: var(--text); }

.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.row-end { justify-content: flex-end; }

/* ---------- feedback ---------- */

.alert { border-radius: 10px; padding: 10px 13px; font-size: .87rem; margin: 12px 0; border: 1px solid transparent; }
.alert.error { background: var(--danger-soft); border-color: #f2c6c2; color: #7f1d17; }
.alert.ok { background: var(--success-soft); border-color: #bfe6d1; color: #10512f; }
.alert.warn { background: var(--warn-soft); border-color: #eddbaa; color: var(--warn); }
.alert.info { background: var(--accent-soft); border-color: #c6dcff; color: #123c78; }

.badge {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: .74rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: #eaeef4; color: #465667;
}
.badge.sent { background: var(--accent-soft); color: #123c78; }
.badge.partially_signed { background: var(--warn-soft); color: var(--warn); }
.badge.completed { background: var(--success-soft); color: var(--success); }
.badge.declined, .badge.voided, .badge.expired { background: var(--danger-soft); color: var(--danger); }

.pill { background: #eaeef4; border-radius: 999px; padding: 1px 8px; font-size: .72rem; color: #465667; }

/* The live marker on the request detail: the panel re-reads the envelope every few
   seconds, so the owner can watch documents arrive while they wait. */
.live { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
.live-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--success);
  animation: live-pulse 1.8s ease-in-out infinite;
}
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* ---------- table ---------- */

table { width: 100%; border-collapse: collapse; font-size: .89rem; }
th { text-align: left; font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); padding: 8px 10px; border-bottom: 1px solid var(--border); }
td { padding: 11px 10px; border-bottom: 1px solid #eef2f7; vertical-align: top; }
tr:last-child td { border-bottom: none; }

/* ---------- misc ---------- */

.linkbox {
  background: var(--surface-2); border: 1px dashed var(--border); border-radius: 10px;
  padding: 10px 12px; font-size: .82rem; word-break: break-all;
}

.stat { font-size: 1.35rem; font-weight: 700; }
.meta { color: var(--muted); font-size: .8rem; margin: 2px 0 0; }
.meta.ok { color: var(--success); }
.meta.warn { color: var(--warn); }

details summary { cursor: pointer; font-weight: 600; font-size: .88rem; }
pre.trail {
  background: #0f1a26; color: #d6e2f0; padding: 12px; border-radius: 10px;
  font-size: .76rem; overflow: auto; max-height: 320px; white-space: pre-wrap;
}

/* ---------- modal ---------- */

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(12, 22, 34, .55);
  display: grid; place-items: center; padding: 18px; z-index: 60;
}
.modal {
  background: var(--surface); border-radius: 14px; padding: 18px;
  width: min(620px, 100%); max-height: 92vh; overflow: auto;
  box-shadow: 0 24px 60px rgba(8, 16, 26, .35);
}
.modal-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }

/* Document preview: wide enough for a page, and the frame is what the visitor
   reads before deciding to download. */
.modal-wide { width: min(1040px, 100%); }
.pdf-frame {
  width: 100%; height: min(72vh, 780px); border: 1px solid var(--border);
  border-radius: 10px; background: #fff; display: block;
}
.tabs { display: flex; gap: 6px; margin: 12px 0; }
/* One button per signed document of the envelope: as many as ten, with names long
   enough to need the second row. */
#pdfModalNav { flex-wrap: wrap; }
.tabs button { padding: 6px 13px; font-size: .86rem; }
.tabs button[aria-selected="true"] { background: var(--accent-soft); border-color: #bcd4ff; color: #123c78; }

.sig-pad {
  border: 1px solid var(--border); border-radius: 10px; background: #fff;
  touch-action: none; width: 100%; display: block; cursor: crosshair;
}
/* The typed signature: one card per style, each drawn with a font the machine
   already has, so the whole choice is visible before it is applied. The fonts
   below mirror the canvas settings in sign.js, style for style. */
.sig-styles { display: grid; gap: 8px; margin-top: 12px; }
.sig-style {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: #fff; color: #101c2b; border: 1px solid var(--border);
  border-radius: 10px; padding: 6px 14px; cursor: pointer;
}
.sig-style:hover, [data-theme="dark"] .sig-style:hover { background: #fff; border-color: var(--accent); }
.sig-style.selected { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.sig-style-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; line-height: 1.6; }
.sig-style-label { flex: none; font-size: .68rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #5d6b7c; }
.sig-style[data-style="signature"] .sig-style-name { font: italic 700 30px "Brush Script MT", "Segoe Script", "Lucida Handwriting", cursive; }
.sig-style[data-style="script"] .sig-style-name { font: italic 400 28px "Segoe Script", "Snell Roundhand", "Apple Chancery", cursive; }
.sig-style[data-style="formal"] .sig-style-name { font: italic 400 30px "Times New Roman", Georgia, serif; }
.sig-style[data-style="printed"] .sig-style-name { font: 400 26px "Segoe Print", "Bradley Hand", "Comic Sans MS", cursive; }
.sig-style[data-style="modern"] .sig-style-name { font: 300 27px "Segoe UI Light", "Helvetica Neue", Arial, sans-serif; letter-spacing: 3px; }

/* ---------- electronic records disclosure ---------- */

.consent-body {
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2);
  padding: 12px 14px; margin: 10px 0 14px; max-height: 340px; overflow: auto;
}
.consent-body p { margin: 0 0 9px; }
.consent-body p:last-child { margin-bottom: 0; }

.check { display: flex; gap: 10px; align-items: flex-start; font-size: .88rem; font-weight: 500; }
.check input { margin-top: 3px; flex: none; }

/* ---------- signing page ---------- */

.sign-shell { max-width: 900px; margin: 0 auto; padding: 18px 16px 80px; }
.steps { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.step { font-size: .78rem; font-weight: 600; color: var(--muted); background: #e7ecf3; border-radius: 999px; padding: 4px 12px; }
.step.active { background: var(--accent); color: #fff; }
.step.done { background: var(--success-soft); color: var(--success); }

.otp-input {
  font-size: 26px; letter-spacing: .42em; text-align: center; text-transform: none;
  padding: 12px; font-family: ui-monospace, Consolas, monospace;
}

.viewer { position: relative; display: flex; flex-direction: column; gap: 14px; }
.page-wrap { position: relative; background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow); overflow: hidden; }
.page-wrap canvas { display: block; width: 100%; height: auto; }
.page-label { position: absolute; top: 6px; right: 8px; font-size: .7rem; color: var(--muted); background: rgba(255,255,255,.9); border-radius: 6px; padding: 1px 7px; }

/* One block per document in the envelope; the pages themselves line up exactly
   as they did before an envelope could hold more than one. */
.doc-card { display: flex; flex-direction: column; gap: 10px; }
.doc-card + .doc-card { margin-top: 8px; padding-top: 18px; border-top: 1px solid var(--border); }
/* A document the signer has already signed: still shown, visibly closed for
   business — there is nothing left to fill in on it. */
.doc-card.signed .doc-pages { opacity: .92; }
.doc-badge { align-self: flex-start; border-radius: 999px; padding: 2px 10px; font-size: .7rem; font-weight: 700; }
.doc-badge.ok { background: var(--success-soft); color: var(--success); }
.doc-pages { position: relative; display: flex; flex-direction: column; gap: 14px; }  .doc-heading { display: flex; flex-direction: column; gap: 2px; }
.doc-heading strong { font-size: .95rem; }

/* One entry per document above the viewer: how many there are, which one is open
   and what is still owed on each. Only the chosen document is rendered below. */
.doc-list-head { display: flex; align-items: baseline; gap: 8px; margin: 14px 0 6px; }
.doc-list { display: grid; gap: 8px; }
.doc-list-item {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 12px; cursor: pointer;
}
.doc-list-item:hover { border-color: var(--accent); }
.doc-list-item.active { background: var(--surface); border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.doc-list-item.next { border-color: var(--accent); }
.doc-list-index { flex: none; font-size: .74rem; font-weight: 700; color: var(--muted); }
.doc-list-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: .88rem; font-weight: 600; }
.doc-list-pages { flex: none; font-size: .74rem; color: var(--muted); }
.doc-status { flex: none; border-radius: 999px; padding: 3px 9px; font-size: .68rem; font-weight: 700; }
.doc-list-item[data-state="pending"] .doc-status { background: var(--accent-soft); color: var(--accent-dark); }
.doc-list-item[data-state="ready"] .doc-status { background: var(--success-soft); color: var(--success); }
.doc-list-item[data-state="signed"] .doc-status { background: var(--success-soft); color: var(--success); }

.field-box {
  position: absolute; border: 2px dashed var(--accent); border-radius: 6px;
  background: rgba(31, 111, 235, .09); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: .72rem; font-weight: 700; color: var(--accent-dark);
}
.field-box.filled { border-style: solid; background: rgba(22, 121, 76, .08); border-color: var(--success); color: var(--success); }
.field-box img { max-width: 100%; max-height: 100%; }
.field-box.required::after { content: "*"; position: absolute; top: -9px; right: -3px; color: var(--danger); }
/* A box that can be filled from the signature the signer already gave: it says so
   before it is tapped, instead of asking for the same drawing a second time. */
.field-box.reusable { border-style: solid; background: rgba(31, 111, 235, .15); }

/*
 * A signed box holds the signature and nothing else — the date of signing is not
 * printed beside the mark any more, so the ink is simply centred in the space the
 * sender left for it, exactly as it is stamped on the page.
 */
.field-box.filled[data-field-type="signature"] img { object-fit: contain; }

/*
 * The one corner of the box that is the signer's: the paper it sits on and the
 * position are the sender's terms, but how much room the signature needs is
 * theirs to say. It sits inside the box, because the page clips what hangs over
 * the edge of it.
 */
.field-resize {
  position: absolute; right: 0; bottom: 0; width: 14px; height: 14px;
  border-left: 1px solid rgba(31, 111, 235, .45);
  border-top: 1px solid rgba(31, 111, 235, .45);
  border-bottom-right-radius: 4px; cursor: nwse-resize; touch-action: none;
  background-image: repeating-linear-gradient(135deg, currentColor 0 1.5px, transparent 1.5px 4.5px);
  opacity: .55;
}
.field-resize:hover, .field-resize:focus-visible {
  opacity: 1; background-color: var(--accent-soft); outline: 1px solid var(--accent);
}
/* While a corner is being dragged the whole page keeps the resize cursor. */
body.resizing-box { cursor: nwse-resize; user-select: none; }

/* ---------- signature reuse (one signature, many documents) ---------- */

.reuse-card {
  display: flex; align-items: center; gap: 14px; margin: 10px 0 4px;
  border: 1px solid var(--border); background: var(--surface-2);
  border-radius: 12px; padding: 12px;
}
.reuse-card img {
  flex: none; width: 168px; height: 70px; object-fit: contain;
  background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 4px;
}
.reuse-copy { min-width: 0; }
.reuse-copy p { margin: 3px 0 9px; }

.sign-bar {
  position: fixed; left: 0; right: 0; bottom: 0; background: var(--surface);
  border-top: 1px solid var(--border); padding: 12px 16px;
  display: flex; align-items: center; gap: 12px; z-index: 30;
}
.sign-bar .inner { max-width: 900px; margin: 0 auto; width: 100%; display: flex; align-items: center; gap: 12px; }

/* ---------- auth + outbox ---------- */

.auth-body { display: grid; place-items: center; min-height: 100vh; padding: 24px; }
.auth-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  padding: 26px; width: min(460px, 100%); box-shadow: var(--shadow);
}
.auth-note { font-size: .84rem; color: var(--muted); background: var(--surface-2); border-radius: 9px; padding: 10px 12px; }

.ms-signin {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-top: 16px; padding: 11px 16px;
  border: 1px solid #d3dae6; border-radius: 9px; background: #fff;
  color: var(--text); font-weight: 600; text-decoration: none;
}
.ms-signin:hover { background: #f4f6fa; border-color: #c3cddd; }
.ms-signin-mark { display: inline-flex; }

.outbox { max-width: 760px; margin: 0 auto; }
.outbox article { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px; margin: 12px 0; }
.outbox pre { background: var(--surface-2); border-radius: 8px; padding: 10px; font-size: .8rem; white-space: pre-wrap; }

/* ===========================================================================
   Interactive layer
   ===========================================================================
   Appearance, toasts, dialogs, drag-and-drop, skeletons, the audit timeline and
   the guided signing progress. Everything is additive: the page works without
   any of it, and nothing here needs a build step.
   =========================================================================== */

/* ---------- appearance ---------- */

.theme-toggle { font-size: .82rem; padding: 5px 10px; border-color: var(--border); background: var(--surface-2); }
.theme-toggle:hover { background: var(--hover); }

.auth-theme { position: fixed; top: 16px; right: 16px; z-index: 5; }

[data-theme="dark"] {
  --bg: #0c1320;
  --surface: #131c2b;
  --surface-2: #182233;
  --border: #27344a;
  --text: #e7eef8;
  --muted: #93a4bb;
  --accent: #4d8bf5;
  --accent-dark: #7aa9ff;
  --accent-soft: #1b2c49;
  --success: #4fd396;
  --success-soft: #14301f;
  --warn: #e6bd63;
  --warn-soft: #33280f;
  --danger: #ff8279;
  --danger-soft: #3a1c1c;
  --hover: #1f2b3d;
  --shadow: 0 1px 2px rgba(0, 0, 0, .45), 0 12px 34px rgba(0, 0, 0, .38);
  color-scheme: dark;
}

:root { --hover: #eef2f8; }

/* The handful of places that hardcoded a light colour. */
[data-theme="dark"] input[type="text"],
[data-theme="dark"] input[type="email"],
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="search"],
[data-theme="dark"] textarea,
[data-theme="dark"] select { background: var(--surface); color: var(--text); }

[data-theme="dark"] button:hover,
[data-theme="dark"] button.ghost:hover { background: var(--hover); }

[data-theme="dark"] .badge,
[data-theme="dark"] .pill,
[data-theme="dark"] .step { background: #1e293b; color: #a9bad1; }  [data-theme="dark"] .badge.sent { background: var(--accent-soft); color: #a8c8ff; }
[data-theme="dark"] .badge.completed { background: var(--success-soft); color: var(--success); }
[data-theme="dark"] .badge.declined,
[data-theme="dark"] .badge.voided,
[data-theme="dark"] .badge.expired { background: var(--danger-soft); color: var(--danger); }
[data-theme="dark"] .badge.partially_signed { background: var(--warn-soft); color: var(--warn); }

[data-theme="dark"] .ms-signin { background: var(--surface); border-color: var(--border); color: var(--text); }
[data-theme="dark"] .ms-signin:hover { background: var(--hover); }
[data-theme="dark"] .outbox article { background: var(--surface); }
/* A signature and a rendered page are white paper: keep them white in dark mode. */
[data-theme="dark"] .sig-pad,
[data-theme="dark"] .sig-style { background: #fff; color: #101c2b; }

/* ---------- focus ---------- */

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* ---------- toasts ---------- */

.toast-host {
  position: fixed; right: 16px; bottom: 16px; z-index: 90;
  display: flex; flex-direction: column; gap: 8px;
  max-width: min(420px, calc(100vw - 32px));
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 10px 12px;
  box-shadow: var(--shadow); font-size: .87rem;
  animation: toast-in .18s ease-out;
}
.toast.ok { border-left-color: var(--success); }
.toast.warn { border-left-color: var(--warn); }
.toast.error { border-left-color: var(--danger); }
.toast .toast-text { flex: 1; }
.toast.leaving { animation: toast-out .18s ease-in forwards; }

.toast-close, .toast-action {
  flex: none; background: none; border: 0; padding: 0 2px;
  font: inherit; font-size: 1rem; line-height: 1.2; color: var(--muted); cursor: pointer;
}
.toast-action { font-size: .82rem; font-weight: 700; color: var(--accent); }
.toast-close:hover, .toast-action:hover { color: var(--text); background: none; }

@keyframes toast-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px) scale(.98); } }

/* ---------- dialogs ---------- */

.modal-narrow { width: min(430px, 100%); }
body.modal-open { overflow: hidden; }
.modal-backdrop.leaving { animation: fade-out .16s ease-in forwards; }
@keyframes fade-out { to { opacity: 0; } }

/* ---------- toolbar: search + filters ---------- */

.toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }
.search { position: relative; display: flex; align-items: center; gap: 8px; flex: 1 1 240px; }
.search input { padding-right: 64px; }
.search #listSearchClear { position: absolute; right: 4px; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: 999px; font-size: .8rem; font-weight: 600;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
}
.chip:hover { background: var(--hover); color: var(--text); }
.chip[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); }
.chip .pill { background: rgba(125, 145, 175, .18); color: inherit; }

.empty { text-align: center; padding: 18px 0; }

/* ---------- drag & drop ---------- */

.drop-zone {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 20px 14px; border: 1.5px dashed var(--border); border-radius: 12px;
  background: var(--surface-2); text-align: center; cursor: pointer;
  transition: border-color .15s, background .15s, transform .15s;
}
.drop-zone input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; padding: 0; border: 0;
}
.drop-zone .drop-icon { color: var(--muted); }
.drop-zone .drop-hint { font-size: .84rem; color: var(--muted); }
.drop-zone:hover { border-color: var(--accent); background: var(--accent-soft); }
.drop-zone.dragging { border-color: var(--accent); background: var(--accent-soft); transform: scale(1.01); }
.drop-zone.checking { border-style: solid; }
.drop-zone:focus-within { border-color: var(--accent); outline: 2px solid var(--accent-soft); }

/* The chosen documents, one row each, with that file's own check result — an
   envelope holds several, and one bad file must not hide the good ones. */
.file-list {
  list-style: none; margin: 10px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.file-list:empty { display: none; }
.file-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 10px; border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface-2); font-size: .84rem;
}
.file-row .file-name { font-weight: 600; }
.file-row .file-state { margin-left: auto; }
.file-row .file-state.ok { color: var(--success); }
.file-row .file-state.error { color: var(--danger); }
.file-row[data-status="error"] { border-color: var(--danger); }
.file-row .file-remove { padding: 3px 8px; font-size: .78rem; }
.file-row .file-remove[disabled] { opacity: .5; cursor: not-allowed; }

/* Where the sender decides the signer signs. One card per document, showing one
   page at a time: a long document is walked page by page instead of being
   squeezed into a strip, and the page being looked at is the page that gets
   rendered. The box is draggable and the page is clickable. */
.placement-list { display: grid; gap: 14px; margin-top: 12px; }
.placement-card {
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2);
  padding: 10px; display: flex; flex-direction: column; gap: 8px;
}
.placement-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.placement-head strong { font-size: .88rem; }
.placement-head .spacer { flex: 1; }
/* The chosen page and spot, as a badge: "page 14 of 14 · bottom right". */
.placement-note {
  flex: none; font-size: .76rem; font-weight: 600; color: var(--accent-dark);
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 2px 10px;
}
.placement-pager { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.placement-pager label { display: flex; align-items: center; gap: 6px; color: var(--muted); }
.placement-pager select { width: auto; padding: 4px 8px; }
.placement-step { padding: 2px 11px; font-size: .95rem; line-height: 1.3; }
.placement-step[disabled] { opacity: .45; cursor: not-allowed; }

/* The whole page is kept in view: a place is chosen by looking at the page, so
   the page is fitted to the height the card can spare rather than squashed or
   left half out of sight. The wrap is never anything but the canvas, so a
   percentage position still lines up with the paper. */
.placement-stage {
  position: relative; display: flex; align-items: center; justify-content: center;
  min-height: 200px; min-width: 0; padding: 2px;
}
/* Fitted to whichever runs out first — the height the card can spare, or the
   width it actually has — so a long page is never wider than its own card on a
   phone, and never taller than the screen on a desktop. */
.placement-stage .page-wrap {
  flex: 0 1 auto; cursor: crosshair;
  max-width: min(100%, calc((62vh - 46px) / var(--page-aspect, 1.414)));
}
.placement-box {
  position: absolute; border: 2px solid var(--accent); border-radius: 6px;
  background: rgba(31, 111, 235, .14); cursor: grab; touch-action: none;
  display: flex; align-items: center; justify-content: space-between; gap: 2px;
  padding: 0 3px 0 6px; overflow: hidden;
  font-size: .7rem; font-weight: 700; color: var(--accent-dark);
}
.placement-box:active { cursor: grabbing; }
/* The box being worked on, so two boxes on one page are told apart. */
.placement-box.selected { border-color: var(--accent-dark); box-shadow: 0 0 0 2px rgba(31, 111, 235, .25); }
.placement-box-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Removing lives inside the box: the page canvas clips anything outside it. */
.placement-box-remove {
  flex: none; width: 17px; height: 17px; padding: 0; line-height: 1; border-radius: 50%;
  border: 1px solid currentColor; background: var(--surface); color: inherit;
  font-size: .74rem; font-weight: 700; cursor: pointer;
}
.placement-box-remove:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.placement-box-remove[disabled] { opacity: .35; cursor: not-allowed; }
.placement-box-remove[disabled]:hover { background: var(--surface); border-color: currentColor; color: inherit; }

/* One tag per box: which page it is on, and the way to remove it. */
.placement-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.placement-chip {
  display: inline-flex; align-items: stretch; border: 1px solid var(--border);
  border-radius: 999px; background: var(--surface); overflow: hidden; font-size: .74rem;
}
.placement-chip.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.placement-chip .chip-jump {
  border: 0; background: transparent; color: inherit; font: inherit;
  padding: 3px 4px 3px 10px; cursor: pointer; white-space: nowrap;
}
.placement-chip .chip-jump:hover { color: var(--accent-dark); }
.placement-chip .chip-remove {
  border: 0; border-left: 1px solid var(--border); background: transparent;
  color: var(--muted); font: inherit; padding: 3px 9px 3px 7px; cursor: pointer;
}
.placement-chip .chip-remove:hover { color: #fff; background: var(--danger); }
.placement-chip .chip-remove[disabled] { opacity: .4; cursor: not-allowed; }
.placement-chip .chip-remove[disabled]:hover { color: var(--muted); background: transparent; }

/* The per-document table inside the detail panel. */
.doc-table { margin-top: 4px; }
.doc-table td:first-child { width: 45%; }

/* ---------- skeletons ---------- */

.skeleton-rows { display: flex; flex-direction: column; gap: 10px; }
.skeleton-row { display: flex; gap: 14px; }
.skeleton-row span {
  height: 14px; border-radius: 6px; flex: 1;
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 37%, var(--surface-2) 63%);
  background-size: 400% 100%; animation: shimmer 1.3s ease-in-out infinite;
}
.skeleton-row span:first-child { flex: 2; }
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* ---------- hashes + copy ---------- */

.hash {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface-2); border: 1px dashed var(--border);
  border-radius: 10px; padding: 8px 10px;
}
.hash .mono { flex: 1; font-size: .78rem; word-break: break-all; }
.copy { font-size: .72rem; padding: 3px 9px; flex: none; }
.copy.ok { color: var(--success); border-color: var(--success); }

.section-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ---------- audit timeline ---------- */

.timeline { list-style: none; margin: 12px 0 0; padding: 0 0 0 4px; }
.timeline-item { position: relative; display: flex; gap: 12px; padding: 0 0 14px 4px; }
.timeline-item::before {
  content: ""; position: absolute; left: 9px; top: 14px; bottom: 0;
  width: 1px; background: var(--border);
}
.timeline-item:last-child::before { display: none; }
.timeline-dot {
  position: relative; z-index: 1; flex: none;
  width: 11px; height: 11px; margin-top: 4px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 3px var(--surface);
}
.timeline-dot.good { background: var(--success); }
.timeline-dot.warn { background: var(--warn); }
.timeline-dot.bad { background: var(--danger); }
.timeline-body { min-width: 0; }
.timeline-event { margin: 0; display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.timeline-event strong { font-size: .86rem; }

.timeline-body .meta { margin: 1px 0 0; }
.hash-mini { font-size: .7rem; }

/* ---------- signing progress + guided field ---------- */

.progress-block { margin-top: 12px; }
.progress {
  height: 6px; border-radius: 999px; background: var(--surface-2);
  overflow: hidden; border: 1px solid var(--border);
}
.progress > span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent), #7aa9ff);
  transition: width .35s ease;
}
.progress-block .meta { margin-top: 6px; }

.field-box { transition: box-shadow .2s, transform .2s; }
.field-box.pulse {
  animation: field-pulse 1.6s ease-in-out infinite;
  box-shadow: 0 0 0 4px rgba(31, 111, 235, .18);
}
@keyframes field-pulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(31, 111, 235, .12); }
  50% { box-shadow: 0 0 0 9px rgba(31, 111, 235, .04); }
}

/* ---------- busy buttons ---------- */

button.busy { position: relative; color: transparent !important; }
button.busy::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid rgba(125, 145, 175, .4); border-top-color: var(--text);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- brand blocks (sign-in page, signer footer) ---------- */

.auth-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.auth-brand-name { font-size: 1.08rem; font-weight: 800; letter-spacing: -.01em; }
.auth-brand-tagline { font-size: .78rem; color: var(--muted); margin-top: 1px; }

.sign-footer {
  text-align: center; color: var(--muted); font-size: .78rem;
  margin: 26px 0 10px; letter-spacing: .01em;
}

/* ---------- motion ---------- */

/*
  The small movements that make the product feel alive rather than printed.
  Every one of them is transform/opacity only (cheap on a phone), and the
  site-wide `prefers-reduced-motion` rule at the foot of this file turns the
  whole section off for anybody who has asked for less motion.
*/

@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes rise-soft { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes pop { from { opacity: 0; transform: scale(.965); } to { opacity: 1; transform: none; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Cards arrive instead of appearing; a second card follows a beat later. */
.card { animation: rise .34s cubic-bezier(.2, .7, .3, 1) both; }
.grid > .card:nth-child(2), #panels > .card:nth-child(2) { animation-delay: .07s; }
.auth-card { animation: rise .42s cubic-bezier(.2, .7, .3, 1) both; }

/* Warnings and confirmations slide in with the card. */
.alert { animation: rise-soft .24s ease-out both; }

/* The administrator's counters tick in together. */
.stat-card { animation: pop .3s cubic-bezier(.2, .7, .3, 1) both; }

/* Dialogs: the backdrop fades, the panel pops. */
.modal-backdrop:not(.hidden) { animation: fade-in .18s ease-out both; }
.modal-backdrop:not(.hidden) .modal { animation: pop .22s cubic-bezier(.2, .7, .3, 1) both; }

/* Each document the sender picks lands as its own row. */
.file-row, .doc-list-item { animation: rise-soft .22s ease-out both; }

/* Keyboard users get a ring they can actually see; the pointer does not need one. */
:where(button, a, .chip, .doc-list-item, .sig-style):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 9px;
}

/* Controls answer the hand: a lift on the primary action, a press everywhere. */
button { transition: background .18s, border-color .18s, color .18s, box-shadow .18s, transform .12s; }
button.primary { box-shadow: 0 1px 2px rgba(31, 111, 235, .3); }
button.primary:hover:not(:disabled) { box-shadow: 0 6px 16px rgba(31, 111, 235, .26); transform: translateY(-1px); }
button:not(:disabled):active { transform: translateY(1px); box-shadow: none; }

.chip { transition: background .16s, border-color .16s, color .16s, transform .16s; }
.chip:active { transform: scale(.97); }
.badge { transition: background .2s, color .2s; }

/* The step rail on the signing page: the active step rises a little. */
.step { transition: background .2s, color .2s, transform .2s; }
.step.active { transform: translateY(-1px); box-shadow: 0 2px 8px rgba(31, 111, 235, .22); }

/* The document picker nudges towards the row under the pointer. */
.doc-list-item { transition: border-color .16s, background .16s, transform .16s, box-shadow .16s; }
.doc-list-item:hover { transform: translateX(2px); }

/* ---------- signature upload + the closing seal ---------- */

/* The three ways to give a signature share one panel; the panel that is shown
   slides in, so switching tabs is a change rather than a jump. */
#tabDraw, #tabType, #tabUpload { animation: rise-soft .22s ease-out both; }
.tabs button[aria-selected="true"] { box-shadow: 0 1px 2px rgba(31, 111, 235, .16); }

/* Uploading a signature: the picture is turned into ink in the browser, and the
   preview sits on a checkerboard so the transparent paper is visible before the
   signature is applied to a document. */
.sig-upload .drop-title { font-weight: 700; font-size: .9rem; }
.sig-upload.has-image { border-style: solid; border-color: var(--accent); }
.sig-upload-preview {
  margin-top: 10px; padding: 12px; border: 1px solid var(--border); border-radius: 10px;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eef2f8 25%, transparent 25%),
    linear-gradient(-45deg, #eef2f8 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #eef2f8 75%),
    linear-gradient(-45deg, transparent 75%, #eef2f8 75%);
  background-size: 14px 14px;
  background-position: 0 0, 0 7px, 7px -7px, -7px 0;
  display: grid; place-items: center;
  animation: pop .24s cubic-bezier(.2, .7, .3, 1) both;
}
.sig-upload-preview img { max-width: 100%; max-height: 120px; object-fit: contain; }

/* The seal that closes the signing flow: it stamps in, then the tick draws
   itself. `aria-hidden` in the markup, because the heading says it in words. */
.seal { width: 58px; height: 58px; margin-bottom: 10px; animation: seal-stamp .5s cubic-bezier(.2, 1.25, .4, 1) both; }
.seal svg { width: 100%; height: 100%; display: block; }
.seal-ring { fill: var(--success-soft); stroke: var(--success); stroke-width: 2; }
.seal-tick {
  fill: none; stroke: var(--success); stroke-width: 3.6;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 42; stroke-dashoffset: 42;
  animation: seal-draw .45s .16s ease-out forwards;
}
@keyframes seal-stamp { from { opacity: 0; transform: scale(.6) rotate(-9deg); } to { opacity: 1; transform: none; } }
@keyframes seal-draw { to { stroke-dashoffset: 0; } }

/* The progress bar turns green when there is nothing left to sign. */
.progress > span.full { background: linear-gradient(90deg, var(--success), #47b380); }

/* ---------- admin ---------- */

.wrap-wide { max-width: 1320px; }

.admin-pill { background: var(--accent); color: #fff; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; font-size: .64rem; }

.admin-filters {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin: 14px 0 4px;
}

.admin-filters .search { flex: 1 1 260px; }
.admin-filters select { width: auto; min-width: 170px; }

.button-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  padding: 8px 13px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--surface);
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
  margin-top: 14px;
}

.stat-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 13px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
}

.table-wrap { overflow-x: auto; margin-top: 6px; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: .87rem;
}

table.data th {
  text-align: left;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

table.data td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  /* A 64-character hash or a long address has no spaces to break at, and would
     otherwise push the whole table sideways behind a scrollbar. */
  overflow-wrap: anywhere;
}

table.data tbody tr:hover { background: var(--surface-2); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data .badge { margin-top: 4px; }
table.data code { font-size: .8rem; }

.tiny { font-size: .72rem; }

.pager {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-content: flex-end;
  margin-top: 12px;
}

.ghost.disabled { opacity: .45; cursor: default; }

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px;
  margin-top: 6px;
}

/* ---------- mobile ---------- */

@media (max-width: 700px) {
  .wrap { padding: 16px 14px 60px; }
  .topbar { padding: 10px 14px; gap: 10px; flex-wrap: wrap; }
  .topbar .theme-toggle { order: 5; }
  .toolbar { gap: 8px; }
  .chips { width: 100%; overflow-x: auto; flex-wrap: nowrap; padding-bottom: 4px; }
  .chip { flex: none; }
  .sign-bar { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .sign-bar .inner { flex-wrap: wrap; }
  .toast-host { left: 12px; right: 12px; bottom: 12px; max-width: none; }
  .modal { padding: 14px; }
  .skeleton-row span:nth-child(4) { display: none; }
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); }
  .admin-filters select { min-width: 0; flex: 1 1 100%; }
  .pager { justify-content: space-between; }
  .sign-footer { margin: 20px 0 6px; }
  .auth-brand { margin-bottom: 14px; }
  /* A thumb needs a real target, not a 34px one. */
  .theme-toggle { min-height: 40px; padding: 8px 12px; }
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
