:root {
    --bg: #1a1a1a;
    --surface: #222222;
    --surface-2: #2b333f;
    --menu-bg: #2b333f;
    --accent: #2ba5e1;
    --accent-hover: #4db4e6;
    --text: #fff;
    --text-muted: rgba(255, 255, 255, 0.6);
    --border: rgba(255, 255, 255, 0.08);
    --radius: 10px;
    --radius-sm: 6px;
    --nav-height: 60px;
    --sidebar-width: 232px;
    --danger: #e14b4b;
    --font-display: 'Space Grotesk', Roboto, system-ui, sans-serif;
}

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    height: 100%;
}

body {
    background: var(--bg);
    color: var(--text);
    font-family: Roboto, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
    -webkit-tap-highlight-color: transparent;
    padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

@media (min-width: 960px) {
    body {
        padding-bottom: 0;
        padding-left: var(--sidebar-width);
    }
}

a {
    color: inherit;
    text-decoration: none;
}

img {
    max-width: 100%;
    display: block;
}

button,
input {
    font-family: inherit;
}

.container {
    flex: 1 0 auto;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    padding: 1rem;
}

/* ── Top bar ── */
.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem;
    max-width: 1100px;
    margin: 0 auto;
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.brand span {
    color: var(--accent);
}

.brand-logo {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
}

@media (min-width: 960px) {

    /* Brand lives in the sidebar at this size; avoid showing it twice. */
    .topbar .brand {
        display: none;
    }
}

/* ── Section headings ── */
.section-title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    margin: 1.5rem 0 0.75rem;
}

.section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.section-header .section-title {
    margin: 1.5rem 0 0.75rem 0;
}

.section-header .type-toggle {
    margin: 0;
    flex-shrink: 0;
}

/* ── Trending strip ── */
.strip {
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-bottom: 0.5rem;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}

.strip .card {
    flex: 0 0 128px;
    scroll-snap-align: start;
}

/* ── Spotlight carousel (home trending banner) ── */
.spotlight {
    position: relative;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--border);
    touch-action: pan-y;
}

.spotlight.skeleton {
    aspect-ratio: 16 / 9;
}

@media (min-width: 960px) {
    .spotlight:not(.skeleton) {
        aspect-ratio: 21 / 8;
    }

    .spotlight.skeleton {
        aspect-ratio: 21 / 8;
    }
}

.spotlight-track {
    display: flex;
    height: 100%;
    transition: transform 0.45s ease;
}

.spotlight-track.dragging {
    transition: none;
}

.spotlight-slide {
    position: relative;
    flex: 0 0 100%;
    aspect-ratio: 16 / 9;
    display: block;
}

@media (min-width: 960px) {
    .spotlight-slide {
        aspect-ratio: 21 / 8;
    }
}

.spotlight-slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    -webkit-user-drag: none;
    user-select: none;
}

.spotlight-scrim {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 1.1rem 1.1rem 1.4rem;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0.85) 100%);
}

.spotlight-rank {
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.3rem;
}

.spotlight-title {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.3;
    max-width: 640px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
}

@media (min-width: 960px) {
    .spotlight-title {
        font-size: 1.5rem;
    }
}

.spotlight-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, 0.45);
    border: none;
    color: var(--text);
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.2s, background 0.2s;
    z-index: 2;
}

.spotlight-arrow:hover {
    background: rgba(0, 0, 0, 0.7);
}

.spotlight:hover .spotlight-arrow,
.spotlight:focus-within .spotlight-arrow {
    opacity: 1;
}

@media (hover: none) {
    .spotlight-arrow {
        opacity: 1;
    }
}

.spotlight-arrow.prev {
    left: 10px;
}

.spotlight-arrow.next {
    right: 10px;
}

.spotlight-dots {
    position: absolute;
    right: 1.1rem;
    bottom: 1.4rem;
    display: flex;
    gap: 6px;
    z-index: 2;
}

.spotlight-dot {
    width: 6px;
    height: 6px;
    padding: 0;
    border: none;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.4);
    cursor: pointer;
    transition: width 0.2s, background 0.2s;
}

.spotlight-dot.active {
    width: 18px;
    background: var(--accent);
}

/* ── Grid ── */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 0.9rem;
}

@media (min-width: 640px) {
    .grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }
}

@media (min-width: 960px) {
    .grid {
        grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    }
}

/* ── Card ── */
.card {
    display: block;
    background: var(--surface);
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--border);
    position: relative;
}

.card .poster-wrap {
    width: 100%;
    aspect-ratio: 2 / 3;
    background: var(--surface-2);
    overflow: hidden;
}

.card img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.card .card-body {
    padding: 0.5rem 0.6rem 0.65rem;
}

.card .card-title {
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.card .card-sub {
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-top: 0.2rem;
}

.badge {
    position: absolute;
    top: 6px;
    right: 6px;
    font-size: 0.65rem;
    font-weight: 700;
    padding: 0.15rem 0.4rem;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.6);
    color: var(--text);
    letter-spacing: 0.03em;
}

.badge-sub {
    color: var(--accent);
}

.badge-dub {
    color: #f0a84b;
}

/* ── Buttons ── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    padding: 0.55rem 1rem;
    font-size: 0.85rem;
    font-weight: 600;
    border-radius: var(--radius-sm);
    cursor: pointer;
}

/* display:inline-flex above would otherwise beat the UA stylesheet's [hidden]
   rule, same as .modal-backdrop below - a hidden .btn would render anyway. */
.btn[hidden] {
    display: none;
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #06202c;
}

.btn-danger {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

.btn-block {
    width: 100%;
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ── Search ── */
.search-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.6rem 0.9rem;
}

.search-bar input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--text);
    font-size: 0.95rem;
}

.search-bar input::placeholder {
    color: var(--text-muted);
}

.pagination {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin: 1.5rem 0;
}

/* ── Skeleton ── */
.skeleton {
    background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 37%, var(--surface) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
    border-radius: var(--radius);
}

.skeleton-card .poster-wrap {
    background: none;
}

@keyframes skeleton-shimmer {
    0% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0 50%;
    }
}

.detail-poster.skeleton,
.episode-num.skeleton,
.watch-video-frame.skeleton {
    background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 37%, var(--surface) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
}

.skeleton-line,
.skeleton-chip,
.skeleton-btn {
    background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 37%, var(--surface) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
    border-radius: var(--radius-sm);
}

.skeleton-line {
    height: 0.8rem;
    margin: 0.4rem 0;
}

.skeleton-line.skeleton-title {
    height: 1.2rem;
    width: 65%;
}

.skeleton-line.skeleton-sub {
    width: 40%;
    margin-bottom: 0.75rem;
}

.skeleton-chip {
    width: 56px;
    height: 22px;
    border-radius: 999px;
}

.skeleton-btn {
    height: 42px;
    margin-top: 0.75rem;
}

.episode-row.skeleton-row {
    cursor: default;
}

.episode-row.skeleton-row .episode-info {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* ── Empty state ── */
.empty-state {
    text-align: center;
    color: var(--text-muted);
    padding: 3rem 1rem;
    font-size: 0.9rem;
}

.grid .empty-state {
    grid-column: 1 / -1;
}

/* ── Load more sentinel ── */
.load-more-sentinel {
    display: none;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.75rem 0;
    color: var(--text-muted);
    font-size: 0.85rem;
    opacity: 0;
    transition: opacity 0.2s ease;
}

.load-more-sentinel.is-loading {
    opacity: 1;
}

.spinner {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spinner-rotate 0.7s linear infinite;
}

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

/* ── Toast ── */
.toast {
    position: fixed;
    left: 50%;
    bottom: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px) + 0.75rem);
    transform: translate(-50%, 8px);
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--border);
    padding: 0.65rem 1rem;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    max-width: 90vw;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
    z-index: 200;
}

.toast.toast-visible {
    opacity: 1;
    transform: translate(-50%, 0);
}

.toast.toast-error {
    border-color: var(--danger);
}

/* ── Modal ── */
.modal-backdrop {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(0, 0, 0, 0.6);
    /* Above the toast (200), which is above the nav/sidebar (100). */
    z-index: 300;
}

/* display:flex above would otherwise beat the UA stylesheet's [hidden] rule. */
.modal-backdrop[hidden] {
    display: none;
}

.modal {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

.modal-title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 0.6rem;
}

.modal-body {
    font-size: 0.85rem;
    color: var(--text-muted);
    line-height: 1.5;
    margin: 0 0 1.1rem;
}

.modal-actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* ── Bottom nav ── */
.bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--nav-height);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--menu-bg);
    border-top: 1px solid var(--border);
    display: flex;
    z-index: 100;
}

.bottom-nav a {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 600;
}

.bottom-nav a svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
}

.bottom-nav a[aria-current="page"] {
    color: var(--accent);
}

@media (min-width: 960px) {
    .bottom-nav {
        display: none;
    }
}

@media (max-width: 959px) {
    .container {
        padding-bottom: calc(var(--nav-height) + 16px);
    }
}

/* ── Sidebar (desktop / high-end device layout) ── */
.sidebar {
    display: none;
}

@media (min-width: 960px) {
    .sidebar {
        display: flex;
        flex-direction: column;
        position: fixed;
        left: 0;
        top: 0;
        bottom: 0;
        width: var(--sidebar-width);
        background: var(--menu-bg);
        border-right: 1px solid var(--border);
        padding: 1.25rem 0.75rem;
        z-index: 100;
    }
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    padding: 0.5rem 0.75rem 1.5rem;
}

.sidebar-brand span {
    color: var(--accent);
}

.sidebar-brand .brand-logo {
    width: 30px;
    height: 30px;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.sidebar-nav a {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.65rem 0.75rem;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-size: 0.9rem;
    font-weight: 600;
}

.sidebar-nav a svg {
    width: 19px;
    height: 19px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    flex-shrink: 0;
}

.sidebar-nav a:hover {
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
}

.sidebar-nav a[aria-current="page"] {
    background: rgba(43, 165, 225, 0.15);
    color: var(--accent);
}

/* ── Footer ── */
.site-footer {
    display: none;
}

@media (min-width: 960px) {
    .site-footer {
        display: block;
        background: var(--menu-bg);
        border-top: 1px solid var(--border);
    }

    .site-footer-inner {
        max-width: 1100px;
        margin: 0 auto;
        padding: 1rem;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
    }

    .site-footer-notice {
        margin: 0 0 0.35rem;
        font-size: 0.85rem;
        color: var(--accent);
    }

    .site-footer-copy {
        margin: 0;
        font-size: 0.8rem;
        color: var(--text-muted);
    }

    .site-footer-report {
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        gap: 0.4rem;
        background: var(--accent);
        color: #06202c;
        font-size: 0.85rem;
        font-weight: 600;
        padding: 0.55rem 1.1rem;
        border-radius: 999px;
    }

    .site-footer-report svg {
        width: 18px;
        height: 18px;
        fill: none;
        stroke: currentColor;
        stroke-width: 2;
    }
}

/* ── Anime detail page ── */
.detail-hero {
    display: flex;
    gap: 1rem;
    margin-bottom: 1rem;
}

.detail-poster {
    flex: 0 0 120px;
    width: 120px;
    aspect-ratio: 2 / 3;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--border);
}

.detail-poster img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.detail-meta h1 {
    font-size: 1.15rem;
    margin: 0 0 0.25rem;
}

.detail-meta .detail-english {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-bottom: 0.5rem;
}

.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0.5rem 0;
}

.chip {
    font-size: 0.7rem;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text-muted);
}

.description {
    font-size: 0.85rem;
    color: var(--text-muted);
    line-height: 1.5;
    margin: 0.75rem 0;
}

.play-btn {
    margin-top: 0.75rem;
}

.play-btn svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.type-toggle {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    margin: 0.5rem 0 1rem;
}

.type-toggle button {
    background: var(--surface);
    color: var(--text-muted);
    border: none;
    padding: 0.4rem 0.9rem;
    font-size: 0.78rem;
    font-weight: 700;
    cursor: pointer;
}

.type-toggle button.active {
    background: var(--accent);
    color: #06202c;
}

.episode-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.episode-row {
    display: flex;
    gap: 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.6rem 0.75rem;
    cursor: pointer;
    align-items: center;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.episode-row:hover {
    background: var(--surface-2);
    border-color: var(--accent);
}

.episode-num {
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--accent);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.85rem;
}

.episode-info {
    flex: 1;
    min-width: 0;
}

.episode-title {
    font-size: 0.82rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.episode-sub {
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-top: 0.15rem;
}

.episode-play-icon {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    fill: currentColor;
    color: var(--text-muted);
}

.episode-row:hover .episode-play-icon {
    color: var(--accent);
}

.server-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.server-chip {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.35rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
}

.server-chip.active {
    background: var(--accent);
    color: #06202c;
    border-color: var(--accent);
}

/* ── History page ── */
.history-row {
    display: flex;
    gap: 0.9rem;
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.75rem;
    margin-bottom: 0.65rem;
}

.history-poster {
    flex: 0 0 56px;
    width: 56px;
    aspect-ratio: 2 / 3;
    border-radius: 6px;
    overflow: hidden;
    background: var(--surface-2);
}

.history-poster img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.history-info {
    flex: 1;
    min-width: 0;
}

.history-title {
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.history-sub {
    font-size: 0.72rem;
    color: var(--text-muted);
    line-height: 1.4;
    margin-top: 0.3rem;
}

.history-remove {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.1rem;
    cursor: pointer;
    padding: 0.4rem;
}

.history-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.history-header .section-title {
    margin: 0;
}

/* Four buttons don't fit one row next to the title on a narrow phone, so the
   header wraps and the group drops below it rather than overflowing. */
.history-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* ── Transfer page ── */
.transfer-card {
    max-width: 360px;
    margin: 1.5rem auto 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem;
    text-align: center;
}

.transfer-card .section-title {
    margin: 0 0 0.4rem;
}

.transfer-hint {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin: 0 0 1.1rem;
}

/* White background regardless of the app's dark theme - QR modules need real
   contrast against their quiet zone to scan reliably. */
.transfer-qr {
    display: inline-block;
    background: #fff;
    padding: 0.75rem;
    border-radius: var(--radius-sm);
    line-height: 0;
    margin-bottom: 1.1rem;
}

.transfer-status {
    font-size: 0.88rem;
    margin: 0 0 1rem;
}

.transfer-status.transfer-status-error {
    color: var(--danger);
}

.transfer-spinner {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: 0.4em;
    border: 2px solid var(--text-muted);
    border-top-color: var(--accent);
    border-radius: 50%;
    vertical-align: -0.15em;
    animation: transfer-spin 0.8s linear infinite;
}

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

/* Session-creation loader. Deliberately QR-shaped: it occupies the same box the
   real code drops into, so the card doesn't resize when the two swap. The <i>
   children are the three finder squares, the <b> is the scan line. */
.transfer-loader {
    position: relative;
    /* Matches the rendered code: a /transfer/<token> URL lands on a 45-module
       version-7 QR, which utils/transferQr.js draws at 45 * 4px + 2 * 8px. */
    width: 196px;
    max-width: 100%;
    height: 196px;
    margin: 0 auto 1.1rem;
    border-radius: var(--radius-sm);
    background-color: var(--surface-2);
    /* Two offset diagonal gradients make the classic checkerboard - close enough
       to a module grid to read as "a QR is coming". */
    background-image:
        linear-gradient(45deg, var(--border) 25%, transparent 25% 75%, var(--border) 75%),
        linear-gradient(45deg, var(--border) 25%, transparent 25% 75%, var(--border) 75%);
    background-size: 8px 8px;
    background-position: 0 0, 4px 4px;
    overflow: hidden;
}

.transfer-loader i {
    position: absolute;
    width: 30px;
    height: 30px;
    border: 4px solid var(--accent);
    border-radius: 3px;
    animation: transfer-eye 1.5s ease-in-out infinite;
}

.transfer-loader i:nth-child(1) { top: 12px; left: 12px; }
.transfer-loader i:nth-child(2) { top: 12px; right: 12px; animation-delay: 0.18s; }
.transfer-loader i:nth-child(3) { bottom: 12px; left: 12px; animation-delay: 0.36s; }

@keyframes transfer-eye {
    0%, 100% { opacity: 0.2; transform: scale(0.85); }
    50% { opacity: 1; transform: scale(1); }
}

.transfer-loader b {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 44px;
    background: linear-gradient(180deg, rgba(43, 165, 225, 0) 0%, rgba(43, 165, 225, 0.35) 100%);
    border-bottom: 1px solid var(--accent);
    animation: transfer-scan 1.9s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

@keyframes transfer-scan {
    0% { transform: translateY(-44px); }
    50% { transform: translateY(196px); }
    100% { transform: translateY(-44px); }
}

/* Animated ellipsis, so the status text itself shows progress instead of sitting
   frozen behind the box. The dots are markup rather than a ::after content
   animation so the label stays selectable and screen-reader-clean. */
.transfer-ellipsis i {
    display: inline-block;
    font-style: normal;
    opacity: 0.2;
    animation: transfer-dot 1.2s ease-in-out infinite;
}

.transfer-ellipsis i::before { content: '.'; }
.transfer-ellipsis i:nth-child(2) { animation-delay: 0.2s; }
.transfer-ellipsis i:nth-child(3) { animation-delay: 0.4s; }

@keyframes transfer-dot {
    0%, 60%, 100% { opacity: 0.2; }
    30% { opacity: 1; }
}

/* Motion here is decorative - the status text already says what is happening. */
@media (prefers-reduced-motion: reduce) {
    .transfer-loader i,
    .transfer-loader b,
    .transfer-ellipsis i,
    .transfer-spinner,
    .btn-loading::after {
        animation: none;
    }

    .transfer-loader b { opacity: 0; }
    .transfer-loader i { opacity: 1; transform: none; }
    .transfer-ellipsis i { opacity: 1; }
}

/* The Sync button on /history spins in place while its session is minted, rather
   than just greying out and looking stuck. */
.btn-loading {
    position: relative;
    color: transparent;
}

/* Beats .btn:disabled's opacity, which the JS also sets - a half-faded spinner
   reads as broken rather than busy. */
.btn.btn-loading:disabled {
    opacity: 1;
    cursor: wait;
}

.btn-loading::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1em;
    height: 1em;
    margin: -0.5em 0 0 -0.5em;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: transfer-spin 0.8s linear infinite;
}

.transfer-progress {
    height: 6px;
    background: var(--surface-2);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: 1.1rem;
}

.transfer-progress-bar {
    height: 100%;
    width: 0%;
    background: var(--accent);
    transition: width 0.15s ease-out;
}

.transfer-cancel {
    display: block;
    width: 100%;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.8rem;
    padding: 0.75rem 0 0;
    cursor: pointer;
}

.transfer-cancel[hidden] {
    display: none;
}

/* ── Test proxy page ── */
.field {
    margin-bottom: 1rem;
}

.field label {
    display: block;
    font-size: 0.8rem;
    font-weight: 600;
    margin-bottom: 0.4rem;
    color: var(--text-muted);
}

.field input[type="text"],
.field textarea {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);
    padding: 0.6rem;
    font-size: 0.85rem;
}

.field textarea {
    min-height: 80px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    resize: vertical;
}

.proxy-frame {
    width: 100%;
    height: 300px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #000;
    margin-top: 1rem;
}

/* ── Watch page ── */
.watch-video-frame {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #000;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--border);
}

.watch-video-frame iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.watch-info {
    margin-top: 0.9rem;
}

.watch-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 700;
    margin: 0;
}

.watch-title a {
    color: var(--text-muted);
    font-size: 0.85rem;
    font-weight: 600;
    display: block;
    margin-bottom: 0.2rem;
}

.watch-sub {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 0.25rem;
}

.watch-nav-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    margin: 1rem 0 0.25rem;
}

.watch-nav-row .btn {
    flex: 1;
}

.watch-servers {
    margin-top: 1.25rem;
}

/* ── Remote browser (/vnc) ── */
.vnc-card {
    max-width: 900px;
    margin: 1.25rem auto 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem;
}

.vnc-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.vnc-header .section-title {
    margin: 0;
}

.vnc-badge {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.28rem 0.55rem;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-muted);
    border: 1px solid var(--border);
}

.vnc-badge.vnc-badge-live {
    background: var(--accent);
    border-color: var(--accent);
    color: #06202c;
}

/* The frame is letterboxed inside a fixed 16:10 well so the card does not resize
   every time the upstream page changes the screencast's dimensions. */
.vnc-screen {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 10;
    background: #000;
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.vnc-screen canvas {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Only meaningful with the admin key - a view-only visitor's pointer should look
   like it does anywhere else on the site. */
.vnc-screen.vnc-interactive canvas {
    cursor: crosshair;
}

.vnc-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 1rem;
    background: rgba(0, 0, 0, 0.72);
    font-size: 0.88rem;
    color: var(--text-muted);
    /* Status text only - it must never swallow a click. It covers the whole
       screen area, so without this it sits between the cursor and the canvas and
       silently eats every interaction while it is up (e.g. before the first
       frame arrives, which is exactly when an admin wants to click through a
       challenge). */
    pointer-events: none;
}

.vnc-overlay[hidden] {
    display: none;
}

/* Admin controls - only rendered when the admin key unlocked them. */
.vnc-controls,
.vnc-unlock {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.vnc-controls[hidden],
.vnc-unlock[hidden] {
    display: none;
}

/* .vnc-input is still used by the admin-key unlock form; the URL box it was
   shared with is gone. */
.vnc-input {
    flex: 1;
    min-width: 0;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.55rem 0.7rem;
    font-size: 0.85rem;
    font-family: inherit;
}

.vnc-input:focus {
    outline: none;
    border-color: var(--accent);
}

/* Status readout: label above value, wrapping into as many columns as fit. */
.vnc-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 0.7rem 1rem;
    margin: 1rem 0 0;
    padding: 0.9rem 0 0;
    border-top: 1px solid var(--border);
}

.vnc-stat {
    min-width: 0;
}

.vnc-stat dt {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 0.2rem;
}

.vnc-stat dd {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 600;
    word-break: break-word;
}

.vnc-stat dd.vnc-stat-url {
    font-size: 0.74rem;
    font-weight: 400;
    word-break: break-all;
}

.vnc-stat dd.vnc-ok {
    color: var(--accent);
}

.vnc-stat dd.vnc-bad {
    color: var(--danger);
}

.vnc-note {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin: 0.75rem 0 0;
}