/*
 * TX Data Center Tracker — design tokens.
 * Ported verbatim from globals.css / design-language.md in the Next.js repo
 * (the @theme block there becomes plain :root custom properties here — this
 * theme has no Tailwind build step). Source of truth for the visual language
 * is design-language.md, carried into this repo as
 * .gitdocs/design-language.md.
 * Light "paper" is the only theme — there is intentionally no dark mode.
 */

:root {
  --color-ink: #2a2f37;
  --color-slate: #454b54;
  --color-slate-mute: #646a72; /* 5.07 paper / 4.84 raised — #6b7178 failed raised at 4.37 */
  --color-paper: #faf6ef;
  --color-paper-raised: #f4f1ea;
  --color-line: #e7e1d6;

  /* Accent text/links must clear 4.5:1 on BOTH --color-paper and
     --color-paper-raised; the raised panel is the tighter of the two and is
     where .tag-link / .item-card__source actually sit. #b4552a cleared paper
     (4.56) but not raised (4.36), so it is darkened here rather than patched
     per call site. */
  --color-terracotta: #a94d24; /* accent text / links — 5.17 paper / 4.93 raised */
  --color-terracotta-fill: #cc6a3c; /* decorative fills / rules only — 3.42:1, never behind text */
  --color-terracotta-deep: #8f401e; /* button ground — 6.68:1 under --color-paper */
  --color-terracotta-press: #7a3618; /* button hover/pressed — 8.23:1 */

  /* Semantic status scale (login error / misc UI only — the map/tier
     ramp below is the one that matters for the tracker itself). */
  --color-tier-active: #c0311c;
  --color-tier-pending: #d98a2b;
  --color-tier-resolved: #8a8f98;
  --color-tier-econ: #2f6f76;
  --color-tier-none: #e7e1d6;

  /* Tier palette. NOT a single-hue ramp — three families, because the six
     tiers are three different kinds of thing:

       opposition, ordinal  terracotta dark -> light, then gold
       opposite stance      teal (tax_abatement: courting, not weakly opposing)
       no signal            slate + hatch (rejected), cream (none)

     The previous single-hue terracotta ramp could not separate its own
     neighbours — closest adjacent pair dE 15 / 1.44:1, dE 13 simulated for
     deuteranopia — which is below what a reader resolves at county size. This
     palette's closest pair is dE 26 (21-22 under deuteranopia/protanopia),
     and it is active_moratorium vs resolutions_enacted: two tiers adjacent in
     MEANING, so a same-hue lightness step is correct there specifically.

     Colour is still not the only channel, and the other two remain
     load-bearing, not decoration:
       1. a white hairline on every county path (below), so adjacent counties
          always read as separate shapes;
       2. the diagonal hatch on rejected_action (see txdcm_render_county_map()),
          which is what separates it from `none` in grayscale and at the small
          county sizes in East Texas.

     Must match txdcm_tier_colors() in the plugin exactly. */
  --tier-active_moratorium: #7d2614;
  --tier-resolutions_enacted: #c25f30;
  --tier-pending_action: #efc169;
  --tier-tax_abatement: #2f6f76;
  --tier-rejected_action: #99a0a7;
  --tier-none: #e8e2d7; /* unchanged from the old ramp — see txdcm_tier_colors() */

  /* Dot-sized variants — anything ~10px uses these, never the fills above. A
     county-sized fill gives the eye enough colour to integrate; a dot does
     not, and the pale end of the palette vanishes on cream (pending's fill is
     2.16:1 against --color-paper, rejected's 2.43:1). Each below clears 3:1
     against --color-paper AND --color-paper-raised, except `none`, which is
     pushed as far as it goes before it would start reading as a real tier
     rather than as absence.

     Must match txdcm_tier_dots() in the plugin — js/map.js reads these back
     off :root for the tooltip dot. */
  --tier-dot-active_moratorium: #7d2614; /* 9.03 paper / 8.62 raised */
  --tier-dot-resolutions_enacted: #b9532b; /* 4.50 / 4.29 */
  --tier-dot-pending_action: #b07c1c; /* 3.39 / 3.24 */
  --tier-dot-tax_abatement: #2f6f76; /* 5.33 / 5.09 */
  --tier-dot-rejected_action: #767e86; /* 3.82 / 3.65 */
  --tier-dot-none: #968a78; /* 3.14 / 3.00 */

  /* The stripe painted over rejected_action's hatch, on the map and on the
     legend swatch that keys it. Its own token because it is neither the fill
     nor the dot — it sits ON #99a0a7 and must hold at 1.4px. It used to
     borrow --tier-pending_action, which was fine while every tier shared one
     hue and is not fine now that pending_action is gold. Must match
     txdcm_hatch_stripe_color(). */
  --tier-hatch-stripe: #5f676f;

  --font-sans: "Lato", ui-sans-serif, system-ui, sans-serif;

  /* Warm, tinted, layered elevation — never a flat gray drop shadow. */
  --shadow-panel: 0 1px 2px rgba(42, 47, 55, 0.04),
    0 8px 24px -12px rgba(42, 47, 55, 0.12);
  --shadow-lift: 0 2px 4px rgba(42, 47, 55, 0.05),
    0 16px 40px -16px rgba(42, 47, 55, 0.18);
}

html {
  background: var(--color-paper);
  color: var(--color-ink);
}

body {
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Tabular figures for anything that must align (stats, dates, counts). */
.tnum {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Small-caps eyebrow / label. */
.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  font-size: 0.6875rem;
  color: var(--color-slate-mute);
}

/* Consistent focus ring across every interactive element. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--color-terracotta-fill);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Texas county map paths — quiet by default, forward on hover.
   The white hairline is not decoration: it is the only thing that separates
   two adjacent counties one ramp step apart (1.44:1 at the worst pair), and
   design-language.md has always specified it. */
.county-path {
  transition: opacity 0.15s ease, stroke-width 0.15s ease;
  cursor: pointer;
  stroke: #fff;
  stroke-width: 0.5;
  stroke-linejoin: round;
  /* Without this the hairline scales with the viewBox and vanishes: the map
     renders 227px wide at a 320px viewport, where 0.5 user units is 0.12 CSS
     px. non-scaling-stroke pins every stroke below to real CSS pixels. */
  vector-effect: non-scaling-stroke;
}
.county-path:hover {
  stroke: var(--color-ink);
  stroke-width: 1.4;
  opacity: 0.88;
}

/* Tier fills, as classes rather than a per-path fill="" attribute — one
   attribute instead of two on 254 elements, and the hatch below needs a
   class hook anyway. */
.tier-active_moratorium { fill: var(--tier-active_moratorium); }
.tier-resolutions_enacted { fill: var(--tier-resolutions_enacted); }
.tier-pending_action { fill: var(--tier-pending_action); }
.tier-tax_abatement { fill: var(--tier-tax_abatement); }
.tier-none { fill: var(--tier-none); }

/* rejected_action carries a diagonal hatch as a second, non-chromatic
   channel. On the old single-hue ramp that was because it collided with
   `none` (1.44:1). The three-family palette separates those two on colour
   (slate vs cream, dE 28), so the hatch is now here for what colour cannot
   reach at all: grayscale printing, and the small county shapes in East Texas
   where a 10px polygon carries too little fill to judge. The <pattern> paints the tier colour as
   its own background, so this single fill gives colour AND texture.
   See txdcm_render_map_defs() and txdcm_patterned_tiers(). */
/* The second value is a fallback paint, and it matters: if the <defs> block
   ever fails to render — a template edit, a partial cache, the SVG being
   inlined somewhere without its defs — a bare url() reference resolves to no
   paint at all and those counties disappear into the background as empty
   outlines. With the fallback they degrade to the plain tier colour. */
.tier-rejected_action { fill: url(#txdcm-hatch-rejected_action) var(--tier-rejected_action); }

/*
 * Map focus: a DUAL ring, because a single ring cannot clear 3:1 (SC 1.4.11)
 * across a palette this wide. The plain terracotta ring measured 1.01:1
 * against pending_action — literally invisible on the county it was
 * surrounding. Dark outline outside + white stroke inside: every fill clears
 * 3:1 against at least one of the two. Re-measured for the three-family
 * palette, and it still holds with room to spare — the closest any fill comes
 * to failing both is tax_abatement (2.34 vs ink, but 5.74 vs white) and
 * resolutions_enacted, which clears BOTH (3.19 / 4.22). Ink covers the light
 * half at 5.1–10.9, white covers the dark half at 4.2–9.7.
 *
 * box-shadow is deliberately not used — it does not render on SVG elements.
 * `stroke` on the child path is the SVG-native second ring.
 */
/* Outer half. `outline` is set on the <a> itself, which does work on an SVG
   anchor. */
.map-wrap svg a:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 1px;
}

/*
 * Inner half. This is a CLASS, toggled by js/map.js, and that is not a stylistic
 * choice — it is a workaround.
 *
 * Blink does not style-match :focus or :focus-visible through a descendant
 * combinator out of an SVG <a>. Verified on the live site: with
 * `.map-wrap svg a:focus .county-path { stroke-width: 7 !important }` in the
 * sheet and the link genuinely focused, element.matches() on that exact
 * selector returns TRUE while getComputedStyle still reports the base 0.5px.
 * The rule silently does nothing. The pseudo-class rules are kept below as
 * progressive enhancement for engines that do resolve them.
 *
 * Consequence: never move this back to a :focus-visible descendant selector,
 * and if map.js is ever removed the map loses its inner focus ring.
 */
.county-path.is-focused,
.map-wrap svg a:focus-visible .county-path {
  stroke: #fff;
  stroke-width: 2;
  opacity: 1;
}

/* One page-load choreography: hero band rises once, staggered. */
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.rise {
  animation: rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  .rise {
    animation: none;
  }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
  }
}
