SyncMadeEasy/force-app/main/default/lwc/shopifySyncDashboard/shopifySyncDashboard.css

2980 lines
62 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* =========================================================================
* Shopify Sync Dashboard — Lime-olive palette
* primary brand #95BE45 hsl(80, 48%, 51%) — vibrant olive/lime
* sidebar #6E8E27 → #7DA02C (darker derivatives, keeps white text legible)
* sidebar active #95BE45 — primary brand pops against the darker sidebar
* brand #95BE45 — primary buttons, accents, active states
* brand hover #7CA02E — darker derivative for primary:hover
* accents blue/yellow/purple/cyan/red for KPI cards
* fonts Inter, Montserrat
* ====================================================================== */
:host {
--sidebar-bg: #6E8E27;
/* matches the SME Settings page sidebar */
--sidebar-bg-2: #7DA02C;
/* matches the SME Settings page sidebar gradient bottom */
--sidebar-active-bg: #95BE45;
/* PRIMARY BRAND — pops on the darker sidebar */
--sidebar-text: #ffffff;
--sidebar-muted: rgba(255, 255, 255, 0.78);
--brand-green: #95BE45;
/* PRIMARY BRAND — buttons, accents, active states */
--brand-green-dark: #7CA02E;
/* darker derivative for primary:hover */
--brand-gradient: linear-gradient(125deg, #5fa832 0%, #3f9a86 55%, #2f8fb0 100%);
/* Accent gradient used in place of solid green for backgrounds */
--brand-gradient-solid: #3f9a86;
/* Flat fallback for text-color/border-color spots where a gradient value isn't valid CSS */
--shopify-green: #95BF47;
/* Shopify brand — DO NOT change */
--salesforce-blue: #00A1E0;
/* Salesforce brand — DO NOT change */
--page-bg: #f4f4f2;
--card-bg: #ffffff;
--card-bg-2: #fbfbfa;
--text-1: #1f2937;
--text-2: #4b5563;
--text-3: #9ca3af;
--border: #e5e7eb;
--border-strong: #d1d5db;
--row-hover: #f6f7f5;
--kpi-blue: #3b7ec4;
--kpi-green: #7CA02E;
--kpi-yellow: #b8932f;
--kpi-purple: #7c5cbf;
--kpi-cyan: #2f8f7f;
--kpi-red: #c14f4f;
--up-color: #16a34a;
--down-color: #dc2626;
--shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 3px rgba(16, 24, 40, 0.04);
--scrollbar-track: #edf2e8;
--scrollbar-thumb: #a2a2a2;
--scrollbar-thumb-hover: #a2a2a2;
--sidebar-scrollbar-track: rgba(255, 255, 255, 0.10);
--sidebar-scrollbar-thumb: rgba(255, 255, 255, 0.36);
--sidebar-scrollbar-thumb-hover: rgba(255, 255, 255, 0.56);
display: block;
background: var(--page-bg);
color: var(--text-1);
font-family: 'Inter', 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
font-size: 13px;
}
/* ---- DARK THEME (tuned for contrast + brand visibility) ---- */
.app.dark {
--sidebar-bg: #4F671C;
/* darker olive base for dark mode */
--sidebar-bg-2: #3A4C14;
/* even darker gradient bottom */
--sidebar-active-bg: #95BE45;
/* brand pops brightly against dark olive */
--sidebar-text: #f0f3eb;
--sidebar-muted: rgba(240, 243, 235, 0.7);
--page-bg: #14191b;
--card-bg: #1c2226;
--card-bg-2: #232a2e;
--text-1: #f0f3eb;
--text-2: #d4d8ce;
--text-3: #9aa295;
--border: #2d343a;
--border-strong: #3d454c;
--row-hover: #232a2e;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.35);
--scrollbar-track: #111719;
--scrollbar-thumb: #a2a2a2;
--scrollbar-thumb-hover: #a2a2a2;
--sidebar-scrollbar-track: rgba(255, 255, 255, 0.08);
--sidebar-scrollbar-thumb: rgba(255, 255, 255, 0.30);
--sidebar-scrollbar-thumb-hover: rgba(255, 255, 255, 0.48);
}
/* Dark mode overrides for SVG elements that use hardcoded presentation attributes */
.app.dark .svg-line text,
.app.dark .svg-bar text {
fill: var(--text-2);
}
.app.dark .record-detail-id-row .record-detail-label,
.app.dark .record-detail-field .record-detail-label,
.app.dark .record-detail-id-row .record-detail-value,
.app.dark .record-detail-field .record-detail-value {
color: #ffffff !important;
}
.app.dark .svg-line line,
.app.dark .svg-bar line {
stroke: var(--border-strong);
}
.app.dark .svg-donut circle:first-child {
stroke: var(--border-strong);
}
/* ============== Theme-aware scrollbars ============== */
.main,
.store-menu,
.field-list,
.kpi-row,
.dash-row,
.table-scroll,
.record-detail-body,
.modal-card.schedule-card,
.menu.sort-menu,
.menu.filter-menu {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.obj-list,
.sync-health-stores {
scrollbar-width: thin;
scrollbar-color: var(--sidebar-scrollbar-thumb) var(--sidebar-scrollbar-track);
}
.main::-webkit-scrollbar,
.store-menu::-webkit-scrollbar,
.field-list::-webkit-scrollbar,
.kpi-row::-webkit-scrollbar,
.dash-row::-webkit-scrollbar,
.table-scroll::-webkit-scrollbar,
.record-detail-body::-webkit-scrollbar,
.modal-card.schedule-card::-webkit-scrollbar,
.menu.sort-menu::-webkit-scrollbar,
.menu.filter-menu::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.main::-webkit-scrollbar-track,
.store-menu::-webkit-scrollbar-track,
.field-list::-webkit-scrollbar-track,
.kpi-row::-webkit-scrollbar-track,
.dash-row::-webkit-scrollbar-track,
.table-scroll::-webkit-scrollbar-track,
.record-detail-body::-webkit-scrollbar-track,
.modal-card.schedule-card::-webkit-scrollbar-track,
.menu.sort-menu::-webkit-scrollbar-track,
.menu.filter-menu::-webkit-scrollbar-track {
background: var(--scrollbar-track);
border-radius: 999px;
}
.main::-webkit-scrollbar-thumb,
.store-menu::-webkit-scrollbar-thumb,
.field-list::-webkit-scrollbar-thumb,
.kpi-row::-webkit-scrollbar-thumb,
.dash-row::-webkit-scrollbar-thumb,
.table-scroll::-webkit-scrollbar-thumb,
.record-detail-body::-webkit-scrollbar-thumb,
.modal-card.schedule-card::-webkit-scrollbar-thumb,
.menu.sort-menu::-webkit-scrollbar-thumb,
.menu.filter-menu::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb);
border: 2px solid var(--scrollbar-track);
border-radius: 999px;
}
.main::-webkit-scrollbar-thumb:hover,
.store-menu::-webkit-scrollbar-thumb:hover,
.field-list::-webkit-scrollbar-thumb:hover,
.kpi-row::-webkit-scrollbar-thumb:hover,
.dash-row::-webkit-scrollbar-thumb:hover,
.table-scroll::-webkit-scrollbar-thumb:hover,
.record-detail-body::-webkit-scrollbar-thumb:hover,
.modal-card.schedule-card::-webkit-scrollbar-thumb:hover,
.menu.sort-menu::-webkit-scrollbar-thumb:hover,
.menu.filter-menu::-webkit-scrollbar-thumb:hover {
background-color: var(--scrollbar-thumb-hover);
}
.obj-list::-webkit-scrollbar,
.sync-health-stores::-webkit-scrollbar {
width: 8px;
}
.obj-list::-webkit-scrollbar-track,
.sync-health-stores::-webkit-scrollbar-track {
background: var(--sidebar-scrollbar-track);
border-radius: 999px;
}
.obj-list::-webkit-scrollbar-thumb,
.sync-health-stores::-webkit-scrollbar-thumb {
background-color: var(--sidebar-scrollbar-thumb);
border: 2px solid transparent;
background-clip: padding-box;
border-radius: 999px;
}
.obj-list::-webkit-scrollbar-thumb:hover,
.sync-health-stores::-webkit-scrollbar-thumb:hover {
background-color: var(--sidebar-scrollbar-thumb-hover);
}
/* ============== Toasts ============== */
.toast-container {
position: fixed;
top: 16px;
left: 50%;
transform: translateX(-50%);
z-index: 2000;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
width: 100%;
max-width: 360px;
}
.toast {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 14px;
border-radius: 8px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
color: #fff;
width: 100%;
box-sizing: border-box;
animation: toast-in 180ms ease;
}
@keyframes toast-in {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.toast-icon {
flex-shrink: 0;
font-size: 14px;
line-height: 1.3;
}
.toast-body {
flex: 1;
min-width: 0;
}
.toast-title {
font-weight: 700;
font-size: 12.5px;
line-height: 1.3;
}
.toast-message {
font-size: 12px;
line-height: 1.35;
opacity: 0.95;
margin-top: 2px;
word-break: break-word;
}
.toast-close {
flex-shrink: 0;
background: transparent;
border: none;
color: inherit;
opacity: 0.8;
cursor: pointer;
font-size: 16px;
line-height: 1;
padding: 0;
}
.toast-close:hover {
opacity: 1;
}
.toast-success {
background: var(--brand-gradient);
}
.toast-error {
background: #dc2626;
}
.toast-warning {
background: #f59e0b;
color: #1f2937;
}
.toast-info {
background: #3b7ec4;
}
/* ============== Layout ============== */
.app {
display: grid;
grid-template-columns: 250px 1fr;
/* Pin to the viewport and scroll .main internally — at 100% zoom the
content used to extend past the visible area with no scrollbar. */
height: 100vh;
max-height: 100vh;
min-height: 0;
overflow: hidden;
background: var(--page-bg);
transition: background 200ms ease;
}
/* When any modal is open, lock the dashboard's overflow so the underlying
content doesn't scroll behind the backdrop. */
.app.modal-open {
height: 100vh;
overflow: hidden;
}
.app.modal-open .main {
overflow: hidden;
}
/* ============== Refresh banner ============== */
.refresh-banner {
grid-column: 1 / -1;
background: var(--brand-gradient);
color: #fff;
padding: 10px 18px;
display: flex;
align-items: center;
gap: 12px;
font-size: 12.5px;
font-weight: 600;
}
.refresh-banner.blinking .dot-blink {
animation: blink 0.9s ease-in-out infinite;
}
.refresh-banner.done {
background: var(--brand-gradient);
}
.dot-blink {
width: 10px;
height: 10px;
border-radius: 50%;
background: #fff;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.25;
}
}
.banner-text {
flex: 0 0 auto;
}
.banner-progress-track {
flex: 1;
height: 4px;
background: rgba(255, 255, 255, 0.25);
border-radius: 2px;
overflow: hidden;
}
.banner-progress-bar {
height: 100%;
background: #fff;
transition: width 200ms ease;
}
/* ============== Sidebar ============== */
.sidebar {
background: var(--brand-gradient);
color: var(--sidebar-text);
padding: 16px 0;
display: flex;
flex-direction: column;
min-height: 0;
/* .obj-list scrolls internally within the fixed sidebar */
overflow: hidden;
}
.brand {
display: flex;
align-items: center;
gap: 10px;
padding: 4px 12px 16px;
}
.brand-logo {
width: 38px;
height: 38px;
display: grid;
place-items: center;
flex-shrink: 0;
}
.brand-logo-img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
.brand-text {
min-width: 0;
flex: 1;
}
.brand-text .t1 {
font-size: 18px;
font-weight: 700;
line-height: 1.1;
letter-spacing: -0.2px;
}
.brand-text .t1 .italic {
font-style: italic;
font-weight: 500;
opacity: 0.92;
}
.brand-text .t2 {
font-size: 8.5px;
opacity: 0.88;
letter-spacing: -0.1px;
margin-top: 3px;
line-height: 1.2;
display: flex;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.store-selector {
position: relative;
margin: 0 12px 14px;
padding: 10px 12px;
background: rgba(255, 255, 255, 0.10);
border-radius: 8px;
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
.store-selector .store-icon {
width: 30px;
height: 30px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.18);
display: grid;
place-items: center;
color: var(--sidebar-text);
}
.store-selector .meta {
min-width: 0;
line-height: 1.2;
}
.store-selector .meta .l1 {
font-weight: 600;
font-size: 13px;
}
.store-selector .meta .l2 {
font-size: 10.5px;
opacity: 0.85;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.store-selector .caret {
margin-left: auto;
opacity: 0.8;
}
.store-menu {
position: absolute;
top: calc(100% + 6px);
left: 0;
right: 0;
background: var(--card-bg);
color: var(--text-1);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: var(--shadow);
padding: 6px;
z-index: 50;
display: none;
max-height: 260px;
overflow-y: auto;
}
.store-menu.open {
display: block;
}
.store-menu-row {
display: grid;
grid-template-columns: 8px 1fr auto;
gap: 8px;
padding: 8px 10px;
border-radius: 6px;
align-items: center;
cursor: pointer;
}
.store-menu-row:hover {
background: var(--row-hover);
}
.store-menu-row.selected {
background: rgba(47, 158, 68, 0.10);
}
.store-menu-row .store-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--brand-gradient);
}
.store-menu-row .store-name {
font-weight: 600;
font-size: 12.5px;
}
.store-menu-row .store-domain {
font-size: 11px;
color: var(--text-3);
}
.store-menu-row .store-status {
color: var(--brand-gradient-solid);
font-size: 12px;
font-weight: 700;
}
.nav-label {
font-size: 10.5px;
letter-spacing: 1px;
opacity: 0.75;
padding: 8px 16px 6px;
}
.obj-list {
display: flex;
flex-direction: column;
gap: 2px;
padding: 0 8px;
overflow-y: auto;
flex: 1 1 auto;
min-height: 0;
/* required for flex:1 + overflow:auto to behave correctly */
}
.obj-item {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 4px;
padding: 8px 10px;
border-radius: 8px;
cursor: pointer;
color: var(--sidebar-text);
/* Subtle card style so each row reads as a distinct box */
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.10);
transition: background 100ms ease, border-color 100ms ease;
}
.obj-item:hover {
background: rgba(255, 255, 255, 0.14);
border-color: rgba(255, 255, 255, 0.22);
}
.obj-item.active {
background: var(--brand-gradient);
color: var(--sidebar-text);
border-color: rgba(255, 255, 255, 0.32);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
}
.obj-item.active::before {
content: "";
position: absolute;
left: -8px;
top: 6px;
bottom: 6px;
width: 3px;
border-radius: 3px;
background: #fff;
}
.obj-text {
min-width: 0;
display: flex;
align-items: center;
gap: 6px;
}
.obj-icon {
flex-shrink: 0;
display: inline-grid;
place-items: center;
width: 18px;
height: 18px;
--sds-c-icon-color-foreground-default: var(--sidebar-text);
--sds-c-icon-color-foreground: var(--sidebar-text);
}
.obj-name {
font-weight: 600;
font-size: 13px;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
/* Counts — two pills stacked vertically. Each pill: [logo + name stack] [count].
Sizes tuned for visual balance with the object icon + name on the left side. */
.counts {
display: flex;
flex-direction: column;
gap: 5px;
align-items: stretch;
color: var(--sidebar-text);
}
.count-pill {
display: grid;
grid-template-columns: 42px auto;
/* narrower logo-stack column */
align-items: center;
gap: 6px;
/* tighter logo→count gap */
padding: 0;
background: transparent;
border: none;
border-radius: 0;
font-variant-numeric: tabular-nums;
}
.obj-item.active .count-pill {
background: transparent;
color: var(--sidebar-text);
}
.logo-stack {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 2px;
line-height: 1;
}
.logo {
display: inline-grid;
place-items: center;
width: 18px;
height: 18px;
background: transparent;
border-radius: 0;
}
.logo svg {
width: 18px;
height: 18px;
}
.logo-name {
font-size: 8.5px;
font-weight: 500;
letter-spacing: 0.1px;
opacity: 0.9;
line-height: 1.1;
text-transform: none;
}
.count-val {
font-weight: 700;
font-size: 15px;
line-height: 1;
text-align: right;
font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
letter-spacing: -0.2px;
min-width: 32px;
/* room for 4-5 digit counts */
white-space: nowrap;
}
/* Shopify logo brand color #95BF47 visually collides with the active row
background #95BE45 (basically the same green) — switch the SVG fill to
white when the row is active so the logo stays recognizable.
CSS `fill` overrides the inline `fill` attribute on the SVG path. */
.obj-item.active .logo-shopify svg path {
fill: #ffffff;
}
/* ---- Sync Health panel (sidebar between object list and footer) ---- */
.sync-health {
margin: 12px 12px 0;
padding: 10px 12px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: var(--sidebar-text);
font-size: 11px;
display: flex;
flex-direction: column;
gap: 8px;
}
.sync-health-title {
font-size: 9.5px;
font-weight: 700;
letter-spacing: 1px;
opacity: 0.6;
flex-shrink: 0;
}
/* Stores list — show 2 at a time, then scroll. Each store row is
~31px (label row + last-order subtitle) plus ~14px separator/gap between
rows, so 2 rows ≈ 80px. */
.sync-health-stores {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 80px;
overflow-y: auto;
padding-right: 2px;
}
.sync-health-store {
display: flex;
flex-direction: column;
gap: 2px;
flex-shrink: 0;
}
.sync-health-store+.sync-health-store {
padding-top: 6px;
border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.sync-health-row {
display: flex;
align-items: center;
gap: 6px;
line-height: 1.3;
}
.sync-health-label {
flex: 1;
font-weight: 600;
font-size: 11.5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.sync-health-value {
font-weight: 600;
font-size: 10.5px;
opacity: 0.92;
}
.sync-health-last {
padding-left: 14px;
font-size: 9.5px;
opacity: 0.65;
letter-spacing: 0.1px;
line-height: 1.3;
}
.health-dot {
flex-shrink: 0;
width: 8px;
height: 8px;
border-radius: 50%;
}
.health-dot.health-ok {
background: #4ade80;
box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.25);
}
.health-dot.health-err {
background: #ef4444;
box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.25);
}
.sidebar-footer {
margin-top: 10px;
padding: 12px 14px;
text-align: center;
font-size: 10px;
line-height: 1.4;
color: rgba(255, 255, 255, 0.78);
border-top: 1px solid rgba(255, 255, 255, 0.08);
letter-spacing: 0.1px;
}
.sidebar-footer a {
color: rgba(255, 255, 255, 0.95);
text-decoration: none;
font-weight: 600;
}
.sidebar-footer a:hover {
text-decoration: underline;
}
.footer-heart {
color: #ef4444;
font-size: 11px;
vertical-align: -1px;
margin: 0 1px;
}
/* ============== Main column ============== */
.main {
display: flex;
flex-direction: column;
min-width: 0;
min-height: 0;
overflow-y: auto;
/* internal scroll — the whole page is now reachable */
}
.topbar {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
background: var(--card-bg);
border-bottom: 1px solid var(--border);
flex-wrap: wrap;
row-gap: 8px;
}
.topbar-filters {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
min-width: 0;
flex: 1 1 auto;
}
.topbar-actions {
margin-left: auto;
display: flex;
gap: 6px;
align-items: center;
flex: 0 0 auto;
}
/* Force Refresh — subtle amber warning style so it reads as "use when needed" */
.btn.btn-force {
background: #fff8eb;
border-color: #f59e0b;
color: #b45309;
}
.btn.btn-force:hover {
background: #fef3c7;
border-color: #d97706;
color: #92400e;
}
.app.dark .btn.btn-force {
background: rgba(245, 158, 11, 0.15);
border-color: #b45309;
color: #fbbf24;
}
.btn {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 6px 10px;
border-radius: 6px;
border: 1px solid var(--border-strong);
background: var(--card-bg);
color: var(--text-1);
font-size: 12px;
cursor: pointer;
font-weight: 500;
font-family: inherit;
white-space: nowrap;
}
.btn:hover {
background: var(--row-hover);
}
.btn.primary {
background: var(--brand-gradient);
border-color: var(--brand-gradient-solid);
color: #fff;
}
.btn.primary:hover {
background: var(--brand-gradient);
border-color: var(--brand-gradient-solid);
}
.btn.small {
padding: 5px 10px;
font-size: 11.5px;
}
.icon-btn {
width: 30px;
height: 30px;
border-radius: 6px;
border: 1px solid var(--border-strong);
background: var(--card-bg);
color: var(--text-1);
cursor: pointer;
display: grid;
place-items: center;
}
.icon-btn:hover {
background: var(--row-hover);
}
.theme-icon {
font-size: 16px;
line-height: 1;
}
.menu-wrap {
position: relative;
}
.menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
min-width: 200px;
background: var(--card-bg);
color: var(--text-1);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: var(--shadow);
padding: 6px;
z-index: 100;
display: none;
}
.menu.open {
display: block;
}
.menu-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 6px;
font-size: 12.5px;
cursor: pointer;
}
.menu-item:hover {
background: var(--row-hover);
}
.menu-icon {
width: 18px;
display: inline-grid;
place-items: center;
}
.menu-sep {
height: 1px;
background: var(--border);
margin: 4px 0;
}
.menu-title {
padding: 8px 10px 4px;
font-size: 11px;
letter-spacing: 0.8px;
color: var(--text-1);
font-weight: 800;
text-transform: uppercase;
flex-shrink: 0;
}
/* Field selector menu */
.field-menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
width: 380px;
/* Triple-cap so the dropdown stays inside typical LWC card bounds:
1) hard ceiling 320px so it doesn't dwarf the card
2) 50vh so it never takes more than half the viewport
3) viewport - 200px to leave headroom for topbar + footer */
max-height: min(320px, 50vh, calc(100vh - 200px));
background: var(--card-bg);
color: var(--text-1);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: var(--shadow);
padding: 6px;
z-index: 100;
display: none;
/* Flex column lets the title + search pin to the top while only the
.field-list region inside scrolls. */
flex-direction: column;
min-height: 0;
}
.field-menu.open {
display: flex;
}
.field-search {
padding: 6px 8px 4px;
flex-shrink: 0;
}
.field-search input {
width: 100%;
padding: 6px 10px;
border: 1px solid var(--border-strong);
border-radius: 6px;
background: var(--card-bg);
color: var(--text-1);
font-size: 12.5px;
font-family: inherit;
box-sizing: border-box;
}
.field-search input:focus {
outline: none;
border-color: var(--brand-gradient-solid);
}
.field-list {
display: flex;
flex-direction: column;
gap: 2px;
/* Only this region scrolls — title + search stay pinned above */
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding-right: 2px;
/* small gap so scrollbar doesn't crowd content */
margin-top: 4px;
}
.field-row {
display: grid;
grid-template-columns: 22px 1fr auto;
gap: 8px;
padding: 6px 10px;
border-radius: 6px;
align-items: center;
user-select: none;
}
.field-row:hover {
background: var(--row-hover);
}
.field-row .check-box {
width: 18px;
height: 18px;
border-radius: 4px;
border: 1.5px solid var(--border-strong);
display: grid;
place-items: center;
font-size: 12px;
color: #fff;
background: var(--card-bg);
cursor: pointer;
}
.field-row.on .check-box {
background: var(--brand-gradient);
border-color: var(--brand-gradient-solid);
}
.field-meta {
min-width: 0;
line-height: 1.2;
}
.field-row .field-name {
font-weight: 600;
font-size: 12.5px;
}
.field-row .field-api {
font-size: 10.5px;
color: var(--text-3);
font-family: ui-monospace, monospace;
}
.field-reorder {
display: inline-flex;
flex-direction: column;
gap: 2px;
flex-shrink: 0;
}
.reorder-btn {
width: 24px;
height: 20px;
border: 1px solid var(--border-strong);
background: var(--card-bg);
color: var(--text-2);
font-size: 11px;
line-height: 1;
cursor: pointer;
border-radius: 4px;
padding: 0;
display: inline-grid;
place-items: center;
transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
}
.reorder-btn:hover:not([disabled]) {
background: rgba(47, 158, 68, 0.08);
color: var(--brand-gradient-solid);
border-color: var(--brand-gradient-solid);
}
.reorder-btn[disabled] {
opacity: 0.3;
cursor: not-allowed;
}
/* ============== Filter bar (legacy — kept selector, no longer rendered) ============== */
.filterbar {
display: none;
}
.filter-label {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 600;
color: var(--text-2);
padding-right: 10px;
margin-right: 4px;
border-right: 1px solid var(--border);
white-space: nowrap;
line-height: 1;
}
.filter-funnel {
color: var(--brand-gradient-solid);
flex-shrink: 0;
}
.filter-label-text {
letter-spacing: 0.2px;
}
.select {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 9px;
border: 1px solid var(--border-strong);
border-radius: 6px;
background: var(--card-bg);
font-size: 12px;
cursor: pointer;
min-width: 100px;
justify-content: space-between;
color: var(--text-1);
white-space: nowrap;
}
.select>span:first-child {
overflow: hidden;
text-overflow: ellipsis;
max-width: 130px;
}
.select .caret {
color: var(--text-3);
flex-shrink: 0;
}
/* sort-by no longer needs auto margin — placement is controlled by topbar-filters flex order */
.sort-by {
min-width: 110px;
}
/* ============== Content ============== */
.content {
padding: 18px 24px 24px;
display: flex;
flex-direction: column;
gap: 18px;
flex: 1;
}
.section-title {
font-size: 13.5px;
font-weight: 700;
color: var(--text-1);
text-transform: uppercase;
letter-spacing: 1px;
display: flex;
align-items: center;
gap: 12px;
}
.section-title .muted-tag {
font-weight: 500;
text-transform: none;
letter-spacing: 0;
font-size: 11px;
color: var(--text-3);
background: var(--card-bg-2);
border: 1px solid var(--border);
padding: 2px 8px;
border-radius: 999px;
font-family: ui-monospace, monospace;
}
.report-title-row .report-actions {
margin-left: auto;
}
/* ============== KPI Cards ============== */
/* 8 KPIs ALWAYS in a single row at every screen size.
minmax(0, 1fr) lets cards shrink rather than wrap; overflow-x scroll
kicks in only if the viewport is truly too narrow to fit all 8. */
.kpi-row {
display: grid;
grid-template-columns: repeat(8, minmax(0, 1fr));
gap: 8px;
overflow-x: auto;
padding-bottom: 4px;
/* room for the horizontal scrollbar without clipping shadows */
}
.kpi {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 12px 12px;
position: relative;
box-shadow: var(--shadow);
overflow: hidden;
min-width: 0;
}
.kpi::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 3px;
background: var(--accent, var(--kpi-blue));
}
.kpi.k-blue {
--accent: var(--kpi-blue);
}
.kpi.k-green {
--accent: var(--brand-gradient);
}
.kpi.k-yellow {
--accent: var(--kpi-yellow);
}
.kpi.k-purple {
--accent: var(--kpi-purple);
}
.kpi.k-cyan {
--accent: var(--kpi-cyan);
}
.kpi.k-red {
--accent: var(--kpi-red);
}
.kpi .label {
font-size: 9px;
letter-spacing: 0.6px;
color: var(--text-3);
font-weight: 600;
text-transform: uppercase;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.kpi .value {
font-size: 18px;
font-weight: 700;
margin-top: 4px;
color: var(--text-1);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.15;
}
.kpi .sub {
font-size: 10px;
color: var(--text-3);
margin-top: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.kpi .delta {
display: inline-flex;
align-items: center;
gap: 3px;
margin-top: 6px;
font-size: 10.5px;
font-weight: 600;
}
.kpi .delta.up {
color: var(--up-color);
}
.kpi .delta.down {
color: var(--down-color);
}
/* ============== Panels / Dashboards ============== */
.panel {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
min-width: 0;
}
/* Dashboard panels specifically — hide overflow so chart legends/labels
never escape the card. Report panel is separately allowed to scroll
its table horizontally via .table-scroll. */
.dash-panel {
overflow: hidden;
}
.panel-head {
display: flex;
align-items: center;
padding: 14px 16px 10px;
gap: 10px;
}
.panel-head .title {
font-size: 13.5px;
font-weight: 600;
color: var(--text-1);
}
/* Dashboards ALWAYS in a single row of 3 at every screen size. */
.dash-row {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
overflow-x: auto;
padding-bottom: 4px;
}
.dash-row.dash-single {
grid-template-columns: 1fr;
}
.dash-panel .chart-body {
padding: 6px 16px 18px;
min-height: 280px;
}
/* Hover targets on chart elements */
.svg-bar rect {
cursor: pointer;
}
.svg-bar rect:hover {
opacity: 0.85;
}
.hover-target {
cursor: pointer;
}
.svg-donut circle:not([stroke="#eef0ee"]) {
cursor: pointer;
}
.chip-group {
margin-left: auto;
display: inline-flex;
border: 1px solid var(--border-strong);
border-radius: 6px;
overflow: hidden;
}
.chip {
background: var(--card-bg);
border: none;
padding: 4px 8px;
cursor: pointer;
font-size: 13px;
color: var(--text-2);
font-family: inherit;
}
.chip:hover {
background: var(--row-hover);
}
.chip.on {
background: var(--brand-gradient);
color: #fff;
}
.svg-line,
.svg-bar {
width: 100%;
height: 280px;
display: block;
}
/* Flex (not grid) so the legend wraps BELOW the donut when the panel gets
narrow, instead of the legend column collapsing to ~0 width and clipping
the label text (which made chart/object names disappear). */
.donut-wrap {
display: flex;
flex-wrap: wrap;
gap: 14px 18px;
align-items: center;
justify-content: center;
min-width: 0;
}
.svg-donut {
width: 150px;
max-width: 150px;
height: 150px;
aspect-ratio: 1 / 1;
flex: 0 0 auto;
}
.legend {
display: flex;
flex-direction: column;
gap: 11px;
font-size: 13px;
flex: 1 1 140px;
min-width: 140px;
}
/* Legend label colour is explicit so it stays visible in dark mode too. */
.legend-name {
color: var(--text-1);
}
.legend-row {
display: grid;
grid-template-columns: 14px minmax(0, 1fr) auto;
align-items: center;
gap: 10px;
min-width: 0;
}
.legend .sw {
width: 13px;
height: 13px;
border-radius: 3px;
flex-shrink: 0;
}
.legend-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.legend-value {
color: var(--text-2);
font-weight: 700;
font-variant-numeric: tabular-nums;
flex-shrink: 0;
}
/* ============== Report ============== */
.report-panel {
padding: 0;
}
.table-scroll {
overflow-x: auto;
}
.report {
width: 100%;
border-collapse: collapse;
font-size: 12.5px;
}
.report th {
text-align: center;
font-weight: 700;
color: var(--text-1);
font-size: 11px;
letter-spacing: 0.6px;
padding: 11px 14px;
border-top: 1px solid var(--border);
border-bottom: 2px solid var(--border-strong);
background: var(--card-bg-2);
text-transform: uppercase;
cursor: pointer;
user-select: none;
white-space: nowrap;
}
.report th .sort-ind {
margin-left: 6px;
color: var(--text-3);
font-size: 11px;
}
.report th.sorted .sort-ind {
color: var(--brand-gradient-solid);
}
.report th:hover {
background: var(--row-hover);
}
/* ----- Drag-and-drop column reordering ----- */
.report th .col-grip {
display: inline-block;
opacity: 0;
color: var(--text-3);
font-size: 10px;
margin-right: 6px;
cursor: grab;
transition: opacity 100ms ease;
transform: rotate(90deg);
}
.report th:hover .col-grip {
opacity: 0.7;
}
.report th.col-dragging {
opacity: 0.4;
background: rgba(47, 158, 68, 0.10);
}
.report th[draggable="true"] {
cursor: pointer;
user-select: none;
}
.report th[draggable="true"]:active .col-grip {
cursor: grabbing;
}
/* ----- Pinned first column + clickable pin toggle ----- */
.report th.col-locked {
cursor: pointer;
}
/* When pinned, freeze the whole first column (header + every cell) so it stays
locked in place while the other columns scroll/reorder. Opaque backgrounds so
scrolled cells don't bleed through. */
.report.pinned-first th:first-child,
.report.pinned-first td:first-child {
position: sticky;
left: 0;
z-index: 2;
background: var(--card-bg);
box-shadow: 1px 0 0 var(--border);
/* subtle separator from the moving columns */
}
.report.pinned-first th:first-child {
z-index: 3;
/* header above body cells */
background: var(--card-bg-2);
}
.report.pinned-first tbody tr:hover td:first-child {
background: var(--row-hover);
}
.report th .col-pin {
display: inline-block;
margin-right: 6px;
font-size: 11px;
vertical-align: middle;
cursor: pointer;
opacity: 0.35;
/* dim = unpinned */
filter: grayscale(1);
transition: opacity 100ms ease, filter 100ms ease, transform 100ms ease;
user-select: none;
}
.report th .col-pin:hover {
opacity: 0.7;
transform: scale(1.15);
}
.report th .col-pin.on {
opacity: 1;
/* bright = pinned */
filter: none;
}
/* ----- "<Object> Record Details" title with info icon ----- */
.records-title {
display: inline-flex;
align-items: center;
gap: 8px;
}
.records-info {
display: inline-grid;
place-items: center;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--card-bg-2);
border: 1px solid var(--border);
color: var(--text-3);
font-size: 11px;
font-weight: 700;
font-style: normal;
cursor: pointer;
transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
}
.records-info:hover {
background: rgba(149, 190, 69, 0.12);
border-color: var(--brand-gradient-solid);
color: var(--brand-gradient-solid);
}
/* ----- Filter info modal styling ----- */
.modal-card.filter-info-card {
width: 480px;
}
.filter-info-list {
margin: 0;
padding: 0;
list-style: none;
}
.filter-info-row {
padding: 10px 12px;
margin-bottom: 6px;
background: var(--card-bg-2);
border: 1px solid var(--border);
border-radius: 6px;
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
font-size: 12.5px;
color: var(--text-1);
word-break: break-all;
}
.filter-info-row:last-child {
margin-bottom: 0;
}
.report td {
padding: 10px 14px;
border-bottom: 1px solid var(--border);
vertical-align: middle;
color: var(--text-1);
white-space: nowrap;
text-align: center;
}
.report tr:last-child td {
border-bottom: none;
}
.report tbody tr:hover {
background: var(--row-hover);
}
/* Clickable record cell — primary record + lookup record links.
Clicking opens the record-detail popup, NOT a direct navigation. */
.record-link {
color: #1f6feb;
text-decoration: none;
font-weight: 500;
cursor: pointer;
}
.record-link:hover {
text-decoration: underline;
color: #1453c0;
}
.record-link:focus {
outline: 2px solid rgba(31, 111, 235, 0.35);
outline-offset: 2px;
border-radius: 2px;
}
/* ============== Record Detail modal ============== */
.modal-card.record-detail-card {
width: 540px;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.record-detail-body {
overflow-y: auto;
padding-right: 4px;
flex: 1 1 auto;
min-height: 0;
}
.record-detail-field {
display: grid;
grid-template-columns: minmax(140px, 200px) 1fr;
gap: 12px;
align-items: start;
padding: 8px 7px;
border-bottom: 1px solid var(--border);
}
.record-detail-field:last-child {
border-bottom: none;
}
.record-detail-id-row {
background: var(--brand-gradient);
border: 1px solid var(--brand-gradient);;
border-radius: 6px;
padding: 10px 7px;
margin-bottom: 8px;
}
.record-detail-label {
font-size: 11px;
font-weight: 700;
color: #000000;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.record-detail-value {
font-size: 13px;
color: var(--text-1);
word-break: break-word;
}
.record-id-link {
color: #000000;
text-decoration: none;
font-weight: 600;
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
font-size: 12.5px;
}
.record-id-link:hover {
text-decoration: underline;
}
.record-detail-loading {
padding: 32px 16px;
text-align: center;
color: var(--text-3);
font-size: 13px;
font-style: italic;
}
.panel-footer {
display: flex;
align-items: center;
padding: 10px 16px;
border-top: 1px solid var(--border);
font-size: 11.5px;
color: var(--text-3);
}
.pager {
margin-left: auto;
display: flex;
align-items: center;
gap: 4px;
}
.pager .pg {
min-width: 26px;
height: 26px;
display: grid;
place-items: center;
border-radius: 5px;
cursor: pointer;
padding: 0 8px;
font-size: 12px;
color: var(--text-2);
}
.pager .pg:hover {
background: var(--brand-gradient);
}
.pager .pg.active {
background: var(--brand-gradient);
color: #fff;
font-weight: 600;
}
.pager .nav {
height: 26px;
padding: 0 10px;
display: grid;
place-items: center;
border-radius: 5px;
color: var(--text-2);
cursor: pointer;
font-size: 12px;
}
.pager .nav:hover {
background: var(--row-hover);
}
.footer-copy {
text-align: center;
font-size: 11.5px;
color: var(--text-3);
padding: 12px 0 18px;
}
.footer-copy a {
color: var(--text-2);
text-decoration: underline;
}
/* ============== Modals ============== */
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.45);
display: grid;
place-items: center;
backdrop-filter: blur(2px);
}
.modal-card {
position: relative;
background: var(--card-bg);
color: var(--text-1);
border-radius: 10px;
box-shadow: var(--shadow);
width: 380px;
padding: 22px 24px;
overflow: hidden;
}
.modal-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--brand-gradient);
}
.modal-card.share-card {
width: 480px;
}
.modal-title {
font-size: 16px;
font-weight: 700;
margin-bottom: 12px;
}
.modal-body {
font-size: 13px;
color: var(--text-2);
}
.modal-body p {
margin: 4px 0 8px;
}
.cooldown {
font-size: 22px;
font-weight: 700;
background: var(--brand-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-variant-numeric: tabular-nums;
margin-top: 6px;
letter-spacing: 1px;
}
.app.dark .cooldown {
color: var(--shopify-green);
}
.modal-actions {
margin-top: 16px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
/* Share tiles */
.share-format-pill {
display: inline-block;
font-size: 11.5px;
color: var(--text-2);
background: var(--card-bg-2);
border: 1px solid var(--border);
padding: 4px 10px;
border-radius: 999px;
margin-bottom: 12px;
}
.more-share-hint {
margin: 0 0 14px;
padding: 10px 12px;
background: rgba(149, 190, 69, 0.08);
border: 1px solid rgba(149, 190, 69, 0.30);
border-radius: 6px;
font-size: 11.5px;
line-height: 1.45;
color: var(--text-2);
}
.more-share-hint strong {
color: var(--brand-green-dark);
font-weight: 700;
}
.more-share-hint em {
color: var(--text-1);
font-style: normal;
font-weight: 600;
}
.share-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.share-tile {
background: var(--card-bg-2);
border: 1px solid var(--border);
border-radius: 8px;
padding: 14px 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
cursor: pointer;
transition: all 150ms ease;
}
.share-tile:hover {
background: var(--card-bg);
border-color: var(--brand-gradient-solid);
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(47, 158, 68, 0.18);
}
.share-tile-icon {
font-size: 22px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
}
.share-tile-icon svg {
display: block;
width: 40px;
height: 40px;
}
.share-tile-label {
font-size: 11.5px;
font-weight: 600;
color: var(--text-1);
}
/* ============== Schedule Report modal ============== */
.modal-card.schedule-card {
width: 480px;
max-height: 90vh;
}
.scrollbar-hidden{
max-height: 60vh;
overflow: scroll;
&::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for Firefox */
scrollbar-width: none;
/* Hide scrollbar for IE and Edge */
-ms-overflow-style: none;
}
.sched-form {
display: flex;
flex-direction: column;
gap: 12px;
}
.sched-row {
display: flex;
flex-direction: column;
gap: 4px;
}
.sched-label {
font-size: 11px;
letter-spacing: 0.5px;
font-weight: 600;
color: var(--text-2);
text-transform: uppercase;
}
.sched-input {
padding: 8px 10px;
border: 1px solid var(--border-strong);
border-radius: 6px;
background: var(--card-bg);
color: var(--text-1);
font-size: 13px;
font-family: inherit;
box-sizing: border-box;
width: 100%;
}
.sched-input:focus {
outline: none;
border-color: var(--brand-gradient-solid);
}
.sched-input.sched-input-readonly {
background: var(--card-bg-2);
color: var(--text-2);
cursor: default;
font-weight: 600;
}
.sched-input.sched-input-readonly:focus {
border-color: var(--border-strong);
}
.sched-textarea {
resize: vertical;
min-height: 48px;
}
/* Existing schedules list inside the Schedule Report modal */
.sched-existing {
margin-bottom: 16px;
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px 12px;
background: var(--row-hover);
}
.sched-existing-title {
font-size: 10.5px;
letter-spacing: 1px;
font-weight: 700;
color: var(--text-3);
margin-bottom: 4px;
}
.sched-existing-row {
display: flex;
align-items: center;
gap: 10px;
padding: 7px 0;
}
.sched-existing-row+.sched-existing-row {
border-top: 1px solid var(--border);
}
.sched-existing-meta {
flex: 1;
min-width: 0;
}
.sched-existing-name {
font-weight: 600;
font-size: 12.5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sched-existing-sub {
font-size: 11px;
color: var(--text-3);
}
.sched-delete-btn {
color: #dc2626;
flex-shrink: 0;
}
.sched-delete-btn:disabled {
opacity: 0.55;
cursor: default;
}
.sched-existing-loading {
font-size: 12px;
color: var(--text-3);
margin-bottom: 12px;
}
.sched-hint {
font-size: 11px;
color: var(--text-3);
margin-top: 2px;
}
.sched-error {
background: rgba(220, 38, 38, 0.08);
border: 1px solid rgba(220, 38, 38, 0.35);
color: var(--down-color);
font-size: 12px;
padding: 8px 10px;
border-radius: 6px;
}
.rcpt-summary {
font-size: 11.5px;
color: var(--text-3);
margin-top: 4px;
}
.rcpt-pills {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 6px;
}
.rcpt-pill {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 500;
line-height: 1.3;
}
.rcpt-pill.rcpt-valid {
background: rgba(47, 158, 68, 0.12);
color: var(--brand-gradient-solid);
border: 1px solid rgba(47, 158, 68, 0.35);
}
.rcpt-pill.rcpt-invalid {
background: rgba(220, 38, 38, 0.10);
color: var(--down-color);
border: 1px solid rgba(220, 38, 38, 0.35);
}
.rcpt-pill.rcpt-overlimit {
background: rgba(245, 158, 11, 0.10);
color: #b45309;
border: 1px dashed rgba(245, 158, 11, 0.55);
}
.app.dark .rcpt-pill.rcpt-overlimit {
background: rgba(245, 158, 11, 0.15);
color: #fbbf24;
}
.rcpt-icon {
font-size: 11px;
}
/* Inline secondary hint inside a label (used in the Recipients label) */
.sched-label-hint {
font-weight: 500;
font-size: 10px;
color: var(--text-3);
text-transform: none;
letter-spacing: 0;
margin-left: 4px;
}
/* ============== Filter / Sort dropdown sizing ============== */
.sort-by-wrap {
margin-left: auto;
}
.menu.sort-menu {
min-width: 240px;
max-height: 360px;
overflow-y: auto;
}
.menu.filter-menu {
min-width: 180px;
max-height: 320px;
overflow-y: auto;
}
.menu-item.active {
background: rgba(47, 158, 68, 0.12);
color: var(--brand-gradient-solid);
font-weight: 600;
}
/* ============== Responsive ============== */
/* Goal: filters + action buttons stay on ONE row at every typical laptop width.
We progressively shrink internal element padding/min-widths as the viewport
narrows — only at very small widths do we allow flex-wrap to break them. */
@media (max-width: 1440px) {
/* Common laptop (1366–1440px) — keep "Filter by" label, slightly tighter elements */
.topbar {
gap: 8px;
padding: 10px 14px;
}
.topbar-filters {
gap: 4px;
}
.topbar-actions {
gap: 4px;
}
.select {
min-width: 90px;
padding: 5px 8px;
font-size: 11.5px;
}
.select>span:first-child {
max-width: 110px;
}
.btn {
padding: 5px 9px;
font-size: 11.5px;
}
.filter-label {
font-size: 11.5px;
padding-right: 8px;
margin-right: 2px;
}
}
@media (max-width: 1280px) {
/* Topbar tighter — charts already at 2 cols by default */
.topbar {
gap: 6px;
padding: 9px 12px;
}
.topbar-filters {
gap: 3px;
}
.topbar-actions {
gap: 3px;
}
.select {
min-width: 80px;
padding: 4px 7px;
font-size: 11px;
}
.select>span:first-child {
max-width: 90px;
}
.btn {
padding: 5px 8px;
font-size: 11px;
gap: 4px;
}
.icon-btn {
width: 28px;
height: 28px;
}
}
@media (max-width: 1440px) {
/* Keep 8-col / 3-col single-row but slightly tighter type */
.kpi {
padding: 8px 10px 10px;
}
.kpi .value {
font-size: 16px;
}
.kpi .label {
font-size: 8.5px;
}
}
@media (max-width: 1280px) {
/* Same — single row enforced. Just shrink card type further. */
.kpi {
padding: 6px 8px 8px;
}
.kpi .value {
font-size: 14px;
}
.kpi .label {
font-size: 8px;
letter-spacing: 0.4px;
}
.kpi .sub {
font-size: 9px;
}
.kpi .delta {
font-size: 9.5px;
margin-top: 4px;
}
/* Give dashboard panels a min-width floor so charts/legends stay legible;
horizontal scroll engages instead of squishing them (which made the
donut legend collapse and chart layout break at ~100% on 1366px screens). */
.dash-row {
grid-template-columns: repeat(3, minmax(300px, 1fr));
}
/* Slightly smaller donut on tighter panels so it sits beside its legend. */
.svg-donut {
width: 130px;
max-width: 130px;
height: 130px;
}
.legend {
flex-basis: 130px;
min-width: 130px;
}
}
@media (max-width: 1100px) {
/* Topbar still single-row at this width — even tighter */
.select {
min-width: 72px;
max-width: 110px;
}
.select>span:first-child {
max-width: 78px;
}
.btn {
padding: 4px 7px;
font-size: 10.5px;
}
/* Below 1100px we drop the "Filter:" label to reclaim space */
.filter-label {
display: none;
}
/* KPIs keep single-row but each card needs a floor width to stay
legible — horizontal scroll handles overflow. */
.kpi-row {
grid-template-columns: repeat(8, minmax(110px, 1fr));
}
}
@media (max-width: 900px) {
.kpi-row {
grid-template-columns: repeat(8, minmax(100px, 1fr));
}
.dash-row {
grid-template-columns: repeat(3, minmax(320px, 1fr));
}
}
@media (max-width: 980px) {
/* Last stop before wrapping — drop verbose labels on action buttons */
.btn {
padding: 4px 6px;
font-size: 10.5px;
}
}
@media (max-width: 880px) {
/* Genuinely not enough horizontal room — allow filters block to wrap below actions */
.topbar-filters {
width: 100%;
flex-wrap: wrap;
}
.topbar-actions {
margin-left: 0;
width: 100%;
justify-content: flex-end;
}
.select {
flex: 0 0 auto;
min-width: 80px;
}
}
@media (max-width: 720px) {
.app {
grid-template-columns: 1fr;
}
.sidebar {
display: none;
}
/* Mobile keeps single-row enforcement — horizontal scroll handles
the narrow viewport. User scrolls left/right to see all cards/charts. */
.kpi-row {
grid-template-columns: repeat(8, minmax(96px, 1fr));
}
.dash-row {
grid-template-columns: repeat(3, minmax(300px, 1fr));
}
.share-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media print {
/* Force-hide ALL modal backdrops by selector, regardless of state */
.modal-backdrop,
[class*="modal-backdrop"] {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
position: absolute !important;
z-index: -9999 !important;
}
/* Hide the modal card itself if backdrop failed */
.modal-card,
.share-card,
.schedule-card,
.filter-info-card,
.record-detail-card {
display: none !important;
visibility: hidden !important;
}
/* Hide non-content elements (sidebar nav + store name kept for print) */
.topbar,
.footer-copy,
.refresh-banner,
.sync-health,
.sidebar-footer {
display: none !important;
}
/* Restructure layout for print — stack sidebar on top of main content */
.app,
.app.modal-open {
display: block !important;
height: auto !important;
max-height: none !important;
min-height: auto !important;
overflow: visible !important;
}
.main,
.app.modal-open .main {
overflow: visible !important;
height: auto !important;
min-height: auto !important;
}
/* ---- Sidebar: transformed into a top center header for print ---- */
.sidebar {
background: transparent !important;
color: #1f2937 !important;
padding: 10px 0 15px 0 !important;
overflow: visible !important;
height: auto !important;
min-height: 0 !important;
border-right: none !important;
border-bottom: 2px solid #c5d6a4 !important;
width: 100% !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
}
.brand {
display: none !important;
}
.store-selector {
display: flex !important;
background: transparent !important;
border: none !important;
margin: 0 auto 5px !important;
cursor: default !important;
justify-content: center !important;
align-items: center !important;
text-align: center !important;
padding: 0 !important;
}
.store-selector .store-icon {
display: none !important;
}
.store-selector .meta {
text-align: center !important;
}
.store-selector .meta .l1 {
color: #000 !important;
font-weight: 700 !important;
font-size: 18px !important;
}
.store-selector .meta .l2 {
display: none !important; /* Hide store domain URL for a cleaner print header */
}
.store-selector .caret,
.store-menu {
display: none !important;
}
.nav-label {
display: none !important; /* Hide the "OBJECTS" label in print */
}
.obj-list {
overflow: visible !important;
height: auto !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
margin-top: 5px !important;
}
/* Hide non-active navigation items from the print view completely */
.obj-item:not(.active) {
display: none !important;
}
/* Style the active object item to sit directly below the store name */
.obj-item.active {
background: transparent !important;
border: none !important;
color: #000 !important;
padding: 0 !important;
margin: 0 !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
box-shadow: none !important;
}
.obj-item.active::before {
display: none !important;
}
.obj-item.active .obj-text {
display: inline-flex !important;
align-items: center !important;
}
.obj-item.active .obj-icon {
display: none !important; /* Hide Salesforce icons in header */
}
.obj-item.active .obj-name {
color: #000 !important;
font-size: 14px !important;
font-weight: 700 !important;
}
.obj-item.active .obj-name::after {
content:" \2014" !important;
margin-left: 8px !important;
color: #9ca3af !important;
font-weight: normal !important;
}
.obj-item.active .counts {
display: inline-flex !important;
align-items: center !important;
gap: 8px !important;
}
.obj-item.active .count-pill {
background: transparent !important;
border: none !important;
padding: 0 !important;
font-size: 13px !important;
color: #374151 !important;
display: inline-flex !important;
align-items: center !important;
gap: 4px !important;
}
.obj-item.active .count-pill .logo-stack {
display: inline-flex !important;
align-items: center !important;
gap: 2px !important;
}
.obj-item.active .count-pill .logo {
display: none !important; /* Hide SVGs for a clean inline look */
}
.obj-item.active .count-pill .logo-name {
display: inline !important;
font-size: 13px !important;
font-weight: 600 !important;
color: #4b5563 !important;
}
.obj-item.active .count-pill .logo-name::after {
content: ":" !important;
}
.obj-item.active .count-pill .count-val {
font-size: 13px !important;
font-weight: 700 !important;
color: #000 !important;
}
/* Add a clean separator between Shopify and Salesforce counts if both exist */
.obj-item.active .count-pill + .count-pill::before {
content: "\2014 " !important;
margin-right: 8px !important;
color: #9ca3af !important;
font-weight: normal !important;
}
.content {
padding: 0 !important;
gap: 16px !important;
}
/* Ensure panels print cleanly */
.panel,
.kpi,
.dash-panel {
break-inside: avoid !important;
page-break-inside: avoid !important;
box-shadow: none !important;
border: 1px solid #ddd !important;
}
/* KPI row: keep horizontal but allow natural sizing */
.kpi-row {
display: grid !important;
grid-template-columns: repeat(8, 1fr) !important;
gap: 8px !important;
overflow: visible !important;
}
/* Dashboards: stack vertically for print */
.dash-row {
display: flex !important;
flex-direction: column !important;
gap: 16px !important;
overflow: visible !important;
}
.dash-row.dash-single {
display: block !important;
}
@page {
size: landscape;
margin: 10mm;
}
.report-panel {
zoom: 0.85 !important;
}
/* Report table: un-scroll and fit */
.table-scroll {
overflow: visible !important;
}
.section-title,
.panel-head .title {
font-size: 15px !important;
}
.kpi .label {
font-size: 11px !important;
}
.kpi .value {
font-size: 20px !important;
}
.kpi .sub,
.kpi .delta {
font-size: 11px !important;
}
.report {
font-size: 11.5px !important;
width: 100% !important;
}
.report th {
font-size: 11px !important;
}
.report th,
.report td {
padding: 5px 8px !important;
white-space: normal !important;
word-break: break-word !important;
}
/* Hide interactive chrome */
.chip-group,
.report-actions,
.panel-footer,
.pager,
.records-info,
.col-grip,
.col-pin,
.reorder-btn,
.hidden-download-anchor {
display: none !important;
}
/* Force background colors */
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
color-adjust: exact !important;
}
/* SVG sizing for print */
.svg-line,
.svg-bar {
height: 180px !important;
max-height: 200px !important;
}
/* Ensure text is black for readability */
body,
.app,
.main,
.content,
.panel,
.kpi,
.report {
color: #000 !important;
background: #fff !important;
}
}
@media print {
/* Force-hide ALL modal elements by structure — works even if JS fails */
.modal-backdrop,
.modal-card,
.share-card,
.schedule-card,
.filter-info-card,
.record-detail-card,
[class*="modal-"],
[class*="share-"] {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
position: absolute !important;
z-index: -9999 !important;
height: 0 !important;
width: 0 !important;
overflow: hidden !important;
}
}
/* --- Single-chart dashboard: cap height + center chart so it doesn't stretch --- */
.dash-row.dash-single {
grid-template-columns: minmax(0, 720px);
justify-content: center;
}
.dash-row.dash-single .dash-panel {
max-width: 720px;
margin: 0 auto;
}
.dash-row.dash-single .dash-panel .chart-body {
min-height: 260px;
max-height: 320px;
display: flex;
align-items: center;
justify-content: center;
}
.dash-row.dash-single .svg-line,
.dash-row.dash-single .svg-bar {
height: 260px;
max-height: 260px;
}
.dash-row.dash-single .svg-donut {
width: 180px;
max-width: 180px;
height: 180px;
}
.panel-head {
display: flex;
align-items: center;
padding: 14px 16px 10px;
gap: 10px;
min-width: 0;
}
.panel-head .title {
font-size: 13px; /* slightly smaller so long titles fit in one line */
font-weight: 600;
color: var(--text-1);
flex: 1 1 auto; /* take all available space */
min-width: 0; /* allow shrinking */
white-space: nowrap; /* never wrap */
overflow: hidden;
text-overflow: ellipsis; /* "Top 6 Products by Unit…" instead of wrapping */
line-height: 1.3;
}
.chip-group {
flex-shrink: 0; /* never shrink — stays right-aligned */
margin-left: auto;
display: inline-flex;
align-items: center; /* vertically centre all chips together */
border: 1px solid var(--border-strong);
border-radius: 6px;
overflow: hidden;
height: 28px; /* fixed height so all 3 chips are the same size */
}
.chip {
background: var(--card-bg);
border: none;
border-right: 1px solid var(--border-strong); /* separator between chips */
padding: 0 8px;
height: 100%; /* fill the chip-group height — no size difference */
cursor: pointer;
font-size: 13px;
color: var(--text-2);
font-family: inherit;
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 1;
transition: background 100ms ease, color 100ms ease;
}
.chip:last-child {
border-right: none; /* no trailing separator on last chip */
}
.chip:hover {
background: var(--row-hover);
}
.chip.on {
background: var(--brand-gradient);
color: #fff;
}