/* Love at First Bite -- browser preview.
   Warm, golden-hour, notebook-and-wood, per the design doc.

   This is the same design system as the desktop build's game/gui.rpy, in the
   other language: one panel treatment, one four-step spacing scale, one type
   scale of six roles, one card, one pair of buttons. The two builds share their
   story data and their rules engine already; they should not look like two
   different games, so a change to a token here has a counterpart there.

     tokens          :root, below                gui.rpy `lafb.*` + styles
     paper panel     .sheet                      lafb_paper_bg
     eyebrow label   .kicker / .sheet h2         style lafb_kicker / lafb_h2
     card            .card, .hub-opt             lafb_card_bg
     thermometer     .thermo, .stat-bar          screen lafb_thermometer
     buttons         .btn / .btn.ghost           lafb_paper_button / lafb_ghost */

:root {
  --wood-dark: #2b1d15;
  --wood: #4a3121;
  --wood-light: #6b4630;

  --paper: #efe3cd;
  --paper-card: #f3e8d1;
  --paper-card-hover: #fdf6e6;

  /* Dividers are translucent black, not a fixed cream: the paper texture in
     images/ is a good deal darker than --paper and swallowed a literal one. */
  --rule: rgba(0, 0, 0, .15);
  --rule-strong: rgba(0, 0, 0, .24);

  --ink: #2e241c;
  --ink-soft: #6b5c4b;
  --ink-faint: #8a7c68;
  --kicker: #8a7350;
  --heading: #8a6a3a;

  --brand: #7a3f1c;
  --brand-hover: #96501f;
  --ember: #e0762d;
  --ember-dim: #a8511c;
  --gold: #d9a441;
  --good: #6d8c47;
  --bad: #b8503f;
  --rival: #5b7fbd;
  --romance: #c94f4f;
  --respect: #b98b2e;

  /* Vertical rhythm. Four steps, used everywhere. */
  --gap-xs: 6px;
  --gap-s: 12px;
  --gap-m: 22px;
  --gap-l: 34px;

  --shadow: 0 18px 48px rgba(0, 0, 0, .45);
  --font: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --ui-font: "Avenir Next", "Segoe UI", system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: #17100c;
  color: var(--paper);
  font-family: var(--font);
  overflow: hidden;
}

button { font: inherit; cursor: pointer; }
button:disabled { cursor: not-allowed; }

#app {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* The eyebrow label: small, letterspaced, upper case. Every block of content
   on paper is introduced by one, which is most of what makes the panels read
   as one interface rather than six. */
.kicker,
.sheet h2,
.hud-label,
.axis,
#choice-prompt,
#continue,
#title .tag,
#ending-card .kicker {
  font-family: var(--ui-font);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}

/* -- backdrop ------------------------------------------------------------ */

#backdrop {
  position: absolute;
  inset: 0;
  transition: background 900ms ease;
  background: linear-gradient(170deg, #c9a227 0%, #a5701f 55%, #4a3121 100%);
}

#backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 120%, rgba(0, 0, 0, .55), transparent 60%),
    radial-gradient(ellipse at 20% -10%, rgba(255, 220, 150, .28), transparent 55%);
  pointer-events: none;
}

.smoke {
  position: absolute;
  left: -30%;
  width: 160%;
  height: 34%;
  pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(255, 255, 255, .07), transparent 68%);
  filter: blur(14px);
  animation: drift linear infinite;
}
.smoke.a { top: 12%; animation-duration: 64s; }
.smoke.b { top: 34%; animation-duration: 91s; opacity: .7; }
.smoke.c { top: 2%;  animation-duration: 47s; opacity: .5; }

@keyframes drift {
  from { transform: translateX(-18%) translateY(0); }
  50%  { transform: translateX(10%) translateY(-14px); }
  to   { transform: translateX(-18%) translateY(0); }
}

#location-tag {
  position: absolute;
  left: 26px;
  bottom: 300px;
  font-family: var(--ui-font);
  font-size: 12px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
  text-shadow: 0 2px 8px rgba(0, 0, 0, .6);
}

/* -- sprite -------------------------------------------------------------- */

#sprite {
  position: absolute;
  right: 7%;
  bottom: 264px;
  width: 300px;
  /* Never taller than the room left above the dialogue box. A fixed height
     plus a fixed offset from the bottom runs off the top of a short window --
     a laptop with a bookmarks bar has around 640px of viewport, and the
     character was being beheaded by it. `dvh` where it is understood, so a
     phone's collapsing address bar does not reintroduce the same bug. */
  height: min(430px, calc(100vh - 330px));
  height: min(430px, calc(100dvh - 330px));
  border-radius: 10px 10px 0 0;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .35s ease, transform .35s ease, background .35s ease;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 22px;
}
#sprite.on { opacity: 1; transform: translateY(0); }
#sprite .sprite-name {
  font-family: var(--ui-font);
  font-weight: 700;
  font-size: 20px;
  color: rgba(255, 255, 255, .95);
  letter-spacing: .02em;
}
#sprite .sprite-emo {
  font-family: var(--ui-font);
  font-size: 12px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
  margin-top: 4px;
}
#sprite .sprite-note {
  margin-top: auto;
  font-size: 12px;
  font-family: var(--ui-font);
  color: rgba(255, 255, 255, .45);
}

/* -- HUD ----------------------------------------------------------------- */

#hud {
  position: absolute;
  top: 18px;
  left: 18px;
  display: flex;
  gap: 10px;
  align-items: stretch;
  font-family: var(--ui-font);
  z-index: 6;
}

.hud-card {
  background: rgba(43, 29, 21, .84);
  border: 1px solid rgba(224, 118, 45, .3);
  border-left: 3px solid var(--ember-dim);
  border-radius: 8px;
  padding: 9px 14px;
  backdrop-filter: blur(6px);
}
.hud-label {
  font-size: 10px;
  color: rgba(240, 226, 200, .52);
}
.hud-value { font-size: 17px; font-weight: 600; color: var(--paper); }

/* The thermometer the readme asks for: a mercury column with a bulb. Same
   shape as screen lafb_thermometer in the desktop build, and the bulb sits
   inside the box rather than hanging off its left edge. */
.thermo {
  position: relative;
  width: 128px;
  height: 10px;
  margin: 8px 0 1px 15px;
  background: rgba(0, 0, 0, .42);
  border-radius: 5px;
}
.thermo::before {
  content: "";
  position: absolute;
  left: -15px;
  top: 50%;
  width: 13px;
  height: 13px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: var(--therm, var(--ember));
}
.thermo i {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--therm, var(--ember));
  border-radius: 5px;
  transition: width .4s ease;
}

#hud-buttons { margin-left: auto; }

.icon-btn {
  background: rgba(43, 29, 21, .84);
  border: 1px solid rgba(224, 118, 45, .3);
  color: var(--paper);
  border-radius: 8px;
  padding: 10px 15px;
  font-family: var(--ui-font);
  font-size: 13px;
  transition: background .18s ease, border-color .18s ease;
}
.icon-btn:hover { background: rgba(107, 70, 48, .95); border-color: var(--ember); }
/* Muted reads as off rather than as disabled: still the same button, still
   the first thing you look for when you want it back. */
.icon-btn.off { color: rgba(240, 226, 200, .42); border-color: rgba(224, 118, 45, .14); }

#actions {
  position: absolute;
  top: 18px;
  right: 18px;
  display: flex;
  gap: 8px;
  z-index: 6;
}

/* #rail wraps #actions and #hud. Both of those are absolutely positioned here,
   so on a desktop window the wrapper draws nothing and measures nothing -- it
   only starts doing work at phone widths, where it becomes the left column
   (see "phone rail"). */

/* -- dialogue ------------------------------------------------------------ */

#dialogue {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  min-height: 250px;
  background:
    linear-gradient(180deg, rgba(23, 16, 12, .0), rgba(23, 16, 12, .93) 16%, rgba(23, 16, 12, .97) 100%),
    url("images/ui_wood_dark.webp") repeat;
  background-color: #17100c;
  background-size: auto, 256px 256px;
  padding: 44px 8% 34px;
  cursor: pointer;
  z-index: 5;
}
#dialogue::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 40px;
  height: 2px;
  background: linear-gradient(90deg, transparent, rgba(224, 118, 45, .5), transparent);
}
#speaker {
  font-family: var(--ui-font);
  font-weight: 700;
  font-size: 21px;
  letter-spacing: .01em;
  margin-bottom: 10px;
  min-height: 26px;
}
#line {
  font-size: 25px;
  line-height: 1.55;
  max-width: 1100px;
  color: #f3ead9;
  white-space: pre-wrap;
}
#continue {
  position: absolute;
  right: 8%;
  bottom: 20px;
  font-size: 11px;
  color: rgba(240, 226, 200, .38);
  animation: pulse 1.9s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: .35; } 50% { opacity: .85; } }

/* -- choices ------------------------------------------------------------- */

#choices {
  /* Centred, over a scrim that stops above the dialogue box -- so the line
     that prompted the choice stays readable underneath it.

     An earlier version pushed this into a left band to keep it off the
     character. That trades one problem for a worse one: off-centre buttons
     over full-bleed art read as a layout bug, and the contrast still depends
     on whatever happens to be painted behind them. Dimming the scene instead
     is the standard visual-novel move, and it reads as deliberate. */
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 232px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gap-s);
  padding: 24px 6%;
  z-index: 7;
  background: linear-gradient(to bottom,
              rgba(10, 7, 5, .59) 0%, rgba(10, 7, 5, .76) 62%, rgba(10, 7, 5, .81) 100%);
}
/* One column width for the prompt and every button, so their left edges line
   up regardless of how long the option text is. */
#choices > * { width: min(720px, 100%); }

/* A prompt with one field. Sized to its content rather than to the widest
   sheet in the game, and its actions centred instead of hugging the left. */
.sheet.narrow { width: min(560px, 100%); text-align: center; }
.sheet.narrow h1 { text-align: center; }
.sheet.narrow input { text-align: center; }
.sheet.narrow .row-actions { justify-content: center; }
.sheet input[type="text"] {
  width: 100%;
  margin: 18px 0 4px;
  padding: 12px;
  font-family: inherit;
  font-size: 24px;
  color: var(--brand);
  background: transparent;
  border: 0;
  border-bottom: 2px solid var(--rule-strong);
  outline: none;
}
.sheet input[type="text"]:focus { border-bottom-color: var(--ember-dim); }
#choice-prompt {
  font-size: 12px;
  color: rgba(255, 255, 255, .72);
  text-align: center;
  margin-bottom: 4px;
  text-shadow: 0 2px 10px #000;
}
.choice {
  display: block;
  width: 100%;
  text-align: left;
  /* Near-opaque. Below about 90% the option text reads over whatever the scene
     happens to be painting behind it, which on a bright background is exactly
     where a choice is hardest to read. */
  background: rgba(38, 25, 18, .95);
  border: 1px solid rgba(224, 118, 45, .22);
  border-left: 4px solid var(--ember-dim);
  color: #e9dcc6;
  border-radius: 7px;
  padding: 17px 22px;
  font-size: 19px;
  line-height: 1.4;
  transition: transform .14s ease, background .14s ease, border-color .14s ease;
  box-shadow: var(--shadow);
}
.choice:hover:not(:disabled) {
  background: rgba(107, 70, 48, .96);
  border-left-color: var(--ember);
  transform: translateX(6px);
}
.choice:disabled { opacity: .42; border-left-color: #55483c; }
.choice .note {
  display: block;
  font-family: var(--ui-font);
  font-size: 12.5px;
  color: rgba(240, 226, 200, .5);
  margin-top: 5px;
}
.choice .cost {
  float: right;
  font-family: var(--ui-font);
  font-size: 12px;
  color: var(--gold);
}

/* -- paper panels (hub, journal, judging, ending) ------------------------ */

.overlay {
  position: absolute;
  inset: 0;
  background: rgba(12, 8, 6, .74);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 26px;
  z-index: 10;
  backdrop-filter: blur(3px);
}

.sheet {
  /* images/ui_paper.webp is a seamless 256px tile, so it repeats at its own
     size -- stretching it to the panel smears the ruled lines into bands. The
     colour underneath is what shows if the art folder is not there. */
  background-color: var(--paper);
  background-image: url("images/ui_paper.webp");
  background-repeat: repeat;
  background-size: 256px 256px;
  color: var(--ink);
  box-shadow: var(--shadow);
  width: min(1120px, 100%);
  max-height: 100%;
  overflow: auto;
  padding: 30px 40px 34px;
  position: relative;

  /* The ember cap every panel in both builds shares. A real top border rather
     than a ::before, so it cannot scroll away with the content on a long
     journal -- which is the one panel that always scrolls. */
  border: 0 solid transparent;
  border-top-width: 5px;
  border-image: linear-gradient(90deg,
      var(--ember-dim), var(--ember) 35%, var(--gold) 72%, var(--ember-dim)) 1;
  border-radius: 0 0 6px 6px;
}

.sheet h1 {
  font-size: 30px;
  margin: 0 0 2px;
  color: var(--brand);
  line-height: 1.15;
}
.sheet h2 {
  font-size: 12px;
  color: var(--heading);
  margin: var(--gap-l) 0 var(--gap-s);
  border-bottom: 2px solid var(--rule);
  padding-bottom: 6px;
}
.sheet .sub {
  font-family: var(--ui-font);
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 6px;
}

.sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 20px;
  border-bottom: 2px solid var(--rule-strong);
  padding-bottom: var(--gap-s);
}

/* A number with its label above it: the readouts along the top of a panel,
   and the same shape as screen lafb_readout in the desktop build. */
.clock {
  text-align: right;
  font-family: var(--ui-font);
  flex: none;
}
.clock .big {
  font-size: 24px;
  font-weight: 700;
  color: var(--brand);
  line-height: 1.2;
}
.clock .thermo {
  background: rgba(0, 0, 0, .16);
  width: 180px;
  margin-left: auto;
  --therm: var(--ember-dim);
}
.clock .thermo::before { left: auto; right: 100%; margin-right: 2px; }

/* hub options */
.hub-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  /* Equal rows, so a one-line option and a three-line one still make a grid
     rather than a ragged wall. */
  grid-auto-rows: 1fr;
  gap: var(--gap-s);
  margin-top: var(--gap-m);
}

/* One card, used by the hub, the galleries and anything else that is a
   pressable block on paper. Live cards are lighter than the page and dead ones
   darker, so the difference survives whatever the paper is doing underneath. */
.hub-opt {
  display: flex;
  flex-direction: column;
  min-height: 92px;
  text-align: left;
  background: var(--paper-card);
  border: 1px solid var(--rule);
  border-left: 4px solid var(--ember-dim);
  border-radius: 5px;
  padding: 14px 16px;
  color: var(--ink);
  transition: transform .14s ease, background .14s ease, border-color .14s ease;
}
.hub-opt:hover:not(:disabled) {
  background: var(--paper-card-hover);
  border-left-color: var(--ember);
  transform: translateY(-2px);
}
.hub-opt:disabled {
  background: rgba(0, 0, 0, .06);
  border-left-color: rgba(107, 92, 75, .4);
  color: var(--ink-faint);
}
.hub-opt .t {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.25;
}
.hub-opt .t span:last-child {
  font-family: var(--ui-font);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--heading);
  white-space: nowrap;
}
.hub-opt .d {
  font-family: var(--ui-font);
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-top: 5px;
  line-height: 1.4;
}
.hub-opt .v {
  font-family: var(--ui-font);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: auto;
  padding-top: 6px;
}

.row-actions {
  display: flex;
  gap: 10px;
  margin-top: var(--gap-l);
  flex-wrap: wrap;
}

/* One primary action per panel, the rest ghosted. A row of identical slabs
   tells the player nothing about which one is the way forward. */
.btn {
  background: var(--brand);
  color: #f6ecd8;
  border: 1px solid var(--brand);
  border-radius: 5px;
  padding: 12px 22px;
  font-family: var(--ui-font);
  font-size: 14px;
  font-weight: 700;
  transition: background .16s ease, border-color .16s ease;
}
.btn:hover:not(:disabled) { background: var(--brand-hover); border-color: var(--brand-hover); }
.btn:disabled { background: #b6a894; border-color: #b6a894; }
.btn.ghost {
  background: transparent;
  color: var(--brand);
  border: 1px solid var(--rule-strong);
  font-weight: 600;
}
.btn.ghost:hover { background: var(--paper-card); border-color: var(--ember-dim); }

/* -- journal ------------------------------------------------------------- */

.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; }
.cols3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }

/* label | thermometer | value, on a fixed grid -- so every bar in the column
   starts and ends at the same x no matter how long its label is. */
.stat-row {
  display: grid;
  grid-template-columns: 132px minmax(80px, 1fr) 30px;
  align-items: center;
  gap: 14px;
  font-family: var(--ui-font);
  font-size: 13px;
  margin-bottom: 7px;
  color: var(--ink);
}
.stat-row > span:last-child {
  text-align: right;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.stat-bar {
  position: relative;
  height: 10px;
  margin-left: 15px;
  background: rgba(0, 0, 0, .16);
  border-radius: 5px;
}
.stat-bar::before {
  content: "";
  position: absolute;
  right: 100%;
  margin-right: 2px;
  top: 50%;
  width: 13px;
  height: 13px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: var(--therm, var(--ember));
}
.stat-bar i {
  display: block;
  height: 100%;
  border-radius: 5px;
  background: var(--therm, var(--ember));
}

/* One person: who they are on the left, the four axes in fixed columns on the
   right, so the axes line up down the page instead of reflowing per name.
   Placed explicitly -- the name and the blurb stack into one cell, and with
   only `grid-template-columns` they take a column each and shove the axes onto
   their own row. */
.person {
  display: grid;
  grid-template-columns: minmax(180px, 320px) 1fr;
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: 32px;
  border-bottom: 1px solid var(--rule);
  padding: 12px 0;
}
.person .nm { grid-column: 1; grid-row: 1; font-size: 17px; font-weight: 700; }
.person .bl { grid-column: 1; grid-row: 2; }
.person .axes { grid-column: 2; grid-row: 1 / span 2; }
.person .bl {
  font-family: var(--ui-font);
  font-size: 11.5px;
  color: var(--ink-faint);
  line-height: 1.45;
}
.axes {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin: 0;
}
.axis { font-size: 10px; color: var(--kicker); }
.pips { display: flex; gap: 3px; margin-top: 5px; }
.pip { width: 12px; height: 12px; border-radius: 2px; background: rgba(0, 0, 0, .14); }

.taglist { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  font-family: var(--ui-font);
  font-size: 11.5px;
  background: rgba(0, 0, 0, .06);
  border: 1px solid var(--rule);
  border-radius: 20px;
  padding: 4px 11px;
  color: var(--ink-faint);
}
.tag.on {
  background: var(--brand);
  color: #f6ecd8;
  border-color: var(--brand);
}

/* -- scorecard ----------------------------------------------------------- */

.card-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--ui-font);
  font-variant-numeric: tabular-nums;
  margin-top: var(--gap-m);
}
.card-table th {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--kicker);
  text-align: right;
  padding: 7px 6px;
  border-bottom: 2px solid var(--rule-strong);
}
.card-table th:first-child, .card-table td:first-child { text-align: left; }
.card-table th:last-child, .card-table td:last-child { width: 90px; }
.card-table td {
  padding: 11px 6px;
  font-size: 18px;
  text-align: right;
  border-bottom: 1px solid var(--rule);
}
.card-table tr.hidden td { color: var(--ink-faint); }
.card-table tr.dropped td { color: var(--ink-faint); text-decoration: line-through; }
/* The "dropped" note is a label, not a score, and must not be struck through
   along with the row it labels -- so it has to out-specify `tr.dropped td`. */
.card-table tbody td:last-child {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-decoration: none;
}
.card-table td.flip { animation: flip .34s ease; }
@keyframes flip {
  from { opacity: 0; transform: translateY(-7px) rotateX(60deg); }
  to   { opacity: 1; transform: none; }
}

.total-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: var(--gap-s);
  padding-top: var(--gap-s);
  border-top: 2px solid var(--rule-strong);
}
.total-row .sub {
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--kicker);
  margin: 0;
}
.total-row .big {
  font-family: var(--ui-font);
  font-size: 42px;
  font-weight: 700;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.dq { text-align: center; padding: 40px 0; }
.dq .big {
  font-size: 46px;
  letter-spacing: .06em;
  color: var(--bad);
  font-weight: 700;
  text-transform: uppercase;
}

.standings {
  max-height: 340px;
  overflow: auto;
  font-family: var(--ui-font);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.standing {
  display: grid;
  grid-template-columns: 56px 1fr 84px;
  gap: 8px;
  align-items: center;
  padding: 7px 8px;
  border-bottom: 1px solid var(--rule);
  border-radius: 3px;
}
.standing span:first-child { color: var(--ink-faint); }
.standing span:last-child { text-align: right; color: var(--ink-faint); }
/* Your own line, which is the one line the screen exists to show you. */
.standing.me {
  background: rgba(122, 63, 28, .13);
  font-weight: 700;
  color: var(--brand);
}
.standing.me span:first-child,
.standing.me span:last-child { color: var(--brand); }

/* -- minigames ----------------------------------------------------------- */

.track {
  position: relative;
  height: 40px;
  background: rgba(0, 0, 0, .14);
  border-radius: 5px;
  margin: var(--gap-m) 0 6px;
  overflow: hidden;
}
.zone { position: absolute; top: 0; bottom: 0; background: #9dbb7a; }
.zone.core { background: #5d7a44; }
.marker {
  position: absolute;
  top: -6px;
  width: 5px;
  height: 52px;
  background: var(--brand);
  border-radius: 3px;
  box-shadow: 0 0 10px rgba(122, 63, 28, .6);
}
.scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--ui-font);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--kicker);
}
.readout {
  display: flex;
  gap: 48px;
  margin: var(--gap-m) 0;
  font-family: var(--ui-font);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--kicker);
}
.readout b {
  font-size: 24px;
  color: var(--brand);
  display: block;
  letter-spacing: normal;
  text-transform: none;
  margin-top: 2px;
}
.verdict { font-size: 21px; font-weight: 700; min-height: 28px; color: var(--brand); }
.pickgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 9px; margin: var(--gap-m) 0; }
.pick {
  background: var(--paper-card);
  border: 1px solid var(--rule);
  border-left: 4px solid var(--ember-dim);
  border-radius: 5px;
  padding: 12px 14px;
  color: var(--ink);
  font-size: 15px;
  text-align: left;
}
.pick:hover { background: var(--paper-card-hover); }
.pick.on { background: var(--brand); color: #f6ecd8; border-color: var(--brand); border-left-color: var(--ember); }

.stars { font-size: 30px; letter-spacing: 6px; color: var(--gold); }

/* -- ending -------------------------------------------------------------- */

#ending-card {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 9%;
  transition: background 1s ease;
}
#ending-card .kicker {
  font-size: 12px;
  letter-spacing: .34em;
  opacity: .9;
}
#ending-card h1 {
  font-size: clamp(38px, 6.4vw, 84px);
  margin: 10px 0 0;
  line-height: 1.04;
  color: #f4ecdd;
}
#ending-card .rule { width: 200px; height: 5px; margin-top: 20px; }

/* -- toasts -------------------------------------------------------------- */

#toasts {
  position: absolute;
  top: 74px;
  right: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 20;
  pointer-events: none;
  align-items: flex-end;
}
.toast {
  background: rgba(43, 29, 21, .95);
  border: 1px solid rgba(224, 118, 45, .45);
  border-left: 4px solid var(--ember);
  border-radius: 7px;
  padding: 11px 16px;
  font-family: var(--ui-font);
  font-size: 13px;
  color: #f0d9b5;
  max-width: 330px;
  box-shadow: var(--shadow);
  animation: toast-in .3s ease;
}
.toast.ach { border-color: var(--gold); border-left-color: var(--gold); color: var(--gold); }
@keyframes toast-in {
  from { opacity: 0; transform: translateX(26px); }
  to { opacity: 1; transform: none; }
}

.hide { display: none !important; }

/* -- title --------------------------------------------------------------- */

#title {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 9%;
  background: radial-gradient(ellipse at 25% 20%, #6b4630, #17100c 70%);
}
#title h1 {
  font-size: clamp(44px, 8.5vw, 108px);
  line-height: .96;
  margin: 0;
  letter-spacing: -.01em;
}
#title .tag {
  background: none;
  border: none;
  padding: 0;
  font-size: 14px;
  color: var(--gold);
  margin-top: 20px;
}
/* The maker's credit, matching style lafb_byline on the Ren'Py title screen.
   Mixed case and dimmer than the gold tagline above it on purpose -- stacking
   a second letterspaced capital line reads as two competing taglines, and this
   is a signature rather than a pitch. Unlike .note it survives the narrow
   breakpoint: a credit that disappears on a phone is not a credit. */
#title .byline {
  font-family: var(--ui-font);
  font-size: 13px;
  color: rgba(240, 226, 200, .52);
  margin-top: 9px;
}
#title .rule { width: 220px; height: 5px; background: var(--ember); margin: 22px 0; }
#title .menu { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
#title .note {
  position: absolute;
  bottom: 26px;
  font-family: var(--ui-font);
  font-size: 12px;
  color: rgba(240, 226, 200, .38);
  max-width: 620px;
  line-height: 1.6;
  /* Decorative. On a short screen it lands on top of the New Game button, and
     a paragraph of grey text should never be able to eat a tap. */
  pointer-events: none;
}

@media (max-width: 720px) {
  #dialogue { padding: 34px 5% 30px; }
  #line { font-size: 20px; }
  /* Options stack up off the dialogue box instead of sitting in the middle of
     the screen. Centred, a three-option list landed across the middle of the
     rail below and hid the Time and Cash cards behind two strips of butcher
     paper. `margin-top: auto` on the first row rather than
     `justify-content: flex-end`, because a list long enough to scroll cannot
     be reached at the top when a flex column is end-justified -- and an auto
     margin collapses to nothing in exactly that case. */
  #choices { padding: 18px 5%; bottom: 200px; overflow-y: auto; }
  #choices > :first-child { margin-top: auto; }
  .cols, .cols3 { grid-template-columns: 1fr; gap: var(--gap-m); }
  .sheet { padding: 22px 20px 26px; }

  /* The four axes cannot hold a column each at this width, and the name column
     stops earning its place once the row has to stack anyway. */
  .person { grid-template-columns: 1fr; row-gap: 8px; }
  .person .axes { grid-column: 1; grid-row: 3; }
  .axes { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* "click or press space" is wrong on a phone and lands on the last line of
     dialogue at these widths. Tapping is self-evident. */
  #continue { display: none; }

  /* -- phone rail --------------------------------------------------------
     The clock cards and the three buttons cannot share a row this narrow --
     they were overlapping by 200px, with the cash card behind the Title
     button. Stacking them (buttons in the corner, cards underneath) stopped
     them fighting each other but not the game: a phone shows the character
     from about x 94 rightwards (#sprite below), so a band across the top of
     the screen lands squarely across their face.

     So both blocks come down the left edge instead, in one narrow column. It
     is the only strip of a portrait screen nothing else wants: the character
     bleeds off the right, the dialogue box owns the bottom, and the choice
     list is centred over a scrim that dims the rail along with the scene.

     #rail does the stacking rather than a hard-coded `top` on #hud, so the
     buttons keep their place when the Cycle card appears on a second loop. */
  #rail {
    position: absolute;
    top: 12px;
    left: 12px;
    width: 104px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: 6;
  }
  #rail > #actions, #rail > #hud {
    position: static;
    flex-direction: column;
  }
  /* Four buttons and up to four cards have to fit above the dialogue box on a
     640px-tall phone, which is the shortest screen this layout still shows a
     character on. The buttons are what give: they are a fixed count, so every
     pixel taken off one is four off the column. */
  #rail > #actions { gap: 5px; }
  #rail > #hud { gap: 6px; }

  .icon-btn {
    font-size: 11px;
    line-height: 1;
    padding: 8px 10px;
    text-align: left;
  }
  /* Nothing to press it with. */
  .icon-btn .key { display: none; }

  .hud-card { padding: 6px 9px; }
  .hud-label { font-size: 9px; letter-spacing: .14em; }
  .hud-value { font-size: 14px; }
  /* The bulb hangs 15px into the card's padding box, so the column is what is
     left of the rail once both are paid for. */
  .thermo { width: 58px; height: 8px; margin: 6px 0 1px 15px; }

  /* The caption used to float 300px off the bottom on the left, which on a
     phone is the middle of the rail -- the last card landed on top of it, and
     on a New Game+ run the Cycle card made that certain. The other side, just
     above the dialogue box, is clear of the rail at every card count and still
     reads as a caption on the scene. */
  #location-tag {
    left: auto;
    right: 12px;
    bottom: 262px;
    font-size: 11px;
    text-align: right;
  }
}

/* A phone on its side has about 140px above the dialogue box: no room for a
   figure, and the title screen's centred menu collides with its own footnote. */
@media (max-height: 480px) {
  #sprite { display: none !important; }

  /* Which is also why the left rail unwinds here: with no figure on screen
     there is nobody for a row across the top to cover, and a column of cards
     down a 390px-tall window would reach the dialogue box. Back to corners. */
  #rail { position: static; }
  #rail > #hud {
    position: absolute;
    top: 12px;
    left: 12px;
    flex-direction: row;
  }
  #rail > #actions {
    position: absolute;
    top: 12px;
    right: 12px;
    left: auto;
    flex-direction: row;
  }

  #title h1 { font-size: clamp(30px, 7vw, 54px); }
  #title .rule { margin: 12px 0; }
  #title .tag { margin-top: 10px; }
  #title .menu { margin-top: 14px; }
  #title .note { display: none; }

  /* Three options plus a full-height dialogue box do not fit in 390px, and the
     third one was landing below the fold with nothing to tell you it was there.
     Give the text less room, the options less padding, and let the column
     scroll if a hub ever offers more of them than the screen can hold. */
  #dialogue { min-height: 150px; padding: 20px 6% 16px; }
  #line { font-size: 17px; line-height: 1.42; }
  #speaker { font-size: 17px; margin-bottom: 6px; min-height: 0; }
  #choices {
    bottom: 156px;
    padding: 10px 5%;
    gap: 7px;
    overflow-y: auto;
    justify-content: flex-start;
  }
  .choice { padding: 9px 14px; font-size: 15px; }
  .choice .note { font-size: 11px; margin-top: 2px; }
  #choice-prompt { font-size: 12px; margin-bottom: 2px; }
}

/* -- real artwork -------------------------------------------------------
   Applied only once an image has actually loaded (see withArt in engine.js),
   so the placeholder slab is never left showing through a transparent cut-out. */

#sprite.art {
  width: min(460px, 34vw);
  /* Same reasoning as the placeholder above, with room left for the buttons
     in the top right rather than only for the dialogue box below. */
  height: min(700px, calc(100vh - 300px));
  height: min(700px, calc(100dvh - 300px));
  right: 5%;
  bottom: 236px;
  padding: 0;
  border-radius: 0;
  box-shadow: none;
  background-color: transparent !important;
  background-size: contain;
  background-position: bottom center;
  background-repeat: no-repeat;
  filter: drop-shadow(0 18px 34px rgba(0, 0, 0, .55));
}

#sprite.art .sprite-name,
#sprite.art .sprite-emo,
#sprite.art .sprite-note { display: none; }

#title.art {
  background-size: cover;
  background-position: center;
}

/* Phones get the characters too. They were hidden outright, which on the most
   likely device to be handed the link meant a visual novel with nobody in it.
   A portrait phone is narrower than a sprite is wide, so the figure is sized by
   the room above the dialogue box and allowed to bleed off the right edge --
   which is what a phone visual novel does anyway. */
@media (max-width: 720px) {
  #sprite {
    width: min(300px, 66vw);
    height: min(430px, calc(100vh - 300px));
    height: min(430px, calc(100dvh - 300px));
    right: 4%;
    bottom: 232px;
  }
  #sprite.art {
    width: min(330px, 78vw);
    height: min(560px, calc(100vh - 290px));
    height: min(560px, calc(100dvh - 290px));
    right: -2%;
    bottom: 210px;
  }
  /* The scrim over the choices already dims the scene; drop the sprite a little
     further so long option text never fights the character's face. */
  #choices { background: linear-gradient(to bottom,
             rgba(10, 7, 5, .62) 0%, rgba(10, 7, 5, .84) 55%, rgba(10, 7, 5, .89) 100%); }
}

/* -- ?diag overlay ------------------------------------------------------- */

#diag {
  position: fixed;
  inset: 0;
  z-index: 900;
  overflow: auto;
  padding: 32px clamp(16px, 5vw, 64px) 48px;
  background: #140e0a;
  color: #e8dccb;
  font: 13px/1.55 ui-monospace, "Cascadia Code", Consolas, monospace;
}
#diag h2 {
  margin: 0 0 4px;
  font: 600 22px/1.3 var(--font-display, Georgia, serif);
  color: #e0762d;
}
#diag .diag-note { margin: 4px 0 18px; color: #9a8b79; }
#diag code { color: #c9b79f; }
.diag-row {
  display: grid;
  grid-template-columns: 18px minmax(0, 22em) 1fr;
  gap: 10px;
  align-items: baseline;
  padding: 3px 0;
  border-bottom: 1px solid #241a13;
}
.diag-row.good .diag-dot { color: #6fbf5f; }
.diag-row.bad  .diag-dot { color: #d8523f; }
.diag-row.bad  code      { color: #e8907f; }
.diag-msg { color: #9a8b79; }
#diag-verdict {
  margin: 20px 0 0;
  padding: 14px 16px;
  border-radius: 8px;
  max-width: 70ch;
  line-height: 1.6;
}
#diag-verdict.good { background: #1b2a17; border: 1px solid #3c5c33; color: #cde5c4; }
#diag-verdict.bad  { background: #2c1512; border: 1px solid #6b2b22; color: #f0c9c1; }
