/* The War room's harbor view (ticket 935): a night harbor drawn as a lit pixel diorama (js/harbor/).
   `.harbor` is the picture and the one image for a screen reader; it gives its children a
   perspective, and `.harbor__world` keeps the layers in 3D so each sits on its own plane. Every scale()
   below cancels the size change the perspective makes at that depth (1400 / (1400 + z)), and each layer
   scales about the perspective origin, so the scene composes as drawn and would only move against
   itself if the world were turned. The glass labels are text in `.harbor__hud`, a sibling of the
   picture, at native resolution. The script writes the stage's max-width and the labels' places
   through the CSSOM (the page's content security policy has no inline styles).

   Linked before css/depth.css, which keeps the last word and supplies the glass plate (.glass), the
   grain and the plate fallbacks. Look rules: no image file, no web font, no library. */

.harbor-view {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
}

.harbor__field {
  position: relative;
  width: 100%;
  max-width: 100%;
}

.harbor {
  position: relative;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  isolation: isolate;
  perspective: 1400px;
  perspective-origin: 50% 30%;
  border-radius: var(--radius);
  box-shadow: 0 0 0 1px var(--border-strong);
  background: #070b1a;
}

.harbor__world {
  position: absolute;
  inset: 0;
  z-index: 1;
  transform-style: preserve-3d;
  transform-origin: 50% 30%;
}

.harbor__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-origin: 50% 30%;
  pointer-events: none;
}

/* The pixel layers keep hard edges; the water is drawn at half resolution and scaled up smoothly. */
.harbor__layer--sky,
.harbor__layer--quay,
.harbor__layer--actors,
.harbor__layer--front,
.harbor__layer--light {
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.harbor__layer--sky {
  transform: translateZ(-320px) scale(1.23);
  filter: blur(1.5px);
}

.harbor__layer--water {
  transform: translateZ(-120px) scale(1.09);
}

.harbor__layer--quay {
  transform: translateZ(0);
}

/* The visitors walk on the quay's own plane, over the buildings and under the foreground. */
.harbor__layer--actors {
  transform: translateZ(0);
}

.harbor__layer--front {
  transform: translateZ(140px) scale(0.9);
  filter: blur(2px);
}

.harbor__layer--light {
  transform: translateZ(0);
  mix-blend-mode: screen;
}

/* Tilt-shift: at the top and at the bottom, three stacked backdrop blurs of 2, 4 and 8 pixels, each
   masked to a narrower strip toward the edge, so the blur grows smoothly toward the frame. */
.harbor__shift {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 2;
  pointer-events: none;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

.harbor__shift--top {
  top: 0;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 100%);
}

.harbor__shift--bottom {
  bottom: 0;
  -webkit-mask-image: linear-gradient(to top, #000 0%, transparent 100%);
  mask-image: linear-gradient(to top, #000 0%, transparent 100%);
}

.harbor__shift--a {
  height: 30%;
}

.harbor__shift--b {
  height: 21%;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

.harbor__shift--c {
  height: 12%;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

/* No backdrop-filter: dark bands at the top and bottom instead. One band per edge is enough. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .harbor__shift {
    -webkit-mask-image: none;
    mask-image: none;
  }

  .harbor__shift--b,
  .harbor__shift--c {
    display: none;
  }

  .harbor__shift--top {
    background: linear-gradient(to bottom, rgba(3, 6, 20, 0.55), rgba(3, 6, 20, 0));
  }

  .harbor__shift--bottom {
    background: linear-gradient(to top, rgba(3, 6, 20, 0.55), rgba(3, 6, 20, 0));
  }
}

.harbor__vignette,
.harbor__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.harbor__vignette {
  z-index: 3;
  background: radial-gradient(ellipse at 50% 45%, transparent 52%, rgba(0, 0, 0, 0.58));
}

/* The film grain of the depth layer (ticket 930), drawn over the picture only. */
.harbor__grain {
  z-index: 4;
  background-image: var(--depth-grain);
  opacity: 0.8;
}

/* The glass labels: text over the picture, one per building, put at the building's roof by the script
   (left and top are percentages of the stage). The plate itself is the console's .glass. */
.harbor__hud {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}

.harbor__chip {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  box-sizing: border-box;
  max-width: 24%;
  padding: 0.2rem 0.55rem;
  border-radius: 0.5rem;
  line-height: 1.2;
  white-space: nowrap;
  transform: translate(-50%, -100%);
}

.harbor__chip-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.harbor__chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink);
  font-size: var(--fs-xs);
  font-weight: 600;
}

.harbor__chip-count {
  color: var(--ink-dim);
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
}

.harbor__dot {
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--st-unknown);
  box-shadow: 0 0 8px var(--st-unknown);
}

.harbor__dot[data-state="running"] {
  background: var(--health-ok);
  box-shadow: 0 0 8px var(--health-ok);
}

.harbor__dot[data-state="stopped"] {
  background: var(--health-down);
  box-shadow: 0 0 8px var(--health-down);
}

/* Ticket 936: over the picture, a sibling of the image. The overlay keeps the picture's own 16:9 box
   (the labels may sit below it on a phone), so the percentages the script writes for a button, the
   name tag and a toast are the picture's. It lets pointer events through except on the buttons. */
.harbor__overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 16 / 9;
  z-index: 6;
  pointer-events: none;
}

.harbor__hits {
  position: absolute;
  inset: 0;
}

.harbor__hit {
  position: absolute;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 3px;
  background: transparent;
  cursor: pointer;
  pointer-events: auto;
}

.harbor__hit:hover,
.harbor__hit:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}

.harbor__tag {
  position: absolute;
  display: flex;
  flex-direction: column;
  max-width: 40%;
  padding: 0.25rem 0.55rem;
  border-radius: 0.5rem;
  line-height: 1.25;
  white-space: nowrap;
  transform: translate(-50%, -100%);
}

.harbor__tag[hidden] {
  display: none;
}

.harbor__tag-address {
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink);
  font-size: var(--fs-xs);
  font-weight: 600;
}

.harbor__tag-request,
.harbor__tag-reply {
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink-dim);
  font-size: var(--fs-2xs);
}

.harbor__toasts {
  position: absolute;
  top: 4%;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  max-width: 80%;
  transform: translateX(-50%);
}

.harbor__toast {
  padding: 0.3rem 0.8rem;
  border-radius: 0.5rem;
  color: var(--ink);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-align: center;
}

/* A wall screen: the harbor fills the screen (its height, less the page head and toolbar, sets the width) and the
   labels grow one step. */
body.is-kiosk .harbor__field {
  width: min(100%, calc((100vh - 15rem) * 16 / 9));
  max-width: none !important; /* beats the cap the script wrote for the windowed layout */
}

body.is-kiosk .harbor__chip {
  gap: 0.55rem;
  padding: 0.3rem 0.75rem;
}

body.is-kiosk .harbor__chip-name {
  font-size: var(--fs-md);
}

body.is-kiosk .harbor__toast {
  padding: 0.45rem 1.1rem;
  font-size: var(--fs-md);
}

body.is-kiosk .harbor__chip-count {
  font-size: var(--fs-sm);
}

/* A phone: eight labels cannot share 358 pixels over the picture, so they leave it and sit in a grid
   under it, in the same order (the places the script wrote are ignored by a static box). */
@media (max-width: 640px) {
  .harbor__hud {
    position: static;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.4rem;
    margin-top: 0.5rem;
  }

  .harbor__chip {
    position: static;
    max-width: none;
    transform: none;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .harbor__shift {
    display: none;
  }
}

/* Forced colors: the picture keeps its own colours (a canvas is an image), the labels use the
   system palette. */
@media (forced-colors: active) {
  .harbor__shift,
  .harbor__vignette,
  .harbor__grain {
    display: none;
  }

  .harbor__chip {
    border: 1px solid CanvasText;
    background: Canvas;
  }

  .harbor__chip-name,
  .harbor__chip-count {
    color: CanvasText;
  }
}

@media print {
  .harbor__shift,
  .harbor__vignette,
  .harbor__grain {
    display: none;
  }
}
