/* ==========================================================================
   directory.css — shared primitives for the Acres directory + data modules
   --------------------------------------------------------------------------
   Loaded per-module via require_css(get_asset_url("../../css/directory.css")),
   never from base.html (geekify Phase 5 rule: no sitewide library growth).
   require_css de-duplicates, so every directory module can ask for it and it
   still lands once.

   Token discipline (geekify CLAUDE.md hard rule 2): no hardcoded hex. The mint
   accent is var(--tertiary-color), which is what .cm-dark already re-points
   eyebrows and links to, so these primitives inherit the right accent on a dark
   surface without restating it. Glows are color-mix()'d from that same token,
   so a Brand Kit change re-derives them.

   Scoping: these are instance-independent structural classes. Anything driven
   by a module field belongs in that module's #-scoped inline <style>.
   ========================================================================== */

/* ==========================================================================
   1. Shared shell
   ========================================================================== */

.dir-block__header {
  margin-bottom: 2rem;
}

.dir-block__header--center {
  text-align: center;
  max-width: 42rem;
  margin-inline: auto;
}

.dir-block__title {
  margin: 0 0 .35rem;
}

.dir-block__sub {
  margin: 0;
  color: var(--text-on-dark-2);
  max-width: 70ch;
}

.dir-block__header--center .dir-block__sub {
  margin-inline: auto;
}

/* Empty in-page anchor target. scroll-margin-top keeps the sticky header from
   covering the heading it lands on. */
.dir-anchor {
  display: block;
  scroll-margin-top: 6rem;
}

/* ==========================================================================
   2. Card primitive
   --------------------------------------------------------------------------
   Pairs with .glass-dark from geekify/css/components/_cards.css — that supplies
   the translucent fill, hairline and radius. This adds only the interaction
   layer: a lift plus the parcel mint glow, matching the live site's hover
   treatment on resource cards.
   ========================================================================== */

.dir-card {
  position: relative;
  display: flex;
  flex-direction: column;
  content-visibility: visible;
  gap: .3rem;
  padding: 1.15rem 1.25rem;
  text-decoration: none;
  color: inherit;
  transition: transform var(--transition-base), box-shadow var(--transition-base),
              border-color var(--transition-base);
}

a.dir-card:hover,
a.dir-card:focus-visible {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--tertiary-color) 45%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--tertiary-color) 30%, transparent),
    0 0 28px color-mix(in srgb, var(--tertiary-color) 22%, transparent),
    var(--shadow-md);
}

.dir-card__eyebrow {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--tertiary-color);
}

.dir-card__title {
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0;
  color: var(--text-on-dark-1);
}

.dir-card__desc {
  font-size: .85rem;
  line-height: 1.5;
  color: var(--text-on-dark-2);
  margin: 0;
}

/* Label/value meta rows inside a card (Counties 67 / Parcels 2.1M+). */
.dir-card__meta {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  margin-top: .4rem;
  font-size: .78rem;
  color: var(--text-on-dark-2);
}

.dir-card__meta-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
}

.dir-card__meta-val {
  font-weight: 600;
  color: var(--text-on-dark-1);
  font-variant-numeric: tabular-nums;
}

.dir-card__arrow {
  position: absolute;
  top: 1rem;
  right: 1rem;
  font-size: .8rem;
  line-height: 1;
  color: color-mix(in srgb, var(--text-on-dark-1) 35%, transparent);
  transition: color var(--transition-fast), transform var(--transition-fast);
}

a.dir-card:hover .dir-card__arrow,
a.dir-card:focus-visible .dir-card__arrow {
  color: var(--tertiary-color);
  transform: translateX(3px);
}

/* ==========================================================================
   3. Grids — CSS Grid rather than the flex_grid() macro, because directory
      card counts are data-driven and auto-fill reflows without breakpoint math.
   ========================================================================== */

.dir-grid {
  display: grid;
  gap: .85rem;
  grid-template-columns: repeat(auto-fill, minmax(var(--dir-col, 200px), 1fr));
}

.dir-grid--wide { --dir-col: 320px; }
.dir-grid--mid  { --dir-col: 240px; }
.dir-grid--tight { --dir-col: 180px; }

/* ==========================================================================
   4. Filter controls — alpha buttons, category pills, search
   --------------------------------------------------------------------------
   All interactive targets clear 44px (geekify Phase 3 a11y rule) via min-height
   plus padding, without visually inflating the small pills: the tap area is the
   button box itself.
   ========================================================================== */

.dir-filters {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  align-items: center;
  margin-bottom: 1.5rem;
}

.dir-filters__label {
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-on-dark-2);
  white-space: nowrap;
  margin-right: .25rem;
}

.dir-filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 .75rem;
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-on-dark-2);
  background: transparent;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast),
              border-color var(--transition-fast);
}

.dir-filter-btn--pill { border-radius: var(--radius-pill); }

.dir-filter-btn:hover {
  color: var(--tertiary-color);
  border-color: color-mix(in srgb, var(--tertiary-color) 45%, transparent);
}

.dir-filter-btn[aria-pressed="true"] {
  color: var(--surface-dark);
  background: var(--tertiary-color);
  border-color: var(--tertiary-color);
}

.dir-search {
  position: relative;
  max-width: 34rem;
  margin-inline: auto;
  width: 100%;
}

.dir-search__input {
  width: 100%;
  min-height: 52px;
  padding: 0 3rem 0 1.15rem;
  font: inherit;
  font-size: .95rem;
  color: var(--text-on-dark-1);
  background-color: color-mix(in srgb, var(--text-on-dark-1) 6%, transparent);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.dir-search__input::placeholder {
  color: color-mix(in srgb, var(--text-on-dark-1) 45%, transparent);
}

.dir-search__input:focus {
  outline: none;
  border-color: var(--tertiary-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tertiary-color) 20%, transparent);
}

.dir-search__icon {
  position: absolute;
  right: 1rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-on-dark-2);
  pointer-events: none;
  display: flex;
}

/* Hidden by the filter controller until a query returns nothing. */
.dir-empty {
  display: none;
  grid-column: 1 / -1;
  padding: 3rem 1rem;
  text-align: center;
  color: var(--text-on-dark-2);
}

/* Declared after .dir-card so it wins on source order at equal specificity —
   no !important needed (geekify CLAUDE.md workflow rule 3). */
.dir-is-hidden { display: none; }

/* Screen-reader-only live region announcing result counts. */
.dir-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   5. Tag chips
   ========================================================================== */

.dir-tags {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .5rem;
}

.dir-tag {
  font-size: .68rem;
  font-weight: 600;
  padding: .15rem .45rem;
  border-radius: var(--radius-sm);
  color: var(--tertiary-color);
  background-color: color-mix(in srgb, var(--tertiary-color) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--tertiary-color) 20%, transparent);
}

/* ==========================================================================
   6. Key/value spec table
   --------------------------------------------------------------------------
   Serves the county "Key Statistics" block and the layer "Data Specification"
   block. Wrapped in .dir-table-scroll so a wide value never forces the page
   body to scroll horizontally.
   ========================================================================== */

.dir-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  margin-bottom: 2rem;
}

.dir-spec {
  width: 100%;
  border-collapse: collapse;
  font-size: .875rem;
}

.dir-spec tr + tr { border-top: 1px solid var(--border-subtle); }

.dir-spec tr:nth-child(even) {
  background-color: color-mix(in srgb, var(--text-on-dark-1) 3%, transparent);
}

.dir-spec th,
.dir-spec td {
  padding: .7rem 1rem;
  text-align: left;
  vertical-align: top;
}

.dir-spec th {
  font-weight: 400;
  color: var(--text-on-dark-2);
  border-right: 1px solid var(--border-subtle);
  width: 45%;
  white-space: nowrap;
}

.dir-spec td {
  font-weight: 700;
  color: var(--text-on-dark-1);
}

.dir-spec a { color: var(--tertiary-color); font-weight: 600; }

/* ==========================================================================
   6b. Dynamic Tables (dynamic-tables.module)
   --------------------------------------------------------------------------
   Extends the .dir-spec treatment above rather than restating it: the module
   puts BOTH classes on the table, so borders, padding, type scale, zebra and
   the mobile step all come from section 6 and only the additions live here.
   Any change to the directory tables therefore reaches these automatically.

   Two differences from .dir-spec, both forced by the content model:
   .dir-spec is a fixed two-column key/value block whose `th` is pinned at 45%
   and never wraps. These tables are n-column, so the width pin and the nowrap
   are released, and a real <thead> exists (the spec block has no header row).

   TONES. Green is the brand primary, which is already green in this scheme.
   No red existed, so --danger-base derives one from the primary with relative
   colour syntax: same saturation and lightness, hue rotated into the red
   family, so it reads as a deliberate sibling of the green and a Brand Kit
   change still re-derives it. Zero hardcoded hex (geekify hard rule 2).

   CONTRAST. Row tints are alpha mixes into `transparent`, never opaque fills,
   so they composite onto whatever surface the section paints and stay legible
   under both inks — .cm-dark and .cm-light already colour `td, th`, and the
   module passes the colour-mode class through, so the ink follows the surface.

   COLOUR IS NOT THE ONLY SIGNAL. A toned row also carries a left border the
   default rows do not have, and a check/cross glyph with a screen-reader label
   (the module's Tone Meaning field). Either one identifies the row with colour
   removed entirely.
   ========================================================================== */

body {
  /* -158, not -140: the primary sits at H 160, so -140 lands on H 20 — a rust
     orange that reads muddy rather than red. -158 lands on H 2, a true red at
     the primary's own saturation and lightness, so the pair stays balanced. */
  --danger-base: hsl(from var(--primary-base) calc(h - 158) s l);
}

/* The rhythm lives here, not on the dnd_section: the three insertion points
   declare zero padding so a placement holding no table for this page collapses
   to nothing rather than leaving a gap. The module's own Spacing field is
   #id-scoped at (1,0,0) and still overrides this. */
.dyn-table { padding: 3rem 0; }

.dyn-table__block + .dyn-table__block { margin-top: 2.5rem; }

.dyn-table__caption {
  margin: 0 0 .5rem;
  font-size: 1.125rem;
  letter-spacing: -.01em;
}

.dyn-table__intro { margin-bottom: 1rem; }
.dyn-table__intro > :last-child { margin-bottom: 0; }

/* SURFACE — load-bearing, not decoration.
   theme-overrides.css carries a bare `table { background-color: var(--surface-0) }`
   at (0,0,1): an opaque WHITE fill on every table in the theme. The Directory
   pages escape it only because hubdb-detail-body writes
   `<table class="dir-spec glass-dark">` and .glass-dark wins at (0,1,0). This
   module therefore ALWAYS emits a surface class, and "None" is a real class
   rather than an absence, so that element rule can never win. Same reason
   `thead th` is reset: theme-overrides paints it --surface-2, a light grey. */
.dyn-table__table--plain { background-color: transparent; }

/* Release the two-column spec pins — these tables have n columns. */
.dyn-table__table th[scope="row"] { width: auto; white-space: normal; }

.dyn-table__table thead th {
  background-color: transparent;
  font-weight: 600;
  color: var(--text-on-dark-1);
  border-right: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.dyn-table__table thead th:last-child { border-right: 0; }
.cm-light .dyn-table__table thead th { color: var(--text-1); }

/* One variable per tone drives the fill, the rule and the glyph, so a tone is
   defined in exactly one place and the green and red rules cannot fork. */
.dyn-table__row--green { --tone: var(--primary-base); }
.dyn-table__row--red   { --tone: var(--danger-base); }

/* The glyph and the left rule take a LIFTED tone, never the base. Both brand
   tones sit at L≈39%, and measured against the 18% fill the base red reaches
   only 2.72:1 — under the 3:1 floor for a graphical object, which is exactly why
   the crosses were hard to pick out. 40% white lifts red to 5.6:1 and green to
   8.4:1, and both stay unmistakably their own hue. */
.dyn-table__row--green,
.dyn-table__row--red { --tone-ink: color-mix(in srgb, var(--tone) 60%, white); }

/* The zebra in section 6 is nth-child(even) on every row; a tinted row has to
   outrank it, so the tone rules are one level more specific by construction. */
.dyn-table__table .dyn-table__row--green,
.dyn-table__table .dyn-table__row--green:nth-child(even),
.dyn-table__table .dyn-table__row--red,
.dyn-table__table .dyn-table__row--red:nth-child(even) {
  background-color: color-mix(in srgb, var(--tone) 18%, transparent);
  box-shadow: inset 4px 0 0 0 var(--tone-ink);
}

/* A toned row is an emphasised row, so its label takes the full-strength ink
   rather than the 75% the default rows use. */
.dyn-table__row--green th[scope="row"],
.dyn-table__row--red th[scope="row"] { color: var(--text-on-dark-1); }

/* Hover matches the directory cards' lift-on-hover feel without moving a table
   row: a small tint step, and only on rows that are actually interactive-ish. */
.dyn-table__table tbody tr:hover {
  background-color: color-mix(in srgb, var(--text-on-dark-1) 6%, transparent);
}

.cm-light .dyn-table__table tbody tr:hover {
  background-color: color-mix(in srgb, var(--surface-dark) 5%, transparent);
}

.dyn-table__table .dyn-table__row--green:hover,
.dyn-table__table .dyn-table__row--red:hover {
  background-color: color-mix(in srgb, var(--tone) 26%, transparent);
}

.dyn-table__mark {
  display: inline-block;
  width: 1.15em;
  margin-right: .45em;
  color: var(--tone-ink, currentColor);
  font-size: 1.1em;
  font-weight: 700;
  line-height: 1;
}

/* Editor-only hint panel. Never reaches a live page — the module emits it
   inside its `elif is_in_editor` branch. */
.dyn-table--empty { padding: 1.25rem; }

.dyn-table__hint {
  padding: 1rem 1.25rem;
  border: 1px dashed var(--border-default);
  border-radius: var(--radius-lg);
  font-size: .875rem;
}

.dyn-table__hint code {
  padding: .1em .4em;
  border-radius: var(--radius-sm);
  background-color: color-mix(in srgb, var(--tertiary-color) 12%, transparent);
}

.dyn-table__hint-list { margin: .75rem 0; padding-left: 1.1rem; }
.dyn-table__hint-list li { margin-bottom: .4rem; }
.dyn-table__hint-meta { display: block; opacity: .75; font-size: .8125rem; }
.dyn-table__hint-note { margin-bottom: 0; opacity: .7; font-style: italic; }

/* Mobile matches section 12's step for .dir-spec (which these tables also
   carry, so the padding step is inherited). The only addition is releasing the
   header nowrap: a 4-column header cannot stay on one line on a phone, and the
   .dir-table-scroll wrapper is there to scroll what still overflows. */
@media (max-width: 600px) {
  .dyn-table__table thead th { white-space: normal; }
  .dyn-table__caption { font-size: 1rem; }
  .dyn-table__block + .dyn-table__block { margin-top: 1.75rem; }
}
/* ==========================================================================
   7. Sidebar panel
   --------------------------------------------------------------------------
   The content/sidebar split itself is done with the section's own dnd columns
   rather than a grid here, so editors can rebalance it and it stacks natively.
   This is only the panel chrome a sidebar block sits in.
   ========================================================================== */

.dir-side-card {
  padding: 1.25rem;
}

.dir-side-card__title {
  font-size: .875rem;
  font-weight: 700;
  color: var(--text-on-dark-1);
  margin: 0 0 1rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid var(--border-subtle);
}

/* Checklist ("Useful for") */
.dir-checklist {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .875rem;
  color: var(--text-on-dark-1);
}

.dir-checklist li {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
}

.dir-checklist li::before {
  content: "\2713";
  color: var(--tertiary-color);
  font-weight: 700;
  line-height: 1.5;
}

/* ==========================================================================
   8. Numbered how-to steps
   ========================================================================== */

.dir-steps {
  margin: 0 0 2rem;
  padding: 0;
  list-style: none;
  counter-reset: dir-step;
}

.dir-steps__item {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  padding: 1rem 0;
  border-bottom: 1px solid var(--border-subtle);
}

.dir-steps__item:last-child { border-bottom: none; }

.dir-steps__num {
  counter-increment: dir-step;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  font-size: .875rem;
  font-weight: 700;
  color: var(--surface-dark);
  background: var(--tertiary-color);
}

.dir-steps__num::before { content: counter(dir-step); }

.dir-steps__title {
  font-size: .9375rem;
  font-weight: 700;
  color: var(--text-on-dark-1);
  margin: 0 0 .2rem;
}

.dir-steps__body {
  font-size: .875rem;
  color: var(--text-on-dark-2);
  margin: 0;
}

.dir-steps__body a { color: var(--tertiary-color); }

/* ==========================================================================
   9. Breadcrumb bar (visual only — BreadcrumbList JSON-LD is emitted sitewide
      by layouts/base.html, so this must not add a second one)
   ========================================================================== */

.dir-crumbs {
  font-size: .8125rem;
  color: var(--text-on-dark-2);
}

.dir-crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dir-crumbs__list a {
  color: var(--tertiary-color);
  text-decoration: none;
}

.dir-crumbs__list a:hover { text-decoration: underline; }

.dir-crumbs__sep {
  color: color-mix(in srgb, var(--text-on-dark-1) 30%, transparent);
}

.dir-crumbs__current {
  color: var(--text-on-dark-1);
}

/* ==========================================================================
   10. Freshness legend + status dots
   --------------------------------------------------------------------------
   The four band colours are set per-instance from module colour fields
   (--dir-dot), so nothing here hardcodes a status hue.
   ========================================================================== */

.dir-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  align-items: center;
}

.dir-legend__item {
  display: flex;
  align-items: center;
  gap: .45rem;
  font-size: .75rem;
  color: var(--text-on-dark-2);
}

.dir-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--dir-dot, var(--tertiary-color));
}

.dir-dot--lg { width: 10px; height: 10px; }

/* Freshest band gets a halo so "updated today" reads at a glance. */
.dir-dot--glow {
  box-shadow: 0 0 6px color-mix(in srgb, var(--dir-dot, var(--tertiary-color)) 60%, transparent);
}

.dir-dot--pulse { animation: dir-pulse 2s infinite; }

@keyframes dir-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .5; transform: scale(.8); }
}

/* ==========================================================================
   11. Figure treatments
   --------------------------------------------------------------------------
   Shared by page-sections media rows and hubdb-media, which is why they live
   here rather than in either module. Every value derives from
   --tertiary-color via color-mix(), so a Brand Kit change re-derives the glow.

   Note: parcel/child.css carries older .glow-image / .glow-border rules that
   hardcode the mint as rgb(114 255 152 / 10%). Those still work and are left
   alone (existing pages use them), but new work should use these instead.
   ========================================================================== */

.dir-figure {
  margin: 0;
  min-width: 0;
}

.dir-figure--framed,
.dir-figure--glow_framed {
  padding: .5rem;
  border: 1px solid color-mix(in srgb, var(--tertiary-color) 25%, transparent);
  border-radius: var(--radius-xl);
  background: color-mix(in srgb, var(--tertiary-color) 4%, transparent);
}

.dir-figure--glow,
.dir-figure--glow_framed {
  /*box-shadow: 0 0 64px color-mix(in srgb, var(--tertiary-color) 10%, transparent);
  filter: drop-shadow(0 0 64px color-mix(in srgb, var(--tertiary-color) 10%, transparent));
  -webkit-filter: drop-shadow(0 0 64px color-mix(in srgb, var(--tertiary-color) 10%, transparent));
}

.dir-figure--glow img,
.dir-figure--glow_framed img {
  border-radius: var(--radius-lg);
}

/* A ticked list whose lines carry a bold lead-in label, e.g.
   "Grid Intelligence: filter parcels by proximity to substations." The label
   is promoted onto its own line so the list scans as a definition list. */
.dir-checklist--labeled li > strong:first-child {
  display: block;
  font-weight: 700;
  letter-spacing: -.01em;
  margin-bottom: .15rem;
}

/* ==========================================================================
   12. Responsive
   ========================================================================== */

@media (max-width: 600px) {
  .dir-spec th { width: 50%; white-space: normal; }
  .dir-spec th,
  .dir-spec td { padding: .6rem .75rem; }
  .dir-filters { gap: .35rem; }
  .dir-block__header { margin-bottom: 1.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .dir-card,
  .dir-card__arrow,
  .dir-filter-btn,
  .dir-side-list__item a { transition: none; }

  a.dir-card:hover,
  a.dir-card:focus-visible { transform: none; }

  a.dir-card:hover .dir-card__arrow,
  a.dir-card:focus-visible .dir-card__arrow { transform: none; }

  .dir-dot--pulse { animation: none; }
}