/**
 * DESIGN TOKENS & CSS VARIABLES
 * Emerging brand palette + typography + spacing + scales
 *
 * EDITORIAL LIGHT. The page is paper: light ground, ink type, hairline rules.
 * Two things stay exactly as they were, because they are the brand:
 *   1. the Digital Leaders blue banner (--color-dl-blue, #1839E2)
 *   2. the accent, which is Emerging orange (--color-orange, #FF4901)
 *
 * Gold (#DBB67D) has been retired from this interface. It is the GEURS
 * colour and does not belong to Digital Leaders. --color-gold is kept as an
 * alias so no rule breaks, but it now resolves to the orange accent.
 */

:root {
  /* ====================================================================
     COLORS - EMERGING BRAND PALETTE
     ==================================================================== */

  /* Primary Colors */
  --color-navy: #0F1374;

  /* Digital Leaders blue, as used on the website. The header band and the
     intro band sit on it. Do not change this value. */
  --color-dl-blue: #1839E2;

  /* On a light ground the true blue is readable as type at 7.4:1, so the
     lifted variant the dark theme needed now simply resolves to the brand
     blue itself. */
  --color-dl-blue-text: #1839E2;

  /* The map canvas (sea). Pale enough to read as paper, cool enough to still
     say "water", and clearly separated from the unranked land above it. */
  --color-navy-dark: #EAEDF7;

  /* Chrome: the control band and the side panel. White, so the controls read
     as page furniture and the map is the only coloured surface. */
  --color-navy-darker: #FFFFFF;

  /* Land with no ranking. Sits BETWEEN the sea and the lightest ramp stop:
     darker than the water so the coastline reads without a stroke, lighter
     than any scored country so it never passes for a low score. */
  --color-land-unranked: #D2D7E6;

  /* One step down again, for the "not ranked" swatch and dimmed land. */
  --color-navy-light: #BFC5DA;

  /* The accent. Emerging orange: the selected state, the active ranking, and
     the Global institution dots. It is deliberately NOT in the country ramp.
     Orange sits next to red, and a reader takes red on a map for a warning
     before they take it for a large number. The ramp is blue to violet. */
  --color-orange: #FF4901;

  /* The same orange, lightened. This is the Next 50 tier: visibly the same
     family as Global, one step down. */
  --color-orange-soft: #FFC4A8;

  /* A tint of the accent, for the soft fill behind a selected control. */
  --color-orange-wash: #FFEDE4;

  /* Retired. Kept as an alias so older rules resolve to the accent instead
     of to a colour that belongs to another product. */
  --color-gold: #FF4901;

  --color-blue: #4B5BCB;
  --color-maroon: #860018;
  --color-coral: #FF9E79;

  /* Pill controls, as used on the Digital Leaders website: a pale periwinkle
     capsule with navy type, turning solid orange with white type when it is
     the one selected. */
  --chip-bg: #E5E9FB;
  --chip-bg-hover: #D6DDF8;
  --chip-ink: #0F1374;
  --chip-border: #CCD5F6;
  --chip-bg-active: #FF4901;
  --chip-ink-active: #FFFFFF;

  /* The same capsule where it sits ON the blue banner, which needs a lighter
     ground to hold its own against #1839E2. */
  --chip-on-blue-bg: #C9D2F7;
  --chip-on-blue-hover: #DCE2FB;

  /* Semantic Colors */
  --color-text: #14163A;
  --color-text-secondary: #4A4E77;
  --color-text-muted: #7B7FA3;
  --color-background: #F4F5FA;
  --color-background-elevated: #FFFFFF;
  --color-border: #DDE0EC;
  --color-border-strong: #C6CBDE;

  --color-success: #0E8A5F;
  --color-warning: #B85C12;
  --color-error: #C8300A;
  --color-info: #1839E2;

  /* Evolution (DL25 to DL26). Direction has to read without a legend, so
     this is the one encoding that leaves the brand palette for the universal
     red/green convention. */
  --color-rising: #0E8A5F;
  --color-falling: #C21E2F;

  /* The same pair as type on white. The map fills are already dark enough to
     read on paper, so these barely move; they exist so the pairing stays
     explicit if either fill is ever lightened. */
  --color-rising-text: #0B7350;
  --color-falling-text: #AE1B2A;

  /* ====================================================================
     TYPOGRAPHY - MONTSERRAT
     ==================================================================== */

  --font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* Font Sizes */
  --font-size-xs: 11px;
  --font-size-sm: 13px;
  --font-size-base: 15px;
  --font-size-md: 16px;
  --font-size-lg: 18px;
  --font-size-xl: 24px;
  --font-size-2xl: 32px;
  --font-size-3xl: 40px;
  --font-size-4xl: 48px;
  --font-size-5xl: 56px;
  --font-size-6xl: 64px;
  --font-size-7xl: 72px;
  --font-size-8xl: 80px;
  --font-size-9xl: 96px;

  /* Font Weights */
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-extrabold: 800;

  /* Line Heights */
  --line-height-tight: 1.2;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.75;
  --line-height-loose: 2;

  /* Letter Spacing */
  --letter-spacing-tight: -0.02em;
  --letter-spacing-normal: 0;
  --letter-spacing-wide: 0.02em;
  --letter-spacing-wider: 0.05em;

  /* ====================================================================
     SPACING - 8PX GRID SYSTEM
     ==================================================================== */

  --spacing-xs: 4px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --spacing-xl: 32px;
  --spacing-2xl: 48px;
  --spacing-3xl: 64px;
  --spacing-4xl: 80px;

  /* ====================================================================
     SHADOWS
     Light theme: a shadow is how a surface lifts off paper, so they are
     tinted with the brand navy rather than neutral black.
     ==================================================================== */

  --shadow-sm: 0 1px 2px 0 rgba(15, 19, 116, 0.06);
  --shadow-base: 0 1px 3px 0 rgba(15, 19, 116, 0.10), 0 1px 2px 0 rgba(15, 19, 116, 0.06);
  --shadow-md: 0 4px 10px -2px rgba(15, 19, 116, 0.12), 0 2px 4px -1px rgba(15, 19, 116, 0.06);
  --shadow-lg: 0 10px 24px -6px rgba(15, 19, 116, 0.16), 0 4px 8px -4px rgba(15, 19, 116, 0.08);
  --shadow-xl: 0 20px 44px -10px rgba(15, 19, 116, 0.20), 0 8px 16px -8px rgba(15, 19, 116, 0.10);

  /* ====================================================================
     OPACITY
     ==================================================================== */

  --opacity-0: 0;
  --opacity-10: 0.1;
  --opacity-20: 0.2;
  --opacity-30: 0.3;
  --opacity-40: 0.4;
  --opacity-50: 0.5;
  --opacity-60: 0.6;
  --opacity-70: 0.7;
  --opacity-80: 0.8;
  --opacity-90: 0.9;
  --opacity-100: 1;

  /* ====================================================================
     BORDERS & RADIUS
     ==================================================================== */

  --border-1: 1px;
  --border-2: 2px;
  --border-3: 3px;
  --border-4: 4px;
  --border-6: 6px;
  --border-8: 8px;

  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --radius-full: 9999px;

  /* ====================================================================
     TRANSITIONS & ANIMATIONS
     ==================================================================== */

  --transition-fast: 150ms ease-out;
  --transition-base: 250ms ease-out;
  --transition-slow: 350ms ease-out;

  --easing-linear: linear;
  --easing-ease-out: cubic-bezier(0.4, 0, 0.2, 1);
  --easing-ease-in: cubic-bezier(0.4, 0, 1, 1);
  --easing-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* ====================================================================
     Z-INDEX SCALE
     ==================================================================== */

  --z-dropdown: 1000;
  --z-sticky: 1020;
  --z-fixed: 1030;
  --z-modal: 1040;
  --z-popover: 1050;
  --z-tooltip: 1060;
  --z-header: 100;
  --z-base: 1;

  /* ====================================================================
     DATA VISUALIZATION SCALES

     Blue through violet, lightest at the bottom. Orange was tried at the
     top and retired: next to red, it reads as a warning rather than as a
     large number. Green is reserved for the Evolution measure, where it
     means "rising", so it is kept out of the magnitude ramp.

     Keep these in step with COUNTRY_RAMP in scales.js.
     ==================================================================== */

  --scale-seq-0: #EAEEFC;
  --scale-seq-25: #A7B3EE;
  --scale-seq-50: #5566D2;
  --scale-seq-75: #6B3CA8;
  --scale-seq-100: #4C1D95;

  /* Diverging: maroon, through the page ground, to green */
  --scale-div-neg: #C21E2F;
  --scale-div-zero: #EDEFF6;
  --scale-div-pos: #0E8A5F;

  /* Categorical: 5 colors */
  --scale-cat-1: #1839E2;
  --scale-cat-2: #4B5BCB;
  --scale-cat-3: #FF9E79;
  --scale-cat-4: #93B23C;
  --scale-cat-5: #FF4901;
}

/* ========================================================================
   D3 ELEMENT STYLES
   ======================================================================== */

/* Graticule. White lines vanish on a pale sea, so the grid is drawn in the
   brand blue at very low opacity instead. */
.graticule {
  fill: none;
  stroke: #1839E2;
  stroke-width: 0.5px;
  stroke-opacity: 0.09;
}

/* Sphere (the ocean behind everything) */
.sphere {
  fill: var(--color-navy-dark);
  stroke: none;
}

/* Country
   NOTE: deliberately no `fill` here. A CSS fill declaration outranks the
   fill *attribute*, so declaring one would silently override every colour
   D3 computes from the data. Ranked countries are filled from JS; only
   unranked ones get their fill from the stylesheet. */
.country {
  stroke: #FFFFFF;
  stroke-width: 0.7px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  transition: fill var(--transition-base), opacity var(--transition-fast);
  cursor: pointer;
}

.country.is-unranked {
  fill: var(--color-land-unranked);
  opacity: var(--opacity-90);
  cursor: default;
}

/* Institution view: land is context, not data. Every country renders the
   same neutral tone so the coloured dots are the only encoding on screen. */
.country.is-basemap {
  fill: var(--color-land-unranked);
  opacity: var(--opacity-90);
  cursor: default;
}

.country.is-basemap:hover {
  stroke-width: 0.7px;
}

/* Ranked, but no figures for the metric currently on screen. Distinct from
   "not ranked" so the reader can tell "we have no number" from "they are not
   in the ranking", and so it never falls through to SVG's black. */
.country.is-nodata {
  fill: #E3E5EF;
  opacity: var(--opacity-100);
}

.city-state.is-nodata .city-state-dot {
  fill: #E3E5EF;
  opacity: var(--opacity-100);
}

/* Hover and selection are drawn in the accent, because on paper a white
   stroke no longer reads as emphasis. */
.country.is-ranked:hover {
  stroke: var(--color-orange);
  stroke-width: 2px;
}

.country.active {
  stroke: var(--color-orange);
  stroke-width: 2.5px;
}

/* Institution dots, one colour per ranking, drawn in the institution view */
.institution-dot {
  stroke: #FFFFFF;
  stroke-width: 1.2px;
  vector-effect: non-scaling-stroke;
  cursor: pointer;
  transition: opacity var(--transition-fast);
}

.institution-dot:hover {
  stroke: var(--color-navy);
  stroke-width: 2px;
}

.institution-dot.active {
  stroke: var(--color-navy);
  stroke-width: 2.5px;
}

/* Next 50: ranks 151 to 200 in the Global ranking. Same family as Global,
   one tier down, so it carries the lighter orange rather than a hollow ring. */
.institution-dot.is-next50 {
  /* The Next 50 fill is a pale orange that would dissolve into the grey
     basemap behind a white ring. An orange edge keeps each dot legible and
     still reads as the lighter member of the Global family. */
  stroke: #FF8A5B;
  stroke-width: 1.2px;
}

/* City-state markers: countries with no polygon at 110m (Singapore, Hong Kong) */
.city-state {
  cursor: pointer;
}

.city-state-halo {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: 2px;
  vector-effect: non-scaling-stroke;
}

.city-state-dot {
  stroke: #FFFFFF;
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
  transition: fill var(--transition-base);
}

/* Filtered out entirely. Matches how excluded countries are dimmed. */
.city-state.is-filtered-out {
  opacity: var(--opacity-40);
}

.city-state.is-filtered-out .city-state-dot {
  fill: var(--color-navy-light);
}

.city-state:hover .city-state-halo,
.city-state.active .city-state-halo {
  stroke: var(--color-orange);
  stroke-width: 3px;
}

/* Hub bubble.
   Size carries DL Points; the fill is deliberately uniform and translucent so
   the layer reads as an annotation on top of the choropleth rather than a
   second colour encoding competing with it. On paper the translucent white of
   the dark theme was invisible, so the bubble is now a navy wash with a navy
   edge. */
.hub {
  cursor: pointer;
}

.hub-bubble {
  fill: rgba(15, 19, 116, 0.10);
  stroke: var(--color-navy);
  stroke-width: 1.25px;
  stroke-opacity: 0.55;
  vector-effect: non-scaling-stroke;
  transition: fill var(--transition-fast), stroke var(--transition-fast);
}

.hub:hover .hub-bubble {
  fill: rgba(255, 73, 1, 0.22);
  stroke: var(--color-orange);
  stroke-opacity: 1;
}

.hub.active .hub-bubble {
  fill: rgba(255, 73, 1, 0.30);
  stroke: var(--color-orange);
  stroke-opacity: 1;
  stroke-width: 2.5px;
}

/* SVG legend and caption.
   The legend and the coverage caption no longer live in the bottom-left
   corner of the map; they are HTML, in the key strip directly under the
   control band. These rules remain so any SVG fallback still renders in the
   light palette rather than in SVG's default black. */
.legend-heading {
  fill: var(--color-text);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--letter-spacing-wide);
}

.legend-tick {
  fill: var(--color-text-secondary);
  font-size: var(--font-size-xs);
}

.legend-swatch-unranked {
  fill: var(--color-land-unranked);
}

.legend-swatch-nodata {
  fill: #E3E5EF;
}

/* Tooltip */
.tooltip {
  background-color: #FFFFFF;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-sm);
  font-size: var(--font-size-xs);
  color: var(--color-text);
  pointer-events: none;
  box-shadow: var(--shadow-lg);
}

.tooltip-title {
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
  margin-bottom: var(--spacing-xs);
}

.tooltip-content {
  color: var(--color-text-secondary);
  line-height: var(--line-height-tight);
}

/* Caption */
.caption {
  font-size: var(--font-size-xs);
  fill: var(--color-text-muted);
  color: var(--color-text-muted);
  font-weight: var(--font-weight-regular);
}

/* Filters narrow what the whole map is showing, so the caption says so. */
.caption.is-filtered {
  fill: var(--color-orange);
  color: var(--color-orange);
}

/* ========================================================================
   INTERACTIVE STATES
   ======================================================================== */

button {
  font-family: var(--font-family);
  transition: background-color var(--transition-fast),
              border-color var(--transition-fast),
              color var(--transition-fast);
}

/* Deliberately no lift-and-shadow on hover. On a light editorial page the
   controls are set type in a capsule, not raised objects, and a translate on
   every button made the whole toolbar twitch as the pointer crossed it. */

select,
input {
  font-family: var(--font-family);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-strong);
  padding: var(--spacing-sm) var(--spacing-md);
  background-color: #FFFFFF;
  color: var(--color-text);
  transition: border-color var(--transition-base), box-shadow var(--transition-base);
}

select:hover,
input:hover {
  border-color: var(--color-orange);
}

select:focus,
input:focus {
  outline: none;
  border-color: var(--color-dl-blue);
  box-shadow: 0 0 0 3px rgba(24, 57, 226, 0.15);
}

/* A visible focus ring on every control, which the dark theme never had.
   On paper there is no glow to fall back on. */
button:focus-visible,
a:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--color-dl-blue);
  outline-offset: 2px;
}
