/*
 * Plain stylesheet, custom properties, no framework -- see docs/CONVENTIONS.md.
 * Kept deliberately small: the map and chart pages of the next milestones will add their
 * own rules, not rewrite these.
 */

:root {
    /* Tells the browser to paint its own widgets -- selects, checkboxes, scrollbars -- in
       the scheme in force. Without it they stay light on a dark page. */
    color-scheme: light dark;

    --colour-bg: #fbfaf8;
    --colour-surface: #ffffff;
    --colour-text: #1b1b1b;
    --colour-muted: #5f5f5f;
    --colour-accent: #1f6f4a;
    --colour-error: #a52222;
    --colour-border: #dcd9d2;
    --radius: 6px;
    --spacing: 1rem;
    --measure: 34rem;

    /* One colour per chart. uPlot is handed these rather than reading the stylesheet, so
       they have to exist as custom properties in both themes. */
    --chart-ele: #8a5a2b;
    --chart-speed: #1f6f4a;
    --chart-hr: #a52222;
    --chart-cad: #4a4ea5;
    --chart-pwr: #7a3f9d;
    --chart-temp: #2b6f8a;
}

@media (prefers-color-scheme: dark) {
    :root {
        --colour-bg: #16181a;
        --colour-surface: #1f2225;
        --colour-text: #ececec;
        --colour-muted: #a3a3a3;
        --colour-accent: #6fc79b;
        --colour-error: #f08a8a;
        --colour-border: #33383d;

        /* Lifted well above the dark ground: the light-theme values are mud on it. */
        --chart-ele: #d79a5b;
        --chart-speed: #6fc79b;
        --chart-hr: #f08a8a;
        --chart-cad: #9aa0ee;
        --chart-pwr: #c391e8;
        --chart-temp: #7fc4de;
    }
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--colour-bg);
    color: var(--colour-text);
    font: 1rem/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

a {
    color: var(--colour-accent);
}

.site-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing);
    padding: var(--spacing);
    border-bottom: 1px solid var(--colour-border);
    background: var(--colour-surface);
}

.site-title {
    font-weight: 600;
    font-size: 1.15rem;
    text-decoration: none;
    letter-spacing: 0.02em;
}

.site-nav {
    display: flex;
    align-items: center;
    gap: var(--spacing);
}

.nav-link {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--colour-accent);
    text-decoration: underline;
    cursor: pointer;
}

.locale-switcher {
    margin: 0;
}

.site-main {
    max-width: var(--measure);
    margin: 0 auto;
    padding: calc(var(--spacing) * 2) var(--spacing);
}

/* The reading measure is 34rem because most pages are prose. The track detail is a map, a
   table and a set of charts, so it opts out -- and it is the only page that does.
   Capped rather than unbounded: on an ultrawide screen a 3 000 px map is not more useful,
   only four times the tiles to fetch from the provider. */
.site-main--wide {
    max-width: 96rem;
}

/* The heading and the states that have nothing to show keep a column they can be read in,
   even on the wide page. */
.site-main--wide .track-heading,
.site-main--wide .track-narrow,
.site-main--wide .track-actions,
.site-main--wide > p {
    max-width: var(--measure);
}

h1 {
    margin-top: 0;
    font-size: 1.5rem;
}

.muted {
    color: var(--colour-muted);
}

.stack {
    display: grid;
    gap: 0.6rem;
    margin-top: calc(var(--spacing) * 1.5);
}

label {
    font-weight: 600;
}

input[type="email"] {
    padding: 0.6rem;
    font: inherit;
    color: inherit;
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}

button[type="submit"] {
    justify-self: start;
    padding: 0.6rem 1.1rem;
    font: inherit;
    color: #ffffff;
    background: var(--colour-accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}

.flash {
    padding: 0.7rem var(--spacing);
    border: 1px solid var(--colour-border);
    border-left-width: 4px;
    border-radius: var(--radius);
    background: var(--colour-surface);
}

.flash--error {
    border-left-color: var(--colour-error);
    color: var(--colour-error);
}

.flash--success {
    border-left-color: var(--colour-accent);
}

.button {
    display: inline-block;
    padding: 0.6rem 1.1rem;
    color: #ffffff;
    background: var(--colour-accent);
    border-radius: var(--radius);
    text-decoration: none;
}

.track-list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.track-list li {
    padding: 0.7rem var(--spacing);
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}

.track-list .muted {
    display: block;
    font-size: 0.9rem;
}

.statistics {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--spacing);
}

.statistics th,
.statistics td {
    padding: 0.45rem 0;
    text-align: left;
    border-bottom: 1px solid var(--colour-border);
}

.statistics th {
    font-weight: 600;
    width: 45%;
}

select,
input[type="file"] {
    padding: 0.5rem;
    font: inherit;
    color: inherit;
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}

.page-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--spacing);
    flex-wrap: wrap;
}

.track-cards {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 0.7rem;
    margin: var(--spacing) 0;
}

.track-card {
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}

.track-card__link {
    display: flex;
    gap: var(--spacing);
    align-items: center;
    padding: 0.7rem var(--spacing);
    color: inherit;
    text-decoration: none;
}

.track-card__link:hover .track-card__name {
    text-decoration: underline;
}

.track-card__shape {
    flex: 0 0 auto;
    color: var(--colour-accent);
    line-height: 0;
}

.thumbnail {
    display: block;
    background: var(--colour-bg);
    border-radius: calc(var(--radius) / 2);
}

.track-card__body {
    display: grid;
    gap: 0.15rem;
    min-width: 0;
}

.track-card__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.track-card__figures {
    font-variant-numeric: tabular-nums;
}

.track-card__failed {
    color: var(--colour-error);
}

.pagination {
    display: flex;
    gap: var(--spacing);
    align-items: center;
    justify-content: center;
    margin-top: calc(var(--spacing) * 1.5);
}

.track-actions {
    margin-top: calc(var(--spacing) * 2);
    padding-top: var(--spacing);
    border-top: 1px solid var(--colour-border);
}

.track-actions h2 {
    font-size: 1rem;
    margin: 0 0 0.6rem;
}

.inline-form {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.8rem;
}

.inline-form input[type="text"] {
    flex: 1 1 14rem;
    padding: 0.5rem;
    font: inherit;
    color: inherit;
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}

.track-actions__links {
    margin: 0 0 0.8rem;
}

button.danger {
    background: none;
    color: var(--colour-error);
    border: 1px solid var(--colour-error);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* One column by default -- a phone, and every viewport too narrow to hold both. */
.track-view {
    display: grid;
    gap: var(--spacing);
    margin: var(--spacing) 0;
}

.map {
    /* The floor, and the whole height until the two columns appear. */
    height: 22rem;
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
    background: var(--colour-surface);
}

.track-view__aside {
    display: grid;
    gap: var(--spacing);
    align-content: start;
}

/* On a phone the summary comes before the charts: the shared cursor means nothing to a
   finger, so the charts are reference material there rather than a companion to the map,
   and scrolling past six of them to read the distance is a poor trade. This is the one
   place where visual order and source order differ. */
@media (max-width: 59.999rem) {
    .track-view__aside .charts {
        order: 2;
    }

    .track-view__aside .statistics {
        order: 1;
    }
}

@media (min-width: 60rem) {
    .track-view {
        /* minmax(0, 1fr), not 1fr: a canvas has an intrinsic width, and uPlot would
           otherwise push its own column wider than the half it was given. */
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        align-items: start;
    }

    /* The map holds still while the column beside it scrolls. A column with its own
       scrollbar was the alternative: it breaks trackpad and keyboard expectations, and the
       page stops being one document. */
    .track-view .map {
        position: sticky;
        top: var(--spacing);
        height: calc(100vh - 9rem);
        min-height: 24rem;
    }
}

.charts {
    display: grid;
    gap: 0.4rem;
}

.chart {
    padding: 0.3rem 0;
}

.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    list-style: none;
    padding: 0;
    margin: 0.4rem 0 0;
}

.tag {
    padding: 0.1rem 0.5rem;
    font-size: 0.85rem;
    color: var(--colour-muted);
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: 999px;
}

.track-description {
    margin: 0.6rem 0 0;
    max-width: var(--measure);
}

.track-heading__links {
    display: flex;
    gap: var(--spacing);
    margin: 0.2rem 0 0;
    font-size: 0.9rem;
}

/* The delete button is set apart rather than sitting in the same column as Save: two
   buttons side by side is how a track gets removed by somebody who meant to rename it. */
.track-danger {
    margin-top: calc(var(--spacing) * 2);
    padding-top: var(--spacing);
    border-top: 1px solid var(--colour-border);
}

.track-danger h2 {
    font-size: 1.1rem;
    margin-top: 0;
}

/* A pair of toggles, not a pair of calls to action: the charts are the content, the axis
   choice is a setting, so it stays quiet until it is the one in force. */
.chart-axis {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    font-size: 0.85rem;
}

.chart-axis__button {
    padding: 0.2rem 0.6rem;
    color: var(--colour-muted);
    background: none;
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
    font: inherit;
    cursor: pointer;
}

.chart-axis__button:hover {
    color: var(--colour-text);
}

.chart-axis__button[aria-pressed='true'] {
    color: var(--colour-text);
    background: var(--colour-surface);
    border-color: var(--colour-muted);
    cursor: default;
}

.chart__caption {
    margin: 0 0 0.1rem;
    font-size: 0.85rem;
}

/* uPlot paints its canvas itself -- axes and grid come from the options the controller
   passes -- but the crosshair and the wrapper are DOM, and its own stylesheet assumes a
   light background. */
.u-cursor-x,
.u-cursor-y {
    border-color: var(--colour-muted) !important;
}

.u-legend {
    display: none;
}

.uplot,
.u-wrap {
    color: var(--colour-text);
}

.chart__caption {
    display: flex;
    justify-content: space-between;
    gap: var(--spacing);
    align-items: baseline;
}

.chart__value {
    color: var(--colour-text);
    font-variant-numeric: tabular-nums;
}

.accounts {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--spacing);
}

.accounts th,
.accounts td {
    padding: 0.45rem 0.4rem;
    text-align: left;
    border-bottom: 1px solid var(--colour-border);
    vertical-align: top;
}

.accounts thead th {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--colour-muted);
}

.accounts__actions {
    display: flex;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.accounts__actions form {
    margin: 0;
}

.danger-link {
    color: var(--colour-error);
}

.checkbox {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 400;
}

.site-main section + section {
    margin-top: calc(var(--spacing) * 2);
}

/* A composed basemap thumbnail. Same box as the inline SVG it replaces, so a row does not
   change height depending on whether the consumer has got to it yet. object-fit because the
   image is 320x180 and shown at half that. */
.thumbnail--map {
    width: 160px;
    height: 90px;
    object-fit: cover;
    border: 1px solid var(--colour-border);
}

.map-attribution {
    font-size: 0.8rem;
    margin-top: var(--spacing);
}

/* The three-point route summary. Three columns on anything wider than a phone, stacked
   below that -- three numbers side by side stop being readable well before they stop
   fitting. */
.route-summary {
    display: grid;
    gap: 0.6rem;
    grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
    margin: var(--spacing) 0 0;
    padding: 0;
}

.route-summary__point {
    padding-left: 0.7rem;
    border-left: 3px solid var(--colour-border);
}

/* The same three colours the maps use, and fixed rather than themed: they mean start,
   turnaround and finish on a composed thumbnail too, and that is a photograph with no
   theme to follow. */
.route-summary__point--start {
    border-left-color: #1f6f4a;
}

.route-summary__point--middle {
    border-left-color: #c77f1f;
}

.route-summary__point--finish {
    border-left-color: #a52222;
}

.route-summary dt {
    font-size: 0.85rem;
    color: var(--colour-muted);
}

.route-summary dd {
    margin: 0;
    font-variant-numeric: tabular-nums;
}

/* The name is the answer and the figure is the qualifier, so the name reads first and the
   figure sits under it. A point no zone claims has no name line at all, and the figure
   simply moves up -- nothing reserves space for a label that may never exist. */
.route-summary__place {
    display: block;
    font-weight: 600;
}

.route-summary__figure {
    display: block;
    font-size: 0.9rem;
    color: var(--colour-muted);
}

/* No zone claimed the point, so there is no name above the figure and the figure is the
   answer rather than the qualifier. :only-child says that without the template having to
   know, and without a second class only one branch would ever set. */
.route-summary__figure:only-child {
    font-size: inherit;
    color: inherit;
}

/* Privacy zones ----------------------------------------------------------- */

.zone-list {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--spacing);
}

.zone-list th,
.zone-list td {
    padding: 0.45rem 0.4rem;
    text-align: left;
    border-bottom: 1px solid var(--colour-border);
    vertical-align: top;
}

.zone-list thead th {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--colour-muted);
}

.zone-list form {
    margin: 0;
}

.zone-picker {
    display: grid;
    gap: var(--spacing);
}

/* Shorter than a track map: this one is a place, not a route, so it needs enough context
   to recognise a street corner and no more. */
.map--picker {
    height: 18rem;
}

.field-row {
    display: grid;
    gap: 0.6rem;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
}

.zone-picker input[type="text"],
.zone-picker input[type="number"] {
    width: 100%;
    padding: 0.5rem;
    font: inherit;
    color: inherit;
    background: var(--colour-surface);
    border: 1px solid var(--colour-border);
    border-radius: var(--radius);
}
