/* ============================================================================
   NIVAS — IIT Hyderabad hostel explorer
   Design system. Read docs/DESIGN.md before changing anything in this file.

   Structure:
     01 Tokens          07 Status key
     02 Base            08 Views (3D / map / site / floor)
     03 Primitives      09 Room detail panel
     04 Header pill     10 Modals + requests
     05 Page + card     11 Component refinements
     06 Stage row       12 Toast, responsive, a11y

   Rule: no hard-coded colours below section 01. Every value is a token.
   ========================================================================= */

/* ── 01 Tokens ───────────────────────────────────────────────────────────── */

:root {
  /* Brand — institute red. Reserved for interactive/branded elements ONLY.
     Never used for room status, so a red button is never confused with a
     red room. See --status-* below. */
  --brand-700: #7e1425;
  --brand-600: #a91f32;
  --brand-500: #c22c3d;
  --brand-200: #f6cabf;
  --brand-100: #ffe0d3;
  --brand-50:  #fff0e6;

  /* Accent — logo orange. Highlights, focus rings, live indicators. */
  --accent-700: #c0430f;
  --accent-600: #d8481e;
  --accent-500: #f05a25;
  --accent-100: #ffdfca;
  --accent-50:  #fff4ec;

  /* Warm neutrals */
  --ink-900:   #15171b;
  --ink-800:   #222831;
  --ink-600:   #46515e;
  --ink-500:   #5d6978;
  --ink-400:   #738093;
  --line:      #dbe2ea;
  --line-soft: #e9eef4;
  --surface:   #ffffff;
  --surface-sunk: #f3f6f9;
  --canvas:    #eef2f6;
  --scene:     #24181b;

  /* On dark (3D viewer overlays) */
  --on-scene:       #fff5ec;
  --on-scene-muted: #f3c9b1;
  --on-scene-label: #ffc5a6;
  --scene-panel:    rgba(38, 23, 25, .84);
  --scene-edge:     rgba(255, 218, 196, .24);
  --overlay-backdrop: rgba(15, 21, 30, .48);
  --brand-action-shadow: 0 12px 24px rgba(169, 31, 50, .22);

  /* Room status colours reflect only student-submitted swap information.
     Traffic-light reading, set by Chandan 2026-07-26: red = registered but
     not moving (no swap possible), yellow = open to swap, green = match.
     The red is deliberately a warmer, brighter vermilion than --brand-600 so
     a status swatch never reads as a brand button. */
  --status-unlisted:       #514346;
  --status-unlisted-tint:  #eee7e2;
  --status-occupied:       #d6452f;
  --status-occupied-tint:  #fbe4de;
  --status-open:           #e0a318;
  --status-open-tint:      #fdf1d3;
  --status-match:          #2f9161;
  --status-match-tint:     #e0f1e7;
  /* Pink: one or more students have bookmarked this room as a destination.
     Overlay tier, not a listing state — see statusAtFor() in app.js. */
  --status-waitlist:       #d6437e;
  --status-waitlist-tint:  #fbe1ec;

  /* Radius — one scale, no ad-hoc values */
  --r-xs:   4px;
  --r-sm:   12px;
  --r-md:   16px;
  --r-lg:   22px;
  --r-xl:   30px;
  --r-pill: 999px;

  /* Space — 4px base */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;

  /* Type */
  --font-sans:    Manrope, system-ui, -apple-system, sans-serif;
  --font-mono:    'DM Mono', ui-monospace, SFMono-Regular, monospace;
  --font-display: 'Playfair Display', Georgia, serif;

  --fs-micro: 10px;
  --fs-xs:    12px;
  --fs-sm:    14px;
  --fs-md:    15px;
  --fs-lg:    15px;
  --fs-xl:    18px;
  --fs-2xl:   24px;
  --fs-3xl:   32px;
  --fs-4xl:   40px;

  --lh-tight: 1.2;
  --lh-base:  1.55;
  --lh-loose: 1.7;

  --track-mono: .09em;  /* mono labels are always tracked out */

  /* Elevation */
  --e-1: 0 2px 5px rgba(20, 31, 47, .05);
  --e-2: 0 10px 30px rgba(20, 31, 47, .08);
  --e-3: 0 20px 48px rgba(20, 31, 47, .12);
  --e-4: 0 30px 72px rgba(20, 31, 47, .2);

  /* Layout — the stage row's one adjustable dimension */
  --detail-w: 316px;

  /* Motion */
  --t-fast: 120ms;
  --t-base: 200ms;
  --ease:   cubic-bezier(.32, .72, .32, 1);

  --focus-ring: 0 0 0 3px var(--accent-100);
}

/* ── 02 Base ─────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink-800);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; line-height: var(--lh-tight); letter-spacing: -.02em; }

.hidden { display: none !important; }

:focus-visible {
  outline: 2px solid var(--accent-500);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* Mono label — the recurring small-caps eyebrow used across every panel */
.u-label {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-500);
}

/* ── 03 Primitives ───────────────────────────────────────────────────────── */

/* Buttons. Every clickable control in the app is one of these four.
   .btn            base — never used alone
   .btn--primary   solid brand, one per view maximum
   .btn--secondary tinted, safe to repeat
   .btn--ghost     text-only
   .icon-btn       square, icon only
   .seg-btn        inside a .segmented group
   .chip           small pill, often a toggle                                */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  padding: var(--s-3) var(--s-4);
  font: 700 var(--fs-xs) var(--font-sans);
  line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.btn b { font-size: var(--fs-lg); line-height: 0; font-weight: 400; }

.btn--primary {
  background: var(--brand-600);
  color: #fff;
  box-shadow: var(--e-1);
}
.btn--primary:hover { background: var(--brand-700); }

.btn--secondary {
  background: var(--brand-50);
  color: var(--brand-600);
  border-color: var(--brand-100);
}
.btn--secondary:hover { background: var(--brand-100); }

.btn--ghost {
  background: transparent;
  color: var(--ink-500);
  padding: var(--s-2) var(--s-3);
}
.btn--ghost:hover { background: var(--surface-sunk); color: var(--ink-800); }

/* Outline — a secondary action that must not compete with .btn--primary but
   still reads as branded. Used by the header's feature-request button. */
.btn--outline {
  background: transparent;
  color: var(--brand-600);
  border-color: var(--brand-600);
}
.btn--outline:hover { background: var(--brand-50); border-color: var(--brand-700); color: var(--brand-700); }

.btn--block { width: 100%; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink-600);
  font-size: var(--fs-lg);
  line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.icon-btn:hover { background: var(--brand-50); color: var(--brand-600); }
.icon-btn:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
.icon-btn--quiet { border-color: transparent; background: transparent; }

/* Segmented control — view switcher, request tabs */
.segmented {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.seg-btn {
  border: 0;
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  background: transparent;
  color: var(--ink-500);
  font: 700 var(--fs-micro) var(--font-sans);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.seg-btn span { font-size: var(--fs-md); margin-right: var(--s-1); }
.seg-btn:hover { color: var(--ink-800); }
.seg-btn.active {
  background: var(--surface);
  color: var(--brand-600);
  box-shadow: var(--e-1);
}
.seg-btn:focus-visible { outline: 0; box-shadow: var(--focus-ring); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding: var(--s-2) var(--s-3);
  background: var(--surface);
  color: var(--brand-600);
  font: 700 var(--fs-micro) var(--font-sans);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.chip span { font-size: var(--fs-md); }
.chip:hover { background: var(--brand-50); }
.chip.active {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: #fff;
  box-shadow: var(--e-2);
}
.chip:focus-visible { outline: 0; box-shadow: var(--focus-ring); }

/* Status pill — read-only state label */
.pill {
  display: inline-block;
  border-radius: var(--r-pill);
  padding: 5px var(--s-3);
  font: 700 var(--fs-micro) var(--font-sans);
}
.pill--unlisted { background: var(--status-unlisted-tint); color: var(--ink-600); }
.pill--occupied { background: var(--status-occupied-tint); color: #2f6242; }
.pill--open     { background: var(--status-open-tint);     color: #8a6011; }
.pill--match    { background: var(--status-match-tint);    color: #246475; }
.pill--waitlist { background: var(--status-waitlist-tint); color: #9c2d5f; }

.avatar {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: var(--r-pill);
  background: linear-gradient(135deg, var(--accent-500), var(--brand-600));
  color: #fff;
  font: 700 var(--fs-micro) var(--font-sans);
}
.avatar--lg { width: 38px; height: 38px; font-size: var(--fs-xs); }
.avatar--private { background: linear-gradient(135deg, var(--ink-400), var(--ink-600)); }

/* Form fields — six-column grid so a row can be 3-up (span-2) or 2-up
   (span-3). The listing form's details fit in exactly two rows. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--s-4);
}
.form-grid > .span-1 { grid-column: span 1; }
.form-grid > .span-2 { grid-column: span 2; }
.form-grid > .span-3 { grid-column: span 3; }
.form-grid > .span-4 { grid-column: span 4; }
.form-grid > label { display: grid; gap: var(--s-2); color: var(--ink-800); font: 700 var(--fs-xs) var(--font-sans); }
.form-grid input {
  width: 100%;
  min-width: 0;
  min-height: 48px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  padding: 0 var(--s-4);
  color: var(--ink-900);
  font: 500 var(--fs-sm) var(--font-sans);
  outline: 0;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.form-grid input::placeholder { color: var(--ink-400); font-weight: 400; }
.form-grid input:focus { border-color: var(--accent-500); background: var(--surface); box-shadow: var(--focus-ring); }
.field-label { display: flex; align-items: baseline; gap: var(--s-2); }
.field-optional { color: var(--ink-400); font: 500 var(--fs-micro) var(--font-sans); font-style: normal; }
.form-grid textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  padding: var(--s-3) var(--s-4);
  color: var(--ink-900);
  font: 500 var(--fs-sm) var(--font-sans);
  line-height: var(--lh-base);
  resize: vertical;
  outline: 0;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.form-grid textarea:focus { border-color: var(--accent-500); background: var(--surface); box-shadow: var(--focus-ring); }
.form-grid > .span-6 { grid-column: span 6; }
.form-note { margin: 0; color: var(--ink-400); font-size: var(--fs-micro); }
.choice-tiles--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.choice-tile--idea:has(input:checked) { border-color: var(--brand-600); background: var(--brand-50); box-shadow: 0 0 0 4px var(--brand-100); }
.choice-tile--idea:has(input:checked) .choice-mark { background: var(--brand-600); color: #fff; }
.choice-tile--bug:has(input:checked) { border-color: var(--status-occupied); background: var(--status-occupied-tint); box-shadow: 0 0 0 4px rgba(214, 69, 47, .14); }
.choice-tile--bug:has(input:checked) .choice-mark { background: var(--status-occupied); color: #fff; }
.choice-tile--other:has(input:checked) { border-color: var(--ink-600); background: var(--surface-sunk); box-shadow: 0 0 0 4px var(--line-soft); }
.choice-tile--other:has(input:checked) .choice-mark { background: var(--ink-600); color: #fff; }

.field-help { margin: 0 0 var(--s-3); color: var(--ink-500); font: 400 var(--fs-xs) var(--font-sans); }

/* Section heading inside a form — same type scale as the rest of the app,
   not a mono utility label. */
.section-head { margin-bottom: var(--s-4); }
.section-head h3 { font-size: var(--fs-lg); font-weight: 800; color: var(--ink-900); }
.section-head p { margin: var(--s-1) 0 0; color: var(--ink-500); font-size: var(--fs-xs); }

.form-actions { grid-column: 1 / -1; display: flex; align-items: center; gap: var(--s-3); }
.form-actions .btn--primary { margin-left: auto; min-height: 52px; padding: 0 var(--s-6); border-radius: var(--r-pill); font-size: var(--fs-sm); box-shadow: var(--brand-action-shadow); }
.form-actions .btn--ghost { color: var(--ink-400); }
.form-actions .btn--ghost:hover { color: var(--status-occupied); background: var(--status-occupied-tint); }

/* Legacy two-column form layout — still used by any non-listing form. */
.field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-4);
}
.field-grid label {
  display: grid;
  gap: var(--s-2);
  color: var(--ink-600);
  font: 700 var(--fs-micro) var(--font-sans);
}
.field-grid input,
.field-grid select,
.field-grid textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  padding: var(--s-3);
  color: var(--ink-800);
  font: 500 var(--fs-sm) var(--font-sans);
  outline: 0;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.field-grid input:focus,
.field-grid select:focus,
.field-grid textarea:focus {
  border-color: var(--accent-500);
  box-shadow: var(--focus-ring);
}
.field-grid textarea { min-height: 112px; resize: vertical; line-height: var(--lh-base); }
.field-grid label:has(textarea),
.field-grid .btn { grid-column: 1 / -1; }
.move-choice,
.move-details { grid-column: 1 / -1; margin: 0; min-width: 0; border: 0; padding: 0; }
.move-choice legend { padding: 0; margin-bottom: var(--s-1); color: var(--ink-900); font: 800 var(--fs-lg) var(--font-sans); }

/* The single most consequential answer in the form, so it gets two real
   tiles that state their consequence — not two radio dots. */
.choice-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.choice-tile {
  position: relative;
  display: grid;
  gap: var(--s-1);
  padding: var(--s-4) var(--s-4) var(--s-4) 60px;
  border: 2px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  cursor: pointer;
  transition: transform var(--t-base) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.choice-tile:hover { transform: translateY(-3px); box-shadow: var(--e-2); }
.choice-tile input { position: absolute; opacity: 0; pointer-events: none; }
.choice-mark {
  position: absolute;
  left: var(--s-4);
  top: var(--s-4);
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-pill);
  background: var(--surface-sunk);
  color: var(--ink-500);
  font-size: var(--fs-lg);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), transform var(--t-base) var(--ease);
}
.choice-tile:hover .choice-mark { transform: scale(1.08); }
.choice-tile strong { color: var(--ink-900); font-size: var(--fs-md); }
.choice-tile small { color: var(--ink-500); font-size: var(--fs-xs); line-height: var(--lh-base); }
.choice-tile small b { color: var(--ink-800); font-weight: 700; }

.choice-tile--open:has(input:checked) {
  border-color: var(--status-open);
  background: var(--status-open-tint);
  box-shadow: 0 0 0 4px rgba(224, 163, 24, .16);
}
.choice-tile--open:has(input:checked) .choice-mark { background: var(--status-open); color: #fff; }
.choice-tile--stay:has(input:checked) {
  border-color: var(--status-occupied);
  background: var(--status-occupied-tint);
  box-shadow: 0 0 0 4px rgba(214, 69, 47, .14);
}
.choice-tile--stay:has(input:checked) .choice-mark { background: var(--status-occupied); color: #fff; }
.choice-tile:focus-within { box-shadow: var(--focus-ring); }

.move-details { padding: var(--s-5); border: 1px solid var(--line-soft); border-radius: var(--r-lg); background: var(--surface-sunk); }
.preference-grid { display: grid; gap: var(--s-2); }
.preference-row { display: grid; grid-template-columns: 28px minmax(0, 1.4fr) minmax(0, 1fr); align-items: center; gap: var(--s-3); }
.preference-rank {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-500);
  font: 700 var(--fs-xs) var(--font-mono);
}

/* ── Custom dropdown ─────────────────────────────────────────────────────
   Every <select> in a form is replaced at runtime by this (enhanceSelect in
   app.js): the native element stays in the DOM for form state, this is what
   the student sees. Same language as the hostel picker in the toolbar. */
.select { position: relative; min-width: 0; }
.select select { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
.select-btn {
  width: 100%;
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0 var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  color: var(--ink-900);
  font: 600 var(--fs-sm) var(--font-sans);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.select-btn:hover { border-color: var(--brand-200); background: var(--surface); }
.select-btn:focus-visible { outline: 0; border-color: var(--accent-500); box-shadow: var(--focus-ring); }
.select-btn span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.select-btn.is-placeholder span { color: var(--ink-400); font-weight: 500; }
.select-btn b { flex: none; color: var(--ink-400); font-weight: 500; transition: transform var(--t-fast) var(--ease); }
.select.open .select-btn { border-color: var(--accent-500); background: var(--surface); }
.select.open .select-btn b { transform: rotate(180deg); }

.select-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 244px;
  overflow-y: auto;
  display: grid;
  gap: 2px;
  padding: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--e-3);
}
.select-option {
  border: 0;
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  background: transparent;
  color: var(--ink-600);
  font: 600 var(--fs-xs) var(--font-sans);
  text-align: left;
  cursor: pointer;
}
.select-option:hover { background: var(--brand-50); color: var(--brand-600); }
.select-option.selected { background: var(--brand-600); color: #fff; }
.select-menu::-webkit-scrollbar { width: 7px; }
.select-menu::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--r-pill); }

/* Card — the one container treatment */
.card {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--e-1);
}

/* ── 04 Top header ───────────────────────────────────────────────────────── */

/* The header is a pill inside the page column, not a full-bleed website
   banner — same width, same radius language and same hairline as the explorer
   card below it, so it reads as part of the tool rather than a marketing
   header bolted on top. */
.app-shell {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.topbar {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: var(--s-6);
  min-height: 92px;
  flex: none;
  padding: var(--s-4) var(--s-4) var(--s-4) var(--s-6);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background:
    radial-gradient(120% 180% at 88% 0%, var(--brand-50), transparent 62%),
    linear-gradient(90deg, var(--surface) 0%, var(--accent-50) 100%);
  box-shadow: var(--e-1);
}
/* The facade's louvre rhythm, barely there, fading in from the right. */
.topbar:after {
  content: '';
  position: absolute;
  inset: 0 0 0 auto;
  width: 340px;
  background: repeating-linear-gradient(90deg, rgba(169, 31, 50, .10) 0 3px, transparent 3px 11px);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000);
  mask-image: linear-gradient(90deg, transparent, #000);
  pointer-events: none;
}
.topbar-id { position: relative; z-index: 1; display: flex; align-items: center; gap: var(--s-4); min-width: 0; }
.topbar-tag { display: grid; gap: 3px; padding-left: var(--s-4); border-left: 1px solid var(--brand-100); }
.topbar-tag span { font: var(--fs-micro) var(--font-mono); letter-spacing: var(--track-mono); color: var(--brand-600); }
.topbar-tag small { color: var(--ink-500); font-size: var(--fs-xs); }

/* Campus-wide total, always visible — distinct from .head-stat, which is
   scoped to whichever hostel is currently selected below. Styled as a live
   pill (pulsing dot) rather than plain text, so it reads as "updating now",
   not a static label. */
.campus-stat {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--status-match);
  border-radius: var(--r-pill);
  background: var(--status-match-tint);
  white-space: nowrap;
}
.campus-stat strong { font: 800 var(--fs-lg) var(--font-sans); line-height: 1; letter-spacing: -.02em; color: #246145; }
.campus-stat small { color: #246145; font-size: var(--fs-xs); font-weight: 600; }
.live-dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--status-match);
  box-shadow: 0 0 0 0 rgba(47, 145, 97, .5);
  animation: live-pulse 2s ease-out infinite;
}
@keyframes live-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(47, 145, 97, .5); }
  70%  { box-shadow: 0 0 0 7px rgba(47, 145, 97, 0); }
  100% { box-shadow: 0 0 0 0 rgba(47, 145, 97, 0); }
}
.topbar-actions { position: relative; z-index: 1; display: flex; align-items: center; gap: var(--s-3); margin-left: auto; }
.topbar-actions .btn { min-height: 44px; padding: 0 var(--s-5); border-radius: var(--r-pill); font-size: var(--fs-sm); }

.topbar-cta { flex: none; box-shadow: var(--brand-action-shadow); white-space: nowrap; }
.topbar-cta b { margin-left: var(--s-1); }

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex: none;
  color: var(--brand-700);
  text-decoration: none;
  font: 800 var(--fs-xl) var(--font-sans);
  letter-spacing: .1em;
}
.brand small {
  display: block;
  margin-top: 2px;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-400);
}
.brand-mark {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 28px;
  width: 26px;
  transform: skewY(-22deg);
}
.brand-mark i { display: block; width: 7px; border-radius: var(--r-xs); background: var(--accent-500); }
.brand-mark i:nth-child(1) { height: 16px; }
.brand-mark i:nth-child(2) { height: 26px; background: var(--brand-600); }
.brand-mark i:nth-child(3) { height: 20px; }

/* ── 05 Page — header pill, headline row, explorer card ─────────────────── */

.page {
  max-width: 1320px;
  width: 100%;
  margin: 0 auto;
  padding: var(--s-5) var(--s-6) var(--s-8);
}

/* Headline left, the selected hostel's live counts right. The counts used to
   sit under the artifact, where they read as an afterthought. */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-8);
  margin: var(--s-8) 0 var(--s-5);
}
.page-head-copy h1 {
  font-size: var(--fs-3xl);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--ink-900);
}
.page-head-copy h1 em { font-style: normal; color: var(--brand-600); }
.page-head-copy p { margin: var(--s-2) 0 0; color: var(--ink-500); font-size: var(--fs-sm); }
.page-head-copy strong { color: var(--ink-800); font-weight: 700; }

/* Counts read as solid chips rather than loose numerals — a status swatch,
   the figure, then what it counts. */
.head-stats { display: flex; align-items: center; gap: var(--s-3); flex: none; }
.head-stat {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--e-1);
  white-space: nowrap;
}
.head-stat:before {
  content: '';
  width: 8px;
  height: 8px;
  align-self: center;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--ink-400);
}
.head-stat--open:before  { background: var(--status-open); }
.head-stat--match:before { background: var(--status-match); }
.head-stat strong { font: 800 var(--fs-xl) var(--font-sans); line-height: 1; letter-spacing: -.02em; color: var(--ink-900); }
.head-stat small { color: var(--ink-500); font-size: var(--fs-xs); font-weight: 600; }
.head-activity { min-height: 42px; padding: 0 var(--s-4); border-radius: var(--r-pill); font-size: var(--fs-xs); }

/* One card: toolbar / stage row / key bar, divided by hairlines. It must NOT
   clip its overflow — that's what was cutting off the hostel dropdown. The
   corners are rounded on the first and last children instead. */
.explorer-card {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--e-2);
}

.toolbar {
  position: relative;
  z-index: 5;            /* above the stage, so the hostel menu drops over it */
  height: 64px;
  display: flex;
  align-items: center;
  gap: var(--s-5);
  padding: 0 var(--s-5);
  border-bottom: 1px solid var(--line);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  background: var(--surface-sunk);
}
/* Picker left, key in the middle, view switch pinned to the right corner. */
.toolbar .key { margin-left: var(--s-4); }
.view-switch { margin-left: auto; }

.building-picker { position: relative; display: flex; align-items: center; }
.building-choice {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  border: 0;
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-3);
  background: transparent;
  text-align: left;
  color: var(--ink-800);
  cursor: pointer;
}
.building-choice:hover { background: var(--surface-sunk); }
.building-dot {
  position: relative;
  height: 26px;
  width: 26px;
  border-radius: var(--r-sm);
  background: linear-gradient(135deg, var(--brand-600), var(--accent-500));
}
.building-dot:after {
  content: '';
  position: absolute;
  inset: 5px;
  border-radius: 2px;
  background: repeating-linear-gradient(90deg, var(--canvas) 0 2px, transparent 2px 5px);
}
.building-choice small {
  display: block;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-400);
}
.building-choice strong { display: block; margin-top: 2px; font-size: var(--fs-sm); }
.building-choice > b { margin-left: var(--s-1); color: var(--ink-400); font-weight: 500; }

.building-menu {
  position: absolute;
  z-index: 20;
  top: 46px;
  left: var(--s-6);
  width: 296px;
  max-height: 288px;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px;
  padding: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--e-3);
}
.building-option {
  border: 0;
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  background: transparent;
  color: var(--ink-600);
  font: 600 var(--fs-micro) var(--font-sans);
  text-align: left;
  cursor: pointer;
}
.building-option:hover { background: var(--brand-50); color: var(--brand-600); }
.building-option.selected { background: var(--brand-600); color: #fff; }
.building-menu::-webkit-scrollbar { width: 7px; }
.building-menu::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--r-pill); }

/* ── 06 Stage row — floors | artifact | room detail ─────────────────────── */

/* Three real columns. Nothing is absolutely positioned over the artifact any
   more: floating cards are what produced the overlap bugs, and they stole the
   space the model needed. */
.stage-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr) var(--detail-w);
  grid-template-areas: "rail stage detail";
  height: clamp(460px, 64vh, 660px);
  overflow: hidden;                                  /* clips to the card's */
  border-radius: 0 0 var(--r-xl) var(--r-xl);        /* bottom corners      */
}

.floor-rail {
  grid-area: rail;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-4) 0;
  overflow-y: auto;
  border-right: 1px solid var(--line);
  background: var(--surface-sunk);
}
.floor-rail-label {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-400);
}
.floor-rail-buttons { display: grid; gap: var(--s-1); }
.floor-rail button {
  width: 38px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink-600);
  font: 600 var(--fs-xs) var(--font-mono);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.floor-rail button:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-600); }
.floor-rail button.active {
  border-color: var(--brand-600);
  background: var(--brand-600);
  color: #fff;
  box-shadow: var(--e-1);
}
.floor-all { margin-top: var(--s-2); font-size: var(--fs-micro) !important; }

.panel-stage { grid-area: stage; position: relative; min-width: 0; overflow: hidden; }
.hero-model, .visual-stage { position: absolute; inset: 0; }
.hero-model { overflow: hidden; background: var(--scene); }
.visual-stage { background: var(--surface-sunk); }

/* The right column holds room detail and nothing else. Its background carries
   the selected room's status, so the colour reading doesn't depend on
   noticing a small pill. */
/* A stack of cards on a recessed column, so the detail reads as an object
   sitting on the page rather than a long tinted strip down the side. */
.room-detail {
  grid-area: detail;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  min-height: 0;
  overflow-y: auto;
  padding: var(--s-4);
  border-left: 1px solid var(--line);
  background: var(--surface-sunk);
}
#panel-detail { display: flex; flex-direction: column; gap: var(--s-3); }

.detail-card {
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--e-1);
}
/* The identity card carries the room's status colour. */
.detail-card--open     { background: var(--status-open-tint);     border-color: var(--status-open); }
.detail-card--occupied { background: var(--status-occupied-tint); border-color: var(--status-occupied); }
.detail-card--match    { background: var(--status-match-tint);    border-color: var(--status-match); }
.detail-card--unlisted { background: var(--status-unlisted-tint); border-color: var(--line); }
.detail-card--waitlist { background: var(--status-waitlist-tint); border-color: var(--status-waitlist); }

/* Title left, status pill hard right. */
.detail-head { display: flex; align-items: flex-start; gap: var(--s-2); }
.detail-head > div:first-child { flex: 1; min-width: 0; }
.detail-head p {
  margin: 0;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-500);
}
.detail-head h3 { margin-top: var(--s-1); font-size: var(--fs-xl); color: var(--ink-900); }
.detail-head .pill { flex: none; margin-left: auto; align-self: center; }
/* On a tinted card the pill's own tint disappears — give it a solid chip. */
.detail-card[class*="detail-card--"] .pill { background: rgba(255, 255, 255, .82); }
.detail-head .icon-btn { margin-left: var(--s-1); }

/* Room / Floor / Pod — the figures are the point, so they are set large. */
.detail-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid rgba(21, 23, 27, .10);
}
.detail-stats div { display: grid; gap: 2px; }
.detail-stats span { color: var(--ink-500); font: 600 var(--fs-micro) var(--font-sans); text-transform: uppercase; letter-spacing: .06em; }
.detail-stats strong { font: 800 var(--fs-xl) var(--font-sans); line-height: 1.1; color: var(--ink-900); }

.detail-card .resident-card { margin-top: var(--s-3); background: rgba(255, 255, 255, .7); border-color: rgba(255, 255, 255, .9); }
.detail-card .choice-title { margin: 0 0 var(--s-3); }

/* ── 07 Status key ──────────────────────────────────────────────────────── */

/* Lives in the toolbar. Four labels, nothing more — each one's explanation is
   a tooltip on hover or keyboard focus, so the key can't crowd the controls
   yet no colour goes unexplained. */
.key { display: flex; align-items: center; gap: var(--s-5); }
.key-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  cursor: help;
}
.key-item i { display: inline-block; height: 10px; width: 10px; flex: none; border-radius: 3px; }
.key-item b { color: var(--ink-600); font: 700 var(--fs-xs) var(--font-sans); white-space: nowrap; }
.key-item:hover b, .key-item:focus-visible b { color: var(--ink-900); }
.key-item i.unlisted { background: var(--status-unlisted); }
.key-item i.occupied { background: var(--status-occupied); }
.key-item i.open     { background: var(--status-open); box-shadow: 0 0 6px var(--status-open); }
.key-item i.match    { background: var(--status-match); box-shadow: 0 0 6px var(--status-match); }
.key-item i.waitlist { background: var(--status-waitlist); box-shadow: 0 0 6px var(--status-waitlist); }

.key-item small {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  z-index: 30;
  width: max-content;
  max-width: 210px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  background: var(--ink-900);
  color: #fff;
  font-size: var(--fs-micro);
  line-height: var(--lh-base);
  text-align: center;
  opacity: 0;
  transform: translate(-50%, -4px);
  pointer-events: none;
  box-shadow: var(--e-3);
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.key-item small:before {   /* pointer back up to the swatch */
  content: '';
  position: absolute;
  bottom: 100%;
  left: 50%;
  margin-left: -5px;
  border: 5px solid transparent;
  border-bottom-color: var(--ink-900);
}
.key-item:hover small, .key-item:focus-visible small { opacity: 1; transform: translate(-50%, 0); }

/* Honesty line — quiet, under the card, not a band inside it. */
.privacy-note {
  margin: var(--s-3) var(--s-1) 0;
  text-align: right;
  color: var(--ink-400);
  font-size: var(--fs-micro);
}
.site-footer {
  margin: var(--s-2) var(--s-1) 0;
  text-align: right;
  color: var(--ink-400);
  font-size: var(--fs-micro);
}
.footer-heart { color: var(--status-waitlist); }

/* ── 08 Views ────────────────────────────────────────────────────────────── */

/* 3D viewer */
.three-view { position: relative; width: 100%; height: 100%; overflow: hidden; background: var(--scene); }
.three-view canvas { display: block; width: 100%; height: 100%; outline: 0; }

.three-title {
  position: absolute;
  top: var(--s-6);
  left: var(--s-6);
  display: grid;
  gap: var(--s-1);
  color: var(--on-scene);
  pointer-events: none;
}
.three-title span {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--on-scene-label);
}
.three-title small { font: 600 var(--fs-xs) var(--font-sans); }

/* Shared treatment for every floating panel over the 3D scene */
.three-readout, .friend-city-hud {
  border: 1px solid var(--scene-edge);
  background: var(--scene-panel);
  color: var(--on-scene);
  backdrop-filter: blur(8px);
}
.three-readout {
  position: absolute;
  right: var(--s-5);
  top: var(--s-5);
  min-width: 224px;
  padding: var(--s-3);
  border-radius: var(--r-md);
  pointer-events: none;
}
.three-readout strong { display: block; font-size: var(--fs-xs); }
.three-readout span { display: block; margin-top: 3px; font-size: var(--fs-micro); color: var(--on-scene-muted); }

.friend-city-hud {
  position: absolute;
  left: var(--s-6);
  bottom: var(--s-6);
  z-index: 2;
  width: 256px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
}
.friend-city-hud > span {
  display: block;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--on-scene-label);
}
.friend-city-hud strong { display: block; margin: var(--s-1) 0; font-size: var(--fs-md); }
.friend-city-hud strong b { color: var(--accent-500); }
.friend-city-hud small { display: block; color: var(--on-scene-muted); font-size: var(--fs-micro); line-height: var(--lh-base); }
.friend-city-hud ul { display: grid; gap: 3px; margin: var(--s-2) 0 0; padding: 0; list-style: none; }
.friend-city-hud li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--on-scene-muted);
  font-size: var(--fs-micro);
}
.friend-city-hud li i { width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--status-intern); }
.friend-city-hud li i.mtech { background: var(--status-mtech); }
.friend-city-hud li i.phd { background: var(--status-graduate); }
.friend-city-hud li b { margin-left: auto; color: var(--on-scene); font: var(--fs-micro) var(--font-mono); }

.three-credit {
  position: absolute;
  left: 50%;
  bottom: var(--s-6);
  transform: translateX(-50%);
  color: var(--on-scene-muted);
  font-size: var(--fs-micro);
  text-align: center;
  opacity: .8;
  white-space: nowrap;
  pointer-events: none;
}
.friend-city .three-readout { top: auto; bottom: var(--s-6); }

/* Campus map */
.map-view { position: relative; height: 100%; background: var(--surface-sunk); }
.map-view #campus-map { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; border: 0; }
.map-title {
  position: absolute;
  z-index: 2;
  top: var(--s-6);
  left: var(--s-6);
  display: grid;
  gap: 3px;
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--e-2);
  pointer-events: none;
}
.map-title span {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--brand-600);
}
.map-title small { color: var(--ink-500); font-size: var(--fs-micro); }
.map-card {
  position: absolute;
  z-index: 2;
  right: var(--s-6);
  top: 66px;
  width: 204px;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--e-3);
}
.map-card p {
  margin: 0;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--brand-600);
}
.map-card h3 { margin: var(--s-2) 0 3px; font-size: var(--fs-lg); }
.map-card > span { color: var(--ink-500); font-size: var(--fs-micro); }
.map-card .btn { margin: var(--s-3) 0 var(--s-2); }
.map-card small { display: block; color: var(--ink-400); font-size: var(--fs-micro); line-height: 1.45; }

/* Site / facade view */
.site-view { position: relative; height: 100%; overflow: hidden; background: var(--scene); }
.facade-reference {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 58%;
  filter: saturate(.88) contrast(.95);
}
.facade-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(36, 24, 27, .5), rgba(36, 24, 27, .08) 52%, rgba(36, 24, 27, .28));
}
.site-title { position: absolute; top: var(--s-6); left: var(--s-6); z-index: 2; display: grid; gap: 3px; }
.site-title span {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--on-scene-label);
}
.site-title small { color: var(--on-scene-muted); font-size: var(--fs-micro); }
.north { position: absolute; right: var(--s-8); top: var(--s-6); color: var(--on-scene); font: var(--fs-micro) var(--font-mono); text-align: center; }
.north span { display: block; color: var(--accent-500); font-size: var(--fs-xl); line-height: 1; }

.facade-hotspot {
  position: absolute;
  left: 44%;
  top: 42%;
  z-index: 2;
  border: 1px solid var(--accent-100);
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-3);
  background: linear-gradient(135deg, var(--brand-600), var(--accent-600));
  color: #fff;
  text-align: left;
  box-shadow: var(--e-3);
  cursor: pointer;
}
.facade-hotspot:before {
  content: '';
  position: absolute;
  left: 22px;
  bottom: 100%;
  height: 34px;
  border-left: 1px dashed var(--accent-100);
}
.facade-hotspot span { display: block; font: var(--fs-micro) var(--font-mono); color: var(--accent-100); }
.facade-hotspot strong { display: block; margin-top: 2px; font: 700 var(--fs-sm) var(--font-sans); }
.facade-hotspot small { display: block; margin-top: 2px; color: var(--accent-50); font-size: var(--fs-micro); }

.site-card {
  position: absolute;
  right: var(--s-6);
  top: 70px;
  z-index: 2;
  width: 190px;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--e-3);
}
.site-card-cap {
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-400);
}
.site-card strong { display: block; margin-top: var(--s-2); font-size: var(--fs-lg); }
.site-card > span { display: block; margin: 3px 0 var(--s-3); color: var(--ink-500); font-size: var(--fs-micro); }

/* Floor plan — the drawing only. Floors are the rail to its left and room
   detail is the column to its right, both shared with the 3D view. */
.floor-view { height: 100%; background: var(--surface); }
.floor-canvas {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: var(--s-5);
}

/* Grows with the stage rather than a fixed height; the SVG's viewBox keeps the
   drawing's aspect ratio, so extra height is never distortion. */
.plan-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  margin: var(--s-3) calc(var(--s-1) * -1) 0;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--surface);
}
.floor-plan { width: 100%; height: 100%; overflow: visible; }
.blueprint { opacity: .84; }

.room {
  stroke: transparent;
  stroke-width: 2;
  opacity: .55;
  cursor: pointer;
  transition: filter var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.room:hover { opacity: .8; stroke: var(--ink-900); }
.room.unlisted { fill: var(--status-unlisted); opacity: .34; }
.room.occupied { fill: var(--status-occupied); }
.room.open { fill: var(--status-open); }
.room.match { fill: var(--status-match); }
.room.waitlist { fill: var(--status-waitlist); }
.room.selected-room { opacity: .9; stroke: var(--ink-900); stroke-width: 4; }

/* A cell the drawing shows but the building doesn't have: solid dark, struck
   through, no pointer. Deliberately wordless — the cross reads on its own. */
.room.void { fill: var(--status-unlisted); opacity: .58; cursor: default; pointer-events: none; }
.room-cross { stroke: var(--surface); stroke-width: 5; stroke-linecap: round; opacity: .85; pointer-events: none; }

/* Pod-hostel plan overlay (Vivekananda, S N Bose) */
.pod-plan-outline { display: none; }
.pod-layout .blueprint { opacity: 0; }
.pod-layout .pod-plan-outline { display: block; }
.pod-plan-outline rect { fill: var(--surface-sunk); stroke: var(--brand-600); stroke-width: 9; }
.pod-plan-outline .pod-corridor { fill: var(--brand-50); stroke: var(--accent-500); stroke-width: 5; }
.pod-plan-outline text {
  fill: var(--brand-700);
  font: 700 var(--fs-xl) var(--font-mono);
  letter-spacing: var(--track-mono);
  text-anchor: middle;
}

/* ── 09 Room detail panel ─────────────────────────────────────────────────── */

/* Sits in the middle of the empty detail column rather than clinging to the top. */
.panel-empty { margin: auto 0; padding: var(--s-4) 0; color: var(--ink-500); text-align: center; }
.empty-icon {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin: auto;
  border-radius: var(--r-pill);
  background: var(--brand-50);
  color: var(--brand-600);
  font-size: var(--fs-xl);
}
.panel-empty h3 { margin: var(--s-3) 0 var(--s-1); color: var(--ink-600); font-size: var(--fs-md); }
.panel-empty p { margin: 0; font-size: var(--fs-micro); line-height: var(--lh-loose); }

.detail-top { display: flex; justify-content: space-between; align-items: start; }
.detail-top p {
  margin: 0;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-400);
}
.detail-top h3 { margin-top: var(--s-1); font-size: var(--fs-xl); }
.detail-top .pill, .panel-detail > .pill { margin: var(--s-2) 0 var(--s-4); }

.resident-card {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.resident-card strong { display: block; font-size: var(--fs-xs); }
.resident-card small { display: block; margin-top: 2px; color: var(--ink-500); font-size: var(--fs-micro); }

.detail-list {
  display: grid;
  gap: var(--s-3);
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line-soft);
}
.detail-list div { display: flex; justify-content: space-between; color: var(--ink-500); font-size: var(--fs-micro); }
.detail-list strong { color: var(--ink-800); font-weight: 600; }

/* Ranked destination choices — shown for your own listing and for anyone
   else who is open to a swap. */
.choice-title { margin: 0 0 var(--s-2); color: var(--ink-500); font: 700 var(--fs-micro) var(--font-sans); text-transform: uppercase; letter-spacing: .06em; }
.choice-list { display: grid; gap: var(--s-2); margin: 0; padding: 0; list-style: none; counter-reset: choice; }
.choice-list li {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.choice-list li:before {
  counter-increment: choice;
  content: counter(choice);
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--brand-600);
  color: #fff;
  font: 700 var(--fs-micro) var(--font-mono);
}
.choice-list span { flex: 1; min-width: 0; color: var(--ink-900); font: 700 var(--fs-xs) var(--font-sans); }
.choice-list small { color: var(--ink-500); font-size: var(--fs-micro); }

/* Waitlist: who has bookmarked this room, first come first served. */
.waitlist-card { padding: var(--s-4); border: 1px solid var(--status-waitlist); border-radius: var(--r-lg); background: var(--status-waitlist-tint); }
.waitlist-list { display: grid; gap: var(--s-2); margin: var(--s-2) 0 0; padding: 0; list-style: none; counter-reset: waitlist; }
.waitlist-list li {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: 1px solid rgba(214, 67, 126, .25);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.waitlist-list li:before {
  counter-increment: waitlist;
  content: counter(waitlist);
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--status-waitlist);
  color: #fff;
  font: 700 var(--fs-micro) var(--font-mono);
}
.waitlist-list span { flex: 1; min-width: 0; color: var(--ink-900); font: 700 var(--fs-xs) var(--font-sans); }
.waitlist-note { margin: 0; color: #9c2d5f; font: 600 var(--fs-micro) var(--font-sans); }
.choice-none { margin: 0; color: var(--ink-400); font-size: var(--fs-micro); }
.panel-edit { margin-top: var(--s-1); min-height: 46px; border-radius: var(--r-md); }
.panel-hint { margin: var(--s-3) 0 0; color: var(--ink-400); font-size: var(--fs-micro); text-align: center; }
.panel-detail .btn { margin-top: var(--s-4); }

/* ── 10 Modals + requests ────────────────────────────────────────────────── */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: var(--s-6);
  background: rgba(39, 16, 21, .55);
  backdrop-filter: blur(6px);
}
.modal-card {
  position: relative;
  width: min(560px, 100%);
  max-height: min(760px, calc(100vh - var(--s-12)));
  overflow: auto;
  padding: var(--s-8);
  border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--e-4);
}
.modal-card--wide { width: min(780px, 100%); }
.modal-close { position: absolute; right: var(--s-4); top: var(--s-4); }
.modal-kicker {
  margin: 0;
  font: var(--fs-micro) var(--font-mono);
  letter-spacing: var(--track-mono);
  color: var(--brand-600);
}
.modal-card h2 { margin: var(--s-2) 0; font-size: var(--fs-2xl); }
.modal-copy { margin: 0 0 var(--s-5); color: var(--ink-500); font-size: var(--fs-xs); line-height: var(--lh-loose); }
.modal-heading { display: flex; justify-content: space-between; align-items: end; gap: var(--s-4); }
.modal-heading > .pill { white-space: nowrap; }
.modal-footer { display: flex; justify-content: flex-end; gap: var(--s-2); margin-top: var(--s-5); }
.modal-open { overflow: hidden; }

.activity-stats { display: grid; gap: var(--s-2); }
.activity-stats > div {
  display: grid;
  grid-template-columns: 42px 1fr;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.activity-stats strong { color: var(--brand-600); font: 800 var(--fs-xl) var(--font-sans); text-align: center; }
.activity-stats span { color: var(--ink-600); font-size: var(--fs-xs); line-height: var(--lh-base); }

.friend-directory {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2);
  max-height: 400px;
  overflow: auto;
  padding: 2px;
}
.friend-card {
  padding: var(--s-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.friend-card.selected { border-color: var(--accent-500); background: var(--accent-50); }
.friend-select {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  color: var(--ink-800);
  cursor: pointer;
}
.friend-select > span:nth-child(2) { display: grid; gap: 2px; min-width: 0; }
.friend-select strong { font-size: var(--fs-xs); }
.friend-select small, .friend-select em {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-500);
  font: var(--fs-micro) var(--font-sans);
}
.friend-select em { font-family: var(--font-mono); font-style: normal; color: var(--brand-600); }
.friend-select i {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-left: auto;
  border-radius: var(--r-pill);
  background: var(--brand-50);
  color: var(--brand-600);
  font-style: normal;
  font-weight: 800;
}
.friend-card.selected .friend-select i { background: var(--brand-600); color: #fff; }
.transfer-link {
  margin: var(--s-2) 0 0 42px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-600);
  font: 700 var(--fs-micro) var(--font-sans);
  text-decoration: underline;
  cursor: pointer;
}

/* Requests inbox */
.request-tabs { margin: var(--s-4) 0; }
.request-list { display: grid; gap: var(--s-2); max-height: 380px; overflow: auto; padding: 2px; }
.request-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface);
}
.request-row > div { min-width: 0; }
.request-row strong { display: block; font-size: var(--fs-xs); }
.request-row .request-meta {
  display: block;
  margin-top: 2px;
  font: var(--fs-micro) var(--font-mono);
  color: var(--ink-400);
}
.request-row p {
  margin: var(--s-2) 0 0;
  color: var(--ink-600);
  font-size: var(--fs-micro);
  line-height: var(--lh-base);
}
.request-actions { display: flex; gap: var(--s-2); margin-top: var(--s-3); }
.request-empty {
  padding: var(--s-10) var(--s-4);
  color: var(--ink-400);
  font-size: var(--fs-xs);
  text-align: center;
}

/* Delivery is not wired yet — this banner must stay until a backend exists. */
.notice {
  display: flex;
  align-items: start;
  gap: var(--s-3);
  margin-top: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border: 1px dashed var(--accent-100);
  border-radius: var(--r-md);
  background: var(--accent-50);
  color: var(--accent-700);
  font-size: var(--fs-micro);
  line-height: var(--lh-base);
}
.notice b { font-size: var(--fs-md); line-height: 1; }

/* ── 11 Component refinements ───────────────────────────────────────────── */

body { background: var(--canvas); }
.brand small { color: var(--ink-500); }
.nav-item { color: var(--ink-600); font-size: var(--fs-sm); }
.nav-item.active { box-shadow: inset 0 0 0 1px var(--brand-100); }

/* The toolbar names the hostel and the detail column reports the clicked
   room, so both on-canvas text overlays would only repeat them. */
.hero-model .three-title, .hero-model .three-readout { display: none; }

.segmented { border: 1px solid var(--line); border-radius: var(--r-pill); padding: var(--s-1); background: var(--surface); }
.seg-btn { min-height: 38px; padding: var(--s-2) var(--s-4); border-radius: var(--r-pill); font-size: var(--fs-xs); }
.seg-btn.active { color: var(--ink-900); box-shadow: var(--e-1); }
.building-choice { padding: var(--s-2) var(--s-3); border-radius: var(--r-lg); background: var(--surface); }
.building-choice strong { color: var(--ink-900); font-size: var(--fs-md); }
.toolbar .btn { min-height: 40px; border-radius: var(--r-pill); }

.modal-backdrop { background: var(--overlay-backdrop); }
.modal-card { width: min(680px, 100%); padding: 36px; border: 1px solid var(--line); border-radius: calc(var(--r-xl) + 2px); }
.modal-card h2 { color: var(--ink-900); font-size: 32px; }
.modal-copy { max-width: 480px; color: var(--ink-600); font-size: var(--fs-md); }
.field-grid { gap: var(--s-4); }
.field-grid label { gap: var(--s-2); color: var(--ink-800); font-size: var(--fs-xs); }
.field-grid input, .field-grid select { min-height: 50px; border-color: var(--line); border-radius: var(--r-md); background: var(--surface-sunk); color: var(--ink-900); font-size: var(--fs-sm); }
.field-grid input::placeholder { color: var(--ink-500); }

/* ── 12 Toast, responsive, a11y ─────────────────────────────────────────── */

.toast {
  position: fixed;
  bottom: var(--s-6);
  left: 50%;
  z-index: 60;
  transform: translate(-50%, 16px);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--ink-900);
  color: #fff;
  font-size: var(--fs-xs);
  opacity: 0;
  pointer-events: none;
  box-shadow: var(--e-3);
  transition: opacity var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

@media (max-width: 1280px) {
  :root { --detail-w: 280px; }
  .page { max-width: 100%; }
  .head-stats { gap: var(--s-2); }
  .head-stat { padding: var(--s-2) var(--s-3); }
  .toolbar { gap: var(--s-3); }
  .key { gap: var(--s-3); }
}

/* The detail column stops being useful narrow — drop it below the stage and
   let the artifact keep the full width of the card. */
@media (max-width: 1060px) {
  .stage-grid {
    grid-template-columns: 60px minmax(0, 1fr);
    grid-template-areas: "rail stage" "detail detail";
    height: auto;
  }
  .panel-stage { height: 60vh; min-height: 400px; }
  .room-detail {
    border-left: 0;
    border-top: 1px solid var(--line);
    max-height: 65vh;
  }
  .page-head { align-items: flex-start; flex-direction: column; gap: var(--s-4); }
  .head-stats { width: 100%; gap: var(--s-8); }
  .head-stat { text-align: left; }
  .head-activity { margin-left: auto; }
}

@media (max-width: 980px) {
  .topbar { min-height: 0; flex-wrap: wrap; }
  .topbar-actions { width: 100%; margin-left: 0; }
  .topbar-actions .btn { flex: 1; }
}

/* ── Mobile revamp (≤690px only — desktop/tablet rules above are untouched) ─
   Two real bugs drove most of this: .head-stats and .key both overflowed the
   viewport (verified: document.documentElement.scrollWidth was 89px wider
   than clientWidth, from these two rows plus an off-screen tooltip). Fixed by
   letting both wrap/grid instead of forcing one nowrap row, and by no longer
   relying on the desktop hover tooltip to explain the status key on a
   touchscreen where hover doesn't reliably exist. */
@media (max-width: 690px) {
  html, body { overflow-x: hidden; }   /* belt-and-suspenders: an invisible
    absolutely-positioned tooltip can still widen scrollWidth even at
    opacity:0, causing an empty rubber-band scroll with nothing visible in it */

  .page { padding: var(--s-4) var(--s-4) var(--s-8); }

  /* Branded header pill */
  .topbar { gap: var(--s-3); padding: var(--s-4); border-radius: var(--r-xl); flex-wrap: wrap; }
  .topbar-id { flex-wrap: wrap; gap: var(--s-3); }
  .topbar-tag { padding-left: 0; border-left: 0; }
  .topbar-actions { width: 100%; flex-direction: column; align-items: stretch; }
  .topbar-actions .btn { width: 100%; }
  .topbar:after { display: none; }

  /* Headline + live counts. Three pills that used to force a nowrap row wider
     than the screen now sit in a 2-column grid, full numbers and labels
     intact — nothing shrunk to fit, nothing truncated. */
  .page-head { flex-direction: column; align-items: stretch; gap: var(--s-4); }
  .page-head-copy h1 { font-size: var(--fs-2xl); }
  .head-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); width: 100%; }
  .head-stat { justify-content: center; text-align: center; padding: var(--s-3); }
  .head-stat--match { grid-column: 1 / -1; }
  .head-activity { display: none; }   /* the same numbers are already above it */

  /* Explorer toolbar: picker, view switch and key each get their own full-
     width row instead of being squeezed onto one and overflowing. */
  .toolbar { height: auto; padding: var(--s-3); flex-wrap: wrap; row-gap: var(--s-3); }
  .building-picker { flex: 1 1 100%; order: 1; }
  .building-choice { width: 100%; padding: var(--s-3); }
  .building-choice strong { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .view-switch { order: 2; flex: 1 1 100%; margin-left: 0; }
  .seg-btn { flex: 1; justify-content: center; padding: var(--s-2); }
  .building-menu { left: 0; width: min(296px, calc(100vw - 34px)); grid-template-columns: 1fr; max-height: 250px; }

  /* Status key: was a single nowrap row ("Match for you" got cut off at the
     edge of the screen). Now wraps 2-up, and since touch has no reliable
     hover, the tooltip is redundant with the visible label anyway. */
  .toolbar .key { margin-left: 0; }
  .key {
    order: 3;
    width: 100%;
    flex-wrap: wrap;
    row-gap: var(--s-3);
    column-gap: var(--s-5);
  }
  .key-item { flex: 1 1 calc(50% - var(--s-5)); }
  .key-item small { display: none; }  /* hover tooltip; unreliable on touch, and the label text already says the same thing */

  /* Stage: narrower floor rail, comfortable but not oversized touch targets. */
  .stage-grid { grid-template-columns: 48px minmax(0, 1fr); }
  .panel-stage { height: 420px; min-height: 0; }
  .floor-rail { padding: var(--s-3) 0; gap: var(--s-1); }
  .floor-rail button { width: 36px; height: 34px; }

  /* 3D canvas overlays: at rail-adjusted stage widths (~320px) the readout's
     224px min-width would overlap the title text in the opposite corner. */
  .three-title { top: var(--s-4); left: var(--s-4); max-width: 60%; }
  .three-title span { font-size: 9px; }
  .three-readout { display: none; }   /* "drag to rotate" — touch orbit is a known gesture, and this collided with .three-title on narrow stages */
  .three-credit { display: none; }

  .choice-tiles, .choice-tiles--three { grid-template-columns: 1fr; }
  /* The listing/feedback/verify forms use a 6-column .form-grid (span-2 =
     3-up, span-3 = 2-up, span-6 = full row) — collapses to one column so
     fields get their full width instead of squeezing into slivers with
     truncated placeholder text ("Your full", "you@iitt…"). */
  /* grid-column: span 2/3/6 on a 1-column grid does NOT clamp to that column
     — CSS Grid creates extra implicit columns to satisfy the span instead,
     which is why an earlier attempt at just setting grid-template-columns:
     1fr here still rendered every field 2-up. Every span-N must be pinned to
     the single explicit column directly. */
  .form-grid { grid-template-columns: 1fr; }
  .form-grid > .span-1,
  .form-grid > .span-2,
  .form-grid > .span-3,
  .form-grid > .span-4,
  .form-grid > .span-6 { grid-column: 1 / -1; }
  /* Each destination-preference row (rank + hostel select + pod select) was
     squeezing a hostel name and a pod name into ~150px/~105px, truncating to
     "Choo…"/"A…". Rank pairs with the hostel select on one line; pod select
     gets its own full-width line below instead of a third sliver. */
  .preference-row {
    grid-template-columns: 28px 1fr;
    grid-template-areas: "rank hostel" "pod pod";
    row-gap: var(--s-2);
  }
  .preference-rank { grid-area: rank; }
  /* enhanceSelect() wraps each native <select> in a .select div, which is the
     actual grid item — targeting the (now hidden) <select> itself would do
     nothing visually. */
  .preference-row > .select:first-of-type { grid-area: hostel; }
  .preference-row > .select:last-of-type { grid-area: pod; }
  .form-actions { flex-direction: column-reverse; align-items: stretch; }
  .form-actions .btn--primary { margin-left: 0; width: 100%; }
  .form-actions .btn--ghost { text-align: center; }
  .privacy-note { text-align: left; }
  .site-footer { text-align: left; }
  .site-card, .map-card { right: var(--s-3); top: 58px; width: 168px; padding: var(--s-3); }
  .floor-canvas { padding: var(--s-3); }
  .friend-city-hud { left: var(--s-3); bottom: var(--s-3); width: 224px; }
  .friend-city .three-readout { display: none; }
  .modal-card { padding: var(--s-6) var(--s-4); max-height: 88vh; overflow-y: auto; }
  .field-grid, .friend-directory { grid-template-columns: 1fr; }
  .modal-heading { flex-direction: column; align-items: start; gap: var(--s-1); }
  .request-row { grid-template-columns: auto minmax(0, 1fr); }
}

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


/* ── 13 Shared board: consent, contact, bookmarks ───────────────────────── */

/* Consent is the most consequential control in the form, so it is a panel and
   not a stray checkbox — a student must understand they are publishing a
   phone number to everyone. */
.consent { grid-column: 1 / -1; margin: 0; padding: 0; border: 0; }
.consent-row {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-sunk);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.consent-row:hover { border-color: var(--brand-200); }
.consent-row:has(input:checked) { border-color: var(--status-match); background: var(--status-match-tint); }
.consent-row input { width: 20px; height: 20px; margin-top: 2px; flex: none; accent-color: var(--status-match); }
.consent-row strong { display: block; color: var(--ink-900); font-size: var(--fs-sm); }
.consent-row small { display: block; margin-top: var(--s-1); color: var(--ink-500); font-size: var(--fs-xs); line-height: var(--lh-base); }

.contact-card { padding: var(--s-4); border: 1px solid var(--status-match); border-radius: var(--r-lg); background: var(--surface); box-shadow: var(--e-1); }
.contact-card strong { display: block; font-size: var(--fs-md); color: var(--ink-900); }
.contact-card > span { display: block; margin-top: 2px; color: var(--ink-600); font: 600 var(--fs-sm) var(--font-mono); }
.contact-actions { display: grid; gap: var(--s-2); margin-top: var(--s-3); }
.contact-actions .btn { text-decoration: none; }
.contact-note { display: block; margin-top: var(--s-2); color: var(--ink-400); font-size: var(--fs-micro); }
.contact-none { margin: 0; padding: var(--s-3) var(--s-4); border: 1px dashed var(--line); border-radius: var(--r-md); color: var(--ink-500); font-size: var(--fs-xs); line-height: var(--lh-base); }

.bookmark-btn {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  margin-top: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .72);
  color: var(--ink-600);
  font: 700 var(--fs-xs) var(--font-sans);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.bookmark-btn:hover { border-color: var(--accent-500); color: var(--accent-700); }
.bookmark-btn span { font-size: var(--fs-lg); line-height: 1; color: var(--accent-500); }
.bookmark-btn b { margin-left: auto; padding: 2px var(--s-2); border-radius: var(--r-pill); background: var(--surface-sunk); color: var(--ink-500); font: 700 var(--fs-micro) var(--font-mono); }
.bookmark-btn.is-on { border-color: var(--accent-500); background: var(--accent-50); color: var(--accent-700); }

.count-badge { margin-left: var(--s-1); padding: 1px var(--s-2); border-radius: var(--r-pill); background: var(--ink-900); color: #fff; font: 700 var(--fs-micro) var(--font-mono); }

.bookmark-list { display: grid; gap: var(--s-2); max-height: 420px; overflow-y: auto; padding: 2px; }
.bookmark-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.bookmark-row:hover { border-color: var(--brand-200); box-shadow: var(--e-1); }
.bookmark-dot { width: 10px; height: 10px; flex: none; border-radius: 3px; background: var(--status-unlisted); }
.bookmark-dot--occupied { background: var(--status-occupied); }
.bookmark-dot--open { background: var(--status-open); }
.bookmark-dot--match { background: var(--status-match); }
.bookmark-copy { flex: 1; min-width: 0; display: grid; gap: 2px; }
.bookmark-copy strong { color: var(--ink-900); font-size: var(--fs-sm); }
.bookmark-copy small { color: var(--ink-500); font-size: var(--fs-micro); }
.bookmark-go { color: var(--brand-600); font: 700 var(--fs-xs) var(--font-sans); }
.bookmarks-empty { margin: 0; color: var(--ink-500); font-size: var(--fs-sm); line-height: var(--lh-loose); }

.modal-card--narrow { width: min(420px, 100%); }
