/* ==========================================================================
   Paper — a warm, dense system for internal tools.
   Full write-up: paper-design-system.md

   The rules everything else follows from:
   structure comes from hairlines, not shadows; two border weights doing two
   different jobs (--line is a boundary, --line-soft a separator); one accent
   spent on two things; warm neutrals; density over whitespace.
   ========================================================================== */

/* --- 1. Tokens (§4.1) ---------------------------------------------------- */

:root {
  color-scheme: light;

  --bg: #fbfaf8;
  --surface: #ffffff;
  --strip: #f5f3ef;
  --line: #e6e2da;
  --line-soft: #f0ece5;
  --input-line: #e0dbd2;

  --ink: #2b2926;
  --body: #78736c;
  --muted: #a8a29a;

  --accent: #0f766e;
  --accent-dark: #0b5b55;
  --on-accent: #ffffff;

  --warn: #b45309;
  --danger: #b42318;
  --danger-bg: #fdf3f2;
  --danger-line: #f6d9d5;

  --off: #c4bdb2;
  --off-dot: #ded8ce;

  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Wider than the canonical 1080px: the table has seven columns, three of them
     content. A deliberate departure from §2.4. */
  --shell: 1160px;

  --focus: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* There is deliberately no dark variant: the system is light, and the
   `color-scheme: light` above stops the browser from repainting native controls
   to match a dark system theme. The dark palette is in §5 if it is ever needed. */

/* --- 2. Base ------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: .875rem;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-dark); text-decoration: underline; }

code, kbd, pre { font-family: var(--font-mono); }

code {
  font-size: .8125rem;
  background: var(--strip);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  padding: 1px 5px;
  color: var(--body);
}

h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -.02em; color: var(--ink); }
h1 { font-size: 1.375rem; }
h2 { font-size: 1rem; }

p { margin: 0; }

::placeholder { color: var(--muted); }

::selection { background: color-mix(in srgb, var(--accent) 22%, transparent); }

/* --- 3. Shell (§3.1) ----------------------------------------------------- */

.topbar {
  background: var(--strip);
  border-bottom: 1px solid var(--line);
}

.topbar-inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 12px 24px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand {
  font-weight: 650;
  font-size: .875rem;
  letter-spacing: -.01em;
  color: var(--ink);
  text-decoration: none;
}
.brand:hover { color: var(--ink); text-decoration: none; }
.brand span { color: var(--accent); }

.topbar-note {
  font-size: .78125rem;
  color: var(--muted);
}

.push { margin-left: auto; }

/* Grid rather than margins between children: a hidden panel (the export one)
   must not leave an empty gap behind it. */
.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 22px 24px 64px;
  display: grid;
  gap: 16px;
  align-content: start;
}
.shell > * { min-width: 0; }

/* --- 4. Panel and strips (§3.2) ------------------------------------------ */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}

.panel-strip {
  background: var(--strip);
  padding: 12px 20px;
  font-size: .8125rem;
  color: var(--body);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.panel-strip.is-top { border-bottom: 1px solid var(--line); }
.panel-strip.is-bottom { border-top: 1px solid var(--line); }
.panel-strip.is-plain { background: var(--surface); }
.panel-strip + .panel-strip { border-top: 1px solid var(--line-soft); }

.panel-strip.is-error {
  background: var(--danger-bg);
  border-bottom-color: var(--danger-line);
  border-top-color: var(--danger-line);
  color: var(--danger);
}

/* The system's signature: 10.5px, uppercase, 0.09em (§2.3). It names every strip. */
.strip-label {
  font-size: .65625rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 700;
  color: var(--muted);
  white-space: nowrap;
}

.panel-body { padding: 16px 20px; display: grid; gap: 12px; }
.panel-body > * { min-width: 0; }

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

.hint {
  font-size: .75rem;
  color: var(--muted);
  max-width: 78ch;
}
.hint code { font-size: .71875rem; }

.notes {
  padding: 0 4px;
  display: grid;
  gap: 8px;
}

/* --- 5. Buttons (§3.6) — two of them, plus a destructive variant -------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: inherit;
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1.3;
  border-radius: 8px;
  padding: 7px 15px;
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background-color .12s, border-color .12s, color .12s;
}

.btn-primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); color: var(--on-accent); text-decoration: none; }

.btn-ghost { background: var(--surface); border-color: var(--input-line); color: var(--body); }
.btn-ghost:hover { border-color: var(--muted); color: var(--ink); text-decoration: none; }

/* A destructive action is a ghost button with red text, never a red fill: the
   fill draws the eye to the most dangerous control on the screen (§3.6). */
.btn-danger { background: var(--surface); border-color: var(--input-line); color: var(--danger); }
.btn-danger:hover { border-color: var(--danger); color: var(--danger); text-decoration: none; }

.btn-sm { padding: 6px 13px; font-size: .78125rem; }
.btn-xs { padding: 3px 8px; font-size: .75rem; border-radius: 6px; }

/* Icon-only button: a fixed square, so a row of them never shifts width when the
   icon inside changes. Every one of these needs a title and an aria-label —
   the label the icon replaced moves there. */
.btn-icon {
  padding: 0;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  justify-content: center;
  gap: 0;
  flex: none;
}
.btn-icon svg { width: 14px; height: 14px; display: block; }

.icon-group { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }

.btn:disabled, .btn[disabled] { opacity: .5; pointer-events: none; }

.btn:focus-visible { outline: none; box-shadow: var(--focus); }

/* --- 6. Fields ----------------------------------------------------------- */

input[type="text"], input[type="password"], input[type="search"],
textarea, select {
  font-family: inherit;
  font-size: .84375rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--input-line);
  border-radius: 8px;
  padding: 9px 12px;
  width: 100%;
}

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: var(--focus);
}

input:disabled, textarea:disabled, select:disabled {
  background: var(--strip);
  color: var(--muted);
  cursor: not-allowed;
}

textarea {
  font-family: var(--font-mono);
  font-size: .8125rem;
  line-height: 1.55;
  resize: vertical;
}

input[type="checkbox"] {
  width: auto;
  accent-color: var(--accent);
  margin: 0;
  cursor: pointer;
}

label { cursor: pointer; }

.field { padding: 16px 20px; border-bottom: 1px solid var(--line-soft); }
.field:last-of-type { border-bottom: 0; }

.field-label {
  display: block;
  font-size: .65625rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: 7px;
}

.inline-field {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .78125rem;
  color: var(--body);
  cursor: pointer;
}
.inline-field input[type="text"] { width: 5.5rem; }
.inline-field select { width: auto; padding: 5px 8px; font-size: .78125rem; }

/* --- 7. Status dot (§3.4) ----------------------------------------------- */

.dot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .71875rem;
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}
.dot::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}
.dot.is-off { color: var(--off); }
.dot.is-off::before { background: var(--off-dot); }

/* The key status is the same component; JS puts the class on it. */
#key-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .71875rem;
  font-weight: 600;
  white-space: nowrap;
}
#key-status::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  flex: none;
}
#key-status.locked { color: var(--body); }
#key-status.locked::before { background: var(--off-dot); }
#key-status.unlocked { color: var(--accent); }
#key-status.unlocked::before { background: var(--accent); }

/* --- 8. Key strip (§3.5) ------------------------------------------------ */

#keybar { gap: 10px; }

/* Secret field (§3.5): monospace plus the tracking that makes a masked value
   look like a real one. */
#key-input {
  flex: 1;
  min-width: 16rem;
  max-width: 30rem;
  font-family: var(--font-mono);
  font-size: .8125rem;
  letter-spacing: 2px;
}
#key-input::placeholder { letter-spacing: 0; }

#delimiter {
  flex: none;
  width: 5rem;
  font-family: var(--font-mono);
  font-size: .8125rem;
  text-align: center;
  padding: 6px 8px;
}

/* The key panel gets an accent edge once the key is in — the one place where the
   accent signals state rather than an action. */
body.unlocked #controls { border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }

/* --- 9. Table (§3.3) ----------------------------------------------------- */

.table-wrap { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: .84375rem;
  margin: 0;
}

.table th {
  text-align: left;
  font-weight: 600;
  font-size: .65625rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 9px 16px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  background: var(--surface);
}

.table td {
  padding: 11px 16px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--strip); }

/* Utility columns shrink to their content; the three content ones split the rest. */
#records th.check, #records td.check,
#records th.actions, #records td.actions,
#records td.id, #records td.created { width: 1%; white-space: nowrap; }

#records th.check, #records td.check { text-align: center; padding-left: 14px; padding-right: 8px; }

.scope-hint {
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--muted);
  margin-top: 2px;
}

#records td.id { color: var(--muted); font-variant-numeric: tabular-nums; }

/* max-width: 0 together with a percentage width is the only reliable way to get
   ellipsis truncation in an auto-layout table. Rows must not wrap: a two-line row
   destroys the very density this is all built for (§3.3). */
#records th[data-sort^="col_"], #records td.cell {
  max-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A is free text and gets the room; B is a small repeating set, so it only needs
   what its multi-select asks for (.ts-wrapper min-width) and no more. */
#records th[data-sort="col_a"], #records td.cell[data-col="col_a"] { width: 80%; }
#records th[data-sort="col_b"], #records td.cell[data-col="col_b"] { width: 20%; }

#records td.cell.garbage {
  font-family: var(--font-mono);
  font-size: .75rem;
  color: var(--muted);
}

#records td.cell input { width: 100%; padding: 5px 8px; font-size: .8125rem; }

#records td.created { font-size: .78125rem; color: var(--body); line-height: 1.35; text-align: right; }
#records td.created .ago { font-size: .6875rem; color: var(--muted); }

#records tbody tr.is-selected td { background: color-mix(in srgb, var(--accent) 5%, var(--surface)); }

/* Sortable headers */
.table th.sortable { cursor: pointer; user-select: none; }
.table th.sortable:hover { color: var(--body); }
.table th.sortable.sorted { color: var(--accent); }
.table th.sortable::after {
  content: attr(data-arrow);
  font-size: .625rem;
  margin-left: 5px;
  letter-spacing: 0;
}
.table th.sortable.disabled { cursor: default; color: var(--off); }
.table th.sortable.disabled:hover { color: var(--off); }

/* Filter row */
#filter-row th {
  background: var(--strip);
  padding: 7px 16px;
  border-bottom: 1px solid var(--line);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}
/* Both filter controls are pinned to the same height so the row cannot grow.
   The bare <select multiple> is what shows before the key is entered — Tom Select
   only takes over once there are decrypted values to list — and a native one is
   four rows tall by default, which is where the row used to balloon. */
#filter-row input.col-filter,
#filter-row select[multiple] {
  height: 28px;
  font-size: .78125rem;
  border-radius: 6px;
}
#filter-row input.col-filter { padding: 5px 9px; }
#filter-row select[multiple] { padding: 4px 8px; }
#filter-row .actions { text-align: right; }

/* Row actions. Now that they are icons rather than words they stay visible at all
   times — an icon that is also hidden until hover is two lost affordances at once.
   Hovering the row lifts them out of --muted; hovering the button itself gives
   them an outline, and the delete one turns red only there. */
#records td.actions { text-align: right; }
#records td.actions .btn { border-color: transparent; background: transparent; color: var(--muted); }
#records tbody tr:hover td.actions .btn { color: var(--body); }
#records td.actions .btn:hover { border-color: var(--input-line); background: var(--surface); color: var(--ink); }
#records td.actions .delete-btn:hover { border-color: var(--danger); color: var(--danger); }
#records td.actions .icon-group { gap: 2px; }

/* A row being edited: its actions stay visible without hovering. */
#records tbody tr.is-editing td { background: var(--strip); }
#records tbody tr.is-editing td.actions .btn { border-color: var(--input-line); background: var(--surface); color: var(--body); }

/* Empty state (§3.8) */
.empty {
  padding: 56px 20px;
  text-align: center;
  color: var(--body);
  font-size: .875rem;
  border-top: 1px solid var(--line-soft);
}

/* --- 10. Pagination ------------------------------------------------------ */

#pager { justify-content: flex-start; }
#page-info { color: var(--body); font-size: .78125rem; }

/* --- 11. Selection strip ------------------------------------------------ */

#selection-info { font-weight: 600; color: var(--ink); font-size: .78125rem; }

/* --- 12. Batch: encryption preview -------------------------------------- */

#batch > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
#batch > summary::-webkit-details-marker { display: none; }
#batch > summary::after {
  content: "▸";
  color: var(--muted);
  font-size: .75rem;
  margin-left: auto;
}
#batch[open] > summary { border-bottom: 1px solid var(--line); }
/* The summary already draws the boundary; the strip below must not add a second. */
#batch > summary + .panel-strip { border-top: 0; }
#batch[open] > summary::after { content: "▾"; }
#batch > summary:hover { background: color-mix(in srgb, var(--accent) 4%, var(--strip)); }

#batch-form, #batch-preview { display: grid; gap: 12px; }
#batch-form > *, #batch-preview > * { min-width: 0; }
#batch-input { min-height: 7.5rem; }

.batch-errors {
  color: var(--danger);
  background: var(--danger-bg);
  border: 1px solid var(--danger-line);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: .78125rem;
}

/* The plain value and its ciphertext stacked: the whole point of the preview is
   seeing that only the bottom line travels upstream. */
table.preview { width: 100%; border-collapse: collapse; font-size: .8125rem; }
table.preview th {
  text-align: left;
  font-size: .65625rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 700;
  color: var(--muted);
  padding: 7px 10px;
  border-bottom: 1px solid var(--line);
}
table.preview td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
table.preview tbody tr:last-child td { border-bottom: 0; }
table.preview td.id { color: var(--muted); width: 1%; font-variant-numeric: tabular-nums; }
table.preview .plain { color: var(--ink); font-weight: 600; }
table.preview .cipher {
  font-family: var(--font-mono);
  font-size: .6875rem;
  color: var(--muted);
  overflow-wrap: anywhere;
  margin-top: 3px;
}

.preview-frame {
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}

#batch details.request {
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
#batch details.request > summary {
  padding: 9px 12px;
  background: var(--strip);
  font-size: .78125rem;
  color: var(--body);
  cursor: pointer;
  user-select: none;
}
#batch details.request > summary:hover { color: var(--ink); }
#batch details.request[open] summary { border-bottom: 1px solid var(--line); }
#batch pre {
  margin: 0;
  padding: 12px;
  background: var(--surface);
  overflow: auto;
  font-size: .6875rem;
  line-height: 1.5;
  max-height: 18rem;
  color: var(--body);
}

/* --- 13. Export ---------------------------------------------------------- */

#export-output { min-height: 9rem; }
#copy-status { font-size: .75rem; color: var(--accent); }
#export-count { color: var(--muted); font-weight: 400; }

/* --- 14. Flash messages -------------------------------------------------- */

.flash {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: .8125rem;
}
.flash.alert { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger); }
.flash.notice { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 25%, transparent); color: var(--accent-dark); }

/* --- 15. Sign-in --------------------------------------------------------- */

.login-shell {
  max-width: 420px;
  margin: 0 auto;
  padding: 10vh 24px 64px;
}
.login-shell > * + * { margin-top: 16px; }

.login-title {
  font-size: .65625rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 700;
  color: var(--muted);
}

/* --- 16. Tom Select: fitted to the system -------------------------------- */

.ts-wrapper { min-width: 11rem; }

/* min-height matches the bare <select> it replaces, so the filter row does not
   jump when the key is entered and Tom Select takes over. */
.ts-wrapper.multi .ts-control {
  background: var(--surface);
  border: 1px solid var(--input-line);
  border-radius: 6px;
  padding: 2px 6px;
  font-size: .78125rem;
  color: var(--ink);
  box-shadow: none;
  min-height: 28px;
}

.ts-wrapper.multi.focus .ts-control {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: var(--focus);
}

.ts-wrapper.multi .ts-control > div {
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  color: var(--accent-dark);
  border-radius: 4px;
  padding: 1px 6px;
  font-size: .71875rem;
}

.ts-wrapper.multi .ts-control > div .remove { border-left-color: color-mix(in srgb, var(--accent) 25%, transparent); }

.ts-wrapper.disabled .ts-control { background: var(--strip); opacity: 1; }

.ts-control input, .ts-control input::placeholder { color: var(--muted); font-size: .78125rem; }

.ts-dropdown {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgb(0 0 0 / .08);
  font-size: .8125rem;
  color: var(--ink);
  margin-top: 4px;
}
.ts-dropdown .option { padding: 6px 12px; }
.ts-dropdown .active { background: var(--strip); color: var(--ink); }
.ts-dropdown .selected { color: var(--accent); }
.ts-dropdown .no-results { color: var(--muted); padding: 6px 12px; }

/* --- 17. Narrow screens -------------------------------------------------- */

@media (max-width: 720px) {
  .shell { padding: 16px 12px 48px; }
  .topbar-inner { padding: 10px 12px; }
  .panel-strip { padding: 10px 14px; }
  .panel-body { padding: 14px; }
  .table th, .table td { padding-left: 12px; padding-right: 12px; }
  #key-input { min-width: 0; }
}
