Glas Theme Coming Next
This commit is contained in:
@@ -8,11 +8,11 @@
|
|||||||
/* ── DESIGN TOKENS (light overrides) ───────────────────────────── */
|
/* ── DESIGN TOKENS (light overrides) ───────────────────────────── */
|
||||||
:root {
|
:root {
|
||||||
--ink: #2c2825; /* soft near-black — readable without harshness */
|
--ink: #2c2825; /* soft near-black — readable without harshness */
|
||||||
--paper: #f4f2ed; /* warm off-white page background */
|
--paper: #ece7dc; /* warm sand/khaki page tone */
|
||||||
--accent: #1a6a98; /* blue — good for buttons, kept full strength */
|
--accent: #1a6a98; /* blue — good for buttons, kept full strength */
|
||||||
--muted: #6b6360; /* mid-grey for secondary text */
|
--muted: #6b6360; /* mid-grey for secondary text */
|
||||||
--border: #d0cdc7; /* soft warm-grey borders */
|
--border: #d2cbc0; /* warm border to match khaki palette */
|
||||||
--card: #ebe8e2; /* off-white card background */
|
--card: #f1ebdf; /* general light-mode utility surface */
|
||||||
--green: #217045; /* darker green — accessible on white */
|
--green: #217045; /* darker green — accessible on white */
|
||||||
--amber: #a05f00; /* darker amber — accessible on white */
|
--amber: #a05f00; /* darker amber — accessible on white */
|
||||||
}
|
}
|
||||||
@@ -29,13 +29,71 @@ body {
|
|||||||
to keep the SVG logo (fill="#0c0c0c" text) legible.
|
to keep the SVG logo (fill="#0c0c0c" text) legible.
|
||||||
─────────────────────────────────────────────────────────────────── */
|
─────────────────────────────────────────────────────────────────── */
|
||||||
.top-bar {
|
.top-bar {
|
||||||
background: #e8e4db !important;
|
background: #e3ddd2 !important;
|
||||||
border-bottom-color: rgba(0, 0, 0, 0.09) !important; /* replace strong blue stripe with soft warm separator */
|
border-bottom-color: rgba(0, 0, 0, 0.09) !important; /* replace strong blue stripe with soft warm separator */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── SECTION CARDS ───────────────────────────────────────────────── */
|
/* ── SECTION CARDS ───────────────────────────────────────────────── */
|
||||||
.section {
|
.section {
|
||||||
background: #faf9f5 !important; /* warm white — less stark than pure white on cream background */
|
background: #f5f2ea !important; /* warm cream — floats above khaki paper */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── SPLIT LIGHT-MODE SURFACES ─────────────────────────────────────
|
||||||
|
Keep sections as the main content cards.
|
||||||
|
Quote settings = warmer utility panel.
|
||||||
|
Live quote = cooler summary panel, including the mobile sheet.
|
||||||
|
*/
|
||||||
|
.quote-settings-bar {
|
||||||
|
background: #ebe1d2 !important;
|
||||||
|
border-color: #d8cab8 !important;
|
||||||
|
}
|
||||||
|
.qs-divider {
|
||||||
|
background: #d6c8b7 !important;
|
||||||
|
}
|
||||||
|
.qs-fee-input-wrap,
|
||||||
|
.qs-fee-dollar,
|
||||||
|
.qs-fee-input {
|
||||||
|
background: #f6f0e6 !important;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-color: #cfdae2 !important;
|
||||||
|
}
|
||||||
|
.sidebar-utility .btn-reset-quote,
|
||||||
|
.mobile-panel-actions .btn-reset-quote {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-color: #cfdae2 !important;
|
||||||
|
}
|
||||||
|
.sidebar-body {
|
||||||
|
background: #f3f7f9 !important;
|
||||||
|
}
|
||||||
|
.export-wrap {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-top: 1px solid #d8e2e8 !important;
|
||||||
|
}
|
||||||
|
.mobile-panel-sheet {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-top-color: #cfdae2 !important;
|
||||||
|
}
|
||||||
|
.mobile-panel-close-row {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-bottom-color: #d8e2e8 !important;
|
||||||
|
}
|
||||||
|
.mobile-panel-actions {
|
||||||
|
background: #edf3f6 !important;
|
||||||
|
border-bottom-color: #d8e2e8 !important;
|
||||||
|
}
|
||||||
|
.mobile-panel-sheet .sidebar {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
.mobile-panel-sheet .sidebar-body {
|
||||||
|
background: #f3f7f9 !important;
|
||||||
|
}
|
||||||
|
.confirm-modal-card {
|
||||||
|
background: #f5f2ea !important;
|
||||||
|
}
|
||||||
|
.confirm-btn-secondary:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── CHEVRON PILL — swap white-alpha tint for dark-alpha ─────────── */
|
/* ── CHEVRON PILL — swap white-alpha tint for dark-alpha ─────────── */
|
||||||
@@ -73,12 +131,12 @@ body {
|
|||||||
/* Dark mode steppers blend in naturally. Light mode needs explicit lift:
|
/* Dark mode steppers blend in naturally. Light mode needs explicit lift:
|
||||||
white surfaces stand off the warm card bg; accent symbols tie to brand. */
|
white surfaces stand off the warm card bg; accent symbols tie to brand. */
|
||||||
.step-btn {
|
.step-btn {
|
||||||
background: #ffffff !important;
|
background: #faf8f3 !important; /* soft cream — not stark white */
|
||||||
border-color: #b8b4ae !important; /* stronger than --border #d0cdc7 for crispness */
|
border-color: #b8b4ae !important; /* stronger than --border for crispness */
|
||||||
color: var(--accent) !important; /* accent blue +/- symbols instead of muted grey */
|
color: var(--accent) !important; /* accent blue +/- symbols instead of muted grey */
|
||||||
}
|
}
|
||||||
.step-btn:hover {
|
.step-btn:hover {
|
||||||
background: #f0ede7 !important; /* warm tint matches section card on hover */
|
background: #ede8de !important; /* warm tint matches khaki family on hover */
|
||||||
border-color: var(--accent) !important;
|
border-color: var(--accent) !important;
|
||||||
color: var(--accent) !important;
|
color: var(--accent) !important;
|
||||||
}
|
}
|
||||||
@@ -88,7 +146,7 @@ body {
|
|||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
.num-input {
|
.num-input {
|
||||||
background: #ffffff !important;
|
background: #faf8f3 !important; /* soft cream — matches step buttons */
|
||||||
border-color: #b8b4ae !important;
|
border-color: #b8b4ae !important;
|
||||||
}
|
}
|
||||||
.num-input:focus {
|
.num-input:focus {
|
||||||
@@ -98,7 +156,7 @@ body {
|
|||||||
|
|
||||||
/* ── ADDON ROW SELECTED ──────────────────────────────────────────── */
|
/* ── ADDON ROW SELECTED ──────────────────────────────────────────── */
|
||||||
.addon-row.selected {
|
.addon-row.selected {
|
||||||
background: #dff0fb !important;
|
background: #daedf8 !important;
|
||||||
border-color: var(--accent) !important;
|
border-color: var(--accent) !important;
|
||||||
box-shadow: inset 3px 0 0 0 var(--accent) !important;
|
box-shadow: inset 3px 0 0 0 var(--accent) !important;
|
||||||
}
|
}
|
||||||
@@ -111,7 +169,28 @@ body {
|
|||||||
|
|
||||||
/* ── FEATURE CARDS ───────────────────────────────────────────────── */
|
/* ── FEATURE CARDS ───────────────────────────────────────────────── */
|
||||||
.feature-card {
|
.feature-card {
|
||||||
background: #f0ede7 !important;
|
background: #e9e4da !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── SIDEBAR / SUMMARY TEXT ────────────────────────────────────────
|
||||||
|
Base dark theme hardcodes a few bright values for money and labels.
|
||||||
|
In light mode those need to return to dark text so the desktop
|
||||||
|
sidebar and the responsive mobile sheet remain readable.
|
||||||
|
*/
|
||||||
|
.sidebar-line .val {
|
||||||
|
color: var(--ink) !important;
|
||||||
|
}
|
||||||
|
.sidebar-mrr {
|
||||||
|
color: var(--ink) !important;
|
||||||
|
}
|
||||||
|
.vs-svs-label {
|
||||||
|
color: var(--ink) !important;
|
||||||
|
}
|
||||||
|
.vs-val-accent {
|
||||||
|
color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
.vs-td-muted {
|
||||||
|
color: var(--muted) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── NUDGE BANNER ────────────────────────────────────────────────── */
|
/* ── NUDGE BANNER ────────────────────────────────────────────────── */
|
||||||
@@ -131,7 +210,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── VS COMPARISON ───────────────────────────────────────────────── */
|
/* ── VS COMPARISON ───────────────────────────────────────────────── */
|
||||||
.vs-comparison-wrap { background: rgba(0, 0, 0, 0.025) !important; }
|
.vs-comparison-wrap {
|
||||||
|
background: #e5edf2 !important;
|
||||||
|
border-color: #cfdae2 !important;
|
||||||
|
}
|
||||||
.vs-save-green td { background: rgba(39, 174, 96, 0.10) !important; }
|
.vs-save-green td { background: rgba(39, 174, 96, 0.10) !important; }
|
||||||
.vs-save-amber td { background: rgba(210, 120, 30, 0.09) !important; }
|
.vs-save-amber td { background: rgba(210, 120, 30, 0.09) !important; }
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
Single source of truth for all colours. Edit here, not inline.
|
Single source of truth for all colours. Edit here, not inline.
|
||||||
─────────────────────────────────────────────────────────────── */
|
─────────────────────────────────────────────────────────────── */
|
||||||
:root {
|
:root {
|
||||||
--ink: #ddd8d0;
|
--ink: #e8e3da; /* warm beige-white — brighter for legibility */
|
||||||
--paper: #22201d;
|
--paper: #1c1a17; /* darker base — widens gap vs card for panel float */
|
||||||
--accent: #2d7aa8;
|
--accent: #3d8aba; /* lifted blue — pops on dark backgrounds */
|
||||||
--muted: #b0a898; /* lifted slightly — #a09890 was too faint on dark cards */
|
--muted: #9e9588; /* softer secondary — clearly subordinate but readable */
|
||||||
--border: #3a3630;
|
--border: #35322c; /* subtler dividers */
|
||||||
--card: #2a2722;
|
--card: #272420; /* elevated surface — clear separation from paper */
|
||||||
--green: #3ab870;
|
--green: #3ab870;
|
||||||
--amber: #e8920f;
|
--amber: #e8920f;
|
||||||
}
|
}
|
||||||
@@ -118,6 +118,110 @@
|
|||||||
}
|
}
|
||||||
.main-col { display: flex; flex-direction: column; gap: 28px; }
|
.main-col { display: flex; flex-direction: column; gap: 28px; }
|
||||||
.side-col { position: sticky; top: 102px; z-index: 10; align-self: start; }
|
.side-col { position: sticky; top: 102px; z-index: 10; align-self: start; }
|
||||||
|
.sidebar-utility { margin-bottom: 12px; }
|
||||||
|
.btn-reset-quote {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 11px 14px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.09em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
|
||||||
|
}
|
||||||
|
.btn-reset-quote:hover {
|
||||||
|
background: rgba(232, 146, 15, 0.08);
|
||||||
|
border-color: rgba(232, 146, 15, 0.38);
|
||||||
|
color: var(--amber);
|
||||||
|
}
|
||||||
|
.btn-reset-quote:active { transform: translateY(1px); }
|
||||||
|
|
||||||
|
.confirm-modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 400;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
.confirm-modal.open {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.confirm-modal-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.62);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
-webkit-backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
.confirm-modal-card {
|
||||||
|
position: relative;
|
||||||
|
width: min(460px, calc(100% - 32px));
|
||||||
|
margin: 12vh auto 0;
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 22px 22px 20px;
|
||||||
|
box-shadow: 0 16px 50px rgba(0,0,0,0.35);
|
||||||
|
}
|
||||||
|
.confirm-modal-eyebrow {
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--amber);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.confirm-modal-title {
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.3;
|
||||||
|
color: var(--ink);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.confirm-modal-copy {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.confirm-modal-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.confirm-btn {
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 11px 14px;
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
|
||||||
|
}
|
||||||
|
.confirm-btn:active { transform: translateY(1px); }
|
||||||
|
.confirm-btn-secondary {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.confirm-btn-secondary:hover {
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
color: var(--ink);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
.confirm-btn-danger {
|
||||||
|
background: var(--amber);
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.confirm-btn-danger:hover { filter: brightness(1.05); }
|
||||||
|
|
||||||
/* ── CLIENT BAR ─────────────────────────────────────────────────
|
/* ── CLIENT BAR ─────────────────────────────────────────────────
|
||||||
Lives inside .main-col, above section I.
|
Lives inside .main-col, above section I.
|
||||||
@@ -706,7 +810,7 @@
|
|||||||
}
|
}
|
||||||
.sidebar-line .val {
|
.sidebar-line .val {
|
||||||
font-family: 'DM Mono', monospace;
|
font-family: 'DM Mono', monospace;
|
||||||
color: var(--ink);
|
color: #f2ede4; /* brighter warm white — money figures pop vs labels */
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.sidebar-line .lbl-icon { margin-right: 5px; }
|
.sidebar-line .lbl-icon { margin-right: 5px; }
|
||||||
@@ -723,7 +827,7 @@
|
|||||||
font-family: 'Poppins', sans-serif;
|
font-family: 'Poppins', sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 48px;
|
font-size: 48px;
|
||||||
color: var(--ink);
|
color: #f5f0e8; /* brightest text — hero MRR number */
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
@@ -1065,15 +1169,15 @@
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
padding: 24px 24px 22px;
|
padding: 24px 24px 22px;
|
||||||
background: rgba(255, 255, 255, 0.04);
|
background: rgba(255, 255, 255, 0.06);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
.vs-inline-icon { margin-right: 6px; vertical-align: middle; }
|
.vs-inline-icon { margin-right: 6px; vertical-align: middle; }
|
||||||
.vs-svs-label { font-size: 14px; color: var(--ink); font-weight: 600; }
|
.vs-svs-label { font-size: 14px; color: #f2ede4; font-weight: 600; }
|
||||||
.vs-val-accent { color: var(--accent); font-weight: 600; font-size: 14px; }
|
.vs-val-accent { color: #5aaedc; font-weight: 600; font-size: 14px; }
|
||||||
.vs-td-muted { color: var(--muted); font-size: 12px; }
|
.vs-td-muted { color: #b5ab9e; font-size: 13px; }
|
||||||
.vs-td-icon { margin-right: 5px; opacity: 0.55; vertical-align: middle; }
|
.vs-td-icon { margin-right: 5px; opacity: 0.7; vertical-align: middle; }
|
||||||
.vs-footnote {
|
.vs-footnote {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
@@ -1135,8 +1239,8 @@
|
|||||||
.vs-val-green — green text for savings value/label
|
.vs-val-green — green text for savings value/label
|
||||||
.vs-val-amber — amber text for "costs more" value/label
|
.vs-val-amber — amber text for "costs more" value/label
|
||||||
─────────────────────────────────────────────────────────────── */
|
─────────────────────────────────────────────────────────────── */
|
||||||
.vs-save-green td { background: rgba(39, 174, 96, 0.13); }
|
.vs-save-green td { background: rgba(39, 174, 96, 0.16); }
|
||||||
.vs-save-amber td { background: rgba(210, 120, 30, 0.13); }
|
.vs-save-amber td { background: rgba(210, 120, 30, 0.16); }
|
||||||
.vs-val-green { color: var(--green) !important; }
|
.vs-val-green { color: var(--green) !important; }
|
||||||
.vs-val-amber { color: var(--amber) !important; }
|
.vs-val-amber { color: var(--amber) !important; }
|
||||||
|
|
||||||
@@ -1160,7 +1264,7 @@
|
|||||||
the checkbox's native accent-color. No pseudo-element needed.
|
the checkbox's native accent-color. No pseudo-element needed.
|
||||||
─────────────────────────────────────────────────────────────── */
|
─────────────────────────────────────────────────────────────── */
|
||||||
.addon-row.selected {
|
.addon-row.selected {
|
||||||
background: #1a2a38;
|
background: #1d2d3a;
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
box-shadow: inset 3px 0 0 0 var(--accent);
|
box-shadow: inset 3px 0 0 0 var(--accent);
|
||||||
}
|
}
|
||||||
@@ -1284,8 +1388,28 @@
|
|||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
.pitch-item:last-child { border-right: none; }
|
.pitch-item:last-child { border-right: none; }
|
||||||
.pitch-icon { font-size: 20px; margin-bottom: 12px; color: var(--accent); }
|
.pitch-head {
|
||||||
.pitch-title { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 16px; margin-bottom: 8px; }
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
.pitch-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
.pitch-title {
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.3;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.pitch-desc { font-size: 14px; color: var(--muted); line-height: 1.7; }
|
.pitch-desc { font-size: 14px; color: var(--muted); line-height: 1.7; }
|
||||||
.pitch-footer {
|
.pitch-footer {
|
||||||
background: #162e22; /* match green callout family — was #1a2e20 */
|
background: #162e22; /* match green callout family — was #1a2e20 */
|
||||||
@@ -1588,6 +1712,13 @@
|
|||||||
/* Nudge banner */
|
/* Nudge banner */
|
||||||
.nudge-banner { padding: 14px 16px; font-size: 14px; }
|
.nudge-banner { padding: 14px 16px; font-size: 14px; }
|
||||||
.export-wrap { padding: 16px 16px 20px; }
|
.export-wrap { padding: 16px 16px 20px; }
|
||||||
|
.confirm-modal-card {
|
||||||
|
margin-top: 8vh;
|
||||||
|
padding: 20px 18px 18px;
|
||||||
|
}
|
||||||
|
.confirm-modal-title { font-size: 21px; }
|
||||||
|
.confirm-modal-actions { flex-direction: column-reverse; }
|
||||||
|
.confirm-btn { width: 100%; }
|
||||||
|
|
||||||
/* Fee table */
|
/* Fee table */
|
||||||
.fee-table td { padding: 7px 0; font-size: 13px; }
|
.fee-table td { padding: 7px 0; font-size: 13px; }
|
||||||
@@ -1626,6 +1757,7 @@
|
|||||||
─────────────────────────────────────────────────────────────── */
|
─────────────────────────────────────────────────────────────── */
|
||||||
.mobile-quote-pill { display: none; }
|
.mobile-quote-pill { display: none; }
|
||||||
.mobile-quote-panel { display: none; }
|
.mobile-quote-panel { display: none; }
|
||||||
|
.mobile-panel-actions { display: none; }
|
||||||
|
|
||||||
/* ═══════════════════════════════════════
|
/* ═══════════════════════════════════════
|
||||||
MOBILE QUOTE PILL + FULL-SCREEN PANEL
|
MOBILE QUOTE PILL + FULL-SCREEN PANEL
|
||||||
@@ -1751,6 +1883,15 @@
|
|||||||
padding: 16px 20px 12px;
|
padding: 16px 20px 12px;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
.mobile-panel-actions {
|
||||||
|
display: block;
|
||||||
|
padding: 0 20px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
background: var(--card);
|
||||||
|
}
|
||||||
|
.mobile-panel-actions .btn-reset-quote {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
.mobile-panel-close-title {
|
.mobile-panel-close-title {
|
||||||
font-family: 'DM Mono', monospace;
|
font-family: 'DM Mono', monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
<span class="mobile-panel-close-title">Quote Summary</span>
|
<span class="mobile-panel-close-title">Quote Summary</span>
|
||||||
<button class="mobile-panel-close-btn" onclick="closeMobilePanel()" aria-label="Close">×</button>
|
<button class="mobile-panel-close-btn" onclick="closeMobilePanel()" aria-label="Close">×</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mobile-panel-actions">
|
||||||
|
<button type="button" class="btn-reset-quote" onclick="openResetConfirm()">Reset Quote</button>
|
||||||
|
</div>
|
||||||
<!-- Sidebar content injected here by JS on first open -->
|
<!-- Sidebar content injected here by JS on first open -->
|
||||||
<div id="mobilePanelContent">
|
<div id="mobilePanelContent">
|
||||||
|
|
||||||
@@ -100,6 +103,7 @@
|
|||||||
<span><span class="lbl-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="12" height="13" fill="currentColor" style="vertical-align:middle;"><path d="M48 0C21.5 0 0 21.5 0 48V464c0 26.5 21.5 48 48 48h96V432c0-26.5 21.5-48 48-48s48 21.5 48 48v80h96c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H48zM64 240c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V240zm112-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V240c0-8.8 7.2-16 16-16zm48-80v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16zm144 208h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16z"/></svg></span> Site Admin Fee</span>
|
<span><span class="lbl-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="12" height="13" fill="currentColor" style="vertical-align:middle;"><path d="M48 0C21.5 0 0 21.5 0 48V464c0 26.5 21.5 48 48 48h96V432c0-26.5 21.5-48 48-48s48 21.5 48 48v80h96c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H48zM64 240c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V240zm112-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V240c0-8.8 7.2-16 16-16zm48-80v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16zm144 208h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16z"/></svg></span> Site Admin Fee</span>
|
||||||
<span class="val" id="sl-admin-val_m">$150</span>
|
<span class="val" id="sl-admin-val_m">$150</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sl-sub hidden" id="sl-admin-sub_m"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Discount line — hidden when no term discount -->
|
<!-- Discount line — hidden when no term discount -->
|
||||||
@@ -344,10 +348,10 @@
|
|||||||
|
|
||||||
<!-- What's Covered collapsible -->
|
<!-- What's Covered collapsible -->
|
||||||
<div class="collapsible-header collapsible-header--mt16" onclick="toggleCollapsible('adminCovered')" tabindex="0" role="button" onkeydown="if(event.key==='Enter'||event.key===' '){toggleCollapsible('adminCovered');event.preventDefault();}">
|
<div class="collapsible-header collapsible-header--mt16" onclick="toggleCollapsible('adminCovered')" tabindex="0" role="button" onkeydown="if(event.key==='Enter'||event.key===' '){toggleCollapsible('adminCovered');event.preventDefault();}">
|
||||||
<span class="collapsible-toggle open" id="adminCovered-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
<span class="collapsible-toggle" id="adminCovered-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||||
<span class="collapsible-label">What's Covered by the Admin Fee</span>
|
<span class="collapsible-label">What's Covered by the Admin Fee</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapsible-body open" id="adminCovered">
|
<div class="collapsible-body" id="adminCovered">
|
||||||
<div class="feature-card-grid">
|
<div class="feature-card-grid">
|
||||||
<div class="feature-card"><div class="feature-card-title"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16" fill="var(--accent)" style="margin-right:8px;flex-shrink:0;vertical-align:middle;"><path d="M96 0C43 0 0 43 0 96V416c0 53 43 96 96 96H344.2c-1.5-9.5-2.2-19.2-2.2-29.1V384H96c-17.7 0-32-14.3-32-32V96c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32v84.2c19.4 6.7 37.3 17.3 52.9 30.6c5.3-2.7 11.3-4.8 17.1-4.8c23.7 0 42.9 19.2 42.9 42.9V272c16.8 10.4 32 23.4 44.8 38.8V176c0-53-43-96-96-96H416V96c0-53-43-96-96-96H96zM224 320a64 64 0 1 1 128 0 64 64 0 1 1 -128 0zm-32 64h192c17.7 0 32 14.3 32 32v32H160V416c0-17.7 14.3-32 32-32zM128 176c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H144c-8.8 0-16-7.2-16-16V176zm0 96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H144c-8.8 0-16-7.2-16-16V272zm128-96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V176zm0 96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V272zm128-96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H384c-8.8 0-16-7.2-16-16V176zM496 512a144 144 0 1 0 0-288 144 144 0 1 0 0 288zm0-96a48 48 0 1 1 0-96 48 48 0 1 1 0 96z"/></svg> Tenant & Identity Management</div><div class="feature-card-desc">Microsoft 365 / Entra ID tenant administration, user lifecycle, MFA enforcement, and conditional access policies.</div></div>
|
<div class="feature-card"><div class="feature-card-title"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16" fill="var(--accent)" style="margin-right:8px;flex-shrink:0;vertical-align:middle;"><path d="M96 0C43 0 0 43 0 96V416c0 53 43 96 96 96H344.2c-1.5-9.5-2.2-19.2-2.2-29.1V384H96c-17.7 0-32-14.3-32-32V96c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32v84.2c19.4 6.7 37.3 17.3 52.9 30.6c5.3-2.7 11.3-4.8 17.1-4.8c23.7 0 42.9 19.2 42.9 42.9V272c16.8 10.4 32 23.4 44.8 38.8V176c0-53-43-96-96-96H416V96c0-53-43-96-96-96H96zM224 320a64 64 0 1 1 128 0 64 64 0 1 1 -128 0zm-32 64h192c17.7 0 32 14.3 32 32v32H160V416c0-17.7 14.3-32 32-32zM128 176c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H144c-8.8 0-16-7.2-16-16V176zm0 96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H144c-8.8 0-16-7.2-16-16V272zm128-96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V176zm0 96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V272zm128-96c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H384c-8.8 0-16-7.2-16-16V176zM496 512a144 144 0 1 0 0-288 144 144 0 1 0 0 288zm0-96a48 48 0 1 1 0-96 48 48 0 1 1 0 96z"/></svg> Tenant & Identity Management</div><div class="feature-card-desc">Microsoft 365 / Entra ID tenant administration, user lifecycle, MFA enforcement, and conditional access policies.</div></div>
|
||||||
<div class="feature-card"><div class="feature-card-title"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16" fill="var(--accent)" style="margin-right:8px;flex-shrink:0;vertical-align:middle;"><path d="M256 64H384v64H256V64zM240 0c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h48v32H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h176v32H160c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V368c0-26.5-21.5-48-48-48H240V288H400v32H352c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V368c0-26.5-21.5-48-48-48H432V288H608c17.7 0 32-14.3 32-32s-14.3-32-32-32H352V192h48c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H240zM192 400H288v64H192V400zm256 0H544v64H448V400z"/></svg> Network & Infrastructure Oversight</div><div class="feature-card-desc">Firewall configuration reviews, DNS management, VLAN segmentation oversight, and network performance monitoring.</div></div>
|
<div class="feature-card"><div class="feature-card-title"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16" fill="var(--accent)" style="margin-right:8px;flex-shrink:0;vertical-align:middle;"><path d="M256 64H384v64H256V64zM240 0c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h48v32H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h176v32H160c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V368c0-26.5-21.5-48-48-48H240V288H400v32H352c-26.5 0-48 21.5-48 48v96c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V368c0-26.5-21.5-48-48-48H432V288H608c17.7 0 32-14.3 32-32s-14.3-32-32-32H352V192h48c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H240zM192 400H288v64H192V400zm256 0H544v64H448V400z"/></svg> Network & Infrastructure Oversight</div><div class="feature-card-desc">Firewall configuration reviews, DNS management, VLAN segmentation oversight, and network performance monitoring.</div></div>
|
||||||
@@ -425,13 +429,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="collapsible-body open" id="userIncluded">
|
<div class="collapsible-body open" id="userIncluded">
|
||||||
<ul class="feature-list">
|
<ul class="feature-list">
|
||||||
<li class="m365-feature">Microsoft 365 Business Premium (M365 tier) — Word, Excel, PowerPoint, Teams, Exchange</li>
|
<li class="m365-feature">Microsoft 365 Business Premium</li>
|
||||||
<li class="m365-feature">Entra ID & MFA — identity protection, conditional access, and SSO</li>
|
<li class="m365-feature">Word, Excel, PowerPoint, Teams, Exchange</li>
|
||||||
<li class="m365-feature">Microsoft Defender for Business — endpoint + email threat protection</li>
|
<li class="m365-feature">Entra ID / conditional access / SSO</li>
|
||||||
<li>Helpdesk support (business hours) — tickets, remote sessions, escalations</li>
|
<li class="m365-feature">Defender for Business</li>
|
||||||
<li>Onboarding & offboarding — provisioning, access revocation, equipment checklists</li>
|
<li class="m365-feature">MFA enforcement</li>
|
||||||
<li>Security awareness training (SAT) — phishing simulations & training modules</li>
|
<li class="m365-feature">SaaS alerting / geo-location lock</li>
|
||||||
<li>User-level documentation — accounts, devices, access tracked per user</li>
|
<li>CORK cyber warranty with $100,000 annual coverage</li>
|
||||||
|
<li>INKY advanced mail protection</li>
|
||||||
|
<li>Security awareness training and phishing simulation</li>
|
||||||
|
<li>SaaS backup for business email, OneDrive, and Google Workspace</li>
|
||||||
|
<li>Dark web ID scanning</li>
|
||||||
|
<li>SOC account monitoring</li>
|
||||||
|
<li>Unlimited remote bilingual help desk support (9am-5pm / Mon-Fri)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -443,7 +453,7 @@
|
|||||||
<div id="addonsA-preview" class="addon-preview-wrap" style="display:none">
|
<div id="addonsA-preview" class="addon-preview-wrap" style="display:none">
|
||||||
<span class="addon-preview-pill" data-addon="addExtHours">Extended Hours</span>
|
<span class="addon-preview-pill" data-addon="addExtHours">Extended Hours</span>
|
||||||
<span class="addon-preview-pill" data-addon="addPWM">1Password</span>
|
<span class="addon-preview-pill" data-addon="addPWM">1Password</span>
|
||||||
<span class="addon-preview-pill" data-addon="addINKY">INKY Pro</span>
|
<span class="addon-preview-pill" data-addon="addINKY">INKY Pro Upgrade</span>
|
||||||
<span class="addon-preview-pill" data-addon="addZT">Zero Trust</span>
|
<span class="addon-preview-pill" data-addon="addZT">Zero Trust</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -461,7 +471,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<label class="addon-row" id="row-inky" onclick="toggleAddon('addINKY','row-inky');update()">
|
<label class="addon-row" id="row-inky" onclick="toggleAddon('addINKY','row-inky');update()">
|
||||||
<input type="checkbox" id="addINKY">
|
<input type="checkbox" id="addINKY">
|
||||||
<div><div class="addon-name">INKY Pro Email Security</div><div class="addon-desc">AI-powered phishing protection & email authentication layer</div></div>
|
<div><div class="addon-name">INKY Pro Upgrade</div><div class="addon-desc">Adds enhanced phishing defense and email security controls on top of the included INKY mail protection</div></div>
|
||||||
<span class="addon-price">+$5/user/mo</span>
|
<span class="addon-price">+$5/user/mo</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="addon-row" id="row-zt" onclick="toggleAddon('addZT','row-zt');update()">
|
<label class="addon-row" id="row-zt" onclick="toggleAddon('addZT','row-zt');update()">
|
||||||
@@ -511,12 +521,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="collapsible-body open" id="endpointIncluded">
|
<div class="collapsible-body open" id="endpointIncluded">
|
||||||
<ul class="feature-list">
|
<ul class="feature-list">
|
||||||
<li>RMM agent — remote monitoring, patching & automated remediation</li>
|
<li>Managed EDR threat protection</li>
|
||||||
<li>Huntress EDR — 24/7 SOC-backed threat hunting & incident response</li>
|
<li>1 full workstation backup included</li>
|
||||||
<li>Patch management — OS & third-party software, tested & staged rollouts</li>
|
<li>24/7 SOC monitoring and response</li>
|
||||||
<li>Disk encryption enforcement — BitLocker management & key escrow</li>
|
<li>Encryption enforcement</li>
|
||||||
<li>Asset inventory — hardware specs, software, warranties tracked per device</li>
|
<li>RMM monitoring and maintenance</li>
|
||||||
<li>Cyber warranty — up to $1M coverage backed by our toolstack compliance</li>
|
<li>Firmware, updates, and patch management</li>
|
||||||
|
<li>Admin password rotation</li>
|
||||||
|
<li>Application ringfencing</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -746,6 +758,9 @@
|
|||||||
nudgeBanner must stay INSIDE .sidebar-body or it gets clipped.
|
nudgeBanner must stay INSIDE .sidebar-body or it gets clipped.
|
||||||
──────────────────────────────────────────────────────────────── -->
|
──────────────────────────────────────────────────────────────── -->
|
||||||
<div class="side-col">
|
<div class="side-col">
|
||||||
|
<div class="sidebar-utility">
|
||||||
|
<button type="button" class="btn-reset-quote" onclick="openResetConfirm()">Reset Quote</button>
|
||||||
|
</div>
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="sidebar-title">SVS MSP — Live Quote</div>
|
<div class="sidebar-title">SVS MSP — Live Quote</div>
|
||||||
@@ -806,6 +821,7 @@
|
|||||||
<span><span class="lbl-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="12" height="13" fill="currentColor" style="vertical-align:middle;"><path d="M48 0C21.5 0 0 21.5 0 48V464c0 26.5 21.5 48 48 48h96V432c0-26.5 21.5-48 48-48s48 21.5 48 48v80h96c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H48zM64 240c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V240zm112-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V240c0-8.8 7.2-16 16-16zm48-80v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16zm144 208h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16z"/></svg></span> Site Admin Fee</span>
|
<span><span class="lbl-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="12" height="13" fill="currentColor" style="vertical-align:middle;"><path d="M48 0C21.5 0 0 21.5 0 48V464c0 26.5 21.5 48 48 48h96V432c0-26.5 21.5-48 48-48s48 21.5 48 48v80h96c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48H48zM64 240c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V240zm112-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V240c0-8.8 7.2-16 16-16zm48-80v32c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16zm144 208h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H272c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16zm-144-16h32c8.8 0 16 7.2 16 16v32c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V352c0-8.8 7.2-16 16-16z"/></svg></span> Site Admin Fee</span>
|
||||||
<span class="val" id="sl-admin-val">$150</span>
|
<span class="val" id="sl-admin-val">$150</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sl-sub hidden" id="sl-admin-sub"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Discount line — hidden when no term discount -->
|
<!-- Discount line — hidden when no term discount -->
|
||||||
@@ -909,23 +925,31 @@
|
|||||||
<div class="pitch-inner">
|
<div class="pitch-inner">
|
||||||
<div class="pitch-grid">
|
<div class="pitch-grid">
|
||||||
<div class="pitch-item">
|
<div class="pitch-item">
|
||||||
|
<div class="pitch-head">
|
||||||
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="18" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M256 0c4.6 0 9.2 1 13.4 2.9L457.7 82.8c22 9.3 38.4 31 38.3 57.2c-.5 99.2-41.3 280.7-213.6 363.2c-16.7 8-36.1 8-52.8 0C57.3 420.7 16.5 239.2 16 140c-.1-26.2 16.3-47.9 38.3-57.2L242.7 2.9C246.8 1 251.4 0 256 0zm0 66.8V444.8C394 378 431.1 230.1 432 141.4L256 66.8z"/></svg></div>
|
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="18" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M256 0c4.6 0 9.2 1 13.4 2.9L457.7 82.8c22 9.3 38.4 31 38.3 57.2c-.5 99.2-41.3 280.7-213.6 363.2c-16.7 8-36.1 8-52.8 0C57.3 420.7 16.5 239.2 16 140c-.1-26.2 16.3-47.9 38.3-57.2L242.7 2.9C246.8 1 251.4 0 256 0zm0 66.8V444.8C394 378 431.1 230.1 432 141.4L256 66.8z"/></svg></div>
|
||||||
<div class="pitch-title">Security-First MSP</div>
|
<div class="pitch-title">Security-First MSP</div>
|
||||||
|
</div>
|
||||||
<div class="pitch-desc">Every engagement is built on a security baseline — EDR, MFA, patch management, and cyber warranty included.</div>
|
<div class="pitch-desc">Every engagement is built on a security baseline — EDR, MFA, patch management, and cyber warranty included.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pitch-item">
|
<div class="pitch-item">
|
||||||
|
<div class="pitch-head">
|
||||||
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="14" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/></svg></div>
|
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="14" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/></svg></div>
|
||||||
<div class="pitch-title">Ottawa-Based Team</div>
|
<div class="pitch-title">Ottawa-Based Team</div>
|
||||||
|
</div>
|
||||||
<div class="pitch-desc">Local presence, Canadian data sovereignty, and an account team that knows your business and your region.</div>
|
<div class="pitch-desc">Local presence, Canadian data sovereignty, and an account team that knows your business and your region.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pitch-item">
|
<div class="pitch-item">
|
||||||
|
<div class="pitch-head">
|
||||||
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="20" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M78.6 5C69.1-2.4 55.6-1.5 47 7L7 47c-8.5 8.5-9.4 22-2.1 31.6l80 104c4.5 5.9 11.6 9.4 19 9.4h54.1l109 109c-14.7 29-10 65.4 14.3 89.6l112 112c12.5 12.5 32.8 12.5 45.3 0l64-64c12.5-12.5 12.5-32.8 0-45.3l-112-112c-24.2-24.2-60.6-29-89.6-14.3l-109-109V104c0-7.5-3.5-14.5-9.4-19L78.6 5zM19.9 396.1C7.2 408.8 0 426.1 0 444.1C0 481.6 30.4 512 67.9 512c18 0 35.3-7.2 48-19.9L233.7 374.3c-7.8-20.9-9-43.6-3.6-65.1l-61.7-61.7L19.9 396.1zM512 144c0-10.5-1.1-20.7-3.2-30.5c-2.4-11.2-16.1-14.1-24.2-6l-63.9 63.9c-3 3-7.1 4.7-11.3 4.7H352c-8.8 0-16-7.2-16-16V102.6c0-4.2 1.7-8.3 4.7-11.3l63.9-63.9c8.1-8.1 5.2-21.8-6-24.2C388.7 1.1 378.5 0 368 0C288.5 0 224 64.5 224 144l0 .8 85.3 85.3c36-9.1 75.8 .5 104 28.7L429 274.5c49-23 83-72.8 83-130.5zM56 432a24 24 0 1 1 48 0 24 24 0 1 1 -48 0z"/></svg></div>
|
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="20" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M78.6 5C69.1-2.4 55.6-1.5 47 7L7 47c-8.5 8.5-9.4 22-2.1 31.6l80 104c4.5 5.9 11.6 9.4 19 9.4h54.1l109 109c-14.7 29-10 65.4 14.3 89.6l112 112c12.5 12.5 32.8 12.5 45.3 0l64-64c12.5-12.5 12.5-32.8 0-45.3l-112-112c-24.2-24.2-60.6-29-89.6-14.3l-109-109V104c0-7.5-3.5-14.5-9.4-19L78.6 5zM19.9 396.1C7.2 408.8 0 426.1 0 444.1C0 481.6 30.4 512 67.9 512c18 0 35.3-7.2 48-19.9L233.7 374.3c-7.8-20.9-9-43.6-3.6-65.1l-61.7-61.7L19.9 396.1zM512 144c0-10.5-1.1-20.7-3.2-30.5c-2.4-11.2-16.1-14.1-24.2-6l-63.9 63.9c-3 3-7.1 4.7-11.3 4.7H352c-8.8 0-16-7.2-16-16V102.6c0-4.2 1.7-8.3 4.7-11.3l63.9-63.9c8.1-8.1 5.2-21.8-6-24.2C388.7 1.1 378.5 0 368 0C288.5 0 224 64.5 224 144l0 .8 85.3 85.3c36-9.1 75.8 .5 104 28.7L429 274.5c49-23 83-72.8 83-130.5zM56 432a24 24 0 1 1 48 0 24 24 0 1 1 -48 0z"/></svg></div>
|
||||||
<div class="pitch-title">Flat-Rate, No Surprises</div>
|
<div class="pitch-title">Flat-Rate, No Surprises</div>
|
||||||
|
</div>
|
||||||
<div class="pitch-desc">Predictable monthly billing with no per-ticket charges — aligned incentives mean we fix things right the first time.</div>
|
<div class="pitch-desc">Predictable monthly billing with no per-ticket charges — aligned incentives mean we fix things right the first time.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pitch-item">
|
<div class="pitch-item">
|
||||||
|
<div class="pitch-head">
|
||||||
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="20" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M64 64c0-17.7-14.3-32-32-32S0 46.3 0 64V400c0 44.2 35.8 80 80 80H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H80c-8.8 0-16-7.2-16-16V64zm406.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L320 210.7l-57.4-57.4c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L240 221.3l57.4 57.4c12.5 12.5 32.8 12.5 45.3 0l128-128z"/></svg></div>
|
<div class="pitch-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="20" height="20" fill="var(--accent)" style="vertical-align:middle;"><path d="M64 64c0-17.7-14.3-32-32-32S0 46.3 0 64V400c0 44.2 35.8 80 80 80H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H80c-8.8 0-16-7.2-16-16V64zm406.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L320 210.7l-57.4-57.4c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L240 221.3l57.4 57.4c12.5 12.5 32.8 12.5 45.3 0l128-128z"/></svg></div>
|
||||||
<div class="pitch-title">Scales With You</div>
|
<div class="pitch-title">Scales With You</div>
|
||||||
|
</div>
|
||||||
<div class="pitch-desc">Add users, endpoints, servers, ZT networking, or VoIP as you grow — one vendor, one invoice, one relationship.</div>
|
<div class="pitch-desc">Add users, endpoints, servers, ZT networking, or VoIP as you grow — one vendor, one invoice, one relationship.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -936,6 +960,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="confirm-modal" id="resetConfirmModal" aria-hidden="true">
|
||||||
|
<div class="confirm-modal-backdrop" onclick="closeResetConfirm()"></div>
|
||||||
|
<div class="confirm-modal-card" role="dialog" aria-modal="true" aria-labelledby="resetConfirmTitle">
|
||||||
|
<div class="confirm-modal-eyebrow">Reset Quote</div>
|
||||||
|
<h2 class="confirm-modal-title" id="resetConfirmTitle">Reset saved quote and return to defaults?</h2>
|
||||||
|
<p class="confirm-modal-copy">This will clear the saved calculator state and generate a fresh quote. Your theme preference will stay the same.</p>
|
||||||
|
<div class="confirm-modal-actions">
|
||||||
|
<button type="button" class="confirm-btn confirm-btn-secondary" id="resetConfirmCancel" onclick="closeResetConfirm()">Cancel</button>
|
||||||
|
<button type="button" class="confirm-btn confirm-btn-danger" onclick="confirmResetQuote()">Yes, Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="SVS-MSP-Calculator.js"></script>
|
<script src="SVS-MSP-Calculator.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ function update() {
|
|||||||
const subParts = [`${users} × ${fmt(baseUserRate)}/user (${byol ? 'BYOL' : 'M365 Incl.'})`];
|
const subParts = [`${users} × ${fmt(baseUserRate)}/user (${byol ? 'BYOL' : 'M365 Incl.'})`];
|
||||||
if (addExtHours) subParts.push(`+ ${fmt(userExt)}/mo ext. hrs`);
|
if (addExtHours) subParts.push(`+ ${fmt(userExt)}/mo ext. hrs`);
|
||||||
if (addPWM) subParts.push(`+ ${fmt(userPWM)}/mo 1Password`);
|
if (addPWM) subParts.push(`+ ${fmt(userPWM)}/mo 1Password`);
|
||||||
if (addINKY) subParts.push(`+ ${fmt(userINKY)}/mo INKY`);
|
if (addINKY) subParts.push(`+ ${fmt(userINKY)}/mo INKY Pro upgrade`);
|
||||||
if (addZT) subParts.push(`+ ${fmt(userZT)}/mo Zero Trust`);
|
if (addZT) subParts.push(`+ ${fmt(userZT)}/mo Zero Trust`);
|
||||||
sub.innerHTML = subParts.join('<br>');
|
sub.innerHTML = subParts.join('<br>');
|
||||||
}
|
}
|
||||||
@@ -376,6 +376,7 @@ function update() {
|
|||||||
if (voipTotal > 0) getEl('sl-voip-val').textContent = fmt(voipTotal);
|
if (voipTotal > 0) getEl('sl-voip-val').textContent = fmt(voipTotal);
|
||||||
const slAdminEl = getEl('sl-admin');
|
const slAdminEl = getEl('sl-admin');
|
||||||
const slAdminValEl = getEl('sl-admin-val');
|
const slAdminValEl = getEl('sl-admin-val');
|
||||||
|
const slAdminSubEl = getEl('sl-admin-sub');
|
||||||
if (adminWaived) {
|
if (adminWaived) {
|
||||||
slAdminEl?.classList.add('sl-admin-waived');
|
slAdminEl?.classList.add('sl-admin-waived');
|
||||||
if (slAdminValEl) slAdminValEl.innerHTML =
|
if (slAdminValEl) slAdminValEl.innerHTML =
|
||||||
@@ -384,6 +385,13 @@ function update() {
|
|||||||
slAdminEl?.classList.remove('sl-admin-waived');
|
slAdminEl?.classList.remove('sl-admin-waived');
|
||||||
if (slAdminValEl) slAdminValEl.textContent = fmt(adminFeeNet);
|
if (slAdminValEl) slAdminValEl.textContent = fmt(adminFeeNet);
|
||||||
}
|
}
|
||||||
|
if (slAdminSubEl) {
|
||||||
|
const adminParts = [`Base ${fmt(siteAdminBase)}/mo`];
|
||||||
|
if (ztActive) adminParts.push(`+ ${fmt(ADMIN_FEE_ZT)}/mo Zero Trust supplement`);
|
||||||
|
if (addPWM && admin1PWM > 0) adminParts.push(`+ ${fmt(admin1PWM)}/mo 1Password admin`);
|
||||||
|
slAdminSubEl.classList.remove('hidden');
|
||||||
|
slAdminSubEl.innerHTML = adminParts.join('<br>');
|
||||||
|
}
|
||||||
|
|
||||||
// MRR + totals — show effective MRR (after term discount) as the headline number
|
// MRR + totals — show effective MRR (after term discount) as the headline number
|
||||||
getEl('mrrDisplay').textContent = fmt(effectiveMrr);
|
getEl('mrrDisplay').textContent = fmt(effectiveMrr);
|
||||||
@@ -546,7 +554,6 @@ function onWaiveToggle() {
|
|||||||
// Calls updateSectionSummaries() to show/hide summary badges.
|
// Calls updateSectionSummaries() to show/hide summary badges.
|
||||||
// Map: section ID → collapsible IDs that should auto-expand when section opens
|
// Map: section ID → collapsible IDs that should auto-expand when section opens
|
||||||
const _sectionCollapsibles = {
|
const _sectionCollapsibles = {
|
||||||
'sec-01': ['adminCovered'],
|
|
||||||
'sec-02': ['userIncluded', 'addonsA'],
|
'sec-02': ['userIncluded', 'addonsA'],
|
||||||
'sec-03': ['endpointIncluded', 'addonsB'],
|
'sec-03': ['endpointIncluded', 'addonsB'],
|
||||||
'sec-04': ['serverIncluded'],
|
'sec-04': ['serverIncluded'],
|
||||||
@@ -849,6 +856,7 @@ function stepInput(id, delta) {
|
|||||||
|
|
||||||
// --- AUTO-SAVE / RESTORE ---
|
// --- AUTO-SAVE / RESTORE ---
|
||||||
const SAVE_KEY = 'svs-msp-quote-v1';
|
const SAVE_KEY = 'svs-msp-quote-v1';
|
||||||
|
const QUOTE_REF_KEY = 'svs-msp-quote-ref';
|
||||||
|
|
||||||
function saveState() {
|
function saveState() {
|
||||||
try {
|
try {
|
||||||
@@ -886,6 +894,50 @@ function debouncedSave() {
|
|||||||
_saveTimer = setTimeout(saveState, 400);
|
_saveTimer = setTimeout(saveState, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncBodyScrollLock() {
|
||||||
|
const panelOpen = document.getElementById('mobileQuotePanel')?.classList.contains('open');
|
||||||
|
const modalOpen = document.getElementById('resetConfirmModal')?.classList.contains('open');
|
||||||
|
document.body.style.overflow = (panelOpen || modalOpen) ? 'hidden' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openResetConfirm() {
|
||||||
|
const modal = document.getElementById('resetConfirmModal');
|
||||||
|
if (!modal) return;
|
||||||
|
modal.classList.add('open');
|
||||||
|
modal.setAttribute('aria-hidden', 'false');
|
||||||
|
syncBodyScrollLock();
|
||||||
|
document.getElementById('resetConfirmCancel')?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeResetConfirm() {
|
||||||
|
const modal = document.getElementById('resetConfirmModal');
|
||||||
|
if (!modal) return;
|
||||||
|
modal.classList.remove('open');
|
||||||
|
modal.setAttribute('aria-hidden', 'true');
|
||||||
|
syncBodyScrollLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmResetQuote() {
|
||||||
|
clearTimeout(_saveTimer);
|
||||||
|
try {
|
||||||
|
localStorage.removeItem(SAVE_KEY);
|
||||||
|
localStorage.removeItem(QUOTE_REF_KEY);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('confirmResetQuote: failed to clear saved quote state', e);
|
||||||
|
}
|
||||||
|
closeResetConfirm();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
const modalOpen = document.getElementById('resetConfirmModal')?.classList.contains('open');
|
||||||
|
if (e.key === 'Escape' && modalOpen) {
|
||||||
|
closeResetConfirm();
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ── restoreState() ───────────────────────────────────────────────
|
// ── restoreState() ───────────────────────────────────────────────
|
||||||
// Restores form state from localStorage on page load.
|
// Restores form state from localStorage on page load.
|
||||||
// SAVE_KEY = 'svs-msp-quote-v1'.
|
// SAVE_KEY = 'svs-msp-quote-v1'.
|
||||||
@@ -966,7 +1018,7 @@ function printInvoice() {
|
|||||||
row(`User Package — ${pkg}`, `${q.users} user${q.users!==1?'s':''} × ${fmt(q.baseUserRate)}/mo`, fmt(q.userBase));
|
row(`User Package — ${pkg}`, `${q.users} user${q.users!==1?'s':''} × ${fmt(q.baseUserRate)}/mo`, fmt(q.userBase));
|
||||||
if (q.userExt > 0) row(`↳ Extended Hours (+${fmt(ADDON_EXT_HOURS)}/user)`, '', fmt(q.userExt), true);
|
if (q.userExt > 0) row(`↳ Extended Hours (+${fmt(ADDON_EXT_HOURS)}/user)`, '', fmt(q.userExt), true);
|
||||||
if (q.userPWM > 0) row(`↳ 1Password Business (+${fmt(ADDON_1PASSWORD)}/user)`, '', fmt(q.userPWM), true);
|
if (q.userPWM > 0) row(`↳ 1Password Business (+${fmt(ADDON_1PASSWORD)}/user)`, '', fmt(q.userPWM), true);
|
||||||
if (q.userINKY > 0) row(`↳ Inky Email Security (+${fmt(ADDON_INKY)}/user)`, '', fmt(q.userINKY), true);
|
if (q.userINKY > 0) row(`↳ INKY Pro Upgrade (+${fmt(ADDON_INKY)}/user)`, '', fmt(q.userINKY), true);
|
||||||
if (q.userZT > 0) row(`↳ Zero Trust User (+${fmt(ADDON_ZERO_TRUST_USER)}/user)`, '', fmt(q.userZT), true);
|
if (q.userZT > 0) row(`↳ Zero Trust User (+${fmt(ADDON_ZERO_TRUST_USER)}/user)`, '', fmt(q.userZT), true);
|
||||||
}
|
}
|
||||||
if (q.endpoints > 0) {
|
if (q.endpoints > 0) {
|
||||||
@@ -1014,7 +1066,7 @@ function printInvoice() {
|
|||||||
feat('Licensing Model', true, q.byol ? 'BYOL — Bring Your Own License' : 'M365 Premium Included');
|
feat('Licensing Model', true, q.byol ? 'BYOL — Bring Your Own License' : 'M365 Premium Included');
|
||||||
feat('Extended Help Desk Hours', q.addExtHours, q.addExtHours ? `+${fmt(ADDON_EXT_HOURS)}/user/mo` : '');
|
feat('Extended Help Desk Hours', q.addExtHours, q.addExtHours ? `+${fmt(ADDON_EXT_HOURS)}/user/mo` : '');
|
||||||
feat('1Password Business', q.addPWM, q.addPWM ? `+${fmt(ADDON_1PASSWORD)}/user/mo` : '');
|
feat('1Password Business', q.addPWM, q.addPWM ? `+${fmt(ADDON_1PASSWORD)}/user/mo` : '');
|
||||||
feat('INKY Pro Email Security', q.addINKY, q.addINKY ? `+${fmt(ADDON_INKY)}/user/mo` : '');
|
feat('INKY Pro Upgrade', q.addINKY, q.addINKY ? `+${fmt(ADDON_INKY)}/user/mo` : '');
|
||||||
feat('Zero Trust User Access', q.addZT, q.addZT ? `+${fmt(ADDON_ZERO_TRUST_USER)}/user/mo` : '');
|
feat('Zero Trust User Access', q.addZT, q.addZT ? `+${fmt(ADDON_ZERO_TRUST_USER)}/user/mo` : '');
|
||||||
feat('USB Device Blocking', q.addUSB, q.addUSB ? `+${fmt(ADDON_USB_BLOCKING)}/endpoint/mo` : '');
|
feat('USB Device Blocking', q.addUSB, q.addUSB ? `+${fmt(ADDON_USB_BLOCKING)}/endpoint/mo` : '');
|
||||||
feat('Bare Metal Backup', q.addBMB, q.addBMB ? `+${fmt(ADDON_BARE_METAL_BACKUP)}/endpoint/mo` : '');
|
feat('Bare Metal Backup', q.addBMB, q.addBMB ? `+${fmt(ADDON_BARE_METAL_BACKUP)}/endpoint/mo` : '');
|
||||||
@@ -1280,7 +1332,7 @@ async function initQuote() {
|
|||||||
const year = now.getFullYear();
|
const year = now.getFullYear();
|
||||||
const month = months[now.getMonth()];
|
const month = months[now.getMonth()];
|
||||||
const dateStr = `${year}${String(now.getMonth()+1).padStart(2,'0')}${String(now.getDate()).padStart(2,'0')}`;
|
const dateStr = `${year}${String(now.getMonth()+1).padStart(2,'0')}${String(now.getDate()).padStart(2,'0')}`;
|
||||||
const savedRef = localStorage.getItem('svs-msp-quote-ref');
|
const savedRef = localStorage.getItem(QUOTE_REF_KEY);
|
||||||
let quoteRef;
|
let quoteRef;
|
||||||
if (savedRef) {
|
if (savedRef) {
|
||||||
// Regenerate if the baked-in date is older than 30 days
|
// Regenerate if the baked-in date is older than 30 days
|
||||||
@@ -1289,13 +1341,13 @@ async function initQuote() {
|
|||||||
const ageMs = refDate ? now - refDate : Infinity;
|
const ageMs = refDate ? now - refDate : Infinity;
|
||||||
if (ageMs > 30 * 24 * 60 * 60 * 1000) {
|
if (ageMs > 30 * 24 * 60 * 60 * 1000) {
|
||||||
quoteRef = `SVS-${dateStr}-${String(Math.floor(Math.random()*9000)+1000)}`;
|
quoteRef = `SVS-${dateStr}-${String(Math.floor(Math.random()*9000)+1000)}`;
|
||||||
localStorage.setItem('svs-msp-quote-ref', quoteRef);
|
localStorage.setItem(QUOTE_REF_KEY, quoteRef);
|
||||||
} else {
|
} else {
|
||||||
quoteRef = savedRef;
|
quoteRef = savedRef;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quoteRef = `SVS-${dateStr}-${String(Math.floor(Math.random()*9000)+1000)}`;
|
quoteRef = `SVS-${dateStr}-${String(Math.floor(Math.random()*9000)+1000)}`;
|
||||||
localStorage.setItem('svs-msp-quote-ref', quoteRef);
|
localStorage.setItem(QUOTE_REF_KEY, quoteRef);
|
||||||
}
|
}
|
||||||
const quoteRefEl = document.getElementById('quoteRef');
|
const quoteRefEl = document.getElementById('quoteRef');
|
||||||
if (quoteRefEl) quoteRefEl.textContent = quoteRef;
|
if (quoteRefEl) quoteRefEl.textContent = quoteRef;
|
||||||
@@ -1341,7 +1393,7 @@ initQuote();
|
|||||||
var panel = document.getElementById('mobileQuotePanel');
|
var panel = document.getElementById('mobileQuotePanel');
|
||||||
if (panel) {
|
if (panel) {
|
||||||
panel.classList.add('open');
|
panel.classList.add('open');
|
||||||
document.body.style.overflow = 'hidden';
|
syncBodyScrollLock();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1349,7 +1401,7 @@ initQuote();
|
|||||||
var panel = document.getElementById('mobileQuotePanel');
|
var panel = document.getElementById('mobileQuotePanel');
|
||||||
if (panel) {
|
if (panel) {
|
||||||
panel.classList.remove('open');
|
panel.classList.remove('open');
|
||||||
document.body.style.overflow = '';
|
syncBodyScrollLock();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1423,10 +1475,12 @@ initQuote();
|
|||||||
syncEl('nudgeCounter');
|
syncEl('nudgeCounter');
|
||||||
syncEl('sl-users-sub');
|
syncEl('sl-users-sub');
|
||||||
syncEl('sl-endpoints-sub');
|
syncEl('sl-endpoints-sub');
|
||||||
|
syncEl('sl-admin-sub');
|
||||||
syncClass('sl-users');
|
syncClass('sl-users');
|
||||||
syncClass('sl-users-sub');
|
syncClass('sl-users-sub');
|
||||||
syncClass('sl-endpoints');
|
syncClass('sl-endpoints');
|
||||||
syncClass('sl-endpoints-sub');
|
syncClass('sl-endpoints-sub');
|
||||||
|
syncClass('sl-admin-sub');
|
||||||
syncClass('sl-servers');
|
syncClass('sl-servers');
|
||||||
syncClass('sl-zt');
|
syncClass('sl-zt');
|
||||||
syncClass('sl-voip');
|
syncClass('sl-voip');
|
||||||
@@ -1452,6 +1506,7 @@ initQuote();
|
|||||||
syncEl('adminWaivedAmt');
|
syncEl('adminWaivedAmt');
|
||||||
syncStyle('sl-users-sub');
|
syncStyle('sl-users-sub');
|
||||||
syncStyle('sl-endpoints-sub');
|
syncStyle('sl-endpoints-sub');
|
||||||
|
syncStyle('sl-admin-sub');
|
||||||
syncStyle('perUserRow');
|
syncStyle('perUserRow');
|
||||||
syncChecked('hstToggle');
|
syncChecked('hstToggle');
|
||||||
// Pill MRR — show effective MRR with label
|
// Pill MRR — show effective MRR with label
|
||||||
|
|||||||
Reference in New Issue
Block a user