/* 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; }

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: #6b7d8f;
  /* Centered like the wordmark above */
  text-align: center;
}

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

.sidebar-legal a {
  color: #6b7d8f;
  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; }

/* ---------- 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; }

.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; }

.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; }

/* 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-faint); }

/* 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; }

.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;
}

.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 an optional renewal-requested badge
   stacked below it (a notification, not a status change). */
.status-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

/* "+ 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;
}

/* ---------- 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;
}

/* The order-undo banner wraps its button in a form */
.stale-banner form { margin-left: auto; }

/* Order-undo banner: header row plus a collapsible list of the codes the
   cancellation would delete */
.order-banner {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

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

.order-banner .order-codes-toggle { flex-shrink: 0; }

.order-banner-row .btn { white-space: nowrap; }

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

/* 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;
}

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

/* License details dialog: masked code with its own eye toggle */
.details-code-row {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 14px;
}

/* 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; }

/* 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; }

/* Description text and edit pencil side by side. The text keeps its
   natural width so the pencil sits right after it; long text shrinks
   with an ellipsis and the pencil follows the truncated end. */
.description-inner {
  display: flex;
  align-items: center;
  gap: 4px;
}

.description-inner .description-text { min-width: 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; }

/* ---------- Table toolbar: search + filters ---------- */

.toolbar-label { font-size: 12.5px; color: var(--text-dim); }
.select-inline + .toolbar-label { margin-left: 8px; }

.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; }

/* ---------- 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 ---------- */

.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; }

/* 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; }
.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: 180px;
  height: 180px;
  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; }
.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; }

.accordion-toolbar {
  display: flex;
  justify-content: flex-end;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
}

.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; }

.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 — the two never show at once: flashes arrive on fresh
   page loads, where no selection exists yet */
.toasts {
  position: fixed;
  bottom: 24px;
  left: calc(50% + 116px);
  transform: translateX(-50%);
  z-index: 60;
  display: grid;
  gap: 10px;
  justify-items: center;
  max-width: 440px;
}

.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;
}

@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; }
}

.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-item:hover,
.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; }

/* ---------- 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 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);
}

.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;
  max-width: 300px;
  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; }

@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. */
.dd-option[role="menuitemcheckbox"]::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="menuitemcheckbox"][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="menuitemcheckbox"]::after { display: none; }
.dd-option[role="menuitemcheckbox"][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-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);
}

/* 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;
}

/* Details dialog: device id row keeps its copy button on one line */
.details-device-row dd { display: flex; align-items: center; gap: 2px; }

/* ---------- 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; }
}
