/* ═══════════════════════════════════════════════════════════════════════════
   QUARTZINE · SET LIKE A PAGE

   The app is a printed page and the game is the plate set into it. Paper is
   warm and off-white, the type is a reading serif with a humanist sans under
   it, and the only lifted thing anywhere is the ink.

   Rules this sheet keeps, without exception:
     · Structure has NO radius. Only the few things a finger operates get 2px.
     · There is NO elevation. No shadow, no glow, no gradient. A hairline rule
       and empty space do every job a shadow would have done.
     · One column, inset from the left, stopping short of the right. Rules run
       wider than the measure so the text reads as a column on a page.
     · Rhythm is 24px. Sections are separated by a rule and 24 to 28px.
     · Motion is a 240ms ease-out crossfade. Nothing moves sideways, nothing
       scales, nothing bounces, nothing loops.
     · Icons are two hairline marks. Everything else is a word.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Written from JS by applySafeArea(). 0 outside Telegram fullscreen, so
     every utility that reads them collapses on its own. */
  --tg-safe-top: 0px;
  --tg-safe-bottom: 0px;

  /* Duplicated from brand.js so the cover paints correctly on frame one,
     before shell.js has stamped the palette onto <html>. */
  --paper:     #F5F2EA;
  --ink:       #17161B;
  --ink-2:     #55525C;
  --ink-3:     #6B6773;
  --ink-red:   #A9301B;
  --rule:      #D5CFC1;
  --spot:      #3B2FB8;
  --good:      #1F6B45;

  /* The plate. These eight are read by game.js off the root element, so the
     playfield can never drift away from the page it is set into. */
  --bg:        #15141A;
  --tint:      #23212C;
  --tint-2:    #322E3D;
  --line:      #38343F;
  --accent:    #6C5CE7;
  --accent-d:  #A99BFF;
  --warn:      #D8442F;

  --f-display: "Newsreader", Georgia, "Times New Roman", serif;
  --f-text: "Source Sans 3", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* The measure. Text stops short of the right edge; rules do not. */
  --mg: 24px;
  --short: 20px;

  --t: 240ms ease-out;
}

*, *::before, *::after { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* Overlays set their own display, which outranks the UA rule for [hidden]. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--paper);
  overscroll-behavior: none;
  -webkit-overflow-scrolling: touch;
}

body {
  font-family: var(--f-text);
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

h1, h2, p, ol, ul, figure, figcaption, table { margin: 0; padding: 0; }
ol, ul { list-style: none; }
button, input { font: inherit; color: inherit; }
button { border: 0; background: none; padding: 0; cursor: pointer; text-align: left; }

/* The mark sheet itself never renders. */
.marks { position: absolute; width: 0; height: 0; overflow: hidden; }

.mk {
  display: block; flex: none;
  width: 20px; height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  stroke-linecap: butt;
  stroke-linejoin: miter;
}
.mk-sm { width: 15px; height: 15px; }
.mk-lg { width: 46px; height: 46px; stroke-width: 0.7; }

/* ── type roles ──────────────────────────────────────────────────────────── */

/* The standing label above a block. Sans, small, letterspaced, quiet. */
.kicker {
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.4;
}

.head {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: clamp(30px, 8.6vw, 36px);
  line-height: 1.1;
  letter-spacing: -0.012em;
  margin-top: 10px;
  text-wrap: balance;
}

.section-h {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.25;
  margin-top: 26px;
}

.footnote {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  font-size: 12.5px; line-height: 1.55;
  color: var(--ink-3);
}
/* Deliberately NOT pushed to the floor with margin-top:auto. auto REPLACES the
   28px whenever the screen overflows, which puts the rule right on top of the
   last line on exactly the screens that scroll. One fixed gap everywhere: the
   small print reads as a colophon under the text, which is what it is. */

/* ── actions ─────────────────────────────────────────────────────────────
   One bordered primary, sitting inline with the text rather than spanning the
   width, and underlined words for everything else. */

.actions {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 12px 22px;
  margin-top: 24px;
}

.primary {
  display: inline-flex; align-items: center; gap: 9px;
  flex: none;
  border: 1px solid var(--ink);
  border-radius: 2px;
  padding: 11px 18px;
  font-family: var(--f-display);
  font-size: 17px; font-weight: 500;
  line-height: 1;
  color: var(--ink);
  background: transparent;
  transition: background var(--t), color var(--t), border-color var(--t);
}
.primary:active { background: var(--ink); color: var(--paper); }
.primary:disabled { color: var(--ink-3); border-color: var(--rule); }

.textlink {
  font-size: 15px;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--spot);
  text-underline-offset: 4px;
  transition: color var(--t), text-decoration-color var(--t);
}
.textlink:active { color: var(--spot); }
.textlink:disabled { color: var(--ink-3); text-decoration-color: var(--rule); }
.is-destructive { color: var(--ink-red); text-decoration-color: var(--ink-red); }

/* ── the hairline gauge ──────────────────────────────────────────────────── */

.gauge {
  height: 2px;
  background: var(--rule);
  margin-top: 12px;
}
.gauge i {
  display: block; height: 100%; width: 0;
  background: var(--ink);
  transition: width var(--t), background var(--t);
}
.gauge i.is-low { background: var(--warn); }

/* ── cover ───────────────────────────────────────────────────────────────── */

#splash {
  position: fixed; inset: 0; z-index: 90;
  background: var(--paper);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  color: var(--ink);
  transition: opacity var(--t);
}
#splash.out { opacity: 0; }
.sp-name {
  font-family: var(--f-display);
  font-size: 46px; font-weight: 400;
  letter-spacing: -0.015em;
  margin-top: 26px;
}
.sp-sub {
  font-family: var(--f-display);
  font-style: italic;
  font-size: 16px;
  color: var(--ink-2);
  margin-top: 2px;
}

/* ── frame ───────────────────────────────────────────────────────────────── */

#app {
  position: fixed; inset: 0;
  display: flex; flex-direction: column;
  background: var(--paper);
}

/* The top element carries the fullscreen top inset, so the masthead clears
   Telegram's floating Close / ⋯ row. */
.masthead {
  flex: none;
  padding-top: max(var(--tg-safe-top), env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--ink);
}
/* Fullscreen already reserves the chrome inset; trim a cosmetic sliver so the
   masthead does not read as a gap, floored at the inset itself. */
[data-fullscreen="1"] .masthead {
  padding-top: max(var(--tg-safe-top),
    calc(max(var(--tg-safe-top), env(safe-area-inset-top, 0px)) - 1.4vh));
}
.masthead-in {
  display: flex; align-items: center; gap: 10px;
  padding: 12px var(--mg) 11px;
}
.wordmark {
  font-family: var(--f-display);
  font-size: 19px; font-weight: 500;
  letter-spacing: 0.01em;
}
/* The rank, set as a standing line: italic, in the right margin. */
.standing {
  margin-left: auto;
  font-family: var(--f-display);
  font-style: italic;
  font-size: 15px;
  color: var(--ink-2);
}

/* ── bottom nav: four words over a hairline ─────────────────────────────────
   A flex-column child of #app, so it pins to the bottom of the fixed viewport
   above the scrolling page. */
.nav {
  flex: none;
  display: flex;
  border-top: 1px solid var(--rule);
  background: var(--paper);
  padding: 11px 10px;
  padding-bottom: calc(11px + max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px)));
}
.navtab {
  flex: 1;
  padding: 2px 4px;
  text-align: center;
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-3);
  transition: color var(--t);
}
/* Present on every tab, inked only on the active one, so nothing shifts. */
.navtab::after {
  content: ""; display: block;
  width: 18px; height: 1px;
  margin: 6px auto 0;
  background: transparent;
  transition: background var(--t);
}
.navtab.is-on { color: var(--ink); }
.navtab.is-on::after { background: var(--ink); }

/* Play is the plate and nothing else, so the page furniture steps aside. */
[data-screen="play"] .masthead,
[data-screen="play"] .nav { display: none; }

main { position: relative; flex: 1; min-height: 0; z-index: 0; }

.screen {
  position: absolute; inset: 0;
  display: none;
  flex-direction: column;
  overflow-y: auto;
}
.screen.is-active { display: flex; }

/* One slow crossfade per screen change. No stagger, no travel. */
@keyframes fade { from { opacity: 0; } }
.screen.is-active { animation: fade var(--t) ease-out; }

/* The column: inset from the left, stopping short of the right. */
.page { padding: 22px var(--mg) 30px; }
.article > p, .article > h1 { padding-right: var(--short); }

/* ── home ────────────────────────────────────────────────────────────────── */

/* The opening paragraph carries a drop cap, because this is a page. */
.standfirst {
  margin-top: 16px;
  color: var(--ink-2);
}
.standfirst::first-letter {
  float: left;
  font-family: var(--f-display);
  font-weight: 400;
  font-size: 3.15em;
  line-height: 0.82;
  color: var(--ink);
  padding: 3px 8px 0 0;
}

/* Your record, as a sentence rather than a row of tiles. Figures are set in
   the serif so they read as printed numerals inside running text. */
.record { margin-top: 20px; }
.record b {
  font-family: var(--f-display);
  font-weight: 600; font-size: 1.16em;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* Sections below the opening: a rule that runs wider than the measure. */
.figure, .item {
  margin: 28px calc(var(--mg) * -1) 0;
  padding: 20px var(--mg) 0;
  border-top: 1px solid var(--rule);
}

/* The figure: the difficulty curve of this exact game, printed as a table. */
.fig-h {
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
}
.tbl {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
  font-variant-numeric: tabular-nums;
}
.tbl th {
  padding: 0 0 7px;
  border-bottom: 1px solid var(--ink);
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-3);
  text-align: right;
}
.tbl th:first-child { text-align: left; }
.tbl td {
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--f-display);
  font-size: 17px;
  text-align: right;
}
.tbl td:first-child { text-align: left; color: var(--ink-2); }
.tbl tr:last-child td { border-bottom: 0; }
.figure figcaption {
  margin-top: 12px;
  padding-right: var(--short);
  font-family: var(--f-display);
  font-style: italic;
  font-size: 15px; line-height: 1.45;
  color: var(--ink-2);
}

/* Today's assignment, and the ad notice, share the standing-item setting. */
.item-goal {
  font-family: var(--f-display);
  font-size: 19px; line-height: 1.3;
  margin-top: 6px;
  padding-right: var(--short);
}
.item-meta {
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.item-meta .sep { margin-left: -3px; }
[data-daily-state].is-done { color: var(--good); }

.notice-tx {
  margin-top: 6px;
  padding-right: var(--short);
  color: var(--ink-2);
}
/* shell.js writes the daily cap here and leaves it EMPTY when there is none,
   so the line has to disappear on its own rather than leave a hole. */
.notice-cap {
  display: block;
  margin-top: 4px;
  font-family: var(--f-display);
  font-style: italic;
  font-size: 14px;
  color: var(--ink-3);
}
.notice-cap:empty { display: none; }
.notice .textlink { display: inline-block; margin-top: 14px; }

/* ── play ────────────────────────────────────────────────────────────────── */

.screen.play { overflow: hidden; padding: 0 18px 10px; }

.hud {
  flex: none;
  display: flex; align-items: baseline; gap: 14px;
  padding-top: calc(max(var(--tg-safe-top), env(safe-area-inset-top, 0px)) + 14px);
}
.hud-score { margin-right: auto; }
.hud-score .kicker { display: block; }
.hud-num {
  display: block;
  font-family: var(--f-display);
  font-size: 40px; font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
/* The clean-cut chain. It is a number in the margin, not a badge. */
.chain {
  font-family: var(--f-display);
  font-style: italic;
  font-size: 19px;
  color: var(--spot);
  opacity: 0;
  transition: opacity var(--t);
}
.chain.is-on { opacity: 1; }
.held {
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-2);
}
.hud-acts { display: flex; gap: 16px; flex: none; }
.hud-acts .textlink { font-size: 14px; }

.window { flex: none; margin-top: 18px; }
.window .kicker { display: block; }
.window .gauge { margin-top: 7px; }

/* The plate: the one dark surface in the app, set into the page like a
   full-bleed figure. 0 radius, a single ink hairline, no shadow. */
.plate {
  flex: 1; min-height: 0;
  position: relative;
  margin-top: 18px;
  border: 1px solid var(--ink);
  background: var(--bg);
}
#stage {
  display: block; width: 100%; height: 100%;
  background: var(--bg);
  touch-action: none;
}
.plate-cap {
  flex: none;
  margin-top: 9px;
  font-family: var(--f-display);
  font-style: italic;
  font-size: 13.5px;
  color: var(--ink-3);
}

/* The briefing sheet, on paper, laid over the plate until the run starts. */
.brief {
  position: absolute; inset: 0;
  background: var(--paper);
  display: flex; align-items: center;
  padding: 22px;
  overflow-y: auto;
}
.brief-in { width: 100%; max-width: 340px; margin: auto; }
.brief-h {
  font-family: var(--f-display);
  font-weight: 500; font-size: 27px;
  line-height: 1.15;
  margin-top: 6px;
}
.rules { margin-top: 18px; }
.rules li {
  padding: 12px 0;
  border-top: 1px solid var(--rule);
  font-size: 14.5px; line-height: 1.5;
  color: var(--ink-2);
  counter-increment: rule-n;
  position: relative;
  padding-left: 30px;
}
.rules li:last-child { border-bottom: 1px solid var(--rule); }
/* Hanging numerals in the left margin, the way a numbered list is set. */
.rules li::before {
  content: counter(rule-n) ".";
  position: absolute; left: 0; top: 12px;
  font-family: var(--f-display);
  font-size: 15px;
  color: var(--ink-3);
}
.rules { counter-reset: rule-n; }
.rules b { font-weight: 600; color: var(--ink); }
.brief .actions { margin-top: 20px; }

/* ── standings ───────────────────────────────────────────────────────────── */

.tabs {
  display: flex; gap: 26px;
  margin-top: 12px;
  border-bottom: 1px solid var(--rule);
}
.seg-btn {
  padding: 0 0 10px;
  font-family: var(--f-display);
  font-size: 19px; font-weight: 400;
  color: var(--ink-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--t), border-color var(--t);
}
.seg-btn.is-on { color: var(--ink); border-bottom-color: var(--ink); }

.board { margin-top: 14px; }
.rw {
  display: flex; align-items: baseline; gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
}
.rw-pos {
  min-width: 20px;
  font-family: var(--f-display);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
/* Icons are almost absent in this language, and an avatar disc is an icon. */
.rw-av { display: none; }
.rw-nm { flex: 1; min-width: 0; font-size: 15.5px; }
.rw-sc {
  font-family: var(--f-display);
  font-size: 19px; font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.rw--top .rw-pos { color: var(--ink); }
/* Your own line is marked in the margin, not filled in. */
.rw--me {
  border-left: 2px solid var(--spot);
  margin-left: -12px;
  padding-left: 10px;
}
.rw--me .rw-nm { font-weight: 600; }
.rw--me .rw-sc { color: var(--spot); }

/* ── more ────────────────────────────────────────────────────────────────── */

.prefs { margin-top: 12px; }
.pref {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--rule);
}
.pref span { flex: 1; min-width: 0; }

.sw {
  appearance: none; -webkit-appearance: none;
  flex: none; margin: 0; position: relative;
  width: 44px; height: 24px;
  border: 1px solid var(--ink);
  border-radius: 2px;
  background: var(--paper);
  transition: background var(--t);
}
.sw::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px;
  background: var(--ink);
  border-radius: 1px;
  transition: transform var(--t), background var(--t);
}
.sw:checked { background: var(--ink); }
.sw:checked::after { transform: translateX(20px); background: var(--paper); }

.index { margin-top: 12px; }
.index li { padding: 13px 0; border-bottom: 1px solid var(--rule); }

/* ── overlays ────────────────────────────────────────────────────────────── */

.scrim { position: fixed; inset: 0; z-index: 40; background: rgba(21, 20, 26, .58); }

.sheet {
  position: fixed; z-index: 50;
  left: 0; right: 0; bottom: 0;
  background: var(--paper);
  border-top: 1px solid var(--ink);
  display: flex; flex-direction: column;
  padding-bottom: max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px));
  max-height: calc(100dvh - max(var(--tg-safe-top), env(safe-area-inset-top, 0px)) - 40px);
  /* Deliberately NOT animated. A sheet that slides in from below sits, for the
     length of the animation, with its own Close control under the fold, and if
     a client throttles animations it stays there. The sheet just appears. */
}
.sheet-head {
  flex: none;
  padding: 20px var(--mg) 14px;
  border-bottom: 1px solid var(--ink);
  position: relative;
}
.sheet-title {
  font-family: var(--f-display);
  font-weight: 500; font-size: 25px;
  line-height: 1.15;
  margin-top: 4px;
  padding-right: 64px;
}
.sheet-x { position: absolute; right: var(--mg); bottom: 16px; font-size: 14px; }
.sheet-body {
  flex: 1; min-height: 0;
  overflow-y: auto;
  padding: 20px var(--mg) 4px;
  color: var(--ink-2);
}
.sheet-body p { margin-bottom: 16px; padding-right: var(--short); }
.sheet-body ul { margin-bottom: 16px; }
.sheet-body li {
  position: relative;
  padding: 0 var(--short) 12px 20px;
}
/* A printed bullet: a small square, sitting on the baseline of the first line. */
.sheet-body li::before {
  content: ""; position: absolute; left: 2px; top: 10px;
  width: 5px; height: 5px;
  background: var(--spot);
}
.sheet-body b { font-weight: 600; color: var(--ink); }
.sheet-foot {
  flex: none;
  padding: 14px var(--mg) 20px;
  border-top: 1px solid var(--rule);
}

.modal {
  position: fixed; inset: 0; z-index: 55;
  display: flex; align-items: center; justify-content: center;
  padding: 22px;
  pointer-events: none;
}
.card {
  pointer-events: auto;
  width: 100%; max-width: 330px;
  background: var(--paper);
  border: 1px solid var(--ink);
  padding: 24px 22px;
  animation: fade var(--t) ease-out;
}
.card-num {
  font-family: var(--f-display);
  font-size: 68px; font-weight: 400;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  margin-top: 10px;
}
.card-lbl {
  font-family: var(--f-display);
  font-style: italic;
  font-size: 17px;
  color: var(--ink-2);
  margin-top: 4px;
}
.card-sub {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--rule);
  font-size: 14px;
  color: var(--ink-2);
}
.card-h {
  font-family: var(--f-display);
  font-weight: 500; font-size: 26px;
  line-height: 1.15;
  margin-top: 8px;
}
.card-alt { display: inline-block; margin-top: 18px; }
/* The ad offer: a bordered notice that prints its reward and its free route
   before the tap, never a bright button. */
.card-ad {
  display: block; width: 100%;
  margin-top: 18px;
  padding: 14px;
  border: 1px solid var(--rule);
  border-radius: 2px;
  transition: border-color var(--t);
}
.card-ad:active { border-color: var(--ink); }
.card-ad b { display: block; font-size: 15px; font-weight: 600; }
.card-ad i {
  display: block;
  font-family: var(--f-display);
  font-size: 13.5px; line-height: 1.4;
  color: var(--ink-3);
  margin-top: 3px;
}
.card-ad i:empty { display: none; }

.revive {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: rgba(21, 20, 26, .62);
  pointer-events: none;
}
.revive span {
  font-family: var(--f-display);
  font-size: 140px; font-weight: 400;
  line-height: 1;
  color: var(--paper);
  font-variant-numeric: tabular-nums;
  animation: fade var(--t) ease-out;
}

.toast {
  position: fixed; z-index: 70;
  left: var(--mg); right: var(--mg);
  bottom: calc(92px + max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px)));
  background: var(--ink);
  color: var(--paper);
  border-radius: 2px;
  padding: 13px 18px;
  font-size: 14px;
  text-align: center;
}

/* ── reduce motion: kill all of it ───────────────────────────────────────── */

[data-reduce-motion="1"] *,
[data-reduce-motion="1"] *::before,
[data-reduce-motion="1"] *::after {
  animation: none !important;
  transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Short phones: the display sizes give first, the measure never does. */
@media (max-height: 690px) {
  .page { padding-top: 16px; }
  .head { font-size: 28px; }
  .standfirst { margin-top: 12px; }
  .hud-num { font-size: 34px; }
  .card-num { font-size: 56px; }
  .brief-h { font-size: 23px; }
  .rules li { padding-top: 9px; padding-bottom: 9px; }
}
