/*
 * Six themes, one stylesheet. `data-game` on <html> selects a variable block.
 *
 * Constraints this file is written against, all of them load-bearing:
 *
 *  - OBS 30.x ships Chromium 103. No :has() (105), no container queries (105),
 *    no oklch()/color-mix() (111), no CSS nesting (112), no unprefixed `mask`
 *    shorthand (120).
 *  - Twitch transcodes to 720p60 with 4:2:0 chroma subsampling, so contrast has
 *    to live in LUMA. Every colour below is annotated with its Rec.709 Y'
 *    (0-255); test/palette.test.js re-derives each annotation and holds the
 *    pairs that matter to a minimum delta. Hue differences smear; luma
 *    differences survive.
 *  - No 1px lines anywhere - they alias into a crawling shimmer. 2px minimum,
 *    3px for anything that must stay crisp.
 *  - Only transform and opacity animate. Never filter, box-shadow, or
 *    background-position.
 *
 * The six games differ in structure, motion and value rather than hue alone,
 * because that is what survives the encode:
 *
 *   III cuts - Vice City flickers - San Andreas bounces - IV dissolves - V wipes
 *
 * and VI, a plain timer until its missions are known, is a sunset.
 *
 * Faces come from fonts.css (generated by fonts/make-embed.py). Pricedown is
 * embedded with its author's permission; see the README.
 */

:root {
  --font-text: "GT Text", "Barlow", "Segoe UI", system-ui, sans-serif;
  --font-pass: "GT Pricedown", "Pricedown Bl", Impact, sans-serif;

  --pad: 18px;
  --w: 640px;            /* set from ?w= by the page */
  --track-h: 22px;
  --dw: .56em;           /* run-clock digit cell, per face */
  --cw: .30em;           /* run-clock colon cell */
}

/* ------------------------------------------------------------- GTA III --- */
/*
 * Liberty City, 2001: bone on soot, one block of Liberty red. Hard edges, heavy
 * grain, and nothing eases - every change is a cut.
 */
[data-game="gta3"] {
  --panel:    #131416;   /* Y20  */
  --panel-rgb: 19, 20, 22;
  --track:    #33363A;   /* Y54  */
  --fill:     #BEB9AE;   /* Y185 - D131 against the track */
  --head:     #FFFFFF;   /* Y255 - D70 against the fill */
  --cap:      #A3A8AD;   /* Y167 - D147 against the panel */
  --keyline:  #4A4E53;   /* Y78  - D58 */
  --text-1:   #F2F0EA;   /* Y240 - D220 */
  --text-2:   #A7A9AB;   /* Y169 - D149 */
  --accent:   #F2F0EA;   /* Y240 - D220 */
  --numeral:  #F4F1EA;   /* Y241 - D180 against the red under it */
  --on-numeral: #A3221B; /* Y61  */
  --pass:     #F2F0EA;   /* Y240 - D220 */
  --pass-edge: #A3221B;  /* Y61  */

  --fill-bg: var(--fill);
  --font-mark: var(--font-pass);
  --font-name: var(--font-pass);
  --font-clock: var(--font-pass);
  --mark-size: 30px;
  --name-size: 44px;
  --name-min: 26px;
  --name-wrap: 25px;
  --name-case: uppercase;
  --ls-name: .03em;
  --ls-tight: 0em;
  --ls-2: .22em;
  --radius: 0;
  --radius-sm: 0;
  --move: 240ms steps(3, end);
  --fade-out: 0ms;       /* cut */
  --fade-in: 0ms;
  --name-in: none;
  --pass-ms: 2400;
  --pass-anim: pass-cut 2400ms linear both;
  --log-in: none;
  --grain-a: .10;
  --vignette: radial-gradient(130% 150% at 50% 35%, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, .55) 100%);
}

/* ---------------------------------------------------------- Vice City ---- */
/*
 * 1986: hot pink and teal on a violet night. A brush script for the names, a
 * static neon glow, and changes that FLICKER in like a tube catching. No
 * scanlines: a 4px pitch becomes 2.67px at 720p and beats into moire.
 */
[data-game="gtavc"] {
  --panel:    #140A1E;   /* Y14  */
  --panel-rgb: 20, 10, 30;
  --track:    #33264A;   /* Y43  */
  --fill:     #FF6EB4;   /* Y146 - D103 against the track */
  --head:     #FFF0FA;   /* Y244 - D98 against the fill */
  --cap:      #3FE0D0;   /* Y189 - D175 */
  --keyline:  #FF6EB4;   /* Y146 - D132 */
  --keyline-2: #3FE0D0;  /* Y189 - D175 */
  --text-1:   #FFF4FB;   /* Y247 - D233 */
  --text-2:   #7FE9DF;   /* Y210 - D196 */
  --accent:   #FF6EB4;   /* Y146 - D132 */
  --numeral:  #140A1E;   /* Y14  - D132: dark ON pink */
  --on-numeral: #FF6EB4; /* Y146 */
  --pass:     #FF6EB4;   /* Y146 - D132 */
  --pass-edge: #140A1E;  /* Y14  */

  --fill-bg: var(--fill);
  --font-mark: "GT Vice", cursive;
  --font-name: "GT Vice", cursive;
  --font-clock: var(--font-pass);
  --mark-size: 38px;
  --name-size: 50px;
  --name-min: 34px;
  --name-wrap: 30px;
  --name-case: none;     /* a script set in capitals is unreadable */
  --name-pad: .36em;
  --ls-name: .01em;
  --ls-tight: -.01em;
  --ls-2: .20em;
  --radius: 0;
  --radius-sm: 2px;
  --move: 700ms cubic-bezier(.22, 1, .36, 1);
  --fade-out: 120ms;
  --fade-in: 0ms;
  --name-in: flicker 700ms linear both;
  --pass-ms: 2600;
  --pass-anim: pass-flicker 2600ms linear both;
  --log-in: flicker 700ms linear both;
  --grain-a: 0;
  --vignette: radial-gradient(120% 140% at 50% 0%, rgba(255, 110, 180, .07) 0%, rgba(20, 10, 30, 0) 60%);
}

/* -------------------------------------------------------- San Andreas ---- */
/*
 * Grove Street, 1992: gold on deep green-black, a gothic face for the names,
 * and a little hydraulic bounce - the fill overshoots, the count hops.
 */
[data-game="gtasa"] {
  --panel:    #0E140C;   /* Y18  */
  --panel-rgb: 14, 20, 12;
  --track:    #2C3826;   /* Y52  */
  --fill:     #E8B83A;   /* Y185 - D133 against the track */
  --head:     #FFF6D8;   /* Y246 - D61 against the fill */
  --cap:      #7DC35A;   /* Y173 - D155 */
  --keyline:  #E8B83A;   /* Y185 - D167 */
  --text-1:   #F5F1E3;   /* Y241 - D223 */
  --text-2:   #B4C49E;   /* Y190 - D172 */
  --accent:   #E8B83A;   /* Y185 - D167 */
  --numeral:  #F5F1E3;   /* Y241 - D151 against the green under it */
  --on-numeral: #2F6B2A; /* Y90  */
  --pass:     #E8B83A;   /* Y185 - D167 */
  --pass-edge: #000000;  /* Y0   */

  --fill-bg: var(--fill);
  --font-mark: "GT Andreas", serif;
  --font-name: "GT Andreas", serif;
  --font-clock: var(--font-pass);
  --mark-size: 34px;
  --name-size: 48px;
  --name-min: 30px;
  --name-wrap: 27px;
  --name-case: none;     /* blackletter capitals run together */
  --ls-name: .02em;
  --ls-tight: 0em;
  --ls-2: .20em;
  --radius: 3px;
  --radius-sm: 3px;
  --move: 650ms cubic-bezier(.34, 1.4, .64, 1);
  --fade-out: 160ms;
  --fade-in: 0ms;
  --name-in: slide-in 320ms cubic-bezier(.34, 1.4, .64, 1) both;
  --pass-ms: 2600;
  --pass-anim: pass-drop 2600ms linear both;
  --log-in: slide-in 320ms cubic-bezier(.34, 1.4, .64, 1) both;
  --grain-a: .07;
  --vignette: radial-gradient(130% 150% at 50% 30%, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, .5) 100%);
}

/* ------------------------------------------------------------ GTA IV ----- */
/*
 * Liberty City, 2008: cold steel and slate, one amber for the pass. Heavy
 * grotesque names, a cold vignette, and everything DISSOLVES, slowly.
 */
[data-game="gta4"] {
  --panel:    #111316;   /* Y19  */
  --panel-rgb: 17, 19, 22;
  --track:    #30353C;   /* Y52  */
  --fill:     #9DB0C2;   /* Y173 - D121 against the track */
  --head:     #EEF2F5;   /* Y241 - D68 against the fill */
  --cap:      #B9C2CB;   /* Y193 - D174 */
  --keyline:  #4E5761;   /* Y86  - D67 */
  --text-1:   #EEF0F2;   /* Y240 - D221 */
  --text-2:   #929DA8;   /* Y155 - D136 */
  --accent:   #EEF0F2;   /* Y240 - D221 */
  --numeral:  #EEF0F2;   /* Y240 - D171 against the slate under it */
  --on-numeral: #3D4650; /* Y69  */
  --pass:     #F2B544;   /* Y186 - D167 */
  --pass-edge: #111316;  /* Y19  */

  --fill-bg: var(--fill);
  --font-mark: var(--font-pass);
  --font-name: "GT Liberty", sans-serif;
  --font-clock: var(--font-pass);
  --mark-size: 30px;
  --name-size: 38px;
  --name-min: 22px;
  --name-wrap: 24px;
  --name-case: uppercase;
  --ls-name: .02em;
  --ls-tight: -.01em;
  --ls-2: .24em;
  --radius: 2px;
  --radius-sm: 2px;
  --move: 1200ms cubic-bezier(.45, 0, .25, 1);
  --fade-out: 1200ms;    /* dissolve out - read by the JS */
  --fade-in: 900ms;
  --name-in: fade-in 900ms ease both;
  --pass-ms: 3000;
  --pass-anim: pass-fade 3000ms ease both;
  --log-in: fade-in 900ms ease both;
  --grain-a: .05;
  --vignette: radial-gradient(120% 150% at 50% 20%, rgba(17, 19, 22, 0) 35%, rgba(5, 8, 12, .65) 100%);
}

/* ------------------------------------------------------------- GTA V ----- */
/*
 * Los Santos, 2013: a clean modern HUD. Money green, gold for the pass, a
 * condensed sans, no texture at all - and changes WIPE in from the left.
 */
[data-game="gta5"] {
  --panel:    #0B0D10;   /* Y13  */
  --panel-rgb: 11, 13, 16;
  --track:    #2A2F35;   /* Y46  */
  --fill:     #72C46B;   /* Y172 - D126 against the track */
  --head:     #F4F7F4;   /* Y246 - D74 against the fill */
  --cap:      #C9CED3;   /* Y205 - D192 */
  --keyline:  #72C46B;   /* Y172 - D159 */
  --text-1:   #F4F6F8;   /* Y246 - D233 */
  --text-2:   #9AA3AC;   /* Y162 - D149 */
  --accent:   #F4F6F8;   /* Y246 - D233 */
  --numeral:  #0B0D10;   /* Y13  - D182: dark ON gold */
  --on-numeral: #F0C24A; /* Y195 */
  --pass:     #F0C24A;   /* Y195 - D182 */
  --pass-edge: #0B0D10;  /* Y13  */

  --fill-bg: var(--fill);
  --font-mark: var(--font-pass);
  --font-name: "GT Santos", sans-serif;
  --font-clock: var(--font-pass);
  --mark-size: 30px;
  --name-size: 46px;
  --name-min: 28px;
  --name-wrap: 26px;
  --name-case: uppercase;
  --ls-name: .03em;
  --ls-tight: 0em;
  --ls-2: .22em;
  --radius: 4px;
  --radius-sm: 3px;
  --move: 350ms cubic-bezier(.2, .8, .2, 1);
  --fade-out: 140ms;
  --fade-in: 0ms;
  --name-in: wipe-in 260ms cubic-bezier(.2, .8, .2, 1) both;
  --pass-ms: 2600;
  --pass-anim: pass-fade 2600ms ease both;
  --log-in: wipe-in 260ms cubic-bezier(.2, .8, .2, 1) both;
  --grain-a: 0;
  --vignette: none;
}

/* ------------------------------------------------------------ GTA VI ----- */
/*
 * Leonida: a sunset over a violet ground. Mission names are not known yet, so
 * this is a plain run timer - wordmark and clock - until a list is added. The
 * wordmark is a SOLID colour, never a logo-style gradient. The ground's
 * gradient stays at or under Y40 everywhere, so the text's contrast bed holds.
 */
[data-game="gta6"] {
  --panel:    #1B0E26;   /* Y18  */
  --panel-rgb: 27, 14, 38;
  --track:    #3C2850;   /* Y47  */
  --fill:     #FF8A4C;   /* Y158 - D111 against the track */
  --fill-2:   #FF5F8F;   /* Y132 - D85  against the track */
  --head:     #FFF1E6;   /* Y243 - D85 against the fill */
  --cap:      #FFC27A;   /* Y202 - D184 */
  --keyline:  #FF8A4C;   /* Y158 - D140 */
  --text-1:   #FFF4EC;   /* Y246 - D228 */
  --text-2:   #F4AFC6;   /* Y191 - D173 */
  --accent:   #FF8A4C;   /* Y158 - D140 */
  --numeral:  #1B0E26;   /* Y18  - D140: dark ON orange */
  --on-numeral: #FF8A4C; /* Y158 */
  --pass:     #FFC27A;   /* Y202 - D184 */
  --pass-edge: #1B0E26;  /* Y18  */

  --fill-bg: linear-gradient(90deg, var(--fill), var(--fill-2));
  --font-mark: var(--font-pass);
  --font-name: "GT Leonida", sans-serif;
  --font-clock: "GT Leonida", sans-serif;
  --dw: .96em;           /* Unbounded 800's widest digit (0) is .935em */
  --cw: .36em;           /* and its colon .339em */
  --mark-size: 34px;
  --name-size: 44px;
  --name-min: 26px;
  --name-wrap: 24px;
  --name-case: uppercase;
  --ls-name: .02em;
  --ls-tight: 0em;
  --ls-2: .24em;
  --radius: 10px;
  --radius-sm: 6px;
  --move: 900ms cubic-bezier(.22, 1, .36, 1);
  --fade-out: 300ms;
  --fade-in: 600ms;
  --name-in: fade-in 600ms ease both;
  --pass-ms: 2600;
  --pass-anim: pass-fade 2600ms ease both;
  --log-in: fade-in 600ms ease both;
  --grain-a: .04;
  --vignette: linear-gradient(115deg, rgba(255, 138, 76, .12) 0%, rgba(255, 95, 143, .08) 45%, rgba(27, 14, 38, 0) 80%);
}

/* ------------------------------------------------------------- document --- */

html, body {
  margin: 0;
  padding: 0;
  background: transparent;
  overflow: hidden;
}

/*
 * The panel sits at 0,0 with no body margin, so the OBS source bounding box IS
 * the panel - no wasted transparent canvas to position around.
 *
 * `isolation: isolate` plus an OPAQUE background is mandatory, not cosmetic: a
 * browser source composites against transparency, so the grain's mix-blend-mode
 * would otherwise blend against nothing and leak into OBS's alpha channel.
 */
#panel {
  position: relative;
  isolation: isolate;
  display: inline-block;
  vertical-align: top;
  padding: var(--pad);
  /* Translucent ground so gameplay shows through - the bar, text and effects
     stay fully opaque. Alpha floors at .5 (set from ?alpha=): below that the
     meta text's delta dips under the 720p floor over a bright scene. */
  background-color: rgba(var(--panel-rgb), var(--panel-a, .88));
  border-radius: var(--radius);
  color: var(--text-1);
  font-family: var(--font-text);
  font-weight: 600;
  -webkit-font-smoothing: antialiased;
  user-select: none;
  overflow: hidden;
}

#panel[hidden] { display: none; }

/* ------------------------------------------------- texture: grain, vignette --- */
/*
 * The grain is a STATIC rasterised data-URI, never a live filter and never
 * per-frame noise. Animated full-panel noise is maximum entropy: it eats the
 * bitrate budget and degrades the gameplay capture sharing the encode.
 */
#panel::before,
#panel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
}

#panel::before {          /* grain */
  z-index: 3;
  mix-blend-mode: overlay;
  opacity: var(--grain-a);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch' seed='7'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

#panel::after {           /* vignette / tint */
  z-index: 4;
  background: var(--vignette);
}

/* Per-theme structure, all static. */
#frame {
  display: none;
  position: absolute;
  inset: 7px;
  pointer-events: none;
  z-index: 2;
}

/* III: 3px corner brackets - cut-paper edges, never a hairline. */
[data-game="gta3"] #frame {
  display: block;
  background:
    linear-gradient(var(--cap), var(--cap)) left top / 16px 3px,
    linear-gradient(var(--cap), var(--cap)) left top / 3px 16px,
    linear-gradient(var(--cap), var(--cap)) right top / 16px 3px,
    linear-gradient(var(--cap), var(--cap)) right top / 3px 16px,
    linear-gradient(var(--cap), var(--cap)) left bottom / 16px 3px,
    linear-gradient(var(--cap), var(--cap)) left bottom / 3px 16px,
    linear-gradient(var(--cap), var(--cap)) right bottom / 16px 3px,
    linear-gradient(var(--cap), var(--cap)) right bottom / 3px 16px;
  background-repeat: no-repeat;
}

/* Vice City: pink keyline top, teal bottom, inset so they never alias. */
[data-game="gtavc"] #panel {
  box-shadow: inset 0 3px 0 var(--keyline), inset 0 -3px 0 var(--keyline-2);
}

/* V: one green strip along the top - the HUD's only ornament. */
[data-game="gta5"] #panel {
  box-shadow: inset 0 3px 0 var(--keyline);
}

/* --------------------------------------------------------------- header --- */

#head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: var(--w);
  height: 40px;
}

#mark {
  font-family: var(--font-mark);
  font-size: var(--mark-size);
  font-weight: 400;
  line-height: 1;
  color: var(--accent);
  white-space: nowrap;
}

/* Vice City's wordmark carries the neon: a STATIC glow, never animated. */
[data-game="gtavc"] #mark,
[data-game="gtavc"] #name {
  text-shadow: 0 0 10px rgba(255, 110, 180, .55), 0 0 2px rgba(255, 240, 250, .6);
}

[data-game="gtavc"] #mark { transform: translateY(2px); }

/* San Andreas: a 3px gold rule under the header. */
[data-game="gtasa"] #head {
  height: 37px;
  border-bottom: 3px solid var(--keyline);
}

#count {
  display: flex;
  align-items: center;
  gap: 12px;
}

.lbl {
  font-size: 14px;
  letter-spacing: var(--ls-2);
  text-transform: uppercase;
  color: var(--text-2);
}

#numBlock {
  display: inline-flex;
  align-items: baseline;
  padding: 5px 10px 3px;
  background: var(--on-numeral);
  color: var(--numeral);
  border-radius: var(--radius-sm);
  font-family: var(--font-pass);
  font-size: 26px;
  font-weight: 400;
  line-height: 1;
}

#of { margin: 0 3px; opacity: .75; }

.narrow #count .lbl { display: none; }

/* San Andreas' hydraulics: the count hops when a mission is passed. */
[data-game="gtasa"] #panel.hop #numBlock { animation: hop 700ms linear both; }

/* ---------------------------------------------------------------- story --- */

#story {
  position: relative;
  width: var(--w);
  margin-top: 12px;
}

#eyebrow,
#nameBox {
  transition: opacity var(--fade-in) ease;
}

#eyebrow {
  height: 18px;
  font-size: 15px;
  line-height: 18px;
  letter-spacing: var(--ls-2);
  text-transform: uppercase;
  color: var(--text-2);
  white-space: pre;
  overflow: hidden;
  text-overflow: ellipsis;
}

#nameBox {
  height: 56px;
  margin-top: 4px;
  display: flex;
  align-items: center;
  overflow: hidden;
}

#name {
  /* Script faces swash and glow past their advance width; the padding gives
     them room inside the clipping box and the margin keeps the text aligned. */
  max-width: calc(100% + var(--name-pad, 0em));
  margin-left: calc(-1 * var(--name-pad, 0em));
  padding: 0 var(--name-pad, 0em);
  font-family: var(--font-name);
  font-size: var(--name-size);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: var(--ls-name);
  text-transform: var(--name-case);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-1);
}

/* Two lines for the rare title that cannot fit on one at the floor size. The
   name box is 56px tall, so the wrap sizes below keep two lines inside it. */
#name.wrap {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  white-space: normal;
  line-height: 1.08;
}

/* Descenders and glow reach below a 1.15 line box. The padding moves #name's
   own clip clear of them and the negative margins keep the layout height. Not
   on .wrap, where the line clamp would show a third line in the padding. */
#name:not(.wrap) {
  padding-top: .4em;
  padding-bottom: .4em;
  margin-top: -.4em;
  margin-bottom: -.4em;
}

/* Mr Dafoe's ink is taller than the name box; let it paint past it. #name
   still clips sideways for the ellipsis. */
[data-game="gtavc"] #nameBox { overflow: visible; }

#name.out {
  opacity: 0;
  transition: opacity var(--fade-out) linear;
}

#name.in { animation: var(--name-in); }

/* The pass banner covers the eyebrow and name while it plays. */
#panel.passing #eyebrow,
#panel.passing #nameBox {
  opacity: 0;
  transition: opacity 120ms linear;
}

#passed {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 78px;
  display: flex;
  align-items: center;
  gap: 18px;
  opacity: 0;
  pointer-events: none;
}

#passedText {
  font-family: var(--font-pass);
  font-size: 46px;
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  color: var(--pass);
  /* A 2px outline ring behind the fill. Not -webkit-text-stroke: OBS's
     Chromium 103 ignores paint-order on HTML text, so a stroke would paint
     OVER the glyphs and thin them. A static text-shadow is safe. */
  text-shadow:
    -2px -2px 0 var(--pass-edge), 0 -2px 0 var(--pass-edge), 2px -2px 0 var(--pass-edge),
    2px 0 0 var(--pass-edge), 2px 2px 0 var(--pass-edge), 0 2px 0 var(--pass-edge),
    -2px 2px 0 var(--pass-edge), -2px 0 0 var(--pass-edge),
    2px 1px 0 var(--pass-edge), 2px -1px 0 var(--pass-edge), -2px 1px 0 var(--pass-edge),
    -2px -1px 0 var(--pass-edge), 1px 2px 0 var(--pass-edge), -1px 2px 0 var(--pass-edge),
    1px -2px 0 var(--pass-edge), -1px -2px 0 var(--pass-edge);
  white-space: nowrap;
}

#passedTime {
  font-size: 24px;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

#panel.passing #passed { animation: var(--pass-anim); }

/* Narrow widths: the time goes under the banner so the row cannot overflow. */
.narrow #passed {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0;
}

/* V: a gold band wipes across first, the text rides in on it. */
[data-game="gta5"] #passed::before {
  content: "";
  position: absolute;
  left: -18px;
  top: 14px;
  bottom: 14px;
  width: 9px;
  background: var(--pass);
  transform-origin: left center;
}

[data-game="gta5"] #panel.passing #passed { animation: pass-wipe 2600ms cubic-bezier(.2, .8, .2, 1) both; }

/* ------------------------------------------------------------------ bar --- */

#bar {
  position: relative;
  width: var(--w);
  height: 36px;
  margin-top: 10px;
}

#track {
  position: absolute;
  left: 0;
  top: 7px;
  width: 100%;
  height: var(--track-h);
  background: var(--track);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

#fill {
  position: absolute;
  inset: 0;
  background: var(--fill-bg);
  transform: translateX(-100%);
  transition: transform var(--move);
  will-change: transform;
}

#headmark {
  position: absolute;
  top: 0;
  left: 0;
  width: 4px;
  height: 100%;
  background: var(--head);
  transform: translateX(0);
  transition: transform var(--move), opacity 200ms linear;
}

#headmark.off { opacity: 0; }

#sheen {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, .55) 50%, rgba(255, 255, 255, 0) 70%);
  transform: translateX(-100%);
}

/* The finale: one sheen across the whole bar, under the banner. */
#panel.finishing #sheen { animation: sheen 1800ms cubic-bezier(.4, 0, .2, 1) 200ms both; }

#caps {
  position: absolute;
  left: 0;
  top: 0;
}

#caps .cap { fill: var(--cap); }

.nofx,
.nofx.in {
  transition: none !important;
  animation: none !important;
}

/* --------------------------------------------------------------- clocks --- */

#clocks {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: var(--w);
  height: 38px;
  margin-top: 10px;
}

#mclock {
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

#mclock .lbl,
#rclock .lbl { margin-right: 10px; }

#rtime {
  font-family: var(--font-clock);
  font-size: 36px;
  font-weight: 400;
  line-height: 1;
}

.digits span {
  display: inline-block;
  width: var(--dw);
  text-align: center;
}

.digits span.c { width: var(--cw); }

#clocks.paused #mtime,
#clocks.paused #rtime { opacity: .5; }

/* ------------------------------------------------------------------ log --- */

#rule {
  width: var(--w);
  height: 3px;
  margin: 12px 0 10px;
  background: var(--keyline);
  opacity: .75;
}

#log {
  list-style: none;
  margin: 0;
  padding: 0;
  width: var(--w);
}

#log li {
  display: flex;
  align-items: center;
  height: 26px;
  font-size: 17px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

#log li:nth-child(2) { opacity: .82; }
#log li:nth-child(3) { opacity: .64; }

#log .sq {
  flex: none;
  width: 8px;
  height: 8px;
  margin-right: 12px;
  background: var(--fill);
  border-radius: var(--radius-sm);
}

#log li.empty .sq { background: var(--track); }

#log .ln {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#log .lt {
  margin-left: 16px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

#log li.new { animation: var(--log-in); }

/* ---------------------------------------------------------- timer mode --- */
/*
 * A game with no mission list (GTA VI, until its names are known) is a plain
 * run timer: wordmark over a big clock, and the panel shrinks to fit it.
 */
#panel.timer-mode #count,
#panel.timer-mode #story,
#panel.timer-mode #bar,
#panel.timer-mode #mclock,
#panel.timer-mode #log { display: none; }

#panel.timer-mode #head,
#panel.timer-mode #clocks { width: auto; }

#panel.timer-mode #clocks {
  height: 70px;
  margin-top: 6px;
  align-items: center;
}

#panel.timer-mode #rclock .lbl { display: none; }

/* The plain timer keeps one ornament: the theme's fill as a strip under the
   clock, so it reads as part of the set rather than as a bare number. */
#panel.timer-mode #rule {
  display: block;
  width: auto;
  height: 4px;
  margin: 10px 0 0;
  background: var(--fill-bg);
  border-radius: 2px;
  opacity: 1;
}

#panel.timer-mode #rtime {
  font-size: 62px;
  color: var(--text-1);
}

/* ----------------------------------------------------------- keyframes --- */

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* A tube catching: two stutters, then steady. Opacity only. */
@keyframes flicker {
  0%   { opacity: 0; }
  8%   { opacity: 1; }
  14%  { opacity: .15; }
  22%  { opacity: 1; }
  30%  { opacity: .4; }
  38%  { opacity: 1; }
  100% { opacity: 1; }
}

@keyframes slide-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes wipe-in {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: translateX(0); }
}

@keyframes hop {
  0%   { transform: translateY(0); }
  18%  { transform: translateY(-7px); }
  36%  { transform: translateY(0); }
  52%  { transform: translateY(-3px); }
  68%  { transform: translateY(0); }
  100% { transform: translateY(0); }
}

/* III: on in one frame, off in one frame. The 0.1% stops are the cut. */
@keyframes pass-cut {
  0%     { opacity: 0; }
  0.1%   { opacity: 1; }
  92%    { opacity: 1; }
  92.1%  { opacity: 0; }
  100%   { opacity: 0; }
}

@keyframes pass-flicker {
  0%   { opacity: 0; }
  4%   { opacity: 1; }
  7%   { opacity: .2; }
  10%  { opacity: 1; }
  13%  { opacity: .4; }
  16%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes pass-drop {
  0%   { opacity: 0; transform: translateY(-16px); }
  10%  { opacity: 1; transform: translateY(4px); }
  16%  { transform: translateY(-2px); }
  21%  { transform: translateY(0); }
  88%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(0); }
}

@keyframes pass-fade {
  0%   { opacity: 0; transform: scale(1.02); }
  22%  { opacity: 1; transform: scale(1); }
  84%  { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes pass-wipe {
  0%   { opacity: 0; transform: translateX(-24px); }
  12%  { opacity: 1; transform: translateX(0); }
  86%  { opacity: 1; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(0); }
}

@keyframes sheen {
  0%   { opacity: 1; transform: translateX(-100%); }
  100% { opacity: 1; transform: translateX(100%); }
}
