/*
 * theme.css — Certify.
 *
 * Brief: a print shop's job counter. Warm paper ground, ink-black type,
 * hairline rules, and one colour — a stamped seal green — used for the
 * frame of a certificate and for the one action that matters. Crisp small
 * radii and flat surfaces, so the UI reads as a counter and the sheet on it
 * reads as paper. Nothing glassy, nothing gold.
 *
 * Type: Newsreader on the certificate itself (--font-display), Instrument
 * Sans for the interface (--font-body), DM Mono for dates and counts.
 */

:root {
  --canvas: #f4f3ef;
  --surface: #ffffff;
  --surface-2: #eceae4;
  --border: #dcd9d1;
  --border-strong: #b3afa4;
  --ink: #1c1b18;
  --muted: #6a675e;
  --accent: #1f5d4c;
  --accent-hover: #174b3d;
  --accent-ink: #ffffff;
  --accent-text: #1a5142;
  --accent-strong: #174537;
  --accent-soft: #dde9e4;
  --accent-border: #b3ccc3;
  --success: #2f6f4e;
  --success-ink: #ffffff;
  --success-soft: #e0ece5;
  --success-strong: #285f43;
  --warning: #8a5a12;
  --warning-ink: #ffffff;
  --warning-soft: #f2e7d4;
  --warning-strong: #7a4f0f;
  --danger: #a32020;
  --danger-ink: #ffffff;
  --danger-soft: #f4e0df;
  --danger-strong: #96201f;
  --chart-1: #1f5d4c;
  --chart-2: #8a5a12;
  --chart-3: #3f5f86;
  --chart-4: #7a3f5e;
  --chart-5: #5c6b32;
  --chart-6: #a32020;

  --font-display: "Newsreader", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Instrument Sans", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --display-weight: 500;
  --display-tracking: -0.01em;
  --eyebrow-tracking: 0.22em;

  --radius-btn: 5px;
  --radius-card: 8px;
  --radius-input: 5px;
  --border-w: 1px;
  --border-strong-w: 1px;
  --shadow-card: none;
  --shadow-raised: 0 1px 2px rgb(28 27 24 / 0.10);
  --shadow-btn: none;
  --card-pad: 1.25rem;
  --caps: uppercase;
  --caps-tracking: 0.14em;
  --btn-weight: 500;
  --measure: 62ch;
}

html[data-theme="dark"] {
  --canvas: #121413;
  --surface: #1b1e1c;
  --surface-2: #242826;
  --border: #313633;
  --border-strong: #4c534f;
  --ink: #f0f1ee;
  --muted: #a2a8a3;
  --accent: #4fbf9a;
  --accent-hover: #6ccfae;
  --accent-ink: #0d1613;
  --accent-text: #66cba8;
  --accent-strong: #7fd8b8;
  --accent-soft: #1b2e27;
  --accent-border: #2f4f44;
  --success: #3f9d6d;
  --success-ink: #0b1a12;
  --success-soft: #17301f;
  --success-strong: #79c99b;
  --warning: #d0a24a;
  --warning-ink: #1d1503;
  --warning-soft: #332711;
  --warning-strong: #e0bd7c;
  --danger: #e05c5c;
  --danger-ink: #1c0808;
  --danger-soft: #3a1c1c;
  --danger-strong: #f09a9a;
  --chart-1: #4fbf9a;
  --chart-2: #d0a24a;
  --chart-3: #7fa8dd;
  --chart-4: #cd8ab0;
  --chart-5: #a8bd6e;
  --chart-6: #e05c5c;
}

/*
 * app.css — the two screens no primitive covers: the certificate sheet, and
 * the filing cabinet around it.
 *
 * THE SHEET is sized by ratio, not by pixels, and every measurement inside it
 * is in cqw — a percentage of the sheet's own width. That is what lets ONE
 * set of rules serve both the small live preview on the composer and the full
 * sheet that goes to the printer: scale the container and the whole
 * composition scales with it. Because the unit is a percentage of WIDTH, a
 * portrait sheet's type scales down with it automatically and nothing
 * overflows; what portrait needs is more air, and that is all its rules add.
 *
 * MOTION here is the kind that explains something: a folder opening, a row
 * leaving, a bar arriving because a selection exists. Anything purely
 * decorative is left to the platform's data-reveal attributes, and every
 * rule below stops at prefers-reduced-motion.
 */

/* ======================================================================== *
 * THE SHEET
 * ======================================================================== */

.cert-stage {
  container-type: inline-size;
  width: 100%;
  background: var(--surface);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.cert {
  --cert-accent: var(--accent);
  --cert-display: var(--font-display);
  position: relative;
  width: 100%;
  aspect-ratio: 297 / 210;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--cert-display);
  break-inside: avoid;
  overflow: hidden;
}

.cert--portrait {
  aspect-ratio: 210 / 297;
}

/* --- the accents: the palette's own colours, never a loose value --------- */

.cert--accent-seal { --cert-accent: var(--accent); }
.cert--accent-amber { --cert-accent: var(--chart-2); }
.cert--accent-slate { --cert-accent: var(--chart-3); }
.cert--accent-plum { --cert-accent: var(--chart-4); }
.cert--accent-olive { --cert-accent: var(--chart-5); }
.cert--accent-rust { --cert-accent: var(--chart-6); }

/* --- the display faces --------------------------------------------------- */

.cert--font-newsreader { --cert-display: "Newsreader", Georgia, "Times New Roman", serif; }
.cert--font-instrument { --cert-display: "Instrument Serif", Georgia, serif; }
.cert--font-unbounded { --cert-display: "Unbounded Variable", ui-sans-serif, system-ui, sans-serif; }
.cert--font-grotesk { --cert-display: "Space Grotesk Variable", ui-sans-serif, system-ui, sans-serif; }

/* --- the three frames ---------------------------------------------------- */

.cert-frame {
  position: absolute;
  inset: 3.4cqw;
  pointer-events: none;
}

.cert--ruled .cert-frame {
  border-top: 0.6cqw solid var(--cert-accent);
  border-bottom: 0.18cqw solid var(--cert-accent);
}

.cert--framed .cert-frame {
  border: 0.28cqw solid var(--border-strong);
  outline: 0.1cqw solid var(--cert-accent);
  outline-offset: 0.75cqw;
}

.cert--band .cert-frame {
  border: 0.16cqw solid var(--border-strong);
}

.cert--band::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2.4cqw;
  background: var(--cert-accent);
}

/* --- the composition ------------------------------------------------------ */

.cert-body {
  position: relative;
  width: 76cqw;
  text-align: center;
}

.cert--portrait .cert-body { width: 78cqw; }

.cert-logo {
  display: block;
  max-height: 7cqw;
  max-width: 34cqw;
  width: auto;
  margin: 0 auto 3.4cqw;
  object-fit: contain;
}

.cert-eyebrow {
  font-family: var(--font-body);
  font-size: 1.5cqw;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--cert-accent);
  margin: 0 0 2.6cqw;
}

.cert-lead {
  font-family: var(--font-body);
  font-size: 1.7cqw;
  color: var(--muted);
  margin: 0 0 1cqw;
}

.cert-name {
  font-size: 7.6cqw;
  line-height: 1.04;
  font-weight: 500;
  letter-spacing: -0.012em;
  margin: 0 0 1.8cqw;
  text-wrap: balance;
}

.cert-detail {
  font-family: var(--font-body);
  font-size: 1.9cqw;
  line-height: 1.55;
  margin: 0 auto 4.6cqw;
  max-width: 58cqw;
  text-wrap: balance;
}

.cert--portrait .cert-eyebrow { margin-bottom: 4cqw; }
.cert--portrait .cert-name { margin-bottom: 3cqw; }
.cert--portrait .cert-detail { margin-bottom: 8cqw; max-width: 66cqw; }

.cert-foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 4cqw;
}

.cert-sign {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.cert-rule {
  display: block;
  width: 100%;
  height: 0.12cqw;
  background: var(--border-strong);
  margin-bottom: 0.9cqw;
}

.cert-sign-name {
  font-size: 1.9cqw;
  line-height: 1.2;
}

.cert-sign-role {
  font-family: var(--font-body);
  font-size: 1.05cqw;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.5cqw;
}

.cert-seal {
  width: 9cqw;
  color: var(--cert-accent);
}

.cert-seal svg { display: block; width: 100%; height: auto; }

.cert-issuer {
  font-family: var(--font-body);
  font-size: 1.25cqw;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 3.2cqw 0 0;
}

/* --- the verification corner ---------------------------------------------- */

.cert-verify {
  position: absolute;
  right: 5.2cqw;
  bottom: 4.6cqw;
  width: 9cqw;
  text-align: center;
  font-family: var(--font-mono);
}

.cert--portrait .cert-verify { width: 12cqw; }

.cert-verify .qr {
  display: block;
  width: 100%;
  height: auto;
  --qr-bg: var(--surface);
  --qr-fg: var(--ink);
}

.cert-verify-code {
  display: block;
  font-size: 0.85cqw;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-top: 0.5cqw;
  word-break: break-all;
}

.cert--portrait .cert-verify-code { font-size: 1.1cqw; }

.cert-verify-slot {
  aspect-ratio: 1;
  border: 0.14cqw dashed var(--border-strong);
  border-radius: 0.4cqw;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.6cqw;
  font-family: var(--font-body);
  font-size: 0.85cqw;
  line-height: 1.3;
  color: var(--muted);
}

.verify-qr {
  width: 100%;
  max-width: 11rem;
  height: auto;
  --qr-bg: var(--surface);
  --qr-fg: var(--ink);
}

/* THE PREVIEW CROSS-FADES as it is retyped. The sheet is replaced wholesale
   on every keystroke burst, and without this the change reads as a flicker
   rather than as the sheet being redrawn. */
#preview .cert-stage {
  animation: fade-in 180ms var(--ease-out, ease-out) both;
}

/* ======================================================================== *
 * THE FILING CABINET
 * ======================================================================== */

/* --- the folder tree ------------------------------------------------------
   A <details> per branch, so the open state survives with no script and the
   keyboard works for free. The caret is the only thing that animates: the
   height of a <details> cannot be transitioned without fighting the element,
   and a half-fought animation is worse than none. */

.tree ul { list-style: none; margin: 0; padding: 0; }

.tree-node > summary {
  list-style: none;
}
.tree-node > summary::-webkit-details-marker { display: none; }

.tree-caret {
  transition: transform 180ms var(--ease, ease);
}
.tree-node[open] > summary .tree-caret {
  transform: rotate(90deg);
}

/* The indent is a rule you can see, so a deep branch reads as a branch. */
.tree-children {
  margin-left: 0.75rem;
  padding-left: 0.5rem;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.tree-node[open] > .tree-children > li {
  animation: fade-up 220ms var(--ease-out, ease-out) both;
}

/* --- the selection bar ----------------------------------------------------
   Always in the DOM so its actions cannot drift from the selection; it slides
   up from the bottom only once something is ticked. Sticky rather than fixed,
   so it sits inside the column and never covers the footer. */

.bulk-bar {
  position: sticky;
  bottom: 1rem;
  z-index: 10;
  pointer-events: none;
  opacity: 0;
  transform: translateY(0.75rem);
  transition:
    opacity 200ms var(--ease, ease),
    transform 200ms var(--ease-out, ease-out);
}

.bulk-bar.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.bulk-bar-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border: var(--border-w, 1px) solid var(--accent-border);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

/* --- rows leaving ---------------------------------------------------------
   htmx puts .htmx-swapping on an element it is about to replace. A row that
   is being trashed should look like it is going, not blink out. */

tr.htmx-swapping,
.htmx-swapping {
  opacity: 0;
  transition: opacity 200ms var(--ease, ease);
}

/* A table that has just been rebuilt announces itself once, quietly. */
#library .table-wrap {
  animation: fade-in 200ms var(--ease-out, ease-out) both;
}

/* --- reduced motion -------------------------------------------------------
   Everything above arrives at its final state instantly. The bar still
   appears and disappears; it simply does not travel. */

@media (prefers-reduced-motion: reduce) {
  #preview .cert-stage,
  #library .table-wrap,
  .tree-node[open] > .tree-children > li {
    animation: none;
  }
  .bulk-bar,
  .tree-caret,
  tr.htmx-swapping,
  .htmx-swapping {
    transition: none;
  }
  .bulk-bar { transform: none; }
}

/* ======================================================================== *
 * SCREEN vs PAPER
 * ======================================================================== */

@page {
  margin: 0;
}

@media screen {
  .print-mode .cert-stage {
    border: var(--border-w) solid var(--border);
    box-shadow: var(--shadow-raised);
    margin: 0 auto 1.5rem;
  }
}

@media print {
  .no-print { display: none !important; }

  .cert-stage {
    width: 297mm;
    border: 0;
    border-radius: 0;
    margin: 0;
    break-after: page;
    page-break-after: always;
    animation: none;
  }

  .cert-stage.is-portrait { width: 210mm; }

  .cert-stage:last-of-type {
    break-after: auto;
    page-break-after: auto;
  }
}
