/* ============================================================
   OnlyCharr — Reset, typography and global utilities
   Loaded after tokens.css, before everything else.
   ============================================================ */

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

/* Painted before anything else so the browser never flashes white while the
   rest of the CSS is still arriving. The layouts repeat this inline in
   <head> for the very first paint. */
html {
    background: #16181c;
    -webkit-text-size-adjust: 100%;
}

/* Thin top progress bar for soft navigation. */
.nav-progress {
    position: fixed;
    top: 0; left: 0;
    z-index: var(--z-toast);
    height: 2px;
    width: 0;
    background: var(--accent);
    opacity: 0;
    pointer-events: none;
}
.nav-progress.is-active {
    opacity: 1;
    width: 80%;
    transition: width 1.4s cubic-bezier(.1,.8,.2,1), opacity var(--dur-fast);
}
.nav-progress.is-done {
    width: 100%;
    opacity: 0;
    transition: width var(--dur-fast), opacity var(--dur-base) var(--dur-fast);
}

/* The swapped-in region should not show a focus ring just because we moved
   focus there for assistive tech. */
#main:focus { outline: none; }

body {
    margin: 0;
    /* Previously neither font-size nor line-height was set on body, so all
       prose inherited the UA default (~1.15) and ran far too tight. */
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    line-height: var(--lh-base);
    font-weight: var(--fw-normal);
    background: var(--bg-base);
    color: var(--text-primary);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    overscroll-behavior-y: none;
    -webkit-tap-highlight-color: transparent;
}

/* Locks background scroll while a modal or lightbox owns the viewport. */
body.is-locked { overflow: hidden; }

/* A class setting `display` outranks the UA rule behind the `hidden`
   attribute, so [hidden] elements stay visible unless this is stated. */
[hidden] { display: none !important; }

/* ---- Headings ------------------------------------------------------
   No global heading rules existed at all, which is why the image detail
   page shipped two different h1 sizes. */
h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-weight: var(--fw-semi);
    line-height: var(--lh-xl);
    letter-spacing: var(--tracking-tight);
    text-wrap: balance;
    color: var(--text-primary);
}
h1 { font-size: var(--fs-2xl); line-height: var(--lh-2xl); font-weight: var(--fw-bold); }
h2 { font-size: var(--fs-xl);  line-height: var(--lh-xl); }
h3 { font-size: var(--fs-lg);  line-height: var(--lh-lg); }
h4 { font-size: var(--fs-md);  line-height: var(--lh-md); }
h5, h6 { font-size: var(--fs-base); }

p { margin: 0 0 var(--sp-3); }
p:last-child { margin-bottom: 0; }

a {
    color: inherit;
    text-decoration: none;
    transition: color var(--transition);
}
a:hover { color: var(--accent); }

img, video { max-width: 100%; display: block; }
svg { display: block; flex-shrink: 0; }

ul, ol { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); }

hr { border: none; border-top: 1px solid var(--border-subtle); margin: var(--sp-5) 0; }

code, kbd, pre { font-family: var(--font-mono); font-size: 0.9em; }

/* Counts and stats stop jittering as they update. */
.tabular, .stat-number, .count { font-variant-numeric: tabular-nums; }

/* ---- Forms ---------------------------------------------------------
   Inherit the type stack rather than falling back to the UA default. */
input, textarea, select, button {
    font: inherit;
    color: inherit;
}
textarea { resize: vertical; }

::placeholder { color: var(--text-dimmed); opacity: 1; }

::selection {
    background: var(--accent-soft);
    color: var(--text-primary);
}

/* ---- Focus ---------------------------------------------------------
   The old stylesheets removed outlines in 11 places and substituted a
   ring at rgba(...,0.1) — about 1.2:1 against the page, i.e. invisible.
   One visible, consistent indicator for everything, keyboard-only. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--border-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}
:where(a, button, input, textarea, select, summary, [tabindex]):focus:not(:focus-visible) {
    outline: none;
}

/* ---- Utilities ----------------------------------------------------- */

/* Was referenced in four places and defined nowhere, so the labels it
   was meant to hide rendered as stray visible text. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}
/* Hidden until focused — used by the skip link. */
.sr-only-focusable:focus-visible {
    position: fixed;
    top: var(--sp-3); left: var(--sp-3);
    z-index: var(--z-toast);
    width: auto; height: auto;
    margin: 0; padding: var(--sp-3) var(--sp-4);
    overflow: visible;
    clip: auto; clip-path: none;
    background: var(--accent);
    color: var(--text-on-accent);
    font-weight: var(--fw-semi);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
}

.truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.clamp-2, .clamp-3 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.clamp-2 { -webkit-line-clamp: 2; line-clamp: 2; }
.clamp-3 { -webkit-line-clamp: 3; line-clamp: 3; }

.muted   { color: var(--text-muted); }
.dimmed  { color: var(--text-dimmed); }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }

.stack   { display: flex; flex-direction: column; gap: var(--sp-3); }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.spacer  { flex: 1 1 auto; }

/* Any wide child (tables, code) scrolls itself rather than the page. */
.scroll-x {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* ---- Media loading --------------------------------------------------
   Images fade in once decoded. Previously this pattern was duplicated in
   ten places, and a JS failure left every image permanently at opacity 0
   with no fallback. The noscript rule below closes that hole. */
.img-fade {
    opacity: 0;
    transition: opacity var(--dur-slow) var(--ease-out);
}
.img-fade.loaded { opacity: 1; }

/* ---- Motion --------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    /* The old block nulled `.card:hover .thumb img` while the actual zoom
       lived on `.card:hover .thumb` — so the most visible motion on the
       site kept firing. Cover the transform on hover generically. */
    :where(.card, .creator-card, .album-card, .studio-card, .btn,
           .stat-card, .like-btn, .action-btn, .scroll-top):hover,
    :where(.card, .creator-card, .album-card, .studio-card):hover :where(.thumb, .thumb img, img) {
        transform: none !important;
    }
    .img-fade { opacity: 1; }
}

/* Hover effects should not stick on touch devices. */
@media (hover: none) {
    .card:hover .thumb img,
    .card:hover .thumb { transform: none !important; }
}
