/* ratiotec license portal — design system
   Self-hosted, no CDNs. Tokens on top, components below.
   Colors follow the ratiotec Mini Brand Guide (CONNECT scheme):
   dark blue #1e2936 for all text, turquoise #1ab1a0 as accent. */

/* Brand font: Be Vietnam Pro (Bold = headlines, Semibold = sublines,
   Regular = body). Self-hosted woff2, latin + latin-ext subsets. */
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-400-latin-79141d22ee0742b4b1159753bc763adc.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-400-latin-ext-a46257d03d747f28e3e0e24c22105ab9.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-600-latin-a4759a77d292a59286ed9a400bfa4aaf.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-600-latin-ext-0ba9b517e5dff80140bd1b698efbd58a.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-700-latin-85718a3b256976f0a87b1ea74037922d.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/be-vietnam-pro-700-latin-ext-e227fa0acdf67f83356a224f374a038a.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg: #f4f6f8;
  --surface: #ffffff;
  --border: #e3e7ec;
  --text: #1e2936;          /* ratiotec dark blue — all text */
  --text-dim: #5c6b7c;
  --text-faint: #8b98a6;
  --primary: #1e2936;       /* dark blue fills: primary buttons (white text ≥ 14:1) */
  --primary-hover: #2e4156;
  --accent: #1ab1a0;        /* CONNECT turquoise — decorative accents, never text on white */
  --accent-ink: #0e7f72;    /* text-safe turquoise (≈ 4.9:1 on white) */
  --accent-hover: #12958a;  /* focus borders, hovered turquoise (≥ 3:1 on white) */
  --accent-soft: #e2f2f6;   /* very light blue (secondary) */
  --steel: #3e5675;         /* steel blue (secondary) */
  --focus-ring: 0 0 0 3px rgba(26, 177, 161, .22);
  --sidebar-bg: #1e2936;
  --sidebar-text: #9fadbc;
  --sidebar-active: #ffffff;
  --green-bg: #dcfce7;  --green-text: #15803d;
  --yellow-bg: #fef3c7; --yellow-text: #b45309;
  --red-bg: #fee2e2;    --red-text: #b91c1c;
  --neutral-bg: #f1f3f5; --neutral-text: #5c6b7c;
  --orange-bg: #ffedd5; --orange-text: #c2410c;
  /* Informational blue (device/trial tags) aliases the secondary brand pair */
  --blue-bg: var(--accent-soft); --blue-text: var(--steel);
  /* Suspended: frozen grey, a step darker than the "not activated" neutral */
  --slate-bg: #e2e8f0; --slate-text: #475569;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(30, 41, 54, .05), 0 1px 3px rgba(30, 41, 54, .06);
  --font: "Be Vietnam Pro", "Segoe UI Variable Text", "Segoe UI", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "Cascadia Code", Consolas, "SF Mono", monospace;
}

* { box-sizing: border-box; }

/* The hidden attribute has to win over any class that sets display. A class
   selector outranks the UA's [hidden] rule, so without this a hidden chip or
   button stays on screen — the kind of bug that only shows up in the browser. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

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

/* ---------- App frame: sidebar + content ---------- */

.app {
  display: grid;
  grid-template-columns: 232px 1fr;
  min-height: 100vh;
}

/* Phone chrome (compact top bar + drawer overlay): desktop hides both, so
   the .app grid still sees exactly sidebar + content */
.mobile-bar,
.drawer-overlay { display: none; }

.sidebar {
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  padding: 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: sticky;
  top: 0;
  height: 100vh;
}

/* Company wordmark (static/img, white variant on the dark sidebar) */
.brand { padding: 6px 10px 22px; }

/* Sidebar variant: centered, links to the dashboard, not draggable */
.sidebar .brand {
  display: flex;
  justify-content: center;
}

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

.brand-logo {
  display: block;
  width: 132px;
  height: auto;
  -webkit-user-drag: none;
  user-select: none;
}

.nav-title {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .09em;
  padding: 12px 10px 6px;
  color: #8ea0b2;
}

.nav-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--sidebar-text);
  font-weight: 500;
  transition: background .12s, color .12s;
}

.nav-link:hover { background: rgba(255, 255, 255, .06); color: #dbe3ea; text-decoration: none; }

.nav-link.active { background: rgba(26, 177, 161, .16); color: var(--sidebar-active); }

/* Open-requests count on the Requests nav item */
.nav-badge {
  margin-left: auto;
  min-width: 20px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--sidebar-bg);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
}

.nav-link.active svg { color: var(--accent); }

.nav-link svg { width: 17px; height: 17px; flex-shrink: 0; }

.sidebar-bottom { margin-top: auto; display: grid; gap: 10px; }

.sidebar-user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .07);
}

.sidebar-user .user-info { min-width: 0; flex: 1; }

.sidebar-user .name {
  color: #e9edf2;
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar-user .role { font-size: 11px; color: var(--sidebar-text); }

.logout-button {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--sidebar-text);
  cursor: pointer;
  transition: background .12s, color .12s;
}

.logout-button:hover { background: rgba(255, 255, 255, .1); color: #fff; }

.logout-button svg { width: 16px; height: 16px; }

.sidebar-footer {
  padding: 0 10px 2px;
  font-size: 11.5px;
  color: var(--sidebar-text);
  /* Centered like the wordmark above */
  text-align: center;
}

.sidebar-legal { margin-top: 2px; }

.sidebar-legal a {
  color: var(--sidebar-text);
  text-decoration: none;
  margin: 0 5px;
}

.sidebar-legal a:hover { color: #a9b7c4; text-decoration: underline; }

/* Legal links under the login card */
.legal-links {
  margin-top: 14px;
  text-align: center;
  font-size: 12px;
}

.legal-links a {
  color: var(--text-dim);
  text-decoration: none;
  margin: 0 7px;
}

.legal-links a:hover { text-decoration: underline; }

/* Public legal pages (Impressum, Datenschutz) */
.legal-page {
  min-height: 100vh;
  background: var(--bg);
  padding: 40px 16px;
}

.legal-card {
  max-width: 720px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 36px 42px;
}

.legal-card h1 { font-size: 22px; margin: 0 0 18px; color: var(--primary); }
.legal-card h2 { font-size: 14.5px; margin: 22px 0 6px; color: var(--primary); }
.legal-card p, .legal-card li { font-size: 13.5px; line-height: 1.6; color: var(--text); }
.legal-card ul { padding-left: 20px; }
.legal-card a { color: var(--accent-ink); }

.legal-back { margin-top: 28px; }

.legal-card a.legal-back-top {
  margin-bottom: 18px;
  color: var(--text);
  text-decoration: none;
}
.legal-back-top svg { width: 15px; height: 15px; }

/* ---------- Language picker (globe + native-name dropdown) ---------- */

.lang-picker { position: relative; }

.lang-picker-globe,
.lang-picker-chevron {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  color: var(--sidebar-text);
  pointer-events: none;
  /* Above the dd trigger button (opaque on the light login card), but
     below an open dd-panel (z-index 70) */
  z-index: 1;
}

.lang-picker-globe { left: 10px; }
.lang-picker-chevron { right: 9px; width: 12px; height: 12px; }

.lang-select {
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  font-size: 12px;
  padding: 7px 26px 7px 32px;
  border-radius: 8px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .07);
  color: #dbe0ea;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}

.lang-select:hover { background: rgba(255, 255, 255, .09); }

.lang-select:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}

/* The native dropdown list keeps UA styling; force readable option colors
   in browsers that inherit the dark select colors (Firefox) */
.lang-select option { color: var(--text); background: var(--surface); }

/* Variant on the light login/register card */
.lang-picker-light { margin-top: 18px; }

.lang-picker-light .lang-picker-globe,
.lang-picker-light .lang-picker-chevron { color: var(--text-dim); }

.lang-picker-light .lang-select {
  font-size: 12.5px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
}

.lang-picker-light .lang-select:hover { background: #fafbfc; }

/* ---------- Main area ---------- */

.content { padding: 0 36px 48px; min-width: 0; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 22px 0 26px;
}

.topbar h1 { font-size: 20px; font-weight: 700; margin: 0; letter-spacing: -.01em; }

.topbar .subtitle { color: var(--text-dim); font-size: 13px; margin-top: 3px; }

/* ---------- Notification bell (top bar) ---------- */

/* What happened in this user's scope while they were elsewhere. The panel is
   anchored to the bell, so the wrapper carries the positioning context. */
.notifications { position: relative; flex-shrink: 0; }

.notifications-trigger { position: relative; color: var(--text-dim); }

/* Fills more of the button than the icons in the dense table rows do: the
   bell stands alone in the top bar, with no label beside it to carry it.
   The compound selector beats .icon-button svg, which is equally specific
   and comes later in this file. */
.notifications-trigger.icon-button svg { width: 20px; height: 20px; }

/* Unread count, same accent-on-dark-blue pair as the sidebar requests badge
   so a waiting number always reads the same way. */
.notifications-badge {
  position: absolute;
  top: -1px;
  right: -1px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--sidebar-bg);
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.notifications-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  width: 360px;
  /* Never wider than the viewport on a phone, where the bell sits close to
     the right edge */
  max-width: calc(100vw - 32px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 10px 28px rgba(30, 41, 54, .14);
  overflow: hidden;
}

.notifications-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
}

.notifications-head h2 { font-size: 13px; font-weight: 700; margin: 0; }

.notifications-read {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--accent-ink);
  cursor: pointer;
}

.notifications-read:hover { text-decoration: underline; }

/* Nothing left to read: the action stays in place instead of disappearing
   and shifting the header. */
.notifications-read:disabled {
  color: var(--text-faint);
  cursor: default;
  text-decoration: none;
}

.notifications-list {
  max-height: 380px;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

.notifications-list li + li { border-top: 1px solid var(--border); }

.notifications-empty {
  padding: 26px 14px;
  color: var(--text-dim);
  font-size: 13px;
  text-align: center;
}

/* The row anchors the mark-as-read button; the link spans the full width
   underneath it, so hovering highlights the whole row. */
.notification-row { position: relative; }

.notification {
  display: flex;
  gap: 9px;
  /* The right padding reserves the button's gutter on every row, read or
     not, so the timestamps line up down the whole panel. */
  padding: 11px 44px 11px 14px;
  color: var(--text);
}

/* Reading one ahead of the others: in the reserved gutter, lined up with the
   event badge on the row's first line. */
.notification-read-one { position: absolute; top: 8px; right: 8px; }

.notification:hover { background: var(--bg); text-decoration: none; }

/* The unread dot sits in a gutter that is always there, so read and unread
   rows keep the same text alignment. */
.notification-mark {
  width: 6px;
  height: 6px;
  margin-top: 6px;
  border-radius: 50%;
  background: transparent;
  flex-shrink: 0;
}

.notification-new .notification-mark { background: var(--accent); }

.notification-new .notification-text { font-weight: 600; }

.notification-body { display: flex; flex-direction: column; flex: 1; gap: 3px; min-width: 0; }

.notification-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

.notification-when { color: var(--text-faint); font-size: 11px; white-space: nowrap; }

.notification-text { font-size: 13px; line-height: 1.35; }

.notification-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  color: var(--text-faint);
  font-size: 11px;
}

.notification-meta .code { font-size: 11px; }

.notifications-foot {
  display: block;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  text-align: center;
}

.avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: linear-gradient(135deg, #3e5675, #1ab1a0);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
  text-transform: uppercase;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: background .12s, border-color .12s;
}

.btn:hover { background: #fafbfc; border-color: #ccd5dc; }

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

.btn:focus-visible { outline: none; border-color: var(--accent-hover); box-shadow: var(--focus-ring); }

/* Primary actions use the dark blue: white on turquoise would fail AA */
.btn-primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  width: 100%;
  justify-content: center;
  padding: 10px;
  font-size: 14px;
}

.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }

/* ---------- Cards & tiles ---------- */

.tile-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* Stacked cards on a page keep a gap (tiles inside .tile-row are excluded) */
.content > .card { margin-bottom: 24px; }

.tile { padding: 18px 20px; }

.tile .label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.tile .value { font-size: 28px; font-weight: 700; letter-spacing: -.02em; margin-top: 6px; }

.tile .value.accent { color: var(--accent-ink); }

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.card-header h2 { font-size: 15px; font-weight: 600; margin: 0; }

/* "Show more" under a card's table (dashboard pending-orders card) */
.card-footer {
  display: flex;
  justify-content: center;
  padding: 12px 20px;
  border-top: 1px solid var(--border);
}

/* Rows beyond the first page, revealed by the .card-footer toggle above */
.orders-extra { display: none; }

#pending-orders-rows[data-open] .orders-extra { display: table-row-group; }

.card-body { padding: 20px; }

/* ---------- Tables ---------- */

/* Every table sits in a scroll container: on phones the table keeps its
   shape and scrolls sideways inside the card instead of squeezing */
.table-scroll { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; }

.table th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-dim);
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.table td {
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background .1s; }
.table tbody tr:hover { background: #f6f9fa; }
/* The whole row opens the detail drawer (portal.js), on every license table */
.table tbody tr.license-row { cursor: pointer; }

/* Sortable column header (e.g. partner column in the admin license list) */
.table th.sortable { cursor: pointer; user-select: none; transition: color .12s; }

.table th.sortable:hover { color: var(--text); }

.table th.sortable::after { content: "↕"; margin-left: 5px; font-size: 10px; opacity: .45; }

.table th.sortable[aria-sort="ascending"]::after { content: "↑"; opacity: 1; }

.table th.sortable[aria-sort="descending"]::after { content: "↓"; opacity: 1; }

.code { font-family: var(--mono); font-size: 12.5px; letter-spacing: .02em; }

.dim { color: var(--text-dim); }

.empty-hint { padding: 40px 20px; text-align: center; color: var(--text-dim); }

/* Small info icon in a table header (e.g. inclusive-date hint on the expiry column) */
.th-hint { width: 13px; height: 13px; vertical-align: -2px; margin-left: 2px; color: var(--text-faint); cursor: help; }

/* ---------- Device chips ---------- */

.device-cell { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* Running license with a free seat: paid runtime is burning unused */
.device-warning {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--orange-text);
  cursor: help;
}

.device-warning svg { width: 17px; height: 17px; flex-shrink: 0; }

/* Inside the status stack the warning is one signal among several, so it
   drops to the size of the chips it sits under */
.status-stack .device-warning { font-size: 11px; gap: 4px; }
.status-stack .device-warning svg { width: 13px; height: 13px; }

.device-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 400;
  background: var(--accent-soft);
  color: var(--steel);
  border: 1px solid #c6e2ec;
  border-radius: 999px;
  padding: 3px 5px 3px 10px;
  white-space: nowrap;
}

.device-chip form { display: inline-flex; }

.chip-remove {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--steel);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: background .12s, color .12s;
}

.chip-remove:hover { background: var(--red-bg); color: var(--red-text); }

/* ---------- Badges ---------- */

.badge {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

/* Author display beats [hidden]: the trial chip is toggled from the drawer */
.badge[hidden] { display: none; }

.badge-green { background: var(--green-bg); color: var(--green-text); }
.badge-yellow { background: var(--yellow-bg); color: var(--yellow-text); }
.badge-red { background: var(--red-bg); color: var(--red-text); }
.badge-neutral { background: var(--neutral-bg); color: var(--neutral-text); }
.badge-blue { background: var(--blue-bg); color: var(--blue-text); }
.badge-slate { background: var(--slate-bg); color: var(--slate-text); }
.badge-orange { background: var(--orange-bg); color: var(--orange-text); }

/* Category palette: slugs are persisted, soft background + dark text like
   the status badges. Also used for the color picker dots (currentColor).
   teal is nudged toward cyan so it stays distinguishable from the
   turquoise brand accent. */
.cat-indigo { background: #e0e7ff; color: #4338ca; }
.cat-blue   { background: #dbeafe; color: #1d4ed8; }
.cat-teal   { background: #cdf0f8; color: #0c7490; }
.cat-green  { background: #dcfce7; color: #15803d; }
.cat-amber  { background: #fef3c7; color: #b45309; }
.cat-orange { background: var(--orange-bg); color: var(--orange-text); }
.cat-red    { background: #fee2e2; color: #b91c1c; }
.cat-pink   { background: #fce7f3; color: #be185d; }
.cat-purple { background: #f3e8ff; color: #7e22ce; }
.cat-gray   { background: #f1f3f5; color: #5c6b7c; }

/* Status cell: the lifecycle badge, plus optional secondary chips stacked
   below it (e.g. trial). */
.status-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

/* Overlay chips under the status badge (e.g. trial) stay visually
   subordinate to the actual license status. */
/* Secondary chips stay subordinate through size and colour, not weight:
   Be Vietnam Pro ships 400/600/700, so a 500 here resolved to the 400 face
   and read as a different typeface next to the status badge's 600. */
.status-stack .badge-sub {
  font-size: 10.5px;
  padding: 2px 8px;
}

/* "+ Kategorie" placeholder chip on rows without a category */
.badge-add {
  background: transparent;
  color: var(--text-faint);
  border: 1px dashed #ccd5dc;
  font-weight: 400;
}

/* The category cell is a button that opens the assignment dialog */
.category-assign {
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  font: inherit;
}

.category-assign:hover .badge { box-shadow: 0 0 0 2px rgba(26, 177, 161, .3); }
.category-assign:hover .badge-add { color: var(--accent-ink); border-color: var(--accent-hover); box-shadow: none; }

/* ---------- Partner overview & filter ---------- */

.row-link { display: grid; gap: 2px; color: inherit; }
.row-link:hover { text-decoration: none; }
.row-link:hover .partner-name { color: var(--accent-ink); }
.partner-name { font-weight: 600; transition: color .12s; }
.row-link .dim { font-size: 12.5px; }

/* Invite link card (admin, partner page) */
.invite-link-card { padding: 20px; }
.invite-link-card h2 { font-size: 15px; margin: 0 0 6px; }
.invite-link-card p { margin: 0 0 12px; font-size: 13px; }

.link-row { display: flex; gap: 10px; }

.link-row input {
  flex: 1;
  font: inherit;
  font-size: 13px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--neutral-bg);
  color: var(--text-dim);
}

.invite-link-cell .code {
  display: inline-block;
  max-width: 340px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* Description in the table: truncated to one line, a click expands it inside
   the cell. The fixed max-width keeps the column width in both states. */
.description-cell { max-width: 240px; }

.description-text {
  display: block;
  max-width: 240px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.description-text.truncatable { cursor: pointer; }

.description-text.truncatable:hover { color: var(--accent-ink); }

.description-text.expanded {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  text-overflow: clip;
}

/* The license table carries ten columns (eleven for admins) and is the widest
   in the portal. Tighter gutters and a cap on the two free-text columns keep
   it inside the card instead of scrolling sideways. */
.licenses-table th,
.licenses-table td { padding-left: 12px; padding-right: 12px; }

/* Seven columns leave slack on a wide screen. Without a cap the action
   column takes all of it and opens a gap before its icons, so pin it to its
   content and let the data columns share what is left. */
.licenses-table th:last-child,
.licenses-table .table-actions { width: 1%; }

/* A cap, not a width: giving this column width:100% made it swallow all the
   slack and pushed the expiry date to the far edge. Without one, the browser
   spreads the slack across the data columns instead of pooling it anywhere. */
.customer-cell { max-width: 260px; }

.customer-cell span,
.customer-cell div {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Chips stay on one line, so a long device name would set the column width.
   Tables only: the details drawer shows the full name. */
.table .device-chip > span:first-child {
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Dialog ---------- */

.dialog {
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px;
  max-width: min(400px, calc(100vw - 32px));
  box-shadow: 0 20px 60px rgba(30, 41, 54, .18);
  text-align: center;
  /* Dropdown panels inside a dialog must overlay past its bounds instead
     of being clipped by the UA default (overflow: auto) */
  overflow: visible;
}

.dialog::backdrop {
  background: rgba(30, 41, 54, .45);
  backdrop-filter: blur(2px);
}

.dialog[open] { animation: dialog-open .16s ease-out; }

@keyframes dialog-open {
  from { opacity: 0; transform: translateY(8px) scale(.97); }
  to { opacity: 1; transform: none; }
}

.dialog-icon {
  width: 44px;
  height: 44px;
  margin: 0 auto 14px;
  border-radius: 12px;
  background: var(--red-bg);
  color: var(--red-text);
  display: grid;
  place-items: center;
}

.dialog-icon svg { width: 22px; height: 22px; }

/* Non-destructive confirmations (suspend): accent instead of alarm red */
.dialog-icon-accent { background: var(--accent-soft); color: var(--steel); }

/* Search-match highlight (audit "By" column): light blue from the brand
   guide's secondary palette ("Farbakzente"); dark text stays readable */
mark.search-mark {
  background: #a8dae5;
  color: inherit;
  border-radius: 3px;
  padding: 0 1px;
}

/* Freshness banner between toolbar and table (licenses page) */
.stale-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 20px;
  font-size: 13px;
  background: var(--accent-soft);
  color: var(--steel);
  border-bottom: 1px solid var(--border);
}

/* display: flex would override the hidden attribute */
.stale-banner[hidden] { display: none; }

.stale-banner svg { width: 15px; height: 15px; flex-shrink: 0; }

.stale-banner .btn { margin-left: auto; padding: 5px 12px; }

/* Page-level variant: sits above the cards instead of inside one */
.stale-banner-standalone {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 18px;
}

/* Internal (demo) licenses: the terms these codes come with. Amber like
   .notice-blocking — it states an obligation, not news — but a block with
   real paragraphs rather than the one-line banner. */
.demo-terms {
  display: flex;
  gap: 12px;
  padding: 16px 20px;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--yellow-bg);
  color: var(--yellow-text);
}

.demo-terms > svg { width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; }

.demo-terms h2 {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
  color: inherit;
}

.demo-terms p {
  margin: 0 0 6px;
  max-width: 68ch;
  font-size: 13px;
  line-height: 1.5;
}

.demo-terms p:last-child { margin-bottom: 0; }

.order-codes {
  list-style: none;
  margin: 0;
  padding: 2px 20px 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 22px;
}

/* Orders table: each order owns two rows — the data row and a collapsible
   codes row right below it. The row separator lives on the codes row, so
   collapsed it draws where the data row's border would be, and expanded it
   moves below the revealed codes. */
.orders-table tbody td { border-bottom: 0; }

.orders-table .order-codes-cell { padding: 0; border-bottom: 1px solid var(--border); }

.orders-table .order-codes-row:hover { background: transparent; }

/* Text toggle and cancel button need more air than icon-button clusters */
.orders-table .row-actions { gap: 12px; }

/* Create dialog: explicit acknowledgment that ordering costs money.
   A divider separates the order zone (acknowledgment + actions) from the
   form fields above. */
.cost-ack {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 20px 0 14px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  cursor: pointer;
}

/* Two short fields side by side (quantity + term in the create dialog) */
.field-row { display: flex; gap: 12px; }

.field-row .field { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Grows to absorb a label that wraps to two lines, so inputs across
   the row stay aligned regardless of how many lines each label takes. */
.field-row .field label { flex: 1; }

/* Checkbox row inside a dialog form, without the order-zone divider */
.dialog-option {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 2px 0 16px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  cursor: pointer;
}

.dialog-option input {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 1px;
  accent-color: var(--primary);
  cursor: pointer;
}

/* The billed zone of the create dialog: one divider above quote + consent */
.order-zone {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.order-zone .extend-quote { margin-bottom: 10px; }

.order-zone .cost-ack { margin: 0 0 14px; padding-top: 0; border-top: 0; }

.cost-ack input {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 1px;
  accent-color: var(--primary);
  cursor: pointer;
}

/* License details dialog: label/value pairs as a striped table */
.details-list {
  margin: 0 0 18px;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.details-list > div { display: flex; gap: 12px; padding: 8px 12px; font-size: 13px; }

/* display: flex would override the hidden attribute (optional rows) */
.details-list > div[hidden] { display: none; }

/* "of" selector so hidden optional rows do not break the striping */
.details-list > div:nth-child(even of :not([hidden])) { background: #f6f8fa; }

.details-list dt { width: 130px; flex-shrink: 0; color: var(--text-dim); }

.details-list dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.dialog h2 { font-size: 17px; font-weight: 600; margin: 0 0 8px; letter-spacing: -.01em; }

.dialog p { color: var(--text-dim); font-size: 13.5px; line-height: 1.55; margin: 0 0 22px; }

.dialog p strong { color: var(--text); }

.dialog-actions { display: flex; gap: 10px; justify-content: center; }

.dialog-actions .btn { min-width: 110px; justify-content: center; }

.btn-danger {
  background: #dc2626;
  border-color: #dc2626;
  color: #fff;
}

.btn-danger:hover { background: #b91c1c; border-color: #b91c1c; }

.btn-accent {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.btn-accent:hover { background: var(--primary-hover); border-color: var(--primary-hover); }

/* Form dialog: left-aligned, with input fields */
.dialog-form { text-align: left; max-width: min(420px, calc(100vw - 32px)); }
.dialog-form h2 { margin-bottom: 4px; }
.dialog-form > p { margin-bottom: 18px; }
.dialog-form .dialog-actions { justify-content: flex-end; margin-top: 4px; }

/* ---------- License detail drawer ----------
   Still a <dialog> (so Esc, the backdrop and the focus trap come for free),
   parked against the right edge at full height instead of centred, so the
   list stays readable behind it. */
.dialog-drawer {
  max-width: min(460px, 100vw);
  width: min(460px, 100vw);
  max-height: 100vh;
  height: 100vh;
  margin: 0 0 0 auto;
  border-radius: 0;
  border-width: 0 0 0 1px;
  padding: 22px 24px 24px;
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: -10px 0 30px rgba(30, 41, 54, .18);
}

/* Only while open: the UA hides a closed dialog with
   dialog:not([open]){display:none}, and any author display beats that, which
   left the whole drawer sitting in the page flow. The column is what lets the
   footer take margin-top:auto. */
.dialog-drawer[open] {
  display: flex;
  flex-direction: column;
}

/* The centred dialog pop reads wrong on a panel pinned to an edge, so the
   drawer slides in and out of the edge it sits on. A transition rather than
   keyframes: display and overlay ride along as discrete steps, which keeps the
   dialog in the top layer until the slide-out ends, so every close path (Esc,
   the backdrop, the footer button) animates without JS. */
.dialog-drawer {
  display: none;
  transform: translateX(100%);
  transition: transform .2s ease, display .2s allow-discrete, overlay .2s allow-discrete;
}

.dialog-drawer[open] { transform: none; animation: none; }

@starting-style {
  .dialog-drawer[open] { transform: translateX(100%); }
}

.dialog-drawer::backdrop {
  opacity: 0;
  transition: opacity .2s ease, display .2s allow-discrete, overlay .2s allow-discrete;
}

.dialog-drawer[open]::backdrop { opacity: 1; }

@starting-style {
  .dialog-drawer[open]::backdrop { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .dialog-drawer,
  .dialog-drawer::backdrop { transition: none; }
}

.drawer-head {
  display: grid;
  gap: 10px;
  padding-bottom: 15px;
  border-bottom: 1px solid var(--border);
}

.drawer-head h2 { margin: 0; }

.drawer-code {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
}

.drawer-code .code { font-size: 13.5px; font-weight: 600; margin-right: 4px; }

/* Copy sits beside .icon-button affordances throughout the drawer, so it takes
   their box instead of the smaller one it wears inside a table cell. */
.dialog-drawer .copy-btn {
  width: 30px;
  height: 30px;
  margin-left: 0;
  border-radius: 8px;
}

.dialog-drawer .copy-btn svg { width: 16px; height: 16px; }

.drawer-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.drawer-badges .badge[hidden] { display: none; }

/* One group per question the reader might arrive with */
.drawer-group { padding: 16px 0 2px; }

.drawer-group h3 {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-faint);
}

/* One label/value grammar for every row in the drawer, hairlines instead of
   zebra stripes so the groups above stay the louder division */
.drawer-rows { margin: 0; display: grid; }

.drawer-rows > div {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  padding: 7px 0;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.drawer-rows > div:first-child { border-top: 0; }
.drawer-rows > div[hidden] { display: none; }

.drawer-rows dt { color: var(--text-dim); }
.drawer-rows dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

/* No row to hover in here, so the edit and copy affordances stay visible */
.drawer-inline { display: flex; align-items: center; gap: 6px; }
.drawer-inline .icon-button-edit,
.drawer-inline .copy-btn { opacity: 1; }

.drawer-stack { display: grid; gap: 6px; justify-items: start; }
.drawer-stack .field-hint { margin: 0; }
.drawer-stack .field-hint[hidden] { display: none; }

/* Actions sit at the bottom, Close last and always on the right */
.drawer-footer {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.drawer-footer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  flex: 1;
}

.drawer-footer-actions[hidden] { display: none; }
.drawer-footer-actions [hidden] { display: none; }
.drawer-footer .dialog-cancel { margin-left: auto; }

/* Collapsible section (inline category creation in the create dialog):
   disclosure button with rotating chevron, height animated via the
   grid-template-rows 0fr -> 1fr technique. */
.collapse-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer;
}

.collapse-toggle:hover { color: var(--accent-hover); }

.collapse-toggle svg {
  width: 14px;
  height: 14px;
  transition: transform .2s ease;
}

.collapse-toggle[aria-expanded="true"] svg { transform: rotate(90deg); }

.collapse {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .25s ease;
}

.collapse > div {
  overflow: hidden;
  min-height: 0;
  /* visibility keeps the collapsed inputs out of the tab order; it flips
     immediately on open (focus works right away) and after the height
     animation on close */
  visibility: hidden;
  transition: visibility 0s .25s;
}

.collapse[data-open] { grid-template-rows: 1fr; }

.collapse[data-open] > div {
  visibility: visible;
  transition: visibility 0s;
}

/* Breathing room between the toggle and the revealed first field. The
   side padding + negative margin keep the fields aligned while giving the
   selected color dot's ring room — the collapse's overflow: hidden would
   clip the 4px box-shadow at the container edge otherwise. */
.collapse .collapse-body { padding: 14px 6px 0; margin: 0 -6px; }

@media (prefers-reduced-motion: reduce) {
  .collapse,
  .collapse > div,
  .collapse-toggle svg { transition: none; }
}

.field select {
  width: 100%;
  font: inherit;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}

.field select:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}


/* Icon button in table rows (e.g. delete license) */
.icon-button {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: background .12s, color .12s;
}

.icon-button:hover { background: var(--red-bg); color: var(--red-text); }

.icon-button svg { width: 16px; height: 16px; }

/* Action column: suspend/resume and delete sit side by side */
.row-actions { display: inline-flex; gap: 2px; }

/* Trial column: the switch is the trial-toggle form's submit button. An
   accent track means redeeming starts a trial, grey means the full term
   starts right away. */

.trial-switch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 2px;
  border: none;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  color: var(--text-dim);
}

.trial-switch-track {
  position: relative;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: #ccd5dc;
  transition: background-color .15s;
}

.trial-switch-track::before {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .25);
  transition: transform .15s;
}

.trial-switch:hover .trial-switch-track { filter: brightness(.96); }
.trial-switch[aria-pressed="true"] { color: var(--accent-ink); }
.trial-switch[aria-pressed="true"] .trial-switch-track { background: var(--accent); }
.trial-switch[aria-pressed="true"] .trial-switch-track::before { transform: translateX(14px); }
.trial-switch:focus-visible { outline: none; }
.trial-switch:focus-visible .trial-switch-track { box-shadow: var(--focus-ring); }

/* Locked switch: the decision was consumed at redemption; the position
   still shows the phase, the tooltip explains why it cannot change. */
.trial-switch:disabled { cursor: default; opacity: .5; }
.trial-switch:disabled:hover .trial-switch-track { filter: none; }

/* Overflow menu for a row's secondary actions. The panel is fixed-positioned
   by portal.js so the table's scroll container cannot clip it. */
.row-menu { display: inline-flex; }

/* The trigger only opens the menu — neutral hover; red stays reserved
   for the destructive items inside the panel. */
.row-menu-trigger:hover,
.row-menu-trigger[aria-expanded="true"] { background: #f2f5f7; color: var(--text); }

.row-menu-panel {
  position: fixed;
  z-index: 60;
  min-width: 215px;
  padding: 4px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(30, 41, 54, .14);
  display: flex;
  flex-direction: column;
}

.row-menu-panel[hidden] { display: none; }

/* Forms wrap the confirming actions; they must not break the item layout */
.row-menu-panel form { display: contents; }

.menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 7px;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text);
  cursor: pointer;
}

.menu-item:hover { background: var(--accent-soft); color: var(--accent-ink); }

.menu-item svg { width: 15px; height: 15px; flex-shrink: 0; }

/* Description pencil: revealed on row hover, like the copy button */
.description-edit { opacity: 0; flex-shrink: 0; }
.table tr:hover .description-edit,
.description-edit:focus-visible { opacity: 1; }

/* ---------- Status rail: the license list's lifecycle selector ---------- */

.status-rail {
  display: flex;
  align-items: stretch;
  gap: 2px;
  padding: 0 12px;
  background: #fafbfc;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}

.status-rail-sep {
  width: 1px;
  background: var(--border);
  margin: 8px 6px;
  flex: none;
}

.status-tab {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 10px 12px 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  transition: color .12s;
}

.status-tab:hover { color: var(--text); }

.status-tab[aria-selected="true"] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

/* The count carries the weight here, so it stays legible unselected */
.status-tab-count {
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  background: var(--neutral-bg);
  border-radius: 999px;
  padding: 1px 7px;
  min-width: 22px;
  text-align: center;
}

.status-tab[aria-selected="true"] .status-tab-count {
  background: var(--accent-soft);
  color: var(--steel);
}

.table-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.search-box {
  position: relative;
  flex: 1;
  min-width: 200px;
  max-width: 340px;
}

.search-box svg {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--text-faint);
  pointer-events: none;
}

.search-box input {
  width: 100%;
  font: inherit;
  font-size: 13px;
  padding: 7px 12px 7px 32px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  transition: border-color .12s, box-shadow .12s;
}

.search-box input:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.select-inline {
  font: inherit;
  font-size: 13px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}

.select-inline:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.toolbar-count { margin-left: auto; font-size: 12.5px; color: var(--text-dim); white-space: nowrap; }

/* Toolbar checkbox filter, boxed like .select-inline so it reads as one
   control among the selects */
.check-inline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}

.check-inline input {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.check-inline:focus-within {
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.check-inline input:focus-visible { outline: none; }

/* ---------- Copy license code ---------- */

.copy-btn {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-left: 4px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  vertical-align: middle;
  opacity: 0;
  transition: background .12s, color .12s, opacity .12s;
}

.table tr:hover .copy-btn, .copy-btn:focus-visible, .copy-btn.copied,
.copy-btn-visible { opacity: 1; }

.copy-btn:hover { background: var(--accent-soft); color: var(--accent-ink); }

.copy-btn svg { width: 13px; height: 13px; }

.copy-btn .icon-check { display: none; }
.copy-btn.copied .icon-check { display: block; color: var(--green-text); }
.copy-btn.copied .icon-copy { display: none; }

/* ---------- Empty states ---------- */

.empty-state { display: grid; justify-items: center; gap: 4px; }

.empty-state svg { width: 34px; height: 34px; margin-bottom: 6px; color: #ccd5dc; }

.empty-state strong { color: var(--text-dim); font-size: 14px; }

.empty-state span { max-width: 380px; }

/* ---------- Dashboard ---------- */

.tile-link { display: block; color: inherit; transition: border-color .12s, box-shadow .12s; }

.tile-link:hover {
  text-decoration: none;
  border-color: #a8dae5;
  box-shadow: 0 2px 8px rgba(26, 177, 161, .14);
}

.breakdown-card { max-width: 520px; }

/* Dashboard cards below the tiles: side by side where they fit */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
  align-items: start;
  margin-bottom: 24px;
}

.card-header-link { font-size: 12.5px; font-weight: 600; }

.breakdown-link:hover { text-decoration: none; }
.breakdown-link:hover .badge { box-shadow: 0 0 0 2px rgba(26, 177, 161, .3); }

/* ---------- Category management ---------- */

.category-create-card { padding: 20px; }

.category-create-form {
  display: flex;
  align-items: flex-end;
  gap: 20px;
  flex-wrap: wrap;
}

.category-create-form .field { margin-bottom: 0; flex: 1; min-width: 220px; max-width: 340px; }

.category-create-form .btn { padding: 9px 16px; }

.color-options { display: flex; gap: 8px; flex-wrap: wrap; padding: 5px 0; }

/* Written as .field label.color-option: the generic ".field label" rule
   (display: block, margin-bottom) has higher specificity than a plain
   .color-option and would flatten the swatch labels — the inline spans
   then lose their size and the picker renders invisible. */
.field label.color-option,
.color-option {
  position: relative;
  cursor: pointer;
  display: inline-grid;
  margin-bottom: 0;
}

.color-option input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

/* The dot takes the strong text color of its .cat-* class as fill
   (currentColor), so the swatches are vivid instead of the pale badge
   background. display: block so width/height apply regardless of the
   parent. */
.color-options .color-dot {
  display: block;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: currentColor;
  border: 1px solid rgba(30, 41, 54, .08);
  transition: transform .12s, box-shadow .12s;
}

.color-option:hover .color-dot { transform: scale(1.12); }

.color-option input:checked + .color-dot {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px currentColor;
}

.color-option input:focus-visible + .color-dot {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-hover);
}

/* Custom-color swatch: the native color input styled as a round swatch that
   shows the chosen color. The radio (hidden, not overlaid) carries the value.
   The overrides beat the generic ".color-option input" hide-rule so the
   swatch stays visible and clickable (opens the native picker). */
.color-option-custom .custom-color-radio { display: none; }

.color-option-custom .custom-color-input {
  position: relative;
  inset: auto;
  opacity: 1;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid rgba(30, 41, 54, .15);
  border-radius: 50%;
  /* Resting look: a rainbow wheel so it reads as "pick your own", not as
     another palette dot. The native swatch (the chosen solid color) sits on
     top of it but is revealed only once a color is actually selected. */
  background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #06b6d4,
                             #3b82f6, #a855f7, #ec4899, #ef4444);
  cursor: pointer;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  transition: transform .12s, box-shadow .12s;
}

.color-option-custom:hover .custom-color-input { transform: scale(1.12); }

.color-option-custom .custom-color-input::-webkit-color-swatch-wrapper { padding: 0; }

/* Hide the solid swatch by default so the gradient shows; reveal the chosen
   color only when this custom option is the selected one. */
.color-option-custom .custom-color-input::-webkit-color-swatch {
  border: none;
  border-radius: 50%;
  opacity: 0;
}
.color-option-custom .custom-color-input::-moz-color-swatch {
  border: none;
  border-radius: 50%;
  opacity: 0;
}
.custom-color-radio:checked + .custom-color-input::-webkit-color-swatch { opacity: 1; }
.custom-color-radio:checked + .custom-color-input::-moz-color-swatch { opacity: 1; }

.custom-color-radio:checked + .custom-color-input {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-hover);
}

.icon-button-edit:hover { background: var(--accent-soft); color: var(--accent-ink); }

.icon-button-accent:hover { background: var(--accent-soft); color: var(--accent-ink); }

/* ---------- Settings ---------- */

/* Group heading between settings cards (account vs company/system) */
.settings-section-title {
  margin: 26px 4px 10px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.settings-nav + .settings-section-title { margin-top: 6px; }

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

/* Outer spacing comes from .card-body; extra rows get a separator */
.setting-row + .setting-row {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.setting-label { font-size: 14px; font-weight: 600; }

.setting-desc { margin-top: 3px; font-size: 13px; color: var(--text-dim); max-width: 60ch; }

.settings-actions { display: flex; justify-content: flex-end; margin-top: 20px; }

/* Dropdowns and the password form on the settings page */
.setting-row .dd { flex-shrink: 0; }
.setting-row .select-inline,
.setting-row .dd-trigger { min-width: 210px; }

.settings-password-form { max-width: 380px; }

/* Blocking notice (missing sales price): amber rather than the accent tone,
   because it reports something the partner must resolve, not just news */
.notice-blocking {
  background: var(--yellow-bg);
  color: var(--yellow-text);
}
.notice-blocking .btn { margin-left: auto; }

/* Audit log: the date is a separator row, so the rows under it carry only
   the clock time and repeat neither the date nor an unchanged actor */
.audit-day th {
  background: var(--neutral-bg);
  color: var(--text-dim);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 6px 14px;
  text-align: left;
}
.audit-time { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Customer column: company with the email quieter underneath */
.customer-cell .dim { font-size: 12px; }

/* Archive of deactivated licenses: collapsed, quieter than the main card */

/* Priced actions (order, extension): the quote above the acknowledgment */
.extend-quote {
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

/* Profile form mirrors the password form */
.settings-profile-form { max-width: 380px; }
.settings-profile-form .field { margin-bottom: 14px; }
/* A value you cannot change still sits in a field, so the card reads as one
   form — dimmed and filled so it does not look editable. */
.field input[readonly],
.field input[disabled],
.field select[disabled] { color: var(--text-dim); background: var(--neutral-bg); }

.settings-profile-form input[readonly],
.settings-profile-form input[disabled] { color: var(--text-dim); background: var(--neutral-bg); }

/* SMTP form mirrors the password form; the test button sits below it */
.settings-smtp-form { max-width: 380px; }
.settings-smtp-form .field { margin-bottom: 14px; }
.settings-smtp-form .cost-ack { border-top: 0; padding-top: 0; margin-top: 4px; }
.settings-smtp-form .dialog-actions { justify-content: flex-start; margin-top: 12px; }
.settings-smtp-test { margin-top: 14px; }
.smtp-test-result { font-size: 12px; margin: 8px 0 0; }
.smtp-test-result.result-ok { color: var(--green-text); }
.smtp-test-result.result-error { color: var(--red-text); }
.settings-password-form .field { margin-bottom: 14px; }

/* Two-factor setup: numbered steps */
.twofa-setup .card-body { max-width: 560px; }
.twofa-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 24px; }
.twofa-steps > li { display: flex; gap: 14px; }
.twofa-step-num {
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: 13px;
  font-weight: 600;
}
.twofa-step-body { flex: 1; min-width: 0; }
.twofa-step-title { font-weight: 600; margin-bottom: 4px; }
.twofa-step-body .setting-desc { margin: 0 0 12px; }
.twofa-qr {
  width: 220px;
  height: 220px;
  padding: 10px;
  box-sizing: border-box;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.twofa-qr svg { width: 100%; height: 100%; display: block; }
button.twofa-qr { cursor: zoom-in; }
/* Enlarged view in the dialog; the dialog itself provides the frame */
.twofa-qr-dialog { max-width: none; }
.twofa-qr-large {
  width: min(70vh, calc(100vw - 96px), 480px);
  height: auto;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  cursor: zoom-out;
}
.twofa-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--neutral-bg);
}
.twofa-key .code { font-size: 13px; letter-spacing: .08em; }

/* Segmented one-time-code input: one box per digit */
.otp-input { display: flex; gap: 8px; }
.otp-cell {
  width: 42px;
  height: 50px;
  padding: 0;
  text-align: center;
  font-family: var(--mono);
  font-size: 20px;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  transition: border-color .12s, box-shadow .12s;
}
.otp-cell:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}
.login-card .otp-input { justify-content: center; }
.twofa-toggle {
  display: block;
  margin: 14px auto 0;
  border: 0;
  background: none;
  padding: 4px;
  font: inherit;
  font-size: 13px;
  color: var(--accent-ink);
  cursor: pointer;
}
.twofa-toggle:hover { text-decoration: underline; }
.twofa-setup .settings-actions { justify-content: flex-start; gap: 10px; }

/* Two-factor "on" state in Settings */
.card-header-title { display: flex; align-items: center; gap: 10px; }
.twofa-disable-row { display: flex; align-items: flex-end; gap: 10px; max-width: 460px; }
.twofa-disable-row .field { flex: 1; margin-bottom: 0; }
.twofa-recovery-left { margin: 14px 0 0; }

/* Recovery codes grid */
.recovery-codes {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  max-width: 420px;
}
.recovery-codes li {
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--neutral-bg);
  text-align: center;
  letter-spacing: .06em;
}
.recovery-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.table-actions { text-align: right; white-space: nowrap; }

/* Toggle switch: a styled checkbox */
.switch { position: relative; display: inline-block; width: 42px; height: 24px; flex-shrink: 0; }

.switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.switch-slider {
  position: absolute;
  inset: 0;
  background: #ccd5dc;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color .15s;
}

.switch-slider::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .25);
  transition: transform .15s;
}

.switch input:checked + .switch-slider { background: var(--accent); }
.switch input:checked + .switch-slider::before { transform: translateX(18px); }
.switch input:focus-visible + .switch-slider { box-shadow: var(--focus-ring); }

/* Permissions dialog: compact toggle rows, the whole row is clickable */
.permission-list { margin-bottom: 20px; }

.permission-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 10px 0;
  font-size: 14px;
  cursor: pointer;
}

.permission-row + .permission-row { border-top: 1px solid var(--border); }

/* ---------- Masked license codes ---------- */

/* The code itself is a button: click toggles masked/revealed */
.code-reveal {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.code-reveal:hover { color: var(--accent-ink); }

/* Eye toggles (toolbar, details dialog): crossed eye while revealed */
.eye-toggle .icon-eye-off { display: none; }
.eye-toggle[aria-pressed="true"] .icon-eye { display: none; }
.eye-toggle[aria-pressed="true"] .icon-eye-off { display: block; }
.eye-toggle[aria-pressed="true"] { color: var(--accent-ink); background: var(--accent-soft); }

/* ---------- Consistent select styling ----------
   Replace the native arrow of the light selects (toolbar filters, dialog
   fields) with the same chevron as the language picker. portal.js swaps
   the selects for custom dropdowns (see "Custom dropdowns" below); these
   rules also style the replacement triggers, and keep the no-JS
   fallback presentable. */

.select-inline,
.field select,
.field .dd-trigger {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c6b7c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px;
  padding-right: 30px;
}

.select-inline:hover,
.field select:hover,
.field .dd-trigger:hover { background-color: #fafbfc; }

/* ---------- Accordion (partner detail page) ---------- */

.accordion summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 20px;
  font-size: 15px;
  font-weight: 650;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.accordion summary::-webkit-details-marker { display: none; }

/* Chevron rotates when the section is open */
.accordion summary::after {
  content: "";
  width: 14px;
  height: 14px;
  margin-left: auto;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c6b7c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  transition: transform .15s;
}

.accordion[open] summary::after { transform: rotate(180deg); }

.accordion[open] summary { border-bottom: 1px solid var(--border); }

.accordion summary .dim { font-size: 13px; font-weight: 500; }

/* Pushes a summary action to the right; the chevron keeps its own slot */
.accordion-spacer { flex: 1 1 auto; }

.accordion summary .btn { padding: 5px 12px; font-weight: 600; }

.accordion-body { padding: 20px; }

/* Subheading between two tables inside one accordion section */
.accordion-subheading {
  padding: 14px 20px 10px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-dim);
}

/* Settings section: compact form + separated danger zone */
.settings-form { max-width: 380px; }

/* ratiotec's own contact sits outside the partner's form (they cannot change
   it), so it needs the separation the form's save row would have given it. */
.company-ratiotec-contact {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  margin-bottom: 0;
}

/* A leading description in a card body: the card padding already sets the
   distance to the header, and the field below needs more air than a default
   paragraph margin gives it. */
.card-body > p.dim:first-child { margin-top: 0; margin-bottom: 20px; }

/* Settings has grown past a screenful, so the sections get jump marks.
   Horizontal rather than a rail, because the app already has a left sidebar. */
.settings-nav {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 24px;
  padding: 10px 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.settings-nav a {
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  text-decoration: none;
  transition: background-color 120ms, color 120ms;
}

.settings-nav a:hover { background: var(--neutral-bg); color: var(--text); }

.settings-nav a.active {
  background: var(--accent-soft);
  color: var(--steel);
  font-weight: 600;
}

/* Clear the sticky bar when an anchor is jumped to */
.content > .card[id] { scroll-margin-top: 64px; }

.danger-zone {
  margin-top: 24px;
  padding: 16px;
  border: 1px solid var(--red-bg);
  border-radius: 10px;
}

.danger-zone h3 { margin: 0 0 6px; font-size: 13.5px; color: var(--red-text); }

.danger-zone p { margin: 0 0 12px; font-size: 13px; }

/* ---------- Toasts (flash messages) ---------- */

/* Bottom-center of the content area (sidebar = 232px), same anchor as the
   bulk pill: a save made from the details drawer can raise a toast while a
   selection is up, so the toasts step over the pill when it is showing.

   A toast raised while the drawer is open must also not end up under its
   backdrop: the drawer is a modal dialog and lives in the top layer, where no
   z-index reaches, so the container is shown as a popover to join it
   (portal.js). Being a popover, it arrives with a UA box - border, padding,
   background, and inset: 0 with auto margins - which applies open or closed
   and is undone first, before the anchor below. */
.toasts {
  position: fixed;
  inset: auto;
  margin: 0;
  border: 0;
  padding: 0;
  background: transparent;
  color: inherit;
  overflow: visible;
  bottom: 24px;
  left: calc(50% + 116px);
  transform: translateX(-50%);
  z-index: 60;
  display: grid;
  gap: 10px;
  justify-items: center;
  width: fit-content;
  max-width: 440px;
}

.toasts.toasts-over-bulk { bottom: 82px; }

.toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 12px 12px 14px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 8px 30px rgba(30, 41, 54, .16);
  font-size: 13px;
  line-height: 1.45;
  animation: toast-in .18s ease-out;
}

/* The shells sit in every page and are raised by JS, so the author display
   above has to give way to [hidden] */
.toast[hidden] { display: none; }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.toast.toast-hide { opacity: 0; transform: translateY(10px); transition: opacity .18s, transform .18s; }

.toast svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 1px; }

.toast-ok svg { color: var(--green-text); }
.toast-error svg { color: var(--red-text); }

.toast span { flex: 1; }

.toast-close {
  border: 0;
  background: transparent;
  color: var(--text-faint);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 1px 4px;
  border-radius: 6px;
  flex-shrink: 0;
}

.toast-close:hover { background: var(--neutral-bg); color: var(--text); }

/* ---------- Bulk selection ---------- */

.table th.select-col, .table td.select-col { width: 34px; padding-right: 4px; }

input.row-select, #select-all {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
  cursor: pointer;
  vertical-align: middle;
}

/* Floating action bar: overlays the bottom of the viewport instead of
   sitting in the layout flow, so appearing/disappearing never shifts the
   table. Centered within the content area (sidebar = 232px wide). */
.bulk-bar {
  position: fixed;
  bottom: 24px;
  left: calc(50% + 116px);
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 18px;
  border-radius: 999px;
  background: var(--sidebar-bg);
  border: 1px solid rgba(255, 255, 255, .1);
  box-shadow: 0 12px 40px rgba(30, 41, 54, .35);
  font-size: 13px;
  color: #fff;
  animation: bulk-bar-in .16s ease-out;
}

@keyframes bulk-bar-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%); }
}

/* display: flex above would override the hidden attribute */
.bulk-bar[hidden] { display: none; }

.bulk-bar #bulk-count { font-weight: 650; white-space: nowrap; }

.bulk-bar .btn {
  padding: 5px 12px;
  background: rgba(255, 255, 255, .1);
  border-color: transparent;
  color: #fff;
  box-shadow: none;
  white-space: nowrap;
}

.bulk-bar .btn:hover { background: rgba(255, 255, 255, .18); border-color: transparent; }

.bulk-bar .btn-danger { background: #dc2626; }

.bulk-bar .btn-danger:hover { background: #b91c1c; }

.btn-link {
  border: 0;
  background: none;
  padding: 0 6px;
  font: inherit;
  font-size: 13px;
  color: var(--sidebar-text);
  cursor: pointer;
  white-space: nowrap;
}

.btn-link:hover { text-decoration: underline; color: #fff; }

/* ---------- "License created" dialog ---------- */

.created-codes {
  list-style: none;
  margin: 0 0 18px;
  padding: 10px 14px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--neutral-bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: grid;
  gap: 6px;
}

.created-codes .code { font-size: 13.5px; }

.created-code-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

/* QR dialog: title, hint, framed code, then a download menu button. */
.qr-dialog { max-width: min(340px, calc(100vw - 32px)); }
.qr-dialog h2 { margin-bottom: 6px; }

.qr-hint {
  margin: 0 auto 20px;
  max-width: 30ch;
  font-size: 13px;
  color: var(--text-dim);
}

/* Framed QR: soft card with padding so the code has a quiet margin */
.qr-frame {
  width: max-content;
  margin: 0 auto 22px;
  padding: 16px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .04);
}

.qr-frame .qr-image { display: block; width: 216px; height: 216px; }

.qr-actions { align-items: center; gap: 10px; }

/* Download menu: a button that opens a small action popover; each item is
   a download link. Styled to match the select dropdowns (.dd-panel). */
.menu { position: relative; display: inline-block; }

.menu-trigger { gap: 8px; }
.menu-trigger .menu-caret { width: 15px; height: 15px; transition: transform .15s ease; }
.menu-trigger[aria-expanded="true"] .menu-caret { transform: rotate(180deg); }

.menu-panel {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: calc(100% + 8px);
  z-index: 70;
  min-width: 180px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .04), 0 4px 10px rgba(30, 41, 54, .06),
              0 16px 40px rgba(30, 41, 54, .14);
  /* Own keyframes (not the select's dd-in): they must carry the
     translateX(-50%) centering, else the animation's transform wipes it
     and the panel jumps sideways before settling */
  animation: menu-in .13s ease-out;
}

.menu-panel[hidden] { display: none; }

.menu-up .menu-panel { top: auto; bottom: calc(100% + 8px); animation-name: menu-in-up; }

@keyframes menu-in {
  from { opacity: 0; transform: translate(-50%, -4px); }
  to { opacity: 1; transform: translateX(-50%); }
}

@keyframes menu-in-up {
  from { opacity: 0; transform: translate(-50%, 4px); }
  to { opacity: 1; transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .menu-panel { animation: none; }
}

/* Scoped to the dropdown: the bare .menu-item rules further up style the
   row overflow menu (flex, icon + label) and must not be overridden here. */
.menu-panel .menu-item {
  display: block;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 13px;
  color: var(--text);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.menu-panel .menu-item:hover,
.menu-panel .menu-item:focus-visible { outline: none; background: #f2f5f7; }

/* ---------- Pagination ---------- */

.page-nav { display: flex; gap: 8px; justify-content: flex-end; padding: 14px 20px; }
.page-nav .btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

/* Numbered pager (trials page): "Page x of y" left, pages right */
.page-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}
.page-bar .page-nav { padding: 0; align-items: center; gap: 4px; }
.page-bar .page-nav .btn { margin: 0 4px; }
.page-info { font-size: 12.5px; color: var(--text-dim); }
.page-num {
  min-width: 32px;
  height: 32px;
  display: inline-grid;
  place-items: center;
  border-radius: 8px;
  font-size: 13px;
  color: var(--text);
  text-decoration: none;
}
.page-num:hover { background: #f2f5f7; }
.page-num.active { background: var(--sidebar-bg); color: #fff; pointer-events: none; }
.page-gap { align-self: center; color: var(--text-dim); padding: 0 2px; }

/* The license pager is built client-side, so its numbers are buttons rather
   than the links the server-rendered pagers use */
button.page-num {
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

/* ---------- Login ---------- */

.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  /* Brand gradient: primary colors only (turquoise + dark blue), softened
     toward white as the guide allows */
  background:
    radial-gradient(1000px 500px at 85% -10%, rgba(26, 177, 161, .18), transparent 60%),
    radial-gradient(800px 400px at -10% 110%, rgba(30, 41, 54, .14), transparent 60%),
    var(--bg);
  padding: 24px;
}

.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(30, 41, 54, .10);
  padding: 36px 32px 30px;
}

.login-card .brand { padding: 0 0 8px; }

.login-card h1 { font-size: 19px; margin: 14px 0 2px; letter-spacing: -.01em; }
.login-card .subtitle { color: var(--text-dim); font-size: 13.5px; margin-bottom: 22px; }

.field { margin-bottom: 16px; }

.field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }

.field-hint { font-size: 12px; color: var(--text-dim); margin-top: 5px; }
.field-hint.warning { color: var(--yellow-text); }

.field input {
  width: 100%;
  font: inherit;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  transition: border-color .12s, box-shadow .12s;
}

.field input:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.field textarea {
  width: 100%;
  font: inherit;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  resize: vertical;
  transition: border-color .12s, box-shadow .12s;
}

.field textarea:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.notice {
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  margin-bottom: 16px;
}

.notice-error { background: var(--red-bg); color: var(--red-text); }
.notice-ok { background: var(--green-bg); color: var(--green-text); }

.login-footer { text-align: center; margin-top: 18px; font-size: 12px; color: var(--text-faint); }

.login-forgot {
  display: block;
  text-align: center;
  margin-top: 12px;
  font-size: 12.5px;
  color: var(--accent-ink);
  text-decoration: none;
}

.login-forgot:hover { text-decoration: underline; }

/* ---------- Error pages (templates/error/*) ---------- */

.error-card { text-align: center; }

.error-status {
  margin: 20px 0 2px;
  font-size: 46px;
  font-weight: 750;
  letter-spacing: -.04em;
  color: var(--accent-ink);
}

.error-card h1 { margin: 0 0 6px; }

.error-card .subtitle { margin-bottom: 24px; }

/* ---------- Custom dropdowns ----------
   Browsers do not allow styling the native <select> option list, and long
   lists (10+ categories, many partners) are hard to navigate. portal.js
   hides each select (it keeps submitting forms and firing change events)
   and renders a trigger button + this popover: scrollable list, selected
   check mark, optional chips/swatches/flags, and a search box from 8
   options up. The status and category filters reuse the same shell with
   multi-select toggle rows (aria-checked). */

.dd { position: relative; display: inline-block; }

.field .dd,
.lang-picker .dd { display: block; }

.dd-trigger { text-align: left; }

.dd-trigger .dd-value {
  display: block;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dialog selects are styled via ".field select"; the shared rules above
   add the chevron. Width and label may fill the field. */
.field .dd-trigger {
  width: 100%;
  font: inherit;
  color: var(--text);
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .12s, box-shadow .12s;
}

.field .dd-trigger .dd-value { max-width: none; }

.field .dd-trigger:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.dd-trigger[aria-expanded="true"] {
  border-color: var(--accent-hover);
  box-shadow: var(--focus-ring);
}

.dd-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 70;
  min-width: 100%;
  width: max-content;
  /* Never wider than the viewport allows, so a narrow screen cannot be
     given a horizontal scrollbar by a long option label */
  max-width: min(300px, calc(100vw - 24px));
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .04), 0 4px 10px rgba(30, 41, 54, .06),
              0 16px 40px rgba(30, 41, 54, .14);
  animation: dd-in .13s ease-out;
}

/* The filter panels get a comfortable fixed minimum: "width: max-content"
   cannot size the panel from its width-100% rows, and labels would
   truncate at the (narrow) trigger width otherwise */
#license-status-filter .dd-panel,
#license-category-filter .dd-panel { min-width: 224px; }

/* Opens upward when the viewport space below is too tight (portal.js) */
.dd-up .dd-panel { top: auto; bottom: calc(100% + 6px); animation-name: dd-in-up; }

/* Hangs from the trigger's right edge when a panel wider than its trigger
   would otherwise reach past the right edge of the page (portal.js). The
   settings rows are space-between, so their triggers sit flush right. */
.dd-end .dd-panel { left: auto; right: 0; }

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

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

@media (prefers-reduced-motion: reduce) {
  .dd-panel { animation: none; }
}

.dd-list {
  max-height: 264px;
  overflow-y: auto;
  overscroll-behavior: contain;
  outline: none;
  scrollbar-width: thin;
  scrollbar-color: #ccd5dc transparent;
}

.dd-list::-webkit-scrollbar { width: 10px; }
.dd-list::-webkit-scrollbar-track { background: transparent; }
.dd-list::-webkit-scrollbar-thumb {
  background: #ccd5dc;
  border-radius: 5px;
  border: 3px solid var(--surface);
}

/* Rows are divs (single-select) or buttons (multi-select filters) —
   the reset keeps both identical */
.dd-option {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: none;
  font: inherit;
  font-size: 13px;
  color: inherit;
  text-align: left;
  cursor: pointer;
  user-select: none;
}

/* display: flex above would override the hidden attribute (search filter) */
.dd-option[hidden] { display: none; }

.dd-option:hover,
.dd-option[data-active] { background: #f2f5f7; }

.dd-option:focus-visible {
  outline: none;
  background: #f2f5f7;
  box-shadow: inset 0 0 0 2px rgba(26, 177, 161, .35);
}

.dd-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dd-option[aria-selected="true"] .dd-label,
.dd-option[aria-checked="true"] .dd-label { font-weight: 600; }

/* Multi-select filter rows lead with an explicit checkbox that fills
   turquoise when checked — clearer than a trailing check mark alone,
   which stays reserved for single-select rows. Grid toggles opt out:
   they carry their checked state as a fill (see .dd-toggle). */
.dd-option[role="checkbox"]:not(.dd-toggle)::before {
  content: "";
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border: 1.5px solid #c6cfd8;
  border-radius: 4px;
  background: #fff center / 11px no-repeat;
  transition: background-color .12s ease, border-color .12s ease;
}

.dd-option[role="checkbox"]:not(.dd-toggle)[aria-checked="true"]::before {
  border-color: var(--accent);
  background-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}

/* The checkbox replaces the trailing check and the bold-on-checked shift */
.dd-option[role="checkbox"]:not(.dd-toggle)::after { display: none; }
.dd-option[role="checkbox"]:not(.dd-toggle)[aria-checked="true"] .dd-label { font-weight: 500; }

/* Check mark on the right of the selected/checked row (CSS-only) */
.dd-option::after {
  content: "";
  width: 14px;
  height: 14px;
  margin-left: auto;
  flex-shrink: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230e7f72' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  visibility: hidden;
}

.dd-option[aria-selected="true"]::after,
.dd-option[aria-checked="true"]::after { visibility: visible; }

/* Chips appear only inside the trigger, where the selected value shows
   the category badge as it appears in the table. Menu rows use a small
   solid dot + plain label instead — calmer to scan than a list of pills. */
.dd-chip { flex-shrink: 0; }

.dd-value .dd-chip { padding: 2px 8px; }

/* Color dot in menu rows: fills with the strong .cat-* text color via
   currentColor (same trick as the category color picker); the overrides
   neutralize the badge padding/background a .cat-* class would apply. */
.dd-panel .dd-dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border-radius: 50%;
  flex-shrink: 0;
  background: currentColor;
  box-shadow: none;
}

/* "Without category": hollow dashed dot */
.dd-panel .dd-dot.badge-add {
  background: transparent;
  border: 1.5px dashed #9fadbb;
}

/* Solid status dots (status filter rows), matching the badge text colors */
.dd-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.sw-neutral { background: var(--neutral-text); }
.sw-green { background: var(--green-text); }
.sw-yellow { background: var(--yellow-text); }
.sw-red { background: var(--red-text); }
.sw-blue { background: var(--blue-text); }
.sw-slate { background: var(--slate-text); }
.sw-orange { background: var(--orange-text); }

/* Round mini flags (language picker), inline SVGs — self-hosted, no CDN */
.dd-flag {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  flex-shrink: 0;
  background-size: cover;
  background-position: center;
  box-shadow: inset 0 0 0 1px rgba(30, 41, 54, .15);
}

.dd-flag-en { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Crect width='60' height='60' fill='%23012169'/%3E%3Cpath d='M0 0 60 60M60 0 0 60' stroke='%23fff' stroke-width='12'/%3E%3Cpath d='M0 0 60 60M60 0 0 60' stroke='%23C8102E' stroke-width='7'/%3E%3Cpath d='M30 0v60M0 30h60' stroke='%23fff' stroke-width='18'/%3E%3Cpath d='M30 0v60M0 30h60' stroke='%23C8102E' stroke-width='10'/%3E%3C/svg%3E"); }

.dd-flag-de { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Crect width='60' height='20' fill='%23000'/%3E%3Crect y='20' width='60' height='20' fill='%23DD0000'/%3E%3Crect y='40' width='60' height='20' fill='%23FFCC00'/%3E%3C/svg%3E"); }

.dd-flag-es { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Crect width='60' height='60' fill='%23AA151B'/%3E%3Crect y='15' width='60' height='30' fill='%23F1BF00'/%3E%3C/svg%3E"); }

.dd-flag-it { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Crect width='20' height='60' fill='%23009246'/%3E%3Crect x='20' width='20' height='60' fill='%23fff'/%3E%3Crect x='40' width='20' height='60' fill='%23CE2B37'/%3E%3C/svg%3E"); }

.dd-flag-fr { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Crect width='20' height='60' fill='%23002395'/%3E%3Crect x='20' width='20' height='60' fill='%23fff'/%3E%3Crect x='40' width='20' height='60' fill='%23ED2939'/%3E%3C/svg%3E"); }

.dd-search {
  position: relative;
  margin: -6px -6px 6px;
  border-bottom: 1px solid var(--border);
}

.dd-search svg {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 13px;
  height: 13px;
  color: var(--text-faint);
  pointer-events: none;
}

.dd-search input {
  width: 100%;
  font: inherit;
  font-size: 13px;
  padding: 9px 12px 9px 32px;
  border: 0;
  border-radius: 12px 12px 0 0;
  background: transparent;
  outline: none;
}

.dd-empty {
  padding: 14px 12px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-faint);
}

/* Wide panel: filters with too many values for a one-per-row list lay them
   out as a grid of toggles instead (audit event filter) */
.dd-panel-wide {
  width: 560px;
  max-width: calc(100vw - 32px);
  max-height: min(70vh, 520px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The panel scrolls, so the search stays put instead of sliding away */
.dd-panel-wide .dd-search {
  position: sticky;
  top: -6px;
  z-index: 1;
  background: var(--surface);
}

.dd-toggle-group + .dd-toggle-group { margin-top: 4px; }
.dd-toggle-group[hidden] { display: none; }

.dd-toggle-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 6px 6px;
}

.dd-group-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-faint);
}

.dd-selectall,
.dd-clear {
  padding: 2px 4px;
  border: 0;
  border-radius: 6px;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--accent-ink);
  cursor: pointer;
}

.dd-selectall:hover,
.dd-clear:hover { text-decoration: underline; }

.dd-selectall:focus-visible,
.dd-clear:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.dd-selectall[aria-pressed="true"] { color: var(--text-faint); }

.dd-toggle-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}

/* A toggle, not a row: the checked state is the fill, so it reads at a
   glance across the grid without a checkbox or check-mark column */
.dd-toggle {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12.5px;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
}

.dd-toggle::after { display: none; }

.dd-toggle[hidden] { display: none; }

.dd-toggle:hover { background: #f2f5f7; }

.dd-toggle[aria-checked="true"] {
  border-color: var(--accent-hover);
  background: var(--accent-soft);
  font-weight: 600;
  color: var(--text);
}

.dd-toggle:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.dd-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

@media (max-width: 640px) {
  .dd-toggle-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 420px) {
  .dd-toggle-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Full-bleed separator between the all-row and the options */
.dd-sep { height: 1px; margin: 6px -6px; background: var(--border); }

/* Dark variant inside the sidebar (language picker) */
.sidebar .dd-panel {
  background: #26323f;
  border-color: rgba(255, 255, 255, .12);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .4);
}

.sidebar .dd-option { color: #dbe0ea; }

.sidebar .dd-option:hover,
.sidebar .dd-option[data-active] { background: rgba(255, 255, 255, .08); }

.sidebar .dd-option::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231ab1a0' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E"); }

/* Second queue on the replacements page (pending device transfers) */
.transfers-card { margin-top: 16px; }

/* ---------- Debug tools (admin) ---------- */

/* Cards in one row share the tallest card's height; every submit button
   sits on the same bottom line regardless of the card's content */
.debug-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 16px;
}

.debug-grid .card { display: flex; flex-direction: column; }
.debug-grid .card-body { flex: 1; display: flex; flex-direction: column; }
.debug-grid .card-body form { flex: 1; display: flex; flex-direction: column; }
.debug-grid .card-body form .btn { margin-top: auto; align-self: flex-start; }

.debug-hint {
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 0 0 16px;
}


/* License-code suggestions (custom datalist replacement, portal.js) */
.suggest-field { position: relative; }

.suggest-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 70;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(30, 41, 54, .04), 0 4px 10px rgba(30, 41, 54, .06),
              0 16px 40px rgba(30, 41, 54, .14);
}

.suggest-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 7px 9px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  font-size: 12.5px;
  text-align: left;
  cursor: pointer;
}

.suggest-option:hover,
.suggest-option.active { background: var(--accent-soft); }

.suggest-option .code { font-size: 12px; white-space: nowrap; }

.suggest-label {
  color: var(--text-dim);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Phones and small tablets: the sidebar becomes a drawer ---------- */

@media (max-width: 900px) {
  .app { display: block; }

  .mobile-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    position: sticky;
    top: 0;
    z-index: 40;
    background: var(--sidebar-bg);
    padding: 10px 14px;
  }

  .mobile-bar .brand { padding: 0; }
  .mobile-bar .brand-logo { height: 24px; display: block; }

  .menu-toggle {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--sidebar-text);
  }
  .menu-toggle svg { width: 22px; height: 22px; }
  .menu-toggle:focus-visible { outline: 2px solid var(--accent); }

  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: 264px;
    height: 100dvh;
    z-index: 60;
    transform: translateX(-100%);
    transition: transform .18s ease;
    box-shadow: 0 0 40px rgba(30, 41, 54, .35);
  }
  .sidebar.open { transform: none; }

  .drawer-overlay.open {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    background: rgba(30, 41, 54, .45);
  }

  .content { padding: 0 16px 32px; }
  .topbar { padding: 16px 0 18px; }

  /* Toolbars and pagers wrap instead of overflowing */
  .table-toolbar { flex-wrap: wrap; }
  .page-bar { flex-wrap: wrap; gap: 10px; }
  .setting-row { flex-wrap: wrap; }

  /* The table keeps its natural width and scrolls inside .table-scroll */
  .table-scroll .table { min-width: max-content; }

  /* Center the floating bulk bar without the sidebar offset */
  .bulk-bar { left: 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}
