/* Train tracker -- a single service drawn as a vertical time axis.
   Everything is scoped under .tt so it cannot leak into the rest of the site.
   Colours follow the site's Bootstrap palette rather than inventing new ones. */

.tt {
    --tt-text: #212529;
    --tt-muted: #6c757d;
    --tt-faint: #adb5bd;
    --tt-line: #dee2e6;
    --tt-accent: #1b6ec2;
    --tt-accent-soft: #1b6ec21f;
    --tt-ontime: #198754;
    --tt-late: #b45309;
    --tt-track-h: 1250px;
    max-width: 680px;
    margin: 0 auto;
    color: var(--tt-text);
}

/* ---- header ------------------------------------------------------------ */

.tt-header {
    border-bottom: 1px solid var(--tt-line);
    padding-bottom: 16px;
}

.tt-headline {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}

.tt-headcode {
    font: 600 20px/1 ui-monospace, "Cascadia Mono", Consolas, monospace;
    letter-spacing: .04em;
}

.tt-operator {
    color: var(--tt-muted);
    font-size: 14px;
}

.tt-journey {
    margin-top: 4px;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -.01em;
}

.tt-arrow {
    color: var(--tt-faint);
    font-weight: 400;
    margin: 0 6px;
}

.tt-status-row {
    margin-top: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.tt-pill {
    display: inline-flex;
    align-items: center;
    padding: 5px 11px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    border: 1px solid transparent;
}

.tt-ontime {
    color: #0f5132;
    background: #d1e7dd;
    border-color: #badbcc;
}

.tt-late {
    color: #664d03;
    background: #fff3cd;
    border-color: #ffecb5;
}

.tt-idle {
    color: var(--tt-muted);
    background: #f8f9fa;
    border-color: var(--tt-line);
}

.tt-badge {
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--tt-muted);
    border: 1px solid var(--tt-line);
    padding: 4px 9px;
    border-radius: 5px;
}

/* Simulated data must never be mistaken for a real train. */
.tt-badge.tt-sim {
    color: #664d03;
    border-color: #ffecb5;
    background: #fff8e5;
}

/* ---- the timeline ------------------------------------------------------ */

.tt-timeline {
    position: relative;
    height: var(--tt-track-h);
    margin-top: 30px;
}

/* Keep in step with the middle grid column below: the rail's centre line (left
   + half its width) must equal that column's centre, or the dots drift off it. */
.tt-rail,
.tt-rail-fill {
    position: absolute;
    left: 108px;
    width: 4px;
    border-radius: 2px;
}

.tt-rail {
    top: 0;
    bottom: 0;
    background: var(--tt-line);
}

.tt-rail-fill {
    top: 0;
    height: calc(var(--tt-progress, 0) * 100%);
    background: var(--tt-accent);
    transition: height 900ms cubic-bezier(.4, 0, .2, 1);
}

.tt-stop {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(var(--tt-p) * 100%);
    transform: translateY(-50%);
    display: grid;
    /* The middle column is sized to contain the largest thing drawn on the rail
       -- the 62px ?trainicon= marker -- so nothing overhangs into the times. */
    grid-template-columns: 78px 64px 1fr;
    align-items: center;
}

.tt-times {
    text-align: right;
    padding-right: 4px;
    line-height: 1.2;
}

.tt-time {
    font: 600 15px/1.2 ui-monospace, "Cascadia Mono", Consolas, monospace;
}

/* A forecast, not a reported time. */
.tt-time.tt-est {
    color: var(--tt-muted);
    font-weight: 500;
}

.tt-time.tt-late-time {
    color: var(--tt-late);
}

.tt-sched {
    font: 400 12px/1.3 ui-monospace, "Cascadia Mono", Consolas, monospace;
    color: var(--tt-faint);
    text-decoration: line-through;
}

.tt-dot-cell {
    display: flex;
    justify-content: center;
}

.tt-dot {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid var(--tt-line);
    transition: background 400ms, border-color 400ms;
}

.tt-stop.departed .tt-dot,
.tt-stop.at .tt-dot {
    background: var(--tt-accent);
    border-color: var(--tt-accent);
}

.tt-stop.next .tt-dot {
    border-color: var(--tt-accent);
    animation: tt-pulse 2s ease-in-out infinite;
}

.tt-stop.terminus .tt-dot {
    width: 15px;
    height: 15px;
}

@keyframes tt-pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--tt-accent-soft); }
    50%      { box-shadow: 0 0 0 7px transparent; }
}

.tt-label {
    padding-left: 6px;
    min-width: 0;
}

.tt-name {
    font-size: 15px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--tt-muted);
    transition: color 400ms;
}

.tt-stop.departed .tt-name,
.tt-stop.at .tt-name {
    color: var(--tt-text);
}

.tt-stop.next .tt-name {
    color: var(--tt-text);
    font-weight: 600;
}

.tt-stop.terminus .tt-name {
    font-weight: 600;
}

.tt-meta {
    font-size: 12px;
    color: var(--tt-faint);
    margin-top: 1px;
}

/* ---- the train --------------------------------------------------------- */

.tt-train {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(var(--tt-progress, 0) * 100%);
    transform: translateY(-50%);
    /* The stop rows are appended after this element, so without a z-index the
       station dots paint over the marker -- obvious once it became a photo. */
    z-index: 2;
    display: grid;
    grid-template-columns: 78px 64px 1fr;
    align-items: center;
    pointer-events: none;
    transition: top 900ms cubic-bezier(.4, 0, .2, 1);
}

.tt-train-dot {
    grid-column: 2;
    justify-self: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--tt-accent);
    border: 3px solid #fff;
    box-shadow: 0 0 0 2px var(--tt-accent);
}

/* The ?trainicon= photo, standing in for the dot. 56px plus a 3px ring is 62px,
   which is what the middle grid column is sized to hold -- change one and change
   the other, or the marker starts overhanging the times again. */
.tt-train-avatar {
    grid-column: 2;
    justify-self: center;
    display: block;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    /* Sources are meant to be square; cover keeps a stray one from distorting. */
    object-fit: cover;
    background: #fff;
    border: 3px solid #fff;
    box-shadow: 0 0 0 2px var(--tt-accent), 0 2px 10px #0000002e;
}

.tt-train-chip {
    grid-column: 3;
    justify-self: end;
    background: #fff;
    border: 1px solid var(--tt-accent);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 12px;
    font-weight: 600;
    color: var(--tt-accent);
    white-space: nowrap;
}

/* ---- footer ------------------------------------------------------------ */

.tt-footer {
    margin-top: 40px;
    padding-top: 14px;
    border-top: 1px solid var(--tt-line);
    font-size: 12px;
    color: var(--tt-muted);
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

.tt-error {
    margin-top: 16px;
    font-size: 13px;
}

@media (max-width: 520px) {
    .tt {
        --tt-track-h: 1500px;
    }

    /* Same relationship at the narrow size: 44px + 3px ring = 50px, so the
       column is 52px and the rail centres on it at 86 + 2 = 88. */
    .tt-stop,
    .tt-train {
        grid-template-columns: 62px 52px 1fr;
    }

    .tt-rail,
    .tt-rail-fill {
        left: 86px;
    }

    .tt-train-avatar {
        width: 44px;
        height: 44px;
    }

    .tt-train-chip {
        display: none;
    }
}

/* ---- train finder ------------------------------------------------------ */

.tf {
    --tf-muted: #6c757d;
    --tf-faint: #adb5bd;
    max-width: 860px;
    margin: 0 auto;
}

.tf-title {
    margin-bottom: 2px;
    font-weight: 600;
}

.tf-arrow {
    color: var(--tf-faint);
    font-weight: 400;
    margin: 0 4px;
}

.tf-sub {
    color: var(--tf-muted);
    font-size: 13px;
}

.tf-form {
    margin: 0 0 18px;
    padding-bottom: 16px;
    border-bottom: 1px solid #dee2e6;
}

.tf-label {
    font-size: 12px;
    color: var(--tf-muted);
    margin-bottom: 2px;
}

.tf-table {
    font-size: 14px;
}

.tf-table .tf-time {
    font: 600 14px/1.2 ui-monospace, "Cascadia Mono", Consolas, monospace;
    white-space: nowrap;
}

/* The booked time, when the train is not keeping to it. */
.tf-sched {
    display: block;
    font: 400 11px/1.3 ui-monospace, "Cascadia Mono", Consolas, monospace;
    color: var(--tf-faint);
    text-decoration: line-through;
}

/* The uid is the durable key; the headcode is only a label. */
.tf-uid {
    display: block;
    font: 400 11px/1.3 ui-monospace, "Cascadia Mono", Consolas, monospace;
    color: var(--tf-faint);
}

/* Status lozenges. Same palette as the tracker's .tt-pill so the two pages
   read as one system; colour alone never carries the meaning -- the text says
   it too. */
.tf-status {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
    white-space: nowrap;
}

.tf-status-ontime {
    color: #0f5132;
    background: #d1e7dd;
    border-color: #badbcc;
}

.tf-status-late {
    color: #664d03;
    background: #fff3cd;
    border-color: #ffecb5;
}

.tf-status-early {
    color: #055160;
    background: #cff4fc;
    border-color: #b6effb;
}

/* Already gone and unremarkable -- deliberately the quietest of the set. */
.tf-status-departed {
    color: #495057;
    background: #f1f3f5;
    border-color: #dee2e6;
}

.tf-status-cancelled {
    color: #842029;
    background: #f8d7da;
    border-color: #f5c2c7;
}

.tf-note,
.tf-credit {
    font-size: 12px;
    color: var(--tf-muted);
}

/* Narrow views: shed columns rather than let .table-responsive turn the board
   into a side-scroller. Dropped in order of how little they carry -- Operator
   is very often the same value down the whole board, and Towards is context
   rather than something you act on. Departs / Service / Plat / Status stay at
   every width, because that is the board's actual job. */
@media (max-width: 700px) {
    .tf-c-operator {
        display: none;
    }
}

@media (max-width: 560px) {
    .tf-c-towards {
        display: none;
    }
}

/* ---- station boxes ------------------------------------------------------ */

.tf-station {
    width: 210px;
    max-width: 100%;
}

/* Narrow views: the two station boxes take a full row each, and so does the
   list under them. */
@media (max-width: 560px) {
    .tf-form .col-auto:has(.tf-station) {
        flex: 1 1 100%;
    }

    .tf-station {
        width: 100%;
    }
}
