/* ══════════════════════════════════════════════════════════════════════════
   THE DIRECTORY GRID  ·  /colleges
   ══════════════════════════════════════════════════════════════════════════

   Replaced the text list on 2026-09-07, when the record went from 60 colleges to
   1,458 and the old page became 564 KB of unbroken links. At that size the
   problem stopped being aesthetic: nobody shortlists from a list of 1,115 names
   under one heading, and PRODUCT.md names a low-cost Android on mobile data as
   the primary reading device.

   Three things carry it. A mark per college so the eye has something to catch, a
   filter so the list can be cut down, and `content-visibility` so a phone does
   not lay out cards it cannot see.

   ⚠️ **THIS IS HEAVIER THAN WHAT IT REPLACED AND THAT IS A TRADE, NOT A WIN.**
   The same 1,458 colleges went from 564 KB to 969 KB of HTML, 89 KB gzipped,
   because every row gained a tile, a wrapper and a status flag. Two rounds of
   trimming got it down from 1,069 KB by deleting `data-name` and `data-place`,
   which duplicated text already in the card; the script reads that text instead.
   What is bought is a scannable grid and a working filter. What protects the
   phone is `content-visibility` and lazy images, which cut LAYOUT and DECODE
   rather than bytes — the cost that actually stalls a cheap Android on a list
   this long. If the byte count has to come down further, the answer is fewer
   cards on first paint, not a thinner card.

   ⚠️ Its own stylesheet rather than more of `ice-colleges.css`, which is shared
   with the college PAGE. The directory is the only surface with 1,460 of
   anything and its performance rules have no business on a profile.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── the tile ──────────────────────────────────────────────────────────────
   Logo and monogram share one plate at one size. 153 of 1,460 colleges publish a
   logo, so a grid that styles the two differently reads as broken on the other
   1,307; the monogram is the design and the logo replaces its contents. */

.ctile {
  --ctile-size: 52px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: var(--ctile-size);
  block-size: var(--ctile-size);
  border-radius: 12px;
  background: var(--ctile-plate, #eef1f6);
  box-shadow: inset 0 0 0 1px var(--ctile-edge, rgb(15 23 42 / 8%));
  overflow: hidden;
}

.ctile[data-size="128"] { --ctile-size: 72px; border-radius: 16px; }

.ctile__img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  /* ⚠️ `contain`, never `cover`. Many of these marks are wordmarks three times
     wider than they are tall, and cropping one square makes it a different logo.
     The padding keeps a full-bleed favicon off the plate's rounded corner. */
  padding: 6px;
}

.ctile__mono {
  font-size: calc(var(--ctile-size) * 0.32);
  font-weight: 650;
  letter-spacing: 0.01em;
  line-height: 1;
  color: var(--ctile-ink, #334155);
}

/* The province tints, all at one lightness so no province reads as more
   important than another, with the ink the same hue darkened rather than grey. */
.ctile[data-tint="koshi"]        { --ctile-plate: #e8f0fb; --ctile-ink: #234b86; --ctile-edge: rgb(35 75 134 / 14%); }
.ctile[data-tint="madhesh"]      { --ctile-plate: #fdeee9; --ctile-ink: #9a4526; --ctile-edge: rgb(154 69 38 / 14%); }
.ctile[data-tint="bagmati"]      { --ctile-plate: #eaf1ea; --ctile-ink: #2f5c3a; --ctile-edge: rgb(47 92 58 / 14%); }
.ctile[data-tint="gandaki"]      { --ctile-plate: #f3edfa; --ctile-ink: #58407f; --ctile-edge: rgb(88 64 127 / 14%); }
.ctile[data-tint="lumbini"]      { --ctile-plate: #fbf1e2; --ctile-ink: #85601f; --ctile-edge: rgb(133 96 31 / 14%); }
.ctile[data-tint="karnali"]      { --ctile-plate: #e6f2f2; --ctile-ink: #1f5f61; --ctile-edge: rgb(31 95 97 / 14%); }
.ctile[data-tint="sudurpaschim"] { --ctile-plate: #f7ecf1; --ctile-ink: #7e3556; --ctile-edge: rgb(126 53 86 / 14%); }

html[data-theme="dark"] .ctile[data-tint="koshi"]        { --ctile-plate: #16233a; --ctile-ink: #9dc0f0; }
html[data-theme="dark"] .ctile[data-tint="madhesh"]      { --ctile-plate: #3a1f16; --ctile-ink: #f0b199; }
html[data-theme="dark"] .ctile[data-tint="bagmati"]      { --ctile-plate: #16291b; --ctile-ink: #9ed0ac; }
html[data-theme="dark"] .ctile[data-tint="gandaki"]      { --ctile-plate: #241c34; --ctile-ink: #c1abe6; }
html[data-theme="dark"] .ctile[data-tint="lumbini"]      { --ctile-plate: #322611; --ctile-ink: #e2c483; }
html[data-theme="dark"] .ctile[data-tint="karnali"]      { --ctile-plate: #122a2b; --ctile-ink: #91cfd0; }
html[data-theme="dark"] .ctile[data-tint="sudurpaschim"] { --ctile-plate: #2f1723; --ctile-ink: #e3a3c0; }
html[data-theme="dark"] .ctile                           { --ctile-edge: rgb(255 255 255 / 10%); }

/* ⚠️ THE UNTINTED DEFAULT NEEDS A DARK VALUE TOO, and it did not have one.
   `data-tint` is the province, and the 171 hand-written and site-drafted records
   predate the province field: they carry a district and no province, so they
   fall through every tint rule to the base plate. In dark mode that left a
   near-white #eef1f6 square with near-black initials sitting in a row of dark
   tiles. Caught by reading the computed background on a dark render, not by
   looking at a screenshot of the tinted ones. */
html[data-theme="dark"] .ctile {
  --ctile-plate: #23262c;
  --ctile-ink: #c3c9d4;
}

html[data-theme="dark"] .ctile__img {
  /* A dark-on-transparent wordmark vanishes on a dark plate. A light backing
     keeps it legible without inverting the mark, which would misrepresent the
     institution's own colours. */
  background: rgb(255 255 255 / 92%);
  border-radius: 8px;
}

/* ── the filter ────────────────────────────────────────────────────────────
   Hidden until the script claims it with `data-ready`. A control that does
   nothing when clicked is a worse failure than an absent one, and every card is
   server-rendered so the page is complete without it. */

.cdir-filter { display: none; }

.cdir-filter[data-ready="true"] {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  align-items: end;
  margin: 0 0 2rem;
  padding: 1rem;
  border-radius: var(--pf-radius, 14px);
  background: var(--edu-glass, rgb(255 255 255 / 60%));
  box-shadow: inset 0 0 0 1px var(--edu-glass-edge, rgb(255 255 255 / 75%)),
              0 1px 2px rgb(12 26 56 / 5%),
              0 10px 28px -20px rgb(12 26 56 / 30%);
}

.cdir-filter__field { display: grid; gap: 6px; min-inline-size: 0; }

.cdir-filter__field label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ice-color-text-muted);
}

.cdir-filter input,
.cdir-filter select {
  inline-size: 100%;
  min-inline-size: 0;
  padding: 0.6rem 0.75rem;
  font: inherit;
  font-size: 0.9375rem;
  color: var(--ice-color-text);
  background: var(--ice-color-bg);
  border: 1px solid var(--ice-color-border, rgb(15 23 42 / 14%));
  border-radius: 10px;
  transition: border-color 140ms var(--edu-ease, ease), box-shadow 140ms var(--edu-ease, ease);
}

.cdir-filter input:focus-visible,
.cdir-filter select:focus-visible {
  outline: none;
  border-color: var(--ice-color-action, #2F5BA8);
  box-shadow: 0 0 0 3px rgb(47 91 168 / 18%);
}

.cdir-filter input::placeholder { color: var(--ice-color-text-muted); opacity: 1; }

.cdir-filter__count {
  margin: 0;
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--ice-color-text-muted);
}

@media (min-width: 720px) {
  .cdir-filter[data-ready="true"] {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1.4fr) auto;
  }
  .cdir-filter__count { padding-block-end: 0.7rem; white-space: nowrap; }
}

/* ── groups and grid ─────────────────────────────────────────────────────── */

.cdir { display: grid; gap: 2.5rem; }
.cdir__group[hidden] { display: none; }

.cdir__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding-block-end: 0.6rem;
  border-block-end: 1px solid var(--ice-color-border, rgb(15 23 42 / 12%));
}

.cdir__head h2 { margin: 0; font-size: 1.125rem; letter-spacing: -0.01em; }

.cdir__count {
  margin: 0;
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--ice-color-text-muted);
}

.cdir__rule {
  margin: 0.75rem 0 0;
  max-inline-size: 68ch;
  font-size: 0.875rem;
  color: var(--ice-color-text-muted);
}

.cdir__grid {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  /* ⚠️ The most important line on this page. 1,460 cards is more than a cheap
     Android lays out without stalling, and this skips the offscreen ones.
     `contain-intrinsic-size` supplies a height so the scrollbar does not jump
     as they resolve. */
  content-visibility: auto;
  contain-intrinsic-size: auto 76px;
}

@media (min-width: 640px)  { .cdir__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1080px) { .cdir__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ── the card ────────────────────────────────────────────────────────────── */

.ccard {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-inline-size: 0;
  padding: 10px 12px;
  border-radius: var(--pf-radius, 14px);
  background: var(--ice-color-bg);
  box-shadow: inset 0 0 0 1px var(--ice-color-border, rgb(15 23 42 / 10%));
  transition: box-shadow 160ms var(--edu-ease, ease), transform 160ms var(--edu-ease, ease);
}

.ccard.is-out { display: none; }

.ccard:hover,
.ccard:focus-within {
  box-shadow: inset 0 0 0 1px var(--ice-color-action, #2F5BA8),
              0 2px 4px rgb(12 26 56 / 6%),
              0 12px 24px -18px rgb(12 26 56 / 40%);
  transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
  .ccard { transition: none; }
  .ccard:hover, .ccard:focus-within { transform: none; }
}

.ccard__body { min-inline-size: 0; display: grid; gap: 2px; }

.ccard__link {
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ice-color-text);
  text-decoration: none;
  /* Two lines then ellipsis. A Nepali college name runs long, and a card that
     grows to fit the longest one leaves holes across its whole row. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The whole card is the target so a thumb does not have to find the text, while
   the link keeps the accessible name to itself. */
.ccard__link::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.ccard__link:hover { color: var(--ice-color-action, #2F5BA8); }
.ccard__link:focus-visible { outline: 2px solid var(--ice-color-action, #2F5BA8); outline-offset: 3px; }

.ccard__meta {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ice-color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ccard__flag {
  position: relative;
  flex: 0 0 auto;
  align-self: flex-start;
  margin-block-start: 2px;
  padding: 2px 7px;
  font-size: 0.6875rem;
  font-weight: 600;
  border-radius: 999px;
  color: #92400e;
  background: rgb(180 83 9 / 10%);
}

html[data-theme="dark"] .ccard__flag { color: #fbbf24; background: rgb(251 191 36 / 12%); }

.cdir__empty {
  margin: 0;
  padding: 1.5rem;
  border-radius: var(--pf-radius, 14px);
  background: rgb(15 23 42 / 4%);
  color: var(--ice-color-text-muted);
  text-align: center;
}

html[data-theme="dark"] .cdir__empty { background: rgb(255 255 255 / 5%); }
