/* Flixtor app stylesheet.
 *
 * No framework. Repeated value math lives in @function, every rule lives in a
 * cascade layer, and classes name structural roles (.card, .sidebar, .tag,
 * ...) while appearance is derived from the HTML structure with element,
 * attribute and relational (:has) selectors. Templates therefore carry no
 * presentational utility classes. */

/* biome-ignore-all lint/style/noDescendingSpecificity: rules are grouped by
   component (.sidebar, .seg, .search, .poster, ...), so a later rule can
   legitimately target a different component with lower specificity than an
   earlier one. */

/* ── Custom functions ─────────────────────────────────────────── */

/* Every call site below also keeps a color-mix() fallback, so a browser
   without @function support still gets the right colour. */

/* Mix --color into a base (transparent by default) at --amount. */
@function --mix(--color, --amount <percentage>, --into: transparent) {
    result: color-mix(in srgb, var(--color) var(--amount), var(--into));
}

/* Darkened variant of a colour, used for hover states. */
@function --shade(--color) {
    result: color-mix(in srgb, var(--color) 82%, var(--text));
}

@layer base, components;

/* Enable cross-document view transitions for full page navigations */
@view-transition {
    navigation: auto;
}

/* ── Base ─────────────────────────────────────────────────────── */

@layer base {

    :root {
        color-scheme: light;

        /* Palette */
        --bg:          #f2f5f7;
        --surface:     #ffffff;
        --surface-2:   #e8edf1;
        --surface-3:   #dbe2e8;
        --text:        #1a232c;
        --text-dim:    #5a6a76;
        --border:      #d7dee4;
        --accent:      #0e7c8b;
        --on-accent:   #ffffff;
        --ok:          #1d7f4f;

        /* Shape & elevation */
        --radius:      .7rem;
        --radius-lg:   .9rem;
        --shadow-sm:   0 1px 2px color-mix(in srgb, var(--text) 8%, transparent);
        --shadow-md:   0 6px 18px color-mix(in srgb, var(--text) 14%, transparent);
    }

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

    html { -webkit-text-size-adjust: 100%; }

    body {
        margin: 0;
        background: var(--bg);
        color: var(--text);
        font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        font-size: 1rem;
        line-height: 1.5;
    }

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

    h1, h2, h3, h4, h5 { line-height: 1.2; margin: 0 0 .5rem; }
    p { margin: 0 0 .5rem; }
    a { color: var(--accent); }
    button { font: inherit; }

    :where(a, button, input, select, textarea, [tabindex]):focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
        border-radius: .25rem;
    }

    /* Inline SVG icons (from the {{icon}} template func), sized to text. */
    svg {
        width: 1.2em;
        height: 1.2em;
        flex: none;
        vertical-align: -0.2em;
    }

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

/* ── Components ───────────────────────────────────────────────── */

@layer components {

    /* ── App shell & sidebar ─────────────────────────────────── */

    .app {
        display: flex;
        min-height: 100dvh;
    }

    .sidebar {
        position: sticky;
        top: 0;
        flex: 0 0 14rem;
        display: flex;
        flex-direction: column;
        gap: .5rem;
        height: 100dvh;
        padding: 1rem .75rem;
        overflow-y: auto;
        background: var(--surface);
        border-right: 1px solid var(--border);
    }

    /* The brand is the sidebar's only direct link (nav links are nested). */
    .sidebar > a {
        display: flex;
        align-items: center;
        gap: .5rem;
        padding: .25rem .5rem 1rem;
        color: var(--text);
        font-size: 1.1rem;
        font-weight: 700;
        text-decoration: none;
        letter-spacing: .01em;
    }

    .sidebar > a img { width: 1.7rem; height: 1.7rem; border-radius: .45rem; }

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

    .sidebar nav a {
        display: flex;
        align-items: center;
        gap: .8rem;
        padding: .55rem .8rem;
        border-radius: var(--radius);
        color: var(--text);
        font-weight: 500;
        text-decoration: none;
    }

    .sidebar nav a:hover { background: var(--surface-2); }

    .sidebar nav a[aria-current="page"] {
        background: color-mix(in srgb, var(--accent) 14%, transparent);
        background: --mix(var(--accent), 14%);
        color: var(--accent);
    }

    .content {
        flex: 1;
        min-width: 0;
        width: min(100%, 96rem);
        margin-inline: auto;
        padding: clamp(1rem, 2.5vw, 2rem);
    }

    @media (max-width: 48rem) {
        .app { flex-direction: column; }

        /* On narrow screens the nav becomes a bar pinned to the bottom of the
           viewport, with room for the device's home indicator. */
        .sidebar {
            position: fixed;
            inset: auto 0 0 0;
            z-index: 10;
            flex-direction: row;
            align-items: center;
            gap: .25rem;
            height: auto;
            width: 100%;
            overflow-x: auto;
            padding: .4rem .75rem calc(.4rem + env(safe-area-inset-bottom));
            border-right: 0;
            border-top: 1px solid var(--border);
        }

        /* Keep the page clear of the fixed bar. */
        .content { padding-bottom: calc(4rem + env(safe-area-inset-bottom)); }

        .sidebar > a { padding: 0 .5rem 0 0; }
        .sidebar > a span { display: none; }

        .sidebar nav { flex-direction: row; }

        .sidebar nav a { padding: .45rem .6rem; gap: 0; }
        .sidebar nav a svg { width: 1.4em; height: 1.4em; }

        /* Label only on the active item, icons alone otherwise */
        .sidebar nav a:not([aria-current="page"]) span { display: none; }
    }

    /* ── Page headers ────────────────────────────────────────── */

    .page-head {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: .75rem 1.25rem;
        margin-bottom: 1.25rem;
    }

    .page-head h1 {
        display: flex;
        align-items: center;
        gap: .6rem;
        margin: 0;
        font-size: clamp(1.35rem, 2.5vw, 1.8rem);
    }

    .page-head h1 svg { width: 1.5em; height: 1.5em; }

    /* Meta line under the heading (e.g. network + Flixtor link). */
    .page-head p {
        margin: .15rem 0 0;
        color: var(--text-dim);
        font-size: .95rem;
    }

    .page-actions {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: .5rem;
        margin-inline-start: auto;
    }

    /* ── Controls ────────────────────────────────────────────── */

    /* Shape shared by every text control. Colours come from the structural
       rules below: ghost (neutral), outlined (internal links) or primary. */
    .page-actions :is(a, button),
    .card-actions a,
    .card-actions form button,
    .poster-actions :is(a, button) {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: .4rem;
        padding: .5rem 1rem;
        border: 1px solid transparent;
        border-radius: var(--radius);
        font-size: .9rem;
        font-weight: 600;
        line-height: 1.4;
        text-decoration: none;
        white-space: nowrap;
        cursor: pointer;
    }

    /* Ghost: page-level actions, the poster's Update, and external links. */
    .page-actions :is(a, button),
    .poster-actions :is(a, button),
    .card-actions a[target="_blank"] {
        background: var(--surface);
        border-color: var(--border);
        color: var(--text);
    }

    .page-actions :is(a, button):hover,
    .poster-actions :is(a, button):hover,
    .card-actions a[target="_blank"]:hover { background: var(--surface-2); }

    /* Outlined: internal links (View) are secondary to Add. */
    .card-actions a:not([target="_blank"]) {
        background: var(--surface);
        border-color: var(--accent);
        color: var(--accent);
    }

    .card-actions a:not([target="_blank"]):hover {
        background: color-mix(in srgb, var(--accent) 12%, var(--surface));
        background: --mix(var(--accent), 12%, var(--surface));
    }

    /* Primary: the Add form submit is the card's call to action. */
    .card-actions form button {
        background: var(--accent);
        color: var(--on-accent);
    }

    .card-actions form button:hover {
        background: color-mix(in srgb, var(--accent) 82%, var(--text));
        background: --shade(var(--accent));
    }

    /* Round icon-only control (mark an episode watched), in cards or tables. */
    .card-actions > button,
    td button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 2.3rem;
        height: 2.3rem;
        padding: 0;
        border: 1px solid var(--border);
        border-radius: 50%;
        background: var(--surface);
        color: var(--text);
        cursor: pointer;
    }

    .card-actions > button:hover,
    td button:hover { background: var(--surface-2); }

    /* ── Tags ────────────────────────────────────────────────── */

    /* Status pills (Finished, Pending, log level, ...). One named role, no
       presentational variant classes. */
    .tag {
        display: inline-flex;
        align-items: center;
        gap: .2rem;
        padding: .1rem .55rem;
        border-radius: 999px;
        background: var(--surface-3);
        color: var(--text-dim);
        font-size: .72rem;
        font-weight: 700;
        line-height: 1.6;
        white-space: nowrap;
    }

    /* ── Filter toolbar & segmented links ────────────────────── */

    .toolbar {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: .5rem;
        margin-bottom: 1.25rem;
    }

    .seg {
        display: inline-flex;
        padding: .2rem;
        gap: .2rem;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius);
    }

    .seg a {
        padding: .35rem .8rem;
        border-radius: calc(var(--radius) - .25rem);
        color: var(--text-dim);
        font-size: .88rem;
        font-weight: 500;
        text-decoration: none;
    }

    .seg a:hover { background: var(--surface-2); color: var(--text); }

    .seg a[aria-current="page"] {
        background: var(--accent);
        color: var(--on-accent);
    }

    /* ── Search fields ───────────────────────────────────────── */

    .search {
        position: relative;
        display: flex;
        flex: 1 1 14rem;
        min-width: 10rem;
        max-width: 22rem;
        align-items: center;
    }

    .search svg {
        position: absolute;
        left: .7rem;
        width: 1.1rem;
        height: 1.1rem;
        color: var(--text-dim);
        pointer-events: none;
    }

    .search input {
        width: 100%;
        padding: .5rem .8rem .5rem 2.2rem;
        border: 1px solid var(--border);
        border-radius: var(--radius);
        background: var(--surface);
        color: var(--text);
        font: inherit;
    }

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

    /* The search page's form is the only .search that is a direct child of
       the page content, so it gets the large standalone treatment. */
    .content > .search { max-width: 34rem; }
    .content > .search svg { width: 1.4rem; height: 1.4rem; left: 1rem; }
    .content > .search input { padding: .8rem 1rem .8rem 3rem; font-size: 1.05rem; }

    /* Results section that follows the big search box. */
    .content > .search + .cards { margin-top: 1.25rem; }

    /* ── Cards grid ──────────────────────────────────────────── */

    .cards {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 12.5rem), 1fr));
        gap: 1rem;
    }

    .card {
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-sm);
    }

    .card[data-href] { cursor: pointer; }

    .card[data-href]:hover {
        transform: translateY(-2px);
        border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
        border-color: --mix(var(--accent), 45%, var(--border));
        box-shadow: var(--shadow-md);
    }

    /* Poster / thumbnail, object-fit keeps grids even when art is square. */
    .card > img {
        aspect-ratio: 2 / 3;
        width: 100%;
        object-fit: cover;
        background: var(--surface-2);
    }

    /* The card body is the card's only direct <div>. */
    .card > div {
        display: flex;
        flex: 1;
        flex-direction: column;
        gap: .2rem;
        padding: .8rem 1rem 1rem;
    }

    .card h2 {
        margin: 0 0 .1rem;
        font-size: 1rem;
        font-weight: 650;
    }

    /* Show name above the episode title (episodes page). */
    .card h2 small {
        display: block;
        margin: 0;
        color: var(--text-dim);
        font-size: .8rem;
        font-weight: 600;
        line-height: 1.4;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .card p {
        margin: 0;
        color: var(--text-dim);
        font-size: .85rem;
    }

    /* Meta row: several inline <span>s (season, date, status). */
    .card p:has(span) {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: .35rem;
    }

    /* Dates row: two <time>s pushed to opposite ends (recent shows). */
    .card p:has(time) {
        display: flex;
        justify-content: space-between;
        gap: .5rem;
        margin-bottom: .25rem;
        font-size: .8rem;
    }

    /* Free text (summaries, descriptions) is clamped to three lines. */
    .card p:not(:has(span, time)) {
        display: -webkit-box;
        line-clamp: 3;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .card-actions {
        display: flex;
        align-items: center;
        gap: .5rem;
        margin-top: auto;
        padding-top: .6rem;
    }

    /* Links and the Add form share the row; tags and icon buttons stay small. */
    .card-actions > :is(a, form) { flex: 1; }
    .card-actions > form button { width: 100%; }
    .card-actions > :is(span, button) { flex: none; }

    /* ── Show detail page ────────────────────────────────────── */

    .show-desc {
        margin: 0 0 1.25rem;
        color: var(--text-dim);
        max-width: 72ch;
    }

    .detail {
        display: grid;
        grid-template-columns: minmax(11rem, 15rem) minmax(0, 1fr);
        gap: 1.5rem;
        align-items: start;
    }

    .poster {
        overflow: hidden;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-sm);
    }

    .poster img { aspect-ratio: 2 / 3; width: 100%; object-fit: cover; }

    .poster-actions { display: grid; gap: .5rem; padding: .7rem; }
    .poster-actions :is(a, button) { width: 100%; }

    /* Episode table columns: watched, downloaded, episode number,
       title/info, published date. */
    .detail td:nth-child(1),
    .detail td:nth-child(2),
    .detail td:nth-child(5) { text-align: center; }

    .detail td:nth-child(3) {
        text-align: center;
        font-variant-numeric: tabular-nums;
    }

    .detail td:nth-child(4) > span { display: block; }
    .detail td:nth-child(4) > span + span {
        margin-top: .1rem;
        color: var(--text-dim);
        font-size: .82rem;
    }

    /* On narrow screens the detail grid collapses to a single column */
    @media (max-width: 48rem) {
        .detail { grid-template-columns: minmax(0, 1fr); }
        .detail .poster { max-width: 24rem; }
    }

    /* ── Tables ──────────────────────────────────────────────── */

    .table-wrap {
        overflow-x: auto;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-sm);
    }

    table {
        width: 100%;
        border-collapse: collapse;
        font-size: .92rem;
    }

    tbody tr:nth-child(even) {
        background: color-mix(in srgb, var(--text) 3%, transparent);
        background: --mix(var(--text), 3%);
    }

    td {
        padding: .55rem .8rem;
        vertical-align: middle;
        border-top: 1px solid var(--border);
        text-align: start;
    }

    /* The logs table is the only table that is a direct child of the content,
       and its timestamps are monospaced. */
    .content > .table-wrap time {
        font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    }

    /* ── Empty states ────────────────────────────────────────── */

    .empty {
        grid-column: 1 / -1;
        padding: 3rem 1rem;
        color: var(--text-dim);
        text-align: center;
        border: 1px dashed var(--border);
        border-radius: var(--radius-lg);
    }

    /* ── Login gate ──────────────────────────────────────────── */

    .login {
        max-width: 22rem;
        margin: clamp(3rem, 12vh, 6rem) auto;
        padding: 1.5rem;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-sm);
    }

    .login h1 {
        display: flex;
        align-items: center;
        gap: .6rem;
        margin: 0;
        font-size: 1.25rem;
    }

    .login form {
        display: flex;
        flex-direction: column;
        gap: .9rem;
        margin-top: 1rem;
    }

    .login label {
        display: flex;
        flex-direction: column;
        gap: .3rem;
        color: var(--text-dim);
        font-size: .85rem;
        font-weight: 600;
    }

    .login input {
        padding: .55rem .8rem;
        border: 1px solid var(--border);
        border-radius: var(--radius);
        background: var(--surface);
        color: var(--text);
        font: inherit;
    }

    .login button {
        padding: .6rem 1rem;
        border: 1px solid transparent;
        border-radius: var(--radius);
        background: var(--accent);
        color: var(--on-accent);
        font-size: .95rem;
        font-weight: 600;
        cursor: pointer;
    }

    .login button:hover {
        background: color-mix(in srgb, var(--accent) 82%, var(--text));
        background: --shade(var(--accent));
    }

    /* Login errors are announced with role="alert". */
    .login [role="alert"] {
        margin: 0;
        color: var(--accent);
        font-size: .85rem;
    }

    /* ── Motion & a11y ───────────────────────────────────────── */

    @media (prefers-reduced-motion: reduce) {
        *, *::before, *::after {
            transition: none;
            animation: none;
        }
    }

    /* htmx request feedback on swap targets */
    .htmx-request { opacity: .6; pointer-events: none; }
}
