:root {
  --bg: #0b0b0e;
  --panel: #131318;
  --edge: #22222a;
  --text: #e8e6e3;
  /* The `why` and every other secondary label. Was #74747f, which measured
     4.01:1 against the tile — under the 4.5:1 floor for normal text, and this
     is set at 12.5px. In the cloud it is then multiplied by the age fade and
     the distance dim, so the effective contrast was worse again. 7.3:1 leaves
     it plainly subordinate to a term at 8-12:1 while actually being readable. */
  --muted: #a0a2b0;
  /* Kind colours. Saturation up about a third from the originals, lightness
     almost unchanged — these already had contrast to spare, so what was missing
     was chroma rather than brightness. */
  --word: #f19ae7;
  --author: #f3c26f;
  --work: #f3c26f;
  --concept: #8abdef;
  --equation: #8be4c5;
  --question: #f88c78;
  --place: #8abdef;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; height: 100%;
  background: var(--bg); color: var(--text);
  font: 15px/1.45 ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
body { display: flex; flex-direction: column; }

/* ---- stage: every view renders into this ---- */

#stage { flex: 1; position: relative; overflow: hidden; }

/* Tiles are shared across views. A view owns *where* a tile is; this owns what
   it looks like. Position is set via transform so views can animate freely. */
.tile {
  position: absolute; top: 0; left: 0;
  width: var(--tile-w);
  height: var(--tile-h);
  border-radius: 9px;
  padding: 10px 13px;
  background: var(--panel);
  border: 1px solid var(--edge);
  cursor: pointer;
  user-select: none;
  overflow: hidden;
  will-change: transform, opacity;
  transition: scale .16s ease, box-shadow .16s ease,
              background .2s ease, border-color .2s ease;
}
.tile.deep { border-left: 2px solid #43435a; }

/* Hover bubbles the tile up to show the rest of its text.
 *
 * The `why` clause is often longer than a tile is tall, and clipping it is the
 * right default — the wall should stay scannable. But when you actually look at
 * something you want the whole thing, so hovering lifts that one tile above its
 * neighbours and lets it grow to fit. `scale` is used rather than `transform`
 * because views own `transform` for positioning; the two are separate CSS
 * properties and do not conflict. */
.tile:hover {
  height: auto;
  min-height: var(--tile-h);
  max-height: 55vh;
  overflow-y: auto;
  z-index: 40;
  scale: 1.025;
  background: #191920;
  border-color: #45455a;
  box-shadow: 0 8px 26px rgba(0,0,0,.55);
  opacity: 1 !important;   /* an aged or distant tile is still fully readable */
}

.term { font-size: 15.5px; font-weight: 500; overflow-wrap: anywhere; }
.why { margin-top: 3px; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }

/* Thumbnail. Only people, works and places ever get one, and it stays small
   and desaturated so the wall still reads as text — the picture is a hint that
   you have the right person, not the content itself.

   Floated, not a flex item. As a flex item the picture claimed a full column
   for its whole height, so every line of the `why` was set in whatever width
   was left — on a 236px tile with a 96px portrait that is a three-word column,
   and the text ran out of the tile long before it ran out of things to say.
   A float only shortens the lines it actually sits beside; the rest reclaim
   the full width underneath it, which is free space the flex version threw
   away. `.tile` already has `overflow: hidden`, so it contains the float and
   nothing needs a clearfix. */
.tile .thumb {
  float: left;
  width: 46px; height: 46px;
  margin: 2px 10px 4px 0;
  object-fit: cover;
  border-radius: 5px;
  filter: saturate(.75) brightness(.9);
  transition: width .16s ease, height .16s ease, filter .16s ease;
}

/* On hover the tile has room, so the image earns more of it. */
.tile.has-image:hover .thumb {
  width: 96px; height: 96px;
  filter: none;
}

/* Outer tiles drop to term-only … */
.tile.far .term { font-size: 13.5px; font-weight: 400; }
.tile.far .why { display: none; }
/* … but hovering one restores it in full. */
.tile.far:hover .term { font-size: 15.5px; font-weight: 500; }
.tile.far:hover .why { display: block; }

/* Grid snaps between cells, so it wants easing on transform. Cloud integrates
   position every frame and must not have one. Both keep the shared hover
   transition (scale, shadow, colours) declared on .tile. */
.view-grid .tile {
  transition: transform .85s cubic-bezier(.22,.61,.36,1),
              opacity .85s ease,
              scale .16s ease, box-shadow .16s ease,
              background .2s ease, border-color .2s ease;
}
.view-cloud .tile {
  transition: opacity .6s ease,
              scale .16s ease, box-shadow .16s ease,
              background .2s ease, border-color .2s ease;
}

@keyframes arrive {
  0%   { box-shadow: 0 0 0 0 rgba(255,255,255,.55), 0 0 22px 5px rgba(255,255,255,.28); }
  100% { box-shadow: 0 0 0 0 rgba(255,255,255,0),   0 0 0 0 rgba(255,255,255,0); }
}
.tile.arriving { animation: arrive 1.15s ease-out; }

/* ---- XR ----
   The canvas fills the stage; this is the only 2D chrome the view needs, since
   entering an immersive session requires a real user gesture. */
.xr-ui {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 30; display: flex; flex-direction: column; align-items: center; gap: 7px;
  pointer-events: none;
}
.xr-enter {
  pointer-events: auto;
  background: #17171d; border: 1px solid #3a3a48; color: var(--text);
  border-radius: 7px; padding: 8px 20px; font: inherit; font-size: 13px;
  cursor: pointer; letter-spacing: .04em;
}
.xr-enter:hover:not(:disabled) { border-color: #5a5a70; background: #1d1d25; }
.xr-enter:disabled { color: #4e4e5a; cursor: default; }
.xr-toggle {
  pointer-events: auto;
  background: none; border: 1px solid var(--edge); color: #4e4e5a;
  border-radius: 5px; padding: 3px 11px; font: inherit; font-size: 11px;
  cursor: pointer; letter-spacing: .05em;
}
.xr-toggle:hover { color: var(--text); border-color: #3a3a48; }
.xr-toggle.on { color: #9ad4a8; border-color: #4a6b52; background: #141b16; }

.xr-hint { color: #3c3c46; font-size: 11px; }

/* ---- kept rail ---- */

#kept-bar {
  flex: 0 0 auto; border-top: 1px solid var(--edge); background: #0e0e12;
  padding: 8px 18px; display: flex; align-items: center; gap: 8px;
  min-height: 44px; overflow-x: auto; scrollbar-width: thin;
}
#kept-toggle {
  flex: 0 0 auto; color: var(--muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: .09em;
  cursor: pointer; border: 0; background: none; padding: 3px 5px;
}
#kept-toggle:hover { color: var(--text); }

/* Pills in the rail. Named apart from the tile mark below on purpose: both
   were once `.kept`, and since a marked tile carries that class too it was
   quietly inheriting everything here that `.tile.kept` did not override —
   pill corners above all, which rounded the text straight off the tile. */
.kept-pill {
  flex: 0 0 auto; background: #1a1a20; border: 1px solid var(--edge);
  border-radius: 999px; padding: 3px 11px; font-size: 13px;
  white-space: nowrap; display: flex; align-items: baseline; gap: 7px;
}
.kept-pill .k-why {
  color: var(--muted); font-size: 11.5px;
  max-width: 230px; overflow: hidden; text-overflow: ellipsis;
}

/* ---- kept panel ---- */

#panel {
  position: fixed; inset: 0; background: rgba(6,6,9,.93);
  display: none; flex-direction: column; padding: 34px 8vw; z-index: 20;
}
#panel.open { display: flex; }
#panel h2 {
  margin: 0 0 4px; font-size: 15px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}
#panel .sub { color: #4e4e5a; font-size: 12px; margin-bottom: 16px; }
#panel-list { flex: 1; overflow-y: auto; }

.row {
  display: flex; gap: 14px; align-items: baseline;
  padding: 9px 4px; border-bottom: 1px solid #16161c;
}
.row .r-term { font-size: 15px; font-weight: 500; min-width: 190px; }
.row .r-why { flex: 1; color: var(--muted); font-size: 13px; }
.row .r-meta { color: #43434e; font-size: 11px; white-space: nowrap; }
.row .r-del {
  background: none; border: 0; color: #43434e; cursor: pointer;
  font-size: 15px; padding: 0 5px;
}
.row .r-del:hover { color: var(--question); }

#panel-actions { display: flex; gap: 9px; padding-top: 14px; }
#panel-actions button {
  background: #17171d; border: 1px solid var(--edge); color: var(--text);
  border-radius: 6px; padding: 6px 13px; font-size: 13px; cursor: pointer;
}
#panel-actions button:hover { border-color: #3a3a48; }

/* ---- ticker / status ---- */

#ticker {
  flex: 0 0 auto; border-top: 1px solid var(--edge); padding: 8px 18px 10px;
  color: #4e4e5a; font-size: 12.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#status {
  position: fixed; top: 10px; right: 14px; z-index: 5;
  font-size: 11px; color: var(--muted);
  display: flex; align-items: center; gap: 9px;
}
/* Running cost. Dim and monospaced so the digits don't jitter the layout as
   they change, and so it never competes with the wall for attention. */
#cost {
  color: #4e4e5a; font-size: 11px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
}

#dot { width: 6px; height: 6px; border-radius: 50%; background: #4a7; }
#dot.off { background: #a44; }
/* The clock has stopped: connected and listening, but nothing is coming in, so
   nothing is ageing either. Hollow rather than a new colour — this is not a
   fault, it is the wall waiting. */
#dot.still { background: transparent; box-shadow: inset 0 0 0 1.5px #4a7; }

/* Attention. Off by default and dim when off, because it is the one control
   that changes what the wall shows you based on what you looked at. */
#attention {
  background: none; border: 1px solid var(--edge); color: #4e4e5a;
  border-radius: 5px; padding: 2px 8px; font: inherit; font-size: 11px;
  cursor: pointer; letter-spacing: .05em;
}
#attention:hover { color: var(--text); border-color: #3a3a48; }
#attention.on {
  color: #9ad4a8; border-color: #4a6b52; background: #141b16;
}

#view-switch {
  background: none; border: 1px solid var(--edge); color: var(--muted);
  border-radius: 5px; padding: 2px 8px; font-size: 11px; cursor: pointer;
  letter-spacing: .05em;
}
#view-switch:hover { color: var(--text); border-color: #3a3a48; }

/* ---- feed bar: the wall as an input, not only an output ---- */

#feed-bar {
  flex: 0 0 auto; border-top: 1px solid var(--edge);
  background: #0c0c10; padding: 7px 18px;
}
#feed {
  width: 100%; background: transparent; border: 0; outline: 0;
  color: var(--text); font: inherit; font-size: 13.5px; padding: 3px 0;
}
#feed::placeholder { color: #3c3c46; }
#feed-bar.flash { background: #16161d; }

/* An echo of what you just fed in, so the input is visibly received even
   before any association comes back from it. */
#feed-echo {
  color: var(--concept); font-size: 12px; padding: 0 18px 6px;
  flex: 0 0 auto; min-height: 0; opacity: 0;
  transition: opacity .3s ease;
}
#feed-echo.on { opacity: .7; }

/* ---- kept mark ----
   Keeping used to remove the tile. It now stays and is marked, so the wall
   keeps its shape and you can still see what you chose.

   Colour only — same box, same corners, same room for text as any other tile.
   Anything that changes a marked tile's geometry costs content on the one tile
   you have said you care about, which is the wrong tile to spend it on. */
.tile.kept { border-color: #4a6b52; }
.tile.kept .term { color: #9ad4a8 !important; }
.tile.kept:hover { border-color: #6a9478; }

/* ---- more / expansion ---- */

.more {
  display: none;
  margin-top: 8px; padding: 2px 9px;
  background: #1b1b22; border: 1px solid var(--edge); border-radius: 5px;
  color: var(--muted); font: inherit; font-size: 11px; cursor: pointer;
  letter-spacing: .04em;
}
/* Only offered once the tile is open — on a 84px tile there is nowhere to put
   it, and a button visible on every tile would turn the wall into a UI. */
.tile:hover .more { display: inline-block; }
.more:hover { color: var(--text); border-color: #45455a; }

.expansion {
  /* Clears the portrait so the rule above it spans the whole tile. A border
     drawn beside a float starts at the float's edge and reads as a broken
     line rather than a separator. */
  clear: left;
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid #26262f;
  font-size: 12.5px; line-height: 1.5; color: #b9b7c4;
}
.expansion .links {
  margin-top: 7px; display: flex; flex-wrap: wrap; gap: 6px;
}
.expansion .links a {
  color: var(--concept); text-decoration: none;
  border: 1px solid var(--edge); border-radius: 999px;
  padding: 1px 9px; font-size: 11.5px;
}
.expansion .links a:hover { border-color: var(--concept); }

/* An expanded tile needs to stay open to be read, so it keeps hover height
   even when the pointer briefly leaves. */
.tile.expanded { height: auto; min-height: var(--tile-h); max-height: 55vh; overflow-y: auto; }

/* Dropped images get their own colour so an input is distinguishable at a
   glance from something the model produced. */
:root { --image: #cdb6f2; }

.dropping::after {
  content: 'drop to feed in';
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,10,14,.72);
  border: 2px dashed #4a4a5e;
  color: var(--muted); font-size: 13px;
  letter-spacing: .08em; text-transform: uppercase;
  pointer-events: none;
}

/* An image the user dropped is the subject, not a hint — so unlike a Wikipedia
   thumbnail it gets real space. */
.tile.dropped .thumb { width: 64px; height: 64px; filter: none; }

/* Opened, it stops floating and takes the top of the tile outright. At 150px
   in a 208px column there is no text width left to wrap into — the label alone
   would be broken across a 48px strip — and this picture is the thing being
   described, so it earns the reading order rather than a corner of it. */
.tile.dropped:hover .thumb {
  float: none; display: block;
  width: 150px; height: 150px;
  margin: 0 0 8px;
}

/* ---- sign-in and settings ----
   Deliberately plain and large. These get typed on a Quest's floating keyboard
   with two controllers, which is slow enough without small targets. */
body.gate {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 24px;
}
.card {
  width: 100%; max-width: 380px;
  background: var(--panel); border: 1px solid var(--edge);
  border-radius: 11px; padding: 26px 24px;
  display: flex; flex-direction: column; gap: 14px;
}
.card h1 { margin: 0; font-size: 19px; font-weight: 500; letter-spacing: .01em; }
.card .sub { margin: -8px 0 0; color: var(--muted); font-size: 13px; }
.card .note { margin: 0; color: var(--muted); font-size: 12.5px; line-height: 1.5; }
.card .error { margin: 0; color: var(--question); font-size: 12.5px; }
.card .error:empty, .card .note:empty { display: none; }
.card label {
  display: flex; flex-direction: column; gap: 5px;
  font-size: 12px; color: var(--muted); letter-spacing: .05em;
}
.card .hint { color: #4e4e5a; letter-spacing: 0; }
.card input {
  background: #0c0c10; border: 1px solid var(--edge); border-radius: 6px;
  color: var(--text); font: inherit; font-size: 15px; padding: 10px 11px;
}
.card input:focus { outline: none; border-color: #45455a; }
.card button {
  background: #17171d; border: 1px solid #3a3a48; color: var(--text);
  border-radius: 7px; padding: 11px 16px; font: inherit; font-size: 14px;
  cursor: pointer; margin-top: 4px;
}
.card button:hover { border-color: #5a5a70; background: #1d1d25; }
.card .row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.card .row a { color: var(--muted); font-size: 12.5px; text-decoration: none; }
.card .row a:hover { color: var(--text); }
.card button.plain {
  background: none; border: 0; color: var(--muted); font-size: 12.5px;
  padding: 0; margin: 0;
}
.card button.plain:hover { color: var(--question); background: none; }

.card .big {
  display: block; text-align: center; color: var(--text);
  background: #17171d; border: 1px solid #3a3a48; border-radius: 7px;
  padding: 12px; text-decoration: none; font-size: 14px;
}
.card .big:hover { border-color: #5a5a70; background: #1d1d25; }
.card ul.rooms { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 7px; }
.card ul.rooms li {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  font-size: 13.5px;
}
.card ul.rooms a { color: var(--concept); text-decoration: none; }
.card ul.rooms a:hover { text-decoration: underline; }
.card form { display: flex; flex-direction: column; gap: 10px; margin: 0; }

/* The room's name, next to the view switch. */
#room {
  color: var(--muted); font-size: 11px; text-decoration: none;
  letter-spacing: .05em; max-width: 180px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
#room:hover { color: var(--text); }
