/* ===================================================================
   OnlyVega UI kit  (ov-ui.css)
   Loaded AFTER hire.css so it can refine it. ASCII ONLY.
   Sections: loading bar - date inputs - install btn - light-mode fixes
   Batch B appends: custom date picker + confirm modal.
   =================================================================== */

/* ---- Top loading bar (navigation + AJAX) ---- */
#ov-progress {
    position: fixed; top: 0; left: 0; height: 3px; width: 0; z-index: 10000;
    background: linear-gradient(90deg, #7C5CFF, #B15CE8, #FF4D8D);
    box-shadow: 0 0 10px rgba(124,92,255,.7);
    opacity: 0; border-radius: 0 3px 3px 0;
    transition: width .2s ease, opacity .35s ease; pointer-events: none;
}
#ov-progress.active { opacity: 1; }

/* small inline spinner utility */
.ov-spin { display: inline-block; width: 1em; height: 1em; border: 2px solid currentColor;
    border-right-color: transparent; border-radius: 50%; animation: ovSpin .6s linear infinite; vertical-align: -.15em; }
@keyframes ovSpin { to { transform: rotate(360deg); } }
.btn.is-loading { position: relative; color: transparent !important; pointer-events: none; }
.btn.is-loading::after { content: ""; position: absolute; inset: 0; margin: auto; width: 15px; height: 15px;
    border: 2px solid rgba(255,255,255,.85); border-right-color: transparent; border-radius: 50%; animation: ovSpin .6s linear infinite; }

/* ==================== NATIVE DATE / TIME / NUMBER CONTROLS ====================
   color-scheme is the switch that tells the engine which palette to render the whole
   native widget with: the drop-down calendar, the spin buttons, the text caret and the
   scrollbars. Declaring it on the ROOT covers every control on the page at once
   (including ones no stylesheet knows about) instead of listing input types.

   Order matters. The media query only ever applies when the root carries NO data-theme
   at all (JS blocked, so nothing was stamped); the two explicit [data-theme] rules come
   after it AND are more specific, so the toggle always wins over the OS preference. */
:root { color-scheme: dark; }
@media (prefers-color-scheme: light) {
    :root:not([data-theme]) { color-scheme: light; }
}
:root[data-theme="dark"]  { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* ---- The calendar button ----
   It was invisible, and color-scheme is exactly why. With color-scheme:dark the engine
   ALREADY draws the indicator glyph in a light colour; the old filter:invert(1) then
   flipped that light glyph back to near-black and painted it on the dark --bg-3 field.
   Dark on dark = nothing to see, which is what the screenshot showed.

   Rather than filtering a glyph whose starting colour depends on the engine, the
   indicator gets its own icon. Setting background-image on the pseudo-element replaces
   the native glyph in Blink/WebKit while the element itself stays the real, clickable
   picker button, so the theme can never get it wrong. Gecko ignores these rules and
   renders its own indicator, which color-scheme above already themes correctly. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator {
    width: 20px; height: 20px; padding: 0; margin: 0 0 0 6px;
    background-color: transparent;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18' fill='none' stroke='%23A7AFC0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='3.75' width='13' height='11.75' rx='2.5'/%3E%3Cpath d='M2.5 7.75h13M6 2v3.2M12 2v3.2'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: center; background-size: 18px 18px;
    border-radius: 6px; opacity: .8; cursor: pointer; filter: none;
    transition: opacity .15s, background-color .15s;
}
input[type="time"]::-webkit-calendar-picker-indicator {
    width: 20px; height: 20px; padding: 0; margin: 0 0 0 6px;
    background-color: transparent;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18' fill='none' stroke='%23A7AFC0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='9' r='6.5'/%3E%3Cpath d='M9 5.4V9l2.6 1.7'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: center; background-size: 18px 18px;
    border-radius: 6px; opacity: .8; cursor: pointer; filter: none;
    transition: opacity .15s, background-color .15s;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover,
input[type="week"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover {
    opacity: 1; background-color: var(--card-hover);
}
/* Light theme: same icon, ink-coloured stroke (--text-2 of the day palette). */
:root[data-theme="light"] input[type="date"]::-webkit-calendar-picker-indicator,
:root[data-theme="light"] input[type="datetime-local"]::-webkit-calendar-picker-indicator,
:root[data-theme="light"] input[type="month"]::-webkit-calendar-picker-indicator,
:root[data-theme="light"] input[type="week"]::-webkit-calendar-picker-indicator {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18' fill='none' stroke='%234E4560' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='3.75' width='13' height='11.75' rx='2.5'/%3E%3Cpath d='M2.5 7.75h13M6 2v3.2M12 2v3.2'/%3E%3C/svg%3E");
    opacity: .75;
}
:root[data-theme="light"] input[type="time"]::-webkit-calendar-picker-indicator {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18' fill='none' stroke='%234E4560' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='9' r='6.5'/%3E%3Cpath d='M9 5.4V9l2.6 1.7'/%3E%3C/svg%3E");
    opacity: .75;
}
/* Keyboard users must be able to see the picker button they are on. */
input[type="date"]::-webkit-calendar-picker-indicator:focus-visible,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:focus-visible,
input[type="month"]::-webkit-calendar-picker-indicator:focus-visible,
input[type="time"]::-webkit-calendar-picker-indicator:focus-visible {
    opacity: 1; outline: 2px solid var(--acc-1); outline-offset: 1px;
}

/* ---- The date value itself ----
   Blink lays the field out as separate mm / dd / yyyy sub-fields. Left alone they
   inherit nothing useful, so the field sat a couple of pixels off from the select next
   to it and an empty field showed a washed-out placeholder. */
input[type="date"], input[type="datetime-local"], input[type="month"],
input[type="week"], input[type="time"] {
    /* Cancel the intrinsic sizing these types carry, so the shared .input width and
       min-height rules decide the box and nothing jumps when a value is picked. */
    min-width: 0; max-width: 100%;
    font-family: inherit; font-variant-numeric: tabular-nums;
}
input[type="date"]::-webkit-datetime-edit,
input[type="datetime-local"]::-webkit-datetime-edit,
input[type="month"]::-webkit-datetime-edit,
input[type="time"]::-webkit-datetime-edit { padding: 0; color: var(--text); }
input[type="date"]::-webkit-datetime-edit-fields-wrapper,
input[type="datetime-local"]::-webkit-datetime-edit-fields-wrapper,
input[type="month"]::-webkit-datetime-edit-fields-wrapper,
input[type="time"]::-webkit-datetime-edit-fields-wrapper { padding: 0; }
input[type="date"]::-webkit-datetime-edit-text,
input[type="datetime-local"]::-webkit-datetime-edit-text,
input[type="month"]::-webkit-datetime-edit-text { color: var(--text-3); padding: 0 1px; }
/* Blink paints the highlight of the focused sub-field with the UA accent; make it ours. */
input[type="date"]::-webkit-datetime-edit-day-field:focus,
input[type="date"]::-webkit-datetime-edit-month-field:focus,
input[type="date"]::-webkit-datetime-edit-year-field:focus,
input[type="datetime-local"]::-webkit-datetime-edit-day-field:focus,
input[type="datetime-local"]::-webkit-datetime-edit-month-field:focus,
input[type="datetime-local"]::-webkit-datetime-edit-year-field:focus,
input[type="month"]::-webkit-datetime-edit-month-field:focus,
input[type="month"]::-webkit-datetime-edit-year-field:focus,
input[type="time"]::-webkit-datetime-edit-hour-field:focus,
input[type="time"]::-webkit-datetime-edit-minute-field:focus,
input[type="time"]::-webkit-datetime-edit-ampm-field:focus {
    background: rgba(61,125,255,.28); color: var(--text); border-radius: 4px; outline: none;
}

/* ---- Numbers ----
   Money and percentage fields: tabular figures so the digits do not jitter while
   typing. The steppers keep their native geometry on purpose (an explicit height
   knocks them out of vertical alignment); color-scheme above is what gives them a
   light-on-dark / dark-on-light palette, so no filter is involved here either. */
input[type="number"] { font-variant-numeric: tabular-nums; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    opacity: .9; margin-left: 4px; cursor: pointer; filter: none;
}
input[type="number"]:hover::-webkit-inner-spin-button,
input[type="number"]:focus::-webkit-inner-spin-button { opacity: 1; }
/* On a touch screen the stepper arrows are far too small to hit and only steal room
   from the value, so the keypad is the input method there. */
@media (pointer: coarse) {
    input[type="number"]::-webkit-outer-spin-button,
    input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
    input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
}

/* ---- Install (PWA) button ----
   Hidden by default; ov-ui.js adds .show ONLY when the browser says the app is
   installable (beforeinstallprompt) and removes it on appinstalled. So the button
   never appears inside the already-installed app or in browsers that can't install. */
#ovInstall { display: none; }
#ovInstall.show { display: inline-flex; }

/* ---- Header logo sizing + spacing (never crowd the nav, incl. RU) ---- */
.cb-logo img { width: 38px !important; height: 38px !important; }
.cb-logo { font-size: 20px; gap: 10px; flex-shrink: 0; margin-right: 10px; }
.cb-nav-inner { gap: 30px; }
@media (max-width: 780px) { .cb-logo { font-size: 18px; margin-right: 4px; } .cb-logo img { width: 34px !important; height: 34px !important; } .cb-nav-inner { gap: 14px; } }
.cb-footer .cb-logo img { width: 28px !important; height: 28px !important; }

/* ---- Sticky workspace tabs (stay put while the page scrolls) ---- */
/* The tab strip pins directly beneath the navbar. Both offsets are derived from the
   SAME source of truth (--ov-nav-h) plus the status-bar inset, so they can never
   drift apart -- previously the 66px guess left a 2px slit on desktop and, in the
   installed PWA where the bar grows by the safe-area inset, the tabs hid behind it. */
:root { --ov-nav-h: 68px; }
@media (max-width: 640px) { :root { --ov-nav-h: 60px; } }
.ov-tabs { position: sticky; top: calc(var(--ov-nav-h) + env(safe-area-inset-top, 0px)); z-index: 50; padding: 12px 0; margin-bottom: 8px;
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    background: rgba(7,8,13,.72); border-bottom: 1px solid var(--line); }
:root[data-theme="light"] .ov-tabs { background: rgba(246,244,250,.82); }

/* Workspace tab bar: primary tabs sit in one horizontal band that fills a wider strip
   than the 1160px page content (uses the empty side space) and distributes evenly.
   Rarely-used tabs (HR + VA/marketer) live under a "More" menu so the row stays a
   single clean line. On small screens it wraps instead of clipping. */
.ov-tabs-inner { max-width: 1400px; margin: 0 auto; padding: 0 24px; }
/* Wrap (never overflow): on a wide screen the tabs grow to fill one distributed row;
   when they cannot all fit (narrow window, or longer Russian labels) they wrap to a
   second row instead of spilling into a page-level horizontal scrollbar. min-width:
   max-content stops any tab shrinking below its label, so text never clips. */
.ov-tabs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* min-width beats max-width in the CSS cascade of used values, so a bare
   min-width:max-content would let one long label push the strip past the window and
   defeat .btn{max-width:100%}. min() keeps the label intact whenever it fits and caps
   it at the row otherwise. */
.ov-tabs-row > .btn { flex: 1 1 auto; min-width: min(max-content, 100%); justify-content: center; white-space: nowrap; }
.ov-more { position: relative; flex: 0 0 auto; }
.ov-more > .btn { width: 100%; white-space: nowrap; }
@media (max-width: 1024px) {
    .ov-tabs-inner {
        padding-left: max(16px, env(safe-area-inset-left, 0px));
        padding-right: max(16px, env(safe-area-inset-right, 0px));
    }
    /* Anchor the "More" menu to the full-width row (not the small button) so it can
       never run off the left or right edge of a phone screen. */
    .ov-more { position: static; }
    .ov-tabs-row { position: relative; }
    #ov-more-menu { left: 0; right: 0; min-width: 0; }
}

/* -- Phones: ONE scrolling band, never a wrapping block --
   Wrapping put 9 tabs onto 4-5 stacked rows; combined with the navbar that froze
   ~43% of an iPhone SE screen as permanent chrome before any content showed. A
   single horizontally-scrollable row costs one row of height at any label length. */
@media (max-width: 780px) {
    .ov-tabs { padding: 8px 0; }
    .ov-tabs-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
        /* let the band bleed to the screen edges so it reads as scrollable */
        margin-left: calc(-1 * max(16px, env(safe-area-inset-left, 0px)));
        margin-right: calc(-1 * max(16px, env(safe-area-inset-right, 0px)));
        padding-left: max(16px, env(safe-area-inset-left, 0px));
        padding-right: max(16px, env(safe-area-inset-right, 0px));
    }
    .ov-tabs-row::-webkit-scrollbar { display: none; }
    .ov-tabs-row > .btn { flex: 0 0 auto; scroll-snap-align: start; }
    .ov-more { position: static; flex: 0 0 auto; }
    .ov-more > .btn { width: auto; }
}

/* ==================== FORM CARD POLISH ====================
   A row of fields laid out in .cb-grid-N used to look ragged because each label is a
   different number of lines ("Sale date" is one, "Amount received (what landed, after
   the platform fee)" is three), and the control simply followed its own label. Making
   each field a column and letting the LABEL absorb the slack bottom-aligns every
   control in the row, so the inputs read as one continuous band.
   The field's own bottom margin also goes: inside a grid the gap already provides the
   rhythm, and the margin was adding a dangling 18px under the last row. */
.cb-grid-2 > .field,
.cb-grid-3 > .field,
.cb-grid-4 > .field {
    display: flex; flex-direction: column; margin-bottom: 0; min-width: 0;
}
.cb-grid-2 > .field > label,
.cb-grid-3 > .field > label,
.cb-grid-4 > .field > label { flex: 1 1 auto; }
.field label { line-height: 1.45; }
/* The label's optional grey qualifier must not compete with the label itself. */
.field label .muted-3 { font-weight: 500; }

/* ---- Branded checkboxes (sales bulk select) ---- */
.js-sale-check, #selAllPending {
    appearance: none; -webkit-appearance: none; width: 18px; height: 18px; flex-shrink: 0;
    border: 1.5px solid var(--line-strong); border-radius: 5px; background: var(--bg-3);
    cursor: pointer; position: relative; vertical-align: middle; transition: border-color .15s, background .15s; }
.js-sale-check:hover, #selAllPending:hover { border-color: var(--acc-1); }
.js-sale-check:checked, #selAllPending:checked { background: var(--grad); border-color: transparent; }
.js-sale-check:checked::after, #selAllPending:checked::after {
    content: ""; position: absolute; left: 5px; top: 1.5px; width: 5px; height: 9px;
    border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }

/* ---- Accent color themes (user-selectable) ---- */
:root[data-accent="ocean"]   { --acc-1:#3D7DFF; --acc-2:#8A5CFF; --grad:linear-gradient(135deg,#3D7DFF 0%,#8A5CFF 100%); --grad-soft:linear-gradient(135deg,rgba(61,125,255,.14),rgba(138,92,255,.10)); }
:root[data-accent="sunset"]  { --acc-1:#FF7A45; --acc-2:#FF4D8D; --grad:linear-gradient(135deg,#FF8A4D 0%,#FF4D8D 100%); --grad-soft:linear-gradient(135deg,rgba(255,138,77,.14),rgba(255,77,141,.10)); }
:root[data-accent="emerald"] { --acc-1:#0FB981; --acc-2:#2CE5A7; --grad:linear-gradient(135deg,#0FB981 0%,#2CE5A7 100%); --grad-soft:linear-gradient(135deg,rgba(15,185,129,.14),rgba(44,229,167,.10)); }
:root[data-accent="royal"]   { --acc-1:#6A5CFF; --acc-2:#B44DFF; --grad:linear-gradient(135deg,#5B5BFF 0%,#B44DFF 100%); --grad-soft:linear-gradient(135deg,rgba(91,91,255,.14),rgba(180,77,255,.10)); }

/* accent picker (swatches in the user menu) */
.ov-accent { display: flex; align-items: center; gap: 8px; padding: 8px 10px 4px; }
.ov-accent .ov-sw { width: 22px; height: 22px; border-radius: 7px; cursor: pointer; border: 2px solid transparent; padding: 0; transition: transform .12s; }
.ov-accent .ov-sw:hover { transform: scale(1.12); }
.ov-accent .ov-sw.active { border-color: var(--text); }
.ov-sw[data-accent="vega"]    { background: linear-gradient(135deg,#7C5CFF,#FF4D8D); }
.ov-sw[data-accent="ocean"]   { background: linear-gradient(135deg,#3D7DFF,#8A5CFF); }
.ov-sw[data-accent="sunset"]  { background: linear-gradient(135deg,#FF8A4D,#FF4D8D); }
.ov-sw[data-accent="emerald"] { background: linear-gradient(135deg,#0FB981,#2CE5A7); }
.ov-sw[data-accent="royal"]   { background: linear-gradient(135deg,#5B5BFF,#B44DFF); }

/* =========================== LIGHT MODE: DAYTIME SKY + SUN =========================== */
/* Dark mode is a night sky with stars; day mode is a clean sky with a soft rising sun.
   The sky gradient lives on the ROOT element (not body) so it also fills the iOS
   safe-area, and so body can stay transparent -- body having a background would paint
   over the ambient .cb-glow / .cb-stars layers, which sit at negative z-index. */
:root[data-theme="light"] {
    background:
        radial-gradient(1200px 560px at 80% -10%, rgba(255,206,120,.50), rgba(255,206,120,0) 60%),  /* warm sun halo, top-right */
        radial-gradient(900px 620px at 8% 2%, rgba(124,92,255,.09), transparent 55%),                /* soft violet sky haze */
        radial-gradient(1000px 720px at 55% 118%, rgba(255,77,141,.05), transparent 60%),            /* faint pink low glow */
        linear-gradient(180deg, #E7F0FF 0%, #F1EEFB 42%, #FCF7FA 100%);                              /* sky: blue -> lavender -> warm white */
}
:root[data-theme="light"] .cb-glow { opacity: 1; }
/* the sun */
:root[data-theme="light"] .cb-glow::before {
    background: radial-gradient(circle at center, #FFF0C9 0%, #FFD983 42%, rgba(255,201,110,0) 72%);
    width: 360px; height: 360px; opacity: .95; filter: blur(26px);
    top: -80px; left: auto; right: 7%; animation: none;
}
/* soft brand haze balancing the lower-left */
:root[data-theme="light"] .cb-glow::after {
    background: #7C5CFF; opacity: .05; filter: blur(130px);
    width: 560px; height: 560px; top: 34%; left: -180px; right: auto;
}

/* Mobile nav dropdown ships a dark bg; give it a light surface on day mode.
   Scope to mobile ONLY -- on desktop .cb-nav-links is a transparent flex:1 row,
   so a background here would paint a huge white pill across the header. */
@media (max-width: 780px) {
    :root[data-theme="light"] .cb-nav-links.open { background: rgba(255,255,255,.98); border-bottom-color: var(--line); }
}

/* Surfaces authored with white overlays (for dark) vanish on light -> give them a faint ink tint. */
:root[data-theme="light"] .card-featured { background: linear-gradient(135deg, rgba(124,92,255,.09), rgba(255,77,141,.06)); border-color: rgba(124,92,255,.22); }
:root[data-theme="light"] .cb-table th { color: var(--text-3); }
:root[data-theme="light"] .chip { background: rgba(20,10,30,.04); }

/* The primary gradient stays vivid; ensure gradient text keeps contrast on light. */
:root[data-theme="light"] .grad-text { filter: saturate(1.05); }

/* Softer card shadow on light so cards read as lifted, not muddy. */
:root[data-theme="light"] .card { box-shadow: 0 1px 2px rgba(30,16,44,.04); }

/* =========================== CONFIRM MODAL =========================== */
.ov-overlay { position: fixed; inset: 0; z-index: 10001; display: flex; align-items: center; justify-content: center;
    padding: 20px; background: rgba(4,3,8,.62); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s; }
.ov-overlay.show { opacity: 1; visibility: visible; }
.ov-dialog { width: 100%; max-width: 424px; background: var(--bg-2); border: 1px solid var(--line-strong);
    border-radius: var(--r-md); box-shadow: var(--shadow); padding: 24px 24px 20px;
    transform: translateY(10px) scale(.98); transition: transform .18s ease;
    /* A long confirm message must scroll inside the dialog rather than run off a
       short (or landscape) phone screen with the buttons out of reach. */
    max-height: calc(100dvh - 40px); overflow-y: auto; overscroll-behavior: contain; }
@media (max-width: 480px) { .ov-dialog .ov-d-actions { flex-direction: column-reverse; } .ov-dialog .ov-d-actions .btn { width: 100%; } }
.ov-overlay.show .ov-dialog { transform: none; }
.ov-dialog .ov-d-icon { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
    font-size: 18px; margin-bottom: 14px; background: var(--grad-soft); color: #A78BFF; }
.ov-dialog.danger .ov-d-icon { background: rgba(255,92,92,.13); color: var(--bad); }
.ov-dialog .ov-d-title { font-family: var(--font-display); font-weight: 700; font-size: 17px; letter-spacing: -.2px; margin-bottom: 6px; color: var(--text); }
.ov-dialog .ov-d-msg { color: var(--text-2); font-size: 14px; line-height: 1.6; }
.ov-dialog .ov-d-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }

/* =========================== USER / DROPDOWN MENU =========================== */
.ov-userwrap { position: relative; }
.ov-usertrigger { display: flex; align-items: center; gap: 9px; background: none; border: 0; cursor: pointer;
    padding: 5px 8px; border-radius: 10px; color: var(--text); font-family: inherit; transition: background .15s; }
.ov-usertrigger:hover { background: var(--card); }
.ov-menu { position: absolute; top: calc(100% + 8px); right: 0; min-width: 226px; z-index: 200;
    background: var(--bg-2); border: 1px solid var(--line-strong); border-radius: var(--r-md); box-shadow: var(--shadow);
    padding: 6px; opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity .16s ease, transform .16s ease, visibility .16s;
    /* Never taller than what is left below the bar -- in landscape the menu used to
       run off the bottom and "Sign out" was unreachable. */
    max-height: calc(100dvh - var(--ov-nav-h, 68px) - env(safe-area-inset-top, 0px) - 24px);
    overflow-y: auto; overscroll-behavior: contain;
    max-width: calc(100vw - 24px); }
/* The accent swatch row must wrap rather than widen the menu (RU labels are longer). */
.ov-accent { flex-wrap: wrap; }
.ov-menu.open { opacity: 1; visibility: visible; transform: none; }
.ov-menu-head { padding: 8px 10px 11px; border-bottom: 1px solid var(--line); margin-bottom: 6px; }
.ov-menu a { display: flex; align-items: center; gap: 11px; padding: 9px 10px; border-radius: 8px;
    font-size: 13.5px; font-weight: 500; color: var(--text-2); }
.ov-menu a:hover { background: var(--card-hover); color: var(--text); }
.ov-menu a i { width: 16px; text-align: center; color: var(--text-3); font-size: 13px; }
.ov-menu a:hover i { color: var(--acc-1); }
.ov-menu-sep { height: 1px; background: var(--line); margin: 6px 4px; }
.ov-menu a.ov-menu-danger, .ov-menu a.ov-menu-danger i { color: var(--bad); }
.ov-menu a.ov-menu-danger:hover { background: rgba(255,92,92,.10); }

/* =========================== BULK ACTION BAR (sales) ===========================
   It must pin BELOW the navbar and the sticky tab strip, and paint ABOVE the tabs.
   With top:10px / z-index:40 it slid underneath both and the Approve/Reject buttons
   became invisible and untappable the moment the list was scrolled. */
.ov-bulkbar { position: sticky; z-index: 55; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    top: calc(var(--ov-nav-h, 68px) + env(safe-area-inset-top, 0px) + 68px);
    padding: 10px 14px; margin-bottom: 12px; border-radius: var(--r-sm);
    background: var(--bg-2); border: 1px solid rgba(124,92,255,.35); box-shadow: var(--shadow); }
.ov-bulkbar .ov-bulk-count { font-weight: 700; }
.js-sale-check { width: 16px; height: 16px; cursor: pointer; accent-color: #7C5CFF; }
.sale-row.is-updating { opacity: .5; transition: opacity .2s; }

/* ---------- Web push invite card ---------- */
.ov-push-card {
    position: fixed; right: 18px; bottom: 84px; z-index: 320;
    display: flex; gap: 12px; align-items: flex-start;
    max-width: 340px; padding: 16px;
    background: var(--card, #1A1916); border: 1px solid var(--line, #2A2823);
    border-radius: 14px; box-shadow: 0 18px 48px rgba(0,0,0,.45);
    opacity: 0; transform: translateY(14px); transition: opacity .3s, transform .3s;
}
.ov-push-card.show { opacity: 1; transform: translateY(0); }
.ov-push-ico {
    flex: 0 0 auto; width: 38px; height: 38px; border-radius: 11px;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--acc-1, #3D7DFF) 16%, transparent);
    color: var(--acc-1, #3D7DFF); font-size: 15px;
}
.ov-push-txt { min-width: 0; }
.ov-push-txt strong { display: block; font-size: 14px; margin-bottom: 3px; color: var(--text, #EDEAE2); }
.ov-push-txt span { display: block; font-size: 12px; line-height: 1.45; color: var(--text-3, #8B877D); }
.ov-push-btns { display: flex; flex-direction: column; gap: 6px; flex: 0 0 auto; }
@media (max-width: 560px) {
    .ov-push-card { left: 14px; right: 14px; bottom: 90px; max-width: none; flex-wrap: wrap; }
    .ov-push-btns { flex-direction: row; width: 100%; justify-content: flex-end; }
}
