/* Bernard GIS: palette, typography and page furniture over Bootstrap 5.3.
   Bootstrap plus this one file, no build step.

   Every colour is a custom property, so dark is a second palette rather than a
   second stylesheet. A script in the head sets data-bs-theme on <html> from the
   system preference; using the attribute rather than a bare media query is what
   lets Bootstrap theme its own components too. Bootstrap's stock red stays in
   place for destructive actions only; it doesn't double as the accent. */

:root {
  --bs-font-sans-serif: "Source Sans 3", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --bs-font-monospace: Consolas, "Cascadia Mono", ui-monospace, Menlo, monospace;

  --bernard-accent: #405a8b;            /* primary, focus rings, active marks */
  --bernard-accent-hover: #2e4775;
  --bernard-accent-tint: #eef3fb;       /* hovered row, info alert */
  --bernard-accent-edge: #c9d6ec;

  --bernard-ink: #16181a;
  --bernard-body: #35373a;
  --bernard-gray: #696b6f;
  /* Faint clears 3:1 but not 4.5:1, so it is for separators, dots and disabled
     controls. Anything meant to be read uses gray. */
  --bernard-faint: #888a8d;

  --bernard-page: #ffffff;
  --bernard-surface: #ffffff;           /* raised: navbar, rail, sticky bars */
  --bernard-inset: #fcfcfb;             /* recessed: hatch, drop target */
  --bernard-panel: #f5f4f2;
  --bernard-line: #e2e1de;
  --bernard-line-soft: #eeedea;
  --bernard-control-line: #d4d3d0;      /* field and button edges */
  --bernard-control-line-hover: #c3c2be;
  --bernard-shadow: rgba(20, 22, 26, 0.08);

  --bernard-ok: #487552;
  --bernard-ok-soft: #eaf5ec;
  --bernard-warn: #7d5a20;
  --bernard-warn-soft: #fbf2de;
  --bernard-warn-edge: #e3cda9;
  --bernard-danger-edge: #e8c9c9;

  --bs-body-font-size: 0.9375rem;
  --bs-link-color: var(--bernard-ink);
  --bs-link-hover-color: #000;
  --bs-border-color: var(--bernard-line);
  --bs-border-radius: 3px;
  --bs-border-radius-sm: 2px;
  --bs-border-radius-lg: 4px;
  --bs-focus-ring-color: rgba(64, 90, 139, 0.2);
}

/* The accent lightens rather than darkens: at its light-mode lightness it is
   illegible on a dark ground, so it moves up in lightness at the same hue.
   --bs-link-color and --bs-border-color are deliberately not repeated here;
   they point at tokens this block has already moved. */
[data-bs-theme="dark"] {
  --bernard-accent: #8eabe1;
  --bernard-accent-hover: #afc8f6;
  --bernard-accent-tint: #1e2735;
  --bernard-accent-edge: #324260;

  --bernard-ink: #ecedef;
  --bernard-body: #c4c6c8;
  --bernard-gray: #909296;
  --bernard-faint: #707275;

  --bernard-page: #121314;
  --bernard-surface: #18191b;
  --bernard-inset: #18191b;
  --bernard-panel: #212325;
  --bernard-line: #303235;
  --bernard-line-soft: #242528;
  --bernard-control-line: #303235;
  --bernard-control-line-hover: #67696c;
  --bernard-shadow: rgba(0, 0, 0, 0.4);

  --bernard-ok: #8fbf98;
  --bernard-ok-soft: #1c2e20;
  --bernard-warn: #d6b57f;
  --bernard-warn-soft: #362913;
  --bernard-warn-edge: #574423;
  --bernard-danger-edge: #4a2b2d;

  --bs-link-hover-color: #fff;
  --bs-body-bg: var(--bernard-page);
  --bs-body-color: var(--bernard-body);
  --bs-emphasis-color: var(--bernard-ink);
  --bs-secondary-bg: var(--bernard-panel);
  --bs-tertiary-bg: var(--bernard-panel);
  --bs-focus-ring-color: rgba(142, 171, 225, 0.25);
}

/* ── Base ─────────────────────────────────────────────────────────── */
body {
  font-family: var(--bs-font-sans-serif);
  color: var(--bernard-body);
  background: var(--bernard-page);
  /* Columns of numbers align without needing a monospace face. */
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--bernard-ink);
  letter-spacing: -0.012em;
  font-weight: 600;
}

/* Machine strings only: coordinates, hashes, geodiff output, code. Windows
   resolves this stack to Consolas, the one monospace face reliably present
   and reliably legible there. */
code, kbd, samp, pre, .mono, .font-monospace {
  font-family: var(--bs-font-monospace);
  font-size: 0.88em;
  font-variant-ligatures: none;
}

/* ── Plain prose links: subtle, not blue, not red ──────────────────
   The negations sit inside :where() so this stays a plain type selector.
   Spelled out as a chain of :not() it outranks every class rule below and
   quietly wins arguments it should lose. */
a:not(:where(.btn, .dropdown-item, .nav-link, .alert-link, .navbar-brand, .page-link)) {
  color: var(--bernard-ink);
  text-decoration: none;
}
a:not(:where(.btn, .dropdown-item, .nav-link, .alert-link, .navbar-brand, .page-link)):hover {
  color: var(--bs-link-hover-color);
  text-decoration: underline;
}

/* Alert links pick up the accent. */
.alert-link { color: var(--bernard-accent); }
.alert-link:hover { color: var(--bernard-accent-hover); }

/* ── Buttons ──────────────────────────────────────────────────────
   Bootstrap declares these on .btn itself, so setting them on :root never
   reaches a button. The vertical padding is the value that lands .btn on the
   same height as .form-control. */
.btn {
  --bs-btn-font-weight: 500;
  --bs-btn-font-size: 0.9375rem;
  --bs-btn-padding-x: 0.85rem;
  --bs-btn-padding-y: 0.28rem;
  --bs-btn-border-radius: 3px;
}
/* A value set on .btn shadows the one .btn-sm sets for itself, so the small
   size has to restate the two that carry its height. */
.btn-sm {
  --bs-btn-font-size: 0.875rem;
  --bs-btn-padding-y: 0.15rem;
}
.btn-primary {
  --bs-btn-bg: var(--bernard-accent);
  --bs-btn-border-color: var(--bernard-accent);
  --bs-btn-hover-bg: var(--bernard-accent-hover);
  --bs-btn-hover-border-color: var(--bernard-accent-hover);
  --bs-btn-active-bg: var(--bernard-accent-hover);
  --bs-btn-active-border-color: var(--bernard-accent-hover);
  --bs-btn-disabled-bg: var(--bernard-accent);
  --bs-btn-disabled-border-color: var(--bernard-accent);
  /* Label sits on the accent, so it takes the page colour rather than white:
     the accent is dark in light mode and light in dark mode. */
  --bs-btn-color: var(--bernard-page);
  --bs-btn-hover-color: var(--bernard-page);
  --bs-btn-active-color: var(--bernard-page);
  --bs-btn-disabled-color: var(--bernard-page);
}
.btn-outline-primary {
  --bs-btn-color: var(--bernard-accent);
  --bs-btn-border-color: var(--bernard-accent-edge);
  --bs-btn-hover-bg: var(--bernard-accent);
  --bs-btn-hover-border-color: var(--bernard-accent);
  --bs-btn-hover-color: var(--bernard-page);
  --bs-btn-active-bg: var(--bernard-accent);
  --bs-btn-active-border-color: var(--bernard-accent);
  --bs-btn-active-color: var(--bernard-page);
}
.btn-outline-secondary {
  --bs-btn-color: var(--bernard-body);
  --bs-btn-border-color: var(--bernard-control-line);
  --bs-btn-hover-color: var(--bernard-ink);
  --bs-btn-hover-bg: var(--bernard-panel);
  --bs-btn-hover-border-color: var(--bernard-control-line-hover);
  --bs-btn-active-color: var(--bernard-ink);
  --bs-btn-active-bg: var(--bernard-panel);
  --bs-btn-active-border-color: var(--bernard-control-line-hover);
}
.btn-outline-secondary.active {
  --bs-btn-active-bg: var(--bernard-accent-tint);
  --bs-btn-active-border-color: var(--bernard-accent-edge);
  --bs-btn-active-color: var(--bernard-accent-hover);
}
.btn-outline-danger { --bs-btn-border-color: var(--bernard-danger-edge); }
.btn:focus-visible { box-shadow: 0 0 0 0.2rem var(--bs-focus-ring-color); }

/* Buttons pairing an icon with a label: icon pinned to the left edge, label
   centered on the button. The balancing right-hand column is what centers the
   label on the button itself rather than on the space left of the icon.
   Icon-only buttons don't take this class. */
.btn-icon {
  display: inline-grid;
  grid-template-columns: 1.25em 1fr 1.25em;
  align-items: center;
}
.btn-icon > .bi:first-child { justify-self: start; }
.btn-icon::after { content: ""; }

/* ── Forms ────────────────────────────────────────────────────────
   Controls come down from Bootstrap's 38px to 32px. At this size a filter
   field and the rows it filters belong to the same instrument. */
.form-control, .form-select {
  padding-top: 0.28rem;
  padding-bottom: 0.28rem;
  font-size: 0.9375rem;
  color: var(--bernard-ink);
  background-color: var(--bernard-surface);
  border-color: var(--bernard-control-line);
  border-radius: 3px;
}
/* Bootstrap floors the small field with a min-height derived from its own
   padding, which would hold it above .btn-sm however the padding is set. */
.form-control-sm, .form-select-sm {
  padding-top: 0.15rem;
  padding-bottom: 0.15rem;
  font-size: 0.875rem;
  min-height: 0;
}
.form-control::placeholder { color: var(--bernard-gray); }
.form-control:focus, .form-select:focus {
  border-color: var(--bernard-accent);
  box-shadow: 0 0 0 0.2rem var(--bs-focus-ring-color);
}
/* A textarea wider than about ninety characters is hard to read back, so the
   field caps itself rather than the whole page narrowing around it. */
textarea.form-control {
  max-width: 90ch;
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
}
.form-label {
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--bernard-ink);
  margin-bottom: 0.3rem;
}
.form-text { color: var(--bernard-gray); }
.form-check-input:checked {
  background-color: var(--bernard-ink);
  border-color: var(--bernard-ink);
}
.form-check-input:focus {
  border-color: var(--bernard-ink);
  box-shadow: 0 0 0 0.2rem rgba(22, 24, 26, 0.14);
}

/* Global search: the one field that reaches past the current page. A data URI
   can't read a custom property, so the magnifier is a fixed mid grey that
   clears 3:1 on both the light and the dark panel. */
.b-search-global {
  background-color: var(--bernard-panel);
  border-color: transparent;
  padding-left: 1.9rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%237e8084'%3E%3Cpath d='M11.74 10.34A6 6 0 1 0 10.34 11.74l3.46 3.46a1 1 0 0 0 1.4-1.4ZM7 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 0.55rem center;
  background-size: 0.8rem;
}
.b-search-global:focus {
  background-color: var(--bernard-surface);
  border-color: var(--bernard-accent);
}
.b-filter-count { font-size: 0.8125rem; color: var(--bernard-gray); white-space: nowrap; }

/* ── Cards are not containers ─────────────────────────────────────
   Content sits directly on the page and rules do the separating. The markup
   says .card in a hundred places, so the neutralising happens here rather than
   in a hundred templates, and a card header becomes the section-label
   register it was always standing in for. */
.card {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.card > .card-body { padding: 0; }
.card > .card-body + .card-body { padding-top: 1rem; }
/* The markup pairs .card-header with .small and .text-muted, and both of those
   utilities carry !important. */
.card-header {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--bernard-line-soft);
  padding: 0 0 0.5rem;
  margin-bottom: 0.875rem;
  font-size: 0.6875rem !important;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--bernard-gray) !important;
}
/* A card holding nothing but a flush list or a table needs no padding of its
   own; the list and the table already carry their own rules. */
.card > .list-group-flush > .list-group-item { padding-left: 0; padding-right: 0; }

/* The exceptions: things that genuinely are discrete objects rather than a
   block of the page. The action rail, the sign-in panel, a modal. */
.b-card-object,
.b-sticky-rail > .card {
  border: 1px solid var(--bernard-line);
  border-radius: 3px;
  background: var(--bernard-surface);
}
.b-card-object > .card-body,
.b-sticky-rail > .card > .card-body { padding: 0.875rem; }
.b-card-object > .card-header,
.b-sticky-rail > .card > .card-header {
  background: var(--bernard-panel);
  border-bottom: 1px solid var(--bernard-line);
  padding: 0.5rem 0.875rem;
  margin-bottom: 0;
}
.b-sticky-rail { position: sticky; top: 1rem; }
.b-sticky-rail .card-body { display: flex; flex-direction: column; gap: 0.5rem; }
.b-sticky-rail hr { margin: 0.25rem 0; border-color: var(--bernard-line-soft); }

.modal-content { border-radius: 3px; border-color: var(--bernard-line); }
.modal-header, .modal-footer { border-color: var(--bernard-line-soft); }

/* ── Tables ───────────────────────────────────────────────────────
   The table is the page, not an object on it: no wrapper, no outer border,
   full width, held together by horizontal rules. */
.table {
  --bs-table-hover-bg: var(--bernard-accent-tint);
  --bs-table-hover-color: var(--bernard-ink);
  --bs-table-border-color: var(--bernard-line-soft);
  color: var(--bernard-body);
  margin-bottom: 0;
}
.table > thead th {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--bernard-gray);
  background: transparent;
  border-bottom: 1px solid var(--bernard-line);
  padding: 0 0.5rem 0.45rem;
  white-space: nowrap;
}
.table > tbody > tr > td {
  border-bottom-color: var(--bernard-line-soft);
  padding: 0.55rem 0.5rem;
}
.table > thead th:first-child,
.table > tbody > tr > td:first-child { padding-left: 0; }
.table > thead th:last-child,
.table > tbody > tr > td:last-child { padding-right: 0; }
.table > tbody > tr:last-child > td { border-bottom-width: 1px; }

.b-row-name { color: var(--bernard-ink); font-weight: 600; text-decoration: none; }
.b-row-name:hover { text-decoration: underline; }
.b-row-secondary { color: var(--bernard-gray); font-size: 0.875rem; }
/* The type column is a label, not a string to be parsed character by
   character, so it reads as small caps rather than as code. */
.b-row-type {
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--bernard-gray);
  text-transform: uppercase;
}
.b-owner {
  color: var(--bernard-gray);
  font-size: 0.875rem;
  max-width: 15ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
  vertical-align: bottom;
}
/* Sixty identical outline buttons are furniture, so a row's buttons are set
   back until the pointer is on the row. Set back, not hidden: a control
   nothing shows is a control nobody knows is there, and on a touch screen
   there is no pointer to reveal it with. */
.table-hover .b-row-action { opacity: 0.55; transition: opacity 0.1s ease; }
.table-hover tr:hover .b-row-action,
.table-hover tr:focus-within .b-row-action { opacity: 1; }

/* ── List groups ──────────────────────────────────────────────────
   Sidebars of users, groups and projects across the access pages: the current
   item is marked by weight and a leading rule, not a fill. */
.list-group-item { color: var(--bernard-body); border-color: var(--bernard-line-soft); }
/* Inside a card the items sit ON the card: Bootstrap's own item background
   is the page colour, which reads as stripes against the card surface in
   dark mode. */
.card .list-group-item { background-color: transparent; }
.list-group-item.active {
  background-color: transparent;
  border-color: var(--bernard-line-soft);
  color: var(--bernard-ink);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--bernard-accent);
}
.list-group-item-action:hover,
.list-group-item-action:focus { background-color: var(--bernard-panel); color: var(--bernard-ink); }

/* ── Breadcrumbs ──────────────────────────────────────────────────── */
.breadcrumb {
  --bs-breadcrumb-divider: '›';
  font-size: 0.8125rem;
  margin-bottom: 0.875rem;
}
.breadcrumb-item a { color: var(--bernard-gray); text-decoration: none; }
.breadcrumb-item a:hover { color: var(--bernard-accent); text-decoration: underline; }
.breadcrumb-item.active { color: var(--bernard-gray); }
.breadcrumb-item + .breadcrumb-item::before {
  color: var(--bernard-faint);
  padding-right: 0.5rem;
  padding-left: 0.25rem;
}

/* ── Pagination: ink, not blue ────────────────────────────────────── */
.page-link { color: var(--bernard-ink); border-color: var(--bernard-line); }
.page-link:hover {
  color: var(--bs-link-hover-color);
  background-color: var(--bernard-panel);
  border-color: var(--bernard-line);
}
.page-link:focus { box-shadow: none; }
.page-item.active .page-link {
  background-color: var(--bernard-ink);
  border-color: var(--bernard-ink);
  color: var(--bernard-page);
}
.page-item.disabled .page-link { color: var(--bernard-faint); }

/* ── State chips ──────────────────────────────────────────────────── */
.badge { font-weight: 500; border-radius: 2px; letter-spacing: 0.01em; }
.badge.b-state-free {
  background-color: var(--bernard-ok-soft);
  color: var(--bernard-ok);
  border: 1px solid var(--bernard-ok);
}
.badge.b-state-locked {
  background-color: var(--bernard-warn-soft);
  color: var(--bernard-warn);
  border: 1px solid var(--bernard-warn-edge);
}
.badge.b-state-free::before,
.badge.b-state-locked::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: middle;
  background: currentColor;
}
.badge.b-state-flag {
  background-color: var(--bernard-surface);
  color: var(--bernard-gray);
  border: 1px solid var(--bernard-line);
}

/* ── Alerts and notes ─────────────────────────────────────────────── */
.alert { border-radius: 3px; padding: 0.7rem 0.9rem; }
.alert-secondary {
  --bs-alert-bg: var(--bernard-panel);
  --bs-alert-border-color: var(--bernard-line);
  --bs-alert-color: var(--bernard-body);
}
.alert-info {
  --bs-alert-bg: var(--bernard-accent-tint);
  --bs-alert-border-color: var(--bernard-accent-edge);
  --bs-alert-color: var(--bernard-accent-hover);
}
.alert-warning {
  --bs-alert-bg: var(--bernard-warn-soft);
  --bs-alert-border-color: var(--bernard-warn-edge);
  --bs-alert-color: var(--bernard-warn);
}
.b-help-note { padding-left: 1rem; border-left: 2px solid var(--bernard-line); }
.b-form-narrow { max-width: 760px; }

/* ── Hatched placeholder for map / preview slots ──────────────────── */
.b-hatch {
  border: 1px solid var(--bernard-line);
  border-radius: 3px;
  background-color: var(--bernard-inset);
  background-image: repeating-linear-gradient(45deg, var(--bernard-line-soft) 0 1px, transparent 1px 12px);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--bernard-gray);
  font-size: 0.8rem;
  min-height: 220px;
}
/* Map and thumbnail share one height so they line up side by side, and give
   back some of it where the column is the whole screen. */
.b-preview-pane { height: 380px; }
@media (max-width: 575.98px) {
  .b-preview-pane { height: 260px; }
}

/* ── Page and section heads ───────────────────────────────────────
   Every page opens with a title, its actions and a closing rule. Below that,
   a section label with a hairline running to the right edge is the only thing
   separating one block of content from the next. */
.b-page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--bernard-line);
  margin-bottom: 1.5rem;
}
.b-page-head h1 {
  font-size: 1.375rem;
  margin: 0;
  line-height: 1.2;
}
.b-page-head p {
  margin: 0.35rem 0 0;
  color: var(--bernard-gray);
  max-width: 68ch;
  text-wrap: pretty;
}
.b-page-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }

.b-section-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--bernard-gray);
}
/* Counts and qualifiers riding along with a label: subordinate by weight and
   case, not by going lighter. */
.b-section-label > span {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
.b-section-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.b-section-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--bernard-line-soft);
}
.b-section-head > a { font-size: 0.8125rem; color: var(--bernard-gray); }

/* Space between blocks does what the card gaps used to. */
.b-block + .b-block { margin-top: 2.25rem; }

/* ── Navbar ───────────────────────────────────────────────────────
   Flattened to a hairline: no shadow, and the current tab is marked by a rule
   under it rather than a fill. */
.navbar {
  background: var(--bernard-surface);
  border-bottom: 1px solid var(--bernard-line);
  padding-top: 0;
  padding-bottom: 0;
}
.navbar-brand {
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--bernard-ink);
  padding-top: 0.7rem;
  padding-bottom: 0.7rem;
  margin-right: 1.5rem;
}
.navbar-brand:hover { color: var(--bernard-ink); }
.navbar-brand .scope { color: var(--bernard-gray); font-weight: 400; }
.navbar .nav-link {
  color: var(--bernard-gray);
  padding: 0.85rem 0.75rem;
  border-bottom: 2px solid transparent;
  font-size: 0.9375rem;
}
.navbar .nav-link:hover { color: var(--bernard-ink); }
.navbar .nav-link.active {
  color: var(--bernard-ink);
  font-weight: 600;
  border-bottom-color: var(--bernard-ink);
}
/* Written to match .nav-link.active so the account menu never takes the
   active underline while its dropdown page is open. */
.navbar .nav-link.dropdown-toggle { border-bottom-color: transparent; }
.dropdown-menu {
  border-radius: 3px;
  border-color: var(--bernard-line);
  box-shadow: 0 4px 16px var(--bernard-shadow);
  font-size: 0.9375rem;
}
.dropdown-item:active {
  background-color: var(--bernard-accent);
  color: var(--bernard-page);
}

/* Checking out, editing in QGIS and checking back in is the workflow, so what
   you are holding sits beside the account menu as personal state rather than
   as a place in the app. */
.b-nav-checkouts {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.5rem;
  margin-right: 0.5rem;
  border-radius: 3px;
  color: var(--bernard-body);
  text-decoration: none;
  font-size: 0.875rem;
}
.b-nav-checkouts:hover {
  background: var(--bernard-panel);
  color: var(--bernard-ink);
  text-decoration: none;
}
.b-nav-checkouts.active {
  background: var(--bernard-panel);
  color: var(--bernard-ink);
  font-weight: 600;
}
.b-nav-checkouts > .bi { color: var(--bernard-gray); }
.b-nav-count {
  display: inline-block;
  min-width: 1.15rem;
  padding: 0 0.3rem;
  margin-left: 0.15rem;
  border-radius: 999px;
  background: var(--bernard-accent);
  color: var(--bernard-page);
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.15rem;
  text-align: center;
  vertical-align: 1px;
}

/* ── Facet list ───────────────────────────────────────────────────
   A list of links with the current one marked by weight and a rule on its
   leading edge. */
.b-facets { font-size: 0.875rem; }
.b-facets a {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.2rem 0.5rem 0.2rem 0.6rem;
  color: var(--bernard-body);
  border-left: 2px solid transparent;
  text-decoration: none;
}
.b-facets a:hover { background: var(--bernard-panel); color: var(--bernard-ink); text-decoration: none; }
.b-facets a.active {
  border-left-color: var(--bernard-accent);
  color: var(--bernard-ink);
  font-weight: 600;
}
.b-facets .count { color: var(--bernard-gray); }
.b-facet-group + .b-facet-group { margin-top: 1.5rem; }
/* Most formats hold a single file; they are grouped and set back so the
   formats that carry the catalogue read first. */
.b-facet-minor a { color: var(--bernard-gray); }

/* ── Recently updated ─────────────────────────────────────────────
   Never wraps: a wrapped item would start a new line still carrying the rule
   on its leading edge and read as an indented orphan. Below the width that
   fits them all, the strip scrolls sideways instead. */
.b-recent {
  display: flex;
  overflow-x: auto;
  border-top: 1px solid var(--bernard-line-soft);
  border-bottom: 1px solid var(--bernard-line-soft);
  scrollbar-width: thin;
}
.b-recent-item {
  flex: 1 1 0;
  min-width: 180px;
  padding: 0.6rem 0.875rem;
  border-left: 1px solid var(--bernard-line-soft);
  background: var(--bernard-surface);
  text-decoration: none;
}
.b-recent-item:first-child { border-left: 0; }
.b-recent-item:hover { background: var(--bernard-accent-tint); text-decoration: none; }
.b-recent-name {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--bernard-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.b-recent-meta {
  display: block;
  font-size: 0.75rem;
  color: var(--bernard-gray);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Results, not rows ────────────────────────────────────────────
   Each result leads with the name, carries the description underneath, and
   puts the filing details on one quiet line below that. */
.b-results { border-top: 1px solid var(--bernard-line); }
/* The checkbox and picture columns are reserved for the list rather than for
   the row, so titles stay in line when only some rows have one. A list where
   no row has either gives the space back instead of indenting every title
   past an empty column. Each track carries its own trailing space, because a
   track collapsed to zero would still be followed by a column gap. */
.b-result {
  --b-pick-track: 38px;
  --b-thumb-track: 88px;
  display: grid;
  grid-template-columns: var(--b-pick-track) var(--b-thumb-track) minmax(0, 1fr) auto;
  align-items: baseline;
  padding: 0.8rem 0.5rem 0.8rem 0;
  border-bottom: 1px solid var(--bernard-line-soft);
}
.b-results:not(:has(.b-result-pick)) .b-result { --b-pick-track: 0px; }
.b-results:not(:has(.b-result-thumb, .b-result-extent)) .b-result { --b-thumb-track: 0px; }
.b-result:hover { background: var(--bernard-accent-tint); }
.b-result-main { min-width: 0; grid-column: 3; }
.b-result-aside {
  grid-column: 4;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: 1rem;
  white-space: nowrap;
}
/* Two names for one picture slot. Where there is no picture yet the markup
   fills it with .b-hatch, so the hatch's own minimum height comes back off. */
.b-result-thumb,
.b-result-extent {
  grid-column: 2;
  width: 72px;
  height: 48px;
  min-height: 0;
  align-self: center;
  font-size: 0.625rem;
  border-radius: 2px;
  object-fit: cover;
  background-color: var(--bernard-panel);
}
/* Format sits on the title line rather than in a grey margin column: it is the
   second thing anyone needs, because it decides whether the file is usable at
   all. */
.b-result-title { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 0.5rem; }
.b-result-format {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--bernard-body);
  background: var(--bernard-panel);
  border-radius: 2px;
  padding: 0.1rem 0.4rem;
  white-space: nowrap;
}
.b-result-name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--bernard-ink);
  text-decoration: none;
}
.b-result-name:hover { text-decoration: underline; }
.b-result-version { font-weight: 400; color: var(--bernard-gray); font-size: 0.875rem; }
.b-result-desc {
  margin: 0.15rem 0 0;
  color: var(--bernard-body);
  max-width: 78ch;
  text-wrap: pretty;
}
.b-result-meta {
  margin: 0.3rem 0 0;
  font-size: 0.8125rem;
  color: var(--bernard-gray);
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.5rem;
}
.b-result-meta > span + span::before { content: "·"; margin-right: 0.5rem; color: var(--bernard-faint); }
.b-result .b-row-action { opacity: 0.55; transition: opacity 0.1s ease; }
.b-result:hover .b-row-action,
.b-result:focus-within .b-row-action { opacity: 1; }

@media (max-width: 575.98px) {
  .b-result { grid-template-columns: var(--b-pick-track) minmax(0, 1fr); row-gap: 0.25rem; }
  .b-result-thumb, .b-result-extent { display: none; }
  .b-result-main, .b-result-aside { grid-column: 2; }
  .b-result-aside { margin-left: 0; }
}

/* ── Selecting several results ────────────────────────────────────
   The catalogue hands its selection straight to the map, so the picker there
   becomes a fallback rather than the only route. */
.b-result-pick {
  grid-column: 1;
  align-self: center;
  margin: 0 0.25rem 0 0;
  opacity: 0;
  transition: opacity 0.1s ease;
}
.b-result:hover .b-result-pick,
.b-result-pick:focus-visible,
.b-result-pick:checked { opacity: 1; }
/* Once selecting has started the column stays put. */
.b-results--selectable .b-result-pick { opacity: 1; }
/* Anything revealed on hover is unreachable where there is no pointer: on a
   touch screen it would be invisible and still clickable. */
@media (hover: none) {
  .b-result-pick,
  .b-result .b-row-action,
  .table-hover .b-row-action { opacity: 1; }
}
/* The bar is sticky inside the list, so the list gives back the height it
   would otherwise float over. */
.b-results--picking { padding-bottom: 4.5rem; }

.b-select-all {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.875rem;
  color: var(--bernard-gray);
  cursor: pointer;
  white-space: nowrap;
}
.b-select-all:hover { color: var(--bernard-ink); }
.b-select-all .form-check-input { margin: 0; }

.b-selection {
  position: sticky;
  bottom: 1rem;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0 0;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--bernard-line);
  border-radius: 3px;
  background: var(--bernard-surface);
  box-shadow: 0 2px 12px var(--bernard-shadow);
}
.b-selection[hidden] { display: none; }
.b-selection-count { font-weight: 600; color: var(--bernard-ink); }

/* ── The decision band ────────────────────────────────────────────
   Everything needed to answer "is this the right dataset and can I work on it
   right now" in one band above the fold. The sections below it are for when
   the answer is yes. */
.b-decision {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--bernard-line);
  margin-bottom: 1.75rem;
}
.b-decision-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.625rem;
  margin: 0.4rem 0 0;
  color: var(--bernard-gray);
  font-size: 0.875rem;
}
.b-decision-facts > span + span::before { content: "·"; margin-right: 0.625rem; color: var(--bernard-faint); }
.b-decision-facts strong { color: var(--bernard-ink); font-weight: 600; }

/* ── Dataset page ─────────────────────────────────────────────────── */
.b-edit-title {
  border: 0;
  background: none;
  padding: 0 0 0 0.5rem;
  color: var(--bernard-gray);
  font-size: 0.75em;
  vertical-align: middle;
  line-height: 1;
}
.b-edit-title:hover { color: var(--bernard-accent); }

.b-map-caption {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  color: var(--bernard-gray);
}

/* Every photo a set holds, in a grid that scrolls rather than a row that
   runs off the side of the page with most of the survey out of reach. */
.b-photos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 0.5rem;
  max-height: 60vh;
  overflow-y: auto;
}
.b-photos img { width: 100%; height: 110px; object-fit: cover; }

/* The activity log continues the History section rather than opening its own,
   because a version and the download of that version are the same story. */
.b-activity {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--bernard-line-soft);
  font-family: var(--bs-font-monospace);
  font-size: 0.78rem;
  color: var(--bernard-gray);
  line-height: 1.7;
}

/* Classification sits behind a disclosure because it is a setting rather than
   something you read. */
.b-disclosure { margin-top: 2.25rem; border-top: 1px solid var(--bernard-line-soft); }
.b-disclosure > summary {
  cursor: pointer;
  padding: 0.75rem 0;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.b-disclosure > summary::-webkit-details-marker { display: none; }
.b-disclosure > summary::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  border-right: 1.5px solid var(--bernard-gray);
  border-bottom: 1.5px solid var(--bernard-gray);
  transform: rotate(-45deg);
  transition: transform 0.12s ease;
}
.b-disclosure[open] > summary::before { transform: rotate(45deg); }
.b-disclosure > summary:hover { color: var(--bernard-ink); }
.b-disclosure-body { padding-bottom: 1.25rem; }

/* ── Metadata lists ───────────────────────────────────────────────
   Terms in grey, values in ink, no card and no rules; the alignment does the
   work. The rail version is a narrow column, so it stacks label over value. */
dl.kv {
  display: grid;
  grid-template-columns: 150px 1fr;
  row-gap: 0.4rem;
  column-gap: 1.25rem;
  margin: 0;
  font-size: 0.9375rem;
}
dl.kv > dt { color: var(--bernard-gray); font-weight: 400; }
dl.kv > dd { margin: 0; color: var(--bernard-ink); }

.kv-rail { margin: 0; font-size: 0.8125rem; display: flex; flex-direction: column; gap: 0.5rem; }
.kv-rail > div { display: flex; flex-direction: column; gap: 0.05rem; min-width: 0; }
.kv-rail dt {
  color: var(--bernard-gray);
  font-weight: 400;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.kv-rail dd { margin: 0; color: var(--bernard-ink); overflow-wrap: anywhere; }

/* ── The map page ─────────────────────────────────────────────────
   A map tool is the map. It fills the window under the navbar rather than
   sitting as a slot below a scrolling list, and the layer picker is a panel
   beside it with its own scroll. */
/* height, not min-height: the page must be EXACTLY the viewport, or a long
   layer list grows the whole body and scrolls the map away with it instead
   of scrolling inside the panel. The mobile layout below stacks and gives
   the height back. */
.b-map-page { display: flex; flex-direction: column; height: 100dvh; }
.b-map-page > main { flex: 1 1 auto; min-height: 0; display: flex; }
.b-map-panel {
  flex: 0 0 320px;
  max-width: 320px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--bernard-line);
  background: var(--bernard-surface);
}
.b-map-panel-head {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem;
  border-bottom: 1px solid var(--bernard-line);
}
.b-map-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0.5rem 0.75rem 1rem; }
.b-map-list > div { border-bottom: 1px solid var(--bernard-line-soft); }
.b-map-list > div:last-child { border-bottom: 0; }
.b-map-list .form-check-label { font-size: 0.875rem; }
.b-map-list a { color: var(--bernard-gray); }
.b-map-canvas { flex: 1 1 auto; min-width: 0; }
/* The markup asks for .min-w-0, which Bootstrap does not ship; without it the
   flex child refuses to shrink and long dataset names push the view link out
   of the panel instead of truncating. */
.min-w-0, .b-map-list .form-check, .b-layer-picker .form-check { min-width: 0; }

/* The layers of one dataset, listed under it. Indented in the map panel so a
   layer is not read as a dataset of its own; on a dataset page it sits under
   the preview with nothing above it to indent from. */
.b-layer-picker { font-size: 0.8125rem; }
.b-layer-picker .form-check-label { font-size: inherit; }
.b-map-list .b-layer-picker { padding: 0 0 0.4rem 1.5rem; }
.b-preview-pane + .b-layer-picker { margin-top: 0.5rem; }

@media (max-width: 767.98px) {
  .b-map-page { height: auto; min-height: 100dvh; }
  .b-map-page > main { flex-direction: column; }
  .b-map-panel { flex: 0 0 auto; max-width: none; border-right: 0; border-bottom: 1px solid var(--bernard-line); }
  .b-map-list { max-height: 40vh; }
  .b-map-canvas { min-height: 55vh; }
}

/* ── Upload drop target ───────────────────────────────────────────
   One field, so one line. The native file control is an unstylable grey box
   on Windows, so the input is hidden inside this label and the chosen
   filename is echoed back in place of the prompt. */
.b-drop {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 1rem 1.125rem;
  border: 1px dashed var(--bernard-control-line);
  border-radius: 3px;
  background: var(--bernard-inset);
  cursor: pointer;
}
.b-drop:hover,
.b-drop:focus-within {
  border-color: var(--bernard-accent-edge);
  background: var(--bernard-accent-tint);
}
.b-drop > .bi { font-size: 1.25rem; color: var(--bernard-gray); line-height: 1; }
.b-drop-label { font-weight: 500; color: var(--bernard-ink); }

/* Applied to elements that also carry Bootstrap's .border utility, which is
   !important, so this has to be too. */
.b-dashed-zone {
  border: 1px dashed var(--bernard-control-line) !important;
  border-radius: 3px;
  background: var(--bernard-inset);
}

/* ── Help page prose ──────────────────────────────────────────────── */
#help-prose { max-width: 68ch; line-height: 1.65; }
#help-prose p { text-wrap: pretty; }
#help-prose :where(h1, h2, h3, h4, h5, h6) { scroll-margin-top: 80px; }
/* A guide isn't a landing page, so headings are about half their default size. */
#help-prose h1 { font-size: 1.3rem; }
#help-prose h2 { font-size: 1.1rem; margin-top: 1.75rem; }
#help-prose h3 { font-size: 1rem; margin-top: 1.25rem; }
#help-prose :where(h4, h5, h6) { font-size: 0.95rem; }
#help-prose img {
  /* A guide screenshot is an illustration, not a hero image, so cap it well
     under the text column so it reads as a figure, not the page. */
  max-width: min(600px, 100%);
  height: auto;
  border: 1px solid var(--bernard-line);
  border-radius: 3px;
  margin: 1rem 0;
}
#help-prose table { border-collapse: collapse; margin: 1rem 0; }
#help-prose th, #help-prose td {
  border: 1px solid var(--bernard-line);
  padding: 0.4rem 0.65rem;
  text-align: left;
  vertical-align: top;
}
#help-prose thead th { background: var(--bernard-panel); }
#help-prose code { background: var(--bernard-panel); padding: 0.1em 0.35em; border-radius: 2px; }
#help-prose pre code { background: none; padding: 0; }

/* ── Dark mode ────────────────────────────────────────────────────
   Everything else is handled by the palette at the top of the file. This is
   the one place a token can't do it: in dark the ink fill is near-white and
   Bootstrap's tick glyph is white, so the checked box moves to the accent. */
[data-bs-theme="dark"] .form-check-input:checked {
  background-color: var(--bernard-accent);
  border-color: var(--bernard-accent);
}

/* ── Print ────────────────────────────────────────────────────────
   The theme attribute is set once at load and never revisited, so without
   this a dark-mode reader prints light grey onto white paper. */
@media print {
  :root,
  [data-bs-theme="dark"] {
    --bernard-ink: #000;
    --bernard-body: #000;
    --bernard-gray: #333;
    --bernard-faint: #555;
    --bernard-accent: #000;
    --bernard-accent-hover: #000;
    --bernard-accent-tint: #fff;
    --bernard-page: #fff;
    --bernard-surface: #fff;
    --bernard-inset: #fff;
    --bernard-panel: #fff;
    --bernard-line: #999;
    --bernard-line-soft: #ccc;
    --bernard-control-line: #999;
    --bs-link-color: #000;
    --bs-link-hover-color: #000;
    --bs-secondary-color: #333;
  }
  body { background: #fff; color: #000; }
  .b-sticky-rail { position: static; }
  .navbar,
  .b-page-actions,
  .b-selection,
  .b-select-all,
  .b-result-pick,
  .b-row-action,
  .b-edit-title { display: none; }
}
