/* Meebits field. Every colour, font and size the page uses is set here. */
:root {
  --field-bg: #0B0B0C;        /* page and field ground */
  --bar-bg: #0B0B0C;          /* top and bottom bars */
  --card-bg: #0B0B0C;
  --card-figure-bg: #0B0B0C;  /* behind the full-body image (it is transparent) */
  --scrim: rgba(11, 11, 12, 0.6);
  --ink: #ECECE8;             /* main text */
  --ink-muted: #85857F;       /* labels, counts, hints */
  --line: #2B2B2E;            /* hairlines and button borders */
  --line-strong: #ECECE8;     /* button hover */
  --hover-line: #ECECE8;      /* outline of the Meebit under the pointer */
  --select-line: #ECECE8;     /* outline of the open Meebit */
  --label-bg: #ECECE8;        /* hover number */
  --label-ink: #0B0B0C;
  --error: #E0A39A;

  --font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --text-xs: 11px;
  --text-sm: 12px;
  --text-md: 13px;
  --title-size: 44px;
  --tracking-label: 0.06em;

  --gutter: 16px;
  --bar-height: 44px;
  --card-width: 440px;
  --radius: 0;
  --line-width: 1px;
  --fade: 140ms;

  /* Block numbers in the gutters (read by field.js) */
  --block-label-ink: #85857F;
  --block-label-size: 11;     /* px, shrinks to fit narrow gutters */

  /* Lens under the pointer (read by field.js) */
  --lens-mode: loupe;         /* loupe: a window of the Meebits around the pointer, enlarged evenly.
                                 lift: the one under the pointer rises. fisheye: a magnifying glass */
  --lens-size: 48;            /* px a Meebit grows to under the lens */
  --lens-size-body: 40;       /* the same for full bodies (px wide; twice as tall) */
  --lens-around: 1;           /* loupe: Meebits shown on each side of the middle one (1 = 3 x 3) */
  --lens-loupe: tiles;        /* loupe: tiles (own squares), float (over the field), window (cleared square) */
  --lens-border: none;        /* loupe edge: none, or a colour for a hairline round it */
  --lens-gain-min: 1.25;      /* zoomed right in, still at least this much bigger */
  --lens-gain-max: 8;         /* zoomed right out, at most this much bigger */
  --lens-spread: 1.4;         /* lift: how far the rise reaches, in Meebits */
  --lens-reach: 3.2;          /* fisheye: lens radius, in magnified Meebits */
  --lens-follow: 50;          /* ms the lens trails the pointer by; 0 sticks to it */
  --lens-fade: 110;           /* ms to ease in and out */
  --lens-tile-bg: #0B0B0C;    /* behind each lifted Meebit */

  /* 3D Meebit in the card (read by viewer3d.js) */
  --viewer-ambient: 0.55;     /* soft room light */
  --viewer-key: 2.2;          /* key light, high on the left */
  --viewer-rim: 1.1;          /* rim light from behind */
  --fade-3d: 500ms;           /* image to 3D cross fade */
  --sheet-height: 74vh;       /* the card on phones: a sheet from the bottom */
  --sheet-in: 280ms;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--field-bg);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  overscroll-behavior: none;
}

[hidden] { display: none !important; }

/* Field */
.field { position: fixed; inset: 0; background: var(--field-bg); }
.field-gl {                                      /* the canvas field-core.js adds */
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;                    /* no callout on a long press */
}
.field.is-over .field-gl { cursor: pointer; }
.field .field-gl.is-dragging { cursor: grabbing; }
.field.is-static { background: var(--field-bg) url("tiles/8/0_0.avif") center / contain no-repeat; }
.labels {                                         /* block numbers, type names, the relatives' rings, drawn by field-ui.js */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;                                     /* under the Meebits: lines show only between them */
}
.field-gl { position: relative; z-index: 1; }
.labels--top { z-index: 2; }                       /* over them: the Relatives and Bubbles text, on plates */

.cell-box {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  will-change: transform;
}
.cell-box--hover { outline: var(--line-width) solid var(--hover-line); z-index: 2; }
/* The open Meebit stays lit; its spread is the dimming over the rest of the field. */
.cell-box--selected {
  outline: var(--line-width) solid var(--select-line);
  box-shadow: 0 0 0 300vmax var(--scrim);
  z-index: 11;
}
/* While a trait filter is on, the field does its own dimming: no extra veil over the matches. */
.is-filtering .cell-box--selected { box-shadow: none; }

.cell-label {
  position: absolute;
  left: calc(-1 * var(--line-width));
  bottom: calc(100% + var(--line-width) + 2px);
  padding: 1px 5px;
  background: var(--label-bg);
  color: var(--label-ink);
  font-size: var(--text-xs);
  line-height: 16px;
  white-space: nowrap;
}
.cell-label.is-below { bottom: auto; top: calc(100% + var(--line-width) + 2px); }

/* Bars */
.bar {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 5;
  height: var(--bar-height);
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  background: var(--bar-bg);
}
.bar--top { top: 0; border-bottom: var(--line-width) solid var(--line); }
/* Above the scrim and the open card's dimming, so the filter and search work and read with a card
   open (the card, later in the page, still covers them where they meet). */
.bar { z-index: 12; }
.bar--bottom { bottom: 0; border-top: var(--line-width) solid var(--line); }
.bar p { margin: 0; }

.bar-title {
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.search { display: flex; align-items: center; gap: 8px; position: relative; }
.search-label { color: var(--ink-muted); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.search-input {
  width: 9ch;
  height: 28px;
  padding: 0 8px;
  border: var(--line-width) solid var(--line);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  font: inherit;
}
.search-input:focus { outline: none; border-color: var(--line-strong); }
.search-input::placeholder { color: var(--ink-muted); }
.search-msg { color: var(--error); font-size: var(--text-xs); }
.search-msg:empty { display: none; }

.hint { color: var(--ink-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hint--coarse { display: none; }
@media (pointer: coarse) {
  .hint--fine { display: none; }
  .hint--coarse { display: inline; }
}

.zoom { display: flex; gap: 6px; flex: none; }
.order { display: flex; align-items: center; gap: 2px; flex: none; margin-left: auto; }
.order-label { color: var(--ink-muted); letter-spacing: var(--tracking-label); text-transform: uppercase; margin-right: 6px; }
.btn.btn--text { border-color: transparent; color: var(--ink-muted); }
.btn.btn--text[aria-pressed="true"] { color: var(--ink); border-color: var(--line); }
.btn {
  min-width: 28px;
  height: 28px;
  padding: 0 8px;
  border: var(--line-width) solid var(--line);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
}
.btn:hover, .btn:focus-visible { border-color: var(--line-strong); outline: none; }

/* Card */
.scrim { position: fixed; inset: 0; z-index: 10; } /* catches clicks outside the card; the dimming comes from .cell-box--selected */

.card {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 12;
  width: var(--card-width);
  max-width: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--card-bg);
  border-left: var(--line-width) solid var(--line);
  animation: card-in var(--fade) ease-out;
}
@keyframes card-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes sheet-in { from { transform: translateY(100%); } to { transform: none; } }

.card-grab { display: none; }
/* Above the sheet's grab strip (z-index 2), or taps on Close land on the strip instead. */
.card-close { position: absolute; top: 12px; right: var(--gutter); z-index: 3; background: var(--card-bg); }

.card-figure {
  margin: 0;
  height: min(var(--card-width), 54vh);
  background: var(--card-figure-bg);
  border-bottom: var(--line-width) solid var(--line);
}
.card-figure { position: relative; overflow: hidden; }
.card-img { display: block; width: 100%; height: 100%; object-fit: contain; transition: opacity var(--fade-3d) ease; }
.card-3d {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity var(--fade-3d) ease;
  touch-action: none;
  cursor: grab;
}
.card-3d:active { cursor: grabbing; }
.card-figure.has-3d .card-3d { opacity: 1; }
.card-figure.has-3d .card-img { opacity: 0; }
.card-hint {
  position: absolute;
  left: var(--gutter);
  bottom: 10px;
  margin: 0;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--fade-3d) ease;
}
.card-figure.has-3d .card-hint { opacity: 1; }
.card-img.is-head { image-rendering: pixelated; padding: 22%; }

.card-body { padding: 20px var(--gutter) 28px; }

.card-title {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-size: var(--title-size);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
}

.traits { list-style: none; margin: 0; padding: 0; border-top: var(--line-width) solid var(--line); }
.trait {
  display: grid;
  grid-template-columns: 9.5em 1fr auto;
  gap: 12px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: var(--line-width) solid var(--line);
  font-size: var(--text-md);
}
.trait-item { color: var(--ink-muted); font-size: var(--text-xs); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.trait-count { color: var(--ink-muted); font-size: var(--text-xs); white-space: nowrap; text-align: right; }

.card-links { margin: 20px 0 0; display: flex; flex-wrap: wrap; gap: 8px 20px; }
.card-link { color: var(--ink); text-underline-offset: 3px; }
.card-link:hover { color: var(--ink-muted); }

/* The filter: traits picked on cards light every Meebit that has them all. */
.filter { display: flex; align-items: center; gap: 8px; min-width: 0; }
.filter[hidden] { display: none; }
.filter-text { color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.filter-clear { flex: none; min-width: 32px; }
.filter-gather { flex: none; }
.bar-title[hidden] { display: none; }

/* Traits on the card are buttons: pick one to light every Meebit with it, more to narrow it down. */
.trait--filter { cursor: pointer; margin: 0 -10px; padding-left: 10px; padding-right: 10px; }
.trait--filter:hover { background: var(--trait-hover, #17171A); }
.trait--filter:focus-visible { outline: var(--line-width) solid var(--line-strong); outline-offset: -1px; }
.trait--filter[aria-pressed="true"] { background: var(--trait-on, #1E1E26); }
.trait--filter[aria-pressed="true"] .trait-name { color: var(--trait-on-ink, #FFFFFF); }
.trait--filter[aria-pressed="true"] .trait-count { color: var(--ink); }
.traits-hint { color: var(--ink-muted); font-size: var(--text-xs); margin: 10px 0 0; }

.look { margin-left: 12px; }
:root { --filter-plate: #2A2A31; }   /* the tile behind each Meebit a trait filter lights */
.label-short { display: none; }

/* Light: a white ground, dark ink. ?theme=light (the Look switch keeps it). */
:root[data-theme="light"] {
  --field-bg: #FFFFFF;
  --bar-bg: #FFFFFF;
  --card-bg: #FFFFFF;
  --card-figure-bg: #F3F3F0;
  --scrim: rgba(255, 255, 255, 0.62);
  --ink: #111113;
  --ink-muted: #76766F;
  --line: #E3E3DF;
  --line-strong: #111113;
  --hover-line: #111113;
  --select-line: #111113;
  --label-bg: #111113;
  --label-ink: #FFFFFF;
  --error: #B4473A;
  --block-label-ink: #8A8A84;
  --lens-tile-bg: #F0F0EC;
  --filter-plate: #EBEBE6;
  --trait-hover: #F4F4F1;
  --trait-on: #ECECF3;
  --trait-on-ink: #000000;
}

/* Relatives: one Meebit in the middle, the Meebits sharing most of its traits around it. The field
   is live with the card open, so no scrim and no veil. */
.card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 16px 0 0; }
.card-actions-hint { flex-basis: 100%; color: var(--ink-muted); font-size: var(--text-xs); line-height: 1.35; }
.is-relatives .scrim { display: none; }
.is-relatives .cell-box--selected { box-shadow: none; }

/* The galaxy (galaxy.html): all 20,000 in 3D. */
.galaxy { position: fixed; inset: 0; background: var(--field-bg); }
.galaxy-gl { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; }
.galaxy-gl:active { cursor: grabbing; }
.galaxy-labels { position: absolute; inset: 0; pointer-events: none; z-index: 1; overflow: hidden; }
.galaxy-label { position: absolute; left: 0; top: 0; text-align: center; font-size: var(--text-xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-muted); white-space: nowrap; }
.galaxy-label b { display: block; font-weight: 500; color: var(--ink); }
.galaxy-tip { position: fixed; left: 0; top: 0; z-index: 4; pointer-events: none; }
.galaxy-panel { position: fixed; top: calc(var(--bar-height) + 16px); left: var(--gutter); z-index: 6; width: 340px;
  max-height: calc(100vh - 2 * var(--bar-height) - 32px); overflow: auto; padding: 18px 20px;
  background: var(--card-bg); border: var(--line-width) solid var(--line); }
.galaxy-panel .card-title { margin: 0 0 14px; }
.galaxy-back { display: inline-flex; align-items: center; text-decoration: none; }
@media (max-width: 640px) {
  .galaxy-panel { left: 0; right: 0; width: auto; top: auto; bottom: var(--bar-height); max-height: 45vh; }
}

/* Phones: a one-time note, gone after a few seconds or the first touch. */
.touch-hint {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bar-height) + 16px);
  z-index: 6;
  margin: 0;
  padding: 6px 10px;
  transform: translateX(-50%);
  background: var(--bar-bg);
  border: var(--line-width) solid var(--line);
  color: var(--ink-muted);
  font-size: var(--text-xs);
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 400ms ease;
}
.touch-hint.is-gone { opacity: 0; }

.load-error {
  position: fixed;
  left: var(--gutter);
  right: var(--gutter);
  top: calc(var(--bar-height) + var(--gutter));
  z-index: 6;
  margin: 0;
  color: var(--error);
}

@media (max-width: 640px) {
  :root { --title-size: 36px; --card-width: 100%; }
  /* The card as a sheet from the bottom, the field still showing above it; drag the grip down to close. */
  .card {
    top: auto;
    height: var(--sheet-height);
    border-top: var(--line-width) solid var(--line);
    animation: sheet-in var(--sheet-in) cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .card.is-dragging { animation: none; }
  .card-grab {
    display: block;
    position: sticky;
    top: 0;
    height: 28px;
    margin-bottom: -28px;
    z-index: 2;
    touch-action: none;
    cursor: grab;
  }
  .card-grab span { display: block; width: 36px; height: 4px; margin: 10px auto 0; background: var(--line); }
  .card-close { top: 10px; min-height: 40px; padding: 0 14px; } /* a finger-sized target */
  .bar-title { font-size: var(--text-xs); }
  .hint { white-space: normal; font-size: var(--text-xs); line-height: 1.35; }
  .hint, .order-label { display: none; }
  .look { margin-left: 4px; }
  .filter-gather { display: none; }
  .label-long, [data-zoom="in"], [data-zoom="out"] { display: none; }   /* pinch zooms on a phone */
  .label-short { display: inline; }
  .card { border-left: 0; }
  .card-figure { height: 36vh; }
  .trait { grid-template-columns: 7.5em 1fr auto; }
}

@media (prefers-reduced-motion: reduce) {
  .card { animation: none; }
  .card-img, .card-3d, .card-hint { transition: none; }
  .card { animation: none; }
}
