/* prototype-backend admin shell
 *
 * Only additions/overrides on top of tokens.css + styles.css. Buttons,
 * base table, empty/loading states, icon-btn and form primitives all come
 * from tokens.css — do not redefine them here.
 *
 * Section order (keep in sync):
 *   LAYOUT · TOPBAR + TABS · VIEW HEADER · SIDEBARS · CARDS ·
 *   FORMS · TABLES & GRIDS · SUBTABS · SIDE PANEL · MODALS · TOASTS ·
 *   CHIPS & BADGES · STATUS / ROLE PILLS · EMPTY & LOADING STATES · UTILITIES
 */

/* ============ LAYOUT ============ */

.pb-body {
  display: flex;
  flex-direction: column;
  background: var(--grey-50);
  /* The document scrolls as a whole — no fixed-viewport chrome. Topbar
   * and section-nav scroll away with the content. Scene viewer opts back
   * into a pinned viewport via `.pb-body--fixed-viewport` (see below). */
}

/* Fixed-viewport escape hatch for surfaces that need a fullscreen canvas
 * (the scene viewer / map creator). Toggled by `js/map-scene.js` on
 * mount/unmount. Also the single signal used to hide the section-nav —
 * every other route keeps the tabs visible. */
.pb-body.pb-body--fixed-viewport {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
.pb-body--fixed-viewport .pb-section-nav { display: none; }

/* Scene viewer: let the topbar span the full width (no 1280px cap) and
 * hide the global search. The scene has its own in-sidebar layer search
 * and its own breadcrumb/back chrome, so the topbar search only adds
 * noise in a fullscreen tool context. */
.pb-body--fixed-viewport .pb-topbar-inner { max-width: none; }
.pb-body--fixed-viewport .pb-topbar-search { display: none; }

.pb-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Skip-to-main-content link — visually hidden until focused via keyboard. */
.pb-skip-link {
  position: absolute;
  left: -9999px;
  z-index: 100;
  padding: var(--space-2) var(--space-3);
  background: var(--grey-900);
  color: var(--white);
  text-decoration: none;
  border-radius: var(--radius-sm);
}
.pb-skip-link:focus { left: var(--space-2); top: var(--space-2); }

.pb-main {
  min-width: 0;
  /* Cap content at the same max-width as `.pb-section-nav-inner` so the
   * tab row above lines up vertically with the content column. Scene
   * viewer opts out (see `.pb-main.pb-scene-root`). */
  max-width: 1280px;
  width: 100%;
  margin-inline: auto;
}
/* Scene viewer re-enables internal scroll so the map + its sub-modules
 * stay pinned while edits happen. `.pb-main` is now a direct child of
 * body, so it absorbs the remaining viewport height itself. */
.pb-body--fixed-viewport .pb-main {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

/* ============ TOPBAR + TABS ============ */

/* Topbar band spans the full viewport width (dark background reads as app
 * chrome). The content sits inside `.pb-topbar-inner`, capped at the same
 * max-width as `.pb-section-nav-inner` and `.pb-main` so logo / tabs /
 * content all share one vertical column on wide monitors. */
.pb-topbar {
  height: 48px;
  flex-shrink: 0;
  background: var(--grey-900);
  color: var(--white);
  border-bottom: 1px solid var(--grey-800);
}
/* Three-column grid: title (left) | hint (centered) | right cluster.
 * Using grid instead of flex+space-between so the hint sits optically
 * centered regardless of how wide the side clusters are. */
.pb-topbar-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-4);
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: var(--space-5);
  height: 100%;
}
.pb-topbar-inner > .pb-topbar-title { justify-self: start; }
.pb-topbar-inner > .pb-topbar-hint { justify-self: center; }
.pb-topbar-right {
  display: flex;
  align-items: center;
  justify-self: end;
  gap: var(--space-3);
}

/* Global search in the topbar right-cluster. Collapses to a 32×32 icon
 * trigger by default — click (or press Enter) to expand into a full
 * search input. Click-outside or Escape on an empty input collapses
 * back. This keeps the topbar cluster compact when the user isn't
 * actively searching. */
.pb-topbar-search {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 32px;
  transition: width var(--transition-fast);
}
.pb-topbar-search.is-collapsed { width: 32px; }
.pb-topbar-search.is-expanded  { width: 300px; }

/* Trigger button — visible only when collapsed. Styled to match the gear
 * icon's visual weight so the right cluster reads as a consistent row of
 * icons until the user opens search. */
.pb-topbar-search-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--grey-300);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.pb-topbar-search-trigger:hover { background: var(--grey-800); color: var(--white); }
.pb-topbar-search-trigger:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 1px;
}
.pb-topbar-search.is-expanded .pb-topbar-search-trigger { display: none; }

/* Input + inline search icon — only visible in the expanded state. */
.pb-topbar-search-icon {
  position: absolute;
  left: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  color: var(--grey-400);
  pointer-events: none;
}
.pb-topbar-search.is-collapsed .pb-topbar-search-icon,
.pb-topbar-search.is-collapsed .pb-topbar-search-input {
  display: none;
}
.pb-topbar-search-input {
  width: 100%;
  height: 32px;
  padding: 0 var(--space-3) 0 calc(var(--space-2) + var(--icon-sm) + var(--space-2));
  background: var(--grey-800);
  border: 1px solid var(--grey-700);
  border-radius: var(--radius-sm);
  color: var(--white);
  font-size: var(--text-sm);
}
.pb-topbar-search-input::placeholder { color: var(--grey-400); }
.pb-topbar-search-input:focus {
  outline: 2px solid var(--primary-red);
  outline-offset: 1px;
  background: var(--grey-700);
  border-color: var(--grey-600);
}

/* Results dropdown below the input. */
.pb-topbar-search-panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  right: 0;
  z-index: 60;
  background: var(--white);
  color: var(--grey-900);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: var(--space-1);
  max-height: 420px;
  overflow-y: auto;
}
.pb-topbar-search-panel[hidden] { display: none; }

.pb-search-group-label {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--grey-500);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.pb-search-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--grey-900);
}
.pb-search-item:hover,
.pb-search-item.is-highlighted {
  background: var(--grey-100);
}
.pb-search-item-icon { color: var(--grey-600); margin-top: 2px; }
.pb-search-item-body { flex: 1; min-width: 0; }
.pb-search-item-title {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-search-item-sub {
  font-size: var(--text-xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-search-empty {
  padding: var(--space-3) var(--space-3);
  font-size: var(--text-sm);
  color: var(--grey-500);
  text-align: center;
}

.pb-topbar-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--font-semibold);
  font-size: var(--text-base);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.pb-topbar-title:hover { color: var(--grey-100); }
.pb-topbar-title:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.pb-topbar-title .material-symbols-outlined { font-size: var(--icon-lg); }

.pb-topbar-hint {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  /* grey-300 on grey-800 fails WCAG AA (~1.8:1). Bumped to grey-100 to clear 4.5:1. */
  color: var(--grey-100);
  background: var(--grey-800);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
}

/* Settings gear — sits between the env hint chip and the avatar. Icon-only
 * round button so it visually belongs to the account cluster rather than
 * the primary tab row. `.is-active` when the current route is a settings
 * sub-route (toggled from `renderTabs` in app.js). */
.pb-topbar-gear {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--grey-300);
  background: transparent;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  padding: 0;
}
.pb-topbar-gear:hover { background: var(--grey-800); color: var(--white); }
.pb-topbar-gear:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 2px;
}
.pb-topbar-gear.is-active {
  background: var(--grey-800);
  color: var(--white);
  border-color: var(--primary-red);
}
.pb-topbar-gear .material-symbols-outlined { font-size: var(--icon-md); }

/* Account avatar button — rightmost element in the topbar. Initials on a
 * dark circle; opens the account menu on click. */
.pb-topbar-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--grey-700);
  color: var(--white);
  border: 1px solid var(--grey-600);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  letter-spacing: 0.02em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.pb-topbar-avatar:hover { background: var(--grey-600); }
.pb-topbar-avatar:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 2px;
}

/* Menu header (account menu) — non-interactive identity strip. */
.pb-menu-header {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--grey-200);
  margin-bottom: var(--space-1);
}
.pb-menu-header-name {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--grey-900);
}
.pb-menu-header-sub {
  font-size: var(--text-xs);
  color: var(--grey-600);
}
.pb-menu-sep {
  height: 1px;
  background: var(--grey-200);
  margin: var(--space-1) 0;
}

.pb-topbar-hint .material-symbols-outlined { font-size: var(--icon-sm); }

/* Section navigation — a white band sitting between the dark topbar and
 * the main content. Background spans the full viewport width so the
 * separator line reads as app chrome; the tab row itself is capped at the
 * same max-width as `.pb-main` (1280px) so tabs align visually with the
 * content column below on wide monitors. */
.pb-section-nav {
  height: 40px;
  flex-shrink: 0;
  background: var(--white);
  border-bottom: 1px solid var(--grey-200);
}
.pb-section-nav-inner {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: var(--space-5);
  height: 100%;
}

.pb-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  color: var(--grey-600);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  border-bottom: 2px solid transparent;
  height: 100%;
  white-space: nowrap;
  cursor: pointer;
  flex: 0 0 auto;
  margin-bottom: -1px; /* overlap the band's bottom border so the active underline sits cleanly on it */
}
.pb-tab:hover { color: var(--grey-900); background: var(--grey-50); }
.pb-tab .material-symbols-outlined { font-size: var(--icon-md); }
.pb-tab--active {
  color: var(--grey-900);
  border-bottom-color: var(--primary-red);
  background: transparent;
}
.pb-tab:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: -2px;
}

/* Back link on the right edge of the Settings sub-tab row. Ghost-style,
 * pushed right with `margin-left: auto` so it sits at the end of the
 * flex flow regardless of how many sub-tabs exist. */
.pb-section-nav-back {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0 var(--space-3);
  color: var(--grey-600);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  white-space: nowrap;
  cursor: pointer;
  flex: 0 0 auto;
}
.pb-section-nav-back:hover { color: var(--grey-900); background: var(--grey-50); }
.pb-section-nav-back:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: -2px;
}

/* Collapse tab labels to icon-only below 900px so the section nav stays single-row. */
@media (max-width: 900px) {
  .pb-tab-label { display: none; }
}

/* Role chip in topbar (visible when role !== 'admin'). */
.pb-role-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--grey-100);
  background: var(--status-warning);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  margin-left: var(--space-2);
  font-weight: var(--font-medium);
}
.pb-role-chip .material-symbols-outlined { font-size: var(--icon-xs); }

/* ============ ABOUT PAGE ============ */

/* Simple external-link rows for Settings → About. Each row is the whole
 * clickable surface (reuses the card body as its frame). */
.pb-about-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.pb-about-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--grey-900);
  text-decoration: none;
  border: 1px solid transparent;
}
.pb-about-link:hover {
  background: var(--grey-50);
  border-color: var(--grey-200);
}
.pb-about-link > .material-symbols-outlined { color: var(--grey-600); }
.pb-about-link-body { flex: 1; min-width: 0; }
.pb-about-link-title {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
}
.pb-about-link-url {
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pb-about-link-arrow { color: var(--grey-500); font-size: var(--icon-sm); }

/* ============ VIEW HEADER ============ */

/* Standard header block at the top of every view content area. Sits
 * directly under the topbar. */
.pb-view-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--grey-200);
  margin: calc(var(--space-5) * -1) calc(var(--space-6) * -1) var(--space-5);
}

.pb-view-header-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Breadcrumb trail inside the view-header, above the title. Omitted on
 * section-root pages where it would just echo the title (e.g. the Maps
 * & Apps gallery). Last crumb is the current page and not a link. */
.pb-breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--grey-500);
  margin-bottom: var(--space-1);
}
.pb-breadcrumb-link {
  color: var(--grey-600);
  text-decoration: none;
}
.pb-breadcrumb-link:hover {
  color: var(--grey-900);
  text-decoration: underline;
}
.pb-breadcrumb-sep { color: var(--grey-400); }
.pb-breadcrumb-current {
  color: var(--grey-700);
  font-weight: var(--font-medium);
}

.pb-view-title {
  font-size: var(--text-2xl);
  font-weight: var(--font-bold);
  color: var(--grey-900);
  line-height: var(--leading-tight);
  margin: 0;
}

.pb-view-subtitle {
  font-size: var(--text-sm);
  color: var(--grey-600);
}

.pb-view-description {
  font-size: var(--text-sm);
  color: var(--grey-600);
  line-height: var(--leading-normal);
  margin-top: var(--space-2);
}

.pb-view-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}

/* Compose title + inline badge/status on one row. */
.pb-title-row {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* The main content area sets its own outer padding; pb-view-header uses
 * negative margins to span edge-to-edge. Give .pb-main consistent padding. */
.pb-main { padding: var(--space-5) var(--space-6); }

/* ============ ROW / BUTTON HELPERS (formerly sidebar) ============ */

/* Compact button modifier. Used by the scene viewer's layer-manager
 * "+ Add ▾" button where the standard .btn-* padding is too generous
 * for a condensed left panel. Class name is historical — it started life
 * in the old object sidebars which are now gone. */
.pb-sidebar-new {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 0;
}

/* Inline row-level icon action (e.g., the "delete member" button inside a
 * table row). 24×24 hit area per WCAG 2.5.8. Hover + focus emphasis
 * signal destructive intent via `--status-error`. */
.pb-sidebar-item-action {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--grey-500);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
}
.pb-sidebar-item-action .material-symbols-outlined { font-size: var(--icon-sm); }
.pb-sidebar-item-action:hover { background: var(--grey-200); color: var(--status-error); }
.pb-sidebar-item-action:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
  background: var(--grey-100);
  color: var(--status-error);
}

/* ============ CARDS ============ */

/* Shell: .pb-card [> .pb-card-header] [> .pb-card-body] [> .pb-card-footer].
 * Body/header get their padding from --padded modifier (always applied in
 * the JS views) — keeps unpadded variants available for custom layouts. */
.pb-card {
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.pb-card-header {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--grey-700);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  border-bottom: 1px solid var(--grey-200);
  background: var(--grey-50);
  padding: var(--space-3) var(--space-4);
}

.pb-card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.pb-card-footer {
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--grey-200);
  background: var(--grey-50);
}

.pb-card--padded .pb-card-header,
.pb-card--padded .pb-card-body { padding: var(--space-4) var(--space-5); }

.pb-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: var(--space-5);
  align-items: start;
}

.pb-card-grid--2col { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--space-4); }

/* Key/value pair layout inside cards. */
.pb-kv {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: var(--space-3);
  align-items: start;
  font-size: var(--text-sm);
  margin: 0;
}
.pb-kv dt { color: var(--grey-600); font-weight: var(--font-medium); }
.pb-kv dd { margin: 0; color: var(--grey-900); min-width: 0; word-break: break-word; }

/* Product gallery cards. (Grid is defined once, in the shared rule near
 * the catalogue block, for both Maps & Apps and Layers.) */
.pb-product-card {
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  display: block;
  color: inherit;
  text-decoration: none;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.pb-product-card:hover,
.pb-product-card:focus {
  border-color: var(--grey-400);
  box-shadow: var(--shadow-md);
  outline: none;
}

.pb-product-card-thumb {
  width: 100%;
  height: 100px;
  object-fit: cover;
  background: var(--grey-100);
  display: block;
}
.pb-product-card-thumb--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--grey-400);
}
.pb-product-card-thumb--placeholder .material-symbols-outlined { font-size: var(--icon-display); }

.pb-product-card-body {
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
}

.pb-product-card-titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.pb-product-card-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  margin: 0;
  color: var(--grey-900);
}

.pb-product-card-desc {
  font-size: var(--text-sm);
  color: var(--grey-700);
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.8em;
}

.pb-product-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--grey-100);
}

/* Layer gallery cards — mirror the product-card chrome for visual parity
 * between the two catalogues. The thumbnail slot holds either a static
 * extent-bbox SVG (via `extentThumbnail()`) or a placeholder icon when
 * no bbox metadata is recorded. */
.pb-layer-card {
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  color: inherit;
  text-decoration: none;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.pb-layer-card:hover,
.pb-layer-card:focus {
  border-color: var(--grey-400);
  box-shadow: var(--shadow-md);
  outline: none;
}
.pb-layer-card-thumb {
  width: 100%;
  height: 100px;
  background: var(--grey-100);
  display: block;
  overflow: hidden;
}
.pb-layer-card-thumb--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--grey-400);
}
.pb-layer-card-thumb--placeholder .material-symbols-outlined { font-size: var(--icon-display); }
.pb-extent-thumb {
  width: 100%;
  height: 100%;
  display: block;
}

.pb-layer-card-body {
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  flex: 1;
}
.pb-layer-card-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--grey-900);
  margin: 0;
}
.pb-layer-card-name {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.pb-layer-card-meta {
  font-size: var(--text-sm);
  color: var(--grey-600);
}
.pb-layer-card-count {
  font-size: var(--text-sm);
  color: var(--grey-700);
}
.pb-layer-card-updated {
  font-size: var(--text-xs);
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--grey-100);
}

/* Layer-detail optional thumbnail (product detail only). */
.pb-hero-thumb {
  width: 100%;
  max-width: 320px;
  height: 140px;
  border-radius: var(--radius-md);
  object-fit: cover;
  background: var(--grey-100);
  margin-bottom: var(--space-4);
}

/* Layer-detail layout wrappers — no visible styling themselves; just
 * spacing hosts for the header + metadata (top) and the REST/Used-by
 * cards (bottom). Subtabs and the tab-host sit between them. */
.pb-layer-hero,
.pb-layer-api,
.pb-layer-bottom {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.pb-layer-hero { margin-bottom: var(--space-4); }
.pb-layer-api { margin-top: var(--space-4); }
.pb-layer-bottom { margin-top: var(--space-4); }


/* Subtitle meta helpers — shared by every view-header (catalogue,
 * detail, scene viewer). `metaLine` builds a dot-separated row; dots
 * come from `.pb-meta-sep` so alignment stays consistent if a token is
 * a Node (chip, link, mono span) instead of plain text. `metaStack`
 * wraps a metaLine + a smaller secondary line (usually an updated-at
 * timestamp) for views with richer metadata. */
.pb-meta-line {
  font-size: var(--text-sm);
  color: var(--grey-600);
}
.pb-meta-sep {
  color: var(--grey-400);
  margin: 0 2px;
}
.pb-meta-stack {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pb-meta-secondary {
  font-size: var(--text-xs);
  color: var(--grey-500);
}

/* Wrapper around the subtabs nav + active tab content. Keeps them visually
 * bound together with no gap between the tab strip and its panel, while
 * giving the whole group consistent vertical breathing room against the
 * hero above and the API/bottom sections below. */
.pb-tabs-wrap {
  display: flex;
  flex-direction: column;
}

/* Metadata grouped sections (ISO 19115 / DCAT). */
.pb-metadata-card { margin-top: var(--space-3); }

.pb-meta-dl {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: var(--space-2) var(--space-3);
  margin: 0;
}
.pb-meta-row { display: contents; }
.pb-meta-label {
  font-weight: var(--font-semibold);
  color: var(--grey-700);
  font-size: var(--text-sm);
  padding-top: var(--space-1);
}
.pb-meta-value { margin: 0; font-size: var(--text-sm); }

.pb-meta-section {
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-2);
  background: var(--white);
}
.pb-meta-section > summary {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--grey-800);
  cursor: pointer;
  user-select: none;
  background: var(--grey-50);
  border-radius: var(--radius-sm);
}
.pb-meta-section[open] > summary {
  border-bottom: 1px solid var(--grey-200);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.pb-meta-section-body { padding: var(--space-3); }

.pb-meta-summary-hint {
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  color: var(--grey-600);
  margin-left: var(--space-2);
  text-transform: none;
  letter-spacing: 0;
}

/* ============ FORMS ============ */

.pb-form {
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.pb-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.pb-field label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--grey-800);
}

.pb-field input[type="text"],
.pb-field input[type="search"],
.pb-field input[type="email"],
.pb-field input[type="number"],
.pb-field input[type="date"],
.pb-field input[type="datetime-local"],
.pb-field textarea,
.pb-field select {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-sm);
  background: var(--white);
  color: var(--grey-900);
}

.pb-field textarea { min-height: 80px; resize: vertical; }

.pb-field-hint { font-size: var(--text-xs); color: var(--grey-500); }
.pb-field-error { font-size: var(--text-xs); color: var(--status-error); }

.pb-field input.is-invalid,
.pb-field textarea.is-invalid { border-color: var(--status-error); }

.pb-radio-group {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.pb-radio {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: var(--white);
}
.pb-radio input { margin: 0; }
.pb-radio:has(input:checked) {
  border-color: var(--grey-900);
  background: var(--grey-100);
}

.pb-form-actions {
  display: flex;
  gap: var(--space-3);
  justify-content: flex-end;
}

/* Inline-editable field. */
.pb-inline-edit { display: block; min-width: 0; }

.pb-inline-value {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-1);
  border-radius: var(--radius-sm);
  cursor: text;
  min-height: 1.4em;
  color: var(--grey-900);
  /* Faint dashed border at rest so the field reads as a fillable slot even
   * before the user hovers. Border becomes solid on hover/focus to confirm
   * the hit-target. */
  border: 1px dashed var(--grey-200);
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.pb-inline-value:hover { background: var(--grey-50); border-color: var(--grey-300); border-style: solid; }
.pb-inline-value:focus { outline: 2px solid var(--grey-400); outline-offset: 1px; }
.pb-inline-value.is-placeholder { color: var(--grey-500); font-style: italic; }
/* Green flash for ~900ms after a successful save so the user sees the
 * change landed. Fades back to the default border state. */
.pb-inline-value.is-just-saved {
  background: color-mix(in srgb, var(--status-success, #2f8a4a) 14%, var(--white));
  border-color: var(--status-success, #2f8a4a);
  border-style: solid;
}
.pb-inline-value--multiline {
  display: flex;
  align-items: flex-start;
}
/* Inner text node inside the inline-edit value. Wraps long text while
 * letting the sibling pencil-icon sit flush on the trailing edge. */
.pb-inline-value-text {
  white-space: pre-wrap;
  min-width: 0;
  flex: 1;
}

/* Pencil affordance on inline-editable fields. Visible at rest (not just
 * on hover) so first-time users can see the field is editable without
 * having to hunt for the hit-target. Pairs with the dashed border on the
 * value for a double-cue. `pointer-events: none` so clicks fall through
 * to the <span> that owns the enter-edit listener. */
.pb-inline-edit-icon {
  font-size: var(--icon-xs);
  color: var(--grey-500);
  opacity: 0.6;
  transition: opacity var(--transition-fast);
  pointer-events: none;
  flex-shrink: 0;
}
.pb-inline-value:hover .pb-inline-edit-icon,
.pb-inline-value:focus .pb-inline-edit-icon,
.pb-inline-edit:focus-within .pb-inline-edit-icon {
  opacity: 1;
}

.pb-inline-input {
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--grey-400);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-sm);
  background: var(--white);
  color: var(--grey-900);
}

.pb-inline-input--ta {
  min-height: 80px;
  resize: vertical;
  font-family: inherit;
}

.pb-inline-title { font-size: var(--text-base); font-weight: var(--font-medium); }

/* Danger button — extends token buttons. */
.btn-danger {
  background: var(--primary-red);
  color: var(--white);
  border: none;
  padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
}
.btn-danger:hover { background: var(--primary-red-dark); }
.btn-danger:disabled { background: var(--grey-300); cursor: not-allowed; }

/* ============ TABLES & GRIDS ============ */

.pb-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.pb-table th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  background: var(--grey-50);
  color: var(--grey-600);
  font-weight: var(--font-medium);
  text-transform: uppercase;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  border-bottom: 1px solid var(--grey-200);
}

.pb-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--grey-100);
  color: var(--grey-800);
}

.pb-table tbody tr { cursor: pointer; }
.pb-table tbody tr:hover td { background: var(--grey-50); }
.pb-table tbody tr:last-child td { border-bottom: none; }

.pb-table .pb-row-actions {
  text-align: right;
  width: 1%;
  white-space: nowrap;
}

.pb-name-mono {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--grey-700);
}

/* ============ DATA GRID ============ */

/* Single-row toolbar: search left, actions right. */
.pb-grid-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding-bottom: var(--space-2);
}

.pb-grid-search-wrap {
  position: relative;
  flex: 0 1 360px;
  min-width: 220px;
}
.pb-grid-search-icon {
  position: absolute;
  left: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  color: var(--grey-500);
  pointer-events: none;
}
.pb-grid-search {
  width: 100%;
  padding: var(--space-1) var(--space-3) var(--space-1) calc(var(--space-2) + var(--icon-sm) + var(--space-2));
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--white);
}
.pb-grid-search:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 1px;
  border-color: var(--grey-400);
}

.pb-grid-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Sticky scrollable table area. */
.pb-data-card { overflow: hidden; }
.pb-data-scroll { overflow-x: auto; max-width: 100%; }
.pb-data-grid { min-width: 100%; }

.pb-data-grid thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--grey-50);
  /* Data-grid headers are sortable column names, not structural labels —
   * drop the overline styling applied by .pb-table th so they read as
   * regular text. Schema-editor tables keep the uppercase treatment. */
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
  color: var(--grey-700);
}

.pb-th-sortable {
  cursor: pointer;
  user-select: none;
}
.pb-th-sortable:hover { background: var(--grey-100); }
.pb-th-sortable.is-sorted { color: var(--grey-900); }
.pb-data-grid tbody tr { cursor: pointer; }

/* Numeric cells right-align with tabular figures so digits line up for
 * magnitude comparison — standard spreadsheet convention. Applied to both
 * `<th>` (header label flips right) and `<td>` (value). */
.pb-cell-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.pb-cell-num .pb-th-label { margin-left: var(--space-1); margin-right: 0; }

/* Header cell label + dual-arrow sort indicator. */
.pb-th-label { margin-right: var(--space-1); }
.pb-sort-indicator {
  display: inline-flex;
  flex-direction: column;
  line-height: 0.7;
  font-size: 9px;
  vertical-align: middle;
  color: var(--grey-400);
}
.pb-sort-arrow--up   { margin-bottom: 1px; }
.pb-sort-arrow--down { margin-top: 1px; }
/* When the column is the active sort, highlight the matching direction and
 * mute the opposite one so the indicator reads as "currently ascending" or
 * "currently descending" at a glance. */
.pb-sort-indicator.is-sorted.is-asc  .pb-sort-arrow--up,
.pb-sort-indicator.is-sorted.is-desc .pb-sort-arrow--down {
  color: var(--grey-900);
}
.pb-sort-indicator.is-sorted.is-asc  .pb-sort-arrow--down,
.pb-sort-indicator.is-sorted.is-desc .pb-sort-arrow--up {
  color: var(--grey-300);
}

/* Footer row: count (left), pager (center), rows-per-page (right). */
.pb-grid-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-1);
  flex-wrap: wrap;
  font-size: var(--text-xs);
}
.pb-grid-footer-count { white-space: nowrap; }
.pb-grid-pager {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.pb-grid-page-btn {
  background: transparent;
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--grey-700);
  padding: 0;
}
.pb-grid-page-btn:hover:not(:disabled) { background: var(--grey-50); color: var(--grey-900); }
.pb-grid-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.pb-grid-page-label { font-variant-numeric: tabular-nums; }
.pb-grid-footer-pagesize {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.pb-grid-pagesize {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  font-size: var(--text-xs);
}

/* Schema table. */
.pb-schema-table .pb-desc-cell {
  min-width: 200px;
  color: var(--grey-800);
}
.pb-schema-table tbody tr { cursor: default; }
.pb-schema-table tbody tr:hover td { background: transparent; }
/* Actions column (delete button in edit mode) — right-align so the icon
 * sits flush with the column edge instead of orphaned in the middle. */
.pb-schema-table .pb-actions-cell { text-align: right; padding-right: var(--space-2); }

/* Drag-and-drop affordances. */
.pb-schema-table.is-edit { position: relative; }
.pb-card:has(.pb-schema-table.is-edit) { position: relative; }

.pb-drag-cell { width: 32px; padding-right: 0 !important; }
.pb-drag-handle {
  display: inline-block;
  width: var(--icon-lg);
  text-align: center;
  color: var(--grey-400);
  cursor: grab;
  user-select: none;
  font-size: var(--icon-xs);
  line-height: 1;
  padding: var(--space-1) 0;
  border-radius: var(--radius-sm);
  letter-spacing: -2px;
}
.pb-drag-handle:hover,
.pb-drag-handle:focus { color: var(--grey-700); background: var(--grey-100); outline: none; }
.pb-drag-handle.is-disabled { color: var(--grey-200); cursor: not-allowed; }
.pb-drag-handle.is-grabbed { background: var(--grey-200); color: var(--grey-900); }

.pb-schema-table tr.is-dragging td { background: var(--grey-50); opacity: 0.6; }

.pb-drop-indicator {
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--primary-red);
  pointer-events: none;
  z-index: 5;
}

/* View toolbar row above tables/grids. */
.pb-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.pb-toolbar-title {
  font-size: var(--text-sm);
  color: var(--grey-600);
  font-weight: var(--font-medium);
}

.pb-toolbar .pb-search {
  flex: 1;
  max-width: 360px;
  position: relative;
}

.pb-search input {
  width: 100%;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-8);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--white);
}

.pb-search .material-symbols-outlined {
  position: absolute;
  left: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  color: var(--grey-500);
  font-size: var(--icon-md);
  pointer-events: none;
}

/* Schema toolbar / edit-mode affordances. */
.pb-schema-toolbar { align-items: center; }

.pb-schema-edit-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.pb-editing-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  background: var(--pill-staging-bg);
  color: var(--pill-staging-text);
  border-radius: var(--radius-full);
  margin-left: var(--space-2);
}

/* ============ SUBTABS ============ */

/* Lighter-weight than .pb-tabs: underline-only, small caps, no pill.
 * Used for Schema · Data · Map on the layer detail. */
.pb-subtabs {
  display: flex;
  gap: var(--space-2);
  border-bottom: 1px solid var(--grey-200);
  margin-bottom: var(--space-5);
}

.pb-subtab {
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: var(--text-xs);
  color: var(--grey-600);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-weight: var(--font-medium);
}
.pb-subtab:hover { color: var(--grey-900); }
.pb-subtab.is-active {
  color: var(--grey-900);
  border-bottom-color: var(--grey-900);
}

/* ============ SIDE PANEL ============ */

.pb-side-panel-backdrop {
  position: fixed;
  inset: 0;
  background: var(--scrim-soft);
  z-index: 1200;
  animation: pb-fadein var(--transition-fast);
}

@keyframes pb-fadein { from { opacity: 0; } to { opacity: 1; } }

.pb-side-panel {
  position: fixed;
  top: 0;
  right: 0;
  height: 100vh;
  height: 100dvh;
  width: 420px;
  max-width: 100%;
  background: var(--white);
  box-shadow: var(--shadow-xl);
  z-index: 1201;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform var(--transition-normal);
}
.pb-side-panel.is-open { transform: translateX(0); }

.pb-side-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--grey-200);
  flex-shrink: 0;
}

.pb-side-panel-title {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
}

.pb-side-panel-close {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: var(--space-1);
  display: flex;
  color: var(--grey-700);
  border-radius: var(--radius-sm);
}
.pb-side-panel-close:hover { background: var(--grey-100); color: var(--grey-900); }

.pb-side-panel-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.pb-side-panel-body .pb-field label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.pb-side-panel-body input[type="text"],
.pb-side-panel-body input[type="number"],
.pb-side-panel-body input[type="date"],
.pb-side-panel-body input[type="datetime-local"],
.pb-side-panel-body textarea,
.pb-side-panel-body select {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-sm);
  background: var(--white);
  color: var(--grey-900);
  width: 100%;
  box-sizing: border-box;
}

.pb-checkbox-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
}

.pb-geom-input {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  min-height: 140px;
  resize: vertical;
}

.pb-side-panel-footer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--grey-200);
  flex-shrink: 0;
  background: var(--grey-50);
}

/* ============ MODALS ============ */

.pb-modal-host {
  position: fixed;
  inset: 0;
  z-index: 1000;
  pointer-events: none;
}

.pb-modal-backdrop {
  position: absolute;
  inset: 0;
  background: var(--modal-scrim);
  pointer-events: auto;
}

.pb-modal {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xl);
  max-width: 480px;
  width: calc(100% - 2 * var(--space-4));
  max-height: calc(100% - 2 * var(--space-4));
  overflow: auto;
  pointer-events: auto;
}

.pb-modal-header {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--grey-200);
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
}

.pb-modal-body {
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.pb-modal-footer {
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--grey-200);
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
}

/* Confirm-to-delete block: prominent echo of the required string so the
 * user doesn't have to scan the message prose for what to type. Input
 * flips to a green outline on match to reinforce the "you're ready" state. */
.pb-confirm-echo {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  background: var(--grey-50);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
}
.pb-confirm-echo-label {
  font-size: var(--text-xs);
  color: var(--grey-600);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.pb-confirm-echo-value {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  color: var(--grey-900);
  user-select: all;
}
.pb-confirm-input {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  box-sizing: border-box;
}
.pb-confirm-input:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}
.pb-confirm-input.is-valid {
  border-color: var(--status-success, #2f8a4a);
  background: color-mix(in srgb, var(--status-success, #2f8a4a) 6%, var(--white));
}

/* Modal size overrides: both import and new-layer drawers need more room
 * than the default 480px to keep their forms readable. */
.pb-modal:has(.pb-import-modal),
.pb-modal:has(.pb-new-layer-drawer) { max-width: 640px; }

/* Import modal. */
.pb-import-modal { display: block; }
.pb-import-step { gap: var(--space-4); }

.pb-import-file {
  padding: var(--space-2);
  border: 1px dashed var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--grey-50);
  font-size: var(--text-sm);
  width: 100%;
  box-sizing: border-box;
}

.pb-import-summary {
  font-size: var(--text-sm);
  color: var(--grey-800);
  font-weight: var(--font-medium);
}

.pb-import-mapping {
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
}
.pb-import-mapping th,
.pb-import-mapping td { padding: var(--space-2) var(--space-3); }
.pb-import-mapping tbody tr { cursor: default; }
.pb-import-mapping tbody tr:hover td { background: transparent; }

.pb-import-target {
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-sm);
  background: var(--white);
  color: var(--grey-900);
}

.pb-import-geom {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.pb-import-geom .pb-field {
  flex: 1;
  min-width: 140px;
}

.pb-import-geom select {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--white);
}

.pb-import-skipbox {
  padding: var(--space-3);
  max-height: 260px;
  overflow-y: auto;
  background: var(--white);
}

.pb-import-skiplist {
  margin: 0;
  padding-left: var(--space-5);
  font-size: var(--text-xs);
  color: var(--grey-700);
  font-family: var(--font-mono);
}
.pb-import-skiplist li { margin-bottom: 2px; }

/* Geometry-type select in the new-layer drawer. */
.pb-geom-select {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  min-width: 200px;
}

/* ============ TOASTS ============ */

.pb-toast-host {
  position: fixed;
  bottom: var(--space-5);
  right: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  z-index: 1100;
  pointer-events: none;
}

.pb-toast {
  background: var(--grey-900);
  color: var(--white);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  font-size: var(--text-sm);
  min-width: 240px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  pointer-events: auto;
  animation: slideIn var(--transition-normal);
}

.pb-toast--error { background: var(--status-error); }
.pb-toast--success { background: var(--status-active); }

.pb-toast-close {
  background: transparent;
  border: none;
  color: inherit;
  cursor: pointer;
  padding: 0;
  display: flex;
}

/* ============ CHIPS & BADGES ============ */

.pb-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  background: var(--grey-100);
  color: var(--grey-900);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-full);
  text-decoration: none;
  font-weight: var(--font-medium);
  font-family: var(--font-mono);
}
.pb-chip:hover { background: var(--grey-200); }
.pb-chip--muted { background: var(--grey-50); color: var(--grey-700); font-family: inherit; }
.pb-chip--danger { background: var(--status-error-bg); color: var(--status-error-text); border-color: var(--status-error); }

.pb-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Neutral type / enum label. Square-ish corners distinguish this from the
 * pill-shaped `.pb-chip` (tags) and colored `.pb-status` (lifecycle). */
.pb-badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  background: var(--grey-100);
  color: var(--grey-700);
  font-weight: var(--font-medium);
}

/* Inline code. */
.pb-code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  background: var(--grey-100);
  color: var(--grey-900);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--grey-200);
  white-space: pre-wrap;
  word-break: break-all;
  margin: 0;
}

.pb-code--inline {
  padding: var(--space-1) var(--space-2);
  display: inline-block;
}

.pb-url-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
}

.pb-url-row .pb-code--inline {
  flex: 1;
  min-width: 200px;
}

.pb-details {
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.pb-details > summary {
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--grey-700);
  background: var(--grey-50);
  user-select: none;
}

.pb-details[open] > summary { border-bottom: 1px solid var(--grey-200); }

.pb-details .pb-code {
  border: none;
  border-radius: 0;
  background: var(--white);
}

/* ============ STATUS / ROLE PILLS ============ */

.pb-status {
  display: inline-block;
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  border-radius: var(--radius-sm);
  font-weight: var(--font-medium);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.pb-status--live     { background: var(--pill-live-bg);     color: var(--pill-live-text); }
.pb-status--staging  { background: var(--pill-staging-bg);  color: var(--pill-staging-text); }
.pb-status--archived { background: var(--pill-archived-bg); color: var(--pill-archived-text); }

/* Generic dismissible banner (warning / info). Currently used by the
 * import modal for the non-WGS84 SRID warning; reusable elsewhere. */
.pb-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--grey-50);
  color: var(--grey-800);
}
.pb-banner--warn {
  background: var(--status-warning-bg);
  color: var(--status-warning-text);
  border-color: var(--status-warning);
}
.pb-banner-icon {
  font-size: var(--icon-md);
  flex-shrink: 0;
  color: var(--grey-600);
}
.pb-banner--warn .pb-banner-icon { color: var(--status-warning); }
.pb-banner-text { flex: 1; min-width: 0; }
.pb-banner-close {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  padding: 0 var(--space-1);
  display: inline-flex;
  align-items: center;
  opacity: 0.7;
}
.pb-banner-close:hover { opacity: 1; }

/* SRID mismatch banner on the Map tab. */
.pb-srid-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
  background: var(--status-warning-bg);
  color: var(--status-warning-text);
  border: 1px solid var(--status-warning);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}
.pb-srid-banner-icon {
  font-size: var(--icon-md);
  flex-shrink: 0;
  color: var(--status-warning);
}
.pb-srid-banner-text { flex: 1; min-width: 0; }
.pb-srid-banner-close {
  background: transparent;
  border: 0;
  color: var(--status-warning-text);
  cursor: pointer;
  padding: 0 var(--space-1);
  display: inline-flex;
  align-items: center;
}
.pb-srid-banner-close:hover { opacity: 0.7; }

/* ============ MAP PREVIEW ============ */

.pb-map {
  position: relative;
  width: 100%;
  height: calc(100vh - 240px);
  min-height: 500px;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-100);
}

.pb-map-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 280px;
  text-align: center;
}

/* ============ DROPDOWN MENU ============ */

/* Lightweight dropdown anchored to a button. Currently used by the
 * Maps & Apps gallery "+ New" button. Scale vertically; right-aligned
 * to the anchor. */
.pb-menu-wrap {
  position: relative;
  display: inline-flex;
}

.pb-menu {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 60;
  min-width: 200px;
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  padding: var(--space-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pb-menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--grey-900);
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.pb-menu-item:hover,
.pb-menu-item:focus-visible {
  background: var(--grey-50);
  outline: none;
}
.pb-menu-item .material-symbols-outlined {
  font-size: var(--icon-md);
  color: var(--grey-600);
}

/* ============ SCENE VIEWER ============ */

/* When map-scene.js mounts into .pb-main it sets this class on the root
 * container so we can collapse the scroll-container padding and let the
 * layout fill the viewport edge-to-edge. */
/* `.pb-scene-root` is added to `#app` (which already has `.pb-main`). The
 * chained selector wins on specificity without needing `!important`. The
 * scene viewer needs the full viewport width for its map canvas, so the
 * 1280px cap inherited from `.pb-main` is lifted here. */
.pb-main.pb-scene-root {
  padding: 0;
  max-width: none;
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

/* View header keeps its own chrome but loses the negative margins it uses
 * in card-style views (we don't have an outer --space-6 padding here). */
.pb-scene-root > .pb-view-header { margin: 0; }

/* 280px fixed sidebar, flexible canvas. */
.pb-scene-layout {
  flex: 1;
  display: grid;
  grid-template-columns: 280px 1fr;
  min-height: 0;
}

.pb-scene-sidebar {
  background: var(--white);
  border-right: 1px solid var(--grey-200);
  overflow-y: auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--space-3) var(--space-3) var(--space-4);
  gap: var(--space-2);
}

.pb-scene-section-header {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--grey-500);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  padding: var(--space-2) var(--space-1) var(--space-1);
}

.pb-scene-section-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 0 var(--space-1);
}
.pb-scene-section-header-row .pb-scene-section-header { padding: 0; }

.pb-scene-divider {
  height: 1px;
  background: var(--grey-200);
  margin: var(--space-2) 0;
}

.pb-scene-search {
  padding: 0 var(--space-1);
}
.pb-scene-search-input {
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--white);
  box-sizing: border-box;
}
.pb-scene-search-input:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}

.pb-scene-layer-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pb-scene-layer-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  cursor: default;
}
.pb-scene-layer-row:hover { background: var(--grey-50); }

.pb-scene-layer-drag {
  background: transparent;
  border: 0;
  /* Reorder isn't wired yet — `pointer` avoids falsely advertising drag-and-drop.
   * When real DnD lands, switch back to `grab`. */
  cursor: pointer;
  color: var(--grey-400);
  /* WCAG 2.5.8: 4px padding + 18px icon = 26×26. */
  padding: var(--space-1);
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-sm);
}
.pb-scene-layer-drag:hover { color: var(--grey-700); background: var(--grey-100); }
.pb-scene-layer-drag .material-symbols-outlined { font-size: var(--icon-md); }

.pb-scene-layer-viz {
  margin: 0 var(--space-1);
  cursor: pointer;
}

.pb-scene-layer-geom {
  font-size: var(--icon-md);
  color: var(--grey-600);
  flex-shrink: 0;
}

.pb-scene-layer-row-body {
  flex: 1;
  min-width: 0;
}

.pb-scene-layer-title {
  font-size: var(--text-sm);
  color: var(--grey-900);
  font-weight: var(--font-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-scene-layer-sub {
  font-size: var(--text-xs);
  color: var(--grey-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pb-scene-layer-overflow {
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--grey-500);
  /* WCAG 2.5.8: 4px padding + 18px icon = 26×26. */
  padding: var(--space-1);
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-sm);
}
.pb-scene-layer-overflow:hover { color: var(--grey-900); background: var(--grey-100); }
.pb-scene-layer-overflow:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}
.pb-scene-layer-overflow .material-symbols-outlined { font-size: var(--icon-md); }

/* Compact popover menu used by layer overflow. */
.pb-menu--compact { min-width: 180px; }

/* ---- Basemap radios ---- */

.pb-scene-basemap-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 var(--space-1);
}

.pb-scene-basemap-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--grey-800);
}
.pb-scene-basemap-row:hover { background: var(--grey-50); }
.pb-scene-basemap-row input { margin: 0; }

.pb-scene-basemap-hint {
  font-size: var(--text-xs);
  color: var(--grey-500);
  padding: var(--space-1) var(--space-2);
  font-style: italic;
}

.pb-scene-edit-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  margin: var(--space-2) var(--space-1) 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  font-size: var(--text-sm);
  color: var(--grey-800);
  cursor: pointer;
}
.pb-scene-edit-toggle:hover { background: var(--grey-50); }
.pb-scene-edit-toggle:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}
.pb-scene-edit-toggle[aria-pressed="true"] {
  background: var(--primary-red-tint);
  border-color: var(--primary-red);
  color: var(--primary-red);
}

/* ---- Canvas ---- */

.pb-scene-canvas {
  position: relative;
  overflow: hidden;
  background: var(--grey-100);
  min-height: 0;
}

.pb-scene-canvas-map {
  position: absolute;
  inset: 0;
  bottom: 28px; /* above footer strip */
}

/* Sidebar empty-state card — shown when the scene has zero layers.
 * Lives inside `.pb-scene-layer-list` so it never occludes the base map
 * (the map is the tool's best demo; don't cover it). */
.pb-scene-layer-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-3);
  text-align: center;
  color: var(--grey-600);
}
.pb-scene-layer-empty .material-symbols-outlined {
  font-size: var(--icon-xl);
  color: var(--grey-400);
}
.pb-scene-layer-empty-title {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--grey-900);
}
.pb-scene-layer-empty-desc {
  font-size: var(--text-xs);
  color: var(--grey-500);
  line-height: var(--leading-normal);
  margin-bottom: var(--space-1);
}

/* ---- Floating edit toolbar ---- */

.pb-scene-edit-toolbar {
  position: absolute;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 2px;
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  padding: var(--space-1);
}

.pb-scene-toolbar-btn {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--grey-700);
}
.pb-scene-toolbar-btn:hover {
  background: var(--grey-50);
  color: var(--grey-900);
}
.pb-scene-toolbar-btn:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}
.pb-scene-toolbar-btn.is-active {
  background: var(--grey-50);
  border-color: var(--primary-red);
  color: var(--primary-red);
}
.pb-scene-toolbar-btn .material-symbols-outlined { font-size: var(--icon-lg); }

.pb-scene-toolbar-divider {
  width: 1px;
  height: 24px;
  background: var(--grey-200);
  margin: 0 var(--space-1);
  display: inline-block;
}

/* ---- Footer strip ---- */

.pb-scene-footer-strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 28px;
  background: var(--white);
  border-top: 1px solid var(--grey-200);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
  color: var(--grey-600);
  z-index: 3;
}

.pb-scene-footer-btn {
  background: transparent;
  border: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--grey-700);
  font-size: var(--text-xs);
}
.pb-scene-footer-btn:hover { background: var(--grey-100); color: var(--grey-900); }
.pb-scene-footer-btn:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}

.pb-scene-footer-item { white-space: nowrap; }
.pb-scene-footer-coords { font-family: var(--font-mono); }
.pb-scene-footer-scale { margin-left: auto; font-family: var(--font-mono); }

/* ---- Inspector drawer ---- */

.pb-scene-inspector {
  position: absolute;
  top: 0;
  bottom: 28px; /* above footer strip */
  right: 0;
  width: 300px;
  background: var(--white);
  border-left: 1px solid var(--grey-200);
  transform: translateX(100%);
  transition: transform 180ms ease;
  z-index: 4;
  display: flex;
  flex-direction: column;
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.06);
}
.pb-scene-inspector--open { transform: translateX(0); }

.pb-scene-inspector-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4) var(--space-3);
  border-bottom: 1px solid var(--grey-200);
}
.pb-scene-inspector-header-main { flex: 1; min-width: 0; }
.pb-scene-inspector-eyebrow {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--grey-500);
  font-weight: var(--font-medium);
}
.pb-scene-inspector-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--grey-900);
  margin-top: 2px;
}
.pb-scene-inspector-close {
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: var(--space-1);
  display: inline-flex;
  color: var(--grey-600);
  border-radius: var(--radius-sm);
}
.pb-scene-inspector-close:hover { color: var(--grey-900); background: var(--grey-100); }
.pb-scene-inspector-close:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 1px;
}

.pb-scene-inspector-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.pb-scene-inspector-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.pb-scene-inspector-section-title {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--grey-500);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}

.pb-scene-inspector-field { gap: 2px; }
.pb-scene-inspector-field label {
  font-size: var(--text-xs);
  color: var(--grey-700);
  font-family: var(--font-mono);
}
.pb-scene-inspector-input {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-sm);
  background: var(--white);
  color: var(--grey-900);
  box-sizing: border-box;
  width: 100%;
}
.pb-scene-inspector-input--ta {
  font-family: var(--font-mono);
  resize: vertical;
  min-height: 60px;
}
.pb-scene-inspector-input:disabled {
  background: var(--grey-50);
  color: var(--grey-700);
}
.pb-scene-inspector-save { align-self: flex-end; margin-top: var(--space-2); }

.pb-scene-inspector-geom > summary {
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--grey-700);
  padding: var(--space-1) 0;
}
.pb-scene-inspector-geom-pre {
  max-height: 200px;
  overflow: auto;
  font-size: 11px;
}

/* Attachments dropzone */
.pb-scene-inspector-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 120px;
  border: 1.5px dashed var(--grey-300);
  border-radius: var(--radius-md);
  background: var(--grey-50);
  color: var(--grey-600);
  padding: var(--space-3);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.pb-scene-inspector-dropzone:hover,
.pb-scene-inspector-dropzone.is-drag {
  border-color: var(--primary-red);
  background: var(--primary-red-tint);
  color: var(--grey-900);
}
.pb-scene-inspector-dropzone:focus-visible {
  outline: 2px solid var(--grey-700);
  outline-offset: 2px;
}
.pb-scene-dropzone-icon { font-size: 28px; color: inherit; }
.pb-scene-dropzone-text { font-size: var(--text-sm); }

.pb-scene-inspector-attachments {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.pb-attachment-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
  background: var(--white);
}
.pb-attachment-icon {
  font-size: var(--icon-lg);
  color: var(--grey-600);
  flex-shrink: 0;
}
.pb-attachment-meta { flex: 1; min-width: 0; }
.pb-attachment-name {
  font-size: var(--text-sm);
  color: var(--grey-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-attachment-size { font-size: var(--text-xs); color: var(--grey-500); }
.pb-scene-attachment-del {
  background: transparent;
  border: 0;
  color: var(--grey-500);
  cursor: pointer;
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  display: inline-flex;
}
.pb-scene-attachment-del:hover { color: var(--status-error); background: var(--grey-100); }

/* "Add from existing" picker modal sizing. */
.pb-modal:has(.pb-scene-picker) { max-width: 560px; }
.pb-scene-picker-body-host { padding: 0; max-height: 60vh; overflow-y: auto; }
.pb-scene-picker-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--grey-100);
  cursor: pointer;
}
.pb-scene-picker-row:hover { background: var(--grey-50); }
.pb-scene-picker-row input { margin: 0; }
.pb-scene-picker-geom { color: var(--grey-600); font-size: var(--icon-md); }
.pb-scene-picker-body { flex: 1; min-width: 0; }
.pb-scene-picker-title { font-size: var(--text-sm); color: var(--grey-900); font-weight: var(--font-medium); }
.pb-scene-picker-sub { font-size: var(--text-xs); color: var(--grey-500); }

/* ============ ICON SIZES ============ */

/* Material-symbols icons appear all over the app at a handful of sizes.
 * Use these utility classes on `<span class="material-symbols-outlined …">`
 * instead of inline `style={{ fontSize: Xpx }}`. */
.pb-icon-xs  { font-size: var(--icon-xs); }
.pb-icon-sm  { font-size: var(--icon-sm); }
.pb-icon-md  { font-size: var(--icon-md); }
.pb-icon-lg  { font-size: var(--icon-lg); }
.pb-icon-2xl { font-size: var(--icon-2xl); }

/* ============ CATALOGUE ============ */

/* Shared container for the Maps & Apps + Layers catalogues.
 * Toolbar row: search (flex-grow left) + view toggle (right).
 * Body: either `.pb-catalogue-grid` (cards) or `.pb-catalogue-list` (table). */
.pb-catalogue {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.pb-catalogue-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.pb-catalogue-search-wrap {
  position: relative;
  flex: 1 1 320px;
  min-width: 220px;
  max-width: 480px;
}
.pb-catalogue-search-icon {
  position: absolute;
  left: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  color: var(--grey-500);
  pointer-events: none;
}
.pb-catalogue-search {
  width: 100%;
  padding: var(--space-1) var(--space-3) var(--space-1) calc(var(--space-2) + var(--icon-sm) + var(--space-2));
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  background: var(--white);
}
.pb-catalogue-search:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 1px;
  border-color: var(--grey-400);
}

/* Gallery / List toggle. Single segmented button, pressed state on the
 * active mode. */
.pb-view-toggle {
  display: inline-flex;
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--white);
  /* Inside `.pb-catalogue-toolbar` (flex row), push to the far right so
   * the search keeps its natural left-anchored width and the toggle
   * anchors to the opposite edge. */
  margin-left: auto;
}
.pb-view-toggle-btn {
  background: transparent;
  border: 0;
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
  color: var(--grey-600);
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 36px;
  justify-content: center;
}
.pb-view-toggle-btn + .pb-view-toggle-btn {
  border-left: 1px solid var(--grey-300);
}
.pb-view-toggle-btn:hover { background: var(--grey-50); color: var(--grey-900); }
.pb-view-toggle-btn.is-active {
  background: var(--grey-100);
  color: var(--grey-900);
}
.pb-view-toggle-btn:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: -2px;
}

/* Gallery grid — shared by the Maps & Apps and Layers catalogues so they
 * lay out identically. (Historically there were two grids with different
 * track sizes — 280px vs 260px — which made the two sections look subtly
 * inconsistent. Use one track for both.) */
.pb-catalogue-grid,
.pb-product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-4);
}

/* Compact list table. */
.pb-catalogue-list-wrap { overflow: hidden; }
.pb-catalogue-list tbody tr { cursor: pointer; }
.pb-catalogue-row-name {
  color: var(--grey-900);
  font-weight: var(--font-medium);
  text-decoration: none;
}
.pb-catalogue-row-name:hover { text-decoration: underline; }

.pb-catalogue-empty { padding: var(--space-6) var(--space-4); }
.pb-card-foot-meta { font-size: var(--text-xs); }

/* Map view container for the catalogue. MapLibre mounts directly into
 * this div; see js/extent-map.js. Sized big enough to be useful without
 * pushing the rest of the page too far down. */
.pb-catalogue-map {
  width: 100%;
  height: 520px;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-50);
}
.pb-catalogue-map-empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--grey-600);
  font-size: var(--text-sm);
}

/* Layer cards — the Layers catalogue gallery. Compact card, anchor so the
 * whole surface is clickable. Icon left, metadata right. Contrast: the
 * product card is large with a thumbnail image; this one is identifier-first. */
.pb-layer-card {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--white);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--grey-900);
  transition: border-color 120ms, box-shadow 120ms;
}
.pb-layer-card:hover {
  border-color: var(--grey-300);
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.06));
}
.pb-layer-card:focus-visible {
  outline: 2px solid var(--primary-red);
  outline-offset: 2px;
}
.pb-layer-card-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--grey-50);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.pb-layer-card-icon .material-symbols-outlined {
  font-size: var(--icon-lg);
  color: var(--grey-700);
}
.pb-layer-card-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.pb-layer-card-title {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pb-layer-card-name {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: var(--text-xs);
}
.pb-layer-card-meta {
  font-size: var(--text-xs);
  color: var(--grey-700);
  margin-top: var(--space-1);
}
.pb-layer-card-count {
  font-size: var(--text-xs);
  color: var(--grey-900);
  font-weight: var(--font-medium);
}
.pb-layer-card-updated { font-size: var(--text-xs); }

/* ============ MAP POPUPS ============ */

/* MapLibre popup body (injected via setDOMContent). Keeps the content
 * compact and makes the "Open in Data" link feel like a button. */
.pb-popup-content {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-xs);
  min-width: 160px;
}
.pb-popup-id {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);
  color: var(--grey-800);
}
.pb-popup-id code {
  background: var(--grey-100);
  padding: 1px var(--space-1);
  border-radius: var(--radius-sm);
  word-break: break-all;
}
.pb-popup-open {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--grey-900);
  text-decoration: none;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--grey-100);
  font-weight: var(--font-medium);
}
.pb-popup-open:hover {
  background: var(--grey-200);
}

/* ============ UTILITIES ============ */

/* Defensive: make the `hidden` HTML attribute bulletproof against later
 * rules that set `display`. This exact pattern has bitten us three times
 * now (menu dropdown, field group, scene empty state). Keep it once
 * globally so component authors don't need per-class `[hidden]` overrides. */
[hidden] { display: none !important; }

/* Button classes are used on both `<button>` and `<a>` (for navigation-
 * flavoured actions like "Open external"). Anchors carry a default
 * underline that breaks the button look. */
a.btn-primary,
a.btn-secondary,
a.btn-tertiary,
a.btn-danger { text-decoration: none; }

.pb-muted { color: var(--grey-500); }
.pb-center { text-align: center; }
