/* ============================================================
   NETORBUS — POLISH LAYER
   Loads LAST, after every other stylesheet.

   This file holds the small, global details that make the game
   feel like a finished product rather than a set of pages:
   selection colours, scrollbars, focus rings, press feedback,
   staggered entrances, tabular figures, skeletons and toasts.

   Rules for anything added here:
     • Animate transform / opacity / filter only — never layout.
     • Name transition properties explicitly, never `transition: all`.
     • Every motion must be silenced by prefers-reduced-motion.
     • Nothing here may be required for the game to function.
   ============================================================ */

/* ------------------------------------------------------------
   1. TYPOGRAPHY — crisper text, no orphans, no number jitter
   ------------------------------------------------------------ */
html {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
}

h1, h2, h3, .page-title, .section-title {
    text-wrap: balance;
}

p, .description, .card-content p {
    text-wrap: pretty;
}

/* Any value that ticks upward must not reflow the row it sits in. */
.money, .stat-value, .sidebar-stat-value, .price-row span, .stat-row span,
[data-countup], .nb-num, td.numeric, .leaderboard-score, .player-score {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
}

/* ------------------------------------------------------------
   2. SELECTION + SCROLLBAR — brand-coloured chrome
   ------------------------------------------------------------ */
::selection {
    background: rgba(217, 35, 54, 0.35);
    color: var(--nb-white-hot, #fffdf7);
}

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(201, 162, 39, 0.35) transparent;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: rgba(7, 6, 7, 0.5); }
::-webkit-scrollbar-thumb {
    background: linear-gradient(180deg, rgba(201, 162, 39, 0.45), rgba(168, 24, 42, 0.45));
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
    transition-property: background;
    transition-duration: var(--nb-dur-base, 220ms);
}
::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(180deg, rgba(232, 193, 90, 0.7), rgba(217, 35, 54, 0.7));
    background-clip: padding-box;
}

/* ------------------------------------------------------------
   3. FOCUS — visible for keyboards, invisible for mice
   ------------------------------------------------------------ */
:focus { outline: none; }

:focus-visible {
    outline: none;
    box-shadow: var(--nb-focus-ring, 0 0 0 2px #0c0a0b, 0 0 0 4px #c9a227);
    border-radius: var(--nb-radius-sm, 4px);
}

/* ------------------------------------------------------------
   4. PRESS FEEDBACK — every control answers the pointer
   ------------------------------------------------------------ */
button, .btn, .action-btn, .filter-btn, [role="button"],
a.button, input[type="submit"], .market-buy-btn, .nav-link {
    transition-property: transform, box-shadow, background-color, border-color, opacity, filter;
    transition-duration: var(--nb-dur-fast, 140ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}

button:active:not(:disabled),
.btn:active:not(:disabled),
.action-btn:active:not(:disabled),
.filter-btn:active:not(:disabled),
input[type="submit"]:active:not(:disabled) {
    transform: scale(0.96);
}

/* Small icon-only controls still need a real target to hit. */
.icon-btn, .close-btn, .nb-icon-action {
    position: relative;
}
.icon-btn::after, .close-btn::after, .nb-icon-action::after {
    content: '';
    position: absolute;
    inset: 50% auto auto 50%;
    width: 40px; height: 40px;
    transform: translate(-50%, -50%);
}

/* ------------------------------------------------------------
   5. SURFACES — depth from layered shadow, not hard borders
   ------------------------------------------------------------ */
.panel, .card, .market-card, .stat-card, .rpg-panel, .content-box {
    transition-property: transform, box-shadow, border-color;
    transition-duration: var(--nb-dur-base, 220ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}

.market-card:hover, .card:hover, .stat-card:hover {
    transform: translateY(-2px);
    box-shadow:
        0 1px 1px rgba(0, 0, 0, 0.5),
        0 8px 24px rgba(0, 0, 0, 0.45),
        0 0 0 1px rgba(201, 162, 39, 0.22);
}

/* Photographic content sits on dark panels; a hairline stops the
   edge from dissolving into the surface. Pure white at low alpha —
   a tinted neutral reads as dirt on the edge. */
.market-card img, .item-image img, .car-image img, .house-image img,
.job-image img, .profile-avatar-img, .player-avatar, .friend-avatar {
    outline: 1px solid rgba(255, 255, 255, 0.1);
    outline-offset: -1px;
}

/* ------------------------------------------------------------
   6. ENTRANCES — split and staggered, never one big fade
   ------------------------------------------------------------ */
/* Gated on nb-reveal-ready for the same reason as [data-reveal] in
   components.css: never let content depend on JS to become visible. */
html.nb-reveal-ready .nb-reveal:not(.is-revealed) {
    opacity: 0;
    transform: translateY(10px);
}
.nb-reveal {
    transition-property: opacity, transform;
    transition-duration: var(--nb-dur-slow, 420ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
    transition-delay: var(--reveal-delay, 0ms);
}
.nb-reveal.is-revealed {
    opacity: 1;
    transform: none;
}

/* .stagger-in is owned by animations.css (opacity:0 + fadeIn ... both).
   Do not re-declare the animation here: overriding it without also
   resetting that opacity leaves every staggered grid invisible. */

/* ------------------------------------------------------------
   7. PAGE TRANSITION — a short cross-dissolve between routes
   ------------------------------------------------------------ */
.nb-page-enter {
    animation: nbPageIn 280ms var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}
@keyframes nbPageIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* Exits are softer than entrances: a small fixed shift, no travel. */
body.nb-leaving .rpg-content {
    opacity: 0;
    transform: translateY(-4px);
    transition-property: opacity, transform;
    transition-duration: 160ms;
    transition-timing-function: var(--nb-ease-in-out, cubic-bezier(0.65, 0, 0.35, 1));
}

/* ------------------------------------------------------------
   8. SCROLL PROGRESS — a hairline of gold under the header
   ------------------------------------------------------------ */
.nb-scroll-progress {
    position: fixed;
    top: 0; left: 0;
    height: 2px;
    width: 100%;
    transform: scaleX(0);
    transform-origin: 0 50%;
    background: var(--nb-grad-gold, linear-gradient(90deg, #8a6a2f, #e8c15a, #8a6a2f));
    z-index: calc(var(--nb-z-header, 100) + 1);
    pointer-events: none;
    will-change: transform;
}

/* ------------------------------------------------------------
   9. BUSY STATE — submitted forms cannot be submitted twice
   ------------------------------------------------------------ */
.nb-busy {
    pointer-events: none;
    opacity: 0.7;
    position: relative;
}
.nb-busy::after {
    content: '';
    position: absolute;
    top: 50%; right: 12px;
    width: 14px; height: 14px;
    margin-top: -7px;
    border: 2px solid rgba(242, 236, 223, 0.25);
    border-top-color: var(--nb-gold-bright, #e8c15a);
    border-radius: 50%;
    animation: nbSpin 620ms linear infinite;
}
@keyframes nbSpin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------
   10. SKELETONS — owned by components.css (.nb-skeleton).
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   11. TOASTS — styled in components.css (.nb-toast*), not here.
   Only the region offset is nudged so toasts clear the fixed header
   on narrow viewports; re-declaring the toast itself would fork the
   component into two competing definitions.
   ------------------------------------------------------------ */
.nb-toast-region {
    top: calc(var(--nb-space-md, 1rem) + 46px);
    max-width: min(360px, calc(100vw - 2rem));
}

/* ------------------------------------------------------------
   12. TOOLTIPS — [data-tip] with no library
   ------------------------------------------------------------ */
[data-tip] { position: relative; }

[data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translate(-50%, 4px);
    padding: 0.35rem 0.55rem;
    border-radius: var(--nb-radius-sm, 4px);
    background: var(--nb-carbon-0, #070607);
    color: var(--nb-champagne, #f0d896);
    font-family: var(--nb-font-ui, sans-serif);
    font-size: var(--nb-text-xs, 0.72rem);
    letter-spacing: 0.02em;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(201, 162, 39, 0.25);
    transition-property: opacity, transform;
    transition-duration: var(--nb-dur-fast, 140ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
    z-index: var(--nb-z-dropdown, 1000);
}

[data-tip]:hover::after,
[data-tip]:focus-visible::after {
    opacity: 1;
    transform: translate(-50%, 0);
}

/* ------------------------------------------------------------
   13. RIPPLE — a single expanding disc on click
   ------------------------------------------------------------ */
.nb-ripple {
    position: absolute;
    border-radius: 50%;
    transform: scale(0);
    background: radial-gradient(circle, rgba(242, 236, 223, 0.35) 0%, transparent 70%);
    pointer-events: none;
    animation: nbRipple 520ms var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1)) forwards;
}
@keyframes nbRipple {
    to { transform: scale(2.4); opacity: 0; }
}

/* ------------------------------------------------------------
   14. VALUE CHANGE — money going up reads green, down reads red
   ------------------------------------------------------------ */
.nb-value-up   { animation: nbValueUp 900ms var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1)); }
.nb-value-down { animation: nbValueDown 900ms var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1)); }

@keyframes nbValueUp {
    0%   { color: var(--nb-jade-bright, #5ecf92); text-shadow: 0 0 12px rgba(94, 207, 146, 0.5); }
    100% { color: inherit; text-shadow: none; }
}
@keyframes nbValueDown {
    0%   { color: var(--nb-danger, #ff4655); text-shadow: 0 0 12px rgba(255, 70, 85, 0.5); }
    100% { color: inherit; text-shadow: none; }
}

/* ------------------------------------------------------------
   15. EMPTY STATES — owned by components.css (.empty-state) and
   surfaced through <x-empty-state>. Enhanced there, not forked here.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   16. SHINE — one slow sweep across the primary call to action
   ------------------------------------------------------------ */
.nb-shine {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.nb-shine::before {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-120%) skewX(-18deg);
    background: linear-gradient(90deg, transparent, rgba(255, 253, 247, 0.16), transparent);
    animation: nbShine 5.5s ease-in-out infinite;
    pointer-events: none;
    z-index: -1;
}
@keyframes nbShine {
    0%, 65% { transform: translateX(-120%) skewX(-18deg); }
    85%     { transform: translateX(120%) skewX(-18deg); }
    100%    { transform: translateX(120%) skewX(-18deg); }
}

/* ------------------------------------------------------------
   17. IMAGE LOAD — fade in rather than pop in
   ------------------------------------------------------------ */
img[data-nb-fade] {
    opacity: 0;
    transition-property: opacity;
    transition-duration: var(--nb-dur-base, 220ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}
img[data-nb-fade].is-loaded { opacity: 1; }

/* ------------------------------------------------------------
   18. REDUCED MOTION — one switch turns all of it off
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    .nb-reveal { opacity: 1; transform: none; transition: none; }
    /* Killing the animation alone would strand these at animations.css's
       opacity:0 — restore visibility explicitly. */
    .stagger-in > * { opacity: 1; animation: none !important; }
    .nb-shine::before,
    .nb-toast,
    .nb-page-enter,
    .nb-value-up,
    .nb-value-down { animation: none !important; }
    .market-card:hover, .card:hover, .stat-card:hover { transform: none; }
    button:active, .btn:active { transform: none; }
    img[data-nb-fade] { opacity: 1; }
}

/* ------------------------------------------------------------
   19. FLASH ALERTS — dismissible, and the good news self-retires
   ------------------------------------------------------------ */
.alert[data-nb-alert] {
    position: relative;
    padding-right: 2.6rem;
    transition-property: opacity, transform;
    transition-duration: var(--nb-dur-base, 220ms);
    transition-timing-function: var(--nb-ease-in-out, cubic-bezier(0.65, 0, 0.35, 1));
    animation: nbAlertIn 320ms var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}

@keyframes nbAlertIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}

/* Exit is a small fixed shift — softer than the entrance. */
.alert.nb-alert-leaving {
    opacity: 0;
    transform: translateY(-6px);
}

.nb-alert-close {
    position: absolute;
    top: 50%; right: 0.5rem;
    transform: translateY(-50%);
    /* 40x40 hit area even though the glyph is small. */
    width: 40px; height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 0;
    color: currentColor;
    opacity: 0.55;
    cursor: pointer;
    border-radius: var(--nb-radius-sm, 4px);
    transition-property: opacity, background-color;
    transition-duration: var(--nb-dur-fast, 140ms);
}
.nb-alert-close:hover { opacity: 1; background: rgba(255, 255, 255, 0.06); }

@media (prefers-reduced-motion: reduce) {
    .alert[data-nb-alert] { animation: none; }
}

/* ------------------------------------------------------------
   20. INVENTORY — the "use a consumable" control
   ------------------------------------------------------------ */
.inv-use-form {
    display: flex;
    align-items: stretch;
    gap: 0.4rem;
    margin-top: 0.5rem;
}

.inv-use-qty { flex: 0 0 62px; }

.inv-use-qty input {
    width: 100%;
    height: 100%;
    padding: 0.35rem 0.4rem;
    border-radius: var(--nb-radius-sm, 4px);
    border: 0;
    background: var(--nb-surface-inset, rgba(7, 6, 7, 0.65));
    box-shadow: inset 0 0 0 1px var(--nb-border, rgba(201, 162, 39, 0.16));
    color: var(--nb-text, #e6ddcf);
    font-family: var(--nb-font-data, monospace);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.inv-use-form .game-btn { flex: 1 1 auto; }

/* Visually hidden, still read by screen readers. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ------------------------------------------------------------
   21. SIDEBAR PROGRESSION — level, XP, nerve and confinement
   ------------------------------------------------------------ */
.sidebar-progress {
    margin: 0.6rem 0.75rem 0.9rem;
    padding: 0.6rem 0.7rem;
    border-radius: var(--nb-radius-md, 6px);
    background: var(--nb-surface-inset, rgba(7, 6, 7, 0.65));
    box-shadow: inset 0 0 0 1px var(--nb-border-soft, rgba(242, 236, 223, 0.08));
}

.sidebar-progress__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

.sidebar-progress__level {
    font-family: var(--nb-font-data, monospace);
    font-size: var(--nb-text-sm, 0.82rem);
    letter-spacing: 0.04em;
    color: var(--nb-gold-bright, #e8c15a);
    font-variant-numeric: tabular-nums;
}

.sidebar-progress__perks {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 1px 7px;
    border-radius: var(--nb-radius-round, 999px);
    background: rgba(201, 162, 39, 0.12);
    color: var(--nb-champagne, #f0d896);
    font-size: var(--nb-text-xs, 0.72rem);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
    transition-property: background, transform;
    transition-duration: var(--nb-dur-fast, 140ms);
}
.sidebar-progress__perks:hover { background: rgba(201, 162, 39, 0.24); }

.sidebar-progress__bar,
.sidebar-progress__nerve-bar {
    display: block;
    height: 5px;
    border-radius: var(--nb-radius-round, 999px);
    background: var(--nb-carbon-4, #241c20);
    overflow: hidden;
}

.sidebar-progress__bar > span,
.sidebar-progress__nerve-bar > span {
    display: block;
    height: 100%;
    width: var(--fill, 0%);
    border-radius: inherit;
    background: var(--nb-grad-gold, linear-gradient(90deg, #8a6a2f, #e8c15a, #8a6a2f));
    transition-property: width;
    transition-duration: var(--nb-dur-slow, 420ms);
    transition-timing-function: var(--nb-ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}

.sidebar-progress__nerve {
    display: grid;
    grid-template-columns: auto auto 1fr;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.45rem;
    font-size: var(--nb-text-xs, 0.72rem);
    color: var(--nb-text-dim, #b3a898);
    font-variant-numeric: tabular-nums;
}
.sidebar-progress__nerve i { color: var(--nb-red, #d92336); }
.sidebar-progress__nerve-bar > span {
    background: linear-gradient(90deg, #7e1522, #d92336);
}

.sidebar-status {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    padding: 0.3rem;
    border-radius: var(--nb-radius-sm, 4px);
    font-size: var(--nb-text-xs, 0.72rem);
    letter-spacing: var(--nb-tracking-wide, 0.14em);
    text-transform: uppercase;
    text-decoration: none;
}

.sidebar-status--jail {
    background: rgba(255, 70, 85, 0.12);
    color: var(--nb-danger, #ff4655);
    box-shadow: inset 0 0 0 1px rgba(255, 70, 85, 0.35);
    animation: nbStatusPulse 2.4s ease-in-out infinite;
}

.sidebar-status--hospital {
    background: rgba(163, 184, 202, 0.12);
    color: var(--nb-steel-bright, #c6d6e4);
    box-shadow: inset 0 0 0 1px rgba(163, 184, 202, 0.35);
    animation: nbStatusPulse 2.4s ease-in-out infinite;
}

@keyframes nbStatusPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.62; }
}

@media (prefers-reduced-motion: reduce) {
    .sidebar-status--jail, .sidebar-status--hospital { animation: none; }
    .sidebar-progress__bar > span,
    .sidebar-progress__nerve-bar > span { transition: none; }
}
