/*
 * Tiseran Harvest - Main Stylesheet
 *
 * This file contains custom CSS that complements Tailwind CSS.
 * Tailwind is compiled separately via the tailwindcss-rails gem.
 */

/* ============================================
   Theme Variables (Light Mode Default)
   ============================================ */
:root {
  /* Background colors — warm stone tones instead of clinical pure grays */
  --color-bg-primary: #fafaf8;
  --color-bg-secondary: #f5f5f3;
  --color-bg-tertiary: #efefec;
  --color-bg-hover: #e7e5e4;

  /* Sidebar surface — distinctly darker than content to create visual hierarchy */
  --color-bg-sidebar: #eaeae7;
  --color-bg-sidebar-hover: #e0dfdc;
  --color-bg-sidebar-active: #d9d8d5;
  --color-border-sidebar: #d6d3d1;

  /* Text colors — warm darks for comfortable reading */
  --color-text-primary: #1c1917;
  --color-text-secondary: #44403c;
  --color-text-tertiary: #78716c;
  --color-text-muted: #a8a29e;

  /* Border colors — warm and subtle */
  --color-border-primary: #e7e5e4;
  --color-border-secondary: #d6d3d1;

  /* Accent colors — higher contrast for light backgrounds */
  --color-accent-blue: #2563eb;
  --color-accent-green: #059669;
  --color-accent-yellow: #d97706;
  --color-accent-red: #dc2626;
  --color-accent-purple: #7c3aed;

  /* Semantic colors — AA-passing on light backgrounds */
  --color-success: #059669;
  --color-warning: #d97706;
  --color-error: #dc2626;
  --color-info: #2563eb;

  /* Elevation */
  --shadow-card: 0 1px 3px rgba(28, 25, 23, 0.04), 0 1px 2px rgba(28, 25, 23, 0.03);
  --shadow-sidebar: none;

  /* Font family */
  --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
}

/* ============================================
   Dark Theme
   ============================================ */
[data-theme="dark"] {
  /* Background colors — neutral-warm darks, content area lifted for sidebar contrast */
  --color-bg-primary: #1e1e21;
  --color-bg-secondary: #2a2a2e;
  --color-bg-tertiary: #3f3f46;
  --color-bg-hover: #52525b;

  /* Sidebar surface — noticeably darker than content area */
  --color-bg-sidebar: #111113;
  --color-bg-sidebar-hover: #1a1a1d;
  --color-bg-sidebar-active: #242428;
  --color-border-sidebar: #2a2a2e;

  /* Text colors — slightly warm whites for comfortable reading */
  --color-text-primary: #fafaf9;
  --color-text-secondary: #e7e5e4;
  --color-text-tertiary: #a8a29e;
  --color-text-muted: #78716c;

  /* Border colors — visible against lifted content surface */
  --color-border-primary: #3f3f46;
  --color-border-secondary: #52525b;

  /* Accent colors — lighter variants for dark backgrounds, all AA-passing */
  --color-accent-blue: #60a5fa;
  --color-accent-green: #34d399;
  --color-accent-yellow: #fbbf24;
  --color-accent-red: #f87171;
  --color-accent-purple: #a78bfa;

  /* Semantic colors — matching lighter accents for dark mode */
  --color-success: #34d399;
  --color-warning: #fbbf24;
  --color-error: #f87171;
  --color-info: #60a5fa;

  /* Elevation — more pronounced in dark mode */
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.15);
  --shadow-sidebar: 2px 0 8px rgba(0, 0, 0, 0.3);
}

/* ============================================
   Base Styles
   ============================================ */
html {
  font-family: var(--font-sans);
}

/* ============================================
   Custom Utility Classes
   ============================================ */

/* Background utilities */
.bg-primary { background-color: var(--color-bg-primary); }
.bg-secondary { background-color: var(--color-bg-secondary); }
.bg-tertiary { background-color: var(--color-bg-tertiary); }
.bg-hover { background-color: var(--color-bg-hover); }
.bg-sidebar { background-color: var(--color-bg-sidebar); box-shadow: var(--shadow-sidebar); position: relative; z-index: 10; }
.bg-sidebar-hover { background-color: var(--color-bg-sidebar-hover); }
.bg-sidebar-active { background-color: var(--color-bg-sidebar-active); }
.bg-accent-blue { background-color: var(--color-accent-blue); }
/* Tinted fill for proportion bars sitting BEHIND row text (#1073's evidence panel).
   `bg-accent-blue/10` does not exist: the accent utilities above are handwritten here, not
   Tailwind theme colours, so the built stylesheet carries no rule for the opacity modifier
   and it renders nothing at all. color-mix keeps the tint theme-aware — --color-accent-blue
   flips in the dark block below, so one class covers both. */
.bg-accent-blue-tint { background-color: color-mix(in srgb, var(--color-accent-blue) 14%, transparent); }
.bg-accent-green { background-color: var(--color-accent-green); }
.bg-accent-yellow { background-color: var(--color-accent-yellow); }
.bg-accent-red { background-color: var(--color-accent-red); }
.bg-accent-purple { background-color: var(--color-accent-purple); }

/* Text utilities */
.text-primary { color: var(--color-text-primary); }
.text-secondary { color: var(--color-text-secondary); }
.text-tertiary { color: var(--color-text-tertiary); }
.text-muted { color: var(--color-text-muted); }
.text-accent-blue { color: var(--color-accent-blue); }
.text-accent-green { color: var(--color-accent-green); }
.text-accent-yellow { color: var(--color-accent-yellow); }
.text-accent-red { color: var(--color-accent-red); }
.text-accent-purple { color: var(--color-accent-purple); }

/* Border utilities */
.border-primary { border-color: var(--color-border-primary); }
.border-secondary { border-color: var(--color-border-secondary); }
.border-sidebar { border-color: var(--color-border-sidebar); }

/* ============================================
   Component Styles
   ============================================ */

/* Card component */
.card {
  background-color: var(--color-bg-secondary);
  border: 1px solid var(--color-border-primary);
  border-radius: 0.75rem;
  padding: 1.5rem;
  box-shadow: var(--shadow-card);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.card-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-text-primary);
}

/* Badge component */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 500;
  border-radius: 9999px;
}

.badge-success {
  background-color: rgba(5, 150, 105, 0.1);
  color: var(--color-success);
}

.badge-warning {
  background-color: rgba(217, 119, 6, 0.1);
  color: var(--color-warning);
}

.badge-error {
  background-color: rgba(220, 38, 38, 0.1);
  color: var(--color-error);
}

.badge-info {
  background-color: rgba(37, 99, 235, 0.1);
  color: var(--color-info);
}

.badge-neutral {
  background-color: var(--color-bg-tertiary);
  color: var(--color-text-secondary);
}

.badge-purple {
  background-color: rgba(124, 58, 237, 0.1);
  color: var(--color-accent-purple);
}

/* Details/summary chevron rotation */
details[open] > summary .chevron-icon {
  transform: rotate(90deg);
}

/* URL section tree (Pages > Structure): collapsed nodes hide their children.
   Chevron rotation is the Tailwind -rotate-90 class alone, toggled in sync
   with .collapsed — don't add a transform here, it would compose with the
   class's rotate property and flip the arrow 180°. */
.url-section-node.collapsed .url-section-children {
  display: none;
}

/* Hide default details marker across browsers */
details > summary { list-style: none; }
details > summary::-webkit-details-marker { display: none; }

/* Button component */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: 0.5rem;
  transition: all 0.15s ease;
  cursor: pointer;
}

.btn-primary {
  background-color: var(--color-accent-blue);
  color: white;
}

.btn-primary:hover {
  background-color: #1d4ed8;
}

.btn-secondary {
  background-color: var(--color-bg-tertiary);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-primary);
}

.btn-secondary:hover {
  background-color: var(--color-bg-hover);
}

.btn-danger {
  background-color: var(--color-error);
  color: white;
}

.btn-danger:hover {
  background-color: #dc2626;
}

/* Table component */

/* The container scrolls in BOTH axes, and that is load-bearing for the sticky
   headers below (#1125). `overflow-x: auto` alone already computes overflow-y
   to `auto` per spec, so this box was always a scroll container — but with no
   height bound it never actually scrolled vertically, which meant a sticky
   <thead> inside it would stick to a scrollport that never moves and sail off
   the top of the page with the rest of the table. Bounding the height makes the
   table its own scrollport, so the header row stays put at row 300.
   The bound is generous: short tables never reach it and look unchanged.

   The 14rem is a CHROME-HEIGHT BUDGET, not a cosmetic bound. `main` is the page
   scroller (the shell is h-screen/overflow-hidden), so the header holds its
   resting position for a table of any length as long as the container fits
   inside main's visible area — i.e. as long as 14rem covers everything above
   main plus main's own padding. Measured on Sites (2026-08-05): 85px of chrome
   above main + 48px padding = 133px used of 224px, ~91px slack; the org status
   banner eats into that when it renders. Grow the header or banner past the
   budget and long tables lose their sticky header silently — raise this
   together with the chrome. */
.table-container {
  overflow: auto;
  max-height: calc(100vh - 14rem);
  border: 1px solid var(--color-border-primary);
  border-radius: 0.75rem;
  box-shadow: var(--shadow-card);
}

.table,
.data-table {
  width: 100%;
  border-collapse: collapse;
}

/* Sticky column headers on every table using the shared styling (#1125,
   Notre Dame 2026-08-04): a portfolio table is hundreds of rows by design, and
   column meaning is exactly what the reader needs deep in one. The opaque
   background is required, not decorative — rows would otherwise show through.
   `border-collapse: collapse` drops a sticky row's own borders, so the header's
   separation comes from that background rather than a border. */
.table thead th,
.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}

.table th,
.data-table th {
  background-color: var(--color-bg-tertiary);
  padding: 0.75rem 1rem;
  text-align: left;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
  white-space: nowrap;
}

.table th.text-right,
.data-table th.text-right {
  text-align: right;
}

.table th.text-center,
.data-table th.text-center {
  text-align: center;
}

.table td,
.data-table td {
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--color-border-primary);
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}

.table tbody tr:hover,
.data-table tbody tr:hover {
  background-color: var(--color-bg-tertiary);
}

/* A column header whose meaning is a definition rather than a word (#1127).
   Rendered by TableHeadersHelper#column_header as an <abbr title>. The dotted
   underline is the affordance that a definition is there at all — without it
   the tooltip is undiscoverable.

   Known limits of this pragmatic choice, tracked in #1133: a `title` is a
   hover-only affordance in practice — NVDA and VoiceOver both need non-default
   settings to announce it, and it is unreachable by keyboard or touch. <abbr>
   also means *abbreviation*, which "Map Coverage" is not. A real tooltip
   pattern (focusable trigger + aria-describedby) is the proper fix. */
.column-term {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
  cursor: help;
}

/* Stats card */
.stat-card {
  background-color: var(--color-bg-secondary);
  border: 1px solid var(--color-border-primary);
  border-radius: 0.75rem;
  padding: 1.25rem;
  box-shadow: var(--shadow-card);
}

.stat-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--color-text-primary);
  line-height: 1;
}

.stat-label {
  font-size: 0.875rem;
  color: var(--color-text-tertiary);
  margin-top: 0.25rem;
}

.stat-change {
  font-size: 0.75rem;
  margin-top: 0.5rem;
}

.stat-change.positive {
  color: var(--color-success);
}

.stat-change.negative {
  color: var(--color-error);
}

/* Progress bar */
.progress-bar {
  width: 100%;
  height: 0.5rem;
  background-color: var(--color-bg-tertiary);
  border-radius: 9999px;
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  border-radius: 9999px;
  transition: width 0.3s ease;
}

.progress-bar-fill.success {
  background-color: var(--color-success);
}

.progress-bar-fill.warning {
  background-color: var(--color-warning);
}

.progress-bar-fill.error {
  background-color: var(--color-error);
}

.progress-bar-fill.info {
  background-color: var(--color-info);
}

/* Attention card (for issues needing review) */
.attention-card {
  background-color: var(--color-bg-secondary);
  border: 1px solid var(--color-border-primary);
  border-radius: 0.75rem;
  padding: 1rem 1.25rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  box-shadow: var(--shadow-card);
}

.attention-card.critical {
  border-left: 4px solid var(--color-error);
}

.attention-card.warning {
  border-left: 4px solid var(--color-warning);
}

.attention-card.info {
  border-left: 4px solid var(--color-info);
}

.attention-count {
  font-size: 1.5rem;
  font-weight: 700;
  min-width: 3rem;
}

.attention-count.critical {
  color: var(--color-error);
}

.attention-count.warning {
  color: var(--color-warning);
}

.attention-count.info {
  color: var(--color-info);
}

/* Form inputs */
.form-input {
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  background-color: var(--color-bg-primary);
  border: 1px solid var(--color-border-primary);
  border-radius: 0.5rem;
  color: var(--color-text-primary);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.form-input:focus {
  outline: none;
  border-color: var(--color-accent-blue);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

[data-theme="dark"] .form-input:focus {
  box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2);
}

.form-input::placeholder {
  color: var(--color-text-muted);
}

.form-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  background-position: right 0.5rem center;
  background-repeat: no-repeat;
  background-size: 1.5em 1.5em;
  padding-right: 2.5rem;
}

/* Dark mode icon visibility */
[data-theme="light"] .dark\:block { display: none; }
[data-theme="light"] .dark\:hidden { display: block; }
[data-theme="dark"] .dark\:block { display: block; }
[data-theme="dark"] .dark\:hidden { display: none; }

/* Spinner animation */
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.animate-spin {
  animation: spin 1s linear infinite;
}

/* Tabs */
.tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--color-border-primary);
}

.tab {
  padding: 0.75rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-text-tertiary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: all 0.15s ease;
  cursor: pointer;
}

.tab:hover {
  color: var(--color-text-primary);
}

.tab.active {
  color: var(--color-accent-blue);
  border-bottom-color: var(--color-accent-blue);
}

/* Details/disclosure chevron rotation */
details[open] .details-chevron {
  transform: rotate(180deg);
}

/* Empty state */
.empty-state {
  text-align: center;
  padding: 3rem 1.5rem;
}

.empty-state-icon {
  width: 4rem;
  height: 4rem;
  margin: 0 auto 1rem;
  color: var(--color-text-muted);
}

.empty-state-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-text-primary);
  margin-bottom: 0.5rem;
}

.empty-state-description {
  font-size: 0.875rem;
  color: var(--color-text-tertiary);
  max-width: 24rem;
  margin: 0 auto;
}

/* ============================================
   Workbench Pick Mode
   ============================================ */

/* Crosshair cursor over the preview pane when picking */
.workbench-preview.pick-mode-active {
  cursor: crosshair;
}

.workbench-preview.pick-mode-active * {
  cursor: crosshair;
}


/* ============================================
   Portfolio Treemap (dashboard)
   ============================================ */

/* Categorical series fills — validated with the dataviz palette checker
   against both card surfaces (#f5f5f3 light, #2a2a2e dark). Slot order is
   the CVD-safety mechanism: assign in fixed order, never cycle past 7 —
   the tail folds into "other"; undetected platforms are "unknown". */
:root {
  --viz-cat-1: #2a78d6;
  --viz-cat-2: #1baf7a;
  --viz-cat-3: #eda100;
  --viz-cat-4: #008300;
  --viz-cat-5: #4a3aa7;
  --viz-cat-6: #e34948;
  --viz-cat-7: #e87ba4;
  --viz-other: #a8a29e;
  --viz-unknown: #e0dedb;

  /* In-fill label ink, picked per fill luminance (light fills carry dark
     ink). Static per theme so no JS color probing is needed. */
  --viz-ink-1: #ffffff;
  --viz-ink-2: #ffffff;
  --viz-ink-3: #1c1917;
  --viz-ink-4: #ffffff;
  --viz-ink-5: #ffffff;
  --viz-ink-6: #ffffff;
  --viz-ink-7: #1c1917;
  --viz-ink-other: #1c1917;
  --viz-ink-unknown: #1c1917;
}

/* Map Currency status fills — state colors, not categorical series.
   Chromatic pair validated with the dataviz palette checker against both
   card surfaces (light: #059669/#dc2626 all-pass; dark: the chart-tuned
   #199e70/#e66767 steps — the text-tone semantic accents are too light for
   fills). Unverified is a deliberate neutral (the viz-other precedent),
   never a third hue; state identity always ships with a text label, and
   the completeness tables below the map are the table-view relief. */
:root {
  --currency-green: #059669;
  --currency-red: #dc2626;
  --currency-yellow: #a8a29e;
  --currency-ink-green: #ffffff;
  --currency-ink-red: #ffffff;
  --currency-ink-yellow: #1c1917;
  /* Nothing mapped (#1148) — the absence of a measure, not a fourth state of
     it, so it takes the categorical palette's "unknown" step (--viz-unknown,
     already contrast-validated against both card surfaces) rather than a step
     on the currency ramp. Not checked is the other neutral here, so the two
     are separated in lightness in BOTH themes — this one lighter in light,
     darker in dark — because two neighbouring greys would read as one scale. */
  --currency-unmapped: #e0dedb;
  --currency-ink-unmapped: #1c1917;
}

.currency-fill-green { background-color: var(--currency-green); color: var(--currency-ink-green); }
.currency-fill-red { background-color: var(--currency-red); color: var(--currency-ink-red); }
.currency-fill-yellow { background-color: var(--currency-yellow); color: var(--currency-ink-yellow); }
.currency-fill-unmapped { background-color: var(--currency-unmapped); color: var(--currency-ink-unmapped); }

.currency-dot {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 9999px;
  flex-shrink: 0;
}

/* Capture-age gradient within Unverified — a neutral sequential ramp,
   lightness-monotonic per theme (1 = recent, 4 = oldest/never). */
:root {
  --currency-age-1: #d6d3d1;
  --currency-age-2: #a8a29e;
  --currency-age-3: #78716c;
  --currency-age-4: #44403c;
}

.currency-age-1 { background-color: var(--currency-age-1); }
.currency-age-2 { background-color: var(--currency-age-2); }
.currency-age-3 { background-color: var(--currency-age-3); }
.currency-age-4 { background-color: var(--currency-age-4); }

[data-theme="dark"] {
  --currency-green: #199e70;
  --currency-red: #e66767;
  --currency-yellow: #6b6862;
  --currency-ink-green: #ffffff;
  --currency-ink-red: #ffffff;
  --currency-ink-yellow: #ffffff;
  --currency-unmapped: #3b3b3f;
  --currency-ink-unmapped: #ffffff;

  --currency-age-1: #52525b;
  --currency-age-2: #78716c;
  --currency-age-3: #a8a29e;
  --currency-age-4: #d6d3d1;
}

[data-theme="dark"] {
  --viz-cat-1: #3987e5;
  --viz-cat-2: #199e70;
  --viz-cat-3: #c98500;
  --viz-cat-4: #008300;
  --viz-cat-5: #9085e9;
  --viz-cat-6: #e66767;
  --viz-cat-7: #d55181;
  --viz-other: #6b6862;
  --viz-unknown: #3b3b3f;

  --viz-ink-1: #ffffff;
  --viz-ink-2: #ffffff;
  --viz-ink-3: #ffffff;
  --viz-ink-4: #ffffff;
  --viz-ink-5: #1c1917;
  --viz-ink-6: #ffffff;
  --viz-ink-7: #ffffff;
  --viz-ink-other: #ffffff;
  --viz-ink-unknown: #ffffff;
}

/* color sets the in-tile label ink (the label inherits from its tile). */
.viz-fill-1 { background-color: var(--viz-cat-1); color: var(--viz-ink-1); }
.viz-fill-2 { background-color: var(--viz-cat-2); color: var(--viz-ink-2); }
.viz-fill-3 { background-color: var(--viz-cat-3); color: var(--viz-ink-3); }
.viz-fill-4 { background-color: var(--viz-cat-4); color: var(--viz-ink-4); }
.viz-fill-5 { background-color: var(--viz-cat-5); color: var(--viz-ink-5); }
.viz-fill-6 { background-color: var(--viz-cat-6); color: var(--viz-ink-6); }
.viz-fill-7 { background-color: var(--viz-cat-7); color: var(--viz-ink-7); }
.viz-fill-other { background-color: var(--viz-other); color: var(--viz-ink-other); }
.viz-fill-unknown { background-color: var(--viz-unknown); color: var(--viz-ink-unknown); }

.treemap-root {
  position: relative;
}

.treemap-canvas {
  position: relative;
  width: 100%;
  height: 26rem;
  overflow: hidden;
}

.treemap-group {
  position: absolute;
  overflow: hidden;
}

.treemap-group-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 20px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0 2px;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
}

.treemap-group-header:hover {
  color: var(--color-text-primary);
  text-decoration: underline;
}

.treemap-group-header::after {
  content: attr(data-count);
  font-weight: 400;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Tiles separate via the 2px surface gap (1px inset each), never a border. */
.treemap-site {
  position: absolute;
  display: block;
  border-radius: 2px;
  overflow: hidden;
}

.treemap-site:hover,
.treemap-site:focus-visible {
  filter: brightness(1.12);
  outline: 2px solid var(--color-text-primary);
  outline-offset: -2px;
}

.treemap-site-label {
  display: block;
  padding: 1px 4px;
  font-size: 0.6875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.treemap-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 20;
  max-width: 20rem;
  padding: 0.375rem 0.625rem;
  background-color: var(--color-bg-primary);
  border: 1px solid var(--color-border-secondary);
  border-radius: 0.375rem;
  box-shadow: var(--shadow-card);
  font-size: 0.75rem;
  color: var(--color-text-secondary);
  pointer-events: none;
}

.treemap-tooltip strong {
  color: var(--color-text-primary);
}

.treemap-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1rem;
  margin-top: 0.75rem;
  font-size: 0.75rem;
  color: var(--color-text-secondary);
}

.treemap-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}

.treemap-swatch {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 2px;
  flex-shrink: 0;
}
