/* Cityscape viewer — dark survey-instrument chrome laid over a photograph.
   The photograph is the hero; every pixel of UI is either translucent or a
   hairline, and nothing but the selection ever uses saturated color. */

@font-face {
  font-family: 'Instrument Serif';
  src: url('fonts/instrument-serif-normal-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('fonts/instrument-serif-italic-400.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/ibm-plex-mono-normal-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/ibm-plex-mono-normal-500.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}

:root {
  --ink:        #07090b;
  --ink-2:      #0e1216;
  --bone:       #ece7dd;
  --bone-dim:   #8b9298;
  --amber:      #f0a53a;
  --amber-soft: rgba(240, 165, 58, 0.16);
  --rule:       rgba(236, 231, 221, 0.13);
  --rule-hi:    rgba(236, 231, 221, 0.26);
  --glass:      rgba(9, 12, 15, 0.72);
  --glass-hi:   rgba(16, 21, 26, 0.88);

  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --display: 'Instrument Serif', 'Iowan Old Style', Georgia, serif;

  --pad: 16px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--mono);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

/* ---------------------------------------------------------------- stage -- */

#stage {
  position: fixed;
  inset: 0;
  background: var(--ink);
}

/* OSD paints tiles into this; keep its own chrome out of the way. */
#stage .openseadragon-canvas { outline: none !important; }

.vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(140% 100% at 50% 45%, transparent 55%, rgba(4, 6, 8, 0.55) 100%),
    linear-gradient(to bottom, rgba(4, 6, 8, 0.75) 0%, transparent 22%, transparent 62%, rgba(4, 6, 8, 0.8) 100%);
}

/* ------------------------------------------------------------- masthead -- */

.masthead {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 5;
  padding: calc(var(--safe-t) + 12px) var(--pad) 12px;
  pointer-events: none;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  animation: rise 0.9s var(--ease) both;
}

.masthead__rule {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--rule-hi) 12%, var(--rule-hi) 88%, transparent);
  transform-origin: left;
  animation: draw 1.4s var(--ease) 0.25s both;
}

.masthead__body { flex: 1; min-width: 0; }

.masthead__title {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: 27px;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--bone);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
}
.masthead__ital { font-style: italic; color: var(--bone-dim); }

.masthead__meta {
  margin: 7px 0 0;
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--bone-dim);
  display: flex;
  align-items: center;
  gap: 8px;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.9);
}
.masthead__meta > * { white-space: nowrap; }
.coord { font-variant-numeric: tabular-nums; }
.tick { width: 10px; height: 1px; background: var(--rule-hi); flex: none; }

.chip {
  pointer-events: none;
  margin: 2px 0 0;
  flex: none;
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
  border: 1px solid rgba(240, 165, 58, 0.4);
  background: rgba(240, 165, 58, 0.09);
  padding: 4px 7px;
  border-radius: 2px;
  animation: rise 0.9s var(--ease) 0.5s both;
}

/* ------------------------------------------------------------- controls -- */

.controls {
  position: fixed;
  right: var(--pad);
  top: calc(var(--safe-t) + 78px);
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 8px;
  animation: rise 0.9s var(--ease) 0.4s both;
}

.ctl {
  -webkit-appearance: none;
  appearance: none;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
  color: var(--bone-dim);
  background: var(--glass);
  border: 1px solid var(--rule);
  border-radius: 3px;
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.ctl svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.ctl__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.ctl:active { background: var(--glass-hi); }
.ctl[aria-pressed="true"] { color: var(--amber); border-color: rgba(240, 165, 58, 0.45); }

/* ----------------------------------------------------------------- hint -- */

.hint {
  position: fixed;
  left: 50%;
  bottom: calc(var(--sheet-h, 96px) + 16px);
  z-index: 6;
  transform: translateX(-50%);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bone-dim);
  background: var(--glass);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 7px 14px;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  pointer-events: none;
  animation: rise 0.7s var(--ease) both;
}
.hint[data-leaving] { animation: fade-out 0.6s var(--ease) both; }

/* ---------------------------------------------------------------- card -- */

.card {
  position: fixed;
  z-index: 8;
  left: var(--pad);
  right: var(--pad);
  /* --sheet-h is measured in app.js so the card always clears the sheet grip. */
  bottom: calc(var(--sheet-h, 96px) + 12px);
  padding: 18px 18px 16px;
  background: var(--glass-hi);
  border: 1px solid var(--rule);
  border-top-color: var(--rule-hi);
  border-radius: 12px;
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.65);
  animation: card-in 0.42s var(--ease) both;
  touch-action: pan-x;
}
.card[data-leaving] { animation: card-out 0.24s ease-in both; }
/* Swipe-to-dismiss: JS drives --card-dy and suppresses the entry animation. */
.card[data-dragging] {
  animation: none;
  transform: translateY(var(--card-dy, 0px));
  transition: none;
}

.card__close {
  position: absolute;
  top: 8px; right: 8px;
  width: 32px; height: 32px;
  display: grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
  color: var(--bone-dim);
  background: none;
  border: 0;
  border-radius: 3px;
}
.card__close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
.card__close:active { color: var(--bone); }

.card__eyebrow {
  margin: 0 0 6px;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
}

.card__name {
  margin: 0 34px 14px 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: 30px;
  line-height: 1.06;
  letter-spacing: 0.005em;
  color: var(--bone);
}

.readout {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0;
  border-top: 1px solid var(--rule);
}
.readout dt,
.readout dd {
  margin: 0;
  padding: 7px 0;
  font-size: 11px;
  border-bottom: 1px solid var(--rule);
}
.readout dt {
  color: var(--bone-dim);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding-right: 18px;
}
.readout dd {
  color: var(--bone);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.readout dd em {
  font-style: normal;
  color: var(--bone-dim);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-left: 7px;
}
.readout dd[data-unset] { color: var(--bone-dim); }

.card__id {
  margin: 12px 0 0;
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bone-dim);
}
.card__id code {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--bone-dim);
  word-break: break-all;
}

/* --------------------------------------------------------------- sheet -- */

/* Dims the photograph behind an open sheet — the one moment the UI is allowed
   to take the foreground. */
.scrim {
  position: fixed;
  inset: 0;
  z-index: 7;
  background: rgba(4, 6, 8, 0.5);
  opacity: 0;
  transition: opacity 0.34s var(--ease);
}
.scrim[data-shown] { opacity: 1; }

.sheet {
  position: fixed;
  z-index: 9;
  left: 0; right: 0; bottom: 0;
  background: var(--glass-hi);
  border-top: 1px solid var(--rule-hi);
  border-radius: 14px 14px 0 0;
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  box-shadow: 0 -18px 50px rgba(0, 0, 0, 0.5);
  animation: rise 0.9s var(--ease) 0.6s both;
}

.sheet__grip {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  padding: 11px var(--pad) 12px;
  cursor: grab;
  background: none;
  border: 0;
  color: var(--bone-dim);
  text-align: center;
  touch-action: none;
}
.sheet__grip:active { cursor: grabbing; }
.sheet__grip-bar {
  display: block;
  width: 36px; height: 4px;
  margin: 0 auto 10px;
  border-radius: 2px;
  background: var(--rule-hi);
  transition: background 0.2s, width 0.25s var(--ease);
}
.sheet[data-state="expanded"] .sheet__grip-bar { width: 22px; background: var(--bone-dim); }
.sheet__grip-label {
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* Height rather than display, so the sheet can follow a finger and animate.
   --body-h is measured in app.js; --drag-h overrides it mid-gesture. */
.sheet__body {
  padding: 0 var(--pad);
  height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: height 0.34s var(--ease);
}
.sheet[data-dragging] .sheet__body { transition: none; }
.sheet[data-state="expanded"] .sheet__body { height: var(--body-h, 46vh); }
.sheet[data-dragging] .sheet__body { height: var(--drag-h); }

.sheet__search {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  margin-bottom: 10px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.35);
}
.sheet__search svg { width: 15px; height: 15px; flex: none; fill: none; stroke: var(--bone-dim); stroke-width: 1.3; stroke-linecap: round; }
.sheet__search input {
  flex: 1; min-width: 0;
  padding: 11px 0;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--bone);
  background: none;
  border: 0;
  outline: none;
}
.sheet__search input::placeholder { color: var(--bone-dim); opacity: 0.7; }
.sheet__search input::-webkit-search-cancel-button { -webkit-appearance: none; }

.results {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  flex: 1;
}
.results li { border-bottom: 1px solid var(--rule); }
.results button {
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  align-items: baseline;
  gap: 12px;
  width: 100%;
  padding: 12px 2px;
  cursor: pointer;
  text-align: left;
  background: none;
  border: 0;
  color: var(--bone);
  font-family: var(--mono);
  font-size: 13px;
}
.results button:active { color: var(--amber); }
.results button[aria-current="true"] { color: var(--amber); }
.results .r-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.results .r-dist {
  flex: none;
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--bone-dim);
  font-variant-numeric: tabular-nums;
}
.results .r-empty {
  padding: 18px 2px;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-dim);
}

/* ------------------------------------------------------------- attrib -- */

.attrib {
  padding: 0 var(--pad) calc(var(--safe-b) + 12px);
  font-size: 9px;
  line-height: 1.65;
  letter-spacing: 0.04em;
  color: var(--bone-dim);
  opacity: 0.85;
  border-top: 1px solid var(--rule);
  margin-top: 10px;
  padding-top: 10px;
}
.attrib a { color: var(--bone-dim); text-decoration: underline; text-underline-offset: 2px; }
.sheet[data-state="expanded"] .attrib { margin-top: 0; }

/* --------------------------------------------------------- svg overlay -- */

/* The overlay group is scaled by the viewport transform, so every stroke is
   counter-scaled with non-scaling-stroke and widths are in screen pixels. */
#stage svg { pointer-events: none; }

.bldg {
  fill: transparent;
  stroke: transparent;
  stroke-width: 1.25;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  transition: fill 0.25s, stroke 0.25s;
}

/* Transient "show outlines" pass — makes tappability discoverable. The photo
   runs from black rooftops to blown-out sky, so the hairline carries its own
   dark halo to stay legible over both. */
svg.show-outlines .bldg {
  fill: rgba(236, 231, 221, 0.06);
  stroke: rgba(240, 237, 230, 0.85);
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.85));
}

.bldg.is-selected,
svg.show-outlines .bldg.is-selected {
  fill: var(--amber-soft);
  stroke: var(--amber);
  stroke-width: 1.75;
  filter: drop-shadow(0 0 6px rgba(240, 165, 58, 0.55));
}

/* Radar-style acquisition sweep the moment a building is selected. Deliberately
   NOT var(--ease): that curve is ~99% complete by the third of its duration,
   which turns the draw into a pop. This one stays perceptible the whole way. */
.bldg.is-acquiring {
  animation: sweep 0.62s cubic-bezier(0.3, 0.55, 0.35, 1) both;
}

/* ------------------------------------------------------------ desktop -- */

@media (min-width: 860px) {
  :root { --pad: 24px; }

  .masthead__title { font-size: 34px; }

  .controls { top: calc(var(--safe-t) + 96px); }

  /* Sheet becomes a permanent left sidebar. */
  .sheet {
    left: var(--pad);
    right: auto;
    top: calc(var(--safe-t) + 96px);
    bottom: calc(var(--safe-b) + 56px);
    width: 306px;
    border: 1px solid var(--rule);
    border-radius: 4px;
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
    display: flex;
    flex-direction: column;
  }
  .sheet__grip { cursor: default; padding-top: 14px; }
  .sheet__grip-bar { display: none; }
  .sheet__grip-label { color: var(--bone-dim); }
  /* The sidebar is always open; the collapse gesture is phone-only. */
  .sheet__body,
  .sheet[data-state="expanded"] .sheet__body,
  .sheet[data-dragging] .sheet__body {
    height: auto;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }
  .scrim { display: none; }

  /* Card floats bottom-right, clear of the sidebar. */
  .card {
    left: auto;
    right: var(--pad);
    bottom: calc(var(--safe-b) + 56px);
    width: 368px;
    border-radius: 6px;
  }

  .attrib { padding-bottom: 14px; }

  .hint { bottom: calc(var(--safe-b) + 24px); left: 50%; }
}

/* -------------------------------------------------------------- motion -- */

@keyframes rise {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes fade-out {
  to { opacity: 0; transform: translateX(-50%) translateY(6px); }
}
@keyframes card-in {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes card-out {
  to { opacity: 0; transform: translateY(8px); }
}
@keyframes sweep {
  from { stroke-dashoffset: var(--sweep-len, 2000); }
  to   { stroke-dashoffset: 0; }
}

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