/*
 * Upgrade Calculator styles
 * --------------------------
 * Styling for the upgrade toggle button and the sliding upgrade
 * calculator panel. Loaded after style.css so it can sit alongside
 * the base theme without needing to duplicate any of it.
 * Depends on .right-panel { position: relative; }, defined in
 * style.css. Positioning for the toggle button itself now comes
 * from the shared .floating-toggle-buttons wrapper in style.css
 * (which both this button and the Death Tracker's share), not from
 * this file - see the note on .upgrade-toggle-button below.
 */


/* Player Count and Game Mode buttons (Solo/Duo/Party/Party+) now
   live in the sidebar instead of inside the upgrade panel itself,
   but they only matter while the Upgrade Shop Calculator is actually
   open - hidden here by default, and toggled to .visible in
   lockstep with the panel's own open state by setUpgradePanelOpen()
   in Upgrades.js. This keeps the curse-tracker sidebar free of
   controls that don't apply to it. */
.upgrade-panel-only-section {
    display: none;
}

.upgrade-panel-only-section.visible {
    display: block;
}


/* Inverse of the above: Active Enemies is normally visible in the
   left panel, but only matters for the curse tracker, not the
   upgrade shop calculator - so it's temporarily hidden while the
   upgrade panel is open, and toggled back in lockstep by the same
   setUpgradePanelOpen() in Upgrades.js. */
.hide-when-upgrades-open.upgrades-open {
    display: none;
}


/*
 * No more position: fixed / right / bottom / z-index here - this
 * button now sits inside the shared .floating-toggle-buttons flex
 * row (see style.css), which owns the fixed placement for both it
 * and the Death Tracker's toggle button. Keeping positioning in one
 * place is what keeps the two buttons pinned together instead of
 * one drifting into normal document flow.
 */
.upgrade-toggle-button {
    flex-shrink: 0;

    display: flex;

    align-items: center;
    gap: 0;

    padding: 12px 14px;
    overflow: hidden;

    /* Mirrored stops (white -> light blue -> white -> light blue ->
       white) so the first and last stops match - combined with the
       200%+-wide background and animating position from 0% to 100%,
       the hue-shift loop has no visible seam or jump. */
    background: linear-gradient(
        90deg,
        #ffffff 0%,
        #8fd9ff 25%,
        #ffffff 50%,
        #8fd9ff 75%,
        #ffffff 100%
    );
    background-size: 260% auto;

    border: 1px solid rgba(143, 217, 255, 0.8);
    border-radius: 999px;

    color: #073349;

    font-family: var(--font-modern);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.5px;

    cursor: pointer;
    user-select: none;

    text-shadow: 0 0 10px rgba(255, 255, 255, 0.6);

    box-shadow:
        0 8px 26px rgba(0, 0, 0, 0.4),
        0 0 10px rgba(143, 217, 255, 0.45),
        0 0 18px rgba(255, 255, 255, 0.3),
        0 0 26px rgba(143, 217, 255, 0.2);

    animation: upgrade-toggle-hue-shift 8s linear infinite;

    transition:
        padding 0.35s ease,
        transform 0.18s,
        box-shadow 0.18s;
}


/* Collapsed by default down to just the icon, same as the Death
   Tracker button (see .death-toggle-button in DeathTracker.css) -
   label and key both start at zero width/opacity and only expand
   once the button is hovered or focused. max-width (rather than
   width) is what's animated since width: auto can't be transitioned,
   but a generous max-width can - overflow: hidden on the button
   clips anything still mid-transition so nothing spills out early. */
.upgrade-toggle-button .btn-label,
.upgrade-toggle-button .upgrade-toggle-key {
    max-width: 0;
    margin-left: 0;
    opacity: 0;

    overflow: hidden;
    white-space: nowrap;

    transition:
        max-width 0.4s cubic-bezier(0.22, 1, 0.36, 1),
        margin-left 0.4s cubic-bezier(0.22, 1, 0.36, 1),
        opacity 0.25s ease;
}


.upgrade-toggle-button:hover .btn-label,
.upgrade-toggle-button:focus-visible .btn-label {
    max-width: 140px;
    margin-left: 8px;
    opacity: 1;
}


.upgrade-toggle-button:hover .upgrade-toggle-key,
.upgrade-toggle-button:focus-visible .upgrade-toggle-key {
    max-width: 30px;
    margin-left: 6px;
    opacity: 1;
}


/* Loop fix: this button's gradient is 260% of its width, so one full
   tile is 2.6x the button. With background-position percentages the
   shift is (container - image) * pct = -1.6x * pct, so ending at 100%
   only slid it 1.6x - short of a whole tile, which made the colors
   snap back at the loop point. 162.5% (= 260 / 160) slides exactly one
   tile, so the end frame equals the start frame and the loop is
   seamless. Durations were stretched by the same 1.625 factor to keep
   the original pace. */
@keyframes upgrade-toggle-hue-shift {

    0% {
        background-position: 0% 50%;
    }

    100% {
        background-position: 162.5% 50%;
    }

}


.upgrade-toggle-icon {
    display: inline-block;

    font-size: 12px;
    line-height: 1;

    transition: transform 0.25s ease;
}


.upgrade-toggle-key {
    padding: 1px 6px;

    background: rgba(0, 0, 0, 0.25);

    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: 4px;

    font-size: 9px;
    font-weight: 800;

    color: #ffffff;
}


.upgrade-toggle-button:hover,
.upgrade-toggle-button:focus-visible {
    padding: 12px 18px;

    transform: translateY(-2px) scale(1.03);

    box-shadow:
        0 10px 32px rgba(0, 0, 0, 0.45),
        0 0 14px rgba(143, 217, 255, 0.6),
        0 0 24px rgba(255, 255, 255, 0.4),
        0 0 34px rgba(143, 217, 255, 0.3);
}


.upgrade-toggle-button:hover .upgrade-toggle-icon {
    transform: translateY(-2px) rotate(10deg);
}


.upgrade-toggle-button.active {
    box-shadow:
        0 10px 32px rgba(0, 0, 0, 0.45),
        0 0 12px rgba(143, 217, 255, 0.65),
        0 0 22px rgba(255, 255, 255, 0.45),
        0 0 32px rgba(143, 217, 255, 0.3);
}


.upgrade-toggle-button.active .upgrade-toggle-icon {
    transform: rotate(180deg);
}


.upgrade-panel {
    position: absolute;
    inset: 0;

    z-index: 10;

    display: flex;

    align-items: stretch;
    justify-content: stretch;

    padding: 32px;

    background: linear-gradient(160deg, #03111c 0%, #060b15 100%);

    border-left: 1px solid rgba(143, 217, 255, 0.35);
    box-shadow: -24px 0 50px rgba(0, 0, 0, 0.5), inset 0 0 90px rgba(143, 217, 255, 0.05);

    transform: translateX(100%);
    opacity: 0;

    transition:
        transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
        opacity 0.4s ease-out;

    pointer-events: none;
}


.upgrade-panel.open {
    transform: translateX(0);
    opacity: 1;

    pointer-events: auto;
}


.upgrade-panel-inner {
    width: 100%;
    height: 100%;

    display: flex;

    flex-direction: column;

    overflow-y: auto;
    overflow-x: hidden;

    scrollbar-width: thin;
    scrollbar-color: rgba(143, 217, 255, 0.35) transparent;
}


.upgrade-panel-inner::-webkit-scrollbar {
    width: 6px;
}


.upgrade-panel-inner::-webkit-scrollbar-track {
    background: transparent;
}


.upgrade-panel-inner::-webkit-scrollbar-thumb {
    background: rgba(143, 217, 255, 0.3);
    border-radius: 999px;
}


.upgrade-panel-inner::-webkit-scrollbar-thumb:hover {
    background: rgba(143, 217, 255, 0.55);
}


.upgrade-panel-header {
    display: flex;

    align-items: center;
    flex-wrap: wrap;

    gap: 16px;

    margin-bottom: 20px;
    padding-bottom: 18px;

    border-bottom: 1px solid rgba(143, 217, 255, 0.22);
}


/* Wraps the heading and the zoom note underneath it so the note
   reads as a subtitle attached to the title, not a stray line
   floating in the header row. margin-right: auto (moved here from
   .upgrade-panel-heading itself) pushes the whole group away from
   the Own All/Reset buttons, same as before. */
.upgrade-panel-heading-group {
    margin-right: auto;
    min-width: 0;

    display: flex;
    flex-direction: column;
    gap: 4px;
}


.upgrade-panel-heading {
    font-size: 24px;
    font-weight: 900;
    letter-spacing: 0.5px;

    background: linear-gradient(
        90deg,
        #ffffff 0%,
        #8fd9ff 25%,
        #ffffff 50%,
        #8fd9ff 75%,
        #ffffff 100%
    );
    background-size: 200% auto;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;

    text-shadow: 0 0 20px rgba(143, 217, 255, 0.55);
}


/* Small hint under the title for anyone whose window/monitor can't
   fit the panel comfortably - points at the browser's own Ctrl +/-
   zoom rather than any in-app control, since there isn't one. */
.upgrade-panel-zoom-note {
    color: #6faccf;

    font-family: var(--font-modern);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.2px;
    line-height: 1.5;
}


.upgrade-zoom-key {
    display: inline-block;

    padding: 1px 6px;
    margin: 0 1px;

    background: rgba(143, 217, 255, 0.12);

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 4px;

    color: #dff5ff;

    font-size: 9px;
    font-weight: 800;
}


/* Own All + Reset now sit grouped together at the right of the
   header, separated from the toggles/purchase row below by the
   header's own border-bottom + padding. */
.upgrade-header-buttons {
    display: flex;

    align-items: center;
    gap: 8px;

    flex-shrink: 0;
}


/* The "Nothing" curse toggle shares the same track+thumb switch
   shape as Progressive Mode (see .upgrade-switch below), just with a
   warm/red accent instead of blue so it still reads as a curse. */
.upgrade-nothing-indicator.upgrade-switch.active {
    background: rgba(255, 130, 130, 0.16);

    border-color: #ff9d9d;

    box-shadow: 0 0 16px rgba(255, 130, 130, 0.45);
}


.upgrade-nothing-indicator.upgrade-switch.active .upgrade-switch-track {
    background: linear-gradient(90deg, #8f2f2f, #ff9d9d);

    border-color: #ff9d9d;
}


.upgrade-nothing-indicator.upgrade-switch.active .upgrade-switch-label {
    color: #ffdede;
}


.upgrade-panel-total {
    display: flex;

    align-items: center;
    gap: 10px;

    padding: 9px 16px;

    background: rgba(143, 217, 255, 0.06);

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 999px;

    box-shadow: 0 0 22px rgba(143, 217, 255, 0.25);
}


.upgrade-panel-total-label {
    color: #8fd9ff;

    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
}


.upgrade-panel-total-value {
    background: linear-gradient(90deg, #ffffff, #8fd9ff);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;

    font-size: 18px;
    font-weight: 900;
}


.upgrade-panel-remaining {
    border-color: rgba(255, 208, 116, 0.5);
    box-shadow: 0 0 22px rgba(255, 208, 116, 0.25);
}


.upgrade-panel-remaining .upgrade-panel-total-label {
    color: #ffd074;
}


.upgrade-panel-remaining .upgrade-panel-total-value {
    background: linear-gradient(90deg, #ffffff, #ffd074);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}


.upgrade-panel-total-value.upgrade-panel-total-value--negative {
    background: none;
    -webkit-text-fill-color: initial;

    color: #ff6b6b;
}


.upgrade-reset-button {
    padding: 10px 16px;

    background: transparent;

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 8px;

    color: #8fd9ff;

    font-size: 10px;
    font-weight: 800;
    letter-spacing: 1px;

    cursor: pointer;

    transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
}


.upgrade-reset-button:hover {
    background: rgba(143, 217, 255, 0.12);

    border-color: #dff5ff;

    color: #ffffff;

    box-shadow: 0 0 18px rgba(143, 217, 255, 0.4);
}


.upgrade-own-all-button {
    border-color: rgba(123, 230, 168, 0.45);

    color: #7be6a8;
}


.upgrade-own-all-button:hover {
    background: rgba(123, 230, 168, 0.14);

    border-color: #7be6a8;

    color: #ffffff;

    box-shadow: 0 0 18px rgba(123, 230, 168, 0.4);
}


.upgrade-icon-mode-button {
    border-color: rgba(255, 208, 116, 0.45);

    color: #ffd074;
}


.upgrade-icon-mode-button:hover {
    background: rgba(255, 208, 116, 0.14);

    border-color: #ffd074;

    color: #ffffff;

    box-shadow: 0 0 18px rgba(255, 208, 116, 0.4);
}


.upgrade-icon-mode-button.active {
    background: rgba(255, 208, 116, 0.22);

    border-color: #ffd074;

    color: #241100;

    box-shadow: 0 0 18px rgba(255, 208, 116, 0.55);
}


.upgrade-freeform-sort-button {
    border-color: rgba(196, 158, 255, 0.45);

    color: #c49eff;
}


.upgrade-freeform-sort-button:hover {
    background: rgba(196, 158, 255, 0.14);

    border-color: #c49eff;

    color: #ffffff;

    box-shadow: 0 0 18px rgba(196, 158, 255, 0.4);
}


.upgrade-freeform-sort-button.active {
    background: rgba(196, 158, 255, 0.22);

    border-color: #c49eff;

    color: #1c1330;

    box-shadow: 0 0 18px rgba(196, 158, 255, 0.55);
}



/* ---- Golden Gifts + purchase controls ---- */

.upgrade-panel-controls {
    display: flex;

    flex-direction: column;
    gap: 12px;

    margin-bottom: 16px;
    padding-bottom: 16px;

    border-bottom: 1px solid rgba(143, 217, 255, 0.15);
}


.upgrade-control-label {
    display: block;

    margin-bottom: 7px;

    color: #8fd9ff;

    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
}


/* Shared track+thumb switch shape, used by both the Progressive Mode
   toggle and the "Nothing" curse toggle (see .upgrade-nothing-indicator
   above for its red accent variant). Default coloring here is the
   blue Progressive Mode look. */
.upgrade-switch {
    display: flex;

    align-items: center;
    gap: 8px;

    padding: 7px 12px;

    background: rgba(143, 217, 255, 0.06);

    border: 1px solid rgba(143, 217, 255, 0.35);
    border-radius: 999px;

    cursor: pointer;
    user-select: none;

    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s, opacity 0.15s;
}


.upgrade-switch:hover {
    border-color: rgba(143, 217, 255, 0.6);
}


.upgrade-switch.active {
    background: rgba(143, 217, 255, 0.16);

    border-color: #8fd9ff;

    box-shadow: 0 0 16px rgba(143, 217, 255, 0.35);
}


.upgrade-switch:disabled {
    opacity: 0.35;

    cursor: not-allowed;
}


.upgrade-switch-track {
    position: relative;

    flex-shrink: 0;

    width: 32px;
    height: 18px;

    background: rgba(0, 0, 0, 0.35);

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 999px;

    transition: background 0.18s, border-color 0.18s;
}


.upgrade-switch.active .upgrade-switch-track {
    background: linear-gradient(90deg, #1c6f96, #8fd9ff);

    border-color: #8fd9ff;
}


.upgrade-switch-thumb {
    position: absolute;
    top: 1px;
    left: 1px;

    width: 14px;
    height: 14px;

    background: #dff5ff;
    border-radius: 50%;

    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);

    transition: transform 0.18s ease;
}


.upgrade-switch.active .upgrade-switch-thumb {
    transform: translateX(14px);
}


.upgrade-switch-label {
    color: #8fd9ff;

    font-family: var(--font-modern);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 1px;
    white-space: nowrap;
}


.upgrade-switch.active .upgrade-switch-label {
    color: #dff5ff;
}


/* The Nothing Curse toggle's block (hardcoded in toolkits.html as
   .upgrade-toggle-block) keeps the plain "label beside switch"
   layout - .upgrade-control-label defaults to display: block, which
   is what this rule corrects for it. */
.upgrade-toggle-block {
    display: flex;

    align-items: center;
    gap: 8px;

    flex-shrink: 0;
}


.upgrade-toggle-block-label {
    margin-bottom: 0;
    white-space: nowrap;
}


/* Progressive Mode's own card. Everything Progressive-related - the
   main switch, the level/revert/advance controls, and the Allow
   Debt / Hide Locked sub-toggles - lives stacked inside one
   self-contained box instead of loosely wrapping across the shared
   toggle-group row. The box is just one flex item inside
   #upgradeToggleGroup, which already has margin-left: auto, so it
   stays anchored to the right beside the Purchase button on its
   own - nothing in here pins or stretches it left.

   The card chrome itself (border/background/padding/glow) only
   exists while Progressive is actually on - see the --active
   modifier below. Off, this is just a transparent wrapper hugging
   the label + switch with no padding, so there's no empty-looking
   box sitting around when there's nothing inside it to justify one;
   turning Progressive on animates the chrome and padding in. */
.upgrade-progressive-box {
    display: flex;
    flex-direction: column;

    flex-shrink: 0;
    gap: 0;

    padding: 0;

    background: transparent;

    border: 1px solid transparent;
    border-radius: 12px;

    transition: background 0.25s ease, border-color 0.25s ease,
        box-shadow 0.25s ease, padding 0.25s ease, gap 0.25s ease;
}


/* Once Progressive is on, the card grows its padding and picks up a
   visible border/background/glow - this is the only state where it
   reads as a distinct box on the page. */
.upgrade-progressive-box--active {
    gap: 2px;

    padding: 8px 12px;

    background: rgba(143, 217, 255, 0.08);

    border-color: rgba(143, 217, 255, 0.32);

    box-shadow: 0 0 14px rgba(143, 217, 255, 0.14);
}


/* Label + main switch - the box's always-visible top row. */
.upgrade-progressive-header-row {
    display: flex;

    align-items: center;
    gap: 8px;
}


/* Revert / level badge / advance button share one row that collapses
   to nothing until Progressive is on, instead of three separately
   hidden elements - the whole row smoothly grows/fades open together
   (see the --visible modifier below) rather than snapping into view. */
.upgrade-progressive-status-row {
    display: flex;

    align-items: center;
    gap: 8px;

    max-height: 0;
    margin-top: 0;
    opacity: 0;

    overflow: hidden;
    pointer-events: none;

    transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease;
}


.upgrade-progressive-status-row--visible {
    max-height: 40px;
    margin-top: 6px;
    opacity: 1;

    pointer-events: auto;
}


/* Each control pops in with a little overshoot instead of just
   fading, staggered slightly left to right (Revert, Level, Advance)
   so they read as arriving in sequence rather than all at once.
   Adding the --visible class back re-triggers the animation every
   time the row opens. */
.upgrade-progressive-status-row--visible .upgrade-progressive-revert-button,
.upgrade-progressive-status-row--visible .upgrade-progressive-level,
.upgrade-progressive-status-row--visible .upgrade-progressive-advance-button {
    animation: upgrade-progressive-pop-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}


.upgrade-progressive-status-row--visible .upgrade-progressive-revert-button {
    animation-delay: 0s;
}


.upgrade-progressive-status-row--visible .upgrade-progressive-level {
    animation-delay: 0.05s;
}


.upgrade-progressive-status-row--visible .upgrade-progressive-advance-button {
    animation-delay: 0.1s;
}


@keyframes upgrade-progressive-pop-in {

    from {
        transform: scale(0.6);
        opacity: 0;
    }

    to {
        transform: scale(1);
        opacity: 1;
    }

}


/* Allow Debt / Hide Locked - the two Progressive sub-toggles. Same
   collapse/expand treatment as the status row above: the row stays
   in the DOM and animates open/shut via max-height + opacity instead
   of an instant display:none swap, with a thin divider so it reads
   as nested under Progressive rather than a third independent
   control. */
.upgrade-progressive-subtoggles {
    display: flex;

    flex-wrap: wrap;
    align-items: center;
    gap: 14px;

    max-height: 0;
    margin-top: 0;
    padding-top: 0;
    opacity: 0;

    overflow: hidden;
    pointer-events: none;

    /* Transparent (not just zero-height) while collapsed - a
       border-top still paints its 1px line even at max-height: 0,
       so color has to fade out too or it'd show as a stray hairline
       above the box's bottom edge while Progressive is off. */
    border-top: 1px dashed transparent;

    transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease,
        padding-top 0.25s ease, border-color 0.25s ease;
}


.upgrade-progressive-subtoggles--visible {
    max-height: 60px;
    margin-top: 6px;
    padding-top: 6px;
    opacity: 1;

    border-color: rgba(143, 217, 255, 0.25);

    pointer-events: auto;
}


/* The two sub-toggle rows pop in the same way as the status row's
   controls, staggered slightly so Allow Debt lands just ahead of
   Hide Locked. */
.upgrade-progressive-subtoggles--visible .upgrade-progressive-subtoggle-row {
    animation: upgrade-progressive-pop-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}


.upgrade-progressive-subtoggles--visible .upgrade-progressive-subtoggle-row:nth-child(2) {
    animation-delay: 0.06s;
}


.upgrade-progressive-subtoggle-row {
    display: flex;

    align-items: center;
    gap: 6px;
}


.upgrade-control-label--sub {
    margin-bottom: 0;

    opacity: 0.8;
    font-size: 9px;
}


/* Scaled-down variant of the shared .upgrade-switch shape (see above)
   for the two Progressive sub-toggles, which sit visually "inside"
   Progressive rather than standing as their own top-level control. */
.upgrade-switch--sub {
    padding: 4px 9px;
    gap: 6px;
}


.upgrade-switch--sub .upgrade-switch-track {
    width: 24px;
    height: 14px;
}


.upgrade-switch--sub .upgrade-switch-thumb {
    width: 10px;
    height: 10px;
}


.upgrade-switch--sub.active .upgrade-switch-thumb {
    transform: translateX(10px);
}


.upgrade-switch--sub .upgrade-switch-label {
    font-size: 8px;
}


/* Small live-level badge shown next to the Progressive toggle only
   while it's on, since the run level only moves in that mode. */
.upgrade-progressive-level {
    flex-shrink: 0;

    padding: 3px 9px;

    background: rgba(143, 217, 255, 0.14);

    border: 1px solid rgba(102, 151, 175, 0.45);
    border-radius: 999px;

    color: #dff5ff;

    font-family: var(--font-modern);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.6px;
    white-space: nowrap;
}


/* Explicit "advance to the next shop level" control - shown right
   next to the current-level badge, displaying the level it'll jump
   to so the player knows what they're clicking before they do it.
   Progressive mode no longer bumps the level automatically on
   purchase; this button is the only way it moves. */
.upgrade-progressive-advance-button {
    flex-shrink: 0;

    padding: 5px 12px;

    background: linear-gradient(
        90deg,
        #ffd074 0%,
        #ff9d3d 25%,
        #ffe3a8 50%,
        #ff9d3d 75%,
        #ffd074 100%
    );
    background-size: 260% auto;

    border: 1px solid #ffe3a8;
    border-radius: 999px;

    color: #241100;

    font-family: var(--font-modern);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.4px;
    white-space: nowrap;

    cursor: pointer;

    box-shadow: 0 0 12px rgba(255, 157, 61, 0.35);

    animation: upgrade-advance-gradient-shift 5.7s linear infinite;

    transition: transform 0.15s, box-shadow 0.15s;
}


/* Loop fix: this button's gradient is 260% of its width, so one full
   tile is 2.6x the button. With background-position percentages the
   shift is (container - image) * pct = -1.6x * pct, so ending at 100%
   only slid it 1.6x - short of a whole tile, which made the colors
   snap back at the loop point. 162.5% (= 260 / 160) slides exactly one
   tile, so the end frame equals the start frame and the loop is
   seamless. Durations were stretched by the same 1.625 factor to keep
   the original pace. */
@keyframes upgrade-advance-gradient-shift {

    0% {
        background-position: 0% 50%;
    }

    100% {
        background-position: 162.5% 50%;
    }

}


.upgrade-progressive-advance-button:hover {
    transform: translateY(-1px);
    box-shadow: 0 0 18px rgba(255, 157, 61, 0.55);
}


/* Revert control - mirrors the Advance button's shape but in a
   cooler, less saturated blue gradient so it reads as "undo" rather
   than "forward," and sits to the left of the level badge instead
   of the right (see renderProgressiveLevelBadge in Upgrades.js).
   Disabled once the run's already at the first shop level (Lv 3) -
   nothing earlier to revert back to. */
.upgrade-progressive-revert-button {
    flex-shrink: 0;

    padding: 5px 12px;

    background: linear-gradient(
        90deg,
        #8fd9ff 0%,
        #4a7a91 25%,
        #c7ecff 50%,
        #4a7a91 75%,
        #8fd9ff 100%
    );
    background-size: 260% auto;

    border: 1px solid #c7ecff;
    border-radius: 999px;

    color: #041824;

    font-family: var(--font-modern);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.4px;
    white-space: nowrap;

    cursor: pointer;

    box-shadow: 0 0 12px rgba(143, 217, 255, 0.35);

    animation: upgrade-revert-gradient-shift 5.7s linear infinite;

    transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
}


/* Loop fix: this button's gradient is 260% of its width, so one full
   tile is 2.6x the button. With background-position percentages the
   shift is (container - image) * pct = -1.6x * pct, so ending at 100%
   only slid it 1.6x - short of a whole tile, which made the colors
   snap back at the loop point. 162.5% (= 260 / 160) slides exactly one
   tile, so the end frame equals the start frame and the loop is
   seamless. Durations were stretched by the same 1.625 factor to keep
   the original pace. */
@keyframes upgrade-revert-gradient-shift {

    0% {
        background-position: 0% 50%;
    }

    100% {
        background-position: 162.5% 50%;
    }

}


.upgrade-progressive-revert-button:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 0 18px rgba(143, 217, 255, 0.55);
}


.upgrade-progressive-revert-button:disabled {
    opacity: 0.35;

    cursor: not-allowed;

    animation-play-state: paused;
    transform: none;
    box-shadow: none;
}


/* Game Mode buttons have moved into the sidebar (see
   .upgrade-mode-sidebar-section) - this grid styling is shared with
   the sidebar's button-grid wrapper. */
.upgrade-mode-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
}


.upgrade-mode-button {
    min-height: 46px;

    padding: 8px;

    font-size: 11px;
}


.upgrade-mode-button.selected {
    background: linear-gradient(135deg, #0d3a52, #1c6f96);

    border-color: #8fd9ff;

    color: #ffffff;

    box-shadow: 0 0 16px rgba(143, 217, 255, 0.45);
}


.upgrade-mode-solo.selected {
    background: linear-gradient(135deg, #0d5c3a, #2fc48a);

    border-color: #7be6a8;

    box-shadow: 0 0 16px rgba(123, 230, 168, 0.45);
}


.upgrade-mode-duo.selected {
    background: linear-gradient(135deg, #0d3a52, #1c6f96);

    border-color: #8fd9ff;

    box-shadow: 0 0 16px rgba(143, 217, 255, 0.45);
}


.upgrade-mode-party.selected {
    background: linear-gradient(135deg, #4a1c85, #9147d6);

    border-color: #d59bff;

    box-shadow: 0 0 16px rgba(184, 102, 255, 0.45);
}


.upgrade-mode-partyplus.selected {
    background: linear-gradient(135deg, #8a5200, #ffb347);

    border-color: #ffd074;

    box-shadow: 0 0 16px rgba(255, 179, 71, 0.45);
}


/* Golden Gifts input, Pending/Left totals, and the Nothing/
   Progressive toggle group sit together in this row so the whole
   "how much do I have / can I afford it" readout stays in one
   glance. Purchase Upgrade used to share this row too, but
   Progressive mode adds a level badge + advance/revert buttons into
   the toggle group once it's on, which kept shoving the button
   sideways or onto a new line as the row's content changed size -
   it now lives in its own dedicated row below instead (see
   .upgrade-purchase-row-bottom), which never grows or shrinks based
   on anything in this row. Top-aligned (not flex-end) so that when
   the Progressive box grows taller as it turns on and its controls
   expand, it just extends further downward instead of dragging the
   shorter Golden Gifts / totals blocks down with it and leaving a
   gap of blank space above them. */
.upgrade-purchase-row {
    display: flex;

    flex-wrap: wrap;

    align-items: flex-start;
    gap: 10px;
}


.upgrade-gifts-block {
    flex: 0 0 140px;
}


.upgrade-gifts-block input {
    width: 100%;

    padding: 9px 11px;

    background: #071620;

    border: 1px solid rgba(143, 217, 255, 0.35);
    border-radius: 8px;

    color: #dff5ff;

    outline: none;

    font-size: 13px;
    font-weight: 700;
    font-family: var(--font-modern);

    transition: border-color 0.15s, box-shadow 0.15s;
}


.upgrade-gifts-block input:focus {
    border-color: #8fd9ff;
    box-shadow: 0 0 0 3px rgba(143, 217, 255, 0.18);
}


/* Pending / Left are the two numbers a player checks before every
   purchase, so they're sized well above the surrounding controls and
   given a stronger border/glow to stay legible at a glance. */
.upgrade-panel-total {
    display: flex;

    align-items: center;
    gap: 10px;

    padding: 11px 20px;

    background: rgba(143, 217, 255, 0.09);

    border: 2px solid rgba(143, 217, 255, 0.55);
    border-radius: 999px;

    box-shadow: 0 0 22px rgba(143, 217, 255, 0.3);
}


.upgrade-panel-total-label {
    color: #8fd9ff;

    font-size: 12px;
    font-weight: 800;
    letter-spacing: 1.2px;
}


.upgrade-panel-total-value {
    background: linear-gradient(90deg, #ffffff, #8fd9ff);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;

    font-size: 22px;
    font-weight: 900;
}


.upgrade-panel-remaining {
    border-color: rgba(255, 208, 116, 0.65);
    box-shadow: 0 0 22px rgba(255, 208, 116, 0.3);
}


.upgrade-panel-remaining .upgrade-panel-total-label {
    color: #ffd074;
}


.upgrade-panel-remaining .upgrade-panel-total-value {
    background: linear-gradient(90deg, #ffffff, #ffd074);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}


.upgrade-panel-total-value.upgrade-panel-total-value--negative {
    background: none;
    -webkit-text-fill-color: initial;

    color: #ff6b6b;
}


/* Nothing-curse + Progressive toggles now sit as one group directly
   beside the Purchase Upgrade button. margin-left: auto pushes this
   whole group (and the purchase button right after it) away from
   the Golden Gifts / Total / Left readouts, and the left
   border/padding reads as a clear divider between them. */
.upgrade-toggle-group {
    display: flex;

    align-items: center;
    gap: 8px;

    margin-left: auto;
    padding-left: 16px;

    border-left: 1px solid rgba(143, 217, 255, 0.2);
}


/* Its own dedicated row, always full width - it no longer needs to
   negotiate space with .upgrade-purchase-row above (see that rule's
   comment), so it always sits in exactly the same place regardless
   of whether Progressive mode's extra badge/buttons are showing. The
   top border + spacing reads as a clear break between "here's your
   info" and "here's the button that does something." */
.upgrade-purchase-row-bottom {
    margin-top: 16px;
    padding-top: 16px;

    border-top: 1px solid rgba(143, 217, 255, 0.15);
}


/* Bigger, easier to hit, and reads as the primary action of the
   panel - noticeably taller than the surrounding controls, and now
   spans the full width of its own row instead of sharing space. */
.purchase-upgrade-button {
    width: 100%;

    padding: 20px 24px;
    min-height: 58px;

    background: linear-gradient(135deg, #ffd074, #ff9d3d);

    border: 1px solid #ffe3a8;
    border-radius: 10px;

    color: #241100;

    font-family: var(--font-modern);
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 1.2px;

    cursor: pointer;

    box-shadow: 0 0 20px rgba(255, 157, 61, 0.4);

    transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
}


.purchase-upgrade-button:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 0 26px rgba(255, 157, 61, 0.6);
}


.purchase-upgrade-button:disabled,
.purchase-upgrade-button.purchase-upgrade-button--disabled {
    opacity: 0.35;

    cursor: not-allowed;

    box-shadow: none;
    transform: none;
}


/* ---- Category columns (vertical lists, side by side) ---- */

/*
 * Categories sit side by side as columns so the whole calculator
 * reads top-to-bottom within each category instead of wrapping
 * left-to-right - this keeps the panel far shorter overall. Columns
 * no longer stretch to match the tallest sibling or scroll on their
 * own - each is only as tall as its own content, and the whole
 * panel (.upgrade-panel-inner) scrolls as a single region instead.
 */
/* auto-fit lets each category claim at least 200px before another
   column is allowed to squeeze in - with 5 categories now instead
   of 4, that means the row wraps onto a second line on narrower
   panels rather than cramming every column down until item names
   have no room left to show. On wide panels all 5 still sit on one
   line same as before. */
.upgrade-categories {
    display: grid;

    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    align-items: stretch;

    gap: 10px 14px;
}


.upgrade-category {
    min-width: 0;

    display: flex;

    flex-direction: column;
}


/* Divider between category columns - a single left border on every
   column but the first, so it still reads correctly if a row wraps
   (the wrapped column just starts a fresh line). Applies to both
   the buyable categories row and the OWNED UPGRADES basin below it
   (both use .upgrade-category), and works the same whether Icon
   Mode is on or off since it's keyed off the column wrapper itself,
   not anything inside it. */
.upgrade-category:not(:first-child) {
    padding-left: 14px;

    border-left: 1px solid rgba(143, 217, 255, 0.16);
}


.upgrade-category-heading {
    flex-shrink: 0;

    margin-bottom: 8px;
    padding-bottom: 6px;

    border-bottom: 1px solid rgba(143, 217, 255, 0.18);

    color: #8fd9ff;

    font-family: var(--font-modern);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.6px;
}


.upgrade-grid {
    display: grid;

    /* level | icon | name+price | stack | unown - the stack
       indicator gets its own fixed-width column (see
       .upgrade-row-stack) so it lines up across every row in a
       category instead of drifting with how long each item's name
       is. Price no longer gets its own column - it now sits under
       the name instead (see .upgrade-row-info below), which is what
       actually gives the name room to show in full now that there
       are 5 categories sharing the panel width instead of 4. */
    grid-template-columns: 22px 40px minmax(0, 1fr) 44px 20px;
    align-content: start;
    align-items: center;

    row-gap: 9px;
    column-gap: 6px;

    padding-right: 4px;
    padding-bottom: 4px;
}


/* A distinct "OWNED UPGRADES" basin sits below the buyable
   categories, split into the same 4 category columns so each column
   lines up directly under its matching category above. */
.upgrade-owned-banner {
    flex-shrink: 0;

    display: flex;

    align-items: center;
    gap: 6px;

    margin-top: 14px;
    padding-top: 12px;
    padding-bottom: 8px;

    border-top: 1px solid rgba(123, 230, 168, 0.3);

    color: #7be6a8;

    font-family: var(--font-modern);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.8px;
}


.upgrade-owned-categories {
    flex: 0 0 auto;
}


/* Freeform Sort: category columns collapse into a single flat
   5-column grid (no per-category headings, no dividers) ordered by
   level instead - see buildFreeformUpgradeGrid in Upgrades.js.
   Normal .upgrade-grid rows are subgrid children of a 5-column
   parent (level|icon|name+price|stack|unown) that spans the full
   category column width - that only works when there's exactly one
   card per grid row. Freeform packs 5 cards per row instead, so each
   .upgrade-row here carries its own 5-column template directly
   (overriding the subgrid/full-span rules) and occupies a single
   cell rather than spanning the parent. */
.upgrade-categories--freeform {
    display: block;
}


.upgrade-grid--freeform {
    grid-template-columns: repeat(5, minmax(0, 1fr));

    column-gap: 10px;
}


.upgrade-grid--freeform .upgrade-row {
    grid-column: auto;
    grid-template-columns: 18px 30px minmax(0, 1fr) 36px 16px;
}


.upgrade-category-heading--owned {
    color: #7be6a8;

    border-bottom-color: rgba(123, 230, 168, 0.25);
}


.upgrade-empty-row {
    grid-column: 1 / -1;

    padding: 10px 8px;

    color: #5c7a68;

    font-family: var(--font-modern);
    font-size: 9px;
    font-style: italic;
    text-align: center;
}


/* ---- Upgrade row (compact, vertical list item) ----
   Each row is itself a grid that shares the parent's column tracks
   (subgrid), so its icon/name/dots/price/unown cells align with
   every other row's cells instead of drifting with content width. */

.upgrade-row {
    position: relative;

    /* Minimum height, not a fixed one - rows stay aligned to a
       consistent baseline size but are never clipped if their
       content (stack dots, price) needs a touch more room.
       overflow is visible so the dependency badge can sit slightly
       outside the card's corner. */
    min-height: 46px;
    box-sizing: border-box;
    overflow: visible;

    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    column-gap: 8px;
    align-items: center;

    padding: 4px 8px;

    background: linear-gradient(160deg, rgba(16, 34, 50, 0.9) 0%, rgba(6, 12, 22, 0.95) 100%);

    border: 1px solid rgba(143, 217, 255, 0.2);
    border-radius: 8px;

    color: #dff5ff;

    cursor: pointer;

    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}


.upgrade-row:hover {
    border-color: #8fd9ff;
    box-shadow: 0 0 14px rgba(143, 217, 255, 0.3);
}


.upgrade-row:focus-visible {
    outline: 2px solid #8fd9ff;
    outline-offset: 1px;
}


.upgrade-row--affordable {
    border-color: #8fd9ff;
    box-shadow: 0 0 12px rgba(143, 217, 255, 0.25);
}


.upgrade-row--active {
    background: linear-gradient(160deg, rgba(255, 208, 116, 0.24) 0%, rgba(80, 55, 10, 0.75) 100%);

    border-color: #ffd074;
    box-shadow: 0 0 16px rgba(255, 208, 116, 0.45);
}


.upgrade-row--owned {
    background: linear-gradient(160deg, rgba(123, 230, 168, 0.2) 0%, rgba(8, 40, 24, 0.9) 100%);

    border-color: #7be6a8;
    box-shadow: 0 0 12px rgba(123, 230, 168, 0.28);
}


.upgrade-row--locked {
    cursor: not-allowed;

    opacity: 0.4;
    filter: grayscale(0.6);
}


.upgrade-row--locked:hover {
    border-color: rgba(143, 217, 255, 0.2);
    box-shadow: none;
}


/* No boxed background/border anymore - the icon sits directly in
   the row's own gradient so it reads as part of the row instead of
   a separate tile stuck inside it. A soft drop-shadow keeps it from
   visually flattening into that background. */
.upgrade-icon {
    grid-column: 2;

    flex-shrink: 0;

    width: 36px;
    height: 36px;

    display: flex;

    align-items: center;
    justify-content: center;

    overflow: hidden;

    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
}


.upgrade-icon-image {
    width: 100%;
    height: 100%;

    object-fit: contain;
}


.upgrade-icon-placeholder {
    padding: 1px;

    color: #8fd9ff;

    font-size: 6px;
    font-weight: 700;
    line-height: 1.1;
    text-align: center;
}


.upgrade-row-info {
    grid-column: 3;
    min-width: 0;

    display: flex;
    flex-direction: column;
    justify-content: center;

    gap: 3px;
}


.upgrade-row-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;

    font-family: var(--font-modern);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.3px;
}


/* Required-level indicator, placed to the left of the icon rather
   than crowded next to the name. */
.upgrade-row-level {
    grid-column: 1;
    justify-self: center;

    flex-shrink: 0;

    color: #6faccf;

    font-family: var(--font-modern);
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 0.3px;
    white-space: nowrap;
}


/* Stack indicator - its own fixed column between the name and the
   price (see the upgrade-grid template above), so it lines up
   across every row in a category instead of drifting with how long
   each item's name is. Shows both a numeric readout (e.g. "2/3")
   and the row of pips underneath it. */
.upgrade-row-stack {
    grid-column: 4;
    justify-self: center;

    flex-shrink: 0;

    display: flex;
    flex-direction: column;
    align-items: center;

    gap: 3px;
}


.upgrade-row-stack-text {
    color: #8fd9ff;

    font-family: var(--font-modern);
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.4px;
    white-space: nowrap;
}


.upgrade-row-dots {
    display: flex;
    flex-direction: row;
    align-items: center;

    gap: 3px;
}


.upgrade-dot {
    width: 4px;
    height: 4px;

    background: rgba(143, 217, 255, 0.2);

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 50%;
}


/* Green once that specific stack has actually been bought - distinct
   from the single "current floor" dot below, so owned and
   selected-but-not-yet-purchased read differently at a glance. */
.upgrade-dot--owned {
    background: #7be6a8;

    border-color: #7be6a8;

    box-shadow: 0 0 6px rgba(123, 230, 168, 0.8);
}


/* Elevator-style position indicator - at most one dot lights up per
   row: the specific tier currently selected/pending, not every dot
   leading up to it. */
.upgrade-dot--current {
    background: #ffd074;
    box-shadow: 0 0 6px rgba(255, 208, 116, 0.8);
}


.upgrade-row-price {
    align-self: flex-start;

    flex-shrink: 0;

    display: inline-flex;

    align-items: center;
    gap: 3px;

    padding: 3px 7px;

    background: linear-gradient(135deg, #ffd074, #ff9d3d);

    border: 1px solid rgba(255, 208, 116, 0.7);
    border-radius: 999px;

    color: #241100;

    font-family: var(--font-modern);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.3px;
    white-space: nowrap;
}


.upgrade-row-price-icon {
    width: 12px;
    height: 12px;

    flex-shrink: 0;

    object-fit: contain;
}


.upgrade-row-price-amount {
    line-height: 1;
}


.upgrade-row-price--unaffordable {
    background: linear-gradient(135deg, #5c5f68, #34363e);

    border-color: rgba(180, 184, 196, 0.5);

    color: #cfd2db;
}


.upgrade-row-price--owned {
    background: linear-gradient(135deg, #7be6a8, #2f9c60);

    border-color: rgba(123, 230, 168, 0.7);

    color: #06210f;
}


/* Distinct from both the normal gold price and the green "OWNED"
   badge - a lime/yellow-green combo so a free stack (e.g. Paycheck's
   first stack in Solo/Duo) reads as its own kind of good news rather
   than being confused with something already purchased. */
.upgrade-row-price--free {
    background: linear-gradient(135deg, #e4ff7a, #8fbf2f);

    border-color: rgba(228, 255, 122, 0.75);

    color: #1c2400;

    box-shadow: 0 0 10px rgba(228, 255, 122, 0.35);
}


.upgrade-row-price--locked {
    background: rgba(120, 120, 130, 0.35);

    border-color: rgba(180, 180, 190, 0.4);

    color: #b8bac2;
}


/* Stack stepper - replaces the old single un-own "-" button. Up
   queues one more stack (same as clicking the row); down either
   cancels a pending stack that hasn't been purchased yet, or - once
   there's no pending left to cancel - un-owns one already-owned
   stack as a tracker correction (no refund, matching the old unown
   button's behavior). Stacked vertically so it fits the narrow
   trailing grid column. */
.upgrade-row-stepper {
    grid-column: 5;
    justify-self: center;

    flex-shrink: 0;

    display: flex;
    flex-direction: column;

    gap: 2px;
}


.upgrade-stepper-button {
    width: 16px;
    height: 14px;

    display: flex;

    align-items: center;
    justify-content: center;

    padding: 0;

    background: rgba(143, 217, 255, 0.12);

    border: 1px solid rgba(143, 217, 255, 0.4);
    border-radius: 3px;

    color: #8fd9ff;

    font-size: 7px;
    line-height: 1;

    cursor: pointer;

    transition: background 0.12s, border-color 0.12s, color 0.12s, transform 0.12s;
}


.upgrade-stepper-button:hover:not(:disabled) {
    background: rgba(143, 217, 255, 0.3);

    border-color: #dff5ff;

    color: #ffffff;

    transform: scale(1.08);
}


/* Down step reads as the "remove" action, so it borrows the old
   unown button's red accent instead of the default blue. */
.upgrade-stepper-button--down {
    background: rgba(255, 100, 100, 0.18);

    border-color: rgba(255, 130, 130, 0.55);

    color: #ffc2c2;
}


.upgrade-stepper-button--down:hover:not(:disabled) {
    background: rgba(255, 100, 100, 0.35);

    border-color: #ff9d9d;

    color: #ffffff;
}


.upgrade-stepper-button:disabled {
    opacity: 0.3;

    cursor: not-allowed;
    transform: none;
}


/* Un-own control - now shown only on rows that have moved into the
   OWNED UPGRADES basin, as the single way to correct/reduce an
   already-purchased stack. Active (not-yet-fully-owned) rows use the
   stepper above instead. */
.upgrade-unown-button {
    grid-column: 5;
    justify-self: center;

    flex-shrink: 0;

    width: 15px;
    height: 15px;

    display: flex;

    align-items: center;
    justify-content: center;

    padding: 0;

    background: rgba(255, 100, 100, 0.18);

    border: 1px solid rgba(255, 130, 130, 0.55);
    border-radius: 50%;

    color: #ffc2c2;

    font-size: 11px;
    font-weight: 800;
    line-height: 1;

    cursor: pointer;

    transition: background 0.12s, border-color 0.12s, color 0.12s, transform 0.12s;
}


.upgrade-unown-button:hover {
    background: rgba(255, 100, 100, 0.35);

    border-color: #ff9d9d;

    color: #ffffff;

    transform: scale(1.1);
}


/* Nested placement (see createStackStepper in Upgrades.js) - sits
   inline between the up/down arrows inside the stepper's own narrow
   column instead of claiming a grid column of its own, so a
   partially-owned, still-buyable row never has to grow a second
   implicit row to fit both controls. Sized down slightly from the
   standalone version to match the arrows it sits between. */
.upgrade-unown-button--inline {
    grid-column: unset;

    width: 14px;
    height: 12px;

    font-size: 10px;
}


/* Requirement / prerequisite chip - a small badge pinned to the
   card's top-left corner, sitting slightly outside the row's own
   border rather than sharing a grid cell with the level text, so it
   never overlaps or merges with it. */
.upgrade-requirement-chip {
    position: absolute;
    top: -8px;
    left: -10px;
    z-index: 2;

    display: flex;

    align-items: center;
    gap: 2px;

    padding: 2px 4px 2px 5px;

    background: rgba(6, 12, 22, 0.95);

    border: 1px solid rgba(143, 217, 255, 0.35);
    border-radius: 999px;

    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
}


.upgrade-requirement-chip--met {
    border-color: rgba(123, 230, 168, 0.6);
}


.upgrade-requirement-arrow {
    color: #6faccf;

    font-size: 9px;
    line-height: 1;
}


.upgrade-requirement-chip--met .upgrade-requirement-arrow {
    color: #7be6a8;
}


.upgrade-requirement-icons {
    display: flex;

    align-items: center;
    gap: 2px;
}


.upgrade-requirement-icon {
    width: 13px;
    height: 13px;

    display: flex;

    align-items: center;
    justify-content: center;

    overflow: hidden;

    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
}


.upgrade-requirement-icon .upgrade-icon-placeholder {
    font-size: 4px;
}


/* ---- Icon Mode ----
   Strips each row down to just its icon, a compact price badge, and
   the stack controls - only the item name drops out visually. Level
   pokes out past the top edge of the tile (same "sticking out"
   treatment curse cards use for their enemy badges), styled
   stale/muted gray rather than the bright gold price treatment so it
   doesn't compete with the price badge for attention. Any dependency
   requirement chip keeps its own default spot poking past the
   top-left corner. The stack stepper/un-own button sit at the
   bottom of the tile, laid out horizontally.
   2 columns per category (was 3) so each tile gets roughly twice
   the room - everything inside (icon, level badge, price badge,
   stepper/unown controls, dots) is scaled up to match rather than
   just leaving the extra space empty. Nothing is actually lost from
   hiding the name either: every row still carries a title/aria-label
   with the full name/level/price/stack info (see createUpgradeCard
   in Upgrades.js). Toggled via #upgradeIconModeToggle, which
   adds/removes this class on #upgradePanel itself. */
.upgrade-panel.icon-mode .upgrade-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-content: start;

    row-gap: 30px;
    column-gap: 18px;
}


.upgrade-panel.icon-mode .upgrade-row {
    grid-column: auto;
    grid-template-columns: none;

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;

    gap: 6px;

    min-height: unset;
    aspect-ratio: unset;

    padding: 12px 8px;
}


/* Only the name drops out visually in Icon Mode - the price badge
   now lives inside this same wrapper (see .upgrade-row-info in the
   normal-mode rules above), so the wrapper itself has to stay
   visible here, just centered under the icon instead of left-
   aligned next to a name. */
.upgrade-panel.icon-mode .upgrade-row-info {
    align-items: center;
}


.upgrade-panel.icon-mode .upgrade-row-name {
    display: none;
}


/* Explicit stacking order - icon, then stack dots (if any), then
   price, then the stepper/unown controls - since the price badge
   now sits inside .upgrade-row-info, which appears earlier in the
   DOM than the stack dots (see Upgrades.js). Without this the price
   would render above the stack dots instead of below them. */
.upgrade-panel.icon-mode .upgrade-icon {
    order: 1;

    width: 70%;
    aspect-ratio: 1 / 1;
    height: auto;

    flex: 0 0 auto;
}


.upgrade-panel.icon-mode .upgrade-row-stack {
    order: 2;
}


.upgrade-panel.icon-mode .upgrade-row-info {
    order: 3;
}


.upgrade-panel.icon-mode .upgrade-row-stepper,
.upgrade-panel.icon-mode .upgrade-unown-button {
    order: 4;
}


/* Level indicator - normally an inline label to the left of the
   icon (see .upgrade-row-level). In Icon Mode it's pulled out of
   the flex flow and pinned above the tile's top edge instead,
   staying outside the box entirely so it never covers the icon. */
.upgrade-panel.icon-mode .upgrade-row-level {
    position: absolute;
    top: -11px;
    left: 50%;

    transform: translateX(-50%);

    z-index: 2;

    grid-column: unset;
    justify-self: unset;

    padding: 2px 7px;

    background: rgba(40, 42, 48, 0.85);

    border: 1px solid rgba(180, 186, 196, 0.35);
    border-radius: 999px;

    color: #b7bcc4;

    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.2px;
    white-space: nowrap;
}


.upgrade-panel.icon-mode .upgrade-requirement-chip {
    top: -11px;
    left: -11px;
}


.upgrade-panel.icon-mode .upgrade-requirement-icon {
    width: 16px;
    height: 16px;
}


.upgrade-panel.icon-mode .upgrade-row-stack {
    flex-direction: row;
}


.upgrade-panel.icon-mode .upgrade-row-stack-text {
    display: none;
}


.upgrade-panel.icon-mode .upgrade-dot {
    width: 6px;
    height: 6px;
}


.upgrade-panel.icon-mode .upgrade-row-price {
    padding: 5px 12px;

    font-size: 15px;
}


.upgrade-panel.icon-mode .upgrade-row-price-amount {
    font-size: 15px;
}


.upgrade-panel.icon-mode .upgrade-row-price-icon {
    width: 18px;
    height: 18px;
}


/* Stack stepper + un-own button sit at the bottom of the tile,
   laid out horizontally so the pair fits in one compact row instead
   of the normal mode's vertical up/down stack in its own grid
   column. Sized up to match the rest of the enlarged tile. */
.upgrade-panel.icon-mode .upgrade-row-stepper {
    grid-column: unset;
    justify-self: unset;

    flex-direction: row;
    gap: 6px;
}


.upgrade-panel.icon-mode .upgrade-stepper-button {
    width: 22px;
    height: 18px;

    font-size: 9px;
}


.upgrade-panel.icon-mode .upgrade-unown-button {
    grid-column: unset;
    justify-self: unset;

    width: 20px;
    height: 20px;

    font-size: 14px;
}


/* Nested placement (see .upgrade-unown-button--inline above) stays
   sized to the stepper's own (also enlarged) arrows here, rather
   than inheriting the larger standalone icon-mode size above. */
.upgrade-panel.icon-mode .upgrade-unown-button--inline {
    width: 18px;
    height: 18px;

    font-size: 12px;
}


/* Freeform Sort + Icon Mode together: the base icon-mode rules above
   assume .upgrade-grid lives inside a narrow ~200px category column,
   so their 2-column layout and 70%-width icon scale to that. In
   Freeform the grid instead spans the whole panel, so that same
   2-column/70% math blows the icons up huge. These overrides (same
   selectors, just scoped under .upgrade-categories--freeform so they
   win via source order) pack more, smaller tiles into that width
   instead. */
.upgrade-panel.icon-mode .upgrade-categories--freeform .upgrade-grid {
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));

    row-gap: 22px;
    column-gap: 12px;
}


.upgrade-panel.icon-mode .upgrade-categories--freeform .upgrade-row {
    padding: 10px 6px;
}


.upgrade-panel.icon-mode .upgrade-categories--freeform .upgrade-icon {
    width: 46px;
}


@media (max-width: 900px) {

    .upgrade-categories {
        grid-template-columns: 1fr;
    }


    .upgrade-category:not(:first-child) {
        padding-left: 0;
        padding-top: 14px;
        margin-top: 14px;

        border-left: none;
        border-top: 1px solid rgba(143, 217, 255, 0.16);
    }

}


@media (max-width: 700px) {

    .upgrade-purchase-row {
        flex-direction: column;
        align-items: stretch;
    }


    .upgrade-gifts-block {
        flex: 1 1 auto;
    }


    .upgrade-toggle-group {
        margin-left: 0;
        padding-left: 0;

        border-left: none;
        border-top: 1px solid rgba(143, 217, 255, 0.2);

        padding-top: 10px;

        flex-wrap: wrap;
        justify-content: space-between;
    }

}


/*
 * No more right/bottom overrides here at small widths - those now
 * live in .floating-toggle-buttons's own media query in style.css,
 * which repositions the whole wrapper (and both buttons inside it)
 * together instead of just this one.
 */
@media (max-width: 500px) {

    .upgrade-mode-grid {
        grid-template-columns: repeat(2, 1fr);
    }


    .upgrade-toggle-button {
        padding: 10px 14px;
    }

}