/* ============================================================================
   RETRIVIUM — knowledge map surface (§8)
   ----------------------------------------------------------------------------
   The map used to render all 308 concepts flat, 17,381px tall on a phone, every
   node reading "Rung 0 · Unseen" beside a raw prerequisite string. This file
   dresses the frontier-first rebuild instead: a filtered, searchable list of the
   10–30 concepts that are actually live for the learner, and a track → strand
   drill-down for everything else.

   Colour policy, held to PRINCIPLES 3, 6 and 7:
     · garnet (--color-loss) appears here for exactly one thing — a demotion.
       Not a heading, not a link, not a node border, not the filter chips.
     · every state carries a word as well as a hue: "Locked", "Ready to start",
       "Moved down", and the rung as a numeral AND its name.
     · the rung ramp below is component-scoped (tier 3) and derived from the
       semantic --color-state, so themes still swap in one place.
   ============================================================================ */

.map {
  --map-rail: 3px;

  /* Monotonic in both themes: rung 0 sits at the ground and each step moves
     one measured stride towards --color-state. Do not reach for
     --color-surface-high at rung 0 — it lands on top of rung 1 and the ramp
     stops reading as an ordering. */
  --map-rung-0: var(--color-surface-sunk);
  --map-rung-1: color-mix(in srgb, var(--color-state) 26%, var(--color-surface));
  --map-rung-2: color-mix(in srgb, var(--color-state) 40%, var(--color-surface));
  --map-rung-3: color-mix(in srgb, var(--color-state) 55%, var(--color-surface));
  --map-rung-4: color-mix(in srgb, var(--color-state) 70%, var(--color-surface));
  --map-rung-5: color-mix(in srgb, var(--color-state) 85%, var(--color-surface));
  --map-rung-6: var(--color-state);

  --map-hatch: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--color-loss) 24%, transparent) 0 2px,
    transparent 2px 6px
  );

  /* The same hatch at card scale. A demotion has to be unmistakable without
     shouting over the four concepts sitting next to it. */
  --map-hatch-soft: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--color-loss) 9%, transparent) 0 2px,
    transparent 2px 7px
  );
}

.map .page-header h1 { font-size: clamp(var(--text-xl), 3.4vw, 1.9rem); }

/* ------------------------------------------------------------------- search */
.map-search {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-5);
}
.map-search__field {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0 var(--space-4);
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  font-size: var(--text-base);
}
.map-search__field::placeholder { color: var(--color-text-subtle); }

/* Ghost, not garnet. Browsing is not the product's one primary action, and the
   map is not where the garnet is spent. */
.map-search__submit {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 var(--space-4);
  background: transparent;
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  font-size: var(--text-md);
  font-weight: var(--weight-semi);
}
.map-search__submit:hover { border-color: var(--color-text-muted); }

/* ------------------------------------------------------------------ filters
   Six chips, wrapping rather than scrolling: a chip you have to discover by
   swiping is a chip that is not there. */
.map-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.map-filter {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-md);
  text-decoration: none;
}
.map-filter:hover { color: var(--color-text); border-color: var(--color-text-muted); }

/* Fill AND weight AND aria-current — three encodings, none of them garnet. */
.map-filter--here {
  background: var(--color-state);
  border-color: var(--color-state);
  color: var(--color-state-text);
  font-weight: var(--weight-semi);
}
.map-filter--here:hover { color: var(--color-state-text); border-color: var(--color-state); }

/* --------------------------------------------------------------------- body */
.map-body { margin-top: var(--space-6); }

.map-lead {
  font-size: var(--text-md);
  color: var(--color-text-muted);
}

.map-section + .map-section { margin-top: var(--space-6); }

.map-section__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.map-section__more {
  margin-top: var(--space-3);
  font-size: var(--text-md);
  color: var(--color-text-muted);
}

.map-list {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

/* ---------------------------------------------------------------- node card
   Title first. The slug is secondary and small — it stopped being the
   headline, which is most of what was wrong with the old surface. */
.map-card {
  position: relative;
  min-width: 0;
  padding: var(--space-2) var(--space-4) var(--space-3) var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.map-card::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--map-rail);
  border-start-start-radius: var(--radius-lg);
  border-end-start-radius: var(--radius-lg);
  background: var(--color-border-strong);
}

.map-card__title {
  font-size: var(--text-base);
  line-height: var(--leading-snug);
}
.map-card__link { text-decoration: none; }
.map-card__link:hover { text-decoration: underline; }

/* The whole card is the tap target; nothing else inside it is interactive. */
.map-card__link::after { content: ""; position: absolute; inset: 0; }

.map-card__marks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin-top: var(--space-1);
}

.map-card__block {
  margin-top: var(--space-1);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  color: var(--color-text-muted);
}

.map-card__origin {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin-top: var(--space-1);
  font-size: var(--text-2xs);
  color: var(--color-text-subtle);
  overflow-wrap: anywhere;
}
.map-card__slug { font-family: var(--font-mono); }
.map-card__strand::before { content: "· "; }

/* Card states. Rail treatment + word, every time. */
.map-card--flight::before { background: var(--color-state); }
.map-card--held::before   { background: var(--color-counted); }
.map-card--ready::before {
  background: repeating-linear-gradient(
    to bottom,
    var(--color-state) 0 4px,
    transparent 4px 8px
  );
}
.map-card--locked {
  background: var(--color-surface-sunk);
  border-style: dashed;
}
.map-card--locked::before { background: var(--color-border-strong); }
.map-card--locked .map-card__title { color: var(--color-text-muted); }

/* A demotion is a loss, and a loss is the one thing on this page allowed to be
   garnet. It is hatched as well, so it survives a greyscale screenshot. */
.map-card--moved::before { background: var(--color-loss); }
.map-card--moved { background-image: var(--map-hatch-soft); }

/* -------------------------------------------------------------------- marks */
.map-mark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
}
.map-mark__numeral {
  font-family: var(--font-mono);
  font-weight: var(--weight-bold);
  color: var(--color-text);
}
.map-mark--rung { background: var(--color-surface-sunk); }
.map-mark--check {
  border-color: color-mix(in srgb, var(--color-state) 40%, transparent);
  background: var(--color-state-wash);
  color: var(--color-state);
  font-weight: var(--weight-medium);
}
.map-mark--moved {
  border-color: var(--color-loss);
  color: var(--color-loss);
  font-weight: var(--weight-semi);
  background-image: var(--map-hatch);
}
.map-mark--state { border-style: dashed; }

/* ------------------------------------------------------- track / strand tree
   Server-side drill-down: a closed row renders no concepts at all, which is
   what keeps `All` from being 308 nodes again. */
.map-groups { display: grid; gap: var(--space-3); margin-top: var(--space-4); }

.map-group {
  padding: var(--space-2) var(--space-3) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
}
.map-group--open { border-color: var(--color-border-strong); }

.map-disclosure {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-1) 0;
  color: var(--color-text);
  text-decoration: none;
}
.map-disclosure__caret {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-md);
  color: var(--color-text-muted);
}
.map-disclosure__name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semi);
  line-height: var(--leading-snug);
  overflow-wrap: anywhere;
}
.map-disclosure--strand .map-disclosure__name { font-size: var(--text-md); font-weight: var(--weight-medium); }
.map-disclosure__count {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  color: var(--color-text-subtle);
  white-space: nowrap;
}
.map-disclosure:hover .map-disclosure__name { text-decoration: underline; }

.map-strands {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border-soft);
}
.map-strand-row {
  padding: var(--space-1) var(--space-3) var(--space-2);
  border: 1px solid var(--color-border-soft);
  border-radius: var(--radius-lg);
  background: var(--color-surface-sunk);
}
.map-strand-row--open { border-color: var(--color-border-strong); background: var(--color-surface); }

/* ------------------------------------------------- rung distribution (no %)
   A distribution, never a percent-of-course bar. It can move backwards, and
   the hatched key is how a demotion shows up in the shape. */
.map-dist { margin-top: var(--space-1); }

.map-dist__bar {
  display: flex;
  height: 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.map-dist__seg { flex-basis: 0; min-width: 3px; }
.map-dist__seg + .map-dist__seg { border-inline-start: 1px solid var(--color-surface); }
.map-dist__seg--0 { background: var(--map-rung-0); }
.map-dist__seg--1 { background: var(--map-rung-1); }
.map-dist__seg--2 { background: var(--map-rung-2); }
.map-dist__seg--3 { background: var(--map-rung-3); }
.map-dist__seg--4 { background: var(--map-rung-4); }
.map-dist__seg--5 { background: var(--map-rung-5); }
.map-dist__seg--6 { background: var(--map-rung-6); }

.map-dist__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}
.map-dist__key { display: inline-flex; align-items: center; gap: var(--space-1); }
.map-dist__key b { font-family: var(--font-mono); color: var(--color-text); }
.map-dist__key::before {
  content: "";
  width: 8px;
  height: 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xs);
}
.map-dist__key--0::before { background: var(--map-rung-0); }
.map-dist__key--1::before { background: var(--map-rung-1); }
.map-dist__key--2::before { background: var(--map-rung-2); }
.map-dist__key--3::before { background: var(--map-rung-3); }
.map-dist__key--4::before { background: var(--map-rung-4); }
.map-dist__key--5::before { background: var(--map-rung-5); }
.map-dist__key--6::before { background: var(--map-rung-6); }
.map-dist__key--moved { color: var(--color-loss); font-weight: var(--weight-semi); }
.map-dist__key--moved::before { border-color: var(--color-loss); background-image: var(--map-hatch); }

/* -------------------------------------------------------------- empty state
   Never a blank, and never without a route out. */
.map-empty {
  padding: var(--space-6) var(--space-5);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  text-align: center;
}
.map-empty h2 { font-size: var(--text-xl); }
.map-empty .note { margin-inline: auto; }
.map-empty__routes {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
}
.map-empty__routes .btn { width: auto; text-decoration: none; }

.map-body__out { margin-top: var(--space-5); }

/* ------------------------------------------------------------------ wider */
@media (min-width: 48rem) {
  .map-search { max-width: 34rem; }
  .map-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
  .map-group { padding: var(--space-3) var(--space-5) var(--space-5); }
}

@media (min-width: 72rem) {
  .map-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
