/* =========================================================================
   Fonts — self-hosted (IBM Plex, SIL OFL 1.1) so the app works fully offline.
   ========================================================================= */
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-400.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-500.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-600.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/ibm-plex-sans-latin-700.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/ibm-plex-mono-latin-400.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/ibm-plex-mono-latin-500.woff2') format('woff2');
}

/* =========================================================================
   Design tokens — the single source of truth for colour.
   Never hardcode a colour in a component; always use var(--*).
   ========================================================================= */
:root, [data-theme="dark"] {
    --bg: #0A1526;
    --surface: #101E36;
    --surface-2: #152540;
    --border: #1E3155;
    --text: #E9F0FA;
    --text-2: #A3B6D2;
    --muted: #6E85A6;
    --accent: #3B82F6;
    --accent-2: #60A5FA;
    --accent-wash: rgba(59, 130, 246, 0.15);
    --ok: #34D399;
    --ok-wash: rgba(52, 211, 153, 0.14);
    --muted-wash: rgba(110, 133, 166, 0.16);
    --track: #1B2E4E;
    --shadow: 0 20px 50px rgba(2, 7, 18, 0.5);
}

[data-theme="light"] {
    --bg: #F1F5FB;
    --surface: #FFFFFF;
    --surface-2: #F5F8FD;
    --border: #DCE6F3;
    --text: #0B1B33;
    --text-2: #3C5478;
    /* Darkened deliberately to clear 4.5:1 on white — do not lighten. */
    --muted: #5A6F8F;
    --accent: #1D4ED8;
    --accent-2: #2563EB;
    --accent-wash: rgba(29, 78, 216, 0.09);
    --ok: #0F9D6E;
    --ok-wash: rgba(15, 157, 110, 0.10);
    --muted-wash: rgba(114, 136, 168, 0.12);
    --track: #E1EAF6;
    --shadow: 0 20px 44px rgba(15, 38, 74, 0.13);
}

/* =========================================================================
   Base
   ========================================================================= */
* { box-sizing: border-box; }

html { background: var(--bg); }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: 'IBM Plex Sans', system-ui, sans-serif;
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-2); text-decoration: underline; }
input, button { font-family: inherit; }

.tc-app { min-height: 100vh; background: var(--bg); color: var(--text); font-size: 14px; }

/* Every number, size, rate and magnet string uses the mono face. */
.tc-mono { font-family: 'IBM Plex Mono', monospace; }
.tc-num { font-variant-numeric: tabular-nums; }

.tc-sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

@keyframes pop {
    from { opacity: 0; transform: translateY(12px) scale(.985); }
    to { opacity: 1; transform: none; }
}

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

/* =========================================================================
   Header
   ========================================================================= */
.tc-header {
    display: flex;
    align-items: center;
    gap: 16px;
    height: 64px;
    padding: 0 24px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 20;
}

.tc-brand { display: flex; align-items: center; gap: 10px; }

.tc-logo {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: var(--accent);
    /* The mark is always white on accent, in both themes. */
    color: #fff;
    display: grid;
    place-items: center;
    flex: none;
}

.tc-wordmark { display: flex; flex-direction: column; line-height: 1.15; }
.tc-wordmark-name { font-size: 15px; font-weight: 700; letter-spacing: -0.2px; }
.tc-wordmark-sub { font-size: 10.5px; color: var(--muted); letter-spacing: 0.3px; }

.tc-header-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.tc-rates {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-right: 6px;
    font-size: 13px;
}

.tc-rate-down { color: var(--accent-2); }
.tc-rate-up { color: var(--ok); }

/* On a phone the header has to fit a wordmark, transfer rates and three buttons across ~375px,
   and by default nothing yields: the name wraps to four lines and the rates break mid-unit.
   The tagline carries no information, so it goes first; the rest is made to stop wrapping. */
@media (max-width: 600px) {
    .tc-wordmark-sub { display: none; }

    .tc-wordmark-name {
        font-size: 13px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* min-width:0 lets the name ellipsis instead of wrapping, but on its own it also lets the
       brand collapse to nothing. flex:1 claims the leftover space so the name keeps priority
       over the controls, which size themselves and must not shrink. */
    .tc-brand { flex: 1 1 auto; min-width: 0; }
    .tc-wordmark { min-width: 0; }

    .tc-header { padding: 0 12px; gap: 8px; }
    .tc-header-right { gap: 6px; flex-shrink: 0; }

    /* The global transfer rates are the one thing here that is also shown per torrent on every
       card, so they are what gives way rather than the app's own name. */
    .tc-rates { display: none; }
}


.tc-icon-btn {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    display: grid;
    place-items: center;
    cursor: pointer;
}

.tc-icon-btn:hover { color: var(--text); border-color: var(--accent); }

.tc-btn-primary {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    padding: 0 16px;
    border-radius: 10px;
    border: none;
    background: var(--accent);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.tc-btn-primary:hover { background: var(--accent-2); }

/* =========================================================================
   Content column
   ========================================================================= */
.tc-content {
    max-width: 880px;
    margin: 0 auto;
    padding: 28px 24px 48px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

/* =========================================================================
   Filter + search row
   ========================================================================= */
.tc-filterbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.tc-chips { display: flex; gap: 6px; }

.tc-chip {
    display: flex;
    align-items: center;
    gap: 7px;
    height: 34px;
    padding: 0 14px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    font-size: 13px;
    font-weight: 400;
    cursor: pointer;
}

.tc-chip:hover { border-color: var(--accent); }

.tc-chip.is-active {
    background: var(--accent-wash);
    border-color: var(--accent);
    color: var(--text);
    font-weight: 600;
}

.tc-chip-count { font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: var(--muted); }

.tc-search { position: relative; margin-left: auto; width: 220px; }

.tc-search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--muted);
    pointer-events: none;
}

.tc-search input {
    width: 100%;
    height: 34px;
    padding: 0 12px 0 34px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    outline: none;
}

.tc-search input:focus { border-color: var(--accent); }

/* On a phone the four chips measure wider than the viewport, so the row overflowed and pushed
   "Finished" off the right edge — while the search sat beside them as a 220px stub pinned right
   by margin-left:auto, leaving most of its row empty.
   
   Each now gets its own full-width row: the chips wrap instead of overflowing, so nothing ends
   up off-screen, and the search spans the width it was always going to need on a small screen. */
@media (max-width: 600px) {
    .tc-filterbar { gap: 10px; }

    /* Two by two. A single row overflowed the viewport and pushed "Finished" off the edge;
       letting it wrap instead stranded that one chip alone on a second line. A grid is the
       only arrangement of four that looks deliberate at this width. */
    .tc-chips {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        width: 100%;
    }

    .tc-chip { justify-content: center; padding: 0 10px; }

    .tc-search { margin-left: 0; width: 100%; flex: 1 0 100%; }
}

/* =========================================================================
   Torrent cards
   ========================================================================= */
.tc-list { display: flex; flex-direction: column; gap: 10px; }

.tc-card {
    padding: 16px 18px;
    border-radius: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.tc-card:hover { border-color: var(--accent); }

.tc-card-top { display: flex; align-items: flex-start; gap: 14px; }

.tc-card-text { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 5px; }

.tc-card-name {
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tc-card-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: 'IBM Plex Mono', monospace;
    font-size: 12px;
    color: var(--muted);
}

.tc-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    flex: none;
    white-space: nowrap;
}

.tc-pill-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

.tc-pill.is-downloading { background: var(--accent-wash); color: var(--accent-2); }
.tc-pill.is-seeding,
.tc-pill.is-done { background: var(--ok-wash); color: var(--ok); }
.tc-pill.is-paused { background: var(--muted-wash); color: var(--muted); }

.tc-card-actions { display: flex; gap: 4px; flex: none; }

.tc-card-btn {
    width: 32px;
    height: 32px;
    border-radius: 9px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    display: grid;
    place-items: center;
    cursor: pointer;
}

.tc-card-btn:hover { color: var(--text); border-color: var(--accent); background: var(--accent-wash); }
.tc-card-btn.is-remove { color: var(--muted); }
.tc-card-btn.is-remove:hover { color: var(--text); border-color: var(--accent); background: var(--surface); }

.tc-progress { display: flex; align-items: center; gap: 12px; }

.tc-track {
    flex: 1;
    height: 6px;
    border-radius: 4px;
    background: var(--track);
    overflow: hidden;
}

.tc-fill {
    height: 100%;
    border-radius: 4px;
    transition: width .4s linear;
}

.tc-fill.is-downloading { background: var(--accent); }
.tc-fill.is-seeding,
.tc-fill.is-done { background: var(--ok); }
.tc-fill.is-paused { background: var(--muted); }

.tc-pct {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 12px;
    color: var(--text-2);
    width: 48px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    flex: none;
}

/* The prototype was designed desktop-first: below ~600px let the name/meta
   block wrap above the pill and buttons rather than squeezing it. */
@media (max-width: 600px) {
    .tc-card-top { flex-wrap: wrap; }
    .tc-card-text { flex-basis: 100%; }
}

/* =========================================================================
   Empty state
   ========================================================================= */
.tc-empty {
    padding: 60px 20px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    border: 1px dashed var(--border);
    border-radius: 14px;
}

.tc-empty-title { font-size: 14px; font-weight: 600; }
.tc-empty-body {
    font-size: 13px;
    color: var(--muted);
    /* The first-run copy is a sentence rather than a fragment, so it needs a measure. */
    max-width: 48ch;
    line-height: 1.55;
}
.tc-empty-body code { font-family: 'IBM Plex Mono', monospace; font-size: 12px; }
.tc-empty-action { margin-top: 6px; }

/* =========================================================================
   Privacy footer
   ========================================================================= */
.tc-footer { border-top: 1px solid var(--border); background: var(--surface); }

.tc-footer-inner {
    max-width: 880px;
    margin: 0 auto;
    padding: 32px 24px 40px;
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.tc-footer-head { display: flex; align-items: flex-start; gap: 14px; }

.tc-shield {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    flex: none;
    background: var(--accent-wash);
    color: var(--accent);
    display: grid;
    place-items: center;
}

.tc-footer-headtext { display: flex; flex-direction: column; gap: 7px; max-width: 620px; }
.tc-footer-title { font-size: 14px; font-weight: 700; }

.tc-footer-body {
    margin: 0;
    font-size: 13px;
    line-height: 1.65;
    color: var(--text-2);
    text-wrap: pretty;
}

.tc-points {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 14px;
}

.tc-point {
    padding: 14px 15px;
    border-radius: 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tc-point-title { font-size: 12.5px; font-weight: 600; }
.tc-point-body { font-size: 12px; line-height: 1.55; color: var(--muted); text-wrap: pretty; }

.tc-legal {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    padding-top: 4px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--muted);
}

.tc-legal-right { margin-left: auto; }

/* Sits in the legal row, which is 12px muted text, so it is styled to belong there rather than
   to shout. Buy Me a Coffee's own badge is a saturated yellow that would become the loudest
   thing on a page whose whole palette is restrained; this reads as a link until you hover it. */
.tc-coffee {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color .15s ease, border-color .15s ease;
}

.tc-coffee:hover,
.tc-coffee:focus-visible {
    color: var(--accent-2);
    border-bottom-color: currentColor;
}

/* =========================================================================
   Add-torrent dialog
   ========================================================================= */
.tc-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(4, 10, 22, 0.6);
    display: grid;
    place-items: center;
    z-index: 50;
    animation: fade .16s ease;
    padding: 20px;

    /* The implicit grid column is auto-sized, so it grows to fit a wide child and the dialog's
       own max-width:100% then resolves against *that* rather than the viewport — which let the
       720px player overflow a phone screen with its close button off-screen. minmax(0, 1fr)
       bounds the column to the backdrop. */
    grid-template-columns: minmax(0, 1fr);
}

.tc-dialog {
    width: 460px;
    max-width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: var(--shadow);
    padding: 22px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    animation: pop .2s cubic-bezier(.2, .8, .3, 1);
}

.tc-dialog-title-row { display: flex; align-items: center; justify-content: space-between; }
.tc-dialog-title { font-size: 15px; font-weight: 700; }

.tc-dialog-close {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    border: none;
    background: var(--surface-2);
    color: var(--muted);
    cursor: pointer;
    display: grid;
    place-items: center;
}

.tc-dialog-close:hover { color: var(--text); }

.tc-magnet-input {
    width: 100%;
    height: 42px;
    padding: 0 14px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text);
    font-family: 'IBM Plex Mono', monospace;
    font-size: 12.5px;
    outline: none;
}

.tc-magnet-input:focus { border-color: var(--accent); background: var(--surface); }

.tc-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 26px;
    border: 1.5px dashed var(--border);
    border-radius: 12px;
    background: var(--surface-2);
    cursor: pointer;
    position: relative;
    color: var(--accent);
}

.tc-dropzone:hover,
.tc-dropzone.is-dragover { border-color: var(--accent); background: var(--accent-wash); }

.tc-dropzone-caption { font-size: 12.5px; color: var(--text-2); }
.tc-dropzone-browse { color: var(--accent); font-weight: 600; }

/* Invisible file input covering the drop zone, so the whole tile is clickable. */
.tc-dropzone input[type="file"] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

.tc-dialog-buttons { display: flex; gap: 9px; justify-content: flex-end; }

.tc-btn-secondary {
    height: 38px;
    padding: 0 16px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}

.tc-btn-secondary:hover { color: var(--text); }

.tc-dialog-submit {
    height: 38px;
    padding: 0 18px;
    border-radius: 10px;
    border: none;
    background: var(--accent);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.tc-dialog-submit:hover { background: var(--accent-2); }
.tc-dialog-submit:disabled { opacity: .5; cursor: not-allowed; }

.tc-dialog-error { font-size: 12.5px; color: #F87171; }

.tc-confirm-check {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 13px;
    color: var(--text-2);
    cursor: pointer;
}

.tc-confirm-check input { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }

/* Destructive confirm: red rather than accent, so it never reads as the safe default. */
.tc-danger { background: #DC2626; }
.tc-danger:hover { background: #EF4444; }

/* =========================================================================
   Blazor framework UI
   ========================================================================= */
/* The boot screen, and — to anything that does not run JavaScript — the whole page. It carries
   a heading and a description now rather than one muted word, so it has to read as a deliberate
   screen for the second or two it is up. */
.tc-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    gap: 12px;
    padding: 24px;
    text-align: center;
    color: var(--muted);
    font-size: 13px;
}

.tc-loading-title {
    margin: 0;
    font-size: 20px;
    font-weight: 600;
    color: var(--text);
}

.tc-loading-body {
    margin: 0;
    /* Measured in ch so the line length stays readable rather than tracking the viewport. */
    max-width: 56ch;
    line-height: 1.55;
}

.tc-loading-note {
    font-family: 'IBM Plex Mono', monospace;   /* matches .tc-mono */
    font-size: 12px;
    opacity: .75;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    color: #111;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: #b32121;
    padding: 1rem;
    color: white;
}

.blazor-error-boundary::after { content: "An error has occurred."; }

.tc-notice {
    padding: 11px 14px;
    border-radius: 10px;
    background: var(--accent-wash);
    border: 1px solid var(--accent);
    color: var(--text);
    font-size: 13px;
}

/* Shown beside a notice that describes work still going on, so a message that will change in
   a moment does not read like a message that has finished. */
.tc-notice.is-busy {
    display: flex;
    align-items: center;
    gap: 9px;
}

.tc-spinner {
    flex: none;
    width: 13px;
    height: 13px;
    border: 2px solid var(--accent);
    border-top-color: transparent;
    border-radius: 50%;
    animation: tc-spin .7s linear infinite;
}

@keyframes tc-spin {
    to { transform: rotate(360deg); }
}

/* A spinner is motion for its own sake to someone who has asked for less of it; the message
   beside it still says what is happening. */
@media (prefers-reduced-motion: reduce) {
    .tc-spinner { animation-duration: 2.4s; }
}

/* =========================================================================
   Bridge / relay
   ========================================================================= */

/* Accent border marks a configured bridge without shouting about it. */
.tc-icon-btn.is-on { color: var(--accent); border-color: var(--accent); }

/* Route marker: which privacy mode a torrent is actually using. */
.tc-route {
    flex: none;
    font-size: 11px;
    color: var(--muted);
    border: 1px solid var(--border);
    border-radius: 20px;
    padding: 3px 9px;
    white-space: nowrap;
}

.tc-bridge-ok { font-size: 12.5px; color: var(--ok); }

/* Player dialog is wider than the standard dialog to fit 16:9 comfortably. */
.tc-player { width: 720px; }

/* Portrait phones. The video is width-constrained here, so every pixel of horizontal padding
   comes straight out of the picture — the dialog goes near-edge-to-edge and the chrome shrinks
   to match. Landscape keeps the roomier desktop treatment, where width is not the scarce axis. */
@media (max-width: 600px) {
    .tc-backdrop { padding: 8px; }

    .tc-dialog.tc-player {
        width: 100%;
        padding: 12px;
        gap: 10px;
        border-radius: 12px;
    }

    .tc-player .tc-dialog-title {
        font-size: 13px;
        /* Release names are long; two lines is plenty before the video is pushed down. */
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    /* 60vh is a desktop figure. In portrait the picture is short anyway, and capping it low
       just wastes the screen someone is holding upright. */
    .tc-player .tc-video,
    .tc-player .tc-video-host > movi-player { max-height: 72vh; }

    .tc-player .tc-point-body { font-size: 11px; line-height: 1.4; }
}

.tc-video {
    width: 100%;
    max-height: 60vh;
    background: #000;
    border-radius: 10px;
    display: block;
}

/* movi-player renders to a canvas it sizes itself; the host only has to give it a box. */
.tc-video-host > movi-player {
    width: 100%;
    max-height: 60vh;
    display: block;
}

/* =========================================================================
   Setup landing (/setup) — where the Bridge app's QR code arrives
   ========================================================================= */
.tc-setup {
    max-width: 420px;
    margin: 0 auto;
    padding: 72px 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 14px;
}

.tc-setup-icon {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: grid;
    place-items: center;
    margin-bottom: 4px;
}

.tc-setup-icon.is-ok { background: rgba(95, 224, 168, 0.14); color: #5fe0a8; }
.tc-setup-icon.is-bad { background: rgba(255, 107, 94, 0.14); color: #ff8a7e; }

.tc-setup-title { font-size: 20px; font-weight: 700; letter-spacing: -0.2px; }

.tc-setup-body { font-size: 13.5px; color: var(--muted); line-height: 1.55; }

.tc-setup-body code {
    font-size: 13px;
    padding: 2px 6px;
    border-radius: 6px;
    background: var(--surface-2, rgba(255, 255, 255, 0.06));
    color: var(--text);
}

.tc-setup .tc-btn-primary,
.tc-setup .tc-btn-secondary { margin-top: 10px; padding: 10px 20px; }

/* =========================================================================
   Get the bridge app
   ========================================================================= */
.tc-get {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

/* Focused programmatically when the bridge dialog sends someone here, so it must not draw a
   focus ring as though it were a control the user tabbed to. */
.tc-get:focus { outline: none; }
.tc-get:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 12px; }

.tc-get-head { display: flex; align-items: flex-start; gap: 14px; }

.tc-get-icon {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    flex: none;
    background: var(--accent-wash);
    color: var(--accent);
    display: grid;
    place-items: center;
}

.tc-get-note {
    margin: 0;
    padding: 10px 13px;
    border-radius: 10px;
    background: var(--accent-wash);
    color: var(--text-2);
    font-size: 12.5px;
    line-height: 1.55;
}

.tc-get-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px;
}

.tc-get-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 14px;
    border-radius: 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: inherit;
    text-decoration: none;
    transition: border-color .12s, background .12s;
}

.tc-get-card:hover { border-color: var(--accent); background: var(--surface); }

/* The build matching the visitor's own machine. A border rather than a fill: the others are
   still perfectly clickable, and dimming them would hide the cross-platform point. */
.tc-get-card.is-yours { border-color: var(--accent); }

.tc-get-card-icon { color: var(--text-2); flex: none; display: grid; place-items: center; }
.tc-get-card:hover .tc-get-card-icon { color: var(--accent); }

.tc-get-card-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tc-get-card-name { font-size: 13px; font-weight: 600; }
.tc-get-card-meta { font-size: 11px; color: var(--muted); white-space: nowrap; }

/* Under the file line rather than beside it: sharing the row cost the longest label ("Apple
   silicon") enough width to wrap it onto three lines. */
.tc-get-badge {
    margin-top: 3px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--accent);
}

.tc-get-foot { margin: 0; font-size: 12px; line-height: 1.55; color: var(--muted); }
.tc-get-foot a { color: var(--accent); }

/* A link that happens to be a button, because it closes the dialog before it navigates. */
.tc-dialog-link {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent);
    font: inherit;
    font-size: 12.5px;
    text-align: left;
    cursor: pointer;
}

.tc-dialog-link:hover { text-decoration: underline; }

/* Version chip beside the section heading, and the placeholder for a platform not yet built. */
.tc-get-version {
    margin-left: 8px;
    font-size: 11px;
    font-weight: 500;
    color: var(--muted);
    letter-spacing: .01em;
}

/* Muted and inert: it names the platform so nobody thinks their machine is unsupported, while
   looking clearly unlike something you can click. */
.tc-get-card.is-pending {
    opacity: .5;
    cursor: default;
}

.tc-get-card.is-pending:hover { border-color: var(--border); }
.tc-get-card.is-pending:hover .tc-get-card-icon { color: var(--text-2); }

/* =========================================================================
   Installed app (PWA)
   ========================================================================= */

/* index.html asks for viewport-fit=cover so the app paints edge to edge when installed. That
   is only safe if the parts pinned to an edge stay clear of the notch, the rounded corners and
   the home indicator — otherwise the header slides under the status bar and the footer sits
   beneath the gesture bar.

   env() resolves to 0 everywhere it does not apply, so these are inert in a browser tab and on
   any device without insets. No feature query needed. */

.tc-header {
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
    /* Extends the header's own background up behind the status bar rather than leaving a strip
       of page showing through above it. */
    padding-top: env(safe-area-inset-top);
    height: calc(64px + env(safe-area-inset-top));
}

body {
    padding-bottom: env(safe-area-inset-bottom);
}

/* Fixed to the viewport, so it needs the insets itself — the padding on body does not move it. */
#blazor-error-ui {
    padding-bottom: calc(0.7rem + env(safe-area-inset-bottom));
    padding-left: max(1.25rem, env(safe-area-inset-left));
    padding-right: max(1.25rem, env(safe-area-inset-right));
}

/* Dialogs are centred, but their padding has to clear the insets or a full-height dialog runs
   under the home indicator on a phone. */
.tc-backdrop {
    padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right))
             max(20px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
}

/* Install-the-app offer, shown only when there is an install path to offer. */
.tc-install {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    margin-bottom: 22px;
    border-radius: 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
}

.tc-install-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    background: var(--accent-wash);
    color: var(--accent);
}

.tc-install-text { flex: 1; min-width: 0; }
.tc-install-title { display: block; font-weight: 600; font-size: 13.5px; color: var(--text); }
.tc-install-body { margin: 3px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--text-2); }

/* Aligned to the title rather than centred: the body text wraps to a different number of lines
   on every width, and a vertically centred button drifts around as it does. */
.tc-install-btn { flex: none; margin-top: 2px; }

@media (max-width: 560px) {
    .tc-install { flex-wrap: wrap; }
    .tc-install-btn { width: 100%; margin-top: 4px; }
}
