@font-face {
  font-family: 'ProggyClean';
  src: url('/fonts/ProggyClean.ttf') format('truetype');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}
:root {
  color-scheme: dark;
  font-family: 'ProggyClean', 'Lucida Console', monospace;
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: auto;
  text-rendering: optimizeSpeed;
  font-synthesis: none;
  font-kerning: none;
  color: #dedfe2;
  background: #252629;
  font-size: 16px;
  line-height: 16px;
  text-transform: lowercase;
}
* { box-sizing: border-box; }
body { margin: 0; }
button, input, select, textarea { font: inherit; }
/* Top bar: title left, source tabs pushed to the right edge. */
.top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 16px;
  background: #303236;
  border-bottom: 1px solid #464951;
}
.top-title { color: #dadce2; text-decoration: none; }
.top-title:hover { color: #ededf0; }
.top-tabs { display: flex; gap: 6px; }
.top-tab {
  padding: 5px 12px;
  color: #acafb7;
  background: #35373c;
  border: 1px solid;
  border-color: #5c5f68 #24262c #24262c #5c5f68;
  text-decoration: none;
}
.top-tab:hover { background: #40434a; color: #dadce2; }
.top-tab.current {
  color: #ededf0;
  background: #53555b;
  border-color: #8b8e97 #1d1f24 #1d1f24 #8b8e97;
  box-shadow: inset 1px 1px #64666e, inset -1px -1px #3b3d43;
}
main { width: min(720px, calc(100% - 32px)); margin: 56px auto; }
h1 { margin: 0 0 24px; font-size: 1rem; font-weight: 400; }
.import-box {
  position: relative;
  min-height: 150px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: #303236;
  border: 1px dashed #74767d;
}
.import-box.dragging { background: #414349; border-color: #dadce2; }
.import-box > span { color: #acafb7; }
.import-button {
  display: inline-block;
  padding: 9px 24px;
  color: #ededf0;
  background: #53555b;
  border: 1px solid;
  border-color: #8b8e97 #1d1f24 #1d1f24 #8b8e97;
  box-shadow: inset 1px 1px #64666e, inset -1px -1px #3b3d43;
  cursor: pointer;
}
.import-button:hover { background: #62646c; }
.import-button:active { border-color: #1d1f24 #8b8e97 #8b8e97 #1d1f24; }
#file-input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); }
.import-box:focus-within .import-button { outline: 1px dashed #e3c48b; outline-offset: 3px; }
progress { display: block; width: 100%; height: 8px; margin-top: 12px; accent-color: #aaaeb9; }
#status { color: #bec2cc; overflow-wrap: anywhere; }
#status.error { color: #edb9ab; }
#report { margin-top: 28px; }
h2 { font-size: 1rem; font-weight: 400; color: #c0c3cc; overflow-wrap: anywhere; margin: 0 0 13px; }
h3 { font-size: 1rem; font-weight: 400; color: #c0c3cc; margin: 22px 0 0; }
#warnings { color: #e2c89b; white-space: pre-line; }
#score-note { color: #acafb7; margin: 12px 0 0; }
#scope, #metric { display: flex; gap: 8px; }
#scope { margin: 12px 0 0; }
#metric { margin: 8px 0 14px; }
#scope button, #metric button {
  padding: 5px 14px;
  color: #b6bac4;
  background: #35373c;
  border: 1px solid;
  border-color: #5c5f68 #24262c #24262c #5c5f68;
  cursor: pointer;
}
#scope button:hover, #metric button:hover { background: #40434a; color: #dadce2; }
#scope button[aria-pressed='true'], #metric button[aria-pressed='true'] {
  color: #ededf0;
  background: #53555b;
  border-color: #8b8e97 #1d1f24 #1d1f24 #8b8e97;
  box-shadow: inset 1px 1px #64666e, inset -1px -1px #3b3d43;
}
#score-legend { display: flex; flex-wrap: wrap; gap: 8px 26px; list-style: none; margin: 0 0 10px; padding: 0; font-variant-numeric: tabular-nums; }
#score-legend li { display: flex; align-items: center; gap: 8px; color: #acafb7; }
#score-legend i, #readout i { width: 9px; height: 9px; flex: none; }
#score-legend b { color: #dadce2; font-weight: 400; }
#chart-wrap { position: relative; background: #303236; border: 1px solid #464951; overflow-x: auto; }
#chart { display: block; width: 100%; min-width: 560px; height: auto; touch-action: none; }
.chart-grid line { stroke: #3f424a; stroke-width: 1; }
.chart-grid line.chart-axis { stroke: #71747d; }
.chart-grid text { fill: #8b8e97; font-size: 11px; }
.chart-lines path { stroke-width: 2; stroke-linejoin: round; }
.chart-cursor line { stroke: #dadce2; stroke-width: 1; stroke-dasharray: 2 3; }
#readout {
  position: absolute;
  top: 10px;
  margin: 0;
  padding: 7px 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: rgba(23, 24, 27, 0.94);
  border: 1px solid #5c5f68;
  color: #acafb7;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  white-space: nowrap;
}
#readout strong { color: #dadce2; font-weight: 400; }
#readout span { display: flex; align-items: center; gap: 7px; }
table { width: 100%; border-collapse: collapse; background: #303236; font-variant-numeric: tabular-nums; }
th { background: #494b52; border: 1px solid; border-color: #71747d #24262c #24262c #71747d; padding: 9px 13px; font-weight: 400; }
td { padding: 10px 13px; border-bottom: 1px solid #464951; }
th, td { text-align: right; }
th:first-child, td:first-child { text-align: left; overflow-wrap: anywhere; }
th:not(:first-child) { width: 80px; }
tbody tr:nth-child(even) { background: #35373c; }
tbody tr:hover { background: #40434a; }
.bot { color: #a4a9b4; margin-left: 8px; }
/* The two sides, in the red and blue the chart already draws with. A team with no id shown
   is left in the default colour rather than guessing one. */
/* Keyed to the faction, so team 2 reads Americans (blue) and team 3 British (red). */
.team-2 { color: #6fb1e8; }
.team-3 { color: #e2755c; }
/* A team inferred from the kill record rather than reported by the server. No colour here,
   so the side's own colour survives; the italics and the title are what say it was inferred. */
.inferred { font-style: italic; }
.empty-row { text-align: center !important; color: #b6bac4; }
/* faq: prose only, so it reads as a page rather than a panel. */
#faq { max-width: 60ch; }
#faq h2 { margin-top: 26px; color: #fff; }
#faq h2:first-child { margin-top: 0; }
#faq p { margin: 10px 0 0; color: #acafb7; line-height: 22px; }
#faq ul { margin: 10px 0 0; padding-left: 22px; color: #acafb7; }
#faq li { line-height: 22px; }
#faq li + li { margin-top: 8px; }
/* Links read as plain text until hovered, matching the clickable text elsewhere. */
#faq a { color: #dedfe2; text-decoration: none; }
#faq a:hover { color: #ededf0; text-decoration: underline; }
/* The default disc marker sits too far left for the pixel font; a dash reads cleaner. */
#faq li::marker { content: '- '; }
#library-note { color: #acafb7; margin: 12px 0 0; }
#library-list { list-style: none; margin: 12px 0 0; padding: 0; background: #303236; border: 1px solid #464951; }
#library-list:empty { display: none; }
#library-list li { display: flex; align-items: center; gap: 14px; padding: 8px 13px; border-bottom: 1px solid #464951; }
#library-list li:last-child { border-bottom: 0; }
#library-list li:nth-child(even) { background: #35373c; }
.library-open {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  text-align: left;
  color: #dedfe2;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}
.library-open:hover { color: #ededf0; text-decoration: underline; }
.library-when { flex: none; color: #8f929a; font-variant-numeric: tabular-nums; }
.library-download { flex: none; color: #acafb7; }
.library-download:hover { color: #dadce2; }
#library-refresh {
  margin-top: 12px;
  padding: 5px 14px;
  color: #b6bac4;
  background: #35373c;
  border: 1px solid;
  border-color: #5c5f68 #24262c #24262c #5c5f68;
  cursor: pointer;
}
#library-refresh:hover { background: #40434a; color: #dadce2; }
.player-button {
  padding: 0;
  color: inherit;
  background: none;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.player-button:hover { color: #ededf0; text-decoration: underline; }
tr.selected .player-button { color: #ededf0; }
tr.selected { background: #3d4046; }
#player-detail { margin-top: 18px; padding: 14px 16px 16px; background: #303236; border: 1px solid #464951; }
#spectators-note { color: #acafb7; margin: 12px 0 0; }
#spectators-table td:last-child { color: #acafb7; }
/* Auto layout hands the leftover width to the last column, which pushed the outcome
   phrase wide and squeezed the names. Fixed layout keeps the fixed columns at their
   declared size and gives the slack to the name column, where it is useful. */
#spectators-table { table-layout: fixed; }
#spectators-table th:nth-child(2), #spectators-table td:nth-child(2) { width: 62px; }
#spectators-table th:nth-child(3), #spectators-table td:nth-child(3) { width: 68px; }
/* 140px is the widest outcome phrase ("no team recorded") plus its horizontal padding, so
   the column is no wider than it needs to be and never wraps. */
#spectators-table th:last-child, #spectators-table td:last-child { width: 140px; text-align: left; }
.detail-head { display: flex; align-items: baseline; gap: 12px; }
.detail-head h3 { margin: 0; color: #dadce2; }
/* No colour of its own, so the side's colour applies; muted covers the no-team case. */
.detail-team.muted { color: #acafb7; }
/* The recorded identity is quieter than the name it sits beside: it is a reference, not
   part of the player's name, so it only brightens when it is pointed at. */
.detail-steamid {
  color: #8b8e97;
  font-size: 12px;
  text-decoration: none;
}
.detail-steamid:hover { color: #dadce2; text-decoration: underline; }
.detail-close {
  margin-left: auto;
  padding: 3px 10px;
  color: #b6bac4;
  background: #35373c;
  border: 1px solid;
  border-color: #5c5f68 #24262c #24262c #5c5f68;
  cursor: pointer;
}
.detail-close:hover { background: #40434a; color: #dadce2; }
/* Three fixed columns rather than auto-fit, so the labels line up and the values stay under
   the label they belong to instead of drifting apart as the panel widens. */
.detail-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2px 20px;
  margin: 14px 0 0;
  font-variant-numeric: tabular-nums;
}
.detail-stats dt { color: #8b8e97; }
.detail-stats dd { margin: 0 0 6px; color: #dadce2; }
/* The label and its value are one grid item, stacked, so they cannot be split across
   columns. */
.detail-stat { display: flex; flex-direction: column; }
.detail-panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 18px 24px; margin-top: 18px; }
.detail-panels h4 { margin: 0 0 9px; color: #acafb7; font-weight: 400; }
.mix-row { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; }
.mix-row > span:first-child { width: 66px; flex: none; color: #acafb7; }
.mix-row i, .detail-weapons i { display: block; height: 7px; flex: 1; background: #3f424a; }
.mix-row b, .detail-weapons b { display: block; height: 100%; background: #6fb1e8; }
.mix-bar.mix-melee { background: #e2755c; }
.mix-bar.mix-ranged { background: #6fb1e8; }
.mix-bar.mix-explosive { background: #e8c76f; }
.mix-count { width: 26px; flex: none; text-align: right; color: #dadce2; font-variant-numeric: tabular-nums; }
.detail-weapons ul { margin: 0; padding: 0; list-style: none; }
.detail-weapons li { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.weapon-name { width: 132px; flex: none; color: #acafb7; overflow-wrap: anywhere; }
.detail-weapons i { flex: 1; }
.detail-weapons b { background: #6fb1e8; }
.detail-weapons .in-melee b { background: #e2755c; }
.detail-weapons .in-ranged b { background: #6fb1e8; }
.detail-weapons .in-explosive b { background: #e8c76f; }
.detail-weapons .in-environment b { background: #8b8e97; }
.detail-weapons .out-melee b { background: #e2755c; }
.detail-weapons .out-ranged b { background: #6fb1e8; }
.detail-weapons .out-explosive b { background: #e8c76f; }
.detail-weapons .out-environment b { background: #8b8e97; }
.weapon-count { width: 26px; flex: none; text-align: right; color: #dadce2; font-variant-numeric: tabular-nums; }
.detail-none { margin: 0; color: #8b8e97; }
[hidden] { display: none !important; }
/* Inferred spectators are dimmed and set in italics, so a row the recording never stated
   is never mistaken for a measured one. */
#spectators-table .inferred td { color: #8b8e97; font-style: italic; }
#event-log { margin-top: 22px; }
#event-log summary { cursor: pointer; color: #c0c3cc; padding: 8px 0; user-select: none; }
#event-log summary::marker { color: #74767d; }
#event-log[open] summary { margin-bottom: 8px; }
#feed-wrap { max-height: 320px; overflow-y: auto; border: 1px solid #464951; }
/* Collapsed borders are painted by the table, so a sticky cell's outline would stay
   behind while its text scrolled on. Separate borders move with the cell, but they
   also stop merging, so only the right edge carries each divider. */
#feed-table { background: #303236; border-collapse: separate; border-spacing: 0; }
#feed-table thead th { position: sticky; top: 0; z-index: 1; border-left-width: 0; }
/* Opaque, so rows do not show through the stuck header. */
#feed-table th { background: #494b52; }
#feed-table th:first-child { border-left-width: 1px; }
#feed-table td { font-size: 0.9375rem; }
#feed-table tr:last-child td { border-bottom: 0; }
#feed-table .feed-suicide td { color: #e2c89b; }
#feed-table .feed-world td { color: #acafb7; }
/* The chat transcript, laid out exactly like the event log above it and for the same reason:
   a fixed-height scrolling table under a collapsed heading, so a long match does not push
   everything else down the page. */
#chat { margin-top: 22px; }
#chat summary { cursor: pointer; color: #c0c3cc; padding: 8px 0; user-select: none; }
#chat summary::marker { color: #74767d; }
#chat[open] summary { margin-bottom: 8px; }
#chat-wrap { max-height: 320px; overflow-y: auto; border: 1px solid #464951; }
#chat-table { background: #303236; border-collapse: separate; border-spacing: 0; }
#chat-table thead th { position: sticky; top: 0; z-index: 1; border-left-width: 0; }
#chat-table th { background: #494b52; }
#chat-table th:first-child { width: 60px; }
#chat-table th:nth-child(2) { width: 140px; white-space: nowrap; }
#chat-table th:last-child { width: 100%; }
#chat-table td:first-child { white-space: nowrap; }
#chat-table td:nth-child(2) { white-space: nowrap; }
#chat-table td:last-child { white-space: pre-wrap; word-break: break-word; }
#chat-table tr:last-child td { border-bottom: 0; }
/* One side's private channel, and the server announcing into the room. Both are dimmed rather
   than recoloured, so a player's name keeps the hue of the side they were on when they said it. */
#chat-table .chat-team td { color: #a4a9b4; }
#chat-table .chat-server td { color: #8b8e97; font-style: italic; }
/* The marker that says which channel a line came from, in the style the bot tag already uses. */
.chat-tag { color: #74767d; margin-left: 8px; font-size: 0.8125rem; }
/* The result the server logged at map end, as one bar rather than a sentence: a half per side,
   each side's name on its outside edge and the two scores meeting in the middle, which is how
   logs.tf sets a score out. Two bevelled buttons in the grey and the bevel the tabs up top already
   use, rather than one flat panel, so the bar is built out of the same parts as the rest of the
   interface instead of being a slab of its own. */
#final-scores { margin-top: 22px; }
.final-bar { display: flex; gap: 4px; font-variant-numeric: tabular-nums; }
.final-side {
  flex: 1;
  min-width: 0;
  padding: 13px 16px 11px;
  background: #35373c;
  border: 1px solid;
  border-color: #5c5f68 #24262c #24262c #5c5f68;
  /* Both halves carry the same 3px rule underneath so the two sides stay the same height and only
     the rule's colour tells them apart. */
  border-bottom-width: 3px;
  border-bottom-color: #24262c;
}
/* The winner is marked by that rule alone, in its own colour. The face stays the same on both
   sides: a half that looks pressed would mark the winner twice over, and a losing side that lost on
   points has not been pressed by anything. The score is never dimmed either way, because a side
   that lost still scored. */
.final-won { border-bottom-color: currentColor; }
.final-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
/* Twice the base size is an exact multiple of the font's 16px pixel grid, so the score keeps the
   font's square pixels instead of being resampled into a blur. */
.final-score { font-size: 2rem; font-weight: 400; line-height: 24px; }
/* The second side's row runs the other way, so its score lands on its inside edge too. */
.final-side.team-3 .final-head { flex-direction: row-reverse; }
/* The muted grey rather than the dimmer one the notes use: the winner's half has the lighter
   pressed face, and on that face the dimmer grey drops to about 2:1 against its background. */
.final-damage { display: block; margin-top: 4px; color: #acafb7; font-size: 0.875rem; }
/* Damage lines up with the score above it rather than with the name, so each side's two figures
   stack on its inside edge and the bar's middle carries the numbers that are being compared. */
.final-side.team-2 .final-damage { text-align: right; }
#final-scores-note { margin: 8px 0 0; color: #8b8e97; font-size: 0.9375rem; }
#chat-note { margin-top: 8px; color: #8b8e97; font-size: 0.875rem; }
@media (max-width: 480px) {
  main { margin-top: 32px; }
  th:not(:first-child) { width: 60px; }
  th, td { padding: 10px; }
  /* The bar keeps its two halves rather than stacking, since the numbers meeting in the middle is
     the whole of it, so it gives up padding and a size step instead. */
  .final-side { padding: 11px 10px 9px; }
  .final-score { font-size: 1.5rem; line-height: 20px; }
  /* Narrow screens give the bar two rows rather than squeezing the title. */
  .top-bar { flex-wrap: wrap; }
  .top-tabs { margin-left: auto; }
}
