:root {
  /* Paper, not screen. The whole thing is a case file, so it is warm off-white with a deep
     crimson for anything that is an action or a verdict. */
  --paper: #faf6f0; --card: #fffdfa; --ink: #15120f; --ink2: #4a443d; --muted: #726a61;
  --soft: #f2ece3; --line: #e6ddd1;
  --red: #b4202f; --red-deep: #8d1824; --red-soft: #fbe9e9;
  --green: #0f7a4a; --green-soft: #e4f3ea; --amber: #8f5c08; --amber-soft: #fdf0d5;
  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --sans: "Inter", system-ui, -apple-system, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
  --shadow-sm: 0 1px 2px rgba(31, 22, 12, .06), 0 2px 8px rgba(31, 22, 12, .04);
  --shadow: 0 2px 4px rgba(31, 22, 12, .05), 0 10px 28px rgba(31, 22, 12, .09);
  --shadow-lg: 0 8px 18px rgba(31, 22, 12, .09), 0 28px 60px rgba(31, 22, 12, .16);
  --safe-t: env(safe-area-inset-top, 0px); --safe-b: env(safe-area-inset-bottom, 0px);
  color-scheme: light;
}
* { box-sizing: border-box; }
/* Any `display` rule beats the hidden attribute, so a hidden full-screen overlay stays in the
   layer above the page and silently eats every click. This has to come first and win. */
[hidden] { display: none !important; }
body {
  margin: 0; font-family: var(--sans); color: var(--ink);
  background: var(--paper); -webkit-font-smoothing: antialiased; line-height: 1.5;
}
/* The display face carries the title-sequence feel; everything functional stays in the sans,
   because a serif in a button looks like a wedding invitation. */
h1, h2, h3 {
  font-family: var(--display); line-height: 1.05; letter-spacing: -0.015em; margin: 0 0 12px;
  font-variation-settings: "opsz" 120; font-weight: 700;
}
h1 { font-size: clamp(32px, 6.8vw, 56px); font-weight: 800; letter-spacing: -0.012em; }
h2 { font-size: clamp(26px, 5vw, 38px); }
h3 { font-size: 19px; }
p { margin: 0 0 14px; }
a { color: inherit; }

/* ---------- chrome ---------- */
.top {
  display: flex; align-items: center; gap: 14px; padding: calc(12px + var(--safe-t)) 20px 12px;
  border-bottom: 1px solid var(--line);
}
.top .brand { display: inline-flex; align-items: center; min-height: 44px; }
.top .brand img { height: 26px; display: block; }
.top .netras { height: 26px; margin-left: auto; }
.tag {
  font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink2); padding-left: 14px; border-left: 2px solid var(--line);
  display: inline-flex; align-items: center; min-height: 44px;
}
.foot {
  display: flex; align-items: center; gap: 14px; padding: 24px 20px calc(28px + var(--safe-b));
  border-top: 1px solid var(--line); color: var(--muted); font-size: 14px; margin-top: 40px;
}
.foot img { height: 30px; flex: none; }
.foot p { margin: 0; }

.screen { display: none; }
.screen.active { display: block; }
body.playing .top, body.playing .foot { display: none; }

.wrap { max-width: 960px; margin: 0 auto; padding: 36px 20px; }
.wrap.narrow { max-width: 620px; }
.hero { max-width: 760px; margin: 0 auto; padding: 44px 20px 10px; }
.badge {
  display: inline-block; font-size: 13px; font-weight: 800; color: var(--red-deep);
  background: #fdeced; border-radius: 99px; padding: 6px 14px; margin-bottom: 18px;
}
.eyebrow { font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); margin: 0 0 8px; }
.lede { font-size: clamp(17px, 2.4vw, 20px); color: var(--ink2); }
.lede em { font-style: normal; color: var(--ink); font-weight: 700; }
.sub, .muted { color: var(--muted); font-size: 15px; }
.fineprint { color: var(--muted); font-size: 13px; margin-top: 26px; }

/* Whatever has focus has to be visible. :focus-visible keeps it off mouse clicks, so this
   costs pointer users nothing and is the only way a keyboard player knows where they are. */
:where(a, button, input, [tabindex]):focus-visible {
  outline: 3px solid var(--red); outline-offset: 2px; border-radius: 6px;
}

/* An inline link in a paragraph is 16px tall and impossible to hit on a phone. Padding it
   out vertically costs nothing in a block of text and makes it a real target. */
.fineprint a, .consent a, .foot a, .sub a {
  display: inline-block; padding: 14px 2px; margin: -14px 0; text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 24px; border: 0; border-radius: 14px; font: inherit; font-weight: 650;
  font-size: 16.5px; cursor: pointer; background: var(--soft); color: var(--ink);
  letter-spacing: -0.005em; transition: transform .12s ease, box-shadow .18s ease, background .18s ease;
}
.btn:active { transform: translateY(1px); }
.btn.primary {
  background: linear-gradient(180deg, var(--red) 0%, var(--red-deep) 100%); color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,.18) inset, 0 8px 22px rgba(180,32,47,.28);
}
.btn.primary:hover { box-shadow: 0 1px 0 rgba(255,255,255,.18) inset, 0 12px 30px rgba(180,32,47,.36); }
.btn.dark { background: var(--ink); color: #fff; box-shadow: 0 8px 22px rgba(21,18,15,.22); }
.btn.outline { background: var(--card); box-shadow: inset 0 0 0 1.5px var(--line); }
.btn.ghost { background: transparent; color: var(--muted); font-weight: 600; font-size: 15px; }
.btn.wide { width: 100%; margin-top: 10px; }
.btn:focus-visible, .icon-btn:focus-visible, .post:focus-visible, .hot:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
.icon-btn { flex: none; width: 44px; height: 44px; border-radius: 50%; border: 0; background: #fff; box-shadow: inset 0 0 0 1px var(--line); cursor: pointer; font-size: 15px; }
input {
  width: 100%; padding: 15px 16px; border-radius: 13px; font: inherit; font-size: 16px;
  border: 1.5px solid var(--line); outline: none; background: var(--card); color: var(--ink);
  transition: border-color .15s ease, box-shadow .15s ease;
}
input::placeholder { color: var(--muted); }
input:focus { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(21,18,15,.08); }
input[aria-invalid="true"] { border-color: var(--red); box-shadow: 0 0 0 3px rgba(180,32,47,.15); }
.field-error { color: var(--red); font-size: 13px; font-weight: 600; margin: 10px 0 0; }
.consent { color: var(--muted); font-size: 13px; margin-top: 12px; }
.start-row { display: flex; gap: 10px; margin-top: 20px; }
.start-row input { flex: 1; min-width: 0; }
.start-row .btn { flex: none; }

/* ---------- case list ---------- */
.case-list { display: grid; gap: 12px; margin: 26px 0 0; }
.case-card {
  display: flex; align-items: center; gap: 14px; padding: 16px; border-radius: 14px;
  background: #fff; box-shadow: inset 0 0 0 1.5px var(--line); cursor: pointer; text-align: left;
  font: inherit; color: inherit; width: 100%; border: 0;
}
.case-card:hover { box-shadow: inset 0 0 0 1.5px #c9ced6; }
.case-card .num {
  flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center;
  background: var(--ink); color: #fff; font-weight: 800; font-family: var(--mono); font-size: 15px;
}
.case-card .t { flex: 1; min-width: 0; }
.case-card b { display: block; font-size: 17px; }
.case-card span { color: var(--muted); font-size: 14px; }
.case-card .done { flex: none; color: var(--green); font-weight: 800; font-size: 14px; }

.mission {
  display: flex; flex-direction: column; gap: 4px; padding: 14px 16px; border-radius: 12px;
  background: var(--amber-soft); color: #5b3a07; margin: 20px 0 0;
}
.mission b { font-size: 12px; text-transform: uppercase; letter-spacing: .1em; }

/* ---------- the feed ---------- */
/* The bar and the dock are siblings of this, not inside it, so they can stick to the viewport
   while the feed scrolls between them. */
#investigate.active { display: flex; flex-direction: column; min-height: 100dvh; }
.game-col { width: 100%; max-width: 560px; margin: 0 auto; flex: 1; padding: 14px 14px 4px; }
.game-bar, .game-strip, .game-dock > * { max-width: 560px; }
.game-bar, .game-strip { margin: 0 auto; width: 100%; }
.game-dock { justify-content: center; }
/* The game is a screen, not a page: a fixed bar on top, a fixed dock at the bottom, and the
   feed scrolling between them. Six controls in one row wrapped badly on every phone. */
.game-bar {
  position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 12px;
  padding: calc(10px + var(--safe-t)) 16px 10px;
  background: rgba(250,246,240,.92); backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--line);
}
.game-id { min-width: 0; flex: 1; display: grid; gap: 1px; }
.game-id .k { font-size: 10.5px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.game-id strong {
  font-family: var(--display); font-weight: 700; font-size: 18px; letter-spacing: -0.015em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.game-strip {
  position: sticky; top: calc(58px + var(--safe-t)); z-index: 29;
  display: flex; align-items: center; gap: 12px; padding: 9px 16px; min-width: 0;
  background: rgba(250,246,240,.92); backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--line);
}
.game-dock {
  position: sticky; bottom: 0; z-index: 30; display: flex; gap: 10px;
  padding: 14px 16px calc(14px + var(--safe-b));
  background: var(--paper); border-top: 1px solid var(--line);
}
/* A fade above the dock so the feed looks like it runs under it rather than stopping dead. */
.game-dock::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 28px;
  background: linear-gradient(180deg, rgba(250,246,240,0), var(--paper)); pointer-events: none;
}
.game-dock { flex-wrap: wrap; }
.game-dock .btn { flex: 1 1 auto; min-width: 0; padding-left: 14px; padding-right: 14px; }
.game-dock #doneBtn { flex: 2 1 160px; }
@media (max-width: 380px) { .game-dock .btn { font-size: 15px; padding-left: 11px; padding-right: 11px; } }
.game-top { display: flex; align-items: center; gap: 10px; padding-bottom: 10px; }
.progress { font-weight: 600; color: var(--muted); font-size: 15px; }
.progress b { color: var(--ink); font-size: 19px; }
.game-top .btn { padding: 9px 14px; font-size: 15px; }
.hint {
  margin: 0 0 10px; padding: 11px 14px; border-radius: 10px; background: var(--amber-soft);
  color: #5b3a07; font-size: 14px;
}
.feed { display: grid; gap: 12px; }
/* The feed arrives rather than simply being there. Four hundred milliseconds of stagger is the
   difference between "a page loaded" and "a case opened". */
.feed .post { animation: postIn .42s cubic-bezier(.2,.9,.3,1) both; }
@keyframes postIn { from { opacity: 0; transform: translateY(14px); } }
@media (prefers-reduced-motion: reduce) { .feed .post { animation: none; } }
.post {
  position: relative; background: var(--card); border-radius: 18px; padding: 16px;
  box-shadow: var(--shadow-sm); text-align: left; width: 100%; border: 0; font: inherit;
  color: inherit; display: block; cursor: default; transition: box-shadow .18s ease, transform .18s ease;
}
.post.tappable:hover { box-shadow: var(--shadow); transform: translateY(-1px); }
/* Only the cards that actually do something say so. The profile card is a clue in several
   cases, and it used to be the one card styled as if it were not touchable. */
.post.tappable { cursor: pointer; }
.post .meta { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 13px; margin-bottom: 8px; }
.post .meta .who { font-weight: 700; color: var(--ink); }
.post .body { font-size: 16px; }
.post .cap { font-size: 15px; margin-top: 10px; }
.post.found { box-shadow: var(--shadow-sm), inset 0 0 0 2px var(--green); }
.post.dud { opacity: .72; }
.flag {
  position: absolute; top: 10px; right: 10px; font-size: 11px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; padding: 4px 8px; border-radius: 99px;
}
.flag.ok { background: var(--green-soft); color: var(--green); }
.flag.no { background: var(--soft); color: var(--muted); }
.flag.wait {
  background: var(--amber); color: #fff;
  animation: waitpulse 1.5s ease-in-out infinite;
}
@keyframes waitpulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(143,92,8,.5); }
  50% { transform: scale(1.06); box-shadow: 0 0 0 7px rgba(143,92,8,0); }
}
@media (prefers-reduced-motion: reduce) { .flag.wait { animation: none; } }
.flag.bad { background: #fdeced; color: var(--red-deep); }
/* Found but never answered. Loud on purpose: an unanswered clue is the most expensive thing
   on the screen, and it used to look exactly like a finished one. */
/* Opened, not answered. A DASHED outline, because the solid ring plus a corner badge was the
   same shape as a completed card and three rounds of testers read it as finished. Dashed reads
   as a gap in a way no wording fixes. */
.post.unread {
  box-shadow: var(--shadow-sm);
  outline: 2px dashed var(--amber);
  outline-offset: -2px;
}
.post.misread { box-shadow: var(--shadow-sm), inset 0 0 0 2px var(--red); }
/* "This is touchable", people read the feed as an article and never tapped anything. */
/* "This is touchable." Quiet enough to live beside the post chrome, loud enough that people
   stopped reading the feed as an article. */
.tapme {
  position: absolute; top: 14px; right: 14px; font-size: 10.5px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase; padding: 6px 11px; border-radius: 99px;
  background: var(--red-soft); color: var(--red-deep); box-shadow: inset 0 0 0 1px #f2d2d2;
}
.post:hover .tapme, .post.next .tapme { background: var(--red); color: #fff; box-shadow: none; }

/* The card to look at next, called out as a whole box rather than a chip in the corner. */
.post.next { box-shadow: var(--shadow), inset 0 0 0 2px var(--red); }
.post.next .tapme { animation: tapme 1.6s ease-in-out infinite; }
@keyframes tapme { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.09); } }
@media (prefers-reduced-motion: reduce) { .post.next .tapme { animation: none; } }

/* The clock. Quiet until it matters, then impossible to ignore. */
.clock {
  font-size: 13px; font-weight: 700; color: var(--ink2); background: var(--soft);
  border-radius: 99px; padding: 5px 12px; white-space: nowrap;
}
.clock b { font-family: var(--mono); font-size: 15px; }
.clock.warn { background: var(--amber-soft); color: #5b3a07; }
/* .urgent, not .hot: see the note on .rec.streaking, .hot is the photo marker. */
.clock.urgent { background: var(--red-soft); color: var(--red-deep); animation: tick 1s steps(2) infinite; }
@keyframes tick { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .clock.urgent { animation: none; } }
.btn .cost { opacity: .6; font-family: var(--mono); font-size: 12px; margin-left: 2px; }
.nudge { animation: nudge 1.1s ease; }
@keyframes nudge { 0%, 100% { transform: none; } 30% { transform: scale(1.02); } }
@media (prefers-reduced-motion: reduce) { .nudge { animation: none; } }
/* The standing instruction: always on screen, always current. */
.task {
  margin: 0 0 14px; font-size: 14px; color: var(--ink2); background: var(--soft);
  border-radius: 12px; padding: 11px 15px; line-height: 1.45;
  box-shadow: inset 0 0 0 1px var(--line);
}
.task.owed { background: var(--amber-soft); color: #6b4506; font-weight: 600; box-shadow: inset 0 0 0 1px #f0dcb0; }
.who-line { margin: 12px 0 0; font-size: 13px; color: var(--muted); text-align: center; }
/* What a returning player came back for: their own numbers, before anything else on the page. */
/* The scoreboard a returning player opens the page for. One card, four readings, hairlines
   between them, four separate boxes read as four unrelated things. */
.record {
  display: grid; grid-template-columns: repeat(4, 1fr); margin: 24px 0 0;
  background: var(--card); border-radius: 18px; overflow: hidden;
  box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--line);
}
.rec { padding: 16px 8px; text-align: center; position: relative; }
.rec + .rec::before {
  content: ""; position: absolute; left: 0; top: 22%; bottom: 22%; width: 1px; background: var(--line);
}
.rec b {
  display: block; font-family: var(--display); font-size: clamp(24px, 6vw, 30px); font-weight: 800;
  line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.rec span {
  display: block; margin-top: 5px; font-size: 11px; color: var(--muted);
  letter-spacing: .05em; text-transform: uppercase; font-weight: 600; line-height: 1.25;
}
@media (max-width: 420px) { .rec span { font-size: 10px; } }
/* NOT .hot, that is the hotspot marker on a photo, which is `position: absolute` and 26px
   round. A record cell called .hot became a circle floating outside the grid. */
.rec.streaking b { color: var(--amber); }
.last-case { margin: 10px 2px 0; font-size: 14px; color: var(--muted); }
.last-case b { color: var(--ink); }
@media (max-width: 520px) { .record { grid-template-columns: repeat(2, 1fr); } }

.hub-who { text-align: left; margin-top: 16px; }
.today .btn.ghost { margin-top: 10px; background: rgba(255,255,255,.12); color: #fff; }
.today.done .btn.ghost { background: #fff; color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--line); }
.who-line button {
  border: 0; background: none; padding: 0; font: inherit; color: var(--ink);
  text-decoration: underline; cursor: pointer;
}

/* The scenes are drawn in a 0-100 square, so the frame is square too: a 4:3 frame sliced the
   header off the map screenshot, which is exactly the sort of detail this game is about. */
.shot { position: relative; margin-top: 10px; border-radius: 10px; overflow: hidden; aspect-ratio: 1 / 1; background: #e9edf2; }
.scene { width: 100%; height: 100%; display: block; }
/* Markers sit BESIDE the detail, never on it: a game about reading what is in a picture must
   not cover the thing it wants you to read. Small, and translucent until you touch them. */
.hot {
  position: absolute; width: 26px; height: 26px; margin: -13px 0 0 -13px; border-radius: 50%;
  border: 2px solid #fff; background: rgba(21,24,29,.45); cursor: pointer; padding: 0;
  box-shadow: 0 2px 8px rgba(0,0,0,.35); animation: pulse 2.4s ease-in-out infinite;
}
.hot::after { content: ""; position: absolute; inset: 8px; border-radius: 50%; background: #fff; }
.hot:hover, .hot:focus-visible { background: var(--ink); }
/* A marker's colour is the PLAYER'S judgement, in this order. Examined, then answered.
   `spent` used to be green and declared last, so opening a marker turned it green before any
   answer was given. Testers read that as "correct", and it was only "looked at". */
.hot.spent { animation: none; background: var(--ink2); border-color: #fff; }
.hot.spent.unread { background: var(--amber); }
.hot.spent.right { background: var(--green); }
.hot.spent.dud { background: var(--muted); }
.hot.spent.misread { background: var(--red); }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.14); } }
@media (prefers-reduced-motion: reduce) { .hot { animation: none; } }

.fields { margin: 6px 0 0; display: grid; gap: 6px; }
.fields .row { display: flex; justify-content: space-between; gap: 12px; font-size: 15px; padding: 7px 10px; border-radius: 8px; background: var(--soft); }
.fields .row span:first-child { color: var(--muted); }

/* ---------- clue progress ---------- */
/* A pip per item, and a case can hold eleven. They have to share whatever width is left
   rather than push the row off a 320px screen. */
.progress { display: flex; align-items: center; gap: 10px; font-weight: 600; color: var(--muted); font-size: 14px; min-width: 0; flex: 1; }
.progress b { color: var(--ink); font-size: 15px; }
.pips { display: flex; gap: 3px; flex: 1; min-width: 40px; }
.pips i {
  flex: 1 1 0; min-width: 5px; max-width: 20px; height: 6px; border-radius: 99px;
  background: var(--line); display: block; transition: background .25s ease;
}
.pips i.on { background: var(--muted); }
.pips i.on.right { background: var(--green); }
.pips i.on.wrong { background: var(--red); }

/* ---------- icons ----------
   Masked SVG rather than an icon font or a sprite: they inherit colour, they scale with the
   text, and there is no extra request for nine small pictures. */
.ico {
  display: inline-block; width: 1em; height: 1em; flex: none; vertical-align: -0.12em;
  background: currentColor; -webkit-mask: var(--d) center/contain no-repeat; mask: var(--d) center/contain no-repeat;
}
.ico-globe { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.5 2.7 2.5 15 0 18M12 3c-2.5 2.7-2.5 15 0 18"/></svg>'); }
.ico-friends { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2"><circle cx="9" cy="8" r="3.4"/><path d="M3 20c0-3.3 2.7-5.5 6-5.5s6 2.2 6 5.5"/><path d="M16 5.5A3.4 3.4 0 0 1 16 12M18 20c0-2.6-1-4.4-2.6-5.3"/></svg>'); }
.ico-heart { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black"><path d="M12 21s-8-5.2-8-10.3A4.7 4.7 0 0 1 12 7a4.7 4.7 0 0 1 8 3.7C20 15.8 12 21 12 21z"/></svg>'); }
.ico-reply { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2"><path d="M21 11.5a8.4 8.4 0 0 1-9 8.4 9.6 9.6 0 0 1-3-.5L4 21l1.7-4.3A8.2 8.2 0 0 1 3 11.5 8.4 8.4 0 0 1 12 3a8.4 8.4 0 0 1 9 8.5z"/></svg>'); }
.ico-share { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2"><path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7M12 15V3M8 7l4-4 4 4"/></svg>'); }
.ico-search { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2"><circle cx="11" cy="11" r="7"/><path d="M16.5 16.5 21 21"/></svg>'); }
.ico-clock { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2"><circle cx="12" cy="12" r="9"/><path d="M12 7v5.2l3.4 2"/></svg>'); }
.ico-tick { --d: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="3"><path d="M4 12.5 9.5 18 20 6.5"/></svg>'); }

/* ---------- the case file on the hub ---------- */
.today.loading { opacity: .75; }
.today.loading .k::after {
  content: ""; display: inline-block; width: 1em; height: 1em; margin-left: 8px;
  vertical-align: -0.15em; border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .today.loading .k::after { animation: none; } }

.case-head { display: flex; gap: 16px; align-items: flex-start; }
.case-portrait {
  width: 88px; height: 88px; flex: none; border-radius: 16px; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.06), var(--shadow-sm); background: var(--soft);
}
.case-portrait .scene { width: 100%; height: 100%; }
.case-who { min-width: 0; }
.case-who h3 { font-size: clamp(24px, 5.4vw, 32px); margin: 6px 0 6px; letter-spacing: -0.02em; }
.case-brief { margin: 0; font-size: 15.5px; opacity: .78; line-height: 1.45; }
.case-facts { display: flex; gap: 10px; margin: 18px 0 14px; flex-wrap: wrap; }
.fact {
  display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600;
  padding: 9px 16px; border-radius: 99px; background: rgba(255,255,255,.10);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
}
.fact .ico { font-size: 15px; opacity: .85; }
.case-mission { margin: 0 0 18px; font-size: 15px; opacity: .72; }
.today.bonus .fact, .today.done .fact { background: var(--soft); box-shadow: inset 0 0 0 1px var(--line); }

/* ---------- a post, as the account's owner would see it ---------- */
.avatar {
  width: 38px; height: 38px; flex: none; border-radius: 50%; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.07);
}
.avatar .scene { width: 100%; height: 100%; }
.who-col { display: grid; gap: 1px; min-width: 0; }
.post .meta { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; color: var(--muted); }
.post .meta .who { font-weight: 700; color: var(--ink); font-size: 14.5px; }
.when { display: flex; align-items: center; gap: 5px; font-size: 12.5px; }
.when .ico { font-size: 12px; }
.when .dot { opacity: .5; }
.more { margin-left: auto; letter-spacing: 1px; color: var(--muted); align-self: flex-start; }
.reactions {
  display: flex; gap: 20px; align-items: center; margin-top: 12px; padding-top: 11px;
  border-top: 1px solid var(--line); color: var(--muted); font-size: 13px;
}
.reaction { display: inline-flex; align-items: center; gap: 6px; }
.reaction .ico { font-size: 15px; }
.reaction:first-child { color: var(--red); }

/* ---------- the evidence sheet ---------- */
.sheet { position: fixed; inset: 0; background: rgba(21,24,29,.5); display: grid; place-items: end center; z-index: 40; padding: 16px; }
.sheet-inner {
  background: var(--card); border-radius: 24px 24px 18px 18px; padding: 24px; width: min(100%, 540px);
  max-height: 88dvh; overflow-y: auto; animation: rise .26s cubic-bezier(.2,.8,.2,1);
  box-shadow: var(--shadow-lg);
}
@keyframes rise { from { transform: translateY(16px); opacity: 0; } }
.ask { font-weight: 700; margin: 14px 0 10px; }
.options { display: grid; gap: 10px; }
.opt {
  text-align: left; padding: 15px 18px; border-radius: 14px; background: var(--card); font: inherit;
  box-shadow: inset 0 0 0 1.5px var(--line); cursor: pointer; border: 0; color: inherit; font-size: 15.5px;
  line-height: 1.45; transition: box-shadow .15s ease, background .15s ease;
}
.opt:hover { box-shadow: inset 0 0 0 1.5px #c9ced6; }
.opt.right { box-shadow: inset 0 0 0 2px var(--green); background: var(--green-soft); }
.opt.wrong { box-shadow: inset 0 0 0 2px var(--red); background: #fdeced; }
.opt:disabled { cursor: default; }
.verdict { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line); }
.verdict-line { font-weight: 800; font-size: 17px; }
.verdict-line.good { color: var(--green); }
.verdict-line.bad { color: var(--red-deep); }

/* ---------- the evidence chips and the readings ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 18px; }
.chip {
  display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600;
  padding: 7px 13px; border-radius: 99px; background: var(--amber-soft); color: #6b4506;
  box-shadow: inset 0 0 0 1px #f0dcb0;
}
.chip.open { background: var(--red-soft); color: var(--red-deep); box-shadow: inset 0 0 0 1px #f2d2d2; }
.chip .ico { font-size: 13px; }

.opt { display: flex; align-items: flex-start; gap: 12px; }
.radio {
  width: 20px; height: 20px; flex: none; border-radius: 50%; margin-top: 1px;
  box-shadow: inset 0 0 0 2px var(--line); position: relative;
}
.opt:hover .radio { box-shadow: inset 0 0 0 2px #cdbfae; }
.opt.right .radio { box-shadow: inset 0 0 0 6px var(--green); }
.opt.wrong .radio { box-shadow: inset 0 0 0 6px var(--red); }
#sheetSkip { color: var(--muted); font-weight: 600; font-size: 14.5px; background: none; padding: 12px; }

/* Who brought you the case. A case has a client; a puzzle does not, and testers felt it. */
.client {
  margin: 0 0 18px; padding: 16px 18px 16px 20px; border-radius: 0 14px 14px 0;
  background: var(--soft); border-left: 3px solid var(--amber);
  font-family: var(--display); font-size: 16.5px; line-height: 1.5; color: var(--ink2);
}

/* ---------- running out of time ----------
   The last thirty seconds belong to the whole screen. A chip changing colour in the corner is
   not a deadline, people ran out without noticing they were close. */
body.lastcall::after {
  content: ""; position: fixed; inset: 0; z-index: 44; pointer-events: none;
  box-shadow: inset 0 0 0 4px var(--red), inset 0 0 70px rgba(180,32,47,.45);
  animation: lastcall 1s ease-in-out infinite;
}
@keyframes lastcall { 50% { opacity: .35; } }

.timeup {
  position: fixed; inset: 0; z-index: 80; display: grid; place-items: center;
  background: radial-gradient(120% 90% at 50% 40%, #c2283a 0%, #7d1420 70%, #5c0d16 100%);
  color: #fff; text-align: center; animation: timeup .32s cubic-bezier(.2,1.2,.3,1) both;
}
.timeup-inner { padding: 0 24px; }
.timeup h2 {
  font-size: clamp(64px, 24vw, 150px); margin: 14px 0 10px; letter-spacing: -0.04em;
  line-height: .9; color: #fff; text-shadow: 0 10px 40px rgba(0,0,0,.35);
}
.timeup p { margin: 0; font-size: clamp(16px, 4.4vw, 19px); color: #ffd9dd; }
.timeup-rule { display: block; width: 72px; height: 4px; margin: 0 auto; border-radius: 99px; background: #fff; opacity: .85; }
@keyframes timeup { from { opacity: 0; transform: scale(1.12); } }
@media (prefers-reduced-motion: reduce) {
  .timeup { animation: none; }
  body.lastcall::after { animation: none; }
}

/* ---------- the case opening and closing ----------
   Theatre, deliberately. A case that simply appears is a form. */
/* A title card, deliberately unlike every other screen. The opening used to be the same warm
   paper as the game, so even at the right speed it read as "the page changed" rather than
   "something is starting". */
#opening.active { display: flex; }
#opening {
  background: radial-gradient(120% 90% at 50% 0%, #241d16 0%, var(--ink) 60%);
  color: #f6efe4;
}
#opening h1 { color: #fff; }
#opening .film-client { color: #ded3c2; border-left-color: var(--amber); }
#opening .film-mission { color: #bfb3a0; }
#opening .film-skip { color: #8f8577; }
#opening .eyebrow { color: #f0a93b; }
.film-title { animation: filmIn .6s ease both; }
.film-no { animation: filmIn .5s ease both; }
.film {
  min-height: 100dvh; width: 100%; max-width: 620px; margin: 0 auto;
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  padding: calc(64px + var(--safe-t)) 24px calc(40px + var(--safe-b)); position: relative;
}
/* The quote grows as it types; reserving its height stops the title walking up the screen. */
#opening .film-client { min-height: 5.6em; }
.film .eyebrow { color: var(--amber); }
.film h1 { font-size: clamp(34px, 9vw, 58px); margin: 4px 0 26px; }
.film-client {
  margin: 0; padding: 0 0 0 20px; border-left: 3px solid var(--amber);
  font-family: var(--display); font-size: clamp(17px, 4.4vw, 21px); line-height: 1.55;
  color: var(--ink2); min-height: 4.8em;
}
.film-client.typing::after {
  content: ""; display: inline-block; width: 2px; height: 1em; margin-left: 3px;
  background: var(--amber); vertical-align: -0.12em; animation: caret .9s steps(2) infinite;
}
@keyframes caret { 50% { opacity: 0; } }
.film-mission {
  margin: 26px 0 0; font-weight: 600; font-size: 16px;
  animation: filmIn .45s ease both;
}
.film .btn { margin-top: 22px; animation: filmIn .45s .1s ease both; }
@keyframes filmIn { from { opacity: 0; transform: translateY(10px); } }
.film-skip {
  position: absolute; top: calc(18px + var(--safe-t)); right: 20px;
  border: 0; background: none; font: inherit; font-size: 14px; color: var(--muted);
  text-decoration: underline; cursor: pointer; padding: 12px;
}

#closing .wrap { max-width: 620px; }
#closing h2 { margin-bottom: 18px; }
#closing .board { margin: 0 0 22px; }
.reveal-line { min-height: 6em; font-size: clamp(17px, 4.2vw, 20px); }
.pin.missed { opacity: .55; background: #f6f1e6; box-shadow: 0 4px 12px rgba(60,40,20,.18); }
.pin.missed .tack { background: radial-gradient(circle at 35% 30%, #cfc7b8, #9a9182); }
.string.missed { stroke: #8a8178; stroke-dasharray: 5 5; opacity: .75; animation: none; }
@media (prefers-reduced-motion: reduce) { .film-mission, .film .btn { animation: none; } }

/* ---------- the evidence board ----------
   The image everybody has of a detective: pinned notes with string between the things that go
   together. A deduction drawn rather than described, and the only part of the game that moves
   on its own. */
.board-wrap {
  position: fixed; inset: 0; z-index: 45; background: var(--paper);
  display: flex; flex-direction: column; animation: boardIn .3s ease both;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
}
@keyframes boardIn { from { opacity: 0; transform: scale(.985); } }
.board-head {
  position: sticky; top: 0; z-index: 2; background: var(--paper);
  display: flex; align-items: flex-start; gap: 14px;
  padding: calc(14px + var(--safe-t)) 18px 12px; border-bottom: 1px solid var(--line);
}
.board-head h3 { margin: 2px 0 0; font-size: 22px; }
.board-head .icon-btn { margin-left: auto; }

/* Height comes from the number of pinned notes (set in app.js), because five pins squeezed
   into a fixed box overlap each other however small the cards are. */
.board {
  position: relative; flex: none; margin: 14px 16px;
  border-radius: 18px; overflow: hidden;
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,.5), transparent 55%),
    repeating-linear-gradient(48deg, #cdb38c 0 3px, #c6aa82 3px 6px);
  box-shadow: inset 0 0 0 6px #8a6b45, inset 0 0 40px rgba(72,48,24,.3);
}
.strings { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* vector-effect keeps the string an even thickness even though the svg is stretched to the
   board's shape by preserveAspectRatio="none". */
.string {
  stroke: #b4202f; stroke-width: 2; stroke-linecap: round; opacity: .85; fill: none;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 400; stroke-dashoffset: 400;
  animation: draw .8s cubic-bezier(.4,0,.2,1) forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }

.pins { position: absolute; inset: 0; }
.pin {
  position: absolute; transform: translate(-50%, -50%) rotate(var(--tilt, -1.2deg));
  width: min(40%, 180px); padding: 12px 12px 13px; border-radius: 3px;
  background: #fffdf5; box-shadow: 0 10px 22px rgba(60,40,20,.28);
  font-size: 12px; line-height: 1.38; animation: pinIn .45s cubic-bezier(.2,1.3,.4,1) both;
}
/* A pin is a note, not the full reading, it has to stay inside the board whatever the text
   length, or the cards overlap each other and spill off the cork. */
.pin b, .pin .pin-text {
  display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden;
}
.pin b { -webkit-line-clamp: 2; }
.pin .pin-text { -webkit-line-clamp: 2; }
.pin:nth-child(even) { --tilt: 1.4deg; }
.pin:nth-child(3n) { --tilt: -2.2deg; }
.pin b { display: block; font-size: 13px; margin-bottom: 4px; }
.pin .pin-text { color: var(--ink2); }
.pin.ruled { background: #f1ece2; }
.pin.ruled b { color: var(--muted); }
.tack {
  position: absolute; top: -7px; left: 50%; margin-left: -7px; width: 14px; height: 14px;
  border-radius: 50%; background: radial-gradient(circle at 35% 30%, #e8604f, #a8281c);
  box-shadow: 0 2px 5px rgba(0,0,0,.35);
}
.pin.ruled .tack { background: radial-gradient(circle at 35% 30%, #b9b2a6, #7d766a); }
@keyframes pinIn { from { opacity: 0; transform: translate(-50%, -62%) rotate(0deg) scale(.9); } }
.board-empty { margin: 0 18px 10px; color: var(--muted); font-size: 14px; text-align: center; }
.board-wrap .deduce-list { margin: 0 16px calc(18px + var(--safe-b)); }
@media (prefers-reduced-motion: reduce) {
  .board-wrap, .pin { animation: none; }
  .string { stroke-dashoffset: 0; animation: none; }
}

/* ---------- the case notebook ---------- */
#notesBtn b { font-family: var(--mono); font-size: 13px; opacity: .55; }
#notesBtn.has { box-shadow: inset 0 0 0 1.5px var(--amber); }
#notesBtn.has b { opacity: 1; color: var(--amber); }

.notes-list, .deduce-list { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 12px; }
.notes-list li { display: grid; gap: 3px; padding-left: 16px; position: relative; font-size: 14.5px; line-height: 1.45; }
.notes-list li::before {
  content: ""; position: absolute; left: 0; top: 8px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--green);
}
.notes-list li.ruled::before { background: var(--muted); }
.notes-list li.empty { color: var(--muted); padding-left: 0; }
.notes-list li.empty::before { display: none; }
.notes-list b { font-weight: 700; }
.notes-list span { color: var(--ink2); }

.deduce-head { margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--line); }
.deduce-list li {
  display: flex; gap: 10px; align-items: flex-start; font-size: 14.5px; line-height: 1.5;
  padding: 13px 15px; border-radius: 13px; background: var(--soft);
}
.deduce-list li.made {
  background: var(--ink); color: #fff; font-family: var(--display); font-size: 16px;
  box-shadow: var(--shadow-sm);
}
.deduce-list li.locked { color: var(--muted); }
.deduce-mark { flex: none; color: var(--amber); font-size: 15px; line-height: 1.4; }
.deduce-list li.made .deduce-mark { color: #f0a93b; }
#notes .btn.wide { margin-top: 22px; }

/* The moment two findings become one conclusion. */
.deduce-banner {
  position: fixed; left: 50%; bottom: calc(92px + var(--safe-b)); transform: translateX(-50%);
  z-index: 55; width: min(92vw, 520px); display: flex; gap: 14px; align-items: flex-start;
  padding: 16px 18px; border-radius: 18px; background: var(--ink); color: #fff;
  box-shadow: var(--shadow-lg); pointer-events: none;
}
.deduce-banner { pointer-events: auto; cursor: pointer; }
.deduce-banner .deduce-mark { font-size: 22px; line-height: 1.1; }
.deduce-cta { display: block; margin-top: 7px; font-size: 12px; color: #bda9e6; opacity: .85; }
.deduce-banner b { display: block; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: #f0a93b; margin-bottom: 5px; }
.deduce-banner p { margin: 0; font-family: var(--display); font-size: 16.5px; line-height: 1.45; }
.deduce-banner.in { animation: deduce .5s cubic-bezier(.2,1,.3,1) both; }
@keyframes deduce { from { transform: translate(-50%, 14px); opacity: 0; } to { transform: translate(-50%, 0); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .deduce-banner.in { animation: none; } }

/* ---------- fixes ---------- */
.fix-list { display: grid; gap: 10px; margin: 20px 0 0; }
.fix {
  display: flex; align-items: flex-start; gap: 13px; padding: 16px 18px; border-radius: 14px;
  background: var(--card); box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--line); cursor: pointer;
  font-size: 16px; transition: box-shadow .15s ease;
}
.fix input { width: 20px; height: 20px; flex: none; margin: 2px 0 0; accent-color: var(--ink); }
.fix.on { box-shadow: inset 0 0 0 2px var(--ink); }

/* ---------- the moment it is finished ---------- */
.complete {
  display: flex; align-items: center; gap: 16px; margin: 0 0 22px; padding: 20px 22px;
  border-radius: 20px; background: var(--green-soft); box-shadow: inset 0 0 0 1px #c9e6d4;
}
.complete h2 { margin: 0 0 3px; font-size: clamp(24px, 5vw, 32px); color: #0b5c38; }
.complete p { margin: 0; font-size: 14.5px; }
.seal {
  width: 52px; height: 52px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: var(--green); color: #fff; font-size: 24px; box-shadow: 0 6px 18px rgba(15,122,74,.3);
  animation: seal .5s cubic-bezier(.2,1.4,.4,1) both;
}
@keyframes seal { from { transform: scale(.4); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .seal { animation: none; } }

/* ---------- result ---------- */
.reveal {
  padding: 26px; border-radius: 22px; background: var(--ink); color: #fff; margin-bottom: 22px;
  box-shadow: var(--shadow);
}
.reveal p:last-child { font-family: var(--display); font-size: 19px; }
.reveal .eyebrow { color: #9aa4b2; }
.reveal p:last-child { margin: 0; font-size: 18px; line-height: 1.55; }
.result-grid { display: grid; gap: 18px; grid-template-columns: 1fr; }
@media (min-width: 820px) { .result-grid { grid-template-columns: 1.1fr 1fr; align-items: start; } }
.card { background: var(--card); border-radius: 18px; padding: 22px; box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--line); }
.card ul { margin: 0; padding-left: 20px; }
.card li { margin-bottom: 8px; color: var(--ink2); }
.score-card .total { margin: 18px 0 0; font-weight: 800; }
.score-card .total b { font-size: 46px; }
.score-card .total span { color: var(--muted); font-size: 20px; }
.bars { display: grid; gap: 12px; margin-top: 18px; }
.bar {
  display: grid; grid-template-columns: 86px 1fr 52px; align-items: center; gap: 4px 10px; font-size: 14px;
  grid-template-areas: "name track pts" "why why why";
}
.bar span { grid-area: name; }
.bar i { grid-area: track; }
.bar em { grid-area: pts; }
.bar small { grid-area: why; color: var(--muted); font-size: 12.5px; }
.bar i { display: block; height: 9px; border-radius: 99px; background: var(--line); overflow: hidden; }
.bar b { display: block; height: 100%; background: var(--green); border-radius: 99px; width: 0; transition: width .5s ease; }
.bar em { font-style: normal; text-align: right; font-weight: 700; font-family: var(--mono); font-size: 13px; }
.result-side { display: grid; gap: 12px; align-content: start; }
.score-why { margin: 14px 0 0; font-size: 15px; line-height: 1.55; color: var(--ink2); }
.small { font-size: 13px; }

/* The whole point of this list: a number on its own told nobody why it was the number it was. */
.ledger { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 10px; }
.ledger li { margin: 0; display: grid; grid-template-columns: 22px 1fr auto; gap: 4px 8px; align-items: baseline; }
.ledger .mark { font-weight: 800; font-size: 15px; }
.ledger .lab { font-weight: 700; color: var(--ink); }
.ledger .pts { font-family: var(--mono); font-size: 13px; font-weight: 700; color: var(--muted); white-space: nowrap; }
.ledger .note { grid-column: 2 / -1; color: var(--ink2); font-size: 14px; line-height: 1.45; }
.ledger .right .mark { color: var(--green); }
.ledger .misread .mark, .ledger .missed .mark { color: var(--red-deep); }
.ledger .unanswered .mark { color: var(--amber); }

.toast {
  position: fixed; left: 50%; bottom: calc(22px + var(--safe-b)); transform: translateX(-50%);
  background: var(--ink); color: #fff; padding: 12px 18px; border-radius: 99px; font-size: 15px;
  z-index: 60; max-width: calc(100vw - 32px);
  /* It floats above the sheet, so without this it silently eats the tap on "Back to the feed"
     which is exactly where it sits after flagging a decoy. Nothing informational takes a tap. */
  pointer-events: none;
}

/* ---------- daily hub ---------- */
.hub-top { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.hub-top .badge { margin: 0; }
.streak {
  display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 800;
  color: var(--amber); background: var(--amber-soft); border-radius: 99px; padding: 6px 14px;
}
.streak::before { content: "🔥"; }
.today {
  display: block; width: 100%; text-align: left; margin: 24px 0 0; padding: 24px; border: 0;
  border-radius: 22px; background: var(--ink); color: #fff; font: inherit; box-shadow: var(--shadow);
}
.today.bonus { background: #fff; color: var(--ink); box-shadow: inset 0 0 0 2px var(--amber); margin-top: 12px; }
.today .k { font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; opacity: .65; }
.today.bonus .k { color: var(--amber); opacity: 1; }
.today h3 { font-size: 22px; margin: 8px 0 6px; }
.today p { margin: 0 0 16px; opacity: .8; font-size: 15px; }
.today .btn { width: 100%; }
.today.done { background: var(--green-soft); color: var(--ink); box-shadow: inset 0 0 0 2px var(--green); }
.today.done .k { color: var(--green); opacity: 1; }
.today.locked { background: var(--soft); color: var(--muted); }
.next-in { margin-top: 18px; color: var(--muted); font-size: 15px; }
.next-in b { color: var(--ink); font-family: var(--mono); }

/* ---------- the coach: teaches by doing, never by explaining ---------- */
.coach { position: fixed; inset: 0; z-index: 70; pointer-events: none; }
.coach-spot {
  position: absolute; border-radius: 14px; transition: all .3s ease;
  box-shadow: 0 0 0 9999px rgba(21,24,29,.72); pointer-events: none;
}
.coach-box {
  position: absolute; left: 50%; transform: translateX(-50%); width: min(92vw, 420px);
  background: #fff; border-radius: 16px; padding: 18px; pointer-events: auto;
  box-shadow: 0 18px 40px rgba(0,0,0,.3);
}
.coach-box p { font-size: 16px; margin: 0 0 14px; }
.coach-box .btn { width: 100%; }
.coach-box.waiting .btn { display: none; }
/* Always reachable, including on the steps that are waiting for an action: whatever else goes
   wrong, nobody is left looking at a dimmed page with no way off it. */
.coach-skip {
  display: block; margin: 0 auto; padding: 4px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 13px; color: var(--muted); text-decoration: underline;
}
.coach-box.waiting .coach-skip { margin-top: -4px; }

/* ---------- signing in ---------- */
#signupBox { margin-top: 26px; display: grid; gap: 18px; }
.field { margin: 0; display: grid; gap: 7px; }
.field label {
  font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted);
}
.hint-line { margin: 2px 2px 0; font-size: 13px; color: var(--muted); line-height: 1.45; }
#signupBox .btn { margin-top: 2px; }

/* a running score, so the player can see the game reacting to them */
.livescore {
  margin-left: auto; flex: none; font-size: 13px; font-weight: 700; color: var(--green);
  background: var(--green-soft); border-radius: 99px; padding: 5px 12px; white-space: nowrap;
}
.livescore b { font-family: var(--mono); font-size: 15px; }
.livescore.bump { animation: bump .4s ease; }
@keyframes bump { 40% { transform: scale(1.18); } }
.game-top .btn { padding: 9px 12px; font-size: 14px; }


/* ---------- landing ---------- */
.hero { max-width: 1120px; margin: 0 auto; padding: 46px 20px 10px; }
.hero-grid { display: grid; gap: 34px; align-items: center; }
@media (min-width: 900px) { .hero-grid { grid-template-columns: 1.05fr .95fr; gap: 48px; } }
.hero-copy h1 em { font-style: normal; color: var(--red); }

/* the demo shows the two-step mechanic without a word of explanation */
.demo { position: relative; display: none; }
@media (min-width: 900px) { .demo { display: block; } }
.demo-card {
  position: relative; background: #fff; border-radius: 16px; padding: 16px;
  box-shadow: 0 24px 50px rgba(16,24,40,.16); max-width: 380px; margin: 0 auto;
}
.demo-meta { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 13px; margin-bottom: 10px; }
.demo-meta b { color: var(--ink); font-size: 14.5px; }
.demo-card .reactions { margin-top: 10px; padding-top: 10px; }
.demo-meta b { color: var(--ink); }
.demo-shot { border-radius: 10px; overflow: hidden; aspect-ratio: 1 / 1; background: #e9edf2; }
.demo-shot .scene { width: 100%; height: 100%; display: block; }
.demo-cap { font-size: 15px; margin-top: 10px; }
.demo-pin {
  position: absolute; left: 90%; top: 38%; width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 50%; border: 2px solid #fff; background: var(--red);
  box-shadow: 0 2px 10px rgba(0,0,0,.35); animation: findPin 6s ease-in-out infinite;
}
.demo-pin::after { content: ""; position: absolute; inset: 9px; border-radius: 50%; background: #fff; }
@keyframes findPin {
  0%, 12% { transform: scale(.4); opacity: 0; }
  20%, 100% { transform: scale(1); opacity: 1; }
}
.demo-bubble {
  position: relative; margin: 16px auto 0; max-width: 380px; background: var(--ink); color: #fff;
  border-radius: 14px; padding: 14px 16px; font-size: 14.5px; line-height: 1.45;
}
.demo-q { display: block; font-weight: 700; opacity: .7; margin-bottom: 8px; }
.demo-a, .demo-x { display: block; padding: 8px 11px; border-radius: 9px; margin-bottom: 6px; }
.demo-a { background: rgba(11,138,74,.28); animation: pickRight 6s ease-in-out infinite; }
.demo-x { background: rgba(227,0,15,.22); opacity: .55; }
.demo-x::after { content: " ✕"; font-weight: 800; }
.demo-a::after { content: " ✓"; font-weight: 800; }
@keyframes pickRight { 0%, 45% { box-shadow: none; } 55%, 100% { box-shadow: inset 0 0 0 2px #35d08a; } }
@media (prefers-reduced-motion: reduce) { .demo-pin, .demo-a { animation: none; } }

.strip { background: var(--soft); margin-top: 44px; padding: 30px 20px; }
.steps { max-width: 1000px; margin: 0 auto; padding: 0; list-style: none; display: grid; gap: 18px; counter-reset: s; }
@media (min-width: 760px) { .steps { grid-template-columns: repeat(3, 1fr); gap: 26px; } }
.steps li { display: flex; gap: 13px; align-items: flex-start; font-size: 15.5px; color: var(--ink2); }
.steps b {
  flex: none; width: 28px; height: 28px; border-radius: 50%; background: var(--ink); color: #fff;
  display: grid; place-items: center; font-size: 14px; font-family: var(--mono);
}
.steps em { font-style: normal; font-weight: 700; color: var(--ink); }

.why { padding-top: 40px; }
.why h2 { max-width: 20ch; }
.why-grid { display: grid; gap: 26px; margin: 26px 0 0; }
@media (min-width: 760px) { .why-grid { grid-template-columns: repeat(3, 1fr); gap: 32px; } }
.why-grid h3 { margin-bottom: 6px; }
.why-grid p { color: var(--ink2); margin: 0; font-size: 15.5px; }

/* ---------------------------------------------------------------- sound
   Asked once, on the dark title card of the first case, so the choice reads as part of the
   opening rather than as a settings dialog. People play this at a desk next to someone. */
.sound-ask {
  margin-top: 26px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,.12);
  animation: filmIn .5s .4s ease both;
}
.sound-ask p { margin: 0 0 12px; font-size: 14px; color: #8f8577; }
.sound-ask-row { display: flex; gap: 10px; flex-wrap: wrap; }
.sound-ask .btn.ghost {
  flex: 1 1 140px; min-height: 44px; padding: 11px 18px; border-radius: 10px;
  background: rgba(255,255,255,.07); color: #ded3c2;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
}
.sound-ask .btn.ghost:hover { background: rgba(255,255,255,.13); color: #fff; }

/* The toggle lives in the game bar, next to the clock: always one tap away, never in a menu. */
.sound-btn { position: relative; font-size: 13px; line-height: 1; color: var(--ink); }
.sound-btn::before {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 15px; height: 15px; border-radius: 2px 2px 0 0;
  /* a small speaker: the cone is the ::before, the state glyph sits beside it */
  background: currentColor;
  clip-path: polygon(0 32%, 32% 32%, 68% 0, 68% 100%, 32% 68%, 0 68%);
  transform: translateX(-7px);
}
.sound-btn > span { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); font-size: 10px; }
.sound-btn.off { color: var(--muted); }
.sound-btn.off > span { color: var(--red); }

@media (prefers-reduced-motion: reduce) {
  .sound-ask { animation: none; }
}

/* A code expires in ten minutes; these are the two ways out of that. */
.code-help { margin: 8px 0 0; font-size: 13.5px; color: var(--muted); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.linkish {
  border: 0; background: none; padding: 8px 0; font: inherit; font-size: 13.5px;
  color: var(--red); text-decoration: underline; cursor: pointer; min-height: 44px;
}
.linkish:disabled { color: var(--muted); text-decoration: none; cursor: default; }

/* ---------- the hint ----------
   Same family as the deduction banner, because it has the same job: say something the player
   must not miss, wherever they happen to be scrolled to. It is amber rather than ink so the
   two are never confused, a deduction is something you worked out, a hint is something you
   bought. */
.hint-banner {
  position: fixed; left: 50%; bottom: calc(92px + var(--safe-b)); transform: translateX(-50%);
  z-index: 56; width: min(92vw, 520px); display: flex; gap: 13px; align-items: flex-start;
  padding: 15px 14px 15px 17px; border-radius: 18px;
  background: #3a2a08; color: #fff8ea; box-shadow: var(--shadow-lg); cursor: pointer;
}
.hint-banner .hint-mark { font-size: 20px; line-height: 1.2; }
.hint-banner .hint-body { flex: 1; min-width: 0; }
.hint-banner b {
  display: block; font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: #f0a93b; margin-bottom: 5px;
}
.hint-banner p { margin: 0; font-family: var(--display); font-size: 16.5px; line-height: 1.45; }
.hint-cta { display: block; margin-top: 7px; font-size: 12px; color: #f0c98a; }
.hint-close {
  flex: none; width: 34px; height: 34px; margin: -4px -4px 0 0; border: 0; border-radius: 50%;
  background: rgba(255,255,255,.1); color: #fff8ea; font-size: 13px; cursor: pointer;
}
.hint-close:hover { background: rgba(255,255,255,.2); }
.hint-banner.in { animation: deduce .5s cubic-bezier(.2,1,.3,1) both; }
@media (prefers-reduced-motion: reduce) { .hint-banner.in { animation: none; } }

/* ---------------------------------------------------------------- the walkthrough
   A detective stands on the screen and plays a sample case while you watch.

   Staged rather than stuck to the bottom edge. On a wide screen the first version put a tiny
   figure in the corner and stretched the speech across the whole window, which reads as a
   status bar rather than somebody talking to you. The bubble is held to a readable measure and
   kept beside him at every width. */
.wt { position: fixed; inset: 0; z-index: 58; pointer-events: none; }

/* The game stays legible behind, but darker at the edges, so the eye goes to the ringed card
   and the person explaining it. */
.wt-scrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(12,10,8,.72) 0%, rgba(12,10,8,.3) 26%, transparent 46%),
    radial-gradient(130% 80% at 50% 38%, transparent 38%, rgba(12,10,8,.42) 100%);
}

.wt-panel {
  position: absolute; left: 0; right: 0; bottom: 0; pointer-events: auto;
  padding: 0 0 calc(10px + var(--safe-b));
}
.wt-stage {
  width: min(960px, 100%); margin: 0 auto; padding: 0 16px;
  display: flex; align-items: flex-end; gap: 0;
}
.wt-figure { flex: none; width: 168px; margin: 0 -18px -4px 0; z-index: 2; }
.wt-figure svg {
  width: 100%; height: auto; display: block;
  filter: drop-shadow(0 16px 30px rgba(0,0,0,.6));
  transform-origin: 50% 100%;
  animation: wtIdle 5.5s ease-in-out infinite;
}
/* He breathes. Without it he is a sticker. */
@keyframes wtIdle {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-5px) rotate(-.7deg); }
}
.wt-panel.talking .wt-figure svg { animation: wtTalk 1.1s ease-in-out infinite; }
@keyframes wtTalk {
  0%, 100% { transform: translateY(-2px) rotate(-.4deg); }
  50% { transform: translateY(-7px) rotate(.5deg); }
}

.wt-bubble {
  flex: 1; min-width: 0; max-width: 620px; position: relative;
  background: linear-gradient(180deg, #2b2218, #141109);
  border-radius: 22px; padding: 18px 22px 16px;
  box-shadow: 0 26px 70px rgba(0,0,0,.7), inset 0 0 0 1.5px rgba(240,169,59,.45);
}
.wt-bubble::before {
  content: ""; position: absolute; left: -10px; bottom: 44px; width: 22px; height: 22px;
  background: #251d14; transform: rotate(45deg);
  box-shadow: inset 1.5px -1.5px 0 rgba(240,169,59,.45);
}
.wt-who { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.wt-who b { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: #f0a93b; }
.wt-step { font-size: 12px; color: #9a8c76; font-variant-numeric: tabular-nums; }
.wt-bubble p {
  margin: 0; color: #fff8ea; font-family: var(--display);
  font-size: 22px; line-height: 1.4; font-weight: 600; min-height: 2.8em;
}
.wt-bubble p mark {
  background: rgba(240,169,59,.2); color: #ffd98f; border-radius: 4px;
  padding: 0 4px; box-shadow: inset 0 -2px 0 rgba(240,169,59,.7);
}

.wt-controls { display: flex; gap: 8px; margin-top: 14px; }
.wt-btn {
  border: 0; font: inherit; font-size: 14.5px; font-weight: 700; cursor: pointer;
  padding: 11px 20px; border-radius: 11px; min-height: 44px;
  background: rgba(255,255,255,.12); color: #e8dcc6;
}
.wt-btn:hover:not(:disabled) { background: rgba(255,255,255,.22); color: #fff; }
.wt-btn:disabled { opacity: .35; cursor: default; }
.wt-btn.primary { background: var(--amber); color: #15120f; }
.wt-btn.primary:hover { background: #ffc063; }
.wt-btn.ghost { background: none; color: #9a8c76; margin-left: auto; }
.wt-btn.ghost:hover { background: rgba(255,255,255,.1); color: #e8dcc6; }

/* How far through, without a number nobody reads. */
.wt-bar { width: min(960px, 100%); margin: 10px auto 0; padding: 0 16px; }
.wt-bar span {
  display: block; height: 3px; border-radius: 2px; background: var(--amber);
  transition: width .4s ease; box-shadow: 0 0 10px rgba(240,169,59,.6);
}

.wt-panel.in { animation: wtIn .55s cubic-bezier(.2,1,.3,1) both; }
@keyframes wtIn { from { transform: translateY(34px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

@media (max-width: 560px) {
  .wt-figure { width: 104px; margin-right: -14px; }
  .wt-bubble p { font-size: 18.5px; }
  .wt-bubble { padding: 15px 16px 14px; }
  .wt-btn { padding: 10px 14px; font-size: 14px; }
}

/* What the detective is pointing at. A ring, not a spotlight: the rest of the screen stays
   readable, because the point is to show how the real screen behaves. */
.wt-point { position: relative; z-index: 2; }
.wt-point::after {
  content: ""; position: absolute; inset: -6px; border-radius: 16px; pointer-events: none;
  border: 3px solid var(--amber); box-shadow: 0 0 0 7px rgba(240,169,59,.18);
  animation: wtRing 1.5s ease-in-out infinite;
}
@keyframes wtRing {
  0%, 100% { box-shadow: 0 0 0 7px rgba(240,169,59,.18); }
  50% { box-shadow: 0 0 0 12px rgba(240,169,59,0); }
}
/* The dock belongs to the player, and during the walkthrough the detective is driving. Left
   visible it showed through behind the panel as a stray "Board 0" and half a "Close the case",
   which looks like a rendering fault and is also a button nobody should be pressing yet. */
body.walking .game-dock { visibility: hidden; }

/* Room so the figure never stands on the last card, and the sheet clears the panel. */
body.walking .game-col { padding-bottom: 330px; }
body.walking .sheet-inner { padding-bottom: 270px; }
@media (prefers-reduced-motion: reduce) {
  .wt-panel.in, .wt-figure svg, .wt-point::after { animation: none; }
}

/* ---------------------------------------------------------------- the leaderboard
   On the page, not behind a button. Deliberately plain: it is a list of colleagues, and
   anything that makes it feel like a podium makes it feel worse to be near the bottom of.

   Every class here is prefixed. Two bugs in a row came from reusing a short, obvious name
   that the rest of the stylesheet already owned: `.board` (the evidence board, which became a
   full-screen overlay) and `.top` (the site header, which turned a table row into a flex
   container). A prefix costs nothing. */
.lb { margin: 30px 0 0; padding: 20px; border-radius: 18px; background: var(--card);
      box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--line); }
.lb-head { display: flex; align-items: center; gap: 10px; }
.lb-head h2 { margin: 0; font-family: var(--display); font-size: 21px; }
.lb-live {
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--green); background: var(--green-soft); padding: 3px 9px; border-radius: 99px;
}
.lb-live::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green); margin-right: 5px; vertical-align: 1px;
  animation: lbPulse 2s ease-in-out infinite;
}
@keyframes lbPulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
.lb .sub { margin: 6px 0 0; font-size: 13.5px; color: var(--muted); }
.lb-table { width: 100%; border-collapse: collapse; margin-top: 14px; font-size: 15px; }
.lb-table th {
  text-align: left; font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: 0 8px 8px; font-weight: 700;
}
.lb-table th.num, .lb-table td.num { text-align: right; }
.lb-table td { padding: 11px 8px; border-top: 1px solid var(--line); }
.lb-table .lb-rank { color: var(--muted); width: 36px; font-variant-numeric: tabular-nums; }
.lb-table tr.lb-podium .lb-rank { color: var(--red); font-weight: 800; }
.lb-table tr.lb-you td { background: var(--amber-soft); font-weight: 700; }
.lb-table tr.lb-you td:first-child { border-radius: 8px 0 0 8px; }
.lb-table tr.lb-you td:last-child { border-radius: 0 8px 8px 0; }
.lb .fineprint { margin-top: 14px; color: var(--muted); font-size: 12px; }

/* Always on the hub: a first-timer is shown the walkthrough automatically, and anyone else
   can ask for it again whenever they like. */
.how-to { margin: 14px 0 0; }

/* The invitation a first-timer gets. Part of the page, not an overlay: it sits above the day's
   case so it is the first thing read, and it takes nothing over. */
.first-run {
  margin: 22px 0 0; padding: 18px 20px; border-radius: 16px;
  background: var(--amber-soft); box-shadow: inset 0 0 0 1.5px var(--amber);
}
.first-run-k {
  margin: 0; font-size: 12px; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--amber);
}
.first-run-t { margin: 6px 0 14px; font-size: 16px; color: var(--ink); }
.first-run-row { display: flex; gap: 10px; flex-wrap: wrap; }
.first-run-row .btn { flex: 1 1 150px; min-height: 44px; }
