/* =========================================================================
   AirRE Design Tokens

   Direction: engineering console, not a marketing template. This is a tool
   an engineer uses daily to edit thresholds and matrices, so legibility and
   density matter more than decoration.

   Color:  ink #14181F, paper #FCFCFC (2026-07-20 — was #F5F6F4, flattened
           to match --paper-raised exactly per direct feedback for "more
           visual eye comfort"), slate (sidenav) #1B2430,
           sage accent #3B5240 (2026-07-19 — was a teal accent #1D7874;
           replaced app-wide per direct feedback so every accent use
           — buttons, focus rings, badges, active tabs — reads as one
           consistent sage-green family instead of two competing
           green hues. The `--teal`/`--teal-soft` variable NAMES were
           deliberately left as-is below to avoid touching every call
           site, including several in app.js that read them by name at
           runtime (getPropertyValue('--teal') for chart colors) — only
           their VALUES changed. Treat `--teal` as this app's "accent"
           token; the name is legacy, not a promise about the hue.),
           amber (fallback/warning) #C97A2B, hairline #DADFE3
   Type:   IBM Plex Sans (UI), IBM Plex Mono (data — thresholds, matrix
           values, version tags). The mono face is deliberate: this app's
           whole value proposition is precise, versioned engineering
           numbers, and monospace makes tabular data and version tags read
           as exactly that.
   Signature: the "version pill" — a small monospace badge carrying a
           Method Version tag (e.g. level1-matrix-v1). It appears next to
           every admin-editable value and every calculation result, making
           the reproducibility model (spec Section 11) visible in the UI
           itself rather than hidden in a database column.
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
  --ink: #14181f;
  --ink-soft: #4a5361;
  --paper: #fcfcfc; /* app-wide page background — was a slightly green-tinted #f5f6f4, 2026-07-20 per direct request ("more visual eye comfort") — now matches --paper-raised exactly, so cards/tables read as flush with the page (distinguished by their --hairline border only) rather than sitting on a faintly different tint. */
  --paper-raised: #fcfcfc; /* card/table surface — was pure white #ffffff, 2026-07-19 per direct request */
  --slate: #1b2430;
  --slate-soft: #2a3444;
  /* Legacy names, sage values (2026-07-19) — see the header comment
     above. --teal is this app's one accent color, now the same deep
     sage-green as the topbar/active-nav (--sage-dark) rather than a
     separate blue-green hue. --teal-soft is its pale-tint pairing, for
     badge backgrounds. */
  --teal: #3b5240;
  --teal-soft: #e3e8de;
  --teal-hover: #2c3f30;
  --teal-bright: #6f9468;
  --amber: #c97a2b;
  --amber-soft: #fbeddc;
  /* Lighter, easier-on-the-eyes burnt orange — .btn--recalc only (2026-07-20
     direct user feedback: the full-strength --amber button was too intense
     to stare at repeatedly). Every OTHER amber usage (readiness checklist,
     pathway badges, .btn--recalc-stale's border/glow) deliberately keeps
     the stronger --amber — this is a one-off, not a palette-wide change. */
  --amber-light: #dc9a5c;
  --amber-light-hover: #c9803d;
  --hairline: #dadfe3;
  --hairline-strong: #b7bfc6;

  /* Added 2026-07-19 (direct user request) — distinct colors for specific
     data-point icons/tiers that previously all shared --teal/--amber and
     were hard to tell apart at a glance (e.g. .priority-pill--high and
     .priority-pill--medium were BOTH --amber, differing only by dot fill).
     --lavender: "High" tier pills (Glazing Significance, Solar Heat Gain
     Management Potential), now visually distinct from "Medium" (--amber).
     --orange: Solar Exposure Potential's gauge icon (keyOutputHtml
     iconKey 'exposure'), everywhere it appears.
     --heat-red / --cool-blue: Climate Thermal Profile's thermometer icon,
     colored by which way the profile leans (Heating-leaning/Cooling-
     leaning) — "Balanced"/"Thermally Mild" keep the neutral --teal. */
  --lavender: #6b4f8a;
  --lavender-soft: #ece6f2;
  --orange: #e2720f;
  --heat-red: #c0392b;
  --cool-blue: #2f6690;

  /* Side navigation — soothing light sage, distinct from the dark --slate
     topbar. --sage-ink/--sage-ink-soft are dark, muted greens used for
     text/labels against this light background (the old sidenav was dark
     with light text, so those had to flip too, not just the background). */
  /* Deliberately muted/grayed-down rather than a bright minty sage — a
     lower-saturation resting background reads calmer and is easier to
     ignore while scanning, which is the point of a sidebar (it shouldn't
     compete with page content for attention). */
  --sage: #e1e5dc;
  --sage-hover: #d2d8c9;
  --sage-divider: #c8cec0;
  --sage-ink: #263524;
  --sage-ink-soft: #5c6f57;
  /* Darker sage for the topbar — deep enough for white text to stay
     comfortably readable, but a sage green rather than the old navy. */
  --sage-dark: #3b5240;
  --sage-dark-soft: #4c6650;
  --sage-dark-muted: #c8d6c5;

  --font-ui: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace;

  --radius-sm: 4px;
  --radius-md: 8px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  --sidenav-width: 240px;
  --topbar-height: 56px;
}

@media (prefers-reduced-motion: no-preference) {
  :root {
    --transition-fast: 120ms ease;
  }
}
@media (prefers-reduced-motion: reduce) {
  :root {
    --transition-fast: 0ms;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--paper);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--teal);
  color: white;
  padding: var(--space-2) var(--space-4);
  z-index: 100;
}
.skip-link:focus {
  left: var(--space-2);
  top: var(--space-2);
}

:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

/* ---------------------------- Layout shell ---------------------------- */

#app {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.topbar {
  height: var(--topbar-height);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-5);
  background: var(--sage-dark);
  color: white;
  border-bottom: 1px solid var(--sage-dark-soft);
}

.topbar__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.topbar__mark {
  width: 18px;
  height: 18px;
  border-radius: 3px;
  background: linear-gradient(135deg, var(--teal) 0%, var(--teal-bright) 100%);
  display: inline-block;
}

.topbar__meta {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.topbar__company {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--sage-dark-muted);
}

.shell {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
}

.sidenav {
  width: var(--sidenav-width);
  flex: 0 0 auto;
  background: var(--sage);
  color: var(--sage-ink);
  padding: var(--space-5) var(--space-3);
  overflow-y: auto;
  border-right: 1px solid var(--sage-divider);
}

.sidenav__list {
  list-style: none;
  margin: 0 0 var(--space-4) 0;
  padding: 0;
}

.sidenav__link {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--sage-ink);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 500;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.sidenav__link:hover {
  background: var(--sage-hover);
  color: var(--sage-ink);
}

.sidenav__link.is-active {
  /* Reuses the same deep sage as the topbar (--sage-dark) instead of
     --teal, so the active-tab highlight matches the sage theme rather
     than standing out as a leftover accent color. */
  background: var(--sage-dark);
  color: white;
  font-weight: 600;
}

.sidenav__divider {
  height: 1px;
  background: var(--sage-divider);
  margin: var(--space-4) var(--space-2);
}

.sidenav__label {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--sage-ink-soft);
  margin: 0 0 var(--space-2) var(--space-3);
}

/* max-width + margin-inline: auto centers the whole reading column
   within .main's available width on wide screens (2026-07-20, direct
   user feedback) — .page-header/.card both cap at 960px, but .main
   itself never did, so on any window meaningfully wider than that the
   capped content just sat flush against the sidenav with every bit of
   leftover space piling up on the right, reading as lopsided rather than
   intentionally spacious. Applied directly on .main (a flex item of
   .shell) rather than via an extra wrapper div — max-width still caps
   its rendered box below what flex-grow would otherwise give it, and the
   auto inline margins then center that box in the remaining space, same
   as a normal block element; no DOM/JS changes needed since every page
   already renders straight into this element. Doesn't change any
   individual page's own internal max-width (.page-header/.card keep
   theirs) — just where the extra room around them goes. */
.main {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--space-6);
  max-width: 1520px;
  margin-inline: auto;
}

/* Building module dashboard only (toggled by router() in app.js) — a
   landing/overview page meant to fit one screen with no scrolling, so it
   trades .main's normal generous padding for a tighter one. Every other
   page keeps the default above. */
.main--compact {
  padding: var(--space-4) var(--space-5);
}

/* ---------------------------- Page structure ---------------------------- */

/* STANDING UX RULE (2026-07-19): a page's primary action button lives in
   .page-header, right-aligned via justify-content: space-between — but
   .page-header itself was full-bleed (no max-width) while .card below it
   is capped at 960px. On any screen wider than ~960px that put the
   button far from the title AND far from the content card it acts on
   ("+ New Portfolio" sitting at the outer edge of a 2500px-wide window
   while the list below it stayed narrow) — easy to miss entirely, per
   direct user feedback (this is the same root cause the Glazing Asset
   Hub's Recalculate button had, fixed separately by moving it into its
   card; this fix instead makes the general pattern correct everywhere
   at once). Capping .page-header to the same max-width as .card means
   every page's primary button now sits directly above the content it
   relates to, never floating alone at the far edge of a wide window —
   this is the standard going forward for where an action button
   belongs: inside the same reading-width as its content, not pinned to
   the outer viewport. */
.page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  max-width: 960px;
  margin-bottom: var(--space-5);
  flex-wrap: wrap;
  gap: var(--space-3);
}

.page-header h1 {
  font-size: 20px;
  font-weight: 600;
  margin: 0;
}

.page-header__subtitle {
  color: var(--ink-soft);
  font-size: 13px;
  margin-top: var(--space-1);
}

/* Small muted explanatory text under a data-table value — e.g. the
   Climate Thermal Profile classification's plain-language explainer and
   HDD/CDD/R breakdown. Same visual weight as .page-header__subtitle but
   sized for use inside a table cell rather than under a page heading. */
.field-note {
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 400;
  margin-top: 2px;
  line-height: 1.4;
}

/* Level 1/1A/1B/2 breadcrumb — sits above a Level 1A result page's <h1>
   (see level1HierarchyHtml() in app.js) so a user always sees where this
   specific screen sits in the fuller hierarchy, not just its own name.
   1B/Level 2 are shown muted rather than hidden — they're real, planned
   next stages (see docs/Level1A_Level1B_Architecture_Scoping.md), just
   not built yet. */
/* 2026-07-20 (direct user feedback): this breadcrumb was competing
   visually with the page's actual <h1> right below it — same rough
   visual weight fighting for attention instead of clearly reading as
   secondary context. Toned down (smaller, lighter letter-spacing, the
   current crumb a touch less bold) and given more room to breathe before
   the title, without losing its job of showing where this screen sits in
   the fuller Stage 1-5 hierarchy. */
.assessment-hierarchy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: var(--space-3);
}
.assessment-hierarchy__crumb {
  color: var(--ink-soft);
}
.assessment-hierarchy__crumb.is-current {
  color: var(--teal);
  font-weight: 500;
}
.assessment-hierarchy__crumb.is-upcoming {
  color: var(--hairline-strong);
}
.assessment-hierarchy__sep {
  color: var(--hairline-strong);
}

/* STANDING UX RULE (2026-07-19): "key Assessment Output" values — Climate
   Thermal Profile, Annual SVF-adjusted Effective Solar Exposure, Exposure
   Class, and any future field of the same kind — get a small inline icon
   plus the app's one accent color, via keyOutputHtml() in app.js. This is
   the one way these values render anywhere in the app (Result table, the
   two All Assessments summary tables, Building Climate page), the same
   precedent as .pathway-badge being the one way pathway pills render —
   any new headline output should use keyOutputHtml() rather than a new
   one-off style. */
.key-output {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.key-output__icon {
  display: inline-flex;
  color: var(--teal);
  flex-shrink: 0;
}
.key-output__value {
  color: var(--teal);
  font-weight: 600;
}
/* Per-data-point color overrides (2026-07-19, direct user request) — see
   the --lavender/--orange/--heat-red/--cool-blue definitions in :root for
   why. Applied via a modifier class on the outer .key-output span from
   keyOutputHtml() itself, so every call site gets this for free. */
.key-output--exposure .key-output__icon,
.key-output--exposure .key-output__value {
  color: var(--orange);
}
.key-output--heat .key-output__icon,
.key-output--heat .key-output__value {
  color: var(--heat-red);
}
.key-output--cool .key-output__icon,
.key-output--cool .key-output__value {
  color: var(--cool-blue);
}

/* Level 1A Readiness checklist (Glazing Asset Hub page) — see
   level1ReadinessChecklistHtml() in app.js. Ready items use the app's
   accent color (--teal); missing items use --amber, the same "needs
   attention" color as .btn--recalc-stale / .pathway-badge--amber, so the
   semantics are consistent with the rest of the app rather than
   introducing a new color meaning. */
.readiness-list {
  list-style: none;
  margin: var(--space-3) 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.readiness-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}
.readiness-item__icon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  margin-top: 1px;
}
.readiness-item.is-ready .readiness-item__icon {
  background: var(--teal-soft);
  color: var(--teal);
}
.readiness-item.is-missing .readiness-item__icon {
  background: var(--amber-soft);
  color: var(--amber);
}
.readiness-item__label {
  font-weight: 500;
  font-size: 13px;
}

/* Narrow, low-width vertical bar chart for the 12 monthly average
   temperatures (see monthlyTempChartHtml() in app.js) — replaces a plain
   monospace text list per direct user feedback. Deliberately compact,
   not full-card-width: this is a small supporting figure, not a
   headline chart. */
.monthly-temp-chart {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  max-width: 260px;
  height: 84px;
  margin-top: var(--space-2);
}
.monthly-temp-chart__col {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  height: 100%;
}
.monthly-temp-chart__track {
  flex: 1;
  width: 9px;
  display: flex;
  align-items: flex-end;
  background: var(--sage);
  border-radius: 3px;
  overflow: hidden;
}
.monthly-temp-chart__bar {
  width: 100%;
  background: var(--teal-bright);
  border-radius: 3px 3px 0 0;
  min-height: 3px;
}
.monthly-temp-chart__label {
  font-size: 9px;
  color: var(--ink-soft);
  margin-top: 3px;
  font-family: var(--font-mono);
}

.card {
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
  max-width: 960px;
}

.card h2 {
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 var(--space-3) 0;
}

/* Result card (renderLevel1AssessmentResult's main "Result" card, plus
   the equivalent Stage 1B result) — 2026-07-20, direct user feedback:
   this specific card reads a bit cramped at the default .card padding,
   more so than a form or list card, since it's the one place holding a
   dense data table, a chart, and several inline notes all at once.
   Deliberately symmetric left/right (not a left-only nudge, which would
   break alignment with .page-header/other .card elements sharing the
   same left edge above it) — same max-width, same left edge, just more
   breathing room on both sides and a touch more at the bottom under the
   chart. Narrower screens fall back to the standard --space-5 padding
   rather than keeping the wide desktop spacing, which would eat into
   already-limited width there. */
.card--result {
  padding: 40px 52px 48px;
}
@media (max-width: 720px) {
  .card--result {
    padding: var(--space-5);
  }
}

/* ---------------------------- Version pill (signature element) ---------------------------- */

.version-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 2px var(--space-2);
  border-radius: 999px;
  background: var(--teal-soft);
  color: var(--teal);
  border: 1px solid rgba(29, 120, 116, 0.25);
  white-space: nowrap;
}

.version-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--teal);
  flex: 0 0 auto;
}

.version-pill--fallback {
  background: var(--amber-soft);
  color: var(--amber);
  border-color: rgba(201, 122, 43, 0.3);
}
.version-pill--fallback::before {
  background: var(--amber);
}

/* ---------------------------- Pathway badge ----------------------------
   Turns each Level 1 pathway's stored icon/uiColor metadata (previously
   unused — see admin-level1-pathways.md) into an actual visual treatment.
   Same visual language as .version-pill above (rounded pill, small icon,
   soft background/solid accent pair) for consistency, not a new pattern.

   uiColor values don't map 1:1 onto a --COLOR/--COLOR-soft pair the way
   .version-pill's teal/amber do: 'slate'/'slate-soft' in this app's
   design tokens are DARK navy tones meant for the sidebar/topbar, not a
   light pill background — using them literally here would render
   unreadable dark-on-dark pills. So this is a curated map, not a
   generic var(--uiColor)/var(--uiColor-soft) substitution. Any uiColor
   not in this list (including null, from resolvePathwayDetails()'s
   "Unknown Pathway" fail-safe) falls through to --pathway-badge--neutral,
   which mirrors .version-pill--fallback's amber warning treatment. */
.pathway-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  padding: 3px var(--space-2) 3px 6px;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}

.pathway-badge svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
}

.pathway-badge--teal {
  background: var(--teal-soft);
  color: var(--teal);
  border-color: rgba(29, 120, 116, 0.25);
}

.pathway-badge--amber {
  background: var(--amber-soft);
  color: var(--amber);
  border-color: rgba(201, 122, 43, 0.35);
}

/* Same color family as --amber, but a lighter border and no background
   fill — reads as one notch lower urgency than .pathway-badge--amber,
   matching the Medium-vs-High priority distinction between
   'reduce-solar-gain' (this) and 'solar-control-assessment' (full amber). */
.pathway-badge--amber-soft {
  background: var(--paper-raised);
  color: var(--amber);
  border-color: rgba(201, 122, 43, 0.3);
}

/* Neutral/muted treatment for the two lowest-priority pathways
   (comfort-assessment, low-priority — uiColor 'slate-soft' in the data).
   Deliberately NOT var(--slate)/var(--slate-soft) — see comment above. */
.pathway-badge--neutral {
  background: var(--hairline);
  color: var(--ink-soft);
  border-color: var(--hairline-strong);
}

/* ---------------------------- Priority pill ----------------------------
   A pathway's priority (High/Medium/Low, from admin-level1-pathways —
   see pathwayBadgeHtml() above for the same source data's icon/color
   treatment) rendered as a small colored dot + text, matching
   .version-pill's established "dot + monospace label" visual language
   rather than introducing a new pattern. Reuses --amber at full/outline/
   muted intensity for the 3 tiers instead of a 3rd color family — keeps
   this reading as "how much does this matter," not a fourth unrelated
   color competing with the pathway badges' own teal/amber/neutral set. */
.priority-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.priority-pill::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
  box-sizing: border-box;
}

.priority-pill--high {
  /* --lavender, not --amber (2026-07-19, direct user request) — previously
     identical to --medium below except for the dot fill style, which made
     "High" and "Medium" hard to tell apart at a glance in a table full of
     these pills. Now each tier reads as a genuinely different color. */
  color: var(--lavender);
}
.priority-pill--high::before {
  background: var(--lavender);
}

.priority-pill--medium {
  color: var(--amber);
}
.priority-pill--medium::before {
  background: transparent;
  border: 2px solid var(--amber);
}

.priority-pill--low {
  color: var(--ink-soft);
}
.priority-pill--low::before {
  background: var(--hairline-strong);
}

.priority-pill--unknown {
  color: var(--ink-soft);
}
.priority-pill--unknown::before {
  background: transparent;
  border: 1px dashed var(--hairline-strong);
}

/* ---------------------------- All Buildings (card grid) ---------------------------- */

.buildings-toolbar {
  display: flex;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.buildings-toolbar input[type='search'] {
  flex: 1 1 auto;
  max-width: none;
}
.buildings-toolbar select {
  flex: 0 0 180px;
  max-width: none;
}

.buildings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-4);
}

.building-card {
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  cursor: pointer;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.building-card:hover {
  border-color: var(--hairline-strong);
  box-shadow: 0 2px 8px rgba(20, 24, 31, 0.06);
}

.building-card__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: var(--space-3);
}

.building-card__icon {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  flex: 0 0 auto;
}
.building-card__icon svg {
  width: 22px;
  height: 22px;
}

.building-card h3 {
  margin: 0 0 var(--space-1) 0;
  font-size: 16px;
}

.building-card p {
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
}

.building-card__divider {
  border: none;
  border-top: 1px solid var(--hairline);
  margin: var(--space-3) 0;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 600;
  padding: 3px var(--space-2);
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  white-space: nowrap;
}
.status-pill--not-started {
  color: var(--ink-soft);
  border-color: var(--hairline);
}
.status-pill--in-progress {
  color: var(--amber);
  border-color: rgba(201, 122, 43, 0.35);
}
.status-pill--complete {
  color: var(--teal);
  border-color: rgba(29, 120, 116, 0.3);
}

/* ---------------------------- Data tables (matrices, thresholds) ---------------------------- */

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.data-table th,
.data-table td {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--hairline);
}

.data-table th {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  font-weight: 500;
}

/* Scoped modifier for label/value two-column data-tables (e.g. the
   assessment Result table) — NOT applied to .data-table globally, since
   most data-tables here are multi-column matrices/lists where auto
   column sizing is correct. Without this, the label column's width
   auto-sizes to its OWN longest label ("Annual SVF-adjusted Effective
   Solar Exposure"), which left a wide dead-space gap before short
   labels' values lined up at that same wide boundary — direct user
   feedback. Capping the label column narrows that gap; long labels wrap
   onto a second line instead, which is the intended trade-off here. */
.data-table--narrow-label td:first-child,
.data-table--narrow-label th:first-child {
  width: 180px;
  max-width: 180px;
}

.data-table td.is-numeric,
.data-table td[data-type='number'] {
  font-family: var(--font-mono);
}

.data-table tr:hover td {
  background: var(--paper);
}

/* Whole-row navigation (2026-07-19) — replaces a trailing "View Full
   Result" button-per-row on the assessment tables (per direct user
   feedback: the row already carries all the context, a dedicated button
   column was redundant). Wired via a single delegated click/keydown
   listener on #app (see wireClickableTableRows in app.js) rather than
   per-row listeners, so it survives tab switches and in-place re-renders
   without needing to be re-attached. tabindex+role make it keyboard-
   reachable, not just mouse-clickable. */
tr[data-href],
tr.entity-list-row--inline-edit,
tr.storey-row {
  cursor: pointer;
}
tr[data-href]:hover td,
tr.entity-list-row--inline-edit:hover td,
tr.storey-row:hover td {
  background: var(--sage-dark-muted);
}
tr[data-href]:focus-visible,
tr.entity-list-row--inline-edit:focus-visible,
tr.storey-row:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

.data-table__editable {
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  font-family: var(--font-mono);
  font-size: 13px;
  width: 100%;
  background: transparent;
}
.data-table__editable:hover {
  border-color: var(--hairline-strong);
}
.data-table__editable:focus {
  border-color: var(--teal);
  background: white;
}

.fallback-row td {
  color: var(--ink-soft);
}

/* ---------------------------- Buttons / forms ---------------------------- */

.btn {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

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

.btn--ghost {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.25);
  color: white;
}
.btn--ghost:hover {
  background: rgba(255, 255, 255, 0.08);
}

.btn--secondary {
  background: var(--paper-raised);
  border-color: var(--hairline-strong);
  color: var(--ink);
}
.btn--secondary:hover {
  border-color: var(--ink-soft);
}

/* Glazing Asset Hub's Run Assessment / Recalculate button — deliberately
   NOT just .btn--primary (2026-07-19). That reused the same teal as
   every other button on the page (Save, tab buttons' active state), so
   it read as just another form control rather than the primary action —
   easy to miss entirely at a glance, per direct user feedback. Bigger,
   bolder, and its own amber accent (already established elsewhere as
   this app's "needs attention" color — see .pathway-badge--amber /
   --amber) makes it visually distinct from the rest of the form even
   before considering the --stale state below. */
.btn--recalc {
  background: var(--amber-light);
  color: white;
  font-size: 15px;
  font-weight: 600;
  padding: 12px 28px;
  border-radius: var(--radius-md);
  box-shadow: 0 2px 8px rgba(220, 154, 92, 0.3);
}
.btn--recalc:hover {
  background: var(--amber-light-hover);
}

/* Stronger still — an already-saved assessment's real inputs (Orientation,
   Directional SVF, Area) have changed since it was last computed, so the
   displayed result no longer matches what's on the form. See
   assessmentInputsAreStale() in app.js.
   Light-highlight treatment (2026-07-19, direct user request — the old
   solid amber fill + reddish glow border read as too intense/alarming for
   something that just means "click Recalculate when convenient," not an
   error) — reuses --amber-soft, the same pale tint already used for this
   app's banner-card "needs attention" callouts elsewhere, with burnt-
   orange text/border on top instead of a bold solid fill + white text. */
.btn--recalc-stale {
  background: var(--amber-soft);
  color: #b3401f;
  border: 2px solid #b3401f;
  box-shadow: 0 0 0 3px rgba(179, 64, 31, 0.12);
}
.btn--recalc-stale:hover {
  background: #f5ddc0;
}

/* Shared wrapper for every tab-button row in the app (Building Profile,
   Glazing Asset Hub, Building Glazing page, and the generic tabbed entity
   form) — extra margin above/below and a darker/thicker divider than a
   plain .card border, so the tab row reads as a distinct navigation
   element instead of blending into the field grid above and below it. */
.entity-form-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 2px solid var(--hairline-strong);
  margin-top: var(--space-5);
  margin-bottom: var(--space-5);
}

.entity-form-tab-btn {
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  padding: var(--space-2) var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: 13.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  cursor: pointer;
  margin-right: var(--space-3);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.entity-form-tab-btn:hover {
  color: var(--ink);
}
.entity-form-tab-btn.is-active {
  color: var(--teal);
  border-bottom-color: var(--teal);
  font-weight: 700;
}

/* Nested "section" sub-tabs inside the Compare Assets tab (2026-07-20,
   direct user request — splits one wide all-fields table into the same
   Geometry/Specification/Manufacturer/Installation Year/Existing
   Measures/Condition sections the Glazing Asset Hub itself uses).
   Deliberately separate class names from .entity-form-tab-btn/
   .entity-form-tab-panel — see wireCompareAssetsTab's own comment for
   why reusing those would break the outer tab handler. Visually one step
   down in weight (smaller text, thinner underline, lighter divider) so
   it reads as a sub-level of navigation under the outer tabs. */
.cmp-assets-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px solid var(--hairline);
  margin-top: var(--space-3);
  margin-bottom: var(--space-3);
}
.cmp-assets-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  cursor: pointer;
  margin-right: var(--space-2);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.cmp-assets-tab-btn:hover {
  color: var(--ink);
}
.cmp-assets-tab-btn.is-active {
  color: var(--teal);
  border-bottom-color: var(--teal);
  font-weight: 700;
}

/* Compare Assets table cell states. .cmp-cell--mismatch reuses the same
   amber "needs attention" semantics as .btn--recalc-stale/
   .field-status-badge (see those comments) rather than inventing a new
   color meaning. */
.cmp-cell--missing {
  color: var(--ink-soft);
  font-style: italic;
}
.cmp-cell--mismatch {
  background: var(--amber-soft);
}
.cmp-flag {
  color: #b3401f;
  cursor: help;
}

/* "All Glazing Assets" tab's own Overview/Compare Assets Inputs
   sub-tabs (2026-07-20, direct user request — see
   renderGlazingAssetsOverviewTabsHtml's own comment). Same visual
   treatment as .cmp-assets-tab-btn (one step down from the outer
   page-level tabs) but its own class names, since this is a THIRD,
   independent nesting level — see wireGlazingAssetsOverviewTabs's own
   comment on why none of these three tab levels share class names. */
.glz-assets-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-3);
}
.glz-assets-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  cursor: pointer;
  margin-right: var(--space-2);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.glz-assets-tab-btn:hover {
  color: var(--ink);
}
.glz-assets-tab-btn.is-active {
  color: var(--teal);
  border-bottom-color: var(--teal);
  font-weight: 700;
}

/* "All Assessments" tab's own Stage 1A/1B/2/3 sub-tabs (2026-07-20,
   direct user request: "Add Tabs for Each Stage"). Same visual treatment
   as .cmp-assets-tab-btn/.glz-assets-tab-btn (one step down from the
   outer page-level tabs) but its own class names — a FOURTH, independent
   nesting level, same "don't share class names across nesting levels"
   reasoning as those two. */
.stage-assess-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-3);
}
.stage-assess-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  cursor: pointer;
  margin-right: var(--space-2);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.stage-assess-tab-btn:hover {
  color: var(--ink);
}
.stage-assess-tab-btn.is-active {
  color: var(--teal);
  border-bottom-color: var(--teal);
  font-weight: 700;
}

/* Façades & Floors module page (2026-07-20, direct user request): the
   "Façades" and "Floors" outer tabs each got their own Overview/Registry/
   Share & Access sub-tabs. Same visual treatment as .stage-assess-tab-btn
   etc. but two more independent class families — .facades-tab-btn for
   the Façades outer tab's own sub-tabs, .floors-tab-btn for the Floors
   outer tab's own sub-tabs — same "own class family per nesting level"
   reasoning as those other tab families (the outer tab click handler
   queries its class name globally on root, so reusing a name risks one
   tab's click handler toggling a completely different tab's panels). */
.facades-tabs-row,
.floors-tabs-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-3);
}
.facades-tab-btn,
.floors-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  cursor: pointer;
  margin-right: var(--space-2);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.facades-tab-btn:hover,
.floors-tab-btn:hover {
  color: var(--ink);
}
.facades-tab-btn.is-active,
.floors-tab-btn.is-active {
  color: var(--teal);
  border-bottom-color: var(--teal);
  font-weight: 700;
}

.spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid var(--hairline-strong);
  border-top-color: var(--teal);
  border-radius: 50%;
  animation: spinner-rotate 0.7s linear infinite;
  flex: 0 0 auto;
}
@keyframes spinner-rotate {
  to {
    transform: rotate(360deg);
  }
}

/* Every Module Block on the Building dashboard must be the same width as
   its grid cell (2026-07-20, direct user request: "Make all Module
   Blocks size width to match the Building Profile Module Block size") —
   .card's own base rule sets max-width: 960px, meant for full-width
   content cards on other pages, but that cap could still leave a module
   card narrower than its grid track (and inconsistent with its
   siblings) on a very wide viewport. Explicitly overridden here so every
   module tile always stretches to fill its assigned grid column,
   regardless of screen width. */
.module-card {
  max-width: none;
  width: 100%;
  box-sizing: border-box;
}
.module-card:hover {
  border-color: var(--teal);
}
.module-card--disabled {
  opacity: 0.6;
}
.module-card--disabled:hover {
  border-color: var(--hairline-strong);
}

label {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  margin-bottom: var(--space-1);
  color: var(--ink-soft);
}

/* Required-field marker (2026-07-19, direct user request — "Add Dark
   Astrix to Required Fields") — appended to a label via
   requiredAsteriskHtml() in app.js, the single shared helper every entity
   form's label rendering calls. Deliberately dark/near-black rather than
   the conventional bright red, per the exact request ("Dark Astrix"). */
.required-asterisk {
  color: var(--ink);
  font-weight: 700;
}

/* Structured Field/Value/Source-status row editor (2026-07-19 "Phase 2" —
   direct user-designed spec from the Input UX Design conversation): every
   tab on the Glazing Asset Hub renders its fields as ROWS in one table —
   Field (+ optional "?" tooltip) | Value | Source status — instead of the
   old 2-column label-above-input grid. See renderGlazingAssetHubRowHtml()/
   glazingAssetFieldStatusHtml() in app.js. Applies to every tab for
   consistency, even tabs whose fields have no calculated counterpart (a
   plain row with an empty status cell, same visual shape throughout). */
.structured-field-table {
  width: 100%;
  border-collapse: collapse;
}

.structured-field-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}

.structured-field-table tr:last-child td {
  border-bottom: none;
}

.structured-field-table td.field-row__label {
  width: 34%;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-soft);
  padding-top: calc(var(--space-2) + 6px); /* roughly vertically centers against the value column's input */
}

/* 2026-07-20, direct user request — "Tool Tip icon should sit on top
   right of label - common standard, not at the bottom." Previously the
   "?" icon was just the next inline element after the label text, so on
   a long/wrapping label it fell wherever the last line ended (often
   bottom-left). A flex row with the label text allowed to wrap and the
   icon pinned via align-items: flex-start keeps the icon anchored at the
   top of the cell, on the right edge, regardless of label length. */
.field-row__label-inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 6px;
}

.field-row__label-inner label {
  flex: 1 1 auto;
  min-width: 0;
}

.structured-field-table td.field-row__value input,
.structured-field-table td.field-row__value select,
.structured-field-table td.field-row__value textarea {
  max-width: none;
  width: 100%;
}

/* 2026-07-20, direct user request — "Give the value area a subtle hover
   state; show the input border only during editing." An always-visible
   border on every row reads as more "form-like"/cluttered than the
   reference mockup wanted; borderless-by-default with a hover/focus
   reveal keeps the row looking like plain data until you actually
   interact with it. Deliberately excludes [readonly] inputs (Glazing
   Area, Directional SVF) — those keep their own permanent grey
   "Calculated" styling from renderGlazingAssetHubControlHtml, since they
   can never be edited regardless of hover/focus. */
.structured-field-table td.field-row__value input:not([readonly]),
.structured-field-table td.field-row__value select {
  border-color: transparent;
  background: transparent;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.structured-field-table td.field-row__value input:not([readonly]):hover,
.structured-field-table td.field-row__value select:hover {
  border-color: var(--hairline-strong);
  background: white;
}
.structured-field-table td.field-row__value input:not([readonly]):focus,
.structured-field-table td.field-row__value select:focus {
  border-color: var(--teal);
  background: white;
}

/* "Required" status-column text (2026-07-20, direct user request — the
   mockup's Field/Value/Type table showed Façade as "Required", distinct
   from the plain-grey "Entered"/"Override" text next to it). A warm
   accent rather than the muted grey the other plain-text statuses use,
   so an incomplete required field stays noticeable at a glance without
   the alarm of a full red/error treatment. */
.field-status-required {
  color: var(--amber);
  font-weight: 500;
}

/* "Advanced inputs" collapsible group (2026-07-20, direct user request —
   Area/SVF/Ground Albedo overrides tucked behind a disclosure so the
   primary Geometry table stays short/scroll-free; see
   renderGlazingAssetHubContent's advancedFields split). Native <details>
   for free keyboard/accessibility support — no custom JS toggle needed. */
.advanced-inputs-details {
  margin-top: var(--space-3);
  border-top: 1px solid var(--hairline);
  padding-top: var(--space-2);
}

.advanced-inputs-details summary {
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-soft);
  list-style: revert;
}

.advanced-inputs-details__hint {
  margin-left: var(--space-2);
  font-weight: 400;
  color: var(--ink-soft);
  opacity: 0.7;
}

.advanced-inputs-details table.structured-field-table {
  margin-top: var(--space-2);
}

.structured-field-table td.field-row__status {
  width: 140px;
  font-size: 11.5px;
  color: var(--ink-soft);
  padding-top: calc(var(--space-2) + 6px);
  white-space: nowrap;
}

/* "Calculated" / "Inherited (Façade)" badges — distinct from the plain
   muted "Override" text label, so a glance down the status column tells
   you which rows are computed-for-you vs. which are your own entry. */
.field-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 500;
  white-space: nowrap;
}

.field-status-badge--calculated {
  background: var(--teal-soft);
  color: var(--teal);
}

.field-status-badge--inherited {
  background: var(--sage-dark-muted);
  color: var(--sage-dark);
}

.field-status-badge__icon {
  width: 10px;
  height: 10px;
}

/* Circled "?" tooltip icon beside a column label (2026-07-19 spec, direct
   user request — hover AND keyboard-focus AND tap-to-open on mobile; kept
   to 2-3 sentences; never used for required-entry/error instructions). */
.field-tooltip {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
  cursor: help;
  vertical-align: middle;
}

.field-tooltip__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid var(--ink-soft);
  font-size: 10px;
  line-height: 1;
  color: var(--ink-soft);
  font-family: var(--font-mono);
  user-select: none;
}

.field-tooltip__bubble {
  display: none;
  position: absolute;
  bottom: 130%;
  left: 50%;
  transform: translateX(-50%);
  width: 220px;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: white;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  white-space: normal;
  z-index: 20;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

/* Hover and keyboard-focus both open it natively via CSS; wireFieldTooltips()
   in app.js adds a click/tap toggle (.is-open) for mobile, where hover
   doesn't fire reliably. */
.field-tooltip:hover .field-tooltip__bubble,
.field-tooltip:focus-visible .field-tooltip__bubble,
.field-tooltip.is-open .field-tooltip__bubble {
  display: block;
}

/* Generic file upload (2026-07-20, direct user request) — Photos fields
   (Glazing Assets, Façades) and every Source of Data evidence upload
   share this one chip-strip look. See renderFileUploadFieldHtml/
   wireFileUploadField in app.js. */
.file-upload__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.file-upload__chips:empty {
  margin-bottom: 0;
}
.file-upload__chip {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: 160px;
  padding: 4px 22px 4px 6px;
  border: 1px solid var(--hairline-strong);
  border-radius: 6px;
  background: var(--paper-raised);
  font-size: 12px;
}
.file-upload__thumb {
  width: 28px;
  height: 28px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
}
.file-upload__doc-icon {
  font-size: 16px;
  flex-shrink: 0;
}
.file-upload__filename {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-soft);
}
.file-upload__remove-btn {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 16px;
  height: 16px;
  line-height: 14px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--hairline-strong);
  color: var(--paper);
  font-size: 12px;
  cursor: pointer;
}
.file-upload__remove-btn:hover {
  background: var(--ink-soft);
}

/* Source of Data tab — one row per tracked field, grouped under a
   category heading, inside the SAME .structured-field-table row shape
   every other Glazing Asset Hub tab uses (Field | Value | Status). See
   renderSourceOfDataTabHtml/renderSourceOfDataFieldHtml/
   wireSourceOfDataTab in app.js.
   UPDATED 2026-07-20 (direct user feedback: "You've again diverged from
   the simple, clean, compact UX Input Form Design we set as the rule")
   — this used to be a bordered/padded "card" per field
   (.sod-field-card, removed); now the Source select + its evidence
   sub-fields + Recorded By/On all sit plainly inside one Value cell,
   separated only by spacing/a thin dashed rule, matching the rest of
   this page's compact, borderless-until-focused look. */
.sod-category {
  margin-bottom: var(--space-4);
}
.sod-category:last-child {
  margin-bottom: 0;
}
.sod-evidence:not(:empty) {
  margin-top: var(--space-2);
}
.sod-evidence-block > div {
  margin-bottom: var(--space-2);
}
.sod-evidence-block > div:last-child {
  margin-bottom: 0;
}
.sod-recorded {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px dashed var(--hairline);
}
.sod-recorded > div {
  flex: 1;
}

/* Access grants table (2026-07-19, direct user request — "Change UX to
   columns, rows format with Inline edits and add Edit/Save Button + Remove
   Button. Follow this Access UI/UX Format as a design theme where ever
   Access is used.") — see accessGrantsHtml()/wireAccessGrantsSection() in
   app.js, the ONE Access UI shared by Portfolios, Buildings, Storeys,
   Façades, and Glazing Assets. */
.access-grants {
  grid-column: 1 / -1; /* spans both columns of the surrounding 2-col form grid, same as a full-width section */
}

.access-grants label {
  display: block;
}

.access-grants-table {
  margin-top: var(--space-2);
}

.access-grants-table td {
  vertical-align: middle;
}

/* Rows use the shared input styling, but scoped tighter/inline since
   they live inside a table cell, not a standalone label+input block. */
.access-grant-input {
  max-width: none;
  padding: var(--space-1) var(--space-2);
  font-family: inherit;
}

.access-grant-input[readonly] {
  background: var(--paper);
  border-color: transparent;
  color: var(--ink-soft);
  cursor: default;
}

/* Shared small icon-button treatment — Edit/Save (pencil <-> check) and
   Remove on each Access grant row. Deliberately understated (no visible
   border/background at rest) since a row can have two of these sitting
   right next to a plain-looking input; a heavier button style would
   compete with the table's own row hover state instead of sitting quietly
   inside it. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  margin-left: var(--space-1);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}

.icon-btn:hover {
  background: var(--sage-dark-muted);
  color: var(--ink);
}

.icon-btn:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
}

.access-grant-remove-btn:hover {
  background: var(--amber-soft);
  color: #b3401f;
}

input,
select {
  font-family: var(--font-mono);
  font-size: 13px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  background: white;
  color: var(--ink);
  width: 100%;
  max-width: 480px;
  box-sizing: border-box;
}
input:focus,
select:focus {
  border-color: var(--teal);
}

textarea {
  font-family: var(--font-mono);
  font-size: 13px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  background: white;
  color: var(--ink);
  width: 100%;
  max-width: 480px;
  box-sizing: border-box;
  resize: vertical;
}
textarea:focus {
  border-color: var(--teal);
}

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

.login-gate {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  z-index: 50;
}

.login-gate[hidden] {
  display: none;
}

.login-gate__card {
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  width: 320px;
  text-align: center;
}

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

.empty-state {
  text-align: center;
  padding: var(--space-6) var(--space-4);
  color: var(--ink-soft);
}

.empty-state h3 {
  color: var(--ink);
  font-size: 15px;
  margin-bottom: var(--space-2);
}

/* ---------------------------- Responsive ---------------------------- */

@media (max-width: 900px) {
  .shell {
    flex-direction: column;
  }
  .sidenav {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: var(--space-3);
    gap: var(--space-1);
  }
  .sidenav__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin: 0;
  }
  .sidenav__divider {
    display: none;
  }
  .sidenav__label {
    width: 100%;
    margin-top: var(--space-2);
  }
  .main {
    padding: var(--space-4);
  }
  .topbar {
    padding: 0 var(--space-3);
  }
  .topbar__company {
    display: none;
  }
}

@media (max-width: 560px) {
  .page-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .data-table {
    font-size: 12px;
  }
}
