/* Ubitri brand tokens layered on Bootstrap 5.3's color modes.
   Light and dark values come from the brand sheet in design/wireframes. */

:root,
[data-bs-theme="light"] {
  --ub-accent: #EA791F;
  --ub-accent-hover: #d46b16;
  --ub-accent-rgb: 234, 121, 31;

  --bs-body-bg: #faf8f6;
  --bs-body-bg-rgb: 250, 248, 246;
  --bs-body-color: #2e1d14;
  --bs-body-color-rgb: 46, 29, 20;
  --bs-secondary-color: #7d6d63;
  --bs-secondary-color-rgb: 125, 109, 99;
  --bs-tertiary-bg: #efe9e4;
  --bs-tertiary-bg-rgb: 239, 233, 228;
  --bs-border-color: #d5ccc4;
  --bs-link-color: #c9611a;
  --bs-link-color-rgb: 201, 97, 26;
  --bs-link-hover-color: #a94f12;
  --bs-link-hover-color-rgb: 169, 79, 18;
  --bs-primary: var(--ub-accent);
  --bs-primary-rgb: var(--ub-accent-rgb);
  --bs-heading-color: #2e1d14;
  --ub-header-bg: rgba(250, 248, 246, 0.92);
}

[data-bs-theme="dark"] {
  --ub-accent: #F28A3C;
  --ub-accent-hover: #f79a55;
  --ub-accent-rgb: 242, 138, 60;

  --bs-body-bg: #1b1613;
  --bs-body-bg-rgb: 27, 22, 19;
  --bs-body-color: #f3ede8;
  --bs-body-color-rgb: 243, 237, 232;
  --bs-secondary-color: #a99d94;
  --bs-secondary-color-rgb: 169, 157, 148;
  --bs-tertiary-bg: #27211d;
  --bs-tertiary-bg-rgb: 39, 33, 29;
  --bs-border-color: #4c423b;
  --bs-link-color: #F28A3C;
  --bs-link-color-rgb: 242, 138, 60;
  --bs-link-hover-color: #f79a55;
  --bs-link-hover-color-rgb: 247, 154, 85;
  --bs-primary: var(--ub-accent);
  --bs-primary-rgb: var(--ub-accent-rgb);
  --bs-heading-color: #f3ede8;
  --ub-header-bg: rgba(27, 22, 19, 0.92);
}

/* Type */
html { font-size: 16px; }
body {
  font-family: "Source Sans 3", "Segoe UI", system-ui, sans-serif;
  line-height: 1.55;
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .display-5 {
  font-family: "Sora", "Segoe UI", system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.display-5 { font-weight: 700; }
.lead { font-size: 1.2rem; }

/* Buttons */
.btn-primary {
  --bs-btn-bg: var(--ub-accent);
  --bs-btn-border-color: var(--ub-accent);
  --bs-btn-hover-bg: var(--ub-accent-hover);
  --bs-btn-hover-border-color: var(--ub-accent-hover);
  --bs-btn-active-bg: var(--ub-accent-hover);
  --bs-btn-active-border-color: var(--ub-accent-hover);
  --bs-btn-color: #fff;
  --bs-btn-hover-color: #fff;
  --bs-btn-active-color: #fff;
  --bs-btn-focus-shadow-rgb: var(--ub-accent-rgb);
}
.btn-outline-primary {
  --bs-btn-color: var(--ub-accent);
  --bs-btn-border-color: var(--ub-accent);
  --bs-btn-hover-bg: var(--ub-accent);
  --bs-btn-hover-border-color: var(--ub-accent);
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--ub-accent);
  --bs-btn-active-border-color: var(--ub-accent);
  --bs-btn-active-color: #fff;
  --bs-btn-focus-shadow-rgb: var(--ub-accent-rgb);
}
.btn-outline-secondary {
  --bs-btn-color: var(--bs-body-color);
  --bs-btn-border-color: var(--bs-border-color);
  --bs-btn-hover-bg: var(--bs-tertiary-bg);
  --bs-btn-hover-border-color: var(--bs-border-color);
  --bs-btn-hover-color: var(--bs-body-color);
  --bs-btn-active-bg: var(--bs-tertiary-bg);
  --bs-btn-active-border-color: var(--bs-border-color);
  --bs-btn-active-color: var(--bs-body-color);
}
.btn { --bs-btn-border-radius: 0.5rem; --bs-btn-font-weight: 600; }
.btn-lg { --bs-btn-padding-x: 1.4rem; }
.btn-icon {
  display: inline-flex; align-items: center; gap: 0.15rem;
  padding: 0.45rem 0.5rem; color: var(--bs-body-color);
  border: 1px solid transparent; border-radius: 0.5rem;
}
.btn-icon:hover { background: var(--bs-tertiary-bg); border-color: var(--bs-border-color); }
.btn-check:focus-visible + .btn, .btn:focus-visible { box-shadow: 0 0 0 0.25rem rgba(var(--ub-accent-rgb), 0.35); }

/* Icons (stroke-based, inherit currentColor) */
.icon {
  width: 1.25rem; height: 1.25rem; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -0.3em;
}
.icon-caret { width: 0.9rem; height: 0.9rem; }
.icon-lg { width: 2.25rem; height: 2.25rem; }
.icon-xl { width: 3.5rem; height: 3.5rem; }
.dropdown-item .icon { margin-right: 0.5rem; }
.dropdown-item.active, .dropdown-item:active { background-color: var(--ub-accent); color: #fff; }

/* Header */
.site-header {
  position: sticky; top: 0; z-index: 1030;
  background: var(--bs-body-bg);
  border-bottom: 1px solid var(--bs-border-color);
}
.site-header .navbar { padding: 0.4rem 0; }
.site-header .nav-link { font-weight: 600; padding: 0.5rem 0.9rem; color: var(--bs-body-color); }
.site-header .nav-link.active, .site-header .nav-link:hover { color: var(--ub-accent); }
.site-header .btn-link { color: var(--bs-body-color); text-decoration: none; font-weight: 600; }
.site-header .btn-link:hover { color: var(--ub-accent); }

/* Products menu: a panel that opens on hover or keyboard focus on wide screens, and a short indented
   list under Products in the collapsed menu, where there is no hover to open it. */
.nav-hover .icon-caret { margin-left: 0.15rem; vertical-align: -0.15em; transition: transform 0.15s ease; }
.nav-submenu { list-style: none; margin: 0; padding: 0 0 0.25rem 1rem; }
.nav-submenu-item {
  display: flex; align-items: flex-start; gap: 0.75rem;
  padding: 0.4rem 0.9rem; border-radius: 0.5rem;
  color: var(--bs-body-color); text-decoration: none;
}
.nav-submenu-icon { color: var(--ub-accent); flex: none; line-height: 1; }
.nav-submenu-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.nav-submenu-title { font-weight: 600; }
.nav-submenu-desc { display: none; color: var(--bs-secondary-color); font-size: 0.875rem; line-height: 1.35; }
.nav-submenu-item:hover, .nav-submenu-item.active { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.nav-submenu-item:hover .nav-submenu-title, .nav-submenu-item.active .nav-submenu-title { color: var(--ub-accent); }
.nav-submenu-item:focus-visible { outline: none; box-shadow: 0 0 0 0.25rem rgba(var(--ub-accent-rgb), 0.35); }
@media (min-width: 992px) {
  .nav-hover { position: relative; }
  .nav-submenu {
    position: absolute; top: 100%; left: 50%; z-index: 1040;
    width: 22rem; margin-top: 0.5rem; padding: 0.5rem;
    background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
    box-shadow: 0 0.75rem 2rem rgba(0, 0, 0, 0.18);
    opacity: 0; visibility: hidden; transform: translate(-50%, 4px);
    /* Stays up a moment after the pointer leaves, so a slightly off-line move does not close it. */
    transition: opacity 0.15s ease 0.12s, transform 0.15s ease 0.12s, visibility 0s linear 0.27s;
  }
  /* Covers the gap between the link and the panel, so the pointer never leaves the item crossing it. */
  .nav-submenu::before { content: ""; position: absolute; left: 0; right: 0; top: -0.6rem; height: 0.6rem; }
  .nav-hover:hover .nav-submenu, .nav-hover:focus-within .nav-submenu {
    opacity: 1; visibility: visible; transform: translate(-50%, 0);
    transition: opacity 0.15s ease, transform 0.15s ease, visibility 0s;
  }
  .nav-hover:hover .icon-caret, .nav-hover:focus-within .icon-caret { transform: rotate(180deg); }
  .nav-submenu-item { padding: 0.65rem 0.75rem; }
  .nav-submenu-icon .icon { width: 1.5rem; height: 1.5rem; }
  .nav-submenu-desc { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-submenu, .nav-hover .icon-caret { transition: none !important; }
}
.logo { height: 64px; width: auto; display: none; }
.logo-sm { height: 44px; }
[data-bs-theme="light"] .logo-on-light, :root:not([data-bs-theme="dark"]) .logo-on-light { display: inline-block; }
[data-bs-theme="dark"] .logo-on-dark { display: inline-block; }
[data-bs-theme="dark"] .logo-on-light { display: none; }

.badge-beta {
  color: var(--ub-accent); background: transparent;
  border: 1.5px solid var(--ub-accent); border-radius: 999px;
  font-weight: 600; font-size: 0.7rem; padding: 0.25em 0.6em; vertical-align: middle;
}

/* Footer */
.site-footer {
  border-top: 1px solid var(--bs-border-color);
  padding: 1.5rem 0;
  margin-top: 3rem;
}
.site-footer .nav-link { color: var(--bs-secondary-color); padding: 0.25rem 0.75rem; }
.site-footer .nav-link:hover { color: var(--ub-accent); }

/* Page building blocks */
.hero { padding: 3.5rem 0 2.5rem; }
.section { padding: 2.5rem 0; }
.page-header { padding: 2.5rem 0 1.5rem; max-width: 46rem; }
.page-header h1 { font-size: 2.4rem; }
.narrow-page { max-width: 34rem; margin: 3rem auto; }
.prose { max-width: 46rem; }

.placeholder-frame {
  display: flex; align-items: center; justify-content: center; text-align: center;
  color: var(--bs-secondary-color); background: var(--bs-tertiary-bg);
  border: 2px dashed var(--bs-border-color); border-radius: 0.75rem;
}
.product-frame { min-height: 320px; }
.split-frame { min-height: 260px; background: var(--bs-body-bg); }

.card {
  --bs-card-border-color: var(--bs-border-color);
  --bs-card-border-radius: 0.75rem;
  --bs-card-bg: var(--bs-body-bg);
  --bs-card-spacer-y: 1.5rem; --bs-card-spacer-x: 1.5rem;
}
.card-link { font-weight: 600; }

.beta-band {
  border: 2px solid var(--ub-accent); border-radius: 0.75rem;
  padding: 2rem;
}
.step-number {
  font-family: "Sora", system-ui, sans-serif; font-weight: 700;
  font-size: 2rem; line-height: 1; color: var(--ub-accent); margin-bottom: 0.5rem;
}
.feature-list { padding-left: 1.2rem; }
.feature-list li { margin-bottom: 0.4rem; }
.cta-panel {
  background: var(--bs-tertiary-bg); border-radius: 0.75rem; padding: 1.75rem;
}
.check-list { list-style: none; padding: 0; margin: 1rem 0 0; }
.check-list li { position: relative; padding-left: 1.6rem; margin-bottom: 0.4rem; }
.check-list li::before {
  content: ""; position: absolute; left: 0; top: 0.45em; width: 0.9rem; height: 0.5rem;
  border-left: 2.5px solid var(--ub-accent); border-bottom: 2.5px solid var(--ub-accent);
  transform: rotate(-45deg);
}

/* Forms */
.form-stack { display: flex; flex-direction: column; gap: 1.1rem; }
.form-control, .form-select {
  background-color: var(--bs-body-bg); color: var(--bs-body-color);
  border-color: var(--bs-border-color); border-radius: 0.5rem; padding: 0.6rem 0.8rem;
}
.form-control:focus, .form-select:focus {
  border-color: var(--ub-accent); box-shadow: 0 0 0 0.25rem rgba(var(--ub-accent-rgb), 0.25);
  background-color: var(--bs-body-bg); color: var(--bs-body-color);
}
.form-check-input:checked { background-color: var(--ub-accent); border-color: var(--ub-accent); }
.form-check-input:focus { border-color: var(--ub-accent); box-shadow: 0 0 0 0.25rem rgba(var(--ub-accent-rgb), 0.25); }
.strength { display: flex; gap: 0.3rem; margin-top: 0.5rem; }
.strength span { flex: 1; height: 5px; border-radius: 3px; background: var(--bs-border-color); }
.strength span.on { background: var(--ub-accent); }

/* Auth pages */
.auth-card {
  max-width: 30rem; margin: 2.5rem auto;
  border: 1px solid var(--bs-border-color); border-radius: 1rem;
  padding: 2.25rem;
  background: var(--bs-body-bg);
}
.auth-step { font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bs-secondary-color); margin-bottom: 0.4rem; }
.auth-footer { border-top: 1px solid var(--bs-border-color); margin-top: 1.5rem; padding-top: 1rem; text-align: center; color: var(--bs-secondary-color); }
.locked-email {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.75rem 1rem; border: 1px solid var(--bs-border-color); border-radius: 0.5rem;
  background: var(--bs-tertiary-bg);
}
.locked-email-value { font-weight: 600; word-break: break-all; }
.divider { display: flex; align-items: center; gap: 0.75rem; color: var(--bs-secondary-color); font-size: 0.9rem; margin: 1.25rem 0; }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--bs-border-color); }

.split-page { display: grid; grid-template-columns: 1fr; min-height: calc(100vh - 82px); }
.split-brand {
  display: none; background: var(--bs-tertiary-bg);
  padding: 3rem; align-items: center;
}
.split-form { display: flex; flex-direction: column; }
.split-form-inner { width: 100%; max-width: 26rem; margin: auto; padding: 2rem 1rem; }
@media (min-width: 992px) {
  .split-page { grid-template-columns: 1fr 1fr; }
  .split-brand { display: flex; }
}

/* Settings */
.settings-layout { display: grid; grid-template-columns: 1fr; gap: 2rem; padding: 2rem 0; }
@media (min-width: 768px) { .settings-layout { grid-template-columns: 15rem 1fr; gap: 3rem; } }
.settings-nav { display: flex; flex-direction: column; gap: 0.15rem; }
.settings-nav-title { font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bs-secondary-color); padding: 0 0.9rem 0.5rem; }
.settings-nav a { padding: 0.55rem 0.9rem; border-radius: 0.5rem; color: var(--bs-body-color); text-decoration: none; }
.settings-nav a:hover { background: var(--bs-tertiary-bg); }
.settings-nav a.active { background: var(--bs-tertiary-bg); color: var(--ub-accent); font-weight: 600; }
.settings-content { max-width: 44rem; }

.segmented { display: inline-flex; gap: 0.25rem; padding: 0.25rem; border: 1px solid var(--bs-border-color); border-radius: 0.6rem; }
.segmented .btn { border: 0; color: var(--bs-body-color); display: inline-flex; align-items: center; gap: 0.4rem; }
.segmented .btn:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
/* Two ways to mark the selected segment: a checked radio (settings forms) and an .active anchor
   (the billing interval toggle, where each segment is a link to the same page at a different
   interval). Both need the same fill, or the control looks like nothing is selected. The :hover
   variants are here so the rule above does not strip the fill off the selected segment. */
.segmented .btn-check:checked + .btn,
.segmented .btn-check:checked + .btn:hover,
.segmented .btn.active,
.segmented .btn.active:hover { background: var(--ub-accent); color: #fff; }

/* The discount code box under the plan cards. Narrow on purpose: a code is a short string, and a
   full-width field invites somebody to think it is the more important thing on the page. */
.discount-box { width: 100%; max-width: 22rem; }
.discount-box input { text-transform: uppercase; }
.discount-box input::placeholder { text-transform: none; }
.theme-preview {
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem; padding: 1rem;
  background: var(--bs-body-bg); color: var(--bs-body-color);
  display: flex; flex-direction: column; gap: 0.6rem; align-items: flex-start;
}
.theme-preview .d-flex { width: 100%; }
.theme-preview-bar { height: 8px; border-radius: 4px; background: var(--bs-border-color); }

/* Dropdowns and alerts in dark mode pick up the body tokens */
.dropdown-menu { --bs-dropdown-bg: var(--bs-body-bg); --bs-dropdown-border-color: var(--bs-border-color); --bs-dropdown-link-color: var(--bs-body-color); --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg); --bs-dropdown-link-hover-color: var(--bs-body-color); }
.list-group { --bs-list-group-bg: var(--bs-body-bg); --bs-list-group-border-color: var(--bs-border-color); --bs-list-group-color: var(--bs-body-color); }

/* Legal pages (Privacy, Terms) */
.prose.legal h2 { font-size: 1.35rem; margin-top: 2.5rem; margin-bottom: 0.75rem; scroll-margin-top: 6rem; }
.prose.legal h3 { font-size: 1.05rem; margin-top: 1.5rem; margin-bottom: 0.5rem; }
.prose.legal li { margin-bottom: 0.35rem; }
.prose.legal .table { font-size: 0.95rem; }
.prose.legal .table th { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; white-space: nowrap; }
.legal-toc {
  background: var(--bs-tertiary-bg); border-radius: 0.75rem;
  padding: 1.25rem 1.5rem; margin: 1.5rem 0 2rem;
}
.legal-toc ol { margin: 0; padding-left: 1.2rem; }
.legal-toc li { margin-bottom: 0.3rem; }
.legal-toc a { text-decoration: none; font-weight: 600; }
.legal-toc a:hover { text-decoration: underline; }
@media (min-width: 768px) { .legal-toc ol { columns: 2; column-gap: 2.5rem; } .legal-toc li { break-inside: avoid; } }

/* Admin portal */
.admin-layout { padding-bottom: 3rem; }
/* min-width: 0 keeps the wide user table inside the grid column instead of stretching the page. */
.admin-content { min-width: 0; }
/* The admin portal uses the whole window rather than the centred column the rest of the site sits in: its
   pages are tables, queues and settings, and a centred 1320px left a wide screen half empty. Keyed to
   .admin-layout, which every admin page has and no other page does, so the header and footer follow the
   page without the layout having to be told what it is rendering. From 768px, where the nav moves beside
   the content; narrower than that the container is the whole width already. */
@media (min-width: 768px) {
  body:has(.admin-layout) .site-header .navbar > .container,
  body:has(.admin-layout) main > .container,
  body:has(.admin-layout) .site-footer > .container { max-width: none; padding-left: 2rem; padding-right: 2rem; }
}
/* What keeps the width the admin pages had before: things built from short controls, which come apart when
   stretched - a two-digit field half a screen wide, a Copy button a long way from what it copies. The
   sections around them, and the tables and lists, still take the whole width. */
.admin-layout form.row,
.admin-layout form[role="search"],
.admin-layout form .row:not(dl),
.admin-layout .config-section > .row:not(dl),
.admin-layout .config-section > .input-group,
.admin-layout .invoice-lines,
.admin-layout .catalog-rates,
.admin-layout .filedrop-now,
.admin-layout .ticket-thread,
.admin-layout .ticket-thread ~ hr,
.admin-layout .config-section > hr { max-width: 56rem; }
/* A textarea outside a row of fields - a snippet to copy, a notice, a list of addresses - lines up with the
   widest field a row would give it: the 56rem row less its gutters. */
.admin-layout textarea { max-width: 55rem; }
/* Running text keeps the width it had as well. Across the whole column a sentence of help runs to 300
   characters on a wide screen, and small grey text that long cannot be read in one pass. Bordered list rows
   are lists rather than text, so they still span. So does an alert's box, which has to line up with the boxes
   above and below it; only its text is held, by padding. A detail list is held as a whole - its widest label
   column plus a paragraph's width - because holding only the values would let the next label move up beside
   them. A measure that no longer changes with the window strands the same word on its last line at every
   width, which text-wrap: pretty avoids where the browser supports it. */
.admin-layout .admin-content :is(p, .form-text, li:not(.list-group-item)) { max-width: 56rem; }
.admin-layout .admin-content .alert { padding-right: max(var(--bs-alert-padding-x), calc(100% - 56rem + var(--bs-alert-padding-x))); }
.admin-layout .admin-content :is(p, .form-text, .alert, li:not(.list-group-item)) { text-wrap: pretty; }
.admin-layout .admin-content dl.row { max-width: 70.5rem; }
/* An analytics card is narrower than that already, except where two share a wide row. */
.admin-layout .admin-content .an-card p { max-width: none; }
/* A label column that is a fixed share of the row puts a one-word label a long way from its value on a wide
   screen. Capped just above the widest it was before, so nothing at that width or narrower changes, and the
   value takes the rest. */
@media (min-width: 576px) {
  .admin-layout dl.row > dt.col-sm-3 { width: min(25%, 14.5rem); }
  .admin-layout dl.row > dd.col-sm-9 { width: calc(100% - min(25%, 14.5rem)); }
  .admin-layout dl.row > dt.col-sm-4 { width: min(33.333333%, 18.5rem); }
  .admin-layout dl.row > dd.col-sm-8 { width: calc(100% - min(33.333333%, 18.5rem)); }
  .admin-layout dl.row > dt.col-sm-5 { width: min(41.666667%, 23rem); }
  .admin-layout dl.row > dd.col-sm-7 { width: calc(100% - min(41.666667%, 23rem)); }
}
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 1rem; }
/* Seven cards, narrow enough to share one row on a laptop rather than leaving one on a row of its own. */
@media (min-width: 768px) { .admin-layout .stat-grid { grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); } }
.stat-card {
  display: flex; flex-direction: column; gap: 0.15rem;
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1.1rem 1.25rem; background: var(--bs-body-bg);
  color: var(--bs-body-color); text-decoration: none;
}
a.stat-card:hover { border-color: var(--ub-accent); background: var(--bs-tertiary-bg); }
.stat-value { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 1.9rem; font-weight: 700; line-height: 1.1; }
.stat-label { font-size: 0.85rem; color: var(--bs-secondary-color); }
.admin-table { --bs-table-color: var(--bs-body-color); --bs-table-bg: transparent; --bs-table-border-color: var(--bs-border-color); }
.admin-table thead th { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 0.8rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bs-secondary-color); }
.admin-table .badge + .badge { margin-left: 0.25rem; }
/* Scheduled jobs, one table per area. The three short columns get fixed widths, so they fit on one line and
   line up from one area's table to the next; the description takes whatever is left. */
.jobs-table > thead > tr > th:nth-child(2) { width: 11rem; }
.jobs-table > thead > tr > th:nth-child(3) { width: 10rem; }
.jobs-table > thead > tr > th:nth-child(4) { width: 7rem; }
.badge-admin { color: #fff; background: var(--ub-accent); }
.admin-detail dt { font-weight: 600; color: var(--bs-secondary-color); }
.admin-detail dd { margin-bottom: 0.6rem; }
.message-body {
  white-space: pre-wrap; border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1.25rem; background: var(--bs-tertiary-bg);
}
/*
   A message body or header block shown as source rather than rendered - see the note in
   AdminMail/Details.cshtml. Wraps rather than scrolls sideways, because a header line and a line of
   HTML are both long, and a horizontal scrollbar per block would make the page unreadable.
*/
.message-source {
  white-space: pre-wrap; overflow-wrap: anywhere;
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1rem; background: var(--bs-tertiary-bg);
  font-size: 0.8125rem; max-height: 32rem; overflow-y: auto; margin-bottom: 0;
}
.text-truncate-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pagination { --bs-pagination-bg: var(--bs-body-bg); --bs-pagination-color: var(--bs-body-color); --bs-pagination-border-color: var(--bs-border-color); --bs-pagination-hover-bg: var(--bs-tertiary-bg); --bs-pagination-hover-color: var(--bs-body-color); --bs-pagination-disabled-bg: var(--bs-body-bg); --bs-pagination-disabled-border-color: var(--bs-border-color); }

/* Admin > General configuration */
.config-section {
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1.5rem; margin: 1.5rem 0;
  background: var(--bs-body-bg);
}
.config-section > h2 { margin-bottom: 0.5rem; }
.config-heading { margin: 1.75rem 0 0.75rem; color: var(--bs-secondary-color); letter-spacing: 0.06em; text-transform: uppercase; font-size: 0.78rem; }
.config-switch { padding-left: 2.9rem; margin-bottom: 0.5rem; }
.config-switch .form-check-input { width: 2.25rem; height: 1.25rem; margin-left: -2.9rem; }
.config-switch .form-check-input:checked { background-color: var(--ub-accent); border-color: var(--ub-accent); }
.config-switch .form-check-label { font-weight: 600; }
.form-text { color: var(--bs-secondary-color); font-size: 0.85rem; }
.input-group .form-control:focus { z-index: 3; }

/* Authenticator enrolment QR code. Always on its own white tile, never the page's
   colours: a reader hunts for dark-on-light finder patterns, and while most cope
   with an inverted code it is not worth failing on somebody's phone.

   The width is a scanning figure rather than a layout one. An enrolment URI comes
   out around 57 modules across including its quiet zone, so 16rem leaves about
   four and a half pixels a module - enough for a phone held in front of a plain
   1x laptop screen, which is the hardest case this has to work on. Narrower and
   it starts depending on the camera. */
.qr-code { width: 16rem; max-width: 100%; border-radius: 0.5rem; overflow: hidden; background: #fff; }
.qr-code svg { display: block; width: 100%; height: auto; }

/* Configuration hub tiles */
.tile-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 40rem) { .tile-grid { grid-template-columns: repeat(2, 1fr); } }
/* Two columns across a full-width admin page make every tile mostly empty space, with its chevron a long way
   from its title. From 1400px the hubs take as many columns of at least 26rem as fit. */
@media (min-width: 1400px) { .admin-layout .tile-grid { grid-template-columns: repeat(auto-fill, minmax(26rem, 1fr)); } }
.config-tile {
  display: flex; align-items: flex-start; gap: 1rem;
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1.25rem; background: var(--bs-body-bg);
  color: var(--bs-body-color); text-decoration: none;
}
.config-tile:hover { border-color: var(--ub-accent); background: var(--bs-tertiary-bg); }
.config-tile:focus-visible { outline: none; box-shadow: 0 0 0 0.25rem rgba(var(--ub-accent-rgb), 0.35); }
.config-tile-icon { color: var(--ub-accent); flex: none; line-height: 1; }
.config-tile-body { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; flex: 1; }
.config-tile-title { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; font-size: 1.05rem; }
.config-tile-desc { color: var(--bs-secondary-color); font-size: 0.9rem; }
.config-tile-status { font-size: 0.82rem; color: var(--bs-secondary-color); margin-top: 0.3rem; }
.config-tile-status.is-active { color: var(--ub-accent); font-weight: 600; }
.config-tile-chevron { flex: none; color: var(--bs-secondary-color); align-self: center; }

/* Second-level nav under a settings section */
.settings-subnav { display: flex; flex-direction: column; gap: 0.15rem; margin: 0.15rem 0 0.15rem 0.9rem; padding-left: 0.6rem; border-left: 2px solid var(--bs-border-color); }
.settings-subnav a { padding: 0.4rem 0.75rem; border-radius: 0.5rem; color: var(--bs-secondary-color); text-decoration: none; font-size: 0.92rem; }
.settings-subnav a:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.settings-subnav a.active { color: var(--ub-accent); font-weight: 600; }
.input-group-text { background: var(--bs-tertiary-bg); border-color: var(--bs-border-color); color: var(--bs-secondary-color); }
textarea.form-control { min-height: 6rem; }

/* Pending contact messages: nav badge, list emphasis, dashboard tile */
.settings-nav a { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem; padding: 0 0.45rem;
  border-radius: 999px; background: var(--ub-accent); color: #fff;
  font-size: 0.75rem; font-weight: 700; line-height: 1; flex: none;
}
.pending-dot {
  display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--ub-accent); margin-right: 0.45rem; vertical-align: 0.08em;
}
.list-group-item.is-pending { border-left: 3px solid var(--ub-accent); }
.list-group-item.is-pending .text-truncate-2 { color: var(--bs-body-color); }
.stat-card-attention { border-color: var(--ub-accent); }
.stat-card-attention .stat-value { color: var(--ub-accent); }

/* Not-found page: an unplugged cable, and the plain header every other status code gets */
.nf-page { max-width: 46rem; padding: 2.5rem 0 1rem; }
.nf-centered { text-align: center; margin: 0 auto; padding-top: 2rem; }
.nf-cable { width: min(380px, 85%); height: auto; margin-bottom: 1.25rem; }
.nf-path code { color: inherit; }
.nf-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.75rem; }
.nf-links {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem;
  padding-top: 1.25rem; margin-top: 1.75rem; border-top: 1px solid var(--bs-border-color);
}
.nf-links a { font-weight: 600; }
.nf-centered .nf-actions, .nf-centered .nf-links { justify-content: center; }

/* Invoice builder: column widths for the line-item table. Classes rather than style attributes,
   so the Content-Security-Policy can keep tightening on inline styles. */
.col-description { width: 60%; }
.col-qty { max-width: 6rem; }
.col-price { max-width: 10rem; }

/* Support tickets: the conversation thread and the attachment chips */
.ticket-thread { display: flex; flex-direction: column; gap: 1rem; margin: 1.5rem 0; }

.ticket-message {
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  padding: 1rem 1.25rem;
  background: var(--bs-body-bg);
  max-width: 46rem;
}
/* The requester sits left and support sits right, so a long thread reads at a glance. */
.ticket-message-requester { align-self: flex-start; }
.ticket-message-agent { align-self: flex-end; background: var(--bs-tertiary-bg); }

.ticket-message-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
}
.ticket-message-head time { color: var(--bs-secondary-color); font-size: 0.82rem; margin-left: auto; }

/* Preserves the line breaks somebody typed without letting a pasted log stretch the page. */
.ticket-message-body { white-space: pre-wrap; overflow-wrap: anywhere; }

/* A status change, not something anybody said, so it reads as a quiet aside. */
.ticket-event {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem;
  align-self: center;
  color: var(--bs-secondary-color); font-size: 0.85rem;
}
.ticket-event-text::before { content: "\2014\00a0"; }
.ticket-event time { font-size: 0.8rem; }

.ticket-reply { max-width: 46rem; margin-top: 2rem; }

.attachment-picker { margin: 0.5rem 0; }
.attachment-picker[aria-busy="true"] { opacity: 0.6; }

.attachment-list {
  list-style: none; padding: 0;
  margin: 0.75rem 0 0;
  display: flex; flex-wrap: wrap; gap: 0.5rem;
}
.attachment-chip {
  display: inline-flex; align-items: center; gap: 0.5rem;
  border: 1px solid var(--bs-border-color); border-radius: 2rem;
  padding: 0.3rem 0.75rem;
  background: var(--bs-tertiary-bg);
  font-size: 0.85rem;
  max-width: 100%;
}
.attachment-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 18rem; }
.attachment-size { font-size: 0.78rem; flex-shrink: 0; }
.attachment-chip .btn-close { font-size: 0.6rem; flex-shrink: 0; }

/* Home page pictures (Views/Home/_HeroProducts and _LinkAnatomy): the products drawn in markup.
   Everything inside a .shot is sized in em, and the em comes from the frame's width, so the
   drawing scales as one piece like an image would instead of reflowing like a page. */
.shot-frame { container-type: inline-size; }
.shot {
  --shot-ground: #ede6e0; --shot-dot: rgba(46, 29, 20, 0.07); --shot-shadow: rgba(46, 29, 20, 0.16);
  position: relative; aspect-ratio: 3 / 2; overflow: hidden;
  font-size: 2.2cqi; line-height: 1.4; color: var(--bs-body-color);
  border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  background-color: var(--shot-ground);
  background-image: radial-gradient(var(--shot-dot) 1px, transparent 1.2px);
  background-size: 1.5em 1.5em;
}
[data-bs-theme="dark"] .shot {
  --shot-ground: #231d19; --shot-dot: rgba(243, 237, 232, 0.06); --shot-shadow: rgba(0, 0, 0, 0.5);
}
.shot-icon { width: 1em; height: 1em; flex: none; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.shot-window, .shot-card {
  position: absolute; overflow: hidden; background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color); border-radius: 0.8em;
  box-shadow: 0 1.4em 3em -1.2em var(--shot-shadow);
}
.shot-bar { display: flex; padding: 0.5em 0.75em; background: var(--bs-tertiary-bg); border-bottom: 1px solid var(--bs-border-color); }
.shot-url {
  flex: 1; display: flex; align-items: center; gap: 0.45em; min-width: 0; overflow: hidden; white-space: nowrap;
  padding: 0.15em 0.75em; border: 1px solid var(--bs-border-color); border-radius: 99px;
  background: var(--bs-body-bg); color: var(--bs-secondary-color);
  font-family: var(--bs-font-monospace); font-size: 0.74em;
}
.shot-pane { padding: 1em 1.2em 1.2em; }
.shot-title, .shot-card-title, .shot-anatomy-title { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; letter-spacing: -0.01em; line-height: 1.2; }
.shot-title { font-size: 1.35em; }
.shot-pill { display: inline-block; padding: 0.12em 0.6em; border-radius: 99px; font-size: 0.7em; font-weight: 600; white-space: nowrap; }
.shot-pill-live { color: var(--bs-success-text-emphasis); background: var(--bs-success-bg-subtle); }
.shot-pill-expired { color: var(--bs-warning-text-emphasis); background: var(--bs-warning-bg-subtle); }
.shot-pill-accent { color: var(--ub-accent); border: 1px solid var(--ub-accent); }

/* File Drop's transfer list, with the Secret Drop card over its lower right corner */
.shot-products .shot-window { left: 5%; top: 7%; width: 74%; }
.shot-products .shot-card { right: 4.5%; bottom: 7%; width: 44%; padding: 0.95em 1.05em; border: 1.5px solid var(--ub-accent); }
.shot-row {
  display: grid; grid-template-columns: 1fr 4.2em 5.6em 4.8em; gap: 0.6em; align-items: center;
  padding: 0.42em 0; border-top: 1px solid var(--bs-border-color);
  font-size: 0.8em; font-variant-numeric: tabular-nums;
}
/* The head row keeps the body rows' font size, so their em-based columns line up; only the
   labels inside it shrink. */
.shot-row-head { margin-top: 0.9em; border-top: 0; padding-bottom: 0.2em; }
.shot-row-head > span { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 0.75em; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bs-secondary-color); }
.shot-row .shot-pill { font-size: 0.85em; }
.shot-what { min-width: 0; }
.shot-what b { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shot-what span { font-size: 0.88em; color: var(--bs-secondary-color); }
.shot-card-title { font-size: 1.1em; margin: 0.35em 0 0.55em; }
.shot-link { display: flex; gap: 0.6em; padding: 0.5em 0.6em; border-radius: 0.4em; background: var(--bs-tertiary-bg); font-family: var(--bs-font-monospace); font-size: 0.78em; white-space: nowrap; }
.shot-link-text { display: flex; flex: 1; min-width: 0; }
.shot-link-path { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.shot-key { flex: none; color: var(--ub-accent); font-weight: 500; }
.shot-copy { font-family: "Source Sans 3", "Segoe UI", system-ui, sans-serif; font-weight: 600; }
.shot-facts { margin: 0.6em 0 0; }
.shot-facts div { display: flex; justify-content: space-between; gap: 1em; padding: 0.38em 0; border-top: 1px solid var(--bs-border-color); font-size: 0.78em; }
.shot-facts dt { font-weight: 400; color: var(--bs-secondary-color); }
.shot-facts dd { margin: 0; font-weight: 600; text-align: right; }

/* The link split in two, with the browser-to-server trip underneath */
.shot-anatomy-inner { position: absolute; inset: 0; padding: 7% 7% 7.5%; display: flex; flex-direction: column; justify-content: space-between; }
.shot-eyebrow { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 0.7em; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bs-secondary-color); }
.shot-anatomy-title { font-size: 1.45em; margin-top: 0.35em; }
.shot-parts { display: flex; align-items: flex-start; font-family: var(--bs-font-monospace); font-size: 1.7em; line-height: 1.2; }
.shot-part { display: flex; flex-direction: column; }
.shot-part-text { white-space: nowrap; }
.shot-part-key .shot-part-text { color: var(--ub-accent); font-weight: 500; }
.shot-brace { height: 0.38em; margin: 0.3em 0.12em 0; border: 2px solid var(--bs-secondary-color); border-top: 0; border-radius: 0 0 0.18em 0.18em; }
.shot-part-key .shot-brace { border-color: var(--ub-accent); }
.shot-part-caption { margin-top: 0.9em; padding-right: 1em; font-family: "Source Sans 3", "Segoe UI", system-ui, sans-serif; font-size: 0.45em; line-height: 1.3; color: var(--bs-secondary-color); }
.shot-part-caption b { display: block; font-weight: 600; color: var(--bs-body-color); }
.shot-flow { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 0.9em; }
.shot-node { padding: 0.55em 0.8em; border: 1px solid var(--bs-border-color); border-radius: 0.6em; background: var(--bs-body-bg); font-size: 0.74em; color: var(--bs-secondary-color); }
.shot-node b { display: block; font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 1.15em; font-weight: 600; color: var(--bs-body-color); }
.shot-wire { position: relative; height: 2px; background-image: linear-gradient(90deg, var(--ub-accent) 55%, transparent 0); background-size: 0.7em 2px; }
.shot-wire::after { content: ""; position: absolute; right: -0.1em; top: 50%; width: 0.55em; height: 0.55em; border-top: 2px solid var(--ub-accent); border-right: 2px solid var(--ub-accent); transform: translateY(-50%) rotate(45deg); }
.shot-wire span { position: absolute; left: 50%; bottom: 0.45em; transform: translateX(-50%); font-family: var(--bs-font-monospace); font-size: 0.7em; color: var(--bs-secondary-color); white-space: nowrap; }

/* Development page: the steps of a project as a timeline, beside a call to action that stays in view */
.eyebrow {
  font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 0.75rem; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--bs-secondary-color); margin-bottom: 0.4rem;
}
.dot-list { list-style: none; padding: 0; margin-bottom: 0; display: flex; flex-wrap: wrap; row-gap: 0.25rem; font-weight: 600; }
.dot-list li:not(:last-child)::after { content: "\00b7"; margin: 0 0.6rem; color: var(--ub-accent); font-weight: 700; }
.timeline { list-style: none; padding: 0; margin: 1.75rem 0 0; }
.timeline > li { position: relative; padding: 0 0 2.25rem 3.25rem; }
.timeline > li::before {
  content: ""; position: absolute; left: calc(1rem - 1px); top: 2.25rem; bottom: 0.25rem;
  width: 2px; background: var(--bs-border-color);
}
.timeline > li:last-child::before { display: none; }
.timeline-marker {
  position: absolute; left: 0; top: 0;
  display: flex; align-items: center; justify-content: center; width: 2rem; height: 2rem;
  border: 2px solid var(--ub-accent); border-radius: 50%; background: var(--bs-body-bg);
  font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 700; font-size: 0.9rem; color: var(--ub-accent);
}
.timeline .eyebrow { padding-top: 0.45rem; margin-bottom: 0.2rem; }
.timeline h3 { font-size: 1.2rem; margin-bottom: 0.4rem; }
.timeline p { margin-bottom: 0; }
.timeline .timeline-gets {
  margin-top: 0.75rem; padding: 0.6rem 0.9rem; border-radius: 0.5rem;
  background: var(--bs-tertiary-bg); font-size: 0.95rem;
}
.timeline-gets b { color: var(--ub-accent); margin-right: 0.25rem; }
.tech-chips { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tech-chips li { padding: 0.3rem 0.85rem; border: 1px solid var(--bs-border-color); border-radius: 999px; font-weight: 600; font-size: 0.92rem; }
@media (min-width: 992px) { .dev-aside { position: sticky; top: 6.5rem; } }
.dev-aside-links { margin-top: 1.5rem; }
.dev-aside-links a {
  display: block; margin-top: 0.5rem; padding: 0.8rem 1rem;
  border: 1px solid var(--bs-border-color); border-radius: 0.6rem;
  color: var(--bs-body-color); text-decoration: none;
}
.dev-aside-links a:hover { border-color: var(--ub-accent); background: var(--bs-tertiary-bg); }
.dev-aside-links b { display: block; font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; }
.dev-aside-links span { font-size: 0.9rem; color: var(--bs-secondary-color); }

/* Services page: the four things we look after as tiles, and the support response time */
.svc-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; margin-bottom: 0.9rem; border-radius: 0.6rem;
  background: rgba(var(--ub-accent-rgb), 0.12); color: var(--ub-accent);
}
.svc-icon .icon { width: 1.4rem; height: 1.4rem; vertical-align: 0; }
.svc-tile .check-list li { font-size: 0.92rem; }
.svc-stat { display: flex; align-items: center; gap: 1.25rem; }
.svc-stat-value {
  font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 700;
  font-size: 4rem; line-height: 1; color: var(--ub-accent);
}
.svc-stat-label { color: var(--bs-secondary-color); font-size: 1.05rem; }
.svc-stat-label b { display: block; color: var(--bs-body-color); font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; }

/* Products page: what is free and what a subscription adds, as label and value rows */
.plan-facts { margin: 0; }
.plan-facts > div {
  display: grid; grid-template-columns: 8rem 1fr; gap: 1rem;
  padding: 0.6rem 0; border-top: 1px solid var(--bs-border-color);
}
.plan-facts dt { font-weight: 600; color: var(--bs-secondary-color); }
.plan-facts dd { margin: 0; }

/* Pricing page: each product's plans in a grid, with a rule between products */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 1.25rem; }
.pricing-product + .pricing-product { border-top: 1px solid var(--bs-border-color); }

/* Contact page: the Development page's timeline, smaller, inside the "What happens next" panel */
.contact-next .timeline { margin-top: 1.25rem; }
.contact-next .timeline > li { padding-bottom: 1.25rem; }
.contact-next .timeline > li::before { top: 2.1rem; }
.contact-next .timeline h3 { font-size: 1.02rem; margin: 0.35rem 0 0.2rem; }
.contact-next .timeline p { font-size: 0.93rem; color: var(--bs-secondary-color); }
.contact-next .timeline-marker { background: var(--bs-tertiary-bg); }

/* Analytics consent banner. Bottom left, clear of the toasts bottom right, and no wider than it needs
   to be: it asks one question and should not cover the page it is asking about. The two buttons share
   one style on purpose - declining has to be exactly as easy as agreeing. */
.consent-banner {
  position: fixed; left: 1rem; right: 1rem; bottom: 1rem; z-index: 1080; max-width: 26rem;
  padding: 1rem 1.15rem; border: 1px solid var(--bs-border-color); border-radius: 0.75rem;
  background: var(--bs-body-bg); color: var(--bs-body-color);
  box-shadow: 0 0.5rem 1.75rem rgba(0, 0, 0, 0.18);
}
.consent-title { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-weight: 600; margin: 0 0 0.3rem; }
.consent-text { font-size: 0.9rem; color: var(--bs-secondary-color); margin: 0 0 0.8rem; }
.consent-actions { display: flex; gap: 0.5rem; }
.consent-actions .btn { min-width: 6.5rem; }
.site-footer button.nav-link { background: none; border: 0; }

/* Admin > Analytics */
.an-toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem 0.75rem; align-items: center; margin: 1.25rem 0 0.75rem; }
.an-toolbar .form-select, .an-toolbar .form-control { width: auto; }
.an-live { display: inline-flex; align-items: center; gap: 0.45rem; font-size: 0.9rem; color: var(--bs-secondary-color); margin-left: auto; }
.an-live::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: #0ca30c; }
.an-live b { color: var(--bs-body-color); }
/* The card the live count opens on hover or focus. The strip above it spans the gap to the count, so the
   pointer can cross onto the card without closing it. */
.an-live { position: relative; border-radius: 0.25rem; cursor: default; }
.an-live:focus { outline: none; }
.an-live:focus-visible { outline: 2px solid rgba(var(--ub-accent-rgb), 0.5); outline-offset: 4px; }
.an-live-card {
  display: none; position: absolute; top: calc(100% + 0.5rem); right: 0; z-index: 20;
  width: max-content; min-width: 15rem; max-width: min(22rem, calc(100vw - 2rem));
  padding: 0.7rem 0.75rem 0.6rem; border: 1px solid var(--bs-border-color); border-radius: 0.5rem;
  background: var(--bs-body-bg); box-shadow: 0 0.35rem 1.25rem rgba(0, 0, 0, 0.14);
  color: var(--bs-body-color); font-size: 0.85rem;
}
.an-live-card::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 0.6rem; }
.an-live:hover .an-live-card, .an-live:focus-within .an-live-card { display: block; }
.an-live[data-an-dismissed] .an-live-card { display: none; }
.an-live-head { margin: 0 0 0.5rem; font-weight: 600; }
.an-live-card .an-rows + .an-panel-title { margin-top: 0.65rem; }
.an-live-card .an-row { font-size: 0.85rem; padding: 0.22rem 0.45rem; }
.an-live-note { margin: 0.55rem 0 0; font-size: 0.78rem; color: var(--bs-secondary-color); }
.an-zone { margin: -0.25rem 0 0.75rem; font-size: 0.85rem; color: var(--bs-secondary-color); }
.an-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0 0 0.75rem; font-size: 0.85rem; }
.an-chip {
  display: inline-flex; align-items: center; gap: 0.45rem; padding: 0.2rem 0.65rem;
  border-radius: 999px; background: var(--bs-tertiary-bg); color: var(--bs-body-color); text-decoration: none;
}
.an-chip:hover { color: var(--bs-body-color); box-shadow: inset 0 0 0 1px var(--bs-border-color); }
.an-chip-x { color: var(--bs-secondary-color); font-size: 1rem; line-height: 1; }

.an-kpis {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  border: 1px solid var(--bs-border-color); border-bottom: 0; border-radius: 0.75rem 0.75rem 0 0; overflow: hidden;
}
.an-kpi {
  display: flex; flex-direction: column; gap: 0.1rem; padding: 0.85rem 1.1rem 0.75rem;
  color: var(--bs-body-color); text-decoration: none; border-bottom: 3px solid transparent;
}
.an-kpi:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.an-kpi.active { border-bottom-color: var(--ub-accent); }
.an-kpi-label { font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bs-secondary-color); }
.an-kpi-value { font-family: "Sora", "Segoe UI", system-ui, sans-serif; font-size: 1.55rem; font-weight: 700; line-height: 1.2; }
.an-kpi-delta { font-size: 0.8rem; color: var(--bs-secondary-color); }
.an-kpi-delta.is-good { color: #006300; }
.an-kpi-delta.is-bad { color: #b42828; }
[data-bs-theme="dark"] .an-kpi-delta.is-good { color: #3fbf3f; }
[data-bs-theme="dark"] .an-kpi-delta.is-bad { color: #e66767; }

.an-chart-card {
  --an-gridline: #e9e5df; --an-previous: #a39c93;
  position: relative; border: 1px solid var(--bs-border-color); border-radius: 0 0 0.75rem 0.75rem;
  padding: 0.9rem 1.1rem 0.6rem; background: var(--bs-body-bg);
}
[data-bs-theme="dark"] .an-chart-card { --an-gridline: #312c28; --an-previous: #857e76; }
.an-legend { display: flex; flex-wrap: wrap; gap: 0.35rem 1.25rem; font-size: 0.85rem; color: var(--bs-secondary-color); margin-bottom: 0.35rem; }
.an-key { display: inline-block; width: 1rem; height: 2px; border-radius: 1px; vertical-align: middle; margin-right: 0.4rem; background: var(--ub-accent); }
.an-key.is-previous { background: var(--an-previous); }
.an-chart { display: block; width: 100%; height: auto; overflow: visible; }
.an-chart:focus { outline: none; }
.an-chart:focus-visible { outline: 2px solid rgba(var(--ub-accent-rgb), 0.5); outline-offset: 4px; border-radius: 0.25rem; }
.an-chart .an-gridlines line { stroke: var(--an-gridline); stroke-width: 1; shape-rendering: crispEdges; vector-effect: non-scaling-stroke; }
.an-chart .an-baseline { stroke: var(--bs-border-color); stroke-width: 1; shape-rendering: crispEdges; vector-effect: non-scaling-stroke; }
.an-chart text { fill: var(--bs-secondary-color); font-size: 11px; font-variant-numeric: tabular-nums; }
.an-chart .an-area { fill: var(--ub-accent); fill-opacity: 0.1; }
.an-chart .an-line, .an-chart .an-previous { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.an-chart .an-line { stroke: var(--ub-accent); }
.an-chart .an-previous { stroke: var(--an-previous); }
.an-chart .an-dot { fill: var(--ub-accent); stroke: var(--bs-body-bg); stroke-width: 2; }
.an-chart .an-crosshair { stroke: var(--bs-secondary-color); stroke-width: 1; vector-effect: non-scaling-stroke; }
.an-tooltip {
  position: absolute; top: 0; left: 0; z-index: 5; pointer-events: none; min-width: 9rem;
  padding: 0.5rem 0.7rem; border: 1px solid var(--bs-border-color); border-radius: 0.5rem;
  background: var(--bs-body-bg); box-shadow: 0 0.35rem 1.25rem rgba(0, 0, 0, 0.14); font-size: 0.82rem;
}
.an-tooltip-title { color: var(--bs-secondary-color); margin-bottom: 0.2rem; white-space: nowrap; }
.an-tooltip-row { display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; }
.an-tooltip-row b { font-variant-numeric: tabular-nums; }
.an-tooltip-row span { color: var(--bs-secondary-color); }
.an-legend .an-zoom { display: inline-flex; align-items: center; gap: 0.3rem; margin-left: auto; }
.an-zoom-status { margin-right: 0.35rem; }
.an-zoom-button {
  min-width: 1.75rem; height: 1.6rem; padding: 0 0.45rem; border: 1px solid var(--bs-border-color); border-radius: 0.375rem;
  background: transparent; color: var(--bs-body-color); font-size: 0.8rem; line-height: 1;
}
.an-zoom-button:hover:not(:disabled) { border-color: var(--ub-accent); color: var(--ub-accent); }
.an-zoom-button:disabled { opacity: 0.45; }
.an-chart[data-an-zoomable] { cursor: crosshair; touch-action: pan-y; user-select: none; }
.an-chart .an-selection { fill: var(--ub-accent); fill-opacity: 0.12; stroke: var(--ub-accent); stroke-opacity: 0.5; stroke-width: 1; vector-effect: non-scaling-stroke; }
.an-table-toggle { font-size: 0.85rem; margin-top: 0.4rem; }
.an-table-toggle summary { color: var(--bs-secondary-color); cursor: pointer; }
.an-table-toggle table { font-size: 0.85rem; font-variant-numeric: tabular-nums; }

.an-cards { display: grid; grid-template-columns: 1fr; gap: 1.25rem; margin-top: 1.5rem; }
@media (min-width: 62rem) { .an-cards { grid-template-columns: 1fr 1fr; } }
/* Across a full-width admin page two columns make each card half the screen, with every figure a long way
   from its label. From 1400px the cards take up to three columns of at least 28rem each. A grid with fewer
   cards than columns - the two speed tables - shares the row between them rather than leaving a gap. */
@media (min-width: 1400px) { .admin-layout .an-cards { grid-template-columns: repeat(auto-fit, minmax(max(28rem, calc((100% - 2.5rem) / 3)), 1fr)); } }
.an-card { border: 1px solid var(--bs-border-color); border-radius: 0.75rem; padding: 0.9rem 1.1rem 1rem; min-width: 0; background: var(--bs-body-bg); }
.an-card-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 0.25rem 1rem; margin-bottom: 0.5rem; }
.an-card-head h2 { font-size: 1rem; margin: 0; }
.an-tabs { display: flex; flex-wrap: wrap; gap: 0.15rem; }
.an-tab { border: 0; background: none; padding: 0.15rem 0.5rem; border-radius: 0.4rem; font-size: 0.82rem; color: var(--bs-secondary-color); }
.an-tab:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.an-tab[aria-selected="true"] { color: var(--ub-accent); font-weight: 600; }
.an-panel + .an-panel { margin-top: 1rem; }
.an-panel-title { font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bs-secondary-color); margin: 0 0 0.35rem; }
.an-card[data-an-ready] .an-panel-title { display: none; }
.an-columns { display: flex; justify-content: space-between; font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bs-secondary-color); padding: 0 0.5rem 0.25rem; }
.an-rows { list-style: none; margin: 0; padding: 0; }
.an-row { position: relative; z-index: 0; display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.28rem 0.5rem; margin-bottom: 2px; font-size: 0.9rem; }
.an-row::before { content: ""; position: absolute; inset: 0; right: auto; width: var(--share, 0%); background: rgba(var(--ub-accent-rgb), 0.14); border-radius: 0 4px 4px 0; z-index: -1; }
.an-row-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--bs-body-color); text-decoration: none; }
a.an-row-label:hover { text-decoration: underline; color: var(--bs-body-color); }
.an-row-value { flex: none; font-variant-numeric: tabular-nums; }
.an-row-value small { color: var(--bs-secondary-color); margin-left: 0.4rem; }
.an-empty { color: var(--bs-secondary-color); font-size: 0.9rem; padding: 0.35rem 0.5rem; margin: 0; }
.an-snippet { font-family: var(--bs-font-monospace); font-size: 0.82rem; white-space: pre; overflow-x: auto; }

/* Admin > Analytics: speed. The rating dots use the fixed status colours and always sit beside their
   word, so a rating never rests on telling green from red. */
.an-speed { margin-top: 2rem; }
.an-section-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 1rem; margin-bottom: 0.75rem; }
.an-speed .an-kpis { border-bottom: 1px solid var(--bs-border-color); border-radius: 0.75rem; }
.an-speed .an-cards { margin-top: 1.25rem; }
.an-speed-tiles { grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); }
.an-speed-tiles .an-kpi-value { font-size: 1.35rem; }
/* Two lines for every label, so a long one does not push its figure out of line with the rest. */
.an-speed-tiles .an-kpi-label { min-height: 3em; }
.an-toolbar #an-site { min-width: 9rem; }
.an-kpi-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem 0.6rem; min-height: 1.2rem; }
.an-rating { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.8rem; color: var(--bs-body-color); white-space: nowrap; }
.an-rating::before { content: ""; flex: none; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--bs-secondary-color); }
.an-rating.is-good::before { background: #0ca30c; }
.an-rating.is-needs-work::before { background: #fab219; }
.an-rating.is-poor::before { background: #d03b3b; }
.an-rating-compact { font-size: inherit; }
.an-speed-table th, .an-speed-table td { white-space: nowrap; font-variant-numeric: tabular-nums; }
.an-speed-table td.an-speed-path { max-width: 16rem; overflow: hidden; text-overflow: ellipsis; }
.an-speed-table a { color: var(--bs-body-color); text-decoration: none; }
.an-speed-table a:hover { text-decoration: underline; }
