/* MTM2.COM — the interior skin.
 *
 * The database pages, details, login and upload. The front door has its own
 * light skin; the contrast between the two is deliberate and original.
 *
 * Built from Design's mockups (_design/mockups/, Tracks turn 4a) as a
 * stylesheet rather than the inline styles the mockups carry — those are how a
 * mockup is made, not how a site ships. Same values, one place to change them.
 *
 * The legacy class names at the bottom (.header1, .header2, .detail, .offset,
 * .nf) are kept working deliberately, so pages can move over one at a time
 * instead of in one flip. stylesdefault.css remains for pages not yet moved.
 */

/* Space Mono, self-hosted.
 *
 * Design sets every small label in it -- 385 places across the ten mockups, at
 * 10 to 30px, in both weights -- so it is the labelling face for the site, not
 * an accent on one page.
 *
 * Served from here rather than linked from Google: no third-party request on
 * every page load, no visitor IPs handed to Google, nothing to fail if Google
 * is slow or blocked, and Cloudflare caches it at the edge like any other
 * file. Two files, 33KB together, and only the latin subset -- the labels are
 * ASCII, and unicode-range below keeps a browser from fetching them at all
 * for text they cannot serve.
 *
 * Space Mono is under the SIL Open Font License 1.1, which permits this;
 * the licence travels with the files in fonts/OFL.txt.
 *
 * font-display: swap matches Design's &display=swap -- a label shows in the
 * page font immediately and swaps when the font lands, rather than sitting
 * invisible.
 */
@font-face {
    font-family: 'Space Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(fonts/spacemono-400.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Space Mono';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url(fonts/spacemono-700.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    --bg:        #000000;   /* with the MTMGbg tile over it */
    --bar:       #000000;   /* the site header — solid, the one hard band */
    --bar-soft:  #050505;   /* the controls row — barely darker than the tile */
    --panel:     #0A0A0A;   /* inputs, footer bar */
    --ink:       #FFFF00;   /* body text — the original's yellow */
    --link:      #C0C0C0;
    /* One step down from --link, and now used only for the search
     * placeholder: it has to read as "nothing typed yet" against the text you
     * type over it. Everything else that used to be muted -- the control
     * labels, the footer bars, the cross-archive label -- uses --link, so the
     * page has one grey rather than two that look like a mistake. It is also
     * still on the two filter labels, which name a control rather than saying
     * anything and sit a step back from the value under them -- Design has
     * them that way too. */
    --muted:     #808080;
    --rule:      #404040;   /* hairlines */
    --rule-soft: #303030;
    --navy:      #000080;   /* header2 in the original */
    --navy-deep: #191970;   /* header1 */
    --on-navy:   #F5F5F5;

    --font: Arial, Helvetica, sans-serif;
    /* The small control labels. Design's face, self-hosted above.
     * Arial is the fallback while it loads and if it ever fails. */
    --font-label: 'Space Mono', ui-monospace, Consolas, monospace;
}

body {
    margin: 0;
    background: var(--bg) url(MTMGbg.gif) repeat;
    color: var(--ink);
    font: 13px/1.45 var(--font);
}

a, a:visited { color: var(--link); }
/* Deliberate departure from the original, per Design: its hover was #0000FF,
 * which is unreadable on black. */
a:hover    { color: var(--ink); }

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

/* The bands.
 *
 * Only the site header is solid. Everything below it sits on the tiled field,
 * and the horizontal structure comes from the NAVY bars — the summary and the
 * table header — with the footer bar closing the page.
 *
 * Two corrections got here. First pass: everything transparent, so nothing
 * banded at all. Second: header, title bar and quick-links all solid, which
 * overshot — it walled off the top third of the page and left the navy bars
 * with nothing to contrast against. Design has one solid bar at the top and
 * lets the tile carry the rest. */
.site-head {
    background: var(--bar);
}

.site-head,
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 12px 18px;
    border-bottom: 1px solid var(--rule);
}

.site-head__brand { display: flex; align-items: center; gap: 12px; }
.site-head__brand img { display: block; }
.site-head__wordmark {
    font-size: 20px;
    font-weight: bold;
    letter-spacing: 0.01em;
    color: var(--ink);          /* the wordmark is yellow, not link-grey */
    text-decoration: none;
}
.site-head__wordmark:hover { color: var(--ink); }

.site-nav { display: flex; align-items: center; gap: 18px; }
.site-nav a { text-decoration: none; }
.site-nav .is-active {
    color: var(--ink);
    border-bottom: 2px solid var(--ink);
    padding-bottom: 2px;
}

/* The header on a narrow screen.
 *
 * Brand, six nav links and the sign-in button come to about 600px and neither
 * row could wrap, so every page on the site scrolled sideways on a phone -- the
 * body inherited the header's width and the content underneath was dragged out
 * with it. Nothing here is a phone-specific layout: the same three groups, told
 * they may take a second line.
 *
 * The nav goes full width and last. Brand and sign-in are the two things worth
 * having on the first line -- one says where you are, the other is the only
 * action in the bar -- and six links do not fit beside them at any size worth
 * targeting. `order` rather than reordering the markup, because the source
 * order is the right reading order and the tab order with it. */
@media (max-width: 720px) {
    .site-head,
    .page-head {
        flex-wrap: wrap;
        gap: 10px 14px;
        padding: 10px 12px;
    }
    .site-nav {
        order: 3;
        width: 100%;
        flex-wrap: wrap;
        gap: 8px 14px;
    }
    /* The two row-2 groups behave the same way: the title keeps the first line
     * and the search drops under it at full width rather than being crushed. */
    .page-head__tools { width: 100%; }
    .page-head__tools .search { flex: 1; }
    .page-head__tools .search input { width: 100%; min-width: 0; }
}

.btn {
    display: inline-block;
    color: var(--link);
    text-decoration: none;
    font-size: 12px;
    border: 1px solid var(--rule);
    padding: 7px 13px;
    background: transparent;
    cursor: pointer;
}
.btn:hover { color: var(--ink); border-color: var(--ink); }

.btn--primary {
    color: var(--on-navy);
    font-weight: bold;
    background: var(--navy);
}
.btn--primary:hover { color: #FFFFFF; }

/* ------------------------------------------------------------ page head -- */

.page-head__title { font-size: 17px; font-weight: bold; }
.page-head__tools { display: flex; align-items: center; gap: 10px; }

.search {
    display: flex;
    align-items: center;
    border: 1px solid var(--rule);
    background: var(--panel);
}
.search input {
    background: transparent;
    border: 0;
    color: var(--ink);
    font: 12px var(--font);
    padding: 7px 9px;
    width: 210px;
}
.search input::placeholder { color: var(--muted); }
.search input:focus { outline: 1px solid var(--rule); }
/* Navy, per Design turn 12a. The one filled control in the row, so the eye
 * lands on it without hunting -- and it matches the .btn--primary action in
 * the header rather than inventing a third button style. */
.search button {
    color: var(--on-navy);
    font: bold 11px var(--font);
    padding: 7px 13px;
    border: 0;
    background: var(--navy);
    cursor: pointer;
}
.search button:hover { color: #FFFFFF; background: var(--navy-deep); }

/* --------------------------------------------------------- quick links -- */

/* The bracket row under the page head. Same punctuation as the closing bar in
 * .sectionfoot, but no background: that band is what ends the page, and giving
 * this one the same fill would make the page look finished before the listing
 * had started. */
.quicklinks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 0;
    padding: 10px 18px;
    border-bottom: 1px solid var(--rule);
    font-size: 12px;
    color: var(--muted);
}
.quicklinks a         { text-decoration: none; padding: 0 8px; }
.quicklinks a:hover   { color: var(--ink); }
.quicklinks .bracket  { padding: 0 8px; }

/* --------------------------------------------------------- filter bar --- */
/* Design's turn 4a consolidates the four stacked filter forms into one row. */

.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 14px 22px;
    padding: 16px 18px;
    border-bottom: 1px solid var(--rule);
    background: var(--bar-soft);   /* barely darker than the tile, per 12a */
}

/* The tracks bar carries more than fits on one line -- six controls and then
 * the whole alphabet -- so it stacks: controls, a hairline, letters. */
.filters--stack { flex-direction: column; align-items: stretch; gap: 14px; }
.filters__row   { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 22px; }
.filters__row--letters {
    align-items: center;
    gap: 4px;
    border-top: 1px solid #202020;
    padding-top: 12px;
}
/* Something pinned to the right of the controls row — "Also by this maker",
 * and the like. */
/* The label stays grey and only the link is yellow, so the yellow marks the
 * thing you can act on rather than the whole phrase. */
.filters__aside { margin-left: auto; font-size: 12px; color: var(--link); }
.filters__aside a,
.filters__aside a:visited { color: var(--ink); }
.filters__aside a:hover   { color: #FFFFFF; }
.filter { display: flex; flex-direction: column; gap: 5px; }
/* The two control labels keep the darker grey, as Design has them. They name
 * the control rather than saying anything, so they sit a step back from the
 * value underneath -- the one place on the page where the dimmer grey is
 * doing a job rather than looking like a mistake. */
.filter__label {
    font: 10px var(--font-label);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
}
.filter select,
.filter input {
    background: var(--panel);
    color: var(--ink);
    border: 1px solid var(--rule);
    font: 12px var(--font);
    padding: 6px 8px;
}

/* "My build" is picked out in yellow, label and border both.
 *
 * It is the one control in the row that describes the visitor rather than the
 * archive, and the only one whose answer changes what the other rows mean
 * rather than which rows appear. Design turn 4b gives it the accent; without
 * it the control that reframes the whole page looks like a fifth way to sort. */
.filter--mine .filter__label { color: var(--ink); }
.filter--mine select         { border-color: var(--ink); }

/* Takes the rest of the line, so its hint has somewhere to sit. */
.filter--wide { flex: 1; min-width: 200px; }

/* A pair of buttons standing in for a control, in a row of dropdowns.
 *
 * Design draws these taller than the selects beside them and lets the row
 * bottom-align, which puts their labels 16px above every other label -- the
 * one row on the page where the eye cannot read the labels straight across.
 * Matching the select height instead lines the labels up and costs nothing:
 * 6px of padding on a 12px face is the same 30px a select comes to.
 *
 * The wrapper carries no padding of its own now; that was the other half of
 * the 45px. */
/* 30px is what a select comes to here: 12px text, 6px padding either side,
 * 1px border. Matching it by padding alone lands within a pixel or two --
 * close enough to look like a mistake rather than a choice -- so the height
 * is stated and the label centred inside it. */
.filter__buttons      { display: flex; align-items: center; gap: 10px; height: 30px; }
.filter__buttons .btn { padding: 0 13px; line-height: 28px; }
.filter__hint    { color: var(--muted); font-size: 11px; }

/* A button that is the current setting. Navy fill, as the header action uses,
 * so "on" reads the same way everywhere. */
.btn--on {
    background: var(--navy-deep);
    color: var(--on-navy);
    border-color: var(--rule);
}
.btn--on:hover { color: #FFFFFF; }

/* A–Z as a click strip rather than a form. */
.letters { display: flex; flex-wrap: wrap; gap: 4px; }
.letters a {
    text-decoration: none;
    font-size: 12px;
    padding: 4px 7px;
    border: 1px solid var(--rule-soft);
}
.letters a:hover      { border-color: var(--rule); color: var(--ink); }
.letters .is-active   { color: var(--ink); border-color: var(--ink); }

/* --------------------------------------------------------------- table -- */

/* The listing block does not run to the page edge.
 *
 * Design turn 12a wraps the summary, the table and the footer bar in
 * padding: 16px 18px 24px, so the navy bands stop short of both sides and the
 * whole listing reads as one object sitting on the tiled field rather than as
 * stripes painted across the window. The bars above it -- the site header and
 * the controls row -- stay full width on purpose: those are page chrome, and
 * the contrast between the two is what makes the listing look placed.
 *
 * 18px, not the 8 it measures at in a screenshot of the mockup: the mockup
 * canvas carries 56px of its own padding and is scaled down to fit. */
.listing { padding: 16px 18px 24px; }

/* The listing table scrolls inside this block rather than dragging the document
 * sideways with it. Before, the body took the table's width and every row of
 * the page -- site header included -- sat wider than the screen.
 *
 * NOT scoped to phones, though that is where it is worst. The eight-column
 * track listing needs about 890px and the maker page needs 1,014 (it carries a
 * "Filed as" column the others do not), so a 1,000px desktop window overflows
 * on the maker page too. A width-conditional rule would leave that broken.
 * Unconditional costs nothing: a table that fits produces no scrollbar.
 *
 * The columns are already at their minimums and hiding any of them loses data
 * the page exists to show, so scrolling is the honest answer rather than a
 * narrow-screen layout that quietly drops information.
 *
 * On .listing rather than the table because tracks, trucks and the maker page
 * all share this wrapper -- one rule instead of a markup change in three files.
 * Safe as a block formatting context: the only sticky element on the site is
 * .mtmg-nav, which is in the MTMG chrome and never inside a listing. */
.listing { overflow-x: auto; }

/* The summary is a band too, not loose text.
 *
 * Design's turn 12a puts it in the navy bar above the table -- "62 tracks by
 * Malibu350, 1999 to 2007. Sorted by date and desc." Left on the tiled
 * background it is the one line on the page competing with the watermark,
 * which is exactly where you least want that: it is the line explaining why
 * the row count is what it is. */
/* The whole line is yellow, not white with yellow highlights: it is the one
 * sentence explaining why the rows below are the rows below, and on navy the
 * yellow is what the eye goes to first.
 *
 * A second line -- the alias list -- stays white on purpose. It is reference
 * detail rather than something to act on, and keeping both lines yellow would
 * flatten the difference. */
.summary {
    background: var(--navy);
    color: var(--ink);
    text-align: center;
    padding: 9px 18px;
    font-size: 12px;
    border-bottom: 1px solid var(--rule);
}
.summary strong { color: var(--ink); font-weight: bold; }

/* Yellow through every state. A sort link that greyed out once used would be
 * dimmest exactly where the reader has already shown interest. */
.summary a,
.summary a:visited { color: var(--ink); }
.summary a:hover   { color: #FFFFFF; }

.summary__also        { color: var(--on-navy); }
.summary__also strong { color: var(--on-navy); font-weight: normal; }

/* The bar that closes a listing.
 *
 * Turn 12a: "Showing 9 of 62 · ◉ name opens the details pop-up, otherwise it
 * asks you to log in · the thumbnail opens the full screenshot" on the left,
 * Prev / Next on the right.
 *
 * Worth copying for its own sake: it puts the count, the legend for the row
 * markers, and the pager in one place, so a reader who wonders what a symbol
 * means finds the answer without leaving the page. The existing pager prints
 * a bare "1-100 of 4,641" and explains nothing. */
.tablefoot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 10px 18px;
    border-top: 1px solid var(--rule);
    background: var(--panel);
    font-size: 12px;
    color: var(--link);
}
.tablefoot__pager { display: flex; gap: 8px; }

/* The same controls at the head of the listing.
 *
 * On tracks it takes the free end of the letters row, which is where the eye
 * already is after picking a letter. On a maker page there is no free end --
 * that is where "Also by this maker" sits -- so the pager takes the right and
 * pushes the aside left of it. Only when there is more than one page, so most
 * maker pages never see it and keep the room. */
.pager            { display: flex; align-items: center; gap: 8px; }

/* Who does the pushing depends on what else is in the row.
 *
 * On the letters row the pager is the only thing on the right, so it takes the
 * free space itself. On the maker bar the aside already claims it, and the
 * pager simply follows on the aside's right -- giving both an auto margin
 * would split the slack between them and open two equal gaps that look like an
 * accident rather than a layout. */
.filters__row--letters .pager--top { margin-left: auto; }
.pager__count     { color: var(--muted); font-size: 12px; white-space: nowrap; }
.pager .btn       { padding: 0 13px; line-height: 28px; }
.tablefoot__pager .is-disabled {
    color: var(--rule);
    border-color: var(--rule-soft);
    pointer-events: none;
}

/* ---------------------------------------------------------- listing rows -- */
/*
 * Design lays these out with CSS grid. A real <table> is used here instead:
 * this is tabular data with a header row and sortable columns, so the table
 * carries meaning a grid of divs does not — column headers announced with each
 * cell by a screen reader, and the rest of the site is tables already. The
 * visual result is the same.
 */

table.rows { width: 100%; border-collapse: collapse; }

/* So the min-widths below mean what Design's grid means.
 *
 * Design lays the listing out as a CSS grid, where a track of 88px is 88px on
 * screen. A table cell measures min-width against its content box, so with
 * 10px of padding either side every column came out 20px wider than the number
 * it was given. border-box puts the padding back inside the figure. */
.rows th, .rows td { box-sizing: border-box; }

.rows th {
    background: var(--navy-deep);
    color: var(--on-navy);
    text-align: left;
    font-weight: bold;
    font-size: 12px;
    padding: 7px 10px;
}
.rows td {
    padding: 7px 10px;
    border-bottom: 1px solid var(--rule-soft);
    vertical-align: middle;
}
/* Size reads in the body grey, not the yellow. It is a fact about the file,
 * the same kind of thing as the date beside it, and in yellow it pulled more
 * attention than the title of the track it belongs to. */
.rows td.num, .rows th.num { text-align: right; }
.rows th.num, .rows td.num { min-width: 90px; }

/* Trucks carry a download count and tracks do not show one. 72px per Design
 * turn 7a, and narrower than the other numeric column because it holds a
 * count rather than a size with a unit on it. */
.rows th.dl, .rows td.dl   { min-width: 72px; }
.rows td.num               { color: var(--link); }

/* Two groups, per Design turn 12a: the picture and the title hold the left,
 * the rest sits over on the right, and the slack falls in the gap between.
 *
 * The title column takes the width so the gap lands there. Without it the
 * table shares spare space evenly across all seven columns and the right-hand
 * group drifts inward instead of staying against the page edge. 100% is not
 * literal -- a table caps it at whatever is left once the others have what
 * they need.
 *
 * Inside that group the values still read LEFT, under their own headings.
 * Ranging them right as well was tried and it is too hard a right: each value
 * ends up flush against the next column with the whitespace behind it, so the
 * eye has nothing to run down. Only Size is right, because it is a number and
 * numbers line up on their units. The min-widths are what hold the columns
 * apart -- without them each shrinks to its longest value and the group jams
 * into the corner.
 *
 * Ranging the title right was tried too, and it is wrong for a different
 * reason: titles run from "Big Whiskey" to "MTM1TRUXnTRAX(MTM1GAME.POD)", so
 * a right edge gives a column of links a ragged left one, and a wrapped title
 * pushes its marker onto a line of its own.
 */
.rows th.name,    .rows td.name    { text-align: left; width: 100%; }
/* Widths straight from Design turn 12a, whose listing grid is
 *
 *     88px  1fr  196px  132px  100px  90px  86px
 *     Pic   Track  Filed as  Type/Revue  Date  Size  J-Viewer
 *
 * min-width rather than width, and set on the header as well as the cell. A
 * table in auto layout treats width on a td as a suggestion and will overrule
 * it -- the title column asking for 100% wins, and everything else collapses
 * toward its longest word. That is what squeezed the J-Viewer column to 69px
 * and left its button looking untouched after its padding had already been
 * corrected. A minimum is not negotiable in the same way. */
.rows th.maker,   .rows td.maker   { text-align: left; min-width: 196px; }
.rows th.type,    .rows td.type    { text-align: left; min-width: 132px; }
.rows th.date,    .rows td.date,
.rows th.laptime, .rows td.laptime { text-align: left; min-width: 100px; white-space: nowrap; }

/* A date is one thing and reads as one. Left to wrap it splits into "2007-" /
 * "10-01", which costs a line of row height on every row and makes a
 * fixed-width value look like an accident. Type/Revue may still wrap --
 * "Straight-a-way" does so in the mockup too. */
/* .quiet is a colour, not a size.
 *
 * It was doing both, which shrank the maker column to 11px along with the
 * date. Design only ever drops the date: its rows are 13px throughout and the
 * date cell is the single override. A maker is a name someone looks for and
 * often clicks, so it reads at the same size as the title it sits beside; a
 * date is a fact you glance at, and can afford to be smaller. */
.rows .quiet    { color: var(--link); }
/* The date alone, not everything shaped like one. A lap time is a result --
 * the thing garage display exists to show -- and shrinking it to timestamp
 * size because it happens to want the same width and nowrap was the same
 * mistake .quiet was making one column over. */
.rows td.date   { font-size: 11px; }

.rows th.pic, .rows td.pic { min-width: 88px; }
.rows td.pic { padding: 6px 9px; }
.rows td.pic img { display: block; border: 1px solid var(--rule); }
/* A missing picture keeps the shape of one: Design turn 12a draws a dashed
 * frame at thumbnail size rather than dropping the words into the gap. Rows
 * stay the same height whether or not there is an image, so the column does
 * not stagger -- which is why it is a box and not just paler text. */
.rows .pic--none {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 68px;
    height: 51px;
    border: 1px dashed var(--rule-soft);
    color: var(--muted);
    font-size: 11px;
}

/* The ◉ beside a name: this one opens the details pop-up. Explained in the
 * footer bar rather than left as a mystery glyph. */
.rows .marker { color: var(--link); font-size: 12px; cursor: help; }

/* The "Revue" half of Type/Revue.
 *
 * A type that was written up on the forum IS the link, as in the original.
 * What is different is the colour: there the link was yellow like every other
 * type, so an underline was the only thing separating a reviewed track from an
 * unreviewed one. Here it also drops to the link grey, which is the signal the
 * rest of the page already uses, so the column reads at a glance -- yellow is
 * just a type, grey and underlined has something to read behind it. */
.rows .revue       { color: var(--link); text-decoration: underline; }
.rows .revue:hover { color: var(--ink); }

/* The build badge, Design turns 4a and 9a: yellow, black text, hard against
 * the name it belongs to.
 *
 * Design states the rule with it -- "nothing is marked unless it needs more
 * than the original game, so 4,000 legacy entries stay clean and the exception
 * stands out". A badge on every row would say nothing; on 2 rows in 5,287 it
 * says everything, which is why it can afford to be the loudest thing in the
 * table.
 *
 * It disappears once the row is dimmed. At that point the visitor has told us
 * their build, the whole row is already saying "not for you", and the exact
 * requirement has moved to the size column -- a yellow flag fighting a greyed
 * row would just be two answers to the same question. */
.rows .badge {
    background: var(--ink);
    color: #000000;
    font-size: 10px;
    font-weight: bold;
    padding: 2px 5px;
    margin-left: 7px;
    white-space: nowrap;
}
.rows td.name { line-height: 1.4; }

/* An item that needs a newer build says so where its size would go, per turn
 * 4b — labelled, not hidden. */
.rows .needs { color: var(--link); font-size: 11px; white-space: nowrap; }

.rows th.viewer { text-align: center; white-space: nowrap; }
/* The J-Viewer button, at Design turn 12a's measurements: padding 6px 4px on
 * an 11px face, filling the width of its cell.
 *
 * The two states are not the same weight, which is the part worth keeping.
 * Load is the live action and takes the brighter border and text; Log in asks
 * for something you cannot do yet, so it sits a step back on both. Fifty rows
 * of identical bright buttons down the right of a page you are not signed in
 * to would be fifty invitations to a dead end. */
.rows th.viewer, .rows td.viewer { min-width: 86px; }
.rows td.viewer { text-align: center; padding: 4px 8px; }
.rows td.viewer .btn {
    display: block;
    background: var(--panel);
    font-size: 11px;
    padding: 6px 4px;
}
.rows td.viewer .btn--load  { border-color: var(--rule);      color: var(--link); }
.rows td.viewer .btn--login { border-color: var(--rule-soft); color: var(--muted); }
.rows td.viewer .btn:hover  { color: var(--ink); border-color: var(--rule); }

/* ------------------------------------------------------------- legacy --- */
/* Class names the un-migrated pages still use. Same values as
 * stylesdefault.css so a half-migrated site stays coherent. */

.nf { color: var(--link); }

table.detail { border: 1px solid var(--rule); }
.detail td   { border-width: 1px; }
td.offset    { color: var(--link); background-color: #202020; }

.header1 td { color: var(--on-navy); text-align: center; background-color: var(--navy-deep); border-bottom-width: 0; }
.header2 td { color: var(--ink);     text-align: center; background-color: var(--navy);      border-bottom-width: 0; }
.header3 td { border-bottom-width: 0; }

li { list-style-type: circle; }


/* ------------------------------------------------------- section footer -- */
/* The bracket nav the archive pages have always ended with -- Rumbles, Drags,
 * Races and so on. Splitting the maker page per archive took it out of the one
 * listing that had none, so it is shared now rather than pasted into each page
 * as it was before.
 *
 * Design turn 12a makes it a solid black bar the full width of the window,
 * with a hairline above it, and that is what makes it read as the end of the
 * page rather than as more links: the header opens with the same band, so the
 * two bracket the listing between them. Left on the tiled field it just looked
 * like a stray line of text after the table.
 *
 * The brackets and the pipes take the dimmer grey and the links the page grey,
 * so the punctuation holds the shape without competing with what you can click.
 */
.sectionfoot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px 0;
    padding: 12px 18px;
    border-top: 1px solid var(--rule);
    background: var(--bar);
    font-size: 12px;
    color: var(--muted);
}
.sectionfoot a          { color: var(--link); text-decoration: none; padding: 0 8px; }
.sectionfoot a:visited  { color: var(--link); }
.sectionfoot a:hover    { color: var(--ink); }
.sectionfoot .bracket   { padding: 0 8px; }
/* The page you are already on: named, not linked. */
.sectionfoot .is-here   { color: var(--ink); padding: 0 8px; }


/* ------------------------------------------------------- build marking --- */
/* Turn 4b. Told which build someone is on, a row they cannot open is dimmed
 * rather than dropped: knowing a track exists, and what it would take to run
 * it, is the point -- that is the whole reason the Community Patch tiers are
 * in the schema. The size column says what it needs instead of how big it is,
 * because at that moment the requirement is the useful fact.
 *
 * Hiding them outright is one click away for anyone who disagrees. */
.rows tr.is-dim td            { background: #060606; border-bottom-color: var(--rule-soft); }
.rows tr.is-dim td,
.rows tr.is-dim a             { color: #6E6E6E; }
.rows tr.is-dim img           { opacity: 0.45; }
.rows tr.is-dim .needs        { color: var(--muted); }
.rows tr.is-dim a:hover       { color: var(--link); }


/* ------------------------------------------------------------ list card -- */
/* The saved list's own description, above the table it filtered to. */
.listcard {
    border: 1px solid var(--rule);
    background: var(--panel);
    padding: 10px 14px;
    margin-bottom: 12px;
    font-size: 12px;
}
.listcard__name  { color: var(--ink); font-weight: bold; font-size: 13px; }
/* The description is stored markup -- paragraphs, bullets and links, written
 * when the lists were made. It is rendered through the whitelist in
 * _inc/richtext.php, so these are the tags that can actually turn up. The
 * defaults would give it browser margins built for a white page, so it gets
 * spacing that suits a small dark card. */
.listcard__desc          { color: var(--link); margin-top: 6px; line-height: 1.55; }
.listcard__desc p        { margin: 8px 0 0; }
.listcard__desc p:first-child { margin-top: 0; }
.listcard__desc ul       { margin: 6px 0; padding-left: 20px; }
.listcard__desc li       { list-style-type: square; margin: 2px 0; }
.listcard__desc a        { color: var(--ink); }
.listcard__desc a:hover  { color: #FFFFFF; }
.listcard__links { margin-top: 6px; color: var(--muted); }

.tablefoot__count { color: var(--muted); align-self: center; }

/* ------------------------------------------------------- details pop-up -- */
/* Design turns 5a and 5b. This runs inside a 1000x600 featherlight iframe, so
 * it is a whole page with no site header: you are already somewhere, looking
 * at one thing, and a nav bar inside a pop-up would only offer ways to break
 * out of it. */

.popup-body { margin: 0; }
.popup {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.popup__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 16px;
    background: var(--navy-deep);
    color: var(--on-navy);
}
.popup__title    { font-size: 15px; font-weight: bold; }
.popup__by       { font-weight: normal; color: var(--on-navy); }
.popup__by a     { color: var(--ink); }
.popup__id       { font: 11px var(--font-label); letter-spacing: 0.1em; color: var(--on-navy); white-space: nowrap; }

/* Detail on the left, picture and the download on the right. */
.popup__body {
    display: grid;
    grid-template-columns: 1fr 274px;
    flex: 1;
    min-height: 0;
}
.popup__main  { padding: 0 0 16px; }
.popup__side  { padding: 12px 16px; border-left: 1px solid var(--rule); }
.popup__empty { padding: 16px; }

/* The facts. A label column and a value column, the labels on their own
 * ground so the eye can run down them without a rule to follow. */
.facts { display: grid; grid-template-columns: 104px 1fr; }
.fact__label {
    padding: 7px 12px;
    background: #202020;
    color: var(--link);
    border-bottom: 1px solid #000000;
    font-size: 12px;
}
.fact__value {
    padding: 7px 12px;
    border-bottom: 1px solid var(--rule-soft);
    font-size: 13px;
}
.facts .quiet { color: var(--link); font-size: 12px; }

/* Other work by the same maker, two across so eight fit without scrolling. */
.moreby        { padding: 16px 12px 0; }
.moreby__head  { font-size: 12px; color: var(--muted); margin-bottom: 8px; }
.moreby__head a { color: var(--ink); }
.moreby__list  { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 14px; font-size: 12px; }

.popup__shot    { display: block; width: 100%; height: auto; border: 1px solid var(--rule); }
.popup__caption { font-size: 11px; color: var(--muted); text-align: center; padding: 5px 0 0; }
.popup__noshot  {
    border: 1px dashed var(--rule-soft);
    color: var(--muted);
    font-size: 11px;
    text-align: center;
    padding: 32px 0;
}

/* The one thing the pop-up is for. */
.cta          { display: flex; flex-direction: column; gap: 9px; margin-top: 14px; }
.cta__go      { text-align: center; }
.cta__why     { font-size: 12px; color: var(--link); }
.cta__aside   { font-size: 11px; color: var(--muted); }

/* Said once, plainly, next to the download rather than in place of it -- the
 * requirement is a warning, not a refusal. See tracks.php on why minbuild
 * cannot be treated as a verdict. */
.buildnote {
    border: 1px solid var(--ink);
    background: var(--panel);
    padding: 10px 12px;
    margin-top: 14px;
    font-size: 12px;
}
.buildnote__head { color: var(--ink); font-weight: bold; margin-bottom: 4px; }
.buildnote__body { color: var(--link); line-height: 1.45; margin-bottom: 6px; }

.popup__foot {
    padding: 9px 16px;
    border-top: 1px solid var(--rule);
    background: var(--bar);
    font-size: 11px;
    color: var(--muted);
}

/* ---------------------------------------------------- the pop-up frame --- */
/* Featherlight's own box, sized for details.php.
 *
 * This lived inline in tracks.php and was lost when that page was rebuilt, so
 * the details pop-up opened at featherlight's default size instead of the
 * 1000x600 the page is laid out for. It belongs here rather than in one page:
 * tracks.php, maker.php and details.php itself all open pop-ups now, and
 * three copies would be three chances to drift.
 *
 * The original comment is worth keeping -- it explains why a pop-up at all:
 * "workaround for the awful old window.open which doesn't work correctly on
 * multiple monitors".
 */
.featherlight-iframe .featherlight-content {
    width: 1000px;
    height: 600px;
    max-width: 90%;    /* keeps it responsive on small screens */
}
.featherlight-iframe iframe {
    width: 100% !important;
    height: 100% !important;
}

/* The JS viewers want the room, and 1000x600 is not it.
 *
 * That size belongs to details.php, which is laid out for it -- a picture, a
 * facts column and a download button. The track and truck viewers are a 3D
 * viewport with a control panel down one side and a minimap in the corner, and
 * at 1000x600 the viewport is the smallest thing on screen.
 *
 * Applied through featherlight's `variant`, which copies the name onto the
 * container, so the Load links opt in with
 * data-featherlight-variant="fl-viewer" and nothing else changes. One rule for
 * both viewers: they have the same shape and the same problem.
 *
 * Sized in viewport units rather than pixels. A fixed box would be too big on a
 * laptop and would still waste half a large monitor, and this is the one pop-up
 * where the extra space is the point. featherlight's own content style carries
 * margin-left/right of 5% and max-height 95%, so 90vw is the practical ceiling
 * anyway -- these numbers sit just inside it rather than fighting it. */
.featherlight-iframe.fl-viewer .featherlight-content {
    width: 1600px;
    height: 1000px;
    max-width: 90vw;
    max-height: 90vh;
}

/* ------------------------------------------------------------- sign in -- */

/* Turns 6a and 6b. Two treatments of one form.
 *
 * 6a is the page you reach on purpose: 620px, tiled like the rest of the
 * interior, hairline border, rhino and wordmark at the top.
 *
 * 6b is the same form reached by clicking a download while signed out. Design
 * gives it a different weight deliberately -- narrower, solid black rather than
 * tiled, edged in yellow rather than grey, and headed by a navy-deep bar. It
 * reads as an interruption to something you were doing, which is exactly what
 * it is, and the yellow edge is the one place on the site that border colour is
 * used to mean "this is the thing to deal with".
 *
 * The action button is YELLOW here, not the navy .btn--primary the listings
 * use. That is Design's call and it is the right one: on a page whose only
 * purpose is one button, the button should be the brightest thing on it. */

.signin-page {
    display: flex;
    justify-content: center;
    padding: 48px 18px;
}

.signin {
    width: 620px;
    max-width: 100%;
    border: 1px solid var(--rule);
    background: var(--bg) url(MTMGbg.gif) repeat;
}

.signin--download {
    width: 540px;
    border-color: var(--ink);
    background: var(--bar);      /* solid: no tile behind the interruption */
}

/* 6a's masthead — the one solid band, matching .site-head elsewhere. */
.signin__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--rule);
    background: var(--bar);
}
.signin__head img   { display: block; }
.signin__title      { font-size: 20px; font-weight: bold; }

/* 6b's title bar. */
.signin__bar {
    background: var(--navy-deep);
    color: var(--on-navy);
    padding: 10px 16px;
    font-size: 14px;
    font-weight: bold;
}

.signin__body {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 22px 24px 26px;
}
.signin--download .signin__body { gap: 16px; padding: 18px 20px 20px; }

.signin__say {
    margin: 0;
    font-size: 13px;
    line-height: 1.7;
    color: var(--link);
}
/* Prose links inside the sign-in panel are yellow rather than link-grey: there
 * are only three of them and each one is a place to go next. */
.signin__say a,
.signin__forum a,
.signin__why a { color: var(--ink); text-decoration: none; }
.signin__say a:hover,
.signin__forum a:hover,
.signin__why a:hover { text-decoration: underline; }

/* -- what you were trying to download (6b) -- */

.signin__item {
    display: flex;
    align-items: center;
    gap: 12px;
    border: 1px solid var(--rule);
    background: var(--panel);
    padding: 10px;
}
.signin__item img     { display: block; border: 1px solid var(--rule); }
.signin__item div     { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.signin__item strong  { font-size: 14px; }
.signin__item span    { font-size: 12px; color: var(--link); }

/* -- the form -- */

.signin__form {
    display: flex;
    flex-direction: column;
    gap: 13px;
    margin: 0;
}
.signin--download .signin__form { gap: 10px; }

.signin__field { display: flex; flex-direction: column; gap: 6px; }
.signin__field span { font-size: 12px; color: var(--link); }

.signin__form input[type="text"],
.signin__form input[type="password"] {
    background: var(--panel);
    border: 1px solid var(--rule);
    color: var(--ink);
    font: 14px var(--font);
    padding: 10px 11px;
    outline: none;
}
.signin--download .signin__form input[type="text"],
.signin--download .signin__form input[type="password"] { padding: 9px 11px; }

.signin__form input::placeholder { color: var(--muted); }
/* The border is the focus ring: an outline would sit outside the 1px hairline
 * and read as a second box. */
.signin__form input:focus { border-color: var(--ink); }

/* AUTOFILL, which paints over all of the above.
 *
 * Pick a saved name from the browser's dropdown and Chrome marks the field
 * :-webkit-autofill and fills it with its own near-white background. That is
 * not a colour the page can set: `background` is ignored on an autofilled
 * field, which is why nothing in this stylesheet explained the symptom. It
 * then sticks until the field is edited, so the box stays bright -- reported
 * as the username going white and staying there, and only sometimes, because
 * it only happens when there is a saved name to pick.
 *
 * The inset box-shadow is the way through: shadows ARE honoured, so a 1000px
 * inset one repaints the whole box in --panel behind the browser's fill.
 * -webkit-text-fill-color for the text, since `color` is overridden too, and
 * caret-color so the cursor does not vanish against it.
 *
 * :hover, :focus and :active are listed because the fill is re-applied on each
 * of those states; one selector alone loses it again the moment you click in.
 *
 * TWO SEPARATE RULES, not one list. A selector a browser does not understand
 * invalidates the ENTIRE comma-separated group it appears in -- so pairing the
 * unprefixed `:autofill` with the prefixed one would drop both on any browser
 * that knows only `-webkit-autofill`, which is precisely the older browser most
 * likely to need this. Split, each stands or falls alone. */
.signin__form input:-webkit-autofill,
.signin__form input:-webkit-autofill:hover,
.signin__form input:-webkit-autofill:focus,
.signin__form input:-webkit-autofill:active {
    -webkit-box-shadow: 0 0 0 1000px var(--panel) inset;
            box-shadow: 0 0 0 1000px var(--panel) inset;
    -webkit-text-fill-color: var(--ink);
    caret-color: var(--ink);
}
/* The standard form. Firefox tints rather than repainting, and its tint is a
 * filter, so that is what has to be cleared there. */
.signin__form input:autofill,
.signin__form input:autofill:hover,
.signin__form input:autofill:focus,
.signin__form input:autofill:active {
    box-shadow: 0 0 0 1000px var(--panel) inset;
    caret-color: var(--ink);
    filter: none;
}

.signin__keep {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--link);
    padding-top: 2px;
    cursor: pointer;
}
.signin__keep input { margin: 0; cursor: pointer; }

.signin__go {
    display: block;
    width: 100%;
    text-align: center;
    background: var(--ink);
    color: #000000;
    border: 0;
    font: bold 14px var(--font);
    padding: 11px 12px;
    cursor: pointer;
}
.signin--download .signin__go { font-size: 13px; padding: 10px 12px; }
.signin__go:hover { background: #FFFFFF; }

/* -- what failed, and where to go -- */

/* auth.php returns one message whatever went wrong, so this never has to carry
 * a list. Yellow-on-panel with a yellow edge, which is the same vocabulary as
 * the 6b border: something for you to deal with. */
.signin__error {
    margin: 0;
    border: 1px solid var(--ink);
    background: var(--panel);
    padding: 10px 12px;
    font-size: 12px;
    line-height: 1.6;
}

.signin__forum {
    display: flex;
    flex-direction: column;
    gap: 9px;
    border-top: 1px solid var(--rule);
    padding-top: 16px;
    font-size: 12px;
    color: var(--link);
}

.signin__after {
    margin: 0;
    font-size: 11px;
    line-height: 1.7;
    color: #999999;
}
.signin__after a { color: var(--link); text-decoration: none; }
.signin__after a:hover { color: var(--ink); text-decoration: underline; }

.signin__why {
    border: 1px solid var(--rule);
    background: var(--panel);
    padding: 13px 14px;
    font-size: 12px;
    line-height: 1.7;
    color: var(--link);
}
.signin__why span { color: var(--ink); }

/* ------------------------------------------------------------- upload -- */

/* Turns 6c and 6d. The two uploaders differ only in their field list, so they
 * share every class here and neither carries any styling of its own.
 *
 * Both were still on the 1999 stylesdefault.css until now: a 480px centred
 * <table class=detail> with right-aligned label cells. That layout is why the
 * grid below is 96px + 1fr with the labels right-aligned -- it is the same
 * shape, which is the shape people who upload here have used for twenty-odd
 * years. Only the skin changed. */

.upload-page {
    display: flex;
    justify-content: center;
    padding: 40px 18px;
}

.upload {
    width: 640px;
    max-width: 100%;
    border: 1px solid var(--rule);
    background: var(--bg) url(MTMGbg.gif) repeat;
}

.upload__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--rule);
    background: var(--bar);
}
.upload__brand { display: flex; align-items: center; gap: 12px; }
.upload__brand img { display: block; }
.upload__title { font-size: 19px; font-weight: bold; }

/* Account state, wherever it appears. See `.who` in the shared section below --
 * the uploader header, the site header and the details panel all say who you
 * are the same way, because they are all saying the same thing. */

.upload__body {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 18px 20px 24px;
}

.upload__intro {
    border: 1px solid var(--rule);
    background: var(--panel);
    padding: 13px 15px;
    font-size: 12px;
    line-height: 1.75;
    color: var(--link);
}
.upload__intro div { padding-top: 8px; }
.upload__intro a { color: var(--ink); text-decoration: none; }
.upload__intro a:hover { text-decoration: underline; }

/* -- fields -- */

.upload__fields { display: flex; flex-direction: column; gap: 13px; }

.upload__row {
    display: grid;
    grid-template-columns: 96px 1fr;
    align-items: center;
    gap: 12px;
}
.upload__row > span {
    font-size: 12px;
    color: var(--link);
    text-align: right;
}

.upload__row input[type="text"],
.upload__row select {
    background: var(--panel);
    border: 1px solid var(--rule);
    color: var(--ink);
    font: 13px var(--font);
    padding: 8px 10px;
    outline: none;
    width: 100%;
    box-sizing: border-box;
}
.upload__row input[type="text"]:focus,
.upload__row select:focus { border-color: var(--ink); }

/* The file inputs.
 *
 * Design draws these as a bordered "Choose file" button with the chosen
 * filename beside it. ::file-selector-button gets exactly that from the real
 * control, so there is no hidden input, no label-as-button, and no JavaScript
 * keeping a filename span in sync -- the browser already does all of it, and
 * the keyboard and screen-reader behaviour stays the browser's. */
.upload__row input[type="file"] {
    font: 12px var(--font);
    color: #999999;
    width: 100%;
}
.upload__row input[type="file"]::file-selector-button {
    border: 1px solid var(--rule);
    background: var(--panel);
    color: var(--link);
    font: 12px var(--font);
    padding: 7px 12px;
    margin-right: 10px;
    cursor: pointer;
}
.upload__row input[type="file"]::file-selector-button:hover {
    color: var(--ink);
    border-color: var(--ink);
}

/* Un-choosing a file.
 *
 * A file input can be pointed at a different file but never emptied, and the
 * picture is the optional one of the two -- so someone who attaches one and
 * then thinks better of it had no way back short of reloading the form and
 * retyping everything.
 *
 * The button is created by upload.js, not written into the markup, because it
 * cannot work without JavaScript. With the script blocked nothing appears and
 * the form behaves exactly as it did.
 */
.upload__file {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;        /* so a long filename shrinks instead of pushing the × out */
}
.upload__file input[type="file"] {
    min-width: 0;
    flex: 1;
}

.upload__clear {
    flex: none;
    width: 24px;
    height: 24px;
    line-height: 1;
    border: 1px solid var(--rule);
    background: var(--panel);
    color: var(--link);
    font: 15px/1 var(--font);
    cursor: pointer;
    padding: 0;
}
.upload__clear:hover {
    color: var(--ink);
    border-color: var(--ink);
}
.upload__clear[hidden] { display: none; }

/* -- which build it needs -- */

/* Yellow-edged, because it is the one field on the form that nothing else can
 * supply. Everything above it can be corrected later from the row itself; this
 * one is a fact about the file that only the person uploading knows.
 *
 * Deliberately NOT pre-filled by inspecting the zip. A pod can reference
 * models and textures from a pre-existing pod -- "podzipping" -- so the absence
 * of a .png proves nothing, and a .png that ships alongside a matching .raw is
 * a pod carrying both formats, which runs on the original game. A scanner would
 * have to be right about all three cases and would get less accurate as the
 * CP3 pool grows. Asking outright is both simpler and more honest. */
.upload__build {
    border: 1px solid var(--ink);
    background: var(--panel);
    padding: 14px 15px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.upload__build .upload__row > span { color: var(--ink); }
.upload__build select {
    background: var(--bar-soft);
    border-color: var(--ink);
}

.upload__hint {
    font-size: 12px;
    line-height: 1.7;
    color: var(--link);
    border-top: 1px solid var(--rule-soft);
    padding-top: 11px;
}
.upload__hint code {
    font: 11.5px var(--font-label);
    color: var(--ink);
}
.upload__note {
    font-size: 11px;
    line-height: 1.7;
    color: #999999;
}
.upload__note code { font: 11px var(--font-label); }

.upload__go {
    display: block;
    width: 100%;
    text-align: center;
    background: var(--ink);
    color: #000000;
    border: 0;
    font: bold 14px var(--font);
    padding: 11px 12px;
    cursor: pointer;
}
.upload__go:hover { background: #FFFFFF; }

/* -- the dots -- */

/* Kept, and kept working. The original marched ten GIFs from blue to purple
 * while the file went up, driven by a setTimeout walking document.images[] by
 * numeric index -- which broke the moment any other image appeared above them
 * on the page. Same effect, addressed by id instead. */
.upload__foot {
    border-top: 1px solid var(--rule);
    padding-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 9px;
    align-items: center;
    font-size: 12px;
    color: var(--link);
}
.upload__dots { display: flex; align-items: center; gap: 7px; }
.upload__dots img { display: block; }
.upload__thanks { color: #999999; }

/* -- the result page -- */

.upload__result {
    border: 1px solid var(--rule);
    background: var(--panel);
    padding: 14px 15px;
    font-size: 13px;
    line-height: 1.8;
}
.upload__result dl { margin: 0; display: grid; grid-template-columns: 96px 1fr; gap: 4px 12px; }
.upload__result dt { color: var(--link); font-size: 12px; text-align: right; }
.upload__result dd { margin: 0; word-break: break-all; }

/* Something went wrong and the file is not stored. Same vocabulary as the
 * sign-in error and the 6b border: yellow edge means deal with this. */
.upload__bad {
    border: 1px solid var(--ink);
    background: var(--panel);
    padding: 13px 15px;
    font-size: 13px;
    line-height: 1.7;
}

.upload__again {
    display: flex;
    gap: 10px;
    justify-content: center;
}

/* ---------------------------------------------------------------- who -- */

/* "signed in as ..." — the one treatment for account state.
 *
 * Design never draws a signed-in header: every mockup shows the Log in button,
 * because that is the state a visitor arrives in. But it does settle how
 * account state reads wherever it does appear -- Space Mono at 10px in #999,
 * in the Track Details panel (turn 5b) and in both uploader headers (6c, 6d).
 * So that is what this is, and the site header uses it too rather than
 * inventing a third size for the same sentence.
 *
 * Quiet on purpose. It is a status line, not a control -- but the sign-out
 * link inside it is underlined and always present, because a remembered login
 * that lasts thirty days has to have a visible way out on every page. That was
 * the condition for having remember-me at all.
 */
.who {
    font: 10px var(--font-label);
    color: #999999;
}
.who a { color: #999999; text-decoration: underline; }
.who a:hover { color: var(--ink); }
/* ----------------------------------------------------------------- mtmg -- */

/* Design's turns 8a, 8b and 11a-11d. One skin for all six.
 *
 * MTMG kept its own look for twenty-odd years -- silver menu links that go
 * white on navy, #848884 group headings, circle bullets -- and Design keeps
 * every one of those rather than repainting the section in the listings'
 * palette. They are already the right family: site.css took --navy and the
 * yellow from here in the first place. So this is the same section, re-laid
 * out, not a different one.
 *
 * What changes is the layout. It was a two-column <table class=page> assembled
 * from head.dat + menu.dat + a fragment, valid only once concatenated. It is a
 * grid now, and the "you are here" marker -- which the old markup could only
 * express by editing one of 35 copies of the menu -- is a class.
 */

/* Row 2: the guild banner and where you are. */
.mtmg-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 18px 24px;
    border-bottom: 1px solid var(--rule);
}
.mtmg-head img { display: block; max-width: 100%; height: auto; }
.mtmg-crumb {
    font: 11px var(--font-label);
    color: #848884;
    white-space: nowrap;
}

.mtmg {
    display: grid;
    grid-template-columns: 244px 1fr;
}

/* -- the menu -- */

/* Sticky, because these are tutorials read top to bottom and the menu is how
 * you get to the next page in a series. It was in a table cell before, so it
 * scrolled away and you went back up for it.
 *
 * min-height:0 with overflow-y:auto is what lets a 79-link menu (traxx) scroll
 * inside itself rather than forcing the page taller than the viewport, which
 * would defeat the stickiness.
 */
.mtmg-nav {
    border-right: 1px solid var(--rule);
    padding: 20px 18px 30px;
    display: flex;
    flex-direction: column;
    gap: 18px;
    position: sticky;
    top: 0;
    align-self: start;
    max-height: 100vh;
    min-height: 0;
    overflow-y: auto;
}

.mtmg-nav__group { display: flex; flex-direction: column; gap: 6px; }

/* #848884 is the legacy DT colour, kept. */
.mtmg-nav__head { color: #848884; font-size: 13px; }

/* A collapsible group.
 *
 * <details>/<summary> rather than a scripted accordion: it is the element for
 * the job, it works with JavaScript off, it is keyboard operable, and screen
 * readers announce expanded/collapsed without any ARIA of ours. traxx has 17
 * groups and 79 links -- without this, every tutorial page carries all 79 in
 * the margin, which is what Design's 8b collapses away.
 *
 * The default marker is removed and replaced by Design's count-and-triangle on
 * the right, because the count is the useful part: it says how much is behind
 * the heading before you spend a click on it.
 */
details.mtmg-nav__group > summary {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    cursor: pointer;
    list-style: none;          /* Firefox */
}
details.mtmg-nav__group > summary::-webkit-details-marker { display: none; }
details.mtmg-nav__group > summary:hover { color: #FFFFFF; }

.mtmg-nav__count { color: #999999; font-size: 11px; white-space: nowrap; }

/* The triangle turns to point down when the group is open, which is the one
 * thing the count alone cannot say. */
details[open] > summary .mtmg-nav__count { transform: rotate(90deg); }
.mtmg-nav__count { display: inline-block; transform-origin: 0.42em 0.52em; }

.mtmg-nav ul {
    list-style-type: circle;
    color: gray;              /* the bullet, not the text */
    margin: 0;
    padding-left: 17px;
}
.mtmg-nav li { margin-bottom: 4px; }

.mtmg-nav a {
    color: silver;
    text-decoration: none;
    font-size: 12px;
}
/* The original hover, unchanged: white on navy, no underline. */
.mtmg-nav a:hover {
    color: #FFFFFF;
    background: var(--navy);
}

/* You are here. The one thing the old menus could not say without being
 * copied and edited -- which is why there were 35 of them. */
.mtmg-nav a.is-here {
    color: #FFFFFF;
    background: var(--navy);
    padding: 1px 5px;
}

/* -- the content -- */

/* min-width:0 so a wide fragment scrolls inside its own column instead of
 * stretching the grid: these pages are full of 2002 markup with fixed-width
 * tables and screenshots, and one of them must not widen the page. */
.mtmg-body {
    padding: 22px 24px 32px;
    min-width: 0;
    overflow-x: auto;
}
.mtmg-title {
    font-size: 21px;
    font-weight: bold;
    margin: 0 0 20px;
}

/* The fragments are 2002 HTML and carry their own <font>, <center> and tables.
 * Rather than fight all of it, only the things that would actually break the
 * new layout are corrected. */
.mtmg-body img { max-width: 100%; height: auto; }
.mtmg-body table { max-width: 100%; }

/* -- the closing strip -- */

.mtmg-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 26px;
    align-items: baseline;
    padding: 14px 24px;
    border-top: 1px solid var(--rule);
    background: var(--bar);
    font-size: 12px;
}
.mtmg-foot__head { color: #848884; }
.mtmg-foot a { color: silver; text-decoration: underline; }
.mtmg-foot a:hover { color: var(--ink); }

/* One column on a narrow screen. The menu stops being sticky first -- a
 * full-height sticky menu above the content is worse than no menu. */
@media (max-width: 860px) {
    .mtmg { grid-template-columns: 1fr; }
    .mtmg-nav {
        position: static;
        max-height: none;
        border-right: 0;
        border-bottom: 1px solid var(--rule);
    }
}


/* ------------------------------------------------------------- models -- */

/* Design's turn 19a: one browser over six archives, replacing 99 hand-written
 * pages -- 29 of which existed only to hold a LIMIT offset, so a category was
 * split across up to seven pages on boundaries that meant nothing and shifted
 * whenever a model was added in the middle. */

.models-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 16px;
}
.models-head h1 { font-size: 21px; font-weight: bold; margin: 0 0 3px; }
.models-head__sub { font-size: 12px; color: var(--link); }

.models-search {
    display: flex;
    align-items: center;
    border: 1px solid var(--rule);
    background: var(--panel);
    margin: 0;
}
.models-search input {
    background: transparent;
    border: 0;
    color: var(--ink);
    font: 13px var(--font);
    padding: 8px 11px;
    width: 224px;
    max-width: 40vw;
    outline: none;
}
.models-search input::placeholder { color: var(--muted); }
.models-search button {
    color: var(--link);
    background: var(--navy-deep);
    border: 0;
    border-left: 1px solid var(--rule);
    font: 11px var(--font);
    padding: 8px 12px;
    cursor: pointer;
}
.models-search button:hover { color: #FFFFFF; }

/* -- the filter panel -- */

.models-filter {
    border: 1px solid var(--rule);
    background: var(--bar-soft);
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 11px;
    margin-bottom: 14px;
}
.models-filter__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px;
}
.models-filter__row--split {
    border-top: 1px solid #202020;
    padding-top: 10px;
}
.models-filter__label {
    font: 10px var(--font-label);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #999999;
    padding-right: 4px;
}
/* Per page and the pager travel together on the right. Given separate auto
 * margins they split the slack into two gaps that read as an accident, and on a
 * narrow row the pager wrapped to the left of a new line -- the opposite corner
 * from where it belongs. */
.models-filter__right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.models-filter__per {
    display: flex;
    align-items: center;
    gap: 7px;
}

/* Buttons, matching the listings' filter row: the chosen one is filled navy,
 * the rest are outlined. Same vocabulary as tracks.php, deliberately -- this is
 * the same kind of control doing the same job. */
.models-filter a:not(.btn),
.models-filter .is-on:not(.btn) {
    font-size: 12px;
    padding: 5px 11px;
    border: 1px solid var(--rule);
    text-decoration: none;
}
.models-filter a:not(.btn) { color: var(--link); background: var(--panel); }
.models-filter a:not(.btn):hover { color: var(--ink); border-color: var(--ink); }
.models-filter .is-on { color: var(--on-navy); background: var(--navy-deep); }

/* -- what you are looking at -- */

.models-summary {
    background: var(--navy);
    color: var(--ink);
    padding: 9px 12px;
    font-size: 13px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 14px;
}
.models-summary__count { font-size: 12px; color: var(--link); }

.models-empty { font-size: 13px; color: var(--link); }
.models-empty a { color: var(--ink); }

/* -- the models -- */

/* auto-fill rather than Design's fixed repeat(3, 1fr): the sidebar is 244px and
 * these pages are read at every width from a laptop to a large monitor, so a
 * hard three columns is either cramped or wasteful depending on the screen. */
.models-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
    gap: 14px;
}

.models-card {
    border: 1px solid var(--rule);
    background: var(--bar-soft);
    display: flex;
    flex-direction: column;
}
.models-card:hover { border-color: var(--rule); }

/* contain, not cover: these are photographs of models against a background, and
 * cropping one to fill a box can cut the model out of its own picture. */
.models-card__pic {
    display: block;
    border-bottom: 1px solid var(--rule);
    background: var(--panel);
}
.models-card__pic img {
    display: block;
    width: 100%;
    height: 132px;
    object-fit: contain;
}

.models-card__body {
    padding: 10px 12px 11px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}
.models-card__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}
.models-card__top a,
.models-card__top > span:first-child {
    color: var(--ink);
    text-decoration: none;
    font-size: 14px;
    font-weight: bold;
    min-width: 0;
    overflow-wrap: anywhere;
}
.models-card__top a:hover { text-decoration: underline; }

/* Which archive it came from. Small and outlined -- it is a fact about the
 * model, not a thing to click. */
.models-card__src {
    font-size: 10px;
    color: var(--link);
    border: 1px solid var(--rule);
    padding: 1px 5px;
    white-space: nowrap;
    flex: none;
}

.models-card__desc { font-size: 11px; color: var(--link); line-height: 1.5; }

.models-card__foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: 11px;
    color: #999999;
    padding-top: 4px;
    border-top: 1px solid #202020;
}
.models-card__foot a { color: var(--link); text-decoration: none; }
.models-card__foot a:hover { color: var(--ink); }

.models-pager {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 18px;
    margin-top: 18px;
    font-size: 12px;
    color: var(--link);
}
.models-pager a { color: var(--link); }
.models-pager a:hover { color: var(--ink); }

/* Which shelf a search result sits on. Only rendered while searching -- inside
 * a category every card would say the same thing. Two badges is possible and
 * correct: one model in the archive is on two shelves. */
.models-card__cats {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-bottom: 1px;
}
.models-card__cats a {
    font: 10px var(--font-label);
    color: var(--on-navy);
    background: var(--navy);
    text-decoration: none;
    padding: 1px 6px;
}
.models-card__cats a:hover { color: var(--ink); }

/* The section's own thanks, from the landing page this browser replaces. Small
 * and at the foot -- it is history rather than navigation, and losing it with
 * the page would have been the easy thing to do. */
.models-credit {
    margin: 22px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--rule-soft);
    font-size: 11px;
    line-height: 1.7;
    color: #999999;
}
.models-credit a { color: var(--link); }
.models-credit a:hover { color: var(--ink); }

/* The pager sits at the far right of the view-controls row, after Per page. */
.models-filter .pager--top { margin-left: 14px; }

/* The divider belongs between two rows, not above the first one. Seven of the
 * seventeen categories live in a single archive, so their Game row is dropped
 * -- it could only have said "All 1 / Custom" -- which leaves Sort as the only
 * row, and its top border reading as a line to nowhere. */
.models-filter__row--split:first-child {
    border-top: 0;
    padding-top: 0;
}

/* ----------------------------------------------------------- tourneys -- */

/* Design's turns 14a, 14b and 14c. The scoring layout -- five rounds, a total,
 * ordered by finish with the winner emphasised -- is kept as it was: it reads
 * well already and the people who use these pages have read it that way for
 * years. What changed around it is the chrome and the load. */

/* -- one event's result -- */

/* The event name above its table.
 *
 * Centred and stacked, because the name and the date are both what the event
 * IS -- a right-aligned date reads as metadata about something else.
 *
 * NO BACKGROUND. It had a navy bar briefly, matching the panels and the table
 * head, and that was one navy block too many: with a filled table directly
 * under it and a navy header row inside that, the page turned into stacked
 * bands. The tile is quiet enough behind a single line of large text -- it was
 * the ruled rows underneath that needed a solid ground, not this. */
.tourney-head {
    padding: 0 0 12px;
    text-align: center;
}
.tourney-head__name {
    font-size: 19px;
    font-weight: bold;
    color: var(--ink);
}
.tourney-head__date {
    font-size: 12px;
    color: var(--link);
    padding-top: 3px;
}

.tourney-none { font-size: 13px; color: var(--link); }

/* The five rounds are fixed-width so the columns line up down the table, and
 * the name takes whatever is left. Grid rather than a table because each row is
 * a single element that can carry the winner's treatment as a whole.
 *
 * Solid, not the tile showing through -- the same call as the record panels.
 * Design leaves these transparent and on a mockup that reads fine, because
 * there is no tile in the picture. On the page there is: a repeating watermark
 * behind every row, with a rule under each one, is two patterns and a grid
 * competing in the same space. The table fills, so the tile frames it instead.
 */
.scores {
    display: block;
    background: var(--bar-soft);
    border: 1px solid var(--rule);
}

.scores__head,
.scores__row {
    display: grid;
    grid-template-columns: 1fr 78px 78px 78px 78px 78px 96px;
    align-items: center;
}
.scores__head {
    background: var(--navy-deep);
    color: var(--on-navy);
    font-size: 12px;
    font-weight: bold;
}
.scores__head > div,
.scores__row > div { padding: 8px 10px; }

.scores__head > div:not(:first-child),
.scores__row > div:not(.scores__name) { text-align: center; }

.scores__row {
    border-bottom: 1px solid var(--rule);
    font-size: 13px;
    color: var(--link);
}
.scores__row:last-child { border-bottom: 0; }
.scores__name a { color: var(--link); text-decoration: none; }
.scores__name a:hover { color: var(--ink); text-decoration: underline; }

/* The finishing position, ahead of the name and deliberately quieter than it --
 * it labels the row rather than being the thing you came to read. */
.scores__pos { font-size: 11px; color: #999999; }

/* The winner. A yellow rule under the row and the name in italic yellow, which
 * is how the original marked it -- kept, because it is legible at a glance and
 * costs no colour the page was not already spending. */
/* Lighter than the rows around it now that they are filled too -- the yellow
 * rule alone did the work when everything else was tile. */
.scores__row.is-winner {
    border-bottom-color: var(--ink);
    background: #131313;
    color: var(--ink);
}
.scores__row.is-winner > div { font-weight: bold; font-style: italic; }
.scores__row.is-winner .scores__name a { color: var(--ink); }
.scores__row.is-winner .scores__pos { color: #999999; font-weight: normal; font-style: normal; }

.scores__points { color: var(--ink); }

/* On a narrow screen the five round columns are what has to give: the name and
 * the total are the parts you can still read something from. */
@media (max-width: 720px) {
    .scores__head,
    .scores__row { grid-template-columns: 1fr 52px 52px 52px 52px 52px 64px; }
    .scores__head > div,
    .scores__row > div { padding: 7px 5px; font-size: 12px; }
}

/* -- the tourney filter bar -- */

/* Same vocabulary as the listings' filter row: the chosen one filled navy, the
 * rest outlined. Two rows -- what you are looking at, then how it is ordered --
 * separated by a hairline, exactly as the tracks bar separates its controls
 * from its alphabet. */
.tourney-filters .filters__row { align-items: center; gap: 7px; }
.tourney-filters .filters__row--sort {
    border-top: 1px solid #202020;
    padding-top: 12px;
}
.tourney-filters .filter__label { padding-right: 4px; }

.tourney-filters a,
.tourney-filters .is-on {
    font-size: 12px;
    padding: 5px 11px;
    border: 1px solid var(--rule);
    text-decoration: none;
    white-space: nowrap;
}
.tourney-filters a { color: var(--link); background: var(--panel); }
.tourney-filters a:hover { color: var(--ink); border-color: var(--ink); }
.tourney-filters .is-on { color: var(--on-navy); background: var(--navy-deep); }
/* The event count rides along with the season but should not compete with it. */
.tourney-filters a .quiet { color: var(--muted); }

.tourney-summary {
    background: var(--navy);
    color: var(--ink);
    padding: 9px 12px;
    font-size: 13px;
    margin-bottom: 14px;
}

/* The breadcrumb back to the table, in the page title. */
.page-head__title .crumb { color: var(--muted); padding: 0 4px; }
.page-head__title a { color: var(--link); text-decoration: none; }
.page-head__title a:hover { color: var(--ink); }

/* The zoomed player's profile link, in the same title. Secondary to the
 * player's own name -- normal weight and smaller, same idea as .rows .quiet
 * on the listings, so it reads as a door to more, not a second heading. */
/* UNDERLINED, and in the link colour rather than --muted.
 *
 * This sat at the end of a breadcrumb -- "Tracks > Fila . profile" -- in grey,
 * at the same weight as the crumbs, with text-decoration: none. So the one
 * word on the line that goes somewhere looked exactly like the two that do
 * not, and the site owner's verdict on finding it was "I was never gonna
 * notice that". They were right: it was a link only in the markup.
 *
 * Underline because that is what this site already does when it wants a link
 * read as a link inside other text -- see .rows .revue. The crumbs themselves
 * stay undecorated, so the underline is now the thing that separates "where
 * you are" from "where you can go". */
.page-head__title .profile-link {
    font-size: 12px;
    font-weight: normal;
    color: var(--link);
    text-decoration: underline;
    margin-left: 6px;
}
.page-head__title .profile-link:hover { color: var(--ink); }

/* -- the season table (14b) and a player's events (14c) -- */

.scores__head--table,
.scores__row--table { grid-template-columns: 46px 1fr 84px 84px 84px 84px 92px; }

.scores__head--events,
.scores__row--events { grid-template-columns: 1fr 128px 96px 96px; }

/* The rank column sits ahead of the name and is quieter than it, the same
 * relationship the finishing position has on a result. */
.scores__rank {
    font-size: 11px;
    color: #999999;
    text-align: right !important;
}

/* Whichever column the table is ordered by. Design marks it, and it is worth
 * marking: five numeric columns look alike, and the one that explains the row
 * order should not have to be inferred from the filter bar. */
.is-sorted { color: var(--ink); font-weight: bold; }

/* -- a player's record (14c) -- */

/* Two columns: the two finish breakdowns stack on the left, the summary sits
 * beside them. Not three equal columns -- the finishes are the same kind of
 * thing as each other and a different kind from the summary, and stacking them
 * says so. */
.rec {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    align-items: start;
    gap: 16px;
    margin-bottom: 18px;
}
.rec__col { display: flex; flex-direction: column; gap: 16px; }

/* Solid, not the tile showing through.
 *
 * Design leaves these panels transparent, and on a mockup that is fine. On the
 * real page the MTMG tile runs behind them, and a tile behind a bordered box
 * full of ruled rows is three patterns competing in one small space. The panel
 * fills instead, so the tile frames the content rather than showing through it,
 * and the rules inside have a plain ground to sit on. */
.rec__panel {
    border: 1px solid var(--rule);
    background: var(--panel);
}

/* A navy bar with yellow on it, which is Design 14c and is what the rest of the
 * site already does -- the listing header, the summary line above a result, the
 * table head. A panel heading in plain yellow read as a different vocabulary on
 * a page that had no need of one. */
.rec__head {
    background: var(--navy);
    color: var(--ink);
    padding: 8px 12px;
    font-size: 13px;
    font-weight: bold;
}
.rec__line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
    color: var(--link);
    padding: 7px 12px;
    border-bottom: 1px solid #202020;
}
.rec__line:last-child { border-bottom: 0; }
.rec__line > span:last-child { color: var(--ink); white-space: nowrap; }

/* The count is the evidence and the share is the reading, so the fraction is
 * the brighter of the two and the percentage trails it. */
.rec__pct { color: var(--link); padding-left: 5px; font-weight: normal; }

/* A note under a panel rather than a row in it -- it is a sentence, not a
 * measurement, and giving it a value column would misrepresent it. */
.rec__note {
    font-size: 12px;
    line-height: 1.6;
    color: #999999;
    padding: 9px 12px 0;
}

@media (max-width: 720px) {
    .scores__head--table,
    .scores__row--table { grid-template-columns: 38px 1fr 46px 60px 52px 40px 52px; }
    .scores__head--events,
    .scores__row--events { grid-template-columns: 1fr 88px 60px 60px; }
}

/* Each event on the season list, separated so the tables do not run together. */
.tourney-event { margin-bottom: 26px; }
.tourney-event:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------ replays -- */

/* Design's turn 15a. Eleven videos and no database.
 *
 * The point of the rebuild is what is NOT here: eleven <iframe>s. Each card
 * shows the video's own still from img.youtube.com and creates the player only
 * when someone clicks it, so the page costs one image each instead of eleven
 * connections to YouTube on every load. */

.replays__say {
    font-size: 13px;
    line-height: 1.7;
    color: var(--link);
    max-width: 760px;
    margin: 0 auto 18px;
    text-align: center;
}
.replays__none { font-size: 13px; color: var(--link); text-align: center; }
.replays__none a { color: var(--ink); }

/* Sized so a card is worth looking at.
 *
 * Design lays these out as repeat(3, 1fr) on a 1280px page, which is about
 * 400px a card -- the still is the whole point, and below roughly that you
 * cannot tell one dirt track from another. auto-fill with a 400px floor keeps
 * that size and still reflows: three across at 1280, more on a wide monitor
 * rather than the eight tiny ones a 300px floor was packing in.
 */
.replays {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
    gap: 16px;
}

.replay {
    border: 1px solid var(--rule);
    background: var(--bar-soft);
}

/* 16/9 so the poster and the player that replaces it are the same size and the
 * grid does not jump when one becomes the other. */
.replay__poster,
.replay__frame {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    border-bottom: 1px solid var(--rule);
    background: #000000;
}
.replay__poster { position: relative; }
/* hqdefault is 4:3 with the video letterboxed inside it, so cover crops the
 * bars away rather than showing black above and below the still. */
.replay__poster img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.replay__play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 34px;
    color: #FFFFFF;
    text-shadow: 0 0 14px rgba(0, 0, 0, 0.9);
    opacity: 0.82;
}
.replay__poster:hover .replay__play { opacity: 1; color: var(--ink); }

.replay__body { padding: 10px 12px 11px; }
.replay__title { font-size: 14px; font-weight: bold; color: var(--ink); }

.replay__meta {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 11px;
    color: #999999;
    padding-top: 4px;
}
.replay__meta a { color: var(--link); }
.replay__meta a:hover { color: var(--ink); }
.replay__by { color: #999999; }

/* ------------------------------------------------------- kmaster tools -- */

/* Design's turns 16a to 16e. Four of Kmaster's tools, one page each plus a
 * landing page.
 *
 * The row between them is the only way from one to the next -- kmaster/menu.dat
 * lists "Kmaster's Utilities" once and does not name the tools -- so it moves
 * out of the <center> block it lived in and becomes navigation proper, in the
 * same bracket vocabulary the archive footers use. */

.kmaster-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 0;
    font-size: 12px;
    padding: 0 0 16px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 18px;
}
.kmaster-nav a          { color: var(--link); text-decoration: none; padding: 0 8px; }
.kmaster-nav a:hover    { color: var(--ink); }
.kmaster-nav .is-here   { color: var(--ink); padding: 0 8px; }
.kmaster-nav .bracket   { color: var(--link); padding: 0 8px; }
.kmaster-nav .sep       { color: var(--rule); }

/* The pages themselves: a heading, a paragraph, a list of features or
 * limitations, repeated. The old markup did headings with <font size="+2"> and
 * lists with "- item<br>", so both are real elements now and the spacing comes
 * from the stylesheet rather than from stacked <br>s. */
.mtmg-body h2 {
    font-size: 17px;
    font-weight: bold;
    color: var(--ink);
    margin: 26px 0 8px;
}
.mtmg-body h2:first-child { margin-top: 0; }

.mtmg-body ul {
    margin: 0 0 4px;
    padding-left: 18px;
    list-style-type: square;
    color: var(--rule);          /* the marker; the text sets its own colour */
}
.mtmg-body li {
    color: var(--link);
    font-size: 13px;
    line-height: 1.6;
    margin-bottom: 3px;
}

/* ---------------------------------------------------- mtmg utilities -- */

/* Design's turn 17a. Forty-six downloads doing four different jobs.
 *
 * The source was three stacked tables with nothing tying them together, and the
 * generations mixed into the first: Winpod32 marked "(recommended version!)"
 * with plain Winpod nineteen rows above it, and Traxx three times over. So the
 * grouping carries the information the alphabetical list could not. */

/* The page title and its search, the row every other section has. This page
 * had no title of its own -- it went straight from the guild banner into a
 * paragraph, so nothing on screen said what you were looking at. */
.util__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    /* Ruled above and below, so the title and its search read as one band the
     * way .page-head does elsewhere. Pulled out to the full width of the body
     * with negative margins -- the band spans the column, the padding puts the
     * words back where the content sits. */
    margin: -22px -24px 22px;
    padding: 14px 24px;
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
}
.util__bar h1 {
    font-size: 21px;
    font-weight: bold;
    color: var(--ink);
    margin: 0;
}

.util__say {
    font-size: 13px;
    line-height: 1.7;
    color: var(--link);
    max-width: 720px;
    margin: 0 0 24px;
}
.util__say b { color: var(--ink); }

.util { margin-bottom: 28px; }
.util:last-child { margin-bottom: 0; }

.util__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 2px;
}
.util__head h2 {
    font-size: 17px;
    font-weight: bold;
    color: var(--ink);
    margin: 0;
}
/* What the group means, beside the name rather than under it -- these headings
 * need a qualifier to be useful ("Legacy" alone reads as "broken") and a
 * qualifier that needs its own line reads as body copy. */
.util__note { font-size: 12px; color: #999999; }
.util__count {
    margin-left: auto;
    font: 11px var(--font-label);
    color: var(--muted);
}

.util__rows { display: block; }

/* Name, description, size. The size is last and narrow because it is the least
 * of the three -- the source put it inside the name, in brackets, which is why
 * every row read "Winpod32 (78k)" before the eye reached the description. */
.util__row {
    display: grid;
    grid-template-columns: 268px 1fr 90px;
    align-items: baseline;
    border-bottom: 1px solid var(--rule);
    font-size: 13px;
}
.util__row > div { padding: 8px 12px; }
.util__row:last-child { border-bottom: 0; }

/* The column header, navy, the same bar the listings and the tourney tables
 * use. Without it the first row of a group had nothing above it saying which
 * column was which -- and the size column in particular is unreadable as a
 * bare number in the right margin. */
.util__row--head {
    background: var(--navy-deep);
    color: var(--on-navy);
    font-size: 12px;
    font-weight: bold;
    border-bottom: 0;
}
.util__row--head > div:last-child { text-align: right; }

.util__name a { color: var(--ink); text-decoration: none; }
.util__name a:hover { text-decoration: underline; }
/* Says what the link is, not how big it is -- these three point at a page. */
.util__islink { font-size: 11px; color: #999999; padding-left: 4px; }

.util__desc { color: var(--link); line-height: 1.55; }
.util__size { color: #999999; text-align: right; white-space: nowrap; font-size: 12px; }

.util__also {
    font-size: 12px;
    line-height: 1.7;
    color: var(--link);
    margin: 14px 0 0;
    padding: 12px 14px;
    border: 1px solid var(--ink);
    background: var(--panel);
}
.util__also a { color: var(--ink); }

@media (max-width: 640px) {
    .util__row { grid-template-columns: 1fr 70px; }
    /* The description drops under the name rather than being squeezed to a
     * column too narrow to read. */
    .util__desc { grid-column: 1 / -1; padding-top: 2px; }
}

/* "1.5.12 is newer." -- the pointer to a current version, on the rows the
 * source says are superseded. Yellow because it is the one thing on a legacy
 * row that changes what you do next: everything else on the row describes the
 * program, this says do not take it. */
.util__newer { color: var(--ink); }

/* ----------------------------------------------------------- inventory -- */

/* Turn 18a. The 2004 index of the download folders, which is mostly a list of
 * things that are gone. In the original a lost file was pink italic text with
 * its link commented out -- indistinguishable from a styling quirk. Here the
 * three states are marked, counted and filterable, and a missing row carries
 * the one action that can fix it. */

/* The ask, and the reason the page exists. Yellow border because it is the
 * only thing on the page that is addressed to the reader rather than
 * describing a file -- the same weight .util__also has, turned up one step. */
.inv__ask {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 14px 20px;
    border: 1px solid var(--ink);
    background: var(--panel);
    padding: 14px 16px;
    margin: 0 0 22px;
}
.inv__ask-say {
    font-size: 12px;
    line-height: 1.7;
    color: var(--link);
    max-width: 760px;
}
.inv__ask-say b { display: block; font-size: 14px; color: var(--ink); margin-bottom: 4px; }

/* The count on a filter chip. Dimmer than the label so the row reads as words
 * first and numbers second. */
.inv__tally { color: var(--muted); }
.btn--on .inv__tally { color: var(--on-navy); }

/* The four source files, which is the only loss on this page that is final.
 * Everything else is a program somebody somewhere may still have on a disk. */
.inv__lost {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 24px;
    border: 1px solid var(--rule);
    background: var(--bar-soft);
    padding: 12px 15px;
    margin: 0 0 22px;
    font-size: 12px;
    color: var(--link);
}
.inv__lost b { color: var(--ink); }

/* A filename quoted in running text. */
.inv__file { font: 11.5px var(--font-label); color: var(--link); }

.inv { margin-bottom: 26px; }
.inv:last-of-type { margin-bottom: 0; }

.inv__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 2px;
}
.inv__head h2 {
    font: bold 15px var(--font-label);
    color: var(--ink);
    margin: 0;
}
.inv__head .btn { margin-left: auto; padding: 4px 10px; }

/* Mark, file, description, action. The mark column is narrow and first because
 * it is what the eye scans down -- the whole page is a question about which
 * rows are which. */
.inv__row {
    display: grid;
    grid-template-columns: 30px 300px 1fr 118px;
    align-items: baseline;
    border-bottom: 1px solid var(--rule-soft);
    font-size: 13px;
}
.inv__row > div { padding: 8px 10px; }
.inv__row:last-child { border-bottom: 0; }
/* The header row carries .util__row--head as well, which supplies the navy
 * fill and the right-aligned last column; nothing extra is needed here. */

/* Filled for a file that is there, hollow for one that is not. A shape rather
 * than a colour, so the state survives being printed, being read by someone
 * who cannot separate the greys, and being glanced at. */
.inv__mark { color: var(--muted); font-size: 11px; }
.inv__row:not(.inv__row--gone) .inv__mark,
.inv__mark--here { color: var(--ink); }

.inv__name { font: 12px var(--font-label); word-break: break-all; }
.inv__name a { color: var(--ink); text-decoration: none; }
.inv__name a:hover { text-decoration: underline; }
/* A missing name is not a link and should not look like one. Dimmed rather
 * than struck through: the file is not cancelled, it is wanted. */
.inv__row--gone .inv__name { color: var(--link); }

.inv__desc { color: var(--link); line-height: 1.55; }

/* On the shelf, but the 2004 index never knew about it. Not a fourth state --
 * the file is there like any other -- so it is a tag on the row rather than a
 * different mark in the margin. */
.inv__tag {
    font: 10px var(--font-label);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px solid var(--rule-soft);
    padding: 1px 5px;
    white-space: nowrap;
}

.inv__star { color: var(--ink); font-size: 11px; }

/* Size for a file that is here; the one thing you can do about one that is
 * not. Right-aligned so the column reads as a single answer to "have it?". */
.inv__act { text-align: right; color: var(--muted); font-size: 12px; white-space: nowrap; }
.inv__send {
    color: var(--ink);
    text-decoration: none;
    font-size: 12px;
    border: 1px solid var(--ink);
    padding: 3px 10px;
}
.inv__send:hover { color: #000000; background: var(--ink); }

.inv__foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px 16px;
    border-top: 1px solid var(--rule);
    margin-top: 22px;
    padding-top: 13px;
    font-size: 12px;
    color: var(--link);
}
.inv__foot .inv__tag { text-transform: none; letter-spacing: 0; }
.inv__by { color: var(--muted); font-size: 11px; }

.inv__also {
    font-size: 12px;
    line-height: 1.9;
    color: var(--link);
    margin: 14px 0 0;
}

@media (max-width: 720px) {
    /* Mark and name stay on the first line with the action; the description
     * drops under them rather than being squeezed to a column too narrow to
     * read, the same way the utilities rows fold. */
    .inv__row { grid-template-columns: 30px 1fr 96px; }
    .inv__desc { grid-column: 2 / -1; padding-top: 0; }
    .inv__row.util__row--head > div:nth-child(3) { display: none; }
}

/* The search sits in the filter row rather than up in the title bar, because
 * on this page it is a filter: it narrows the same list that Show and Folder
 * narrow, and the three read as one control strip. (Utilities keeps its search
 * in the title bar -- there the list is short and ungrouped, and there is no
 * filter row for it to join.) */
/* Takes the free end of the row, and shrinks rather than wraps: at 22 folder
 * names in the select plus four Show chips the row is within about ten pixels
 * of full, so a fixed-width search drops to a second line on the default
 * window and looks like it belongs to something else. */
.inv__search      { margin-left: auto; flex: 1 1 180px; max-width: 300px; }
.inv__search input { width: 100%; min-width: 0; }

/* ------------------------------------------------------- stock settings -- */

/* settings.php. Three sections, one per difficulty class, each a navy-headed
 * .rows table -- the same shape the utilities groups and the tourney tables
 * use, so a page Design never drew still reads as part of the site.
 *
 * Modelled on .util__head rather than inventing a third heading style: the
 * qualifier beside the name is doing the same job there and here, saying what
 * the section holds before you read it. Rookie has three lap times and no
 * setups at all, and that has to be legible from the heading. */
.stock { margin-bottom: 26px; }
.stock:last-of-type { margin-bottom: 0; }

.stock__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 2px;
}
.stock__head h2 {
    font-size: 17px;
    font-weight: bold;
    color: var(--ink);
    margin: 0;
}

/* The Garage cell carries a title spelling the shorthand out -- "1400 ms" is
 * opaque until somebody tells you it means 1400 gears, medium tyres, soft
 * suspension. The dotted underline is the only hint that hovering says more. */
.stock .num span[title] {
    border-bottom: 1px dotted var(--rule);
    cursor: help;
}

/* A label whose value is a short list, one entry per line.
 *
 * The pod list on a multi-pod download used to carry <br> in the database;
 * migration 020 took it out and left newlines, so the value is plain text that
 * escapes like any other label and the browser draws the breaks. pre-line, not
 * pre: runs of spaces still collapse, which is what keeps the old &nbsp;
 * padding from reappearing as gaps. */
.fact__lines { white-space: pre-line; }

/* ------------------------------------------------------------- profiles -- */

/* Lists, profiles and the account page. Turn 20.
 *
 * Deliberately thin: a list renders in the archive's own .rows table, so it
 * looks like the listing it came from rather than like a new kind of page. */
.plist { margin-bottom: 26px; }

/* Section rhythm for things that are NOT a .plist.
 *
 * .plist carries the 26px, so anything standing between two sections without
 * being one butts straight against the next heading. Two turned up: the New
 * list form on a profile, and the "signed in as" bar on account.php.
 *
 * One utility rather than a modifier per element. The first version of this
 * was .filters--section, which would have wanted a .summary--section beside it
 * the moment the second case appeared -- two names for one measurement, and a
 * third the next time. The class says what it does, so it reads the same
 * wherever it lands.
 *
 * Deliberately NOT applied by a selector like `.listing > .summary`, which
 * would catch every standalone summary on the site: on list.php the count line
 * is a direct child of .listing and sits immediately above its own table, where
 * 26px would push a heading away from the thing it heads. This is opt-in
 * because the answer differs per case. */
.section-gap { margin-bottom: 26px; }

/* A confirmation's single action, on the same axis as the question it answers.
 *
 * .summary above and below it is centred text, so a left-aligned button between
 * them reads as belonging to neither. The listings' .filters bar is left-
 * aligned for good reason -- it holds a row of controls that scan left to right
 * -- but one button answering one question is not that. */
.confirm { text-align: center; padding: 16px 18px; }

/* The shareable profile address. Rendered as text you select and copy rather
 * than behind a copy button: a button needs the clipboard API and a fallback
 * for when it is refused, and the whole point of this line is that the URL is
 * short enough to read and retype if it comes to that.
 *
 * user-select: all so one click takes the whole thing -- a URL with a query
 * string is exactly what double-click-to-select-a-word gets wrong. */
.share-url {
    font: 12px var(--font-label);
    color: var(--ink);
    background: var(--bar-soft);
    border: 1px solid var(--rule);
    padding: 1px 6px;
    user-select: all;
}
/* Borrows .vis -- same 11px label chip as the visibility switches, so a control
 * that does something on click looks like the other controls that do something
 * on click. Only the gap is new; it is inserted by script directly after the
 * URL and would otherwise touch it. */
.share-copy { margin-left: 8px; }
.plist__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 2px;
}
.plist__head h2 { font-size: 17px; font-weight: bold; color: var(--ink); margin: 0; }

/* The visibility badge. Navy when public, because it is the state worth
 * noticing -- "Only me" is the default and should sit back. */
.vis {
    font: 11px var(--font-label);
    padding: 2px 8px;
    border: 1px solid var(--rule);
    text-decoration: none;
    color: var(--link);
    /* A <button> gets the arrow cursor by default, not the hand -- so this
     * offered no hover feedback whatsoever. In the list table that is
     * survivable: the buttons sit under a "Who can see it" heading, in their
     * own column, and the column says what they are.
     *
     * On account.php the same control sits INLINE inside a sentence -- "your
     * tournament record is visible to [only you]" -- where a transparent 11px
     * grey-bordered chip with no pointer reads as part of the prose. The site
     * owner could not find it at all, and it was the only way to turn that
     * record on. */
    cursor: pointer;
    /* And a <button> with no background paints the BROWSER'S default, which on
     * a black site is a pale grey box that matches nothing else on the page --
     * .btn above sets `background: transparent` for exactly this reason and
     * .vis simply never did. It showed up worst on the navy summary bar beside
     * the share URL, where the site owner said the control was hard to read as
     * a control at all.
     *
     * --bar-soft rather than transparent: on a black row it is within five
     * values of the background, so the border does the work exactly as it does
     * for .btn -- but on the navy .summary bar it reads as a dark chip beside
     * the dark URL chip, and the two look like one control and its label
     * instead of a hole punched in the bar. */
    background: var(--bar-soft);
}
.vis--public { background: var(--navy-deep); color: var(--on-navy); border-color: var(--rule); }
/* Hover LAST, after .vis--public.
 *
 * The two are the same specificity, so whichever comes second wins. With hover
 * written first, .vis--public overrode both of its declarations and the navy
 * "Everyone" buttons had no hover feedback whatsoever -- the state that most
 * needs it, since those are the ones already carrying a filled background and
 * so looking least like something you can press.
 *
 * The state is carried by colour alone, so hover has to move something or a
 * control that already looks like a label keeps feeling like one. --ink on navy
 * is the site's own high-contrast pair, so this reads in both states. */
.vis:hover { border-color: var(--link); color: var(--ink); }
