/* Library After Dark: minimal line. The painted room is the whole screen; everything else is a
   one-pixel line, a tiny caps label or empty space. Lime only on what the player can act on. */

:root {
  --line: color-mix(in srgb, var(--ak-accent) 26%, var(--ak-ink-muted));
  --faint: color-mix(in srgb, var(--ak-ink-muted) 45%, transparent);
  --edge: 10px;
  --status: var(--ac-status-h, 60px);
  --help-clear: 72px;
  --mast-h: 48px;
  --cell-h: 64px;
  --slow: 1.6s;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

body {
  background-color: var(--ak-bg);
  background-image: var(--ak-bg-art), var(--ak-backdrop-layer, none);
  background-size: var(--ak-bg-size), cover;
  background-position: center, center;
  color: var(--ak-ink);
  font-family: var(--ak-font-body);
  -webkit-tap-highlight-color: transparent;
}

button { font: inherit; color: inherit; }

:focus-visible { outline: 2px solid var(--ak-focus); outline-offset: 2px; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- layout ---------- */

/* Upright: a hairline mast, the room as large as it fits, the coach line, then the list. */
.play {
  position: fixed;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto auto auto;
  grid-template-areas: "mast" "frame" "coach" "look" "list";
  row-gap: 8px;
  padding:
    calc(var(--status) + 2px)
    max(var(--edge), env(safe-area-inset-right))
    max(var(--edge), env(safe-area-inset-bottom))
    max(var(--edge), env(safe-area-inset-left));
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}

.mast { grid-area: mast; }
.frame { grid-area: frame; }
.coach { grid-area: coach; }
.look { grid-area: look; }
.list { grid-area: list; }

/* The frame is a size container so the room can fit both its width and its height. */
.frame {
  container-type: size;
  display: grid;
  place-items: center;
  min-height: 0;
}

.scene {
  position: relative;
  width: min(100%, calc((100dvh - var(--status) - var(--mast-h) - 2 * var(--cell-h) - 60px) * 0.75));
  width: min(100cqw, 75cqh);
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--ak-bg);
  touch-action: none; /* pinch and drag are the room's own; the rest of the page keeps manipulation */
  -webkit-touch-callout: none; /* holding the room opens the lens, never the picture menu */
  cursor: crosshair;
  outline-offset: 3px;
}

/* Sideways: the room on one side at full height, the mast, coach and list on the other. */
@media (orientation: landscape) {
  .play {
    grid-template-columns: minmax(0, 430px) auto;
    grid-template-rows: auto auto auto minmax(0, 1fr);
    grid-template-areas: "mast frame" "coach frame" "look frame" "list frame";
    justify-content: center;
    column-gap: 20px;
    row-gap: 10px;
    /* The room takes the whole height: sideways, height is what sizes it. */
    padding-top: max(4px, env(safe-area-inset-top));
    padding-bottom: max(4px, env(safe-area-inset-bottom));
    padding-right: calc(var(--help-clear) + env(safe-area-inset-right));
  }
  .mast { margin-top: var(--status); }
  .list { align-self: start; }
  .frame {
    width: min(
      calc((100dvh - 8px - env(safe-area-inset-top) - env(safe-area-inset-bottom)) * 0.75),
      calc(100dvw - var(--help-clear) - 300px)
    );
    height: 100%;
  }
}

/* ---------- the mast: logo, one hairline, the hint chip ---------- */

.mast {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--mast-h);
}

.logo {
  display: block;
  height: 30px;
  width: auto;
  flex: none;
}

.mast-line {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

.night {
  flex: none;
  color: var(--ak-ink-muted);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}

.hint-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 48px;
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid var(--faint);
  border-radius: 2px;
  background: var(--ak-bg);
  color: var(--ak-ink-muted);
  font-size: 12px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  cursor: pointer;
  touch-action: manipulation;
}

.hint-mark { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1; }
.hint-used,
.hint-wait { font-variant-numeric: tabular-nums; letter-spacing: 0.08em; }

/* The quiet clock: one hairline under the chip that fills while nothing is found. */
.hint-charge {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 7px;
  height: 1px;
  background: var(--ak-ink-muted);
  transform: scaleX(var(--charge, 0));
  transform-origin: left center;
}

.hint-chip.is-ready {
  border-color: var(--ak-accent);
  color: var(--ak-ink);
}
.hint-chip.is-ready .hint-mark { stroke: var(--ak-accent); }
.hint-chip.is-ready .hint-charge { display: none; }

/* ---------- the room ---------- */

.stage {
  position: absolute;
  left: 0;
  top: 0;
  width: 768px;
  height: 1024px;
  transform-origin: 0 0;
  --k: 0.5;
  --o: calc(0.75px / var(--k));
}

.room {
  position: absolute;
  inset: 0;
  transform-origin: 384px 512px;
  filter: brightness(var(--room-light, 1));
  transition: filter var(--slow) ease;
}

.backdrop {
  position: absolute;
  inset: 0;
  width: 768px;
  height: 1024px;
  display: block;
  pointer-events: none;
  transition: opacity 2.4s ease;
}

.pieces { position: absolute; inset: 0; pointer-events: none; }

/* A piece hides by tone; a found one gets its colour back and a lime outline, slowly. */
.piece {
  position: absolute;
  filter:
    drop-shadow(var(--o) 0 0 transparent)
    drop-shadow(calc(var(--o) * -1) 0 0 transparent)
    drop-shadow(0 var(--o) 0 transparent)
    drop-shadow(0 calc(var(--o) * -1) 0 transparent);
  transition: filter var(--slow) ease;
}

.piece-art {
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  filter: grayscale(1) sepia(1) hue-rotate(222deg) saturate(1.7) brightness(var(--piece-light, 0.56)) contrast(0.95);
  transition: filter var(--slow) ease;
}

.piece.is-found {
  filter:
    drop-shadow(var(--o) 0 0 var(--ak-accent))
    drop-shadow(calc(var(--o) * -1) 0 0 var(--ak-accent))
    drop-shadow(0 var(--o) 0 var(--ak-accent))
    drop-shadow(0 calc(var(--o) * -1) 0 var(--ak-accent));
}
.piece.is-found .piece-art { filter: grayscale(1) sepia(1) hue-rotate(222deg) saturate(0.9) brightness(1.25) contrast(1); }

/* The section map: thin lines the room fades to at the end. */
.map {
  position: absolute;
  inset: 0;
  width: 768px;
  height: 1024px;
  opacity: 0;
  pointer-events: none;
  fill: none;
  stroke: var(--ak-ink-muted);
  stroke-width: 1;
  transition: opacity 2.4s ease;
}
.map * { vector-effect: non-scaling-stroke; }

/* A pick marks its part of the room with lime corners, the same mark the picked list picture
   wears, so the two read as one. Thin at any zoom. */
.area {
  position: absolute;
  pointer-events: none;
  --t: calc(1.5px / var(--k));
  --l: calc(22px / var(--k));
  --b: linear-gradient(var(--ak-accent), var(--ak-accent));
  background:
    var(--b) left top / var(--l) var(--t) no-repeat,
    var(--b) left top / var(--t) var(--l) no-repeat,
    var(--b) right top / var(--l) var(--t) no-repeat,
    var(--b) right top / var(--t) var(--l) no-repeat,
    var(--b) left bottom / var(--l) var(--t) no-repeat,
    var(--b) left bottom / var(--t) var(--l) no-repeat,
    var(--b) right bottom / var(--l) var(--t) no-repeat,
    var(--b) right bottom / var(--t) var(--l) no-repeat;
}
.play.is-solved .area { display: none; }

/* Rings live in the room's coordinates but keep a one-pixel line at any zoom. */
.ring {
  position: absolute;
  border: calc(2px / var(--k)) solid var(--ak-accent);
  border-radius: 50%;
  pointer-events: none;
}

.cursor {
  position: absolute;
  width: calc(48px / var(--k));
  height: calc(48px / var(--k));
  margin: calc(-24px / var(--k)) 0 0 calc(-24px / var(--k));
  border: calc(1px / var(--k)) solid var(--ak-accent);
  border-radius: 50%;
  pointer-events: none;
}
.cursor::before,
.cursor::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--ak-accent);
}
.cursor::before { width: calc(10px / var(--k)); height: calc(1px / var(--k)); translate: -50% -50%; }
.cursor::after { width: calc(1px / var(--k)); height: calc(10px / var(--k)); translate: -50% -50%; }

/* A miss: a small ring with a cross, in ink, one line weight. Shape, not colour, says "missed". */
.miss-mark {
  position: absolute;
  width: calc(30px / var(--k));
  height: calc(30px / var(--k));
  margin: calc(-15px / var(--k)) 0 0 calc(-15px / var(--k));
  border: calc(1px / var(--k)) solid var(--ak-ink);
  border-radius: 50%;
  pointer-events: none;
}
.miss-mark::before,
.miss-mark::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 70%;
  height: calc(1px / var(--k));
  background: var(--ak-ink);
  translate: -50% -50%;
  rotate: 45deg;
}
.miss-mark::after { rotate: -45deg; }
.stage.is-turning .miss-mark,
.play.is-solved .miss-mark { display: none; }

.ripple {
  position: absolute;
  width: calc(44px / var(--k));
  height: calc(44px / var(--k));
  margin: calc(-22px / var(--k)) 0 0 calc(-22px / var(--k));
  border: calc(1px / var(--k)) solid var(--ak-ink-muted);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

.stage.is-turning .area,
.stage.is-turning .ring,
.stage.is-turning .cursor { visibility: hidden; }

/* The trick shown turned off: the ceiling strip, turned the right way, under itself. */
.upright {
  position: absolute;
  top: 112px; /* just under the ceiling shelf; left, width and height come from the strip */
  border: calc(1px / var(--k)) solid var(--ak-ink);
  background: var(--ak-bg);
}
.upright-turn {
  position: absolute;
  inset: 0;
  overflow: hidden;
  rotate: 180deg;
  background-image: url("./art/library-scene.jpg");
  background-size: 768px 1024px;
}
.upright-pieces {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.upright-pieces .piece { transition: none; }
.upright-tag {
  position: absolute;
  left: -1px;
  top: 100%;
  margin-top: calc(4px / var(--k));
  padding: calc(2px / var(--k)) calc(6px / var(--k));
  background: var(--ak-bg);
  color: var(--ak-ink);
  font-size: calc(10px / var(--k));
  letter-spacing: 0.24em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ---------- the coach: one caption on a solid backing, an arrow, a pulsing ring ---------- */

.coach {
  display: flex;
  align-items: center;
  gap: 10px;
}
.coach[hidden] { display: none; }

.coach-text {
  flex: 1 1 auto;
  margin: 0;
  padding: 10px 14px;
  border: 1px solid var(--ak-ink);
  border-radius: 2px;
  background: var(--ak-surface);
  color: var(--ak-ink);
  font-size: 18px;
  line-height: 1.35;
}

.coach-arrow {
  flex: none;
  width: 24px;
  height: 40px;
  fill: none;
  stroke: var(--ak-accent);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.coach.is-up .coach-arrow { rotate: 180deg; }

@media (orientation: landscape) {
  .coach.is-up .coach-arrow { rotate: -90deg; }
}

/* While a message sits on the band, the band's own words step aside so nothing peeks around it. */
.look.is-covered > *,
.coach.is-covered > * { visibility: hidden; }

/* ---------- looking for: what you picked, where to try, what the hint can do ---------- */

/* It stays on screen (never a toast), on the washed backdrop between two hairlines. */
.look {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 60px;
  padding: 6px 2px;
  border-top: 1px solid var(--line);
}
.look[hidden] { display: none; }

.look-art {
  position: relative;
  flex: none;
  width: 72px;
  height: 48px;
}
.look-art[hidden] { display: none; }
/* Shown in the room's own tone, like a found piece: recognisable, never neon. */
.look-piece {
  position: absolute;
  background-repeat: no-repeat;
  filter: grayscale(1) sepia(1) hue-rotate(222deg) saturate(0.9) brightness(1.25);
}

.look-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  margin: 0;
}
.look-what {
  color: var(--ak-ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.look-where {
  color: var(--ak-ink);
  font-size: 15px;
  line-height: 1.35;
}

.look-zoom {
  flex: none;
  min-width: 48px;
  min-height: 48px;
  margin-left: auto;
  padding: 0 12px;
  border: 1px solid var(--ak-accent);
  border-radius: 2px;
  background: var(--ak-bg);
  color: var(--ak-ink);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
}
.look-zoom[hidden] { display: none; }

/* The guide takes two rows: picture, name and zoom on top, the clue across the full width
   underneath, so it stays short and the room and the list keep their space. */
@media all {
  .look {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "art what zoom" "where where where";
    align-items: center;
    column-gap: 10px;
    row-gap: 2px;
  }
  .look-text { display: contents; }
  .look-art { grid-area: art; }
  .look-what { grid-area: what; }
  .look-zoom { grid-area: zoom; }
  .look-where { grid-area: where; }
}

/* ---------- the lens: hold the room to look closer ---------- */

.lens {
  position: fixed;
  z-index: 20;
  width: 140px;
  height: 140px;
  overflow: hidden;
  border: 1px solid var(--ak-ink);
  border-radius: 50%;
  box-shadow: 0 0 0 4px var(--ak-bg), 0 0 0 5px var(--ak-accent);
  background: var(--ak-bg);
  pointer-events: none;
}
.lens { --o: 0.75px; }
.lens .room { transform-origin: 0 0; }

/* ---------- the list: two rows of five hairline cells ---------- */

.list {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}

.list li {
  display: flex;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 100%;
  min-height: var(--cell-h);
  padding: 6px 0;
  border: 0;
  background: none;
  color: var(--ak-ink);
  cursor: pointer;
  touch-action: manipulation;
}

.cell svg.shape {
  width: 30px;
  height: 30px;
  fill: none;
  stroke: var(--ak-ink);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cell-name {
  position: relative;
  max-width: 100%;
  overflow: hidden;
  /* Legible at a glance in either orientation: full ink, bold, close tracking. */
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
  text-overflow: clip;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Found: a tick, a hairline strike, and the shape quietens. */
.cell .tick {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: var(--ak-accent);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}
.cell.is-found .tick { opacity: 1; }
.cell.is-found svg.shape { stroke: var(--ak-ink-muted); }
.cell.is-found .cell-name { color: var(--ak-ink); }
.cell-name::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0.14em;
  top: 50%;
  height: 1px;
  background: var(--ak-ink-muted);
  transform: scaleX(0);
  transform-origin: left center;
}
.cell.is-found .cell-name::after { transform: scaleX(1); }

/* Picked: lime corner brackets, the thing you are looking for. */
.cell::before {
  content: '';
  position: absolute;
  inset: 3px;
  --b: linear-gradient(var(--ak-accent), var(--ak-accent));
  background:
    var(--b) left top / 10px 1px no-repeat,
    var(--b) left top / 1px 10px no-repeat,
    var(--b) right top / 10px 1px no-repeat,
    var(--b) right top / 1px 10px no-repeat,
    var(--b) left bottom / 10px 1px no-repeat,
    var(--b) left bottom / 1px 10px no-repeat,
    var(--b) right bottom / 10px 1px no-repeat,
    var(--b) right bottom / 1px 10px no-repeat;
  opacity: 0;
  pointer-events: none;
}
.cell[aria-pressed="true"]::before { opacity: 1; }

/* The coach's ring around the first thing to pick. */
.cell.is-coached::after {
  content: '';
  position: absolute;
  inset: 2px;
  border: 1.5px solid var(--ak-accent);
  border-radius: 50%;
  pointer-events: none;
}

/* ---------- the ending: the room fades to lines, one sentence stays ---------- */

.play.is-lines .backdrop { opacity: 0.05; }
.play.is-lines .map { opacity: 1; }
.play.is-lines .room { filter: none; }
.play.is-lines .piece-art { filter: brightness(0); }
.play.is-lines .scene { cursor: default; }
.play.is-lines .list { opacity: 0.35; }
.play.is-solved .hint-chip { visibility: hidden; }

/* chrome.js's message chip lands exactly on the guidance band (the looking-for line, or the
   first round's caption), in both orientations, so a message never covers the room or the list.
   Only its place and spacing change; its frame stays chrome.js's. */
:root #activity-chrome-toast[data-at] {
  left: var(--band-left, var(--edge));
  right: auto;
  top: var(--band-mid, 70vh);
  bottom: auto;
  width: var(--band-width, calc(100vw - 2 * var(--edge)));
  max-width: none;
  translate: 0 -50%;
  padding: 6px 12px;
  letter-spacing: 0.14em;
  line-height: 1.35;
  text-align: center;
}

/* Sideways the room's size is set by the height, so the side column spends its width on
   larger words: every label, chip and message comfortably readable at arm's length. */
@media (orientation: landscape) {
  .night { font-size: 12px; }
  .hint-chip { font-size: 13px; }
  .look-what { font-size: 13px; }
  .look-where { font-size: 17px; }
  .look-zoom { font-size: 13px; }
  .cell-name { font-size: clamp(11px, 1.6vw, 13px); }
  .cell { gap: 3px; padding: 4px 0; }
  .cell svg.shape { width: 26px; height: 26px; }
  :root #activity-chrome-toast[data-at] { font-size: 14px; }
}

/* ---------- small and short screens ---------- */

@media (max-width: 370px) {
  .cell-name { font-size: 10px; letter-spacing: 0; }
  .cell svg.shape { width: 26px; height: 26px; }
}

@media (orientation: landscape) and (max-height: 430px) {
  :root { --cell-h: 54px; --mast-h: 48px; }
  .coach-text { padding: 8px 12px; }
  .look { padding: 4px 2px; }
  .look-what { font-size: 12px; }
  .look-where { font-size: 16px; line-height: 1.3; }
}

@media (orientation: portrait) and (max-height: 700px) {
  :root { --cell-h: 54px; }
  .cell { gap: 2px; }
  .cell svg.shape { width: 24px; height: 24px; }
}

/* ---------- motion: slow and small, and only when wanted ---------- */

@media (prefers-reduced-motion: no-preference) {
  :root:not(.ac-still) .play.is-developing .backdrop { animation: develop 1.6s ease-out; }
  :root:not(.ac-still) .play.is-developing .pieces { animation: develop-pieces 1.6s ease-out; }
  :root:not(.ac-still) .piece.just-found { animation: settle 0.9s ease-out both; }
  :root:not(.ac-still) .play.is-solved .piece { animation: settle 0.9s ease-out both; animation-delay: calc(var(--i) * 110ms); }
  :root:not(.ac-still) .ring.is-pulsing { animation: pulse 1.8s ease-in-out infinite; }
  :root:not(.ac-still) .cell.is-coached::after { animation: pulse 1.8s ease-in-out infinite; }
  :root:not(.ac-still) .ripple { animation: ripple 0.7s ease-out both; }
  :root:not(.ac-still) .area:not([hidden]) { animation: develop-pieces 0.6s ease-out; }
  :root:not(.ac-still) .cell-name::after { transition: transform 0.6s ease; }
  :root:not(.ac-still) .cell .tick { transition: opacity 0.6s ease; }
  :root:not(.ac-still) .hint-charge { transition: transform 0.3s linear; }
  :root:not(.ac-still) .upright { animation: develop-late 1.2s ease-out both; }
  :root:not(.ac-still) .map * { stroke-dasharray: 1; stroke-dashoffset: 1; }
  :root:not(.ac-still) .play.is-lines .map * { animation: draw 2.4s ease-out both; }
}

:root.ac-still .ripple,
.ripple.is-still { opacity: 1; }

/* The print develops from a dim but readable room, never from black: even a stalled first frame
   shows the room and every piece. */
@keyframes develop {
  0% { filter: brightness(0.55) contrast(1.3) saturate(0.35); }
  100% { filter: none; }
}
@keyframes develop-pieces {
  from { opacity: 0.6; }
  to { opacity: 1; }
}
@keyframes develop-late {
  0%, 40% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes settle {
  0% { scale: 1.12; }
  60% { scale: 0.98; }
  100% { scale: 1; }
}
@keyframes pulse {
  0%, 100% { opacity: 1; scale: 1; }
  50% { opacity: 0.45; scale: 1.04; }
}
@keyframes ripple {
  from { opacity: 0.9; scale: 0.4; }
  to { opacity: 0; scale: 1.3; }
}
@keyframes draw {
  to { stroke-dashoffset: 0; }
}
