/* ============================================================================
   Padel webapp — base stylesheet
   Design tokens seeded from poc/v01/b91_padel_shots/assets/padel_shots.css, by request
   (webapp/DESIGN.md, "Visual design").
   ========================================================================== */

:root {
    --accent: #2dd4bf;          /* teal */
    --accent-dark: #14b8a6;
    --bg-panel: #1c1f26;
    --bg-panel-2: #23272f;
    --border-soft: rgba(255, 255, 255, 0.08);
    --text-dim: #8b93a1;
}

body {
    background: radial-gradient(1200px 600px at 50% -10%, #23303a 0%, #12151b 55%) fixed;
    margin: 0;
}

/* ── App shell ───────────────────────────────────────────────────────────── */
.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
.app-content {
    flex: 1;
    padding: 1rem 0.75rem;
}
@media (min-width: 768px) {
    .app-content { padding: 1.5rem 1rem 2rem; }
}

/* /results is meant to read as a native app screen, not a page in the site — its own
   results-header already has a back chevron + title, duplicating the top bar's own way
   back. Drop it, and app-content's own padding around results-screen, only on that page,
   via :has() rather than a body/route class, so nothing elsewhere has to know this page
   exists. */
.app-shell:has(.results-screen) .app-topbar { display: none; }
.app-shell:has(.results-screen) .app-content { padding: 0; }

/* ── Top bar ─────────────────────────────────────────────────────────────── */
.app-topbar {
    position: sticky;
    top: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 1rem;
    background: rgba(18, 21, 27, 0.92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--border-soft);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}
.app-brand-group { display: flex; flex-direction: column; line-height: 1.1; }
.app-brand { font-size: 1.15rem; font-weight: 700; letter-spacing: 0.2px; color: #fff; }
.app-subtitle {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--accent);
}
.app-user-menu {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.6rem 0.25rem 0.25rem;
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    color: var(--text-dim);
    font-size: 0.85rem;
}
.user-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-panel-2);
    color: var(--accent);
    font-weight: 700;
    font-size: 0.8rem;
}
/* The display-name link (→ /account) sits inside the compact user-menu pill, not the
   44px-tall primary nav — override .app-nav-link's touch-target sizing so it stays
   pill-sized, while keeping the same hover/color behavior as every other nav link. */
.user-menu-label {
    padding: 0 !important;
    min-height: 0 !important;
    font-weight: 600;
}
.user-menu-label:hover { text-decoration: underline; }

/* ── User-menu links (Log in/Sign up, display name, Admin, Log out) ────────── */
.app-nav-link {
    color: var(--text-dim) !important;
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.5rem 0.75rem !important;
    border-radius: 8px;
    min-height: 44px;
    display: flex;
    align-items: center;
}
/* logout-button is a <button>, not an <a> (see app.py) — strip default button chrome so
   it matches the surrounding .app-nav-link anchors exactly. */
.logout-button {
    background: none;
    border: none;
    font-family: inherit;
    cursor: pointer;
}
.app-nav-link:hover,
.app-nav-link.active {
    color: #e6e9ee !important;
    background: var(--bg-panel-2);
}

/* ── Page placeholder card (milestone 1 scaffold only) ─────────────────────── */
.page-placeholder-wide,
.page-placeholder-narrow {
    padding: 0;
}
.page-placeholder-narrow { max-width: 480px; margin: 2rem auto 0; }
.page-placeholder-wide { max-width: 960px; margin: 1rem auto 0; }
.page-placeholder-card {
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-radius: 14px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.page-placeholder-title { color: #fff; font-size: 1.3rem; margin-bottom: 0.5rem; }
.page-placeholder-text { color: var(--text-dim); margin-bottom: 0; }

/* ── Auth forms (login/signup) ──────────────────────────────────────────── */
.auth-card .page-placeholder-title { text-align: center; }
.auth-card input.form-control {
    background: var(--bg-panel-2);
    border: 1px solid var(--border-soft);
    color: #e6e9ee;
    min-height: 44px;
}
.auth-card input.form-control:focus {
    background: var(--bg-panel-2);
    color: #e6e9ee;
    border-color: var(--accent);
    box-shadow: 0 0 0 0.2rem rgba(45, 212, 191, 0.2);
}
.auth-card .btn-primary {
    background: var(--accent) !important;
    border-color: var(--accent) !important;
    color: #06231f !important;
    font-weight: 700;
    min-height: 44px;
}
.auth-message { color: #ff8a80; font-size: 0.85rem; min-height: 1.2em; }
.auth-switch { color: var(--text-dim); font-size: 0.85rem; text-align: center; }
.auth-switch a { color: var(--accent); }

/* ── User menu, signed-out state ────────────────────────────────────────── */
.app-user-menu-guest { border: none; padding: 0; gap: 0.75rem; }
.app-user-menu-guest .app-nav-link { padding: 0.5rem 0.25rem !important; }

/* ── Library grid + upload card (webapp/DESIGN.md, "Upload flow: a modal on /library") ── */
.library-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.75rem;
    margin-top: 1rem;
}
@media (min-width: 768px) {
    .library-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
}
/* library-jobs wraps only the polled job cards (pages/library.py) so the upload card,
   rendered once outside it, never gets recreated by the poll — display:contents makes the
   wrapper itself invisible to the grid layout, so its children still lay out as direct
   grid items of .library-grid, same as before the split. */
.library-jobs { display: contents; }
.job-card {
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-radius: 12px;
    padding: 1rem;
    min-height: 96px;
}
.upload-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    border: 2px dashed var(--border-soft);
    color: var(--accent);
    cursor: pointer;
    min-height: 44px;
    transition: border-color 0.12s ease, background 0.12s ease;
}
.upload-card:hover { border-color: var(--accent); background: var(--bg-panel-2); }
.upload-card-icon { font-size: 1.6rem; font-weight: 700; line-height: 1; }
.upload-card-label { font-size: 0.85rem; font-weight: 600; }
.library-empty {
    grid-column: 1 / -1;
    color: var(--text-dim);
    text-align: center;
    padding: 2rem 1rem;
}

/* dbc.Modal on the dark theme */
.modal-content {
    background: var(--bg-panel) !important;
    border: 1px solid var(--border-soft) !important;
    color: #e6e9ee;
}
.modal-header, .modal-footer { border-color: var(--border-soft) !important; }

/* ── Admin page (webapp/DESIGN.md, "/admin" page anatomy) ───────────────────
   Two sections, stacked on mobile, side by side on desktop. */
.admin-sections {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    margin-top: 1rem;
}
@media (min-width: 768px) {
    .admin-sections { flex-direction: row; align-items: flex-start; }
    .admin-section { flex: 1; min-width: 0; }
}
.admin-section-title {
    font-size: 1rem;
    font-weight: 700;
    color: #fff;
    margin-bottom: 0.6rem;
}
.admin-list { display: flex; flex-direction: column; gap: 0.5rem; }
.admin-row {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 0.6rem 0.75rem;
}
@media (min-width: 480px) {
    .admin-row { flex-direction: row; align-items: center; justify-content: space-between; }
}
.admin-row-info { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.admin-row-name { font-weight: 700; color: #e6e9ee; }
.admin-row-email { color: var(--text-dim); font-size: 0.8rem; }
.admin-row-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.admin-btn { min-height: 44px; font-size: 0.8rem; }
.admin-empty { color: var(--text-dim); padding: 0.75rem; text-align: center; }

.status-pill {
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
}
.status-pill-active { background: rgba(45, 212, 191, 0.18); color: var(--accent); }
.status-pill-view_only { background: rgba(255, 213, 79, 0.15); color: #ffd54f; }
.status-pill-revoked { background: rgba(255, 82, 82, 0.15); color: #ff8a80; }
.role-pill {
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: rgba(45, 212, 191, 0.1);
    border: 1px solid rgba(45, 212, 191, 0.4);
    color: var(--accent);
}

/* ── Upload modal (webapp/DESIGN.md, "Progress shown to the user" — two separate bars) ── */
input[type="file"].form-control {
    background: var(--bg-panel-2);
    border: 1px solid var(--border-soft);
    color: var(--text-dim);
}
.progress-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.5rem;
}
.progress-row-label { color: var(--text-dim); font-size: 0.8rem; width: 80px; flex-shrink: 0; }
.progress-row-pct { color: var(--text-dim); font-size: 0.8rem; width: 40px; text-align: right; flex-shrink: 0; }
.progress-bar-track {
    flex: 1;
    height: 8px;
    border-radius: 999px;
    background: var(--bg-panel-2);
    border: 1px solid var(--border-soft);
    overflow: hidden;
}
.progress-bar-fill {
    height: 100%;
    width: 0%;
    background: var(--accent);
    border-radius: 999px;
    transition: width 0.2s ease;
}
.upload-status-label { color: var(--text-dim); font-size: 0.85rem; text-align: center; }

/* ── Job cards (webapp/DESIGN.md, "/library" page anatomy) ─────────────────── */
.job-card-link { text-decoration: none; color: inherit; display: block; }
.job-card-link:hover .job-card { border-color: var(--accent); }
.job-card-thumb {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: 8px;
    background: linear-gradient(135deg, #1a1f27 0%, #12151b 100%);
    margin-bottom: 0.6rem;
    object-fit: cover;
    /* Never intercept the tap/click — the whole card is a dcc.Link (pages/library.py);
       a <video> without pointer-events:none can otherwise steal it to show native
       playback controls on some browsers. */
    pointer-events: none;
}
.job-card-info { display: flex; flex-direction: column; gap: 0.3rem; align-items: flex-start; }
.job-card-title {
    font-weight: 700;
    color: #e6e9ee;
    font-size: 0.9rem;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.job-card-date { color: var(--text-dim); font-size: 0.75rem; }

/* Coarse job status (New/In progress/Done/Error) — reuses .status-pill's shape from the
   admin page's access-status pills, different color set. */
.status-pill-new { background: rgba(139, 147, 161, 0.15); color: var(--text-dim); }
.status-pill-in_progress { background: rgba(255, 213, 79, 0.15); color: #ffd54f; }
.status-pill-done { background: rgba(45, 212, 191, 0.18); color: var(--accent); }
.status-pill-error { background: rgba(255, 82, 82, 0.15); color: #ff8a80; }

/* ── Results screen (webapp/DESIGN.md milestone 6/7 — redesigned per discussion: "feel
   like a real smartphone app," organized around the two annotation families (Positions,
   Shots) and the padel entities (rally/team/player) as one readable scope line, not a
   stack of web-form controls). Full-bleed screen, not a boxed card on a page. ──────────── */
.results-screen { display: flex; flex-direction: column; min-height: 100%; }

.results-header {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.5rem;
    position: sticky;
    top: 0;
    z-index: 10;
    background: rgba(18, 21, 27, 0.92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--border-soft);
}
.results-back-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    font-size: 1.3rem;
    color: var(--text-dim);
    text-decoration: none;
}
.results-back-btn:hover { color: #e6e9ee; }
.results-header-title {
    flex: 1;
    font-weight: 700;
    color: #fff;
    font-size: 0.9rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Scope chip — the one line reading "which entity am I looking at" (Rally/Team/
   Player), tap to open results-filter-sheet. Sits at the *bottom* of the screen's content
   (per discussion), after the Positions/Shots panes — compact, not a big form-like bar. ── */
.scope-chip-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: calc(100% - 1.5rem);
    margin: 0.5rem 0.75rem 0.75rem;
    min-height: 38px;
    padding: 0 0.75rem;
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    color: #e6e9ee;
    font-size: 0.78rem;
    cursor: pointer;
}
.scope-chip-row:hover { border-color: var(--accent); }
.scope-chip-arrow { color: var(--text-dim); font-size: 1rem; }

/* ── Bottom sheets (dbc.Offcanvas, placement="bottom") — filters, overlay settings,
   edit — dark-themed to match, rounded top corners like a real native sheet. ──────────── */
.bottom-sheet .offcanvas {
    background: var(--bg-panel) !important;
    border-top: 1px solid var(--border-soft) !important;
    border-radius: 16px 16px 0 0;
    color: #e6e9ee;
}
.bottom-sheet .offcanvas-header { border-bottom: 1px solid var(--border-soft); }
.bottom-sheet .offcanvas-title { color: #fff; font-weight: 700; }
.bottom-sheet .btn-close { filter: invert(1) grayscale(1) opacity(0.7); }

.filter-group { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 1rem; }
.filter-label { color: var(--text-dim); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 1px; }
.filter-radio-group .btn-outline-secondary {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--text-dim);
    border-color: var(--border-soft);
}
.filter-radio-group .btn-check:checked + .btn-outline-secondary {
    background: var(--accent) !important;
    border-color: var(--accent) !important;
    color: #06231f !important;
}

/* ── Segmented control (Positions / Shots) — native-style pill toggle, not web tabs. The
   edit pencil lives in the header (see .results-header), not sharing this row. ──────────── */
.segmented-control {
    display: flex;
    gap: 2px;
    padding: 3px;
    margin: 0.5rem 0.75rem 0.6rem;
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-radius: 12px;
}
.segment-btn {
    flex: 1;
    min-height: 40px;
    background: none;
    border: none;
    border-radius: 9px;
    color: var(--text-dim);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
}
.segment-btn.active { background: var(--accent); color: #06231f; }

/* ── Panes (Positions / Shots) — always mounted, visibility toggled in Python, never
   swapped via children (keeps the video from reloading on every switch). ────────────────── */
.results-pane { padding: 0 0.75rem 1rem; }
/* Sized to the real court's own aspect ratio (10m × 20m, same ratio _positions_figure's
   scaleanchor enforces) plus a fixed extra column (pages/results.py's own
   _LEGEND_WIDTH_PX, kept in sync by hand — that's what the "+ 64px" below is) for the
   player legend down the right side, so the box IS the court-plus-legend, not a taller/
   wider box either one then sits inside of, letterboxed by Plotly with dead space around
   it — most visible on a wide screen, where a generous width budget left the (much
   narrower) court looking small and adrift in the middle of it. height is definite (a
   budget that leaves room for the video/switch/scope chip above and below it, ideally on
   one screen); width is computed from it directly (not via the `aspect-ratio` property,
   which can only express a pure ratio, not ratio-plus-a-fixed-offset), capped so it never
   overflows the available width on a narrow phone screen — there, width ends up the
   binding constraint instead (see the @media block below, where only height's own budget
   changes, using the same "/2 + 64px" formula). */
#results-positions-pane {
    width: calc(40vh / 2 + 64px);
    max-width: 100%;
    height: 40vh;
    min-height: 220px;
    margin: 0 auto;
}
#results-positions-pane .js-plotly-plot,
#results-positions-pane .plot-container { height: 100% !important; width: 100% !important; }

/* ── Video stage — same shape as b91_padel_shots'/backend's test frontend's own video
   stage: the raw clip plays at its own size, the overlay canvas sits exactly on top,
   undecorated. Icon buttons live in the video's own corner, like a real player's own
   controls, instead of a text link sitting below it. ─────────────────────────────────────── */
.video-stage {
    position: relative;
    width: 100%;
    background: #000;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid var(--border-soft);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}
.results-video { width: 100%; height: auto; display: block; background: #000; }
.results-overlay-canvas { position: absolute; top: 0; left: 0; pointer-events: none; }

.video-icon-row {
    position: absolute;
    bottom: 0.6rem;
    right: 0.6rem;
    display: flex;
    gap: 0.4rem;
}
.video-icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    background: rgba(18, 21, 27, 0.75);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 999px;
    color: #fff;
    font-size: 1.1rem;
    cursor: pointer;
    backdrop-filter: blur(4px);
}
.video-icon-btn:hover { background: rgba(18, 21, 27, 0.92); border-color: var(--accent); }

/* Fullscreening #results-video-stage itself (assets/results_video.js), not the <video>
   alone, is what keeps the overlay canvas visible in fullscreen — a sibling element never
   comes along if only the <video> is asked to fullscreen. Letterbox rather than stretch. */
.video-stage:fullscreen,
.video-stage:-webkit-full-screen,
.video-stage:-moz-full-screen {
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0;
    border: none;
}
.video-stage:fullscreen .results-video,
.video-stage:-webkit-full-screen .results-video,
.video-stage:-moz-full-screen .results-video {
    width: auto;
    height: 100%;
    max-width: 100%;
    object-fit: contain;
}

.overlay-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.9rem;
}
.overlay-toggle-label {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--text-dim);
    font-size: 0.8rem;
    cursor: pointer;
}

/* ── Shot tray (poc/v01/b91_padel_shots' own shot-menu/shot-chip pattern, same color
   palette) — horizontal-scrolling chips, tap to play, no separate button. ────────────────── */
.shot-menu {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding: 0.75rem 0.1rem 0.25rem;
    scrollbar-width: thin;
    scrollbar-color: var(--border-soft) transparent;
}
.shot-chip {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 76px;
    min-height: 56px;
    padding: 0.5rem 0.75rem;
    background: var(--bg-panel);
    border: 1px solid var(--border-soft);
    border-top: 3px solid var(--chip-color, var(--accent));
    border-radius: 10px;
    cursor: pointer;
}
.shot-chip:hover { background: var(--bg-panel-2); transform: translateY(-2px); }
.shot-chip-type {
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.3px;
    color: var(--chip-color, var(--accent));
    white-space: nowrap;
}
.shot-chip-count { font-size: 0.85rem; font-weight: 700; color: #e6e9ee; }

/* ── Shot sequence — colored bullets (poc/v01/b91_padel_shots' own rally-dots, "so the
   rally's shape is visible at a glance") — one dot per shot, chronological, tap to play. */
.shot-dots {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 0.6rem 0.1rem 0.1rem;
}
.shot-dot {
    /* Bootstrap sets box-sizing: border-box globally, which would make the 6px padding
       below eat the entire 12px width/height, leaving a 0x0 content-box for
       background-clip to paint into — an invisible dot, confirmed the hard way. Overriding
       box-sizing here is what actually makes the "bigger tap target, small visible dot"
       trick work: content-box makes width/height apply to the dot alone, padding adds on
       top for the tap area, same as originally intended. */
    box-sizing: content-box;
    width: 12px;
    height: 12px;
    padding: 6px; /* enlarges the tap target without enlarging the visible dot itself */
    background-clip: content-box;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.9;
}
.shot-dot:hover { opacity: 1; transform: scale(1.25); }
/* assets/results_reel.js toggles this on whichever dot's shot is currently playing back in
   a chip's reel — a ring in the dot's own color (visible against any dot color, unlike a
   single fixed outline color) plus a growth big enough to read as "now playing" at this
   dot's small size. */
.shot-dot.active {
    opacity: 1;
    transform: scale(1.12);
    /* --dot-color: the same shot-type color the dot's own inline backgroundColor already
       uses (pages/results.py's _shot_sequence_dots sets both together) — box-shadow can't
       read an inline background-color directly, so it's threaded through as a custom
       property instead. */
    box-shadow: 0 0 0 1px var(--bg-panel), 0 0 0 2px var(--dot-color, #fff);
}

/* ── Desktop: a wider centered column instead of a narrow one stretched full-width —
   using the extra space instead of just centering a phone-width layout (webapp/DESIGN.md's
   own milestone-8 commitment). The video is always visible above the Positions/Shots
   switch now (per discussion), so it gets the same centered treatment as everything else
   rather than a side-by-side split. ─────────────────────────────────────────────────────── */
@media (min-width: 768px) {
    .results-header,
    .video-stage,
    .segmented-control,
    .scope-chip-row,
    .results-pane {
        max-width: 900px;
        margin-left: auto;
        margin-right: auto;
    }
    #results-positions-pane { width: calc(65vh / 2 + 64px); height: 65vh; }
    .shots-pane .shot-menu {
        flex-wrap: wrap;
        overflow-x: visible;
    }
}
