/*
 * PlanInk — PDF markup tool for large-format plan sets, served over the LAN.
 *
 * Copyright © 2025 N2EDU INC. All rights reserved.
 * Unauthorized use, reproduction, or distribution of this software,
 * in whole or in part, is strictly prohibited without prior written
 * permission from N2EDU INC.
 */

/* PlanInk — graphite chrome, redline accent, title-block lettering */

:root {
  --bg-chrome: #1a1d21;
  --bg-panel: #23272d;
  --bg-viewer: #2c3036;
  --ink: #d7dade;
  --ink-dim: #8b9097;
  --line: #383d44;
  --redline: #d8260f;
  --redline-soft: rgba(216, 38, 15, 0.16);
  --focus: #4fb8c9;
}

/* Signature tool — bundled locally so LAN/offline deployments render
   the same cursive fonts without reaching out to any font CDN. */
@font-face {
  font-family: "Dancing Script";
  src: url("fonts/dancing-script-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Caveat";
  src: url("fonts/caveat-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Pacifico";
  src: url("fonts/pacifico-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: -apple-system, "Segoe UI", Roboto, Ubuntu, sans-serif;
  background: var(--bg-chrome);
  color: var(--ink);
}

body { display: flex; flex-direction: column; }

/* ---------- Toolbar: styled like a drawing title block ---------- */

#toolbar-inner {
  display: flex;
  align-items: center;
  gap: 4px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: auto;
  -ms-overflow-style: auto;
  white-space: nowrap;
  width: 100%;
  padding-bottom: 10px;
}
/* Scrollbar is deliberately a real, always-visible touch target — not a
   hover-only hairline. On touch devices :hover barely fires, so a thin
   hover-reveal thumb is both invisible and nearly impossible to grab,
   which was causing fingers to land on the buttons/sliders above it
   instead (accidental tool switches, width changes, etc). */
#toolbar-inner::-webkit-scrollbar { height: 10px; }
#toolbar-inner::-webkit-scrollbar-track {
  background: transparent;
}
#toolbar-inner::-webkit-scrollbar-thumb {
  background-color: var(--line, #cccccc);
  border-radius: 5px;
}
#toolbar-inner:hover::-webkit-scrollbar-thumb {
  background-color: var(--ink-dim);
}
/* Firefox */
#toolbar-inner { scrollbar-width: auto; scrollbar-color: var(--line, #cccccc) transparent; }

#toolbar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: 6px 12px;
  background: var(--bg-chrome);
  border-bottom: 1px solid var(--line);
  user-select: none;
  -webkit-user-select: none;
}

/* Pinned second row: whichever color/width/style/measure/fill controls
   apply to the active tool, always visible with no scrolling — switching
   tools never requires hunting back across the icon row above to reach
   them. Contents are the same groups, shown/hidden per tool exactly as
   before; only their position moved. min-height keeps the canvas below
   from shifting when the active tool has no properties to show (Pan,
   Select, Eraser, Table, Sign). */
#tool-props-row {
  display: flex;
  align-items: center;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  white-space: nowrap;
  width: 100%;
  min-height: 34px;
  padding-top: 6px;
  margin-top: 6px;
  border-top: 1px solid var(--line);
}
#tool-props-row::-webkit-scrollbar { height: 8px; }
#tool-props-row::-webkit-scrollbar-track { background: transparent; }
#tool-props-row::-webkit-scrollbar-thumb {
  background-color: var(--line, #cccccc);
  border-radius: 4px;
}
#tool-props-row { scrollbar-width: thin; scrollbar-color: var(--line, #cccccc) transparent; }

.tb-group { display: flex; align-items: center; gap: 4px; }
.tb-rule { width: 1px; background: var(--line); margin: 4px 2px; }
.tb-spacer { flex: 1; }

/* "More tools" overflow group (Triangle/Polygon/Diamond/Measure) --
   collapsed by default; display:contents on expand keeps its buttons as
   direct flex items of the parent .tb-group instead of a nested box. */
.more-tools-group { display: none; }
.more-tools-group.expanded { display: contents; }
#btn-more-tools[aria-expanded="true"] {
  color: var(--ink);
  background: var(--redline-soft);
  border-color: var(--redline);
}

.tb-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 52px;
  padding: 5px 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--ink-dim);
  cursor: pointer;
}
.tb-btn svg {
  width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.tb-btn span {
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.tb-btn:hover:not(:disabled) { color: var(--ink); border-color: var(--line); }
.tb-btn:disabled { opacity: 0.35; cursor: default; }
.tb-btn.active {
  color: var(--redline);
  background: var(--redline-soft);
  border-color: var(--redline);
}
.tb-btn.sq { min-width: 32px; font-size: 16px; padding: 8px; color: var(--ink-dim); }
.tb-btn.sq:hover { color: var(--ink); }

/* .tb-btn's resting state is transparent/borderless -- deliberate for the
   icon buttons packed into the main toolbar row, but for a short text
   label sitting inline next to a plain <label> (Page Orientation's
   Auto/Portrait/Landscape toggle, New Blank Page's Create button) that
   resting state reads as plain text, not a clickable button. This gives
   those an always-visible fill + border instead, the same "obviously
   interactive" resting look .tb-select already uses for the toolbar's
   dropdowns, so it reads as a control at a glance instead of only on
   hover/active. */
.tb-btn.labeled-toggle {
  background: var(--bg-panel);
  border-color: var(--line);
}
.tb-btn.labeled-toggle:hover:not(:disabled) { border-color: var(--ink-dim); }

.tb-select {
  background: var(--bg-panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 4px 6px;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
}
.tb-select:hover { border-color: var(--ink-dim); }
.tb-btn:focus-visible, input:focus-visible, #btn-open-empty:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* .swatch removed — toolbar swatches replaced with native color picker */
/* .color-btn removed — the decorative proxy button (icon + label,
   forwarded clicks to a hidden input) is gone entirely. It never reliably
   opened the native picker on iOS regardless of how the hidden input was
   sized/positioned; a real, directly visible <input type="color"> swatch
   (styled inline in index.html) replaced it and is confirmed working on
   iPhone, Android, and desktop. */

/* Color picker */
.color-picker {
  display: inline-flex;
  align-items: center;
}
/* color-dropdown removed — native OS picker used instead */

#width-group {
  gap: 8px;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
#width-group input { width: 90px; accent-color: var(--redline); }
#width-readout { min-width: 44px; color: var(--ink); }

#zoom-group { gap: 6px; }
#zoom-readout {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  min-width: 46px;
  text-align: center;
  color: var(--ink);
}

/* ---------- Viewer ---------- */

#viewer {
  flex: 1;
  overflow: auto;
  background-color: var(--bg-viewer);
  /* Same faint drafting grid as the empty state, moved here so it stays
     visible as a reference around a loaded page too -- previously it only
     lived on #empty-state and vanished entirely (flat --bg-viewer color,
     no grid) the moment a file was open, even in the space around a page
     that doesn't fill the whole viewer. */
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 48px 48px;
  background-position: center;
  position: relative;
  /* One-finger panning stays native (smooth, momentum scrolling). Two-finger
     pinch is deliberately EXCLUDED so the browser's own pinch-zoom never runs
     against the app's anchored pinch handler in main.js. Without this the
     default (auto) let the browser pan/zoom the viewer natively at the same
     time as the JS pinch was setting scroll positions, and the two fought --
     on real touch hardware the zoom appeared to land away from the pinched
     point even though the anchor math was correct. */
  touch-action: pan-x pan-y;
}
#viewer.tool-pan { cursor: grab; }
#viewer.tool-pan.panning { cursor: grabbing; }
#viewer.tool-pen, #viewer.tool-highlighter { cursor: crosshair; }
#viewer.tool-eraser { cursor: cell; }
/* select tool cursor managed via JS inline style */

#pages {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 24px;
  width: max-content;
  min-width: 100%;
}

.page {
  position: relative;
  background: #fff;
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
  flex: none;
  overflow: hidden;
}
/* tiles is now a <canvas> — one GPU texture per page, no img compositing */
.page canvas.tiles {
  position: absolute;
  top: 0; left: 0;
  display: block;
  image-rendering: auto;
  pointer-events: none;
}
.page canvas.sel-overlay {
  position: absolute;
  top: 0; left: 0;
  display: block;
  pointer-events: none;
}

.page canvas.ink {
  position: absolute;
  top: 0; left: 0;
  display: block;
  touch-action: none;
  pointer-events: auto;
}
.page .page-label {
  position: absolute;
  bottom: -18px;
  right: 0;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
}

/* Shown while a page's tile canvas is still painting -- large/complex
   sheets can leave the canvas blank white for a noticeable moment, which
   some users read as PlanInk having stalled. Toggled by renderPageWindow()
   in main.js. Deliberately NOT a child of #viewer: an absolutely-positioned
   descendant of a scroll container still scrolls with that container's
   content (scrolling translates the whole box, not just in-flow children),
   so it drifted during pan/zoom when nested inside #viewer. As a fixed-
   position element outside #viewer entirely, its left/top/width/height are
   set from #viewer's own getBoundingClientRect() in main.js (on resize and
   whenever shown) so it exactly overlays the viewer, immune to scrolling.
   --ink/--ink-dim are tuned for the dark chrome, so this uses a dedicated
   dark color for legibility against the white page underneath instead. */
#page-loading-indicator {
  display: none;
  position: fixed;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
  z-index: 20;
}
#page-loading-indicator.visible { display: flex; }
#page-loading-indicator .spinner {
  width: 34px; height: 34px;
  border: 4px solid rgba(44, 48, 54, 0.18);
  border-top-color: var(--focus);
  border-radius: 50%;
  animation: planink-spin 0.8s linear infinite;
  background: #fff;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
}
#page-loading-indicator .loading-text {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: #23272d;
  background: #fff;
  padding: 3px 10px;
  border-radius: 4px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
}
@keyframes planink-spin {
  to { transform: rotate(360deg); }
}

/* ---------- Empty state ---------- */

#empty-state {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  padding: 24px;
  /* faint drafting grid */
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 48px 48px;
  background-position: center;
}
.es-logo {
  /* v1.10.4: new sticker-style mark ships on a transparent background with
     its own baked-in white outline + glow, designed to sit directly on the
     dark viewer grid -- no white card wrapper needed (or wanted) anymore. */
  width: 300px;
  max-width: 60vw;
  height: auto;
  opacity: 1;
  user-select: none;
  -webkit-user-drag: none;
}
#empty-state p { color: var(--ink); max-width: 420px; background: var(--bg-chrome); }
#empty-state .es-hint { color: var(--ink-dim); font-size: 13px; }
#empty-state .es-drive-beta-note {
  color: var(--ink-dim);
  font-size: 11px;
  max-width: 420px;
  margin-top: 10px;
  line-height: 1.4;
}
.es-open-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  margin-top: 8px;
}
.es-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 22px;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: 3px;
  cursor: pointer;
  line-height: 1.2;
}
.drive-icon-lg { width: 20px; height: 20px; object-fit: contain; }

/* ---------- Scan modal (crop/straighten/filter a photo) ---------- */
#scan-canvas-wrap {
  position: relative;
  /* display:inline-block never actually centered via margin:auto below --
     that only works on a block-level box, not inline-block -- so this sat
     flush left whenever a sibling row (the button rows, the hint text) was
     wider than the canvas itself. That was invisible on Desktop because the
     modal there (see showScanPane() in main.js) widens to hug the canvas,
     so the canvas IS the widest thing and there's no leftover space for the
     misalignment to show; a narrow mobile viewport is where a narrow
     (e.g. tall/narrow source photo) canvas exposed it. display:table keeps
     the same shrink-to-fit sizing as inline-block but, being block-level,
     actually centers via margin:auto. */
  display: table;
  margin: 0 auto;
  touch-action: none;
}
#scan-canvas {
  display: block;
  border-radius: 4px;
  touch-action: none;
}
.scan-handle {
  position: absolute;
  left: 0; top: 0;
  width: 26px; height: 26px;
  margin-left: -13px; margin-top: -13px;
  border-radius: 50%;
  background: rgba(79, 184, 201, 0.9);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
  cursor: grab;
  touch-action: none;
  z-index: 2;
}
.scan-handle:active { cursor: grabbing; background: rgba(79, 184, 201, 1); }
#scan-magnifier {
  position: absolute;
  left: 0; top: 0;
  width: 130px; height: 130px;
  border-radius: 50%;
  overflow: hidden;
  border: 3px solid #4fb8c9;
  box-shadow: 0 2px 10px rgba(0,0,0,0.5);
  background: #000;
  pointer-events: none; /* never intercepts the drag itself */
  z-index: 3;
  display: none;
}
#scan-magnifier canvas { display: block; }

.es-btn-primary {
  color: #fff;
  background: var(--redline);
  border: none;
}
.es-btn-primary:hover { filter: brightness(1.1); }
.es-btn-secondary {
  color: var(--ink);
  background: var(--bg-chrome);
  border: 1.5px solid var(--line);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
}
.es-btn-secondary:hover { filter: brightness(0.95); }

/* ---------- Status bar ---------- */

#statusbar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 12px;
  min-height: 34px;
  border-top: 1px solid var(--line);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
  background: var(--bg-chrome);
}

/* Coarse pointers (touch) get a taller bar and bigger tap targets across
   the whole footer -- field crews on tablets/phones, not desktop mouse
   users, are who this is for. */
@media (pointer: coarse) {
  #statusbar { padding: 10px 12px; min-height: 44px; }
  .page-nav-btn, .status-action-btn { width: 40px; height: 40px; font-size: 16px; }
}

/* Centered independent of the two flex groups' widths, so it doesn't drift
   toward whichever side has more content. Purely informational (which build
   is deployed), so it stays out of the way of clicks and hides once the bar
   is too narrow to safely fit alongside the doc name and page controls. */
#status-version {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0.55;
}
@media (max-width: 640px) {
  #status-version { display: none; }

  /* Phones: with a multipage file loaded, the doc-name/status-msg group
     (left) and the tip/manual buttons + page counter (right) no longer
     both fit on one line without overlapping. Stack them into two full-
     width rows instead of letting them collide. */
  #statusbar {
    flex-wrap: wrap;
    row-gap: 4px;
  }
  #status-group {
    flex: 1 1 100%;
    order: 1;
  }
  #status-right {
    flex: 1 1 100%;
    order: 2;
    justify-content: flex-end;
  }
}

#status-group {
  display: flex;
  gap: 12px;
  min-width: 0;
}

/* Long file names (name + page count) get an ellipsis instead of
   overflowing past the group's own box and running into the action
   buttons / page counter on the right. */
#status-doc {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

#status-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

#status-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.status-action-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--bg);
  color: var(--ink-dim);
  width: 26px;
  height: 26px;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
  touch-action: manipulation;
}
.status-action-btn:hover { color: var(--ink); border-color: var(--ink-dim); }
.status-action-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* Tip button borrows the same redline treatment as an active tool
   (.tb-btn.active) so it reads as "there's something new here" rather
   than blending in with the neutral Manual link next to it. */
#btn-tip.has-unseen-tip {
  color: var(--redline);
  background: var(--redline-soft);
  border-color: var(--redline);
}
.status-action-dot {
  display: none;
  position: absolute;
  top: -3px;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--redline);
  border: 1.5px solid var(--bg-chrome);
}
#btn-tip.has-unseen-tip .status-action-dot { display: block; }

#page-jump {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  white-space: nowrap;
}

#page-jump input {
  width: 34px;
  padding: 1px 3px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--bg);
  color: var(--ink-dim);
  font: inherit;
  text-align: center;
  /* hide native spinner arrows -- the prev/next buttons replace them with
     touch-sized tap targets instead */
  -moz-appearance: textfield;
}
#page-jump input::-webkit-outer-spin-button,
#page-jump input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.page-nav-btn {
  appearance: none;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--bg);
  color: var(--ink-dim);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  width: 26px;
  height: 22px;
  padding: 0;
  cursor: pointer;
  touch-action: manipulation; /* skip the double-tap-zoom delay on touch */
}
.page-nav-btn:disabled {
  opacity: 0.35;
  cursor: default;
}
.page-nav-btn:not(:disabled):active {
  background: var(--line);
}

@media (prefers-reduced-motion: no-preference) {
  .tb-btn { transition: all 120ms ease; }
}

/* ---------- Tip of the day popover ---------- */
#tip-popover {
  position: fixed;
  right: 12px;
  bottom: 44px;
  z-index: 600;
  width: 260px;
  max-width: calc(100vw - 24px);
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-panel);
  color: var(--ink);
  box-shadow: 0 6px 24px rgba(0,0,0,0.35);
  font-family: -apple-system, "Segoe UI", Roboto, Ubuntu, sans-serif;
  letter-spacing: normal;
}
#tip-popover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--redline);
}
#tip-popover-close {
  appearance: none;
  border: none;
  background: none;
  color: var(--ink-dim);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
}
#tip-popover-close:hover { color: var(--ink); }
#tip-popover-body {
  padding: 12px;
  font-size: 13px;
  line-height: 1.45;
}
#tip-popover-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px 10px;
  border-top: 1px solid var(--line);
}
#tip-popover-footer button {
  appearance: none;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--bg);
  color: var(--ink-dim);
  width: 28px;
  height: 28px;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
}
#tip-popover-footer button:hover { color: var(--ink); border-color: var(--ink-dim); }
#tip-popover-count {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  color: var(--ink-dim);
}
@media (pointer: coarse) {
  #tip-popover { bottom: 54px; }
  #tip-popover-footer button { width: 36px; height: 36px; }
}

/* ---------- Shape hint bar ---------- */
#shape-hint {
  display: none;
  padding: 4px 14px;
  background: var(--bg-panel);
  border-bottom: 1px solid var(--line);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--focus);
  text-transform: uppercase;
}
#shape-hint.visible { display: block; }

/* Fill toggle */
.toggle-label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
  cursor: pointer;
  user-select: none;
}
.toggle-label input[type=checkbox] { accent-color: var(--redline); }
#fill-opacity { width: 70px; accent-color: var(--redline); }

/* Shape-tool cursor variants */
#viewer.tool-line,
#viewer.tool-rect,
#viewer.tool-triangle,
#viewer.tool-polygon,
#viewer.tool-arrow,
#viewer.tool-circle,
#viewer.tool-diamond { cursor: crosshair; }

/* Preview canvas (SVG overlay injected per page) */
.page .preview {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}

/* ===== THEME VARIABLES ===== */

/* Light theme (explicit) */
[data-theme="light"] {
  --bg:        #f4f4f4;
  --bg-chrome: #ffffff;
  --fg:        #1a1a1a;
  --line:      #cccccc;
  --active:    #1554C9;
  --active-fg: #ffffff;
  --redline:   #D8260F;
  --shadow:    rgba(0,0,0,0.12);
  /* --ink/--ink-dim default to a light-on-dark palette (#d7dade / #8b9097)
     that reads fine against the dark chrome but is too washed-out against
     a white background -- darkened here for real contrast in light mode. */
  --ink:       #1a1a1a;
  --ink-dim:   #52565c;
}

/* Dark theme (explicit) */
[data-theme="dark"] {
  --bg:        #1a1a2e;
  --bg-chrome: #16213e;
  --fg:        #e0e0e0;
  --line:      #3a3a5c;
  --active:    #4a7fff;
  --active-fg: #ffffff;
  --redline:   #ff5c42;
  --shadow:    rgba(0,0,0,0.4);
}

/* Auto: follow OS preference */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #1a1a2e;
    --bg-chrome: #16213e;
    --fg:        #e0e0e0;
    --line:      #3a3a5c;
    --active:    #4a7fff;
    --active-fg: #ffffff;
    --redline:   #ff5c42;
    --shadow:    rgba(0,0,0,0.4);
  }
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:        #f4f4f4;
    --bg-chrome: #ffffff;
    --fg:        #1a1a1a;
    --line:      #cccccc;
    --active:    #1554C9;
    --active-fg: #ffffff;
    --redline:   #D8260F;
    --shadow:    rgba(0,0,0,0.12);
    --ink:       #1a1a1a;
    --ink-dim:   #52565c;
  }
}

#theme-group { margin-left: auto; }
#btn-theme { min-width: 64px; }

/* Shared look for every color swatch in the app -- the toolbar's Line/
   Fill/Label-BG color pickers, the Table editor's four color inputs, the
   Sign dialog's Type-tab ink color, the Text Box color, and the Sign
   dialog's Draw-tab Black/Blue buttons. These had drifted into four
   different combinations (a 22x22 bordered squircle, a borderless 32x24
   rect, a borderless 32x28 rect, and a 20x20 circle) -- one shape now,
   applied everywhere: a small bordered squircle, since that was already
   the most-used of the four and reads clearly as "swatch" against either
   theme without relying on the browser's own (inconsistent) default
   <input type="color"> chrome.
   Works for both a native <input type="color"> (which paints its own
   swatch content) and a plain <button> with its color set via inline
   `background` (used for the Draw-tab's fixed Black/Blue choice, since
   that's a pick between exactly two colors, not an open color picker). */
.color-swatch {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  padding: 0;
  border: 1.5px solid var(--line);
  border-radius: 5px;
  cursor: pointer;
  touch-action: manipulation;
}
.color-swatch.active {
  outline: 2px solid var(--redline);
  outline-offset: 2px;
}

/* ---------- Certificate quick-insert slots (StampInk) ----------
   Grid of CERT_SLOT_COUNT (main.js) labeled thumbnails shown in the
   Insert-Image quick panel. Same checkerboard-transparency background and
   dashed/solid border language already used for the Sign/Image upload
   previews above, so a filled or empty slot reads consistently with the
   rest of the app rather than introducing a new visual idiom. */
.certslot-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.certslot {
  position: relative;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  cursor: pointer;
  padding: 8px;
  text-align: center;
  touch-action: manipulation;
}
.certslot:hover { border-color: var(--ink-dim); }
.certslot-thumb-wrap {
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: repeating-conic-gradient(#ddd 0% 25%, transparent 0% 50%);
  background-size: 14px 14px;
  border-radius: 5px;
  overflow: hidden;
  margin-bottom: 6px;
}
.certslot-thumb { max-width: 100%; max-height: 100%; }
.certslot-label {
  font-size: 0.72rem;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.certslot-empty {
  height: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border: 1.5px dashed var(--line);
  border-radius: 5px;
  margin-bottom: 6px;
  color: var(--ink-dim);
}
.certslot-plus { font-size: 1.3rem; line-height: 1; }
.certslot-empty-text { font-size: 0.68rem; }
.certslot-edit {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg-chrome);
  color: var(--ink-dim);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: manipulation;
}
.certslot-edit:hover { color: var(--ink); border-color: var(--ink-dim); }
