/*
  УкрГеймдев — cyberpunk-inspired theme.
  Generic sci-fi/neon-glass aesthetic (angular fonts, cut corners, neon glow) —
  not tied to any specific game's assets, logos, or trademarks.
*/

:root {
    --bg-deep: #0a1330;
    --bg-panel: #101c44;
    --bg-panel-2: #14204f;

    --neon-blue: #2fd9ff;
    --neon-blue-soft: rgba(47, 217, 255, 0.35);
    --neon-blue-dim: rgba(47, 217, 255, 0.16);

    --neon-red: #ff4d6d;
    --neon-red-soft: rgba(255, 77, 109, 0.45);

    --gold: #f2c14e;
    --gold-soft: rgba(242, 193, 78, 0.45);

    --neon-green: #3ddc84;
    --neon-green-soft: rgba(61, 220, 132, 0.45);

    --text: #dce6f5;
    --text-muted: #91a3c7;

    --cut: 16px;
    --cut-sm: 10px;
}

/* ---------- base ---------- */

body {
    background: var(--bg-deep);
    color: var(--text);
    font-family: "Rajdhani", "Segoe UI", sans-serif;
    font-size: 1.05rem;
    min-height: 100vh;
    position: relative;
}

/* Ambient gradients + scanline texture, merged into one fixed-position
   layer instead of body's own background-attachment: fixed — the latter
   forces a full repaint on every scroll frame in most engines (it can't be
   promoted to its own compositor layer the way position: fixed can), which
   is a well-known Windows/Chromium scroll-jank source. A position: fixed
   pseudo-element gives the exact same "stays put while scrolling" look at
   a fraction of the cost.
   z-index: -1 (not main's own +1 stacking context) — a positioned ancestor
   with z-index traps ALL descendants (including Bootstrap modals/dropdowns,
   whose backdrop is appended straight to <body>) inside its local stacking
   order, so the backdrop — outside that context — always wins regardless of
   the modal's own z-index. Pushing the background behind instead avoids the
   footgun entirely. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: -1;
    background:
        linear-gradient(to right, rgba(255, 77, 109, 0.08), transparent 15%),
        linear-gradient(to left, rgba(255, 77, 109, 0.08), transparent 15%),
        radial-gradient(ellipse at top left, rgba(47, 217, 255, 0.08), transparent 45%),
        radial-gradient(ellipse at bottom right, rgba(242, 193, 78, 0.06), transparent 50%),
        repeating-linear-gradient(
            to bottom,
            rgba(255, 255, 255, 0.015) 0,
            rgba(255, 255, 255, 0.015) 1px,
            transparent 1px,
            transparent 3px
        );
}

a {
    color: var(--neon-blue);
}
a:hover {
    color: #7ee9ff;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: "Orbitron", "Rajdhani", sans-serif;
    color: var(--gold);
    text-shadow: 0 0 12px var(--gold-soft);
    letter-spacing: 0.03em;
}

/* card headings stay red — everything else above is gold */
.card-title {
    color: var(--neon-red);
    text-shadow: 0 0 12px var(--neon-red-soft);
}

.text-muted {
    color: var(--text-muted) !important;
}

/* ---------- cut-corner glass panel (cards, forms, alerts) ---------- */

.card,
.alert,
.cyber-panel {
    background: rgba(16, 28, 68, 0.55);
    border: 1px solid var(--neon-blue-soft);
    border-radius: 0;
    color: var(--text);
    clip-path: polygon(
        0 0,
        calc(100% - var(--cut)) 0,
        100% var(--cut),
        100% 100%,
        var(--cut) 100%,
        0 calc(100% - var(--cut))
    );
    transition: filter 0.2s ease, transform 0.2s ease;
}

.card:hover {
    filter: drop-shadow(0 0 16px rgba(47, 217, 255, 0.28));
}

/* .cyber-panel clips overflow to its cut-corner shape via clip-path, so
   content that doesn't fit gets invisibly cut off rather than wrapping.
   table-layout: auto (the default) sizes columns from their "preferred"
   content width — for a single-word label like "Платформи" or "Розробник"
   that preferred width is the whole word (nothing to break at), so once
   the panel narrows past that, auto-layout renders the whole TABLE wider
   than its container instead of shrinking (confirmed: at 992px every row's
   <td> right edge sat ~8.5px past the panel's edge, identically, even
   though every cell's own text was short). table-layout: fixed makes the
   50/50 split a hard cap regardless of content — overflow-wrap: break-word
   is still needed on top of it, since a fixed-width column doesn't
   automatically break a word that's wider than its own column, it just
   spills into the neighbouring cell. */
.game-meta-table {
    table-layout: fixed;
    width: 100%;
}
.game-meta-table th {
    width: 55%;
    overflow-wrap: break-word;
}
.game-meta-table td {
    width: 45%;
    overflow-wrap: break-word;
}

/* The studio/publisher link is display:inline-flex with its default
   flex-wrap: nowrap, which keeps the logo and name on one forced line —
   let it wrap onto a second line (and break the name itself if a single
   word is still too wide) instead of overflowing its now fixed-width cell. */
.cyber-panel table td a.d-inline-flex {
    max-width: 100%;
    flex-wrap: wrap;
    overflow-wrap: anywhere;
}

/* ---------- browse cards (games/news/articles/overviews/collections/blogs/
   videos — the clickable gallery cards, as opposed to review/comment/
   moderation cards which keep the plain blue hover above) ---------- */

.browse-card {
    border-color: var(--neon-blue-soft);
}

/* Border stays the same 1px width on hover (just changes color) and the glow
   reuses the existing filter/transition already set on .card — nothing about
   the card's box size changes, so the layout never shifts. */
.browse-card:hover {
    border-color: var(--neon-red);
    filter: drop-shadow(0 0 16px var(--neon-red-soft));
}

.browse-card .card-img-top {
    aspect-ratio: 16 / 9;
    object-fit: cover;
    transition: transform 0.35s ease;
}

/* clip-path on .card already clips overflowing content to the card's own
   shape, so the zoomed image can't spill into neighboring cards/rows. */
.browse-card:hover .card-img-top {
    transform: scale(1.2);
}

.card-body {
    position: relative;
}

.card-title a {
    text-decoration: none;
}

@media (max-width: 576px) {
    :root {
        --cut: 10px;
    }
}

/* ---------- article cover cards (image fills the whole card, text overlaid) ---------- */

.article-cover-card {
    position: relative;
    display: block;
    min-height: 220px;
    background-color: var(--bg-panel);
    overflow: hidden;
}

/* A real <img> (not a CSS background-image) so the cover is actually in the
   DOM — crawlable, has its own alt text, shows up in Google Images. Sized
   the same way a background-image would be (absolute, inset:0, cover) so
   swapping this in changed nothing about how the card looks. */
.article-cover-card__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.35s ease;
    z-index: 0;
}

.browse-card.article-cover-card:hover .article-cover-card__img {
    transform: scale(1.2);
}

.article-cover-card--featured {
    min-height: 360px;
}

/* Games-list promo banner linking to /collections/ — same technique as
   article-cover-card (image fills the card, text overlaid), just its own
   fixed 200px height instead of that class's min-height. */
.collections-banner-card {
    position: relative;
    display: block;
    height: 200px;
    width: 100%;
    background-color: var(--bg-panel);
    background-size: cover;
    background-position: center;
    overflow: hidden;
}

.collections-banner-card__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    padding: 1.25rem;
    background: linear-gradient(
        to top,
        rgba(4, 8, 20, 0.92) 0%,
        rgba(4, 8, 20, 0.55) 45%,
        transparent 85%
    );
}

.collections-banner-card__overlay h3 {
    color: #fff;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.85);
}

.article-cover-card__overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 1.25rem;
    background: linear-gradient(
        to top,
        rgba(4, 8, 20, 0.92) 0%,
        rgba(4, 8, 20, 0.55) 45%,
        transparent 85%
    );
}

/* Taken out of the overlay's flex column (which stacks title/date at the
   bottom) and pinned to its own corner instead, so it doesn't sit above the
   title as if it were centered. */
.article-cover-card__kind-badge {
    position: absolute;
    z-index: 1;
    bottom: 1.25rem;
    right: 1.25rem;
}

.article-cover-card__views-badge {
    position: absolute;
    z-index: 1;
    top: 0.75rem;
    left: 0.75rem;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    font-size: 0.8rem;
    color: #dfe6f2;
    background: rgba(4, 8, 20, 0.65);
    border: 1px solid var(--neon-blue-soft);
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
}

.article-cover-card .card-title {
    color: #fff;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.85);
}

.article-cover-card p {
    color: #dfe6f2;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
}

.article-cover-card:hover .card-title {
    color: var(--gold);
}

/* ---------- gold accents ---------- */

.cyber-gold {
    color: var(--gold);
    text-shadow: 0 0 8px var(--gold-soft);
    font-weight: 600;
}

.cyber-red {
    color: var(--neon-red) !important;
    text-shadow: 0 0 8px var(--neon-red-soft);
    font-weight: 600;
}

/* ---------- war support banner ---------- */

.war-support-banner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.65rem;
    padding: 0.5rem 1rem;
    margin-bottom: 1.5rem;
    background: rgba(16, 28, 68, 0.55);
    border-top: 2px solid #0057b7;
    border-bottom: 2px solid #ffd700;
    color: var(--text);
    text-align: center;
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

.war-support-banner__stripe {
    display: inline-block;
    width: 18px;
    height: 12px;
    flex-shrink: 0;
    background: linear-gradient(to bottom, #0057b7 50%, #ffd700 50%);
}

/* ---------- social subscribe banner ---------- */

.social-subscribe-banner {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    min-height: 170px;
    padding: 1.75rem 2rem;
    margin-bottom: 1.5rem;
    overflow: hidden;
    background: linear-gradient(135deg, var(--bg-panel) 0%, var(--bg-panel-2) 55%, rgba(255, 77, 109, 0.28) 130%);
    border: 1px solid var(--neon-red-soft);
    border-radius: 1rem;
}

.social-subscribe-banner__content {
    position: relative;
    z-index: 1;
    max-width: 560px;
}

.social-subscribe-banner__eyebrow {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--neon-red);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.social-subscribe-banner__heading {
    margin-bottom: 1rem;
    color: #fff;
    font-family: "Orbitron", sans-serif;
    font-size: 1.4rem;
    font-weight: 800;
    line-height: 1.3;
}

.social-subscribe-banner__links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* Color/hover come from Bootstrap's own .btn-outline-danger (already
   themed neon-red, see the ---------- buttons ---------- section) — this
   only adds the icon+label layout on top. */
.social-subscribe-banner__cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.social-subscribe-banner__logo {
    position: relative;
    z-index: 1;
    flex-shrink: 0;
    height: 88px;
    width: auto;
    object-fit: contain;
    display: none;
}

@media (min-width: 768px) {
    .social-subscribe-banner__logo {
        display: block;
    }
}

/* Below md, the logo above is already hidden — but the card itself still
   used desktop padding/min-height/heading size, so on a phone it stayed
   nearly as tall as the min-height even with far less content to fill it. */
@media (max-width: 767px) {
    .social-subscribe-banner {
        min-height: 0;
        padding: 1.1rem 1.25rem;
        border-radius: 0.75rem;
    }

    .social-subscribe-banner__eyebrow {
        font-size: 0.7rem;
    }

    .social-subscribe-banner__heading {
        margin-bottom: 0.75rem;
        font-size: 1.15rem;
    }
}

/* ---------- navbar ---------- */

/* backdrop-filter forces its own stacking context (same category of footgun
   as body::before above) — without an explicit position+z-index here, the
   whole navbar (dropdowns included) paints as one layer *below* <main>'s
   content, since main comes later in DOM order. Position+z-index makes the
   navbar's stacking context win outright instead of falling back to DOM order.
   sticky (not fixed) keeps it in normal flow until the page scrolls past it —
   no extra top-padding hack needed on <main> to compensate for a removed-
   from-flow fixed header. */
.navbar {
    padding-top: 2px;
    padding-bottom: 2px;
    background: rgba(10, 19, 48, 0.85) !important;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--neon-blue-soft);
    box-shadow: 0 2px 20px rgba(47, 217, 255, 0.12);
    position: sticky;
    top: 0;
    z-index: 1030;
}

/* Logo fills the navbar row instead of Bootstrap's default ~5px
   top/bottom brand padding, without changing the navbar's own height —
   the image is sized to what that padding used to reserve. */
.navbar-brand {
    padding-top: 0;
    padding-bottom: 0;
}

.navbar-brand img {
    height: 62px;
    width: auto;
}

.navbar .nav-link {
    color: var(--text) !important;
}
.navbar .nav-link:hover {
    color: var(--neon-blue) !important;
}
.navbar .nav-link.active {
    color: var(--neon-red) !important;
    text-shadow: 0 0 8px var(--neon-red-soft);
}

.navbar-toggler {
    border-color: var(--neon-blue-soft);
}
.navbar-toggler:focus {
    box-shadow: 0 0 0 3px var(--neon-blue-dim);
}

.navbar .dropdown-menu {
    background: var(--bg-panel);
    border: 1px solid var(--neon-blue-soft);
    border-radius: 0;
    box-shadow: 0 4px 20px rgba(47, 217, 255, 0.15);
}
.navbar .dropdown-item {
    color: var(--text);
}
.navbar .dropdown-item:hover,
.navbar .dropdown-item:focus {
    background: rgba(255, 77, 109, 0.12);
    color: var(--neon-red);
}
.navbar .dropdown-divider {
    border-color: var(--neon-blue-soft);
}

/* ---------- buttons ---------- */

.btn {
    font-family: "Rajdhani", sans-serif;
    font-weight: 600;
    letter-spacing: 0.03em;
    border-radius: 0;
    clip-path: polygon(0 0, calc(100% - var(--cut-sm)) 0, 100% var(--cut-sm), 100% 100%, var(--cut-sm) 100%, 0 calc(100% - var(--cut-sm)));
}

.btn-primary {
    background: rgba(47, 217, 255, 0.15);
    border-color: var(--neon-blue);
    color: var(--neon-blue);
}
.btn-primary.active, .btn-primary:hover, .btn-primary:focus {
    background: var(--neon-blue);
    border-color: var(--neon-blue);
    color: #04101f;
    box-shadow: 0 0 16px var(--neon-blue-soft);
}

.btn-outline-light {
    border-color: var(--neon-blue-soft);
    color: var(--text);
}
.btn-outline-light:hover {
    background: rgba(47, 217, 255, 0.15);
    border-color: var(--neon-blue);
    color: var(--neon-blue);
}

.btn-outline-secondary {
    border-color: rgba(220, 230, 245, 0.3);
    color: var(--text-muted);
}
.btn-outline-secondary:hover {
    border-color: var(--text-muted);
    color: var(--text);
    background: rgba(145, 163, 199, 0.12);
}

.btn-success {
    background: rgba(47, 217, 255, 0.12);
    border-color: var(--gold);
    color: var(--gold);
}
.btn-success:hover, .btn-success:focus {
    background: var(--gold);
    border-color: var(--gold);
    color: #2a1f00;
    box-shadow: 0 0 16px var(--gold-soft);
}

.btn-danger, .btn-outline-danger {
    background: rgba(255, 77, 109, 0.1);
    border-color: var(--neon-red);
    color: var(--neon-red);
}
.btn-danger:hover, .btn-outline-danger:hover, .btn-danger:focus, .btn-outline-danger:focus {
    background: var(--neon-red);
    border-color: var(--neon-red);
    color: #1a0407;
    box-shadow: 0 0 16px var(--neon-red-soft);
}

/* Every button gets the same red border+glow on hover, on top of whatever
   its own variant does for background/text — same border width as at rest,
   so nothing shifts layout, just like the browse-card hover treatment. */
.btn:hover, .btn:focus {
    border-color: var(--neon-red);
    box-shadow: 0 0 16px var(--neon-red-soft);
}

/* ---------- forms ---------- */

/* background-color (not the "background" shorthand) so Bootstrap's own
   background-image on .form-select (its dropdown chevron) is left alone —
   a custom re-declared chevron here previously leaked into the native
   option-list popup in some browsers, painting the arrow on every row. */
.form-control, .form-select, textarea {
    background-color: rgba(6, 12, 30, 0.6);
    border: 1px solid var(--neon-blue-soft);
    color: var(--text);
    border-radius: 0;
}
.form-control:focus, .form-select:focus, textarea:focus {
    background-color: rgba(6, 12, 30, 0.75);
    border-color: var(--neon-blue);
    color: var(--text);
    box-shadow: 0 0 0 3px var(--neon-blue-dim);
}
.form-control::placeholder {
    color: var(--text-muted);
    opacity: 0.7;
}

/* Django's default form-error markup ({{ form.field.errors }}, non-field
   errors) — unstyled it inherits the light body text color and is nearly
   invisible against this dark theme, so give it the same red used for
   every other error/danger cue on the site. */
.errorlist {
    color: var(--neon-red);
    list-style: none;
    margin: 0.25rem 0 0.5rem;
    padding-left: 0;
    font-size: 0.875rem;
}

/* Same red border+glow as buttons on hover — dropdowns, text inputs and
   checkboxes/radios all get the same hover cue, same border width as at
   rest so nothing shifts. Left off :focus here on purpose — that's the
   existing blue focus ring above, a separate (accessibility-relevant) cue
   from a plain mouse-hover highlight. */
.form-select:hover,
.form-control:hover,
textarea:hover,
.form-check-input:hover {
    border-color: var(--neon-red);
    box-shadow: 0 0 12px var(--neon-red-soft);
}

.form-label {
    color: var(--text-muted);
    font-weight: 600;
    letter-spacing: 0.02em;
}

/* ---------- badges ---------- */

.badge {
    font-family: "Rajdhani", sans-serif;
    letter-spacing: 0.03em;
    border-radius: 0;
}
.badge.bg-secondary {
    background: rgba(47, 217, 255, 0.15) !important;
    border: 1px solid var(--neon-blue-soft);
    color: var(--neon-blue);
}
.badge.bg-danger {
    background: rgba(255, 77, 109, 0.2) !important;
    border: 1px solid var(--neon-red);
    color: var(--neon-red);
    text-shadow: 0 0 6px var(--neon-red-soft);
}

/* ---------- alerts (messages, moderation feedback) ---------- */

.alert {
    border-left: 3px solid var(--neon-blue);
}
.alert-success { border-left-color: var(--gold); color: var(--gold); }
.alert-danger, .alert-warning { border-left-color: var(--neon-red); }
.alert-info { border-left-color: var(--neon-blue); }

/* ---------- tables ---------- */

/* Bootstrap's own --bs-table-color/--bs-table-bg default to a light-theme
   palette regardless of our custom properties; data-bs-theme="dark" on <html>
   fixes the contrast (see base.html), this just makes the table blend into
   the glass panel instead of showing Bootstrap's own solid dark-gray box. */
.table {
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--neon-blue-soft);
}

/* ---------- gallery strip (filmstrip of images/YouTube thumbnails) ---------- */

.gallery-strip {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.5rem;
}
/* ---------- CKEditor-produced rich text (article/blog/review/description body) ----------
   Matches static/css/ckeditor_contents.css's img rules — the classic Image
   dialog's Alignment field (Not set/Left/Right) writes style="float:
   left/right" directly on the img; always neutralize that float and force
   block instead, so the image gets its own line no matter where in the
   source it sits (same paragraph as text or its own) — text can never end
   up beside it, only ever above/below it. The float value is reused only
   to pick a margin, never to actually float anything. */
.rich-text img {
    max-width: 100%;
    height: auto;
    display: block !important;
    float: none !important;
    margin: 0.5rem auto !important;
}
.rich-text img[style*="float:left" i],
.rich-text img[style*="float: left" i] {
    margin-left: 0 !important;
    margin-right: auto !important;
}
.rich-text img[style*="float:right" i],
.rich-text img[style*="float: right" i] {
    margin-left: auto !important;
    margin-right: 0 !important;
}

.gallery-strip__item {
    position: relative;
    flex: 0 0 auto;
    display: block;
    height: 200px;
    border: 1px solid var(--neon-blue-soft);
    overflow: hidden;
}
.gallery-strip__item img {
    height: 200px;
    width: auto;
    display: block;
    object-fit: cover;
}
.gallery-strip__item:hover {
    border-color: var(--neon-blue);
    box-shadow: 0 0 8px var(--neon-blue-soft);
}
.gallery-strip__play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: rgba(10, 19, 48, 0.75);
    border: 1px solid var(--neon-blue);
    color: var(--neon-blue);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.2rem;
}

/* ---------- profile tiles (image + caption cards: reviews/bookmarks on the profile page) ---------- */

.profile-tile {
    display: inline-flex;
    flex-direction: column;
    width: 200px;
    text-decoration: none;
}
.profile-tile__image-wrap {
    position: relative;
    display: block;
    width: 200px;
    height: 200px;
    border: 1px solid var(--neon-blue-soft);
    overflow: hidden;
    background: rgba(6, 12, 30, 0.6);
}
.profile-tile__image-wrap img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
}
.profile-tile:hover .profile-tile__image-wrap {
    border-color: var(--neon-blue);
    box-shadow: 0 0 8px var(--neon-blue-soft);
}
.profile-tile__caption {
    /* Full title always shown (wraps instead of truncating), but every tile
       reserves the same caption height so a row of mixed short/long titles
       still lines up evenly. */
    display: block;
    min-height: 2.6em;
    margin-top: 0.35rem;
    color: var(--neon-blue);
    font-size: 0.85rem;
    line-height: 1.3;
    white-space: normal;
    word-break: break-word;
}
.profile-tile__badge {
    position: absolute;
    bottom: 4px;
    right: 4px;
    width: 24px;
    height: 24px;
    background: rgba(10, 19, 48, 0.85);
    border: 1px solid var(--neon-blue-soft);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.profile-tile__badge .bookmark-btn__icon {
    width: 14px;
    height: 14px;
}

.profile-tabs .nav-link.active,
.bookmark-status-tabs .nav-link.active {
    background-color: transparent;
    color: var(--neon-blue);
    border-top: 1px solid var(--neon-blue);
    border-right: 1px solid var(--neon-blue);
    border-bottom: 1px solid transparent;
    border-left: 1px solid var(--neon-blue);
    box-shadow: 0 0 8px var(--neon-blue-soft);
}

/* ---------- scrollbars ---------- */

* {
    scrollbar-width: thin;
    scrollbar-color: var(--neon-blue-soft) rgba(6, 12, 30, 0.6);
}
*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
*::-webkit-scrollbar-track {
    background: rgba(6, 12, 30, 0.6);
}
*::-webkit-scrollbar-thumb {
    background: var(--neon-blue-soft);
    border: 1px solid var(--neon-blue);
    border-radius: 0;
}
*::-webkit-scrollbar-thumb:hover {
    background: var(--neon-blue);
}
*::-webkit-scrollbar-corner {
    background: rgba(6, 12, 30, 0.6);
}

.table > :not(caption) > * > * {
    background-color: transparent;
}

/* ---------- modals (e.g. "Додати рецензію") ---------- */

.cyber-modal .modal-content {
    background: rgba(10, 19, 48, 0.97);
    border: 1px solid var(--neon-blue-soft);
    border-radius: 0;
    color: var(--text);
}

.cyber-modal .modal-header,
.cyber-modal .modal-footer {
    border-color: var(--neon-blue-soft);
}

.cyber-modal .modal-title {
    color: var(--gold);
    font-family: "Orbitron", "Rajdhani", sans-serif;
}

.cyber-modal .modal-dialog {
    height: 60vh;
    margin-top: 5vh;
}

@media (min-width: 768px) {
    .cyber-modal .modal-dialog {
        max-width: 70vw;
        width: 70vw;
        margin-left: auto;
        margin-right: auto;
    }
}

/* ---------- CKEditor toolbar chrome ----------
   The editable area itself is styled separately via contentsCss (loaded
   inside its <iframe>, see settings/base.py + ckeditor_contents.css) —
   page CSS can't reach in there. This part styles the toolbar/status bar
   chrome around it, which IS normal page DOM. */

/* django-ckeditor wraps the whole widget in <div class="django-ckeditor-widget"
   style="display: inline-block;">. inline-block shrink-wraps to its content
   instead of stretching to the container — this, not box-sizing, is why the
   editor rendered far narrower than the Title/Rating fields above it. */
.django-ckeditor-widget {
    display: block !important;
    width: 100% !important;
}

/* CKEditor's own reset.css forces box-sizing:content-box !important on
   .cke_reset_all (a class the outer chrome wrapper also carries), which adds
   its border on top of an inline width:100% — making it a couple pixels
   wider than sibling .form-control/.form-select elements (border-box).
   The compound selector below outranks that single-class rule regardless of
   stylesheet order, so border-box (and the widths) line up again. */
.cke_chrome.cke_reset_all {
    box-sizing: border-box !important;
    width: 100% !important;
}

/* CKEditor's reset.css applies content-box to every descendant carrying
   .cke_reset/.cke_reset_all too (toolbar groups, combo buttons, the path
   bar) — not just the outer chrome above — which throws off padding/width
   math throughout the toolbar against our (border-box) page rules, reading
   as a "crooked"/misaligned toolbar. */
.cke_chrome.cke_reset_all *,
.cke_chrome.cke_reset_all *::before,
.cke_chrome.cke_reset_all *::after {
    box-sizing: border-box !important;
}

.cke_chrome {
    border: 1px solid var(--neon-blue-soft) !important;
    background: var(--bg-panel) !important;
    border-radius: 0 !important;
    margin: 0 !important;
}

.cke_top {
    background: var(--bg-panel) !important;
    border-bottom: 1px solid var(--neon-blue-soft) !important;
}

.cke_bottom {
    background: var(--bg-panel) !important;
    border-top: 1px solid var(--neon-blue-soft) !important;
}

.cke_toolbar_separator {
    background-color: var(--neon-blue-soft) !important;
}

/* Default icons are dark, meant for a light toolbar — invert for visibility
   against our dark one. */
.cke_button_icon {
    filter: invert(1) brightness(1.6);
}

/* The default skin highlights a hovered/active/toggled-on button with a
   near-white background (moono-lisa's editor.css) — fine on its native light
   toolbar, but combined with the inverted (now light) icon above, the icon
   disappears into that highlight. Force a dark highlight instead. */
.cke_button_on,
.cke_button_off:hover,
.cke_button_off:focus,
.cke_button_off:active,
.cke_combo_off .cke_combo_button:hover,
.cke_combo_off .cke_combo_button:focus,
.cke_combo_off .cke_combo_button:active,
/* .cke_combo_on is the "Формат" dropdown's *open* state — a plain class
   toggle, not a :hover/:focus/:active pseudo-class, so it needs its own
   selector. Without this the open combo falls back to the default skin's
   near-white background (see comment above), same bug as an unstyled
   .cke_button_on. */
.cke_combo_on .cke_combo_button {
    background: var(--neon-blue-soft) !important;
    border-color: var(--neon-blue) !important;
}

.cke_path,
.cke_path_item,
.cke_resizer {
    color: var(--text-muted) !important;
}

.cke_button_label,
.cke_combo_text,
.cke_combo_arrow {
    color: var(--text) !important;
}

/* Source view swaps the iframe for a plain <textarea> in the page's own
   DOM (not covered by contentsCss, which only reaches the editable
   iframe) — unstyled, it falls back to the skin's white input background,
   with our own dark-theme text color still applying on top: white on
   white. */
.cke_source {
    background: var(--bg-panel) !important;
    color: var(--text) !important;
}

/* ---------- rating stars (blue neon ★, replaces the flame experiment) ---------- */

/* Single static icon used wherever a rating is displayed (game/studio cards,
   review titles, sidebars) — same star everywhere, just this one glyph. */
.star-icon {
    display: inline-block;
    width: 20px;
    height: 20px;
    vertical-align: text-bottom;
    border-radius: 50%;
    box-shadow: 0 0 4px var(--neon-blue), 0 0 8px var(--neon-blue-soft);
}
.star-icon svg {
    width: 100%;
    height: 100%;
    fill: var(--neon-blue);
}

/* Marks a суперадмін's name wherever username_badge is used (comments,
   reviews, articles, blog/collection authorship, moderation notes). */
/* username_badge wraps the name + wrench in a flex row so the icon is
   vertically centered against the actual glyph box, not the font's
   baseline metrics — vertical-align gets thrown off badly by the site's
   decorative heading font at H1 sizes. */
.username-badge-wrap {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.wrench-icon {
    display: inline-block;
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    /* The heading font (Orbitron) reserves a lot of unused descender space
       below its cap-height glyphs, so flex-centering against the full line
       box still lands the icon visibly low next to h1-h6 text — nudge up
       proportionally to font-size (em, not px) so this stays right both on
       a huge H1 and on small inline text (comments etc). */
    transform: translateY(-0.3em);
}
.wrench-icon svg {
    width: 100%;
    height: 100%;
    fill: var(--gold);
    filter: drop-shadow(0 0 3px var(--gold)) drop-shadow(0 0 6px var(--gold-soft));
}

/* Interactive 1-10 rating input (review form + quick-rate modal): a row of
   stars, unlit by default, lighting up 1..N on hover/selection — the classic
   pure-CSS star-rating trick, with radios in reverse (10..1) DOM order under
   a row-reverse flex container so `~` (general sibling, "all *following*
   elements") lights the correct lower-value stars. Centered and stretched to
   70% of its container's width, per the requested look. */
.rating-stars {
    display: flex;
    flex-direction: row-reverse;
    align-items: center;
    width: 70%;
    margin: 0 auto;
    gap: 4px;
}
.rating-stars input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}
.rating-stars label {
    cursor: pointer;
    opacity: 0.3;
    transition: opacity 0.15s ease;
    display: flex;
    flex: 1 1 0;
    justify-content: center;
}
.rating-stars label .star-icon {
    width: 34px;
    height: 34px;
}
.rating-stars label:hover,
.rating-stars label:hover ~ label,
.rating-stars input:checked ~ label {
    opacity: 1;
}

.rating-value {
    color: var(--neon-blue);
    font-family: "Orbitron", "Rajdhani", sans-serif;
    font-weight: 600;
}

/* ---------- range sliders (noUiSlider — game catalog year/rating filters) ---------- */

/* Selector specificity here must beat noUiSlider's own .noUi-horizontal /
   .noUi-horizontal .noUi-handle rules (loaded after theme.css), so the
   compound .range-slider.noUi-target form is used rather than plain
   descendant selectors, which would tie on specificity and lose on source
   order. The plain .range-slider rule stays as a fallback so the track is
   visible even before noUiSlider's JS has attached the .noUi-target class. */
.range-slider {
    margin: 0.75rem 0.4rem 0.5rem;
    height: 3px;
    background: var(--neon-blue);
    border: none;
    border-radius: 0;
    box-shadow: 0 0 4px var(--neon-blue-soft);
}
.range-slider.noUi-target {
    height: 3px;
}
/* noUiSlider's own .noUi-connects has overflow:hidden, which clips any
   box-shadow glow on .noUi-connect — override it so the glow shows. */
.range-slider.noUi-target .noUi-connects {
    overflow: visible;
}
.range-slider.noUi-target .noUi-connect {
    background: var(--neon-red);
    box-shadow: 0 0 8px 1px var(--neon-red-soft), 0 0 16px var(--neon-red-soft);
    height: 6px;
    top: -1.5px;
}
.range-slider.noUi-target .noUi-handle {
    background: transparent;
    border-style: solid;
    border-width: 10px 5px 0 5px;
    border-color: var(--neon-blue) transparent transparent transparent;
    border-radius: 0;
    box-shadow: none;
    filter: drop-shadow(0 0 3px var(--neon-blue-soft));
    width: 0;
    height: 0;
    top: 3px;
    right: -5px;
    cursor: pointer;
}
.range-slider .noUi-handle::before,
.range-slider .noUi-handle::after {
    display: none;
}

.active-filter-chip {
    background: rgba(6, 12, 30, 0.6);
    border: 1px solid var(--neon-blue-soft);
    color: var(--text);
    font-weight: 500;
    padding: 0.4rem 0.7rem;
}
.active-filter-chip:hover {
    border-color: var(--neon-blue);
    color: var(--text);
}

/* ---------- bookmarks (game "my status" icon buttons) ---------- */

.bookmark-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(6, 12, 30, 0.6);
    border: 1px solid var(--neon-blue-soft);
    border-radius: 4px;
    padding: 0.5rem 0.7rem;
}
.bookmark-btn:hover {
    border-color: var(--neon-blue);
    box-shadow: 0 0 8px var(--neon-blue-soft);
}
.bookmark-btn.active {
    border-color: var(--gold);
    box-shadow: 0 0 8px var(--gold-soft);
}
.bookmark-btn__icon {
    width: 28px;
    height: 28px;
}
.bookmark-btn__icon--want_to_play {
    color: var(--gold);
}
.bookmark-btn__icon--playing,
.bookmark-btn__icon--played {
    color: var(--neon-green);
}
.bookmark-btn__icon--dropped {
    color: var(--neon-red);
}

/* ---------- misc ---------- */

.list-group-item {
    background: rgba(16, 28, 68, 0.55);
    border-color: var(--neon-blue-soft);
    color: var(--text);
}

hr {
    border-color: var(--neon-blue-soft);
    opacity: 0.5;
}

::selection {
    background: var(--neon-blue);
    color: #04101f;
}

/* ---------- footer ---------- */

.site-footer {
    border-top: 1px solid var(--neon-blue-soft);
    background: rgba(10, 19, 48, 0.6);
}

.site-footer__col {
    flex: 1 1 0;
    min-width: 220px;
}

.site-footer__link {
    color: var(--text-muted);
    text-decoration: none;
}

.site-footer__social-link {
    display: inline-flex;
    align-items: center;
}

.site-footer__link:hover {
    color: var(--neon-red);
}

/* ---------- mobile adjustments ---------- */

@media (max-width: 576px) {
    body {
        font-size: 0.98rem;
    }
    h1, .h1 { font-size: 1.6rem; }
    h3, .h3 { font-size: 1.25rem; }
    .navbar-brand {
        font-size: 1.1rem;
    }
}
