/* Bitcoinartwear UI, modelled on the Shopify admin (user decision 30/8-2026).

   WHY: the owner works in the Shopify admin every day and on bitcoinartwear.com.
   An app that looks and behaves like the admin needs no separate learning.

   The rules this follows, so a new page cannot drift:
   - Light is the default theme (the Shopify admin is light). Dark is kept and
     switchable under Settings > My profile.
   - 1px hairlines ARE allowed, around cards and between table rows. That is a
     deliberate softening of the old "no borders" rule (decision 30/8-2026),
     because the hairline is what makes the Shopify look. Shadows and gradients
     are still OUT: depth comes from background tone, never from a glow.
   - Body text 13px, page title 20px, card title 14px, the admin's scale.
   - Corners: 12px on cards, 8px on controls, badges and nav rows.
   - Controls are 32px tall. Everything lines up on that height.

   Every colour is a token below. A page never hardcodes a colour. */

/* ---------------- Tokens: light (default) ---------------- */
:root, [data-theme="light"] {
  color-scheme: light;

  --bg: #f1f1f1;            /* the page itself */
  --nav-bg: #ebebeb;        /* the left menu, one step darker than the page */
  --panel: #ffffff;         /* cards */
  --card: #ffffff;
  --surface-sub: #fafafa;   /* table headers, quiet strips */
  --surface-hover: #f1f1f1; /* row and menu hover */
  --surface-active: #e3e3e3;

  --border: #e3e3e3;        /* hairline between rows and around cards */
  --border-input: #cdcdcd;  /* the slightly darker line around fields */

  --text: #303030;
  --muted: #616161;
  --disabled: #8a8a8a;

  --accent: #303030;        /* primary button fill */
  --accent-text: #ffffff;
  --accent-hover: #1a1a1a;

  --link: #005bd3;
  --focus: #005bd3;

  --ok-bg: #cdfee1;   --ok-text: #0c5132;
  --ok-fill: #0f7a4a; --ok-fill-hover: #0c6a40;
  --crit-bg: #ffe9e8; --crit-text: #8e1f0b; --crit-fill: #e0201a;
  --on-fill: #ffffff;       /* text on the strong ok/crit fills, both themes */
  /* The menu's count bubble (new messages): white with dark digits in BOTH
     themes (owner's call 17/10-2026). */
  --count-bg: #ffffff; --count-text: #303030; --count-border: #cdcdcd;
  /* The page note under a red menu mark: post-it yellow (owner's call
     17/10-2026), a tone apart from the orange warning badges. */
  --note-bg: #fff4b0; --note-text: #453700; --note-border: #ecd774;
  --warn-bg: #fff1e3; --warn-text: #5e4200;
  --info-bg: #ebf9fc; --info-text: #00404d;

  --green: #0c5132;
  --red: #8e1f0b;
  --blue: #005bd3;
  --amber: #5e4200;

  /* Chart series colours, validated for colour-blind separation and 3:1
     contrast against the panel surface in THIS mode (dataviz check,
     10/10-2026). The meaning is fixed across all charts: 1 = us / the
     primary measure, 2 = Bitcoin centric, 3 = broad crypto / secondary. */
  --chart-1: #005bd3;
  --chart-2: #b35a00;
  --chart-3: #0d9488;

  --overlay: rgba(0, 0, 0, 0.5);

  /* Tooltips: dark bubble on the light theme; in dark mode the bubble stays
     DARK too (brugerbeslutning 10/10-2026, never a white bubble there), so it
     has its own tokens instead of riding on the accent. */
  --tooltip-bg: #303030;
  --tooltip-text: #ffffff;
  --tooltip-border: #303030;   /* invisible against the bubble; dark mode needs one */
}

/* ---------------- Tokens: dark ---------------- */
[data-theme="dark"] {
  color-scheme: dark;

  --bg: #1a1a1a;
  --nav-bg: #1a1a1a;
  --panel: #262626;
  --card: #262626;
  --surface-sub: #2e2e2e;
  --surface-hover: #333333;
  --surface-active: #3d3d3d;

  --border: #3d3d3d;
  --border-input: #575757;

  --text: #e3e3e3;
  --muted: #b5b5b5;
  --disabled: #8a8a8a;

  --accent: #e3e3e3;
  --accent-text: #1a1a1a;
  --accent-hover: #ffffff;

  --link: #7fb3ff;
  --focus: #7fb3ff;

  --ok-bg: #133b28;   --ok-text: #a6f0c6;
  --ok-fill: #0f7a4a; --ok-fill-hover: #0c6a40;
  --crit-bg: #3d1a14; --crit-text: #ffb3a7; --crit-fill: #e0201a;
  --on-fill: #ffffff;
  --count-bg: #ffffff; --count-text: #000000; --count-border: #ffffff;
  --note-bg: #3a3313; --note-text: #ffe680; --note-border: #5c5122;
  --warn-bg: #3a2c12; --warn-text: #ffd79d;
  --info-bg: #10333a; --info-text: #a4e3ef;

  --green: #a6f0c6;
  --red: #ffb3a7;
  --blue: #7fb3ff;
  --amber: #ffd79d;

  /* Dark-mode chart steps: picked for the dark surface, not a flip of the
     light ones (validated separately, 10/10-2026). Same meaning as light. */
  --chart-1: #3b82f6;
  --chart-2: #d97706;
  --chart-3: #0d9488;

  --overlay: rgba(0, 0, 0, 0.65);

  --tooltip-bg: #3d3d3d;
  --tooltip-text: #e3e3e3;
  --tooltip-border: #575757;   /* lifts the dark bubble off the dark page */
}

/* ---------------- Shape and size tokens ---------------- */
:root {
  --sidebar-open-w: 232px;   /* the menu's full width, also while it peeks open */
  --sidebar-w: var(--sidebar-open-w);
  --ctrl-h: 32px;        /* every button, input and select is this tall */
  --r-card: 12px;
  --r-ctrl: 8px;
  /* FULL WIDTH (brugerbeslutning 17/10-2026): every app page uses the whole
     window, so grids gain columns and tables room on a big screen. Running
     text is capped by --measure instead (see "Readable text" below). */
  --content-max: none;
  /* Longest line for running text: about 95 characters at the 12 to 13px
     body sizes, fewer for a larger lead. A fixed length, not ch, so text of
     different sizes in one card shares one right edge. */
  --measure: 600px;
  --pad-x: 24px;         /* page gutter, shared by header and main so they align */
  /* Checkmark used as a mask for custom checkboxes (no image files). */
  --check-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.4l3.1 3.1L12.5 4.6' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* Collapsed rail: sidebar padding (12+12) + row padding (10+10) + icon (20). */
html[data-collapsed="true"] { --sidebar-w: 60px; }

/* ---------------- Base ---------------- */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* The hidden attribute always wins, whatever display an element's class
   sets (the nav-dots lesson, 10/10-2026). Intelligent UI leans on it:
   a control with nothing to do carries hidden and is simply gone. */
[hidden] { display: none !important; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  font-size: 13px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  margin-left: var(--sidebar-w);
  transition: margin-left 0.18s ease;
}

h1, h2, h3, h4 { font-weight: 650; letter-spacing: -0.01em; }
h2 { font-size: 14px; }
h3 { font-size: 13px; }
a { color: var(--link); }
strong { font-weight: 650; }

/* One focus ring for the whole app: visible, never on a plain mouse click. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-radius: var(--r-ctrl);
}

/* ---------------- Left menu ----------------
   Built by common.js from /api/nav. Sits on its own tone, and a faint 1px
   hairline on its right edge separates it from the page (owner's call
   17/10-2026, after a darker menu tone was tried and rejected). The line is
   a pseudo-element, not a border, so the 60px rail keeps its exact inner
   width; it rides along when the menu peeks open. */
.sidebar {
  position: fixed; left: 0; top: 0; height: 100vh; width: var(--sidebar-w);
  background: var(--nav-bg);
  display: flex; flex-direction: column; gap: 4px; padding: 12px;
  overflow: hidden; z-index: 50;
  transition: width 0.18s ease;
}
.sidebar::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0;
  width: 1px; background: var(--border); pointer-events: none;
}
.sidebar svg { width: 20px; height: 20px; flex-shrink: 0; }

/* Hover peek (owner's decision 17/10-2026): while the rail is collapsed, a
   cursor resting on it slides the full menu out OVER the content; the page
   never shifts, because --sidebar-w (and with it body's margin) stays at the
   rail width. common.js sets data-peek on <html>, for mouse pointers only,
   and removes it when the cursor leaves; the logo click pins the state. The
   collapsed hiding rules below therefore carry :not([data-peek]), except
   the toggle, which stays hidden while peeking: pinning is the logo's job.
   No border or shadow on the peeking menu: the nav tone is its own edge. */
html[data-collapsed="true"][data-peek] .sidebar { width: var(--sidebar-open-w); }

.nav-text { transition: opacity 0.15s ease; }
html[data-collapsed="true"]:not([data-peek]) .nav-text { opacity: 0; width: 0; overflow: hidden; }

/* MENU SIGNALS (wireNavSignals in common.js; brugerbeslutning 10/10 and
   17/10-2026): busy dots, a count bubble, a red alert. On the page's own
   link and on its level-1 row; they must show in a COLLAPSED menu too. The
   rail has no room beside the icon, so collapsed the dots drop to the row's
   bottom padding under the icon, and the count or alert sits on the icon's
   top right corner like a notification badge. Colour alone, no glow. */
.nav-dots { display: inline-flex; gap: 3px; margin-left: 7px; align-items: center; }
.nav-link { position: relative; }
.nav-link > .nav-dots { margin-left: -1px; }   /* + the row's 8px gap = 7px */
html[data-collapsed="true"]:not([data-peek]) .nav-link > .nav-dots {
  /* 18px of dots under the 20px icon at x 8 to 28: left 9 centres them. */
  position: absolute; left: 9px; bottom: 1px; margin: 0;
}
.nav-count, .nav-alert {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; border-radius: 999px; box-sizing: border-box;
  font-size: 10px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.nav-count {   /* white with dark digits in both themes (--count-*) */
  padding: 0 3px; background: var(--count-bg); color: var(--count-text);
  border: 1px solid var(--count-border); font-size: 9px;
}
.nav-alert { background: var(--crit-fill); color: var(--on-fill); }
.nav-link > :is(.nav-count, .nav-alert) { margin-left: auto; }
.nav-link > :is(.nav-count, .nav-alert) ~ :is(.nav-count, .nav-alert) { margin-left: 0; }
.nav-group > :is(.nav-count, .nav-alert) ~ .nav-chevron { margin-left: 2px; }
html[data-collapsed="true"]:not([data-peek]) .nav-link > :is(.nav-count, .nav-alert) {
  /* Anchored by its RIGHT edge on the row's edge, so a wider count grows
     left over the icon instead of being cut off by the rail. */
  position: absolute; top: 0; right: 0; margin: 0;
}
/* A sub item with a signal becomes a row, so the mark can sit on the right. */
.nav-sub:has(> .nav-sig) { display: flex; align-items: center; gap: 8px; }
.nav-sub:has(> .nav-sig) > .nav-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.nav-sub > .nav-dots { margin-left: -1px; }
.nav-sub > :is(.nav-count, .nav-alert) { margin-left: auto; }
.nav-dots i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--link);
  animation: dot-pulse 1.2s infinite ease-in-out;
}
.nav-dots i:nth-child(2) { animation-delay: 0.2s; }
.nav-dots i:nth-child(3) { animation-delay: 0.4s; }
/* The dot-pulse keyframes live with the shared loading dots further down. */

/* Top row: the shop identity, with the collapse toggle on the right.
   The 8px top margin drops the logo's centre to the page title's centre line:
   sidebar padding (12) + margin (8) + half the 28px row = 34px, matching the
   header's 18px top padding + half its 32px control row (owner's call 10/10-2026). */
.sidebar-top { display: flex; align-items: center; gap: 8px; margin: 8px 0 8px; }
.sidebar-brand {
  display: flex; align-items: center; min-width: 0; flex: 1;
  padding: 4px 8px; border-radius: var(--r-ctrl); text-decoration: none; color: var(--text);
}
.sidebar-brand:hover { background: var(--surface-hover); }
/* The real logo (symbol + wordmark in one file), swapped per theme. It is drawn
   20px tall in a row with the same padding as a menu row, so the knot symbol sits
   in the same 20px box and on the same x as every menu icon below it. It reads a
   touch larger than the icons, because their outlined art only fills 16px of that
   box, and that is deliberate (owner's call 30/8-2026); the logo may carry a little
   more weight than a menu icon. Collapsed, the box narrows to 20px and the wordmark
   is simply cropped away, so no second asset to keep in sync. */
.brand-logo {
  display: block; flex: 1; min-width: 0; height: 20px;
  background-image: url("/img/CVI/bitcoinartwear-logo-v8-black.svg");
  background-repeat: no-repeat;
  background-position: left center;
  background-size: auto 20px;
}
[data-theme="dark"] .brand-logo {
  background-image: url("/img/CVI/bitcoinartwear-logo-v8-white.svg");
}
.sidebar-toggle {
  flex-shrink: 0; background: none; border: none; cursor: pointer; font: inherit;
  color: var(--muted); padding: 4px 8px; border-radius: var(--r-ctrl);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.12s ease, color 0.12s ease;
}
.sidebar-toggle:hover { background: var(--surface-hover); color: var(--text); }
/* Closed, there is no toggle at all: a click anywhere in the rail opens it. */
html[data-collapsed="true"] .sidebar-toggle { display: none; }
html[data-collapsed="true"]:not([data-peek]) .brand-logo { flex: none; width: 20px; }

/* The middle scrolls when the menu outgrows the screen; top and bottom stay. */
.sidebar-scroll {
  flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: none;
  display: flex; flex-direction: column;
}
.sidebar-scroll::-webkit-scrollbar { display: none; }
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar-actions { margin-top: auto; padding-top: 8px; display: flex; flex-direction: column; gap: 2px; }
.sidebar-top, .sidebar-bottom { flex-shrink: 0; }

.nav-link {
  display: flex; align-items: center; gap: 8px; padding: 4px 8px;
  border-radius: var(--r-ctrl); color: var(--text); text-decoration: none;
  font-size: 13px; font-weight: 500; white-space: nowrap; width: 100%;
  background: none; border: none; cursor: pointer; font-family: inherit;
  transition: background 0.12s ease, color 0.12s ease;
}
.nav-link svg { color: var(--muted); }
.nav-link:hover { background: var(--surface-hover); }
.nav-link.active { background: var(--panel); font-weight: 650; }
.nav-link.active svg { color: var(--text); }
.sidebar-actions .nav-link:hover { background: var(--surface-hover); }
html[data-collapsed="true"]:not([data-peek]) .nav-link { padding: 4px 8px; gap: 0; justify-content: flex-start; }

/* Groups: chevron on the right, rotated when open. */
.nav-chevron {
  margin-left: auto; display: inline-flex; color: var(--muted);
  opacity: 0; transition: opacity 0.12s ease;
}
.nav-group:hover > .nav-chevron, .nav-group.open > .nav-chevron { opacity: 1; }
.nav-chevron svg { width: 14px; height: 14px; transition: transform 0.15s ease; }
.nav-group.open > .nav-chevron svg { transform: rotate(90deg); }
html[data-collapsed="true"]:not([data-peek]) .nav-chevron { display: none; }

.nav-subs { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 4px; }
.nav-sub {
  display: block; padding: 4px 8px 4px 36px; border-radius: var(--r-ctrl);
  color: var(--muted); text-decoration: none; font-size: 13px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  transition: background 0.12s ease, color 0.12s ease;
}
.nav-sub:hover { background: var(--surface-hover); color: var(--text); }
.nav-sub.active { background: var(--panel); color: var(--text); font-weight: 650; }
.nav-sub-3 { padding-left: 52px; }  /* third level: one more step in */
/* Third-level items carry an unbroken vertical line (owner's call 10/10-2026).
   It sits at 36px: the text edge shared by level 1 (8px padding + 20px icon +
   8px gap) and level 2 (its padding-left), drawn once on the nested container
   so the 2px row gaps cannot break it. */
.nav-subs .nav-subs { position: relative; }
.nav-subs .nav-subs::before {
  content: ""; position: absolute; left: 36px; top: 2px; bottom: 2px;
  width: 1px; background: var(--border);
}
/* A second-level group is a <button>, and without this it renders with the
   browser's own border and shrink-to-fit width, like a form control in a menu. */
.nav-sub.nav-group {
  display: flex; align-items: center; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  font-family: inherit; font-size: 13px; color: var(--muted);
}
.nav-sub.nav-group:hover { color: var(--text); }
.nav-sub.nav-group.open { color: var(--text); }
.nav-subs.collapsible { display: none; }
.nav-subs.collapsible.open { display: flex; }
html[data-collapsed="true"]:not([data-peek]) .nav-subs,
html[data-collapsed="true"]:not([data-peek]) .nav-subs.collapsible.open { display: none; }

/* Signed-in user at the bottom of the menu. */
.sidebar-bottom { padding-top: 8px; }
.sidebar-user {
  display: flex; align-items: center; gap: 8px; padding: 4px 8px;
  border-radius: var(--r-ctrl);
}
.sidebar-profile {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px;
  color: inherit; text-decoration: none; border-radius: 6px;
  padding: 2px 4px; margin: -2px -4px;
  transition: background 0.12s ease;
}
.sidebar-profile:hover { background: var(--surface-hover); }
.sidebar-avatar {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-active); color: var(--text);
  font-size: 11px; font-weight: 650; object-fit: cover; overflow: hidden;
}
.sidebar-username {
  flex: 1; min-width: 0; color: var(--text); font-size: 13px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar-logout {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer; padding: 4px;
  color: var(--muted); border-radius: 6px; transition: background 0.12s ease, color 0.12s ease;
}
.sidebar-logout:hover { background: var(--surface-hover); color: var(--text); }
html[data-collapsed="true"]:not([data-peek]) .sidebar-user { justify-content: center; gap: 0; }
html[data-collapsed="true"]:not([data-peek]) .sidebar-profile { flex: none; margin: 0; padding: 2px; }
html[data-collapsed="true"]:not([data-peek]) .sidebar-username,
html[data-collapsed="true"]:not([data-peek]) .sidebar-logout { display: none; }

/* ---------------- Sticky page header ----------------
   Title left, page controls right. common.js builds it from the page registry
   and publishes its height as --header-h for the sticky table headers.
   FAST KONVENTION (10/10-2026): header and main share --pad-x and
   --content-max, so the header's LAST control ends exactly on the content's
   right edge; nothing may sit to the right of it (common.js keeps the empty
   actions container out of the DOM for the same reason). */
header {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px;
  padding: 18px var(--pad-x) 14px;
  max-width: var(--content-max); margin: 0 auto;
  background: var(--bg);
}
.page-title { font-size: 20px; font-weight: 650; margin-right: auto; letter-spacing: -0.02em; }
/* The refresh icon stands right after the title (refreshButton in
   common.js); then IT pushes the right-hand controls away, not the title. */
.page-title:has(+ .hdr-refresh) { margin-right: 0; }
.hdr-refresh { margin-left: -6px; margin-right: auto; }
/* Work in progress on THIS page (17/10-2026): the three dots right after
   the title, before the refresh icon; the last of them pushes the right-hand
   controls away. Same dots as the menu's (.nav-dots). */
.page-title:has(+ .hdr-busy) { margin-right: 0; }
header .hdr-busy { margin-left: 10px; margin-right: auto; }
header .hdr-busy:has(+ .hdr-refresh) { margin-right: 0; }
.hdr-busy + .hdr-refresh { margin-left: 8px; }
.page-header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
header .page-header-actions { margin-left: 0; }
/* FAST KONVENTION (brugerbeslutning 12/10-2026): no text in the header. A
   page's status element lives in this line at the top of main instead
   (common.js moves it there) and the line is gone while it is empty. */
.page-status { margin: 0 0 12px; }
/* DRIFT NOTES (pageNote in common.js, fast konvention 17/10-2026): the one
   post-it yellow bar at the top of <main> for every standing condition the
   owner can fix (a paused agent, a missing key, a red menu mark). The same
   red "!" as the menu, then one short line per condition. Tone and a
   hairline only, like a card; no shadow. */
.page-alert {
  display: flex; align-items: flex-start; gap: 10px; margin: 0 0 16px;
  padding: 10px 14px; border-radius: var(--r-card);
  background: var(--note-bg); color: var(--note-text); border: 1px solid var(--note-border);
  font-weight: 550;
}
.page-alert .nav-alert { margin-top: 1px; }
.page-alert a { color: inherit; text-decoration: underline; }
.page-alert-text { flex: 1; min-width: 0; }
/* The x sits at the far right; the bar stays closed for that text for the
   rest of the browser session (pageNote in common.js). */
.page-alert-close {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin: -2px -6px -2px 0; padding: 0;
  border: 0; border-radius: 6px; background: none; color: inherit;
  cursor: pointer; opacity: 0.7; transition: background 0.12s ease, opacity 0.12s ease;
}
.page-alert-close:hover { opacity: 1; background: var(--note-border); }
.page-alert p + p { margin-top: 4px; }
.page-status:not(:has(.sub-h:not(:empty))) { display: none; }

.period-select select { min-width: 150px; }
.hdr-icon {
  width: var(--ctrl-h); height: var(--ctrl-h); flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border-input); border-radius: var(--r-ctrl);
  cursor: pointer; transition: background 0.12s ease;
}
.hdr-icon:hover { background: var(--surface-hover); }
.hdr-icon svg { width: 18px; height: 18px; }
/* The header's segment toggle (17/10-2026, first use: Products > Videos,
   Products / Heroes): one framed control, the chosen view filled with the
   active surface. Built by headerSegment() in common.js. */
.seg {
  display: inline-flex; height: var(--ctrl-h); flex-shrink: 0;
  border: 1px solid var(--border-input); border-radius: var(--r-ctrl);
  background: var(--panel); overflow: hidden;
}
.seg button {
  border: 0; background: transparent; color: var(--muted);
  padding: 0 12px; font: inherit; cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.seg button + button { border-left: 1px solid var(--border-input); }
.seg button:hover { background: var(--surface-hover); color: var(--text); }
.seg button[aria-pressed="true"] { background: var(--surface-active); color: var(--text); font-weight: 600; }
/* The icon toggle for a VIEW choice (iconToggle() in common.js, fast
   konvention 17/10-2026): desktop/phone, light/dark. Same frame as .seg,
   icons instead of words, the chosen one on the active surface. */
.icon-toggle {
  display: inline-flex; flex-shrink: 0; border: 1px solid var(--border-input);
  border-radius: var(--r-ctrl); background: var(--panel); overflow: hidden;
}
.icon-toggle button {
  display: flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--muted);
  padding: 5px 10px; cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.icon-toggle button + button { border-left: 1px solid var(--border-input); }
.icon-toggle button:hover { background: var(--surface-hover); color: var(--text); }
.icon-toggle button.on { background: var(--surface-active); color: var(--text); }
/* FAST KONVENTION (brugerbeslutning 11/10-2026): a filter in effect shows
   the NUMBER of selected filters in a small circle on the header's filter
   icon, never as "filtered: showing X of Y" text in the page's status
   line. filterBadge() in common.js owns the bubble. White with a black
   number, black with a white number in dark mode (ejerens valg): the
   panel/text tokens ARE that pair in both themes. */
.hdr-icon.on { background: var(--surface-active); position: relative; }
.flt-count {
  position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px;
  border-radius: 999px; background: var(--panel); color: var(--text);
  border: 1px solid var(--border-input); box-sizing: content-box;
  font-size: 10px; font-weight: 700; line-height: 16px; padding: 0 4px;
  text-align: center;
}

main {
  max-width: var(--content-max); margin: 0 auto;
  padding: 0 var(--pad-x) 56px;
}

/* Readable text (brugerbeslutning 17/10-2026): the page is full width, but
   running text never runs wider than --measure, on every page, with no page
   doing anything: paragraphs, disclaimers and the grey .sub-h help lines
   under fields. It only caps, so text in a narrow card is untouched. A page
   where a .sub-h is a stretching flex part (a status filling a form footer)
   lifts the cap on that one element, deliberately. */
main p,
main .disclaimer,
main .sub-h { max-width: var(--measure); }

/* ---------------- Cards ----------------
   .panel is the standard section card; .card is a card inside one. */
.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 16px;
  margin-bottom: 16px;
}
.panel.flush { background: none; border: 0; padding: 0; }
.panel-head {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 8px 12px; margin-bottom: 12px;
}
.panel-head h2, .panel-head h3 { margin: 0; }
/* FAST KONVENTION (13/10-2026): a subtitle in a panel head ("7 findings",
   a data-source note, a count) is RIGHT-ALIGNED, standing just left of the
   head's trailing control: the fold chevron when the section folds,
   otherwise the last button. Direct child only, so a subtitle inside a
   stacked title block keeps its place. */
.panel-head > .sub-h { margin-left: auto; text-align: right; }
.panel > .table-wrap:last-child, .panel > :last-child { margin-bottom: 0; }

/* FAST KONVENTION (10/10-2026): sections fold. A .panel with data-fold gets
   a clickable head with a chevron (wired by foldable() in common.js); the
   open/closed state is a display preference and lives in this browser,
   like the sidebar. Buttons and inputs in the head keep working. */
.panel.foldable > .panel-head { cursor: pointer; user-select: none; }
.fold-chevron { display: inline-flex; color: var(--muted); }
.fold-chevron svg { transform: rotate(90deg); transition: transform 0.15s ease; }
.panel.folded .fold-chevron svg { transform: none; }
.panel.folded > .panel-head { margin-bottom: 0; }
.panel.folded > :not(.panel-head) { display: none; }

.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 16px;
}
.panel .card { background: var(--panel); }
.card-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 12px; }

/* ---------------- Service cards (Settings > API keys) ----------------
   One row per service when folded: brand tile, name, status. Shopify's admin
   shows installed apps as rounded tiles, so these are tiles too, with a real glyph
   where a free vector of the mark exists, a monogram where it does not. */
.svc-card { margin-bottom: 12px; }
.svc-card:last-child { margin-bottom: 0; }
.svc-head {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--text); text-align: left;
}
.svc-logo {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--svc-color, var(--accent)); color: #fff;
  font-size: 12px; font-weight: 700;
}
/* The glyph is a mask, not an image, so it renders white on the brand tile in
   both themes without shipping two files. */
.svc-logo img { display: block; width: 16px; height: 16px; }
/* Some marks ship with their own coloured tile, and those fill the square instead
   of sitting on one of ours. */
.svc-logo.full { background: none; overflow: hidden; }
.svc-logo.full img { width: 24px; height: 24px; }
/* The small inline variant (platMark in common.js): platform tiles inside
   table cells and badge rows, where the UI shows the icon instead of the
   written name (fixed convention 10/10-2026). */
.svc-logo.sm { width: 18px; height: 18px; border-radius: 5px; font-size: 10px; vertical-align: middle; }
.svc-logo.sm img { width: 12px; height: 12px; }
.svc-logo.sm.full img { width: 18px; height: 18px; }
.svc-logo.sm .svc-glyph { width: 11px; height: 11px; }
.svc-glyph {
  width: 15px; height: 15px; background: #fff;
  -webkit-mask: var(--glyph) center / contain no-repeat;
          mask: var(--glyph) center / contain no-repeat;
}
/* The shop pin (fast konvention 16/10-2026): generated images exist beyond
   what the shop shows (SoMe material, video sources, archive), so a
   thumbnail that IS on the Shopify product carries the platform tile in
   its corner. The wrapper hugs the image; the pin is platMark's tile. */
.pin-wrap { position: relative; display: inline-block; }
.pin-wrap .shop-pin {
  position: absolute; top: 4px; right: 4px; line-height: 0;
  border-radius: 6px; outline: 1px solid var(--border);
}
.svc-title { font-size: 14px; font-weight: 650; flex-shrink: 0; }
.svc-status {
  margin-left: auto; min-width: 0; display: flex; align-items: center; gap: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.svc-chevron { flex-shrink: 0; display: inline-flex; color: var(--muted); }
.svc-chevron svg { transition: transform 0.15s ease; transform: rotate(90deg); }
.svc-card.closed .svc-chevron svg { transform: none; }
.svc-card.closed .svc-body { display: none; }

/* KPI tiles, ready for the pages that get numbers on them. */
.cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px; margin-bottom: 16px;
}
.card-label { color: var(--muted); font-size: 12px; font-weight: 500; }
.card-value {
  font-size: 24px; font-weight: 650; margin-top: 6px;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.card-value .cur { font-size: 13px; font-weight: 550; color: var(--muted); margin-left: 4px; }
.card-sub { color: var(--muted); font-size: 12px; margin-top: 6px; }

/* Chart wrappers need a fixed height or a responsive canvas grows forever. */
.chart-box { position: relative; height: 320px; }
.chart-box-small { height: 130px; }
.chart-box canvas { width: 100% !important; height: 100% !important; }

/* ---------------- Tables ----------------
   Shopify's index table: quiet header strip, hairline between rows, the whole
   row lights up on hover. Text is left-aligned; numbers use .num. */
/* FAST KONVENTION (brugerbeslutning 15/10-2026): a table NEVER scrolls
   vertically; its frame grows with the rows, so a vertical scrollbar can
   never appear (overflow-y is hidden, and no frame carries a height cap).
   Horizontal scrolling stays where the table is wider than its panel, with
   a THIN scrollbar in the app's own design, never the browser's chunky
   default. */
.table-wrap { overflow-y: hidden; overflow-x: auto; }
/* The app's own THIN scrollbar is ONE design (tokens, 6px, transparent
   track) wherever something scrolls inside the app: table frames, the
   drawer's body, and any other scroll surface via the utility class
   .thin-scroll (first use 16/10-2026: the carousel strip in the Posts
   review drawer). Never the browser's chunky default. */
.table-wrap, .drawer-body, .thin-scroll {
  scrollbar-width: thin;                              /* Firefox */
  scrollbar-color: var(--border) transparent;
}
.table-wrap::-webkit-scrollbar, .drawer-body::-webkit-scrollbar,
.thin-scroll::-webkit-scrollbar { height: 6px; width: 6px; }
.table-wrap::-webkit-scrollbar-track, .drawer-body::-webkit-scrollbar-track,
.thin-scroll::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb, .drawer-body::-webkit-scrollbar-thumb,
.thin-scroll::-webkit-scrollbar-thumb {
  background: var(--border); border-radius: 3px;
}
.table-wrap::-webkit-scrollbar-thumb:hover, .drawer-body::-webkit-scrollbar-thumb:hover,
.thin-scroll::-webkit-scrollbar-thumb:hover { background: var(--muted); }
/* overflow must be fully visible here, or the wrap becomes its own (never
   scrolling) scroll container and position:sticky stops working against the
   page scroll. Wide tables therefore cannot side-scroll in a -full wrap;
   a table that needs that uses the plain scrolling .table-wrap instead. */
.table-wrap-full { max-height: none; overflow: visible; }
/* A full-page table that is wider than its panel trades its page-stuck
   header for a side-scroll (brugerfund 10/10 and 11/10-2026: buttons bled
   out of the panel). common.js MEASURES each table and sets .is-wide, so it
   holds at every window width and zoom, not only below a fixed breakpoint.
   The wrap then becomes a scroll container: the header pins to the frame
   instead of the page, the first column pins like in any scrolling wrap,
   and nothing ever paints outside the panel. */
.table-wrap-full.is-wide { overflow-x: auto; overflow-y: hidden; }
.table-wrap-full.is-wide thead th { top: 0; }
/* The 12/10-2026 viewport cap on .is-wide is gone (brugerbeslutning
   15/10-2026: a table's height always grows with its rows, never a
   vertical scrollbar). The cost, accepted with it: in a wide table taller
   than the window, the in-frame stuck header can leave the screen while
   the page scrolls. */
@media (max-width: 1100px) {
  .run-est { display: none; }   /* the price stays in the row and the tooltip */
}

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 9px 12px; font-size: 13px; vertical-align: middle; }
th {
  background: var(--surface-sub); color: var(--muted);
  font-size: 12px; font-weight: 550; white-space: nowrap;
}
/* FAST KONVENTION (10/10-2026): every table header and footer is sticky.
   In a scrolling wrap they pin to the wrap's edges; in a full-page table the
   header pins just below the sticky page header (its measured height is
   published as --header-h by common.js) and the footer to the viewport bottom.
   The separation line is the opaque strip colour alone: with
   border-collapse:collapse a border would stay behind when the row pins. */
.table-wrap:not(.table-wrap-full) thead th { position: sticky; top: 0; z-index: 2; }
.table-wrap-full thead th { position: sticky; top: var(--header-h, 0px); z-index: 2; }
.table-wrap tfoot td, .table-wrap tfoot th { position: sticky; bottom: 0; z-index: 2; }
/* FAST KONVENTION (brugerbeslutning 12/10-2026): the CARD pins with the
   table. While a full-page table's header (or footer) is stuck, the card
   around it keeps its rounded top (or bottom) edge right above (below) it,
   and a strip of page background keeps a little air between the card and
   the page header (or the window's bottom edge, or the phone's menu bar).
   common.js (frameTables) inserts two zero-height .frame-cap elements in
   each framed wrap, measures the card around it (--cap-l/--cap-r), and
   switches a cap .on exactly while its row is stuck; a page needs nothing
   beyond thead/tfoot. --bottom-h is the phone's menu bar (0 elsewhere). */
:root { --frame-gap: 8px; --frame-cap: var(--r-card); }
.table-wrap-full.framed:not(.is-wide) thead th {
  top: calc(var(--header-h, 0px) + var(--frame-gap) + var(--frame-cap));
}
.table-wrap-full.framed:not(.is-wide) tfoot td,
.table-wrap-full.framed:not(.is-wide) tfoot th {
  bottom: calc(var(--bottom-h, 0px) + var(--frame-gap) + var(--frame-cap));
}
.frame-cap { position: sticky; display: block; height: 0; z-index: 4; visibility: hidden; }
.frame-cap.on { visibility: visible; }
.frame-cap.top { top: calc(var(--header-h, 0px) + var(--frame-gap)); }
.frame-cap.bot { bottom: calc(var(--bottom-h, 0px) + var(--frame-gap)); }
.frame-cap::before, .frame-cap::after {
  content: ""; position: absolute; left: var(--cap-l, 0px); right: var(--cap-r, 0px);
}
/* The card's edge: panel colour, the card's hairline, the card's corners. */
.frame-cap::before {
  height: var(--frame-cap); background: var(--panel); border: 1px solid var(--border);
}
.frame-cap.top::before { top: 0; border-bottom: 0; border-radius: var(--r-card) var(--r-card) 0 0; }
.frame-cap.bot::before { bottom: 0; border-top: 0; border-radius: 0 0 var(--r-card) var(--r-card); }
/* The air: page background over whatever scrolls beneath it. */
.frame-cap::after { height: var(--frame-gap); background: var(--bg); }
.frame-cap.top::after { bottom: 0; }
.frame-cap.bot::after { top: 0; }
/* FAST KONVENTION (10/10-2026): the first column also pins, by default, while
   the table side-scrolls: in a scrolling .table-wrap, and in a -full wrap
   once it is measured .is-wide (see the -full note above). A page opts out with
   .no-pin-col on the wrap, as a deliberate choice when the page is built.
   Body cells get an opaque background so other columns slide beneath them;
   the corner cells pin on both axes and sit on top. */
.table-wrap:not(.table-wrap-full):not(.no-pin-col) thead th:first-child,
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tfoot td:first-child,
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tfoot th:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) thead th:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tfoot td:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tfoot th:first-child { left: 0; z-index: 3; }
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tbody td:first-child,
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tbody th:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tbody td:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tbody th:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--panel);
}
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tbody tr:hover td:first-child,
.table-wrap:not(.table-wrap-full):not(.no-pin-col) tbody tr:hover th:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tbody tr:hover td:first-child,
.table-wrap-full.is-wide:not(.no-pin-col) tbody tr:hover th:first-child {
  background: var(--surface-hover);
}
/* A group row (one cell spanning the whole table, e.g. "Marketing" on
   Agents) cannot pin like the first column: the cell is as wide as the
   table, so it slides out with it. Its label pins instead, at the first
   column's text edge (brugerfund 11/10-2026). Inert where nothing scrolls. */
.pin-label { position: sticky; left: 12px; display: inline-block; }
tfoot td, tfoot th {
  background: var(--surface-sub); color: var(--text);
  font-size: 12px; font-weight: 650; white-space: nowrap;
}
/* Table headers AND footers have square corners, everywhere in the app
   (brugerbeslutning 10/10-2026 for the head, 11/10-2026 for the foot). No
   radius on any table cell; rounding belongs to the card around it. */
tbody tr { border-top: 1px solid var(--border); }
tbody tr:first-child { border-top: 0; }
tbody tr:hover { background: var(--surface-hover); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Drag to sort (sortableRows + DRAG_HANDLE in common.js, 17/10-2026): a
   quiet grip in the row's first cell; the row being dragged lifts to the
   hover tone. Tone only, no shadow (the design rules). */
td.drag-cell, th.drag-cell { width: 36px; padding-right: 0; }
.drag-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; border: 0; background: none;
  border-radius: 6px; color: var(--muted); cursor: grab; touch-action: none;
  transition: background 0.12s ease, color 0.12s ease;
}
.drag-handle:hover { background: var(--surface-active); color: var(--text); }
/* A quiet icon-only button (first use: the mail editor's Duplicate,
   ejerens ønske 17/10-2026): the meaning lives in the tooltip and
   aria-label, the icon follows the theme (currentColor). */
.btn-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; border: 0; background: none;
  border-radius: 6px; color: var(--muted); cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.btn-icon:hover { background: var(--surface-active); color: var(--text); }
tbody tr.dragging { background: var(--surface-active); }
tbody tr.dragging .drag-handle { color: var(--text); }
body.is-sorting, body.is-sorting * { cursor: grabbing !important; user-select: none; }

/* Permission matrix (Settings > Users): grouped rows, checkboxes centred. */
.rights-table { max-width: 640px; }
.rights-table td input[type="checkbox"] { margin: 0; vertical-align: middle; }
/* Select-all box in a column head: the box sits in front of the word. */
.rights-table .us-all { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.rights-table .us-all input { margin: 0; }
.us-group td { font-weight: 650; color: var(--text); background: var(--surface-sub); }
.us-sub td:first-child { padding-left: 32px; }

/* ---------------- Buttons ---------------- */
.btn-primary, .btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: var(--ctrl-h); padding: 0 12px; border-radius: var(--r-ctrl);
  font-family: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background 0.12s ease, color 0.12s ease, opacity 0.12s ease;
}
.btn-primary { background: var(--accent); color: var(--accent-text); border: 1px solid var(--accent); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-ghost { background: var(--panel); color: var(--text); border: 1px solid var(--border-input); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-hover); }
.btn-primary:disabled, .btn-ghost:disabled { opacity: 0.45; cursor: not-allowed; }
/* FAST KONVENTION (10/10-2026): a button that approves is GREEN, a button
   that deletes, rejects or cancels is RED, everywhere in the app. Both are
   modifiers on .btn-primary, so the geometry lives in one place. */
.btn-critical { background: var(--crit-fill); color: #fff; border-color: var(--crit-fill); }
.btn-critical:hover:not(:disabled) { background: #b91c00; border-color: #b91c00; }
.btn-approve { background: var(--ok-fill); color: #fff; border-color: var(--ok-fill); }
.btn-approve:hover:not(:disabled) { background: var(--ok-fill-hover); border-color: var(--ok-fill-hover); }
/* PRIMARY vs SECONDARY (brugerbeslutning 10/10-2026): the strong fill is the
   button that COMMITS (Confirm rejection, Delete); the soft tint with the
   strong 1px border is the way there or the way back (Reject that opens a
   form, Cancel). The hue says what it leads to, the weight says whether it
   happens now. Hover fills to the strong colour. */
.btn-critical-soft { background: var(--crit-bg); color: var(--crit-text); border-color: var(--crit-fill); }
.btn-critical-soft:hover:not(:disabled) { background: var(--crit-fill); color: #fff; }
.btn-approve-soft { background: var(--ok-bg); color: var(--ok-text); border-color: var(--ok-fill); }
.btn-approve-soft:hover:not(:disabled) { background: var(--ok-fill); color: #fff; }
/* The THIRD weight (brugerbeslutning 10/10-2026): a destructive option that
   stands next to a row's real primary action (Delete beside Save, Reject
   beside Approve) is a plain red TEXT LINK; a soft tint appears on hover.
   Used on top of .btn-ghost for the geometry. */
.btn-critical-link { background: none; border-color: transparent; color: var(--crit-text); }
.btn-critical-link:hover:not(:disabled) { background: var(--crit-bg); border-color: transparent; }
.btn-sm { height: 28px; padding: 0 10px; font-size: 12px; }
/* The sparkle marks anything that runs a model (fast konvention 10/10-2026):
   in the button, or left of the link. svg from LLM_ICON in common.js. */
.btn-primary svg, .btn-ghost svg { flex-shrink: 0; }

/* ---------------- Form controls ---------------- */
input[type="text"], input[type="password"], input[type="email"], input[type="number"],
input[type="date"], input[type="datetime-local"], input[type="search"], select, textarea {
  height: var(--ctrl-h); padding: 0 10px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border-input); border-radius: var(--r-ctrl);
  font-family: inherit; font-size: 13px;
  transition: border-color 0.12s ease;
}
textarea { height: auto; padding: 8px 10px; line-height: 1.5; resize: vertical; }
input:hover:not(:disabled), select:hover:not(:disabled) { border-color: var(--muted); }
input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-hover); color: var(--disabled); cursor: not-allowed;
}
input::placeholder { color: var(--disabled); }
select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6 8l4 4 4-4' fill='none' stroke='%23616161' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 16px;
}
input::-webkit-calendar-picker-indicator { opacity: 0.6; cursor: pointer; }

input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; border-radius: 4px; margin: 0 6px 0 0;
  background: var(--panel); border: 1px solid var(--border-input);
  vertical-align: -3px; cursor: pointer; position: relative;
  transition: background 0.12s ease, border-color 0.12s ease;
}
input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
input[type="checkbox"]:checked::after {
  content: ""; position: absolute; inset: 1px;
  background: var(--accent-text);
  -webkit-mask: var(--check-mask) center / contain no-repeat;
          mask: var(--check-mask) center / contain no-repeat;
}
input[type="checkbox"]:disabled { opacity: 0.45; cursor: not-allowed; }

/* One preference per row (Settings > My profile). */
.setting-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 0; border-top: 1px solid var(--border);
}
.setting-row:first-child { border-top: 0; padding-top: 0; }
.setting-row label { font-size: 13px; font-weight: 500; }
.setting-row select { min-width: 200px; }
.setting-example { color: var(--muted); font-size: 12px; margin-top: 12px; }

/* ---------------- Status text and badges ---------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--r-ctrl);
  background: var(--surface-active); color: var(--text);
  font-size: 12px; font-weight: 550; white-space: nowrap;
}
.badge.done { background: var(--ok-bg); color: var(--ok-text); }
.badge.warn { background: var(--warn-bg); color: var(--warn-text); }
.badge.info { background: var(--info-bg); color: var(--info-text); }
.badge.critical { background: var(--crit-bg); color: var(--crit-text); }
.badges { display: flex; gap: 6px; flex-wrap: wrap; }

.pos { color: var(--green); }
.neg { color: var(--red); }
.neutral { color: var(--muted); }
.sub-h { color: var(--muted); font-size: 12px; }
.disclaimer { color: var(--muted); font-size: 12px; line-height: 1.6; margin-top: 12px; }
.disclaimer li { margin-bottom: 6px; }

.crumb { color: var(--muted); text-decoration: none; }
.crumb:hover { color: var(--text); text-decoration: underline; }
.crumb-sep { color: var(--disabled); margin: 0 4px; }
/* The page header's "List › Name" trail (pageCrumb in common.js). */
.page-title .crumb-sep { margin: 0 8px; font-weight: 400; }

/* Folding log rows (Settings > Log, a user's activity): a date row opens
   its groups, a group row its next level. Levels 2 and 3 step inwards. */
.log-day td { background: var(--surface-sub); color: var(--muted); font-size: 12px; font-weight: 650; }
tr.log-op, tr.log-day { cursor: pointer; }
tr.log-op:not([aria-expanded]) { cursor: default; }
.log-chevron { display: inline-flex; vertical-align: -2px; margin-right: 6px; color: var(--muted); }
.log-chevron svg { transition: transform 0.15s ease; }
tr.log-op.open .log-chevron svg, tr.log-day.open .log-chevron svg { transform: rotate(90deg); }
tr.log-l2 td:nth-child(2) { padding-left: 18px; }
tr.log-l3 td:nth-child(3) { padding-left: 18px; }

/* Empty state for pages that exist but have no content yet. */
.page-empty {
  display: grid; place-items: center; text-align: center;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-card);
  padding: 64px 24px; color: var(--muted);
}
.page-empty h2 { color: var(--text); margin-bottom: 6px; font-size: 15px; }
.page-empty p { max-width: 460px; font-size: 13px; }

/* ---------------- Dialogs ----------------
   Used for every confirmation and message (common.js). No shadow: the dimmed
   page behind it is what lifts the box. */
.confirm-overlay {
  position: fixed; inset: 0; z-index: 100;
  background: var(--overlay);
  display: grid; place-items: center; padding: 24px;
  animation: fade-in 0.12s ease;
}
.confirm-box {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-card);
  padding: 20px; width: min(440px, 100%);
  animation: pop-in 0.12s ease;
}
.confirm-box h3 { font-size: 15px; margin: 0 0 8px; }
.confirm-box p { margin: 0 0 18px; color: var(--muted); font-size: 13px; line-height: 1.55; }
.confirm-box.danger h3 { color: var(--crit-text); }
.confirm-box.danger [data-act="yes"] {
  background: var(--crit-fill); border-color: var(--crit-fill); color: #fff;
}
.confirm-box.danger .btn-primary:hover:not(:disabled) { background: #b91c00; border-color: #b91c00; }
.confirm-actions { display: flex; gap: 8px; justify-content: flex-end; }
.us-create-fields { display: flex; flex-direction: column; gap: 10px; margin: 0 0 18px; }
.us-create-fields input { width: 100%; }

/* ---------------- Drawer ----------------
   Page tools opened from a header icon (filter, page settings) live in a
   right-hand drawer on the dimmed page (common.js: openDrawer). No shadow:
   the dim and the 1px edge carry the depth, like the dialogs. */
.drawer-overlay {
  position: fixed; inset: 0; z-index: 100;
  background: var(--overlay);
  display: flex; justify-content: flex-end;
  animation: fade-in 0.12s ease;
}
.drawer {
  width: min(360px, 100%); height: 100%;
  background: var(--panel); border-left: 1px solid var(--border);
  display: flex; flex-direction: column;
  animation: drawer-in 0.16s ease;
}
/* The WIDE drawer (fast konvention 16/10-2026): for content that lays
   things side by side, like the Posts queue's series review. */
.drawer-wide { width: min(1120px, 100%); }
@keyframes drawer-in { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.drawer-head h3 { font-size: 15px; margin: 0; }
.drawer-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; background: none; border: none; cursor: pointer;
  color: var(--muted); border-radius: 6px; transition: background 0.12s ease, color 0.12s ease;
}
.drawer-close:hover { background: var(--surface-hover); color: var(--text); }
.drawer-body { flex: 1; overflow-y: auto; padding: 16px; }
.drawer-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 12px 16px; border-top: 1px solid var(--border);
}
.drawer-foot:empty { display: none; }
.drawer-group { margin: 0 0 18px; }
.drawer-group h4 {
  font-size: 12px; font-weight: 650; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.02em; margin: 0 0 8px;
}
.drawer-option {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 4px; border-radius: var(--r-ctrl); cursor: pointer;
  font-size: 13px; color: var(--text);
}
.drawer-option:hover { background: var(--surface-hover); }
.drawer-option input { accent-color: var(--accent); }
.drawer-option .count { margin-left: auto; color: var(--muted); font-size: 12px; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ---------------- Loading dots ----------------
   FIXED CONVENTION (10/10-2026): anything that takes time shows three
   pulsing dots while it works, in the element that reports the wait: the
   button that started it, the page's status line, a table row's badge.
   One building block (DOTS in common.js). Sized in em so the dots follow
   the text they sit in, drawn in currentColor so they inherit the button's
   or badge's own colour. No spinner anywhere else. */
.dots {
  display: inline-flex; align-items: center; gap: 0.28em;
  vertical-align: baseline; margin-left: 0.15em;
}
.dots i {
  width: 0.3em; height: 0.3em; border-radius: 50%;
  background: currentColor;
  animation: dot-pulse 1.1s infinite ease-in-out;
}
.dots i:nth-child(2) { animation-delay: 0.18s; }
.dots i:nth-child(3) { animation-delay: 0.36s; }
/* One definition for every dot in the app: these loading dots and the
   nav-dots beside the Agents menu item. The pulse deliberately IGNORES the
   OS's reduced-motion setting (brugerbeslutning 10/10-2026): Windows with
   animation effects off would freeze the dots into a dead "...", and the
   wait signal must look alive. Opacity-only on dots this small is not the
   spatial motion that setting exists to avoid. */
@keyframes dot-pulse { 0%, 70%, 100% { opacity: 0.25; } 35% { opacity: 1; } }

/* AUTO-SAVE (fast konvention 12/10-2026): the quiet confirmation for text
   fields that save themselves. One building block (autosave() in common.js);
   light grey "Auto-saved HH:MM" top right in the box being edited, red when
   the save was refused. The absolute variant pins it to the box's corner
   (the box gets position: relative from its own page). */
.autosave { color: var(--muted); font-size: 11px; white-space: nowrap; }
.autosave.bad { color: var(--crit-text); }
.autosave-abs { position: absolute; top: 8px; right: 10px; }

/* ---------------- Sign-in page ----------------
   Served without the menu: body carries class="auth". */
body.auth { margin-left: 0; display: grid; place-items: center; min-height: 100vh; padding: 24px; }
.login-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-card);
  padding: 32px; width: min(400px, 100%); text-align: center;
}
.login-card h1 { font-size: 18px; margin: 0 0 4px; }
.login-sub { color: var(--muted); font-size: 13px; margin: 0 0 22px; }
.login-btn { width: 100%; margin: 8px 0; height: 36px; }
.sso-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; background: #fff; border-radius: 5px; flex: none;
}
.login-error {
  background: var(--crit-bg); color: var(--crit-text);
  border-radius: var(--r-ctrl); padding: 10px 12px; font-size: 13px;
  margin-bottom: 16px; text-align: left;
}
.qr-tile { background: #fff; border-radius: var(--r-ctrl); padding: 12px; display: inline-block; margin: 6px 0 10px; }
.login-secret {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 12px; word-break: break-all; color: var(--muted); margin-bottom: 14px;
}
.tfa-hint { font-size: 13px; color: var(--muted); margin: 0 0 14px; }
#tfa-code {
  width: 100%; height: 40px; font-size: 17px; text-align: center; letter-spacing: 0.35em;
  margin-bottom: 12px;
}
.nowrap { white-space: nowrap; }
.mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; }

/* ---------------- Narrow screens ---------------- */
@media (max-width: 900px) {
  :root { --pad-x: 16px; }
}
@media (max-width: 720px) {
  :root { --sidebar-w: 60px; }
  .nav-text, .nav-chevron { opacity: 0; width: 0; overflow: hidden; }
  .nav-link { gap: 0; }
  .nav-link > .nav-dots { position: absolute; left: 9px; bottom: 1px; margin: 0; }
  .nav-link > :is(.nav-count, .nav-alert) { position: absolute; top: 0; right: 0; margin: 0; }
  .nav-subs, .nav-subs.collapsible.open { display: none; }
  .sidebar-toggle { display: none; }
  .brand-logo { flex: none; width: 20px; }
  .sidebar-username, .sidebar-logout { display: none; }
  .sidebar-user { justify-content: center; gap: 0; }
  .sidebar-profile { flex: none; margin: 0; padding: 2px; }
  .page-title { font-size: 17px; }
}

/* ---------------- Mobile bottom menu (portrait phones) ----------------
   Owner's decision 10/10-2026: on a phone held upright the sidebar takes too
   much width, so it is replaced by a sticky bar at the BOTTOM: all level-1
   icons in one horizontally scrollable row. A level-1 group opens its submenu
   fullscreen, centred both ways, with the bar still visible and the group's
   icon + name pinned at the top so the submenu's home is never in doubt.
   Landscape keeps the collapsed rail above; both elements are built by
   common.js on every screen and only shown here. */
.mobilebar, .mobile-menu { display: none; }

@media (max-width: 720px) and (orientation: portrait) {
  :root { --mobilebar-h: 60px; }
  .sidebar { display: none; }
  body {
    margin-left: 0;
    padding-bottom: calc(var(--mobilebar-h) + env(safe-area-inset-bottom, 0px));
  }
  body.mm-open { overflow: hidden; }   /* the fullscreen submenu owns the scroll */

  .mobilebar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    display: flex; align-items: stretch; gap: 2px;
    padding: 6px 8px calc(6px + env(safe-area-inset-bottom, 0px));
    background: var(--nav-bg); border-top: 1px solid var(--border);
    overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .mobilebar::-webkit-scrollbar { display: none; }
  .mb-item {
    flex: 0 0 auto; min-width: 62px;
    display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 3px;
    padding: 4px 10px; border-radius: var(--r-ctrl);
    background: none; border: none; cursor: pointer;
    font-family: inherit; color: var(--muted); text-decoration: none;
    transition: background 0.12s ease, color 0.12s ease;
  }
  .mb-item svg { width: 22px; height: 22px; flex-shrink: 0; }
  .mb-item { position: relative; }
  .mb-item > :is(.nav-count, .nav-alert) { position: absolute; top: 1px; left: calc(50% + 3px); }
  .mb-label { font-size: 10px; font-weight: 550; white-space: nowrap; }
  .mb-item.active, .mb-item.expanded { color: var(--text); background: var(--panel); }

  .mobile-menu.open {
    display: flex; flex-direction: column;
    position: fixed; left: 0; right: 0; top: 0;
    bottom: calc(var(--mobilebar-h) + env(safe-area-inset-bottom, 0px));
    z-index: 80; background: var(--bg);
  }
  .mm-head {
    flex-shrink: 0; display: flex; align-items: center; gap: 10px;
    padding: 14px var(--pad-x); border-bottom: 1px solid var(--border);
    font-size: 15px; font-weight: 650;
  }
  .mm-head svg { color: var(--muted); flex-shrink: 0; }
  .mm-close {
    margin-left: auto; flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--ctrl-h); height: var(--ctrl-h);
    background: none; border: none; border-radius: var(--r-ctrl);
    color: var(--muted); cursor: pointer;
  }
  .mm-close:hover { background: var(--surface-hover); color: var(--text); }
  /* Flex + margin:auto centres the list both ways, and degrades to a plain
     scroll when the list is taller than the screen (place-items would clip). */
  .mm-body { flex: 1; display: flex; overflow-y: auto; padding: 16px var(--pad-x); }
  .mm-list {
    margin: auto; width: min(340px, 100%);
    display: flex; flex-direction: column; gap: 4px; text-align: center;
  }
  .mm-link {
    display: block; padding: 11px 16px; border-radius: var(--r-ctrl);
    color: var(--text); text-decoration: none; font-size: 15px;
  }
  .mm-link:hover { background: var(--surface-hover); }
  .mm-link.active { background: var(--panel); font-weight: 650; }
  .mm-group { margin-top: 10px; }
  .mm-group:first-child { margin-top: 0; }
  .mm-group-label {
    font-size: 12px; font-weight: 550; color: var(--muted);
    margin-bottom: 2px; padding: 0 16px;
  }
}

/* ---------------- Agents page ----------------
   A switch per agent (active / paused) and a small tag for what kind of thing
   it is. Colours are tokens only; the switch is the accent when on. */
.switch { position: relative; display: inline-block; width: 34px; height: 20px; vertical-align: middle; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch span {
  position: absolute; inset: 0; border-radius: 10px; cursor: pointer;
  background: var(--border-input); transition: background 0.15s ease;
}
.switch span::before {
  content: ""; position: absolute; width: 16px; height: 16px; left: 2px; top: 2px;
  border-radius: 50%; background: var(--panel); transition: transform 0.15s ease;
}
/* FAST KONVENTION (10/10-2026): an ACTIVE toggle is GREEN, everywhere in
   the app: the same green that approves (--ok-fill), so on means on at a
   glance and the colour language matches the buttons. */
.switch input:checked + span { background: var(--ok-fill); }
.switch input:checked + span::before { transform: translateX(14px); }
.switch input:disabled + span { opacity: 0.45; cursor: not-allowed; }
.switch input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
.tag {
  display: inline-block; padding: 1px 7px; border-radius: 6px; font-size: 11px;
  font-weight: 650; letter-spacing: 0.02em; border: 1px solid var(--border-input);
  color: var(--muted); background: var(--surface-sub); white-space: nowrap;
}
.tag.llm { color: var(--info-text); background: var(--info-bg); border-color: transparent; }
.tag.det { color: var(--muted); }
/* Touch screens have no hover, so a tap shows the nearest title as a small
   bubble instead (drawn by common.js). Same surface rules as everything
   else: panel, hairline, 8px corners, no shadow. pre-line keeps the line
   breaks some titles carry (the potential reasons). */
.touch-tip {
  position: fixed; z-index: 2000; max-width: min(320px, calc(100vw - 16px));
  padding: 6px 10px; border-radius: 8px; border: 1px solid var(--border-input);
  background: var(--panel); color: var(--text); font-size: 12px;
  line-height: 1.45; white-space: pre-line; pointer-events: none;
}

/* ---------------- Tooltips ----------------
   FIXED CONVENTION (10/10-2026): the app's own tooltip (common.js), never the
   browser's. A dark bubble in BOTH themes (its own tokens; dark mode must
   never show a white bubble), no shadow. Amount lines sit right-aligned in
   tabular figures, accountant style; label-and-amount lines are two columns. */
.tooltip {
  position: fixed; z-index: 300; max-width: 340px;
  background: var(--tooltip-bg); color: var(--tooltip-text);
  border: 1px solid var(--tooltip-border);
  border-radius: var(--r-ctrl); padding: 6px 10px;
  font-size: 12px; line-height: 1.5; pointer-events: none;
  animation: fade-in 0.12s ease;
}
.tooltip .tt-row { display: flex; gap: 16px; justify-content: space-between; }
.tooltip .tt-num { font-variant-numeric: tabular-nums; text-align: right; }

/* The "i" that carries the one-line description in the app tooltip. */
.tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%; margin-left: 6px;
  border: 1px solid var(--border-input); color: var(--muted);
  font-size: 10px; font-weight: 700; cursor: help; vertical-align: middle;
}
.agent-name { font-weight: 550; white-space: nowrap; }
.agent-area td { background: var(--surface-sub); color: var(--muted); font-size: 12px; font-weight: 650; }
tr.agent-dim td { color: var(--disabled); }

/* ---------------- Mail editor (docs/20) ----------------
   The mail detail page: the block editor on the left, the live preview on
   the right (stacked on narrow screens). The editor is drag and drop
   (17/10-2026): a palette of block tiles above the mail column, dragged in
   or clicked; each block is a small card with the app's drag grip, kind,
   rule select, tools and switch, and its fields (auto-saved). The brand
   header and footer stand as quiet fixed strips around the column. The
   preview is the rendered mail in an iframe on the page background, no
   shadow, hairline and 12px corners like a card; it stays in view while
   the column scrolls. Tone only, never shadows (the design rules). */
.mail-editor { display: grid; grid-template-columns: minmax(320px, 5fr) minmax(300px, 4fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .mail-editor { grid-template-columns: 1fr; } }
.mail-palette-wrap { margin: 0 0 12px; }
.mail-palette-wrap .sub-h { margin: 0 0 6px; }
.mail-palette { display: flex; flex-wrap: wrap; gap: 6px; }
.mail-tile {
  display: inline-flex; align-items: center; gap: 6px; height: var(--ctrl-h);
  padding: 0 12px; border: 1px solid var(--border-input); border-radius: var(--r-ctrl);
  background: var(--panel); color: var(--text); font: inherit; cursor: grab;
  touch-action: none; transition: background 0.12s ease;
}
.mail-tile:hover { background: var(--surface-hover); }
.mail-tile svg { color: var(--muted); }
.mail-ghost {
  position: fixed; z-index: 1000; pointer-events: none;
  background: var(--surface-active); border-color: var(--text);
}
.mail-drop {
  border: 1px dashed var(--muted); border-radius: var(--r-ctrl);
  background: var(--surface-active); color: var(--muted);
  font-size: 12px; text-align: center; padding: 10px; margin: 0 0 10px;
}
.mail-canvas {
  background: var(--surface-sub); border: 1px solid var(--border);
  border-radius: var(--r-card); padding: 10px;
}
.mail-fixed {
  font-size: 12px; color: var(--muted); text-align: center;
  padding: 8px; margin: 0 0 10px; border: 1px dashed var(--border);
  border-radius: var(--r-ctrl);
}
.mail-fixed:last-child { margin: 0; }
.mail-block {
  position: relative; border: 1px solid var(--border); border-radius: var(--r-ctrl);
  padding: 8px 12px 10px; margin: 0 0 10px; background: var(--panel);
}
.mail-block { cursor: grab; }   /* the whole card is a handle (sortableRows whole) */
.mail-block :is(input, textarea) { cursor: text; }
.mail-block.off { background: var(--surface-sub); }
.mail-block.off :is(textarea, input, .mb-kind) { color: var(--disabled); }
.mail-block.dragging { background: var(--surface-active); }
.mail-block.dragging .drag-handle { color: var(--text); }
.mail-block-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.mail-block-head .drag-handle { margin-left: -6px; }
.mail-block-head .mb-kind {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; font-weight: 650; color: var(--muted);
}
.mail-block-head select { height: 26px; font-size: 12px; width: auto; }
.mail-block-head .mb-tools { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; }
.mail-block textarea { width: 100%; font-size: 13px; min-height: 34px; }
.mail-block > input[type="text"] { width: 100%; font-weight: 650; }
.mail-block .autosave { position: absolute; top: -16px; right: 2px; }
.mb-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; flex: 1; min-width: 0; }
.mb-fields label { display: grid; gap: 4px; font-size: 12px; color: var(--muted); min-width: 0; }
.mb-fields input, .mb-fields select { width: 100%; }
.mb-image { display: flex; gap: 12px; align-items: flex-start; }
.mb-thumb {
  width: 88px; height: 88px; flex-shrink: 0; display: flex; align-items: center;
  justify-content: center; border: 1px solid var(--border); border-radius: var(--r-ctrl);
  background: var(--surface-sub); color: var(--muted); overflow: hidden;
}
.mb-thumb img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 560px) {
  .mb-fields { grid-template-columns: 1fr; }
  .mb-image { flex-direction: column; }
}
.mb-divider { border-top: 1px solid var(--border); margin: 6px 0 2px; }
.mb-spacer { height: 28px; }
/* The mail editor's text field with simple formatting (17/10-2026): a
   framed editable area like a textarea, with a small B / I / U / Link bar
   above it. A button lights up (active surface) while the cursor stands
   in that formatting. The link row opens under the bar. */
.rte { display: grid; gap: 6px; }
.rte-bar { display: inline-flex; gap: 2px; }
.rte-bar button {
  width: 28px; height: 26px; padding: 0; display: inline-flex;
  align-items: center; justify-content: center; font: inherit; font-size: 13px;
  border: 1px solid transparent; border-radius: 6px; background: none;
  color: var(--muted); cursor: pointer;
}
.rte-bar button:hover { background: var(--surface-hover); color: var(--text); }
.rte-bar button.on { background: var(--surface-active); color: var(--text); }
.rte-link { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.rte-link input { flex: 1 1 220px; min-width: 0; }
.rte-area {
  min-height: 34px; padding: 8px 10px; line-height: 1.5; font-size: 13px;
  background: var(--panel); color: var(--text); cursor: text;
  border: 1px solid var(--border-input); border-radius: var(--r-ctrl);
  overflow-wrap: anywhere;
}
.rte-area:hover { border-color: var(--muted); }
.rte-area a { color: var(--text); text-decoration: underline; }
.mail-block.off .rte-area { color: var(--disabled); }

/* "Send test" (the mail editor): one address, above the preview. */
.mm-test {
  border: 1px solid var(--border); border-radius: var(--r-ctrl);
  padding: 10px 12px; margin: 0 0 10px; background: var(--surface-sub);
}
.mm-test label { display: block; font-size: 12px; color: var(--muted); margin: 0 0 6px; }
.mm-test-row { display: flex; gap: 6px; flex-wrap: wrap; }
.mm-test-row input { flex: 1 1 220px; min-width: 0; }
.mm-test .sub-h { margin: 8px 0 0; }
.mm-test-note { color: var(--text); }
.mm-test-note.bad { color: var(--crit-text); }
/* A flow's series (Flowmails > <flow>): one row per mail; the row whose
   template is open below is marked with the active surface. */
.mm-series tbody tr[data-step] { cursor: pointer; }
.mm-series tbody tr.selected { background: var(--surface-active); }
.mm-day { display: inline-flex; align-items: center; gap: 6px; }
.mm-day input { width: 70px; }
.mm-day .autosave { position: static; margin-left: 4px; }
.mail-preview-col { position: sticky; top: calc(var(--header-h, 56px) + 8px); }
@media (max-width: 900px) { .mail-preview-col { position: static; } }
.mail-preview-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin: 0 0 8px; }
.mail-preview-head .sub-h { margin: 0; flex: 1 1 220px; min-width: 0; }
.mail-preview-stage.mobile .mail-preview { width: 390px; max-width: 100%; display: block; margin: 0 auto; }
.mail-preview {
  width: 100%; border: 1px solid var(--border); border-radius: var(--r-card);
  background: #F2F2F0; height: 720px;
}
.mail-subjects { display: grid; gap: 8px; margin: 0 0 14px; }
.mail-subjects label { display: grid; gap: 4px; font-size: 12px; color: var(--muted); }
.mail-subjects input { width: 100%; }
