/* ─────────────────────────────────────────────────────
   DESIGN TOKENS — CSS custom properties for use outside
   Tailwind utilities (custom components, animations, etc.)
───────────────────────────────────────────────────── */
:root {
    --brand:         #f38b36;
    --brand-rgb:     243, 139, 54;
    --brand-light:   #f4984a;
    --brand-hover:   #db7d31;
    --brand-active:  #c26f2b;
    --text-on-brand: #100f13;

    --surface-app:    #100f13;
    --surface-canvas: #17151a;
    --surface-dialog: var(--surface-app);
    --surface-raised:   rgba(255, 255, 255, 0.04);
    /* The quietest overlay in the set. Lives here rather than with the app's other --tk-surface-*
       overlays because --surface-input is defined from it. */
    --tk-surface-subtle: rgba(255, 255, 255, 0.02);
    /* An input reads as a dip in whatever it sits on rather than a fixed swatch, so it takes the
       subtle overlay: the same fill the quiet rows elsewhere are drawn on. */
    --surface-input:    var(--tk-surface-subtle);
    /* A readonly field carries no border, so its fill is the only thing telling it apart from a field
       you can type in — one step off the editable 0.02 was not a difference anyone could see. Three
       steps up reads as a plate rather than a field, without climbing back to --surface-neutral,
       where it outranked the inputs around it. */
    --surface-input-readonly: rgba(255, 255, 255, 0.06);
    /* A fill that has to stay legible on its own: sheet grab handles, the level meter's empty track,
       the picked row in a level picker. Not tied to inputs — it is the visibility that matters. */
    --surface-neutral:  rgb(204 204 204 / 10%);
    --surface-hover:    rgba(39, 39, 42, 0.4);

    --text-hi:      #ede8e3;
    --text-hi-rgb:  237, 232, 227;
    --text-mid:     #7c756e;
    --text-lo:      #4a4540;
    --text-faint:   #3a3530;
    --text-nav:     #a1a1aa;
    --text-white:   #ffffff;
    --white-rgb:    255, 255, 255;
    --black-rgb:    0, 0, 0;

    --border:       rgba(39, 39, 42, 0.60);
    --border-hover: rgba(63, 63, 70, 0.80);

    --chip-bg:   rgba(63, 63, 70, 0.60);
    --chip-text: #a1a1aa;

    --heading-accent:      #ede8e3;
    --border-input:        rgba(255, 255, 255, 0.07);
    --color-success:       #22c55e;
    --color-success-rgb:   34, 197, 94;
    --color-error:         #f87171;
    --color-error-rgb:     248, 113, 113;
    --color-error-bg:      rgb(113 44 44 / 46%);
    --color-danger:        #dc3545;
    --color-status-airing: #4ade80;
    --color-status-upcoming: #fb923c;
    --color-attention:     #e0a458;

    --bundle-headlines: #D4783C;
    --bundle-reviews:   #7B6BB5;
    --bundle-behind:    #3D8B7A;
    --bundle-culture:   #C75B7A;
    --bundle-business:  #5B7EAF;
    --bundle-tv_headlines: var(--bundle-headlines);
    --bundle-tv_reviews:   var(--bundle-reviews);
    --bundle-tv_behind:    var(--bundle-behind);
    --bundle-tv_culture:   var(--bundle-culture);
    --bundle-tv_business:  var(--bundle-business);
    --bundle-gaming_headlines:   var(--bundle-headlines);
    --bundle-gaming_reviews:     var(--bundle-reviews);
    --bundle-gaming_behind:      var(--bundle-behind);
    --bundle-gaming_culture:     var(--bundle-culture);
    --bundle-gaming_business:    var(--bundle-business);
    --bundle-gaming_competition: #be3923;

    --tk-radius-sm: 0.375rem;
    --tk-radius-md: 0.5rem;
    --tk-radius-lg: 0.75rem;
    --tk-radius-xl: 1rem;

    /* The corner a text input takes, and with it anything sitting on an input's line that has to
       read as its equal — a control in a list row, a button beside one. Between md and lg, which is
       why it is its own token rather than either of them. */
    --tk-radius-input: 10px;

    /* User text-size preference: --font-scale is driven by the data-font-size
       attribute on <html> (stamped server-side from the font-size cookie).
       All text sizes must go through these variables so the setting reaches
       every component; spacing and icons intentionally do not scale. */
    --font-scale: 1;

    --text-4xl:     calc(2.25rem   * var(--font-scale));
    --text-3xl:     calc(1.875rem  * var(--font-scale));
    --text-lg:      calc(1.125rem  * var(--font-scale));
    --text-base:    calc(1rem      * var(--font-scale));
    --text-md:      calc(0.9375rem * var(--font-scale));
    --text-sm:      calc(0.875rem  * var(--font-scale));
    --text-caption: calc(0.8125rem * var(--font-scale));
    --text-xs:      calc(0.75rem   * var(--font-scale));

    /* --font-sans / --font-display are defined in Styles/theme.css (@theme)
       and emitted into the compiled tailwind.css. */
}

html[data-font-size='small'] { --font-scale: 0.875; }
html[data-font-size='large'] { --font-scale: 1.125; }
html[data-font-size='extra-large'] { --font-scale: 1.25; }

/* On mobile every size label renders one step larger, so the untouched default
   is comfortable on small screens. Extra Large is not offered on mobile (it
   equals Large); legacy extra-large cookies keep rendering at the same 1.25. */
@media (max-width: 767px) {
    :root { --font-scale: 1.125; }
    html[data-font-size='small'] { --font-scale: 1; }
    html[data-font-size='large'] { --font-scale: 1.25; }
    html[data-font-size='extra-large'] { --font-scale: 1.25; }
}

/* User feed-width preference: --feed-max-width caps the article column and is
   driven by the data-feed-width attribute on <html> (stamped server-side from
   the reading-preferences cookie). Only the feed article list reads this token;
   the rest of the app keeps its own widths. Comfortable is the default. */
:root { --feed-max-width: 64rem; }
html[data-feed-width='comfortable'] { --feed-max-width: 64rem; }
html[data-feed-width='full'] { --feed-max-width: 100%; }

* { font-family: var(--font-sans); }
html { font-size: 16px; }
/* Body font-size routes inherited text through the scaled token: text that
   declares no explicit size still follows the user's text-size preference,
   while rem-based spacing and icon sizes stay fixed. */
body { color: var(--text-mid); font-size: var(--text-base); }

/* Custom scrollbar */
@media (pointer: fine) {
    ::-webkit-scrollbar { width: 6px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--text-faint); border-radius: 3px; }
    ::-webkit-scrollbar-thumb:hover { background: var(--text-lo); }
    * { scrollbar-width: thin; scrollbar-color: var(--text-faint) transparent; }
}
:root h1, :root h2, :root h3, :root h4, :root h5, :root h6 { color: var(--heading-accent); }

.text-success { color: var(--color-success); }
.text-error { color: var(--color-error); }

/* Blazor validation messages */
.validation-message {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.5rem;
    font-size: var(--text-xs);
    font-style: normal;
    color: var(--color-error);
    animation: tk-fade-up 0.3s ease-out;
}
.validation-message::before {
    content: '';
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='8' x2='12' y2='12'/%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='8' x2='12' y2='12'/%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'/%3E%3C/svg%3E") center / contain no-repeat;
}

@keyframes tk-fade-up {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}


.brand-glow-sm  { background: radial-gradient(ellipse at 50% 55%, rgba(var(--brand-rgb), 0.04) 0%, transparent 65%); }
.brand-glow-card { background: radial-gradient(ellipse at 50% 110%, rgba(var(--brand-rgb), 0.14) 0%, transparent 65%); }
.focus-brand-ring { box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.08); }

.tk-btn-spinner {
    width: 16px;
    height: 16px;
    border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: tk-btn-spin 0.6s linear infinite;
}

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



@keyframes tk-enter {
    from { opacity: 0; transform: translateY(16px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}


/* ─── Error Fallback ─── */
.tk-error-fallback {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 3rem 1.5rem;
    min-height: 60vh;
    animation: tk-enter 0.5s ease-out;
}
.tk-error-fallback-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(248, 113, 113, 0.08);
    border: 1px solid rgba(248, 113, 113, 0.15);
    color: var(--color-error);
    margin-bottom: 1.5rem;
}
.tk-error-fallback-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: calc(1.5rem * var(--font-scale));
    color: var(--text-hi);
    margin: 0 0 0.5rem;
}
.tk-error-fallback-description {
    font-size: var(--text-sm);
    color: var(--text-mid);
    margin: 0 0 2rem;
    max-width: 24rem;
}
.tk-error-fallback-btn {
    display: inline-flex;
    align-items: center;
    padding: 0.625rem 1.5rem;
    border-radius: var(--tk-radius-lg);
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--border);
    color: var(--text-hi);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s;
}
.tk-error-fallback-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: var(--border-hover);
}

/* ─── Sidebar Nav Active Indicator ─── */
.tk-nav-item {
    width: calc(100% - 1rem);
    margin: 0 0.5rem;
    border-radius: var(--tk-radius-md);
    background: none;
    border: none;
    color: inherit;
    text-decoration: none;
    transition: color 0.15s, background-color 0.15s;
}
.tk-nav-item--active {
    color: var(--brand);
    background-color: rgba(var(--brand-rgb), 0.1);
}
.tk-nav-item--active:hover {
    background-color: rgba(var(--brand-rgb), 0.14);
}

/* ─── Hover Effects ─── */
/* Selectors use a doubled class to bump specificity above Blazor scoped-CSS
   equivalents (`.tk-foo[b-xxx]`), which load later and would otherwise win ties. */

/* A touch has no hover to leave, so a tapped element keeps :hover until something else is tapped —
   which is why a button read as still pressed when its sheet came back. None of these intents mean
   anything without a pointer that can rest on an element, so on touch they simply do not apply. */
@media (hover: hover) {
    /* Intent A — quiet surface hover. Default for nav rows, menu rows, list rows. */
    .tk-hover-surface.tk-hover-surface:hover {
        background-color: var(--surface-hover);
    }

    /* Intent B — surface + text brighten. Standalone action buttons sitting on content. */
    .tk-hover-surface-strong.tk-hover-surface-strong:hover:not(:disabled) {
        background-color: var(--surface-hover);
        color: var(--text-hi);
    }

    /* Intent C — text-only brand accent. Raw text links/actions: label and icon turn brand orange, no background. */
    .tk-hover-text.tk-hover-text:hover:not(:disabled) {
        color: var(--brand);
    }

    /* Intent D — brand accent. Rare, only for semantic brand affordances. */
    .tk-hover-brand.tk-hover-brand:hover:not(:disabled) {
        background-color: rgba(var(--brand-rgb), 0.08);
        color: var(--brand);
    }

    /* Destructive variant — compose with a surface hover class. */
    .tk-hover-destructive.tk-hover-destructive:hover:not(:disabled) {
        color: var(--color-error);
    }

    /* Card-lift — neutral border/shadow/transform polish for larger picker cards. */
    .tk-hover-card-lift.tk-hover-card-lift:hover:not(:disabled) {
        border-color: var(--border-hover);
        transform: translateY(-2px);
        box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
    }
}

/* Language picker — shared by the interactive TkLanguagePicker and the static SSR landing
   language picker (TkLandingLanguagePicker), which reuses these classes on plain markup. */
.tk-langpicker-backdrop {
    position: fixed;
    inset: 0;
    z-index: 60;
}

.tk-langpicker {
    position: relative;
    z-index: 70;
}
.tk-langpicker-trigger {
    display: flex; align-items: center; gap: 0.375rem;
    background: none;
    border: none;
    font-family: inherit;
    color: var(--text-mid);
    font-size: 0.82rem;
    cursor: pointer;
    transition: color 0.2s;
}
.tk-langpicker-dropdown {
    position: absolute; top: 100%; right: 0; z-index: 70;
    min-width: 10rem; margin-top: 0.25rem;
    padding: 0.25rem;
    background: var(--surface-canvas);
    border: 1px solid var(--border);
    border-radius: var(--tk-radius-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.tk-langpicker-option {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: none; border-radius: var(--tk-radius-md);
    background: transparent;
    color: var(--text-mid);
    font-size: var(--text-caption);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.tk-langpicker-option:hover { background: rgba(255,255,255,0.05); }
.tk-langpicker-option.active { color: var(--text-hi); }
.tk-langpicker-check {
    width: 0.875rem;
    height: 0.875rem;
    flex-shrink: 0;
    color: var(--brand);
}

/* Names the sheet on phones. A dropdown hanging off its trigger needs no title — the trigger is
   right there saying what it is; a sheet that takes the bottom of the screen has left its trigger
   behind, so it says so itself, the way every other sheet in the app does. */
.tk-langpicker-sheet-title {
    display: none;
}

/* Phones: the dropdown becomes a bottom sheet in the app's mobile-sheet language — dimmed
   blurred backdrop, canvas surface, grab-handle pill, slide-up. Same markup and open/close
   mechanics (hidden toggling, backdrop tap, Escape); only the styling changes, so the static
   SSR pickers get it for free. */
@media (max-width: 767px) {
    /* The wrapper's stacking context is dropped for the sheet layer to mean anything: nested inside
       it, the sheet could only ever be as high as the wrapper, and the bars pinned to the bottom of
       a phone screen sit higher than that. Without it, backdrop and sheet take the app's sheet band
       directly — and the trigger, left behind in the page, gets dimmed like the rest of it. */
    .tk-langpicker {
        z-index: auto;
    }

    /* A thumb-sized target for the nav's one action: the padding grows the hit area and the
       negative margin gives it back, so the nav keeps exactly the layout it has today. */
    .tk-langpicker-trigger {
        padding: 0.625rem 0.5rem;
        margin: -0.625rem -0.5rem;
    }

    .tk-langpicker-backdrop {
        z-index: 1200;
        background: rgba(var(--black-rgb), 0.6);
        backdrop-filter: blur(0.1875rem);
        -webkit-backdrop-filter: blur(0.1875rem);
    }

    /* Metrics are TkMobileSheet's, so the two read as one sheet: same gutters, same grip, same
       0.375rem above it, same safe-area foot. The top padding carries the grip strip too
       (0.75rem lead + 0.3125rem pill + 0.875rem trail), which that sheet spends on a real element. */
    .tk-langpicker-dropdown {
        position: fixed;
        inset: auto 0 0 0;
        z-index: 1201;
        margin-top: 0;
        border-bottom: none;
        border-radius: var(--tk-radius-xl) var(--tk-radius-xl) 0 0;
        padding: 2.3125rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom));
        box-shadow: 0 -1rem 4rem rgba(var(--black-rgb), 0.6);
        animation: tk-langpicker-sheet-in 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
    }

    /* The sheets' grab-handle pill, drawn in CSS so the markup stays shared with the
       desktop dropdown. Decorative only — closing is backdrop tap or Escape. */
    .tk-langpicker-dropdown::before {
        content: "";
        position: absolute;
        top: 1.125rem;
        left: 50%;
        transform: translateX(-50%);
        width: 2.5rem;
        height: 0.3125rem;
        border-radius: 999px;
        background: var(--surface-neutral);
    }

    /* The section label TkMobileSheet titles itself with, sitting flush in the sheet's gutter while
       the options below keep their own row padding — same offset the feed switcher's list has. */
    .tk-langpicker-sheet-title {
        display: block;
        padding: 0 0 0.625rem;
        font-size: var(--text-sm);
        font-weight: 600;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--text-hi);
    }

    /* List rows, at the feed switcher's height and gap rather than a menu item's padding. */
    .tk-langpicker-option {
        min-height: 3.5rem;
        gap: 0.85rem;
        padding: 0.5rem 0.75rem;
        font-size: var(--text-base);
    }

    /* The current language, marked the way the feed switcher marks the current feed. */
    .tk-langpicker-option.active {
        color: var(--brand);
        font-weight: 600;
    }

    /* TkIcon's Check at its default 18px, weight included — the desktop dropdown's check is drawn
       smaller and heavier to sit in a menu, and at row scale that reads as the wrong mark. */
    .tk-langpicker-check {
        width: 1.125rem;
        height: 1.125rem;
        stroke-width: 2.2;
    }
}

@keyframes tk-langpicker-sheet-in {
    from {
        transform: translateY(100%);
    }

    to {
        transform: translateY(0);
    }
}
