Files
svsmspcalc/SVS-MSP-Calculator.css
2026-03-12 00:47:18 -04:00

1926 lines
72 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.
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* ── FOCUS VISIBLE ──────────────────────────────────────────────
Single rule covers all interactive elements — native inputs,
custom div toggles (section headers, collapsible headers),
addon rows, tier segments, and the theme toggle button.
Uses :focus-visible so mouse clicks don't show the ring.
─────────────────────────────────────────────────────────────── */
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
/* Suppress the default outline on elements we've styled explicitly */
.num-input:focus-visible,
.client-input:focus-visible,
.qs-fee-input:focus-visible,
.savings-input-row input:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(45,122,168,0.25);
}
/* ── DESIGN TOKENS ─────────────────────────────────────────────
Single source of truth for all colours. Edit here, not inline.
─────────────────────────────────────────────────────────────── */
:root {
--ink: #ddd8d0;
--paper: #22201d;
--accent: #2d7aa8;
--muted: #b0a898; /* lifted slightly — #a09890 was too faint on dark cards */
--border: #3a3630;
--card: #2a2722;
--green: #3ab870;
--amber: #e8920f;
}
body {
background: var(--paper);
color: var(--ink);
font-family: 'Lato', sans-serif;
font-size: 16px;
line-height: 1.75;
min-height: 100vh;
}
/* ── TOP BAR ────────────────────────────────────────────────────
Sticky header. z-index:100 sits below mobile panel (z:300)
and mobile pill (z:200). Background is --ink (cream) not --paper.
Contains: SVS logo SVG (inline) | quote ref + date (DM Mono).
─────────────────────────────────────────────────────────────── */
.top-bar {
position: sticky;
top: 0;
z-index: 100;
background: var(--ink);
border-bottom: 2px solid var(--accent);
padding: 14px 0;
display: flex;
justify-content: center;
}
.top-bar-inner {
width: 100%;
max-width: 1600px;
padding: 0 clamp(20px,2vw,40px);
display: flex;
align-items: center;
justify-content: space-between;
}
.top-bar-logo { margin-left: 70px; flex-shrink: 0; }
.top-bar-right {
font-family: 'DM Mono', monospace;
font-size: 12px;
letter-spacing: 0.07em;
color: #555;
text-align: right;
line-height: 1.6;
margin-left: auto;
}
/* ── THEME TOGGLE BUTTON ────────────────────────────────────────
Sits to the right of the quote ref/date in .top-bar-inner.
Slightly darker chip vs the cream top-bar bg so it reads as
a distinct control, not noise. Works on both theme top-bars.
─────────────────────────────────────────────────────────────── */
.theme-toggle-btn {
background: rgba(0, 0, 0, 0.1); /* ~#c9c5bc chip on cream bar */
border: none;
border-radius: 8px;
width: 36px;
height: 36px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: #3a3632;
transition: background 0.15s;
flex-shrink: 0;
margin-left: 14px;
}
.theme-toggle-btn:hover { background: rgba(0, 0, 0, 0.17); }
.theme-toggle-btn:active { background: rgba(0, 0, 0, 0.23); }
.theme-toggle-btn svg { display: block; }
/* ── PAGE LAYOUT ────────────────────────────────────────────────
.outer — CSS grid, 3fr main / 2fr sidebar, max 1600px
.main-col — left: sections IVI stacked vertically
.side-col — right: sticky sidebar (desktop only; hidden ≤1100px)
Roman numeral .section-num floats LEFT outside .section via
position:absolute + negative left offset (left: -96px).
This requires .section to have position:relative + margin-left:96px.
─────────────────────────────────────────────────────────────── */
.outer {
display: grid;
grid-template-columns: 3fr 2fr;
gap: 52px;
padding: 52px clamp(20px,2vw,40px) 52px;
max-width: 1600px;
margin: 0 auto;
align-items: start;
}
.main-col { display: flex; flex-direction: column; gap: 28px; }
.side-col { position: sticky; top: 35px; z-index: 10; align-self: start; }
/* ── CLIENT BAR ─────────────────────────────────────────────────
Lives inside .main-col, above section I.
padding-left:96px aligns "PREPARED FOR" with section card edges
(matching the 96px margin-left on .section).
.client-input — contenteditable-style text input; oninput calls
update() which syncs clientNameDisplay in sidebar.
─────────────────────────────────────────────────────────────── */
.client-bar {
padding: 32px 0 32px 96px;
}
.client-label {
font-family: 'DM Mono', monospace;
font-size: 13px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 10px;
}
.client-input {
background: transparent;
border: none;
border-bottom: 1px solid var(--border);
color: var(--accent);
font-family: 'Poppins', sans-serif;
font-weight: 600;
font-size: 30px;
width: 100%;
max-width: 480px;
outline: none;
padding: 2px 0;
}
.client-input::placeholder { color: var(--muted); opacity: 0.6; font-weight: 400; }
/* ── SECTION CARDS (IVI) ───────────────────────────────────────
Each section = position:relative card with:
.section-num — absolute, floats left outside card (Cinzel)
.section-header — flex row: title-block | summary badge | chevron
.section-body — collapsible content (overflow:hidden, JS toggle)
JS toggleSection(id) adds/removes .sec-open class on .section.
.sec-open .sec-chevron rotates 180deg (down→up arrow).
.sec-summary-badge is shown/hidden by setSummary() in update().
─────────────────────────────────────────────────────────────── */
.section {
position: relative;
margin-left: 96px;
border-radius: 12px;
border: 1px solid var(--border);
background: #272420; /* elevated above paper #22201d — was #1e1c18 (sunken) */
padding: 32px 36px 36px;
}
.main-col > .section:first-of-type { margin-top: 24px; }
.section-header {
display: flex;
align-items: flex-start;
gap: 12px;
margin-bottom: 32px;
}
.section:not(.sec-open) .section-header { margin-bottom: 0; }
.section-num {
font-family: 'Cinzel', serif;
font-weight: 700;
font-size: 62px;
line-height: 1;
color: var(--border);
flex-shrink: 0;
width: 80px;
user-select: none;
position: absolute;
left: -96px;
top: 32px;
text-align: right;
}
.section-title-block { flex: 1; min-width: 0; }
.section-title {
font-family: 'Poppins', sans-serif;
font-size: 24px;
font-weight: 600;
color: var(--ink);
line-height: 1.3;
word-break: break-word;
}
.section-title-tag { font-size: 15px; font-weight: 400; opacity: 0.6; }
.section-subtitle {
font-size: 14px;
color: var(--muted);
margin-top: 6px;
line-height: 1.55;
}
.section-badge {
font-family: 'DM Mono', monospace;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 3px 8px;
border: 1px solid var(--border);
border-radius: 2px;
color: var(--muted);
display: inline-block;
margin-top: 8px;
}
.section-toggle { cursor: pointer; user-select: none; }
.sec-chevron {
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
transition: transform 0.25s ease, color 0.15s;
flex-shrink: 0;
transform: rotate(0deg);
width: 34px;
height: 34px;
background: rgba(255,255,255,0.05);
border-radius: 6px;
margin-top: 2px;
}
.sec-open .sec-chevron { transform: rotate(180deg); color: var(--ink); background: rgba(255,255,255,0.08); }
.section-toggle:hover .sec-chevron { color: var(--ink); background: rgba(255,255,255,0.08); }
.sec-chevron svg { display: block; }
.section-body { overflow: hidden; }
/* ── SECTION SUMMARY BADGE ──────────────────────────────────────
Shown only when section is COLLAPSED (display:none by default).
JS: setSummary(id, text) sets textContent + display:inline-block
when collapsed(secId) && !!text. Hidden when section is open.
On mobile (≤600px) placed in grid col 2 row 1 (top-right of header).
─────────────────────────────────────────────────────────────── */
.sec-summary-badge {
display: none;
font-family: 'DM Mono', monospace;
font-size: 13px;
letter-spacing: 0.08em;
color: var(--accent);
background: rgba(45,122,168,0.12);
border: 1px solid rgba(45,122,168,0.3);
border-radius: 6px;
padding: 5px 11px;
white-space: nowrap;
flex-shrink: 0;
margin-top: 2px;
}
/* ── COLLAPSED SECTION COUNTER (sec-02/03/04 when collapsed) ───
Sits inside .section-title-block below .section-badge.
Two square .sec-count-btn buttons with a small gap between them.
Visible only when the section is collapsed (not .sec-open).
Buttons call stepCount() which stops propagation.
─────────────────────────────────────────────────────────────── */
.sec-collapsed-counter {
display: none;
align-items: center;
gap: 6px;
margin-top: 12px;
}
.section:not(.sec-open) .sec-collapsed-counter {
display: flex;
}
.sec-count-btn {
width: 44px;
height: 44px;
background: var(--card);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--muted);
font-size: 22px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
flex-shrink: 0;
user-select: none;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.sec-count-btn:hover { background: var(--border); color: var(--ink); }
.sec-count-btn:active { background: var(--accent); color: #fff; border-color: var(--accent); }
/* ── PILL TOGGLE (Section II — M365 vs BYOL) ───────────────────
CSS-only toggle using hidden radio inputs + adjacent label styling.
input:checked + label gets accent background.
JS reads: document.getElementById("rateBYOL").checked
On mobile (≤600px) stacks vertically (grid-template-columns:1fr).
─────────────────────────────────────────────────────────────── */
.pill-toggle {
display: grid;
grid-template-columns: 1fr 1fr;
border: 1px solid var(--border);
border-radius: 6px;
overflow: hidden;
margin-bottom: 20px;
}
.pill-toggle input[type=radio] { display: none; }
.pill-toggle label {
padding: 18px 20px;
cursor: pointer;
border-right: 1px solid var(--border);
transition: background 0.15s;
display: flex;
flex-direction: column;
gap: 6px;
}
.pill-toggle label:last-child { border-right: none; }
.pill-toggle input:checked + label {
background: var(--accent);
color: #fff;
}
.pill-toggle input:checked + label .pill-price { color: #fff; }
.pill-toggle input:checked + label .pill-desc { color: rgba(255,255,255,0.85); }
.pill-toggle label .pill-price {
font-family: 'DM Mono', monospace;
font-size: 20px;
font-weight: 500;
color: var(--ink);
}
.pill-toggle label .pill-price small { font-size: 14px; opacity: 0.6; }
.pill-toggle label .pill-desc { font-size: 14px; opacity: 0.7; }
/* ── TIER SEGMENT (Section VI — VoIP Basic/Standard/Premium) ───
3-column radio toggle. JS activateTier(tier) adds .active class.
.active overrides text colours to white on accent background.
Rates: basic $28 | standard $35 | premium $45 /seat/mo.
─────────────────────────────────────────────────────────────── */
.tier-seg-wrap {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
border: 1px solid var(--border);
border-radius: 6px;
overflow: hidden;
margin-bottom: 20px;
}
.tier-seg-wrap input[type=radio] { display: none; }
.tier-seg {
padding: 16px 10px;
cursor: pointer;
border-right: 1px solid var(--border);
text-align: center;
transition: background 0.15s;
}
.tier-seg:last-of-type { border-right: none; }
.tier-seg.active { background: var(--accent); }
.tier-seg .tier-name {
font-family: 'DM Mono', monospace;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--muted);
}
.tier-seg.active .tier-name { color: #fff; }
.tier-seg .tier-price {
font-family: 'DM Mono', monospace;
font-size: 22px;
color: var(--ink);
margin-top: 3px;
}
.tier-seg.active .tier-price { color: #fff; }
.tier-seg .tier-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.tier-seg.active .tier-sub { color: rgba(255,255,255,0.7); }
/* ── INNER COLLAPSIBLES (What's Included / Add-Ons) ────────────
Separate from section-level collapse. JS toggleCollapsible(id)
toggles .open on .collapsible-body and swaps +/- on toggle icon.
.addon-preview-pill pills shown when collapsed (JS toggleCollapsible).
─────────────────────────────────────────────────────────────── */
.collapsible-header {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
padding: 14px 0;
border-top: 1px solid var(--border);
user-select: none;
}
.collapsible-header--mt16 { margin-top: 16px; }
.collapsible-header--addon { flex-wrap: wrap; gap: 4px; margin-top: 8px; }
.collapsible-toggle {
color: var(--accent);
width: 22px;
flex-shrink: 0;
display: flex;
align-items: center;
transition: transform 0.25s ease;
}
.collapsible-toggle.open { transform: rotate(180deg); }
.collapsible-toggle svg { display: block; }
.collapsible-label {
font-family: 'DM Mono', monospace;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--muted);
}
.addon-preview-wrap {
display: flex; flex-wrap: wrap; gap: 5px;
width: 100%; padding-left: 28px; margin-top: 6px;
}
.addon-preview-pill {
font-family: 'DM Mono', monospace;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--muted);
border: 1px solid var(--border);
border-radius: 2px;
padding: 3px 8px;
white-space: nowrap;
}
.collapsible-body {
padding: 16px 0 20px 28px;
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.3s ease, opacity 0.2s ease;
}
.collapsible-body.open {
max-height: 2000px;
opacity: 1;
}
/* FEATURE LIST */
.feature-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 8px;
}
.feature-list li {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
padding-left: 18px;
position: relative;
}
.feature-list li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--green);
font-size: 11px;
}
/* ── NUMBER INPUTS ──────────────────────────────────────────────
.input-row — flex row: label left, .num-input right
.num-input — DM Mono, text-align:center, oninput→update()
On mobile (≤600px) input-row stacks (flex-direction:column)
and num-input goes full width.
─────────────────────────────────────────────────────────────── */
.input-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 0;
border-top: 1px solid var(--border);
}
.input-label { font-family: 'Lato', sans-serif; font-weight: 700; font-size: 16px; }
.input-sublabel { font-size: 13px; color: var(--muted); margin-top: 5px; line-height: 1.55; }
.num-stepper {
display: flex;
align-items: stretch;
flex-shrink: 0;
}
.step-btn {
background: var(--card);
border: 1px solid var(--border);
color: var(--muted);
font-size: 20px;
font-weight: 400;
width: 36px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.12s, color 0.12s;
flex-shrink: 0;
user-select: none;
line-height: 1;
}
.step-btn:first-child { border-radius: 4px 0 0 4px; border-right: none; }
.step-btn:last-child { border-radius: 0 4px 4px 0; border-left: none; }
.step-btn:hover { background: var(--border); color: var(--ink); }
.step-btn:active { background: var(--accent); color: #fff; border-color: var(--accent); }
.num-input {
background: var(--card);
border: 1px solid var(--border);
border-radius: 0;
color: var(--ink);
font-family: 'DM Mono', monospace;
font-size: 22px;
width: 72px;
text-align: center;
padding: 8px;
outline: none;
}
.num-input:focus { border-color: var(--accent); }
.num-input::-webkit-inner-spin-button,
.num-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.num-input[type=number] { -moz-appearance: textfield; }
/* ── ADDON ROWS ─────────────────────────────────────────────────
.addon-row — clickable label wrapping a hidden checkbox.
JS toggleAddon(cbId, rowId) toggles .selected class on row.
.selected gets accent-tinted background + border.
Price is right-aligned via margin-left:auto on .addon-price.
─────────────────────────────────────────────────────────────── */
.addon-grid { display: flex; flex-direction: column; gap: 4px; }
.addon-row {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 13px 14px;
border-radius: 8px;
cursor: pointer;
border: 1px solid transparent;
transition: background 0.12s, border-color 0.12s;
}
.addon-row:hover { background: var(--card); }
.addon-row input[type=checkbox] { margin-top: 3px; accent-color: var(--accent); flex-shrink: 0; }
.addon-name { font-family: 'Lato', sans-serif; font-weight: 700; font-size: 15px; }
.addon-price {
font-family: 'DM Mono', monospace;
font-size: 14px;
color: var(--accent);
white-space: nowrap;
margin-left: auto;
flex-shrink: 0;
}
.addon-desc { font-size: 13px; color: var(--muted); margin-top: 5px; line-height: 1.6; }
/* ── BYOL CALLOUTS (Section II) ────────────────────────────────
Shown/hidden by JS based on BYOL toggle state.
#byolCalloutGreen — M365 savings message (shown when M365 selected)
#byolCalloutRed — missed savings warning (shown when BYOL selected)
display:flex + align-items:flex-start keeps icon pinned to
first line; text wrapped in <span> so it never flows under icon.
─────────────────────────────────────────────────────────────── */
.callout-green {
background: #162e22; /* dark muted green — was #0d2016 (near-black, unreadable as green) */
border: 1px solid #245840;
border-radius: 6px;
padding: 14px 18px;
font-family: 'DM Mono', monospace;
font-size: 14px;
color: var(--green);
margin-bottom: 24px;
line-height: 1.65;
display: flex;
align-items: flex-start;
gap: 9px;
}
.callout-red {
background: #2a1319; /* dark muted red — was #200d10 (near-black) */
border: 1px solid #5e2830;
border-radius: 6px;
padding: 14px 18px;
font-family: 'DM Mono', monospace;
font-size: 14px;
color: #e87882; /* slightly lighter than #e06070 for better contrast on dark red bg */
margin-bottom: 24px;
line-height: 1.65;
display: flex;
align-items: flex-start;
gap: 9px;
}
.hidden { display: none !important; }
/* ── ADMIN FEE PROGRESS BAR (Section I) ────────────────────────
Shows progress toward $650 engagement threshold.
JS: progressEl width% = (baseSubtotal / ADMIN_FEE_MINIMUM) * 100
baseSubtotal = users + endpoints + servers (NOT VoIP or ZT).
Turns green at 100% (threshold met), stays blue below.
─────────────────────────────────────────────────────────────── */
.progress-wrap { margin: 16px 0 10px; }
.progress-label {
font-family: 'DM Mono', monospace;
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
display: flex;
justify-content: space-between;
margin-bottom: 6px;
}
.progress-track {
height: 7px;
background: var(--border);
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
border-radius: 3px;
background: var(--accent);
transition: width 0.3s ease, background 0.3s;
}
/* ── ADMIN FEE BREAKDOWN TABLE (Section I) ─────────────────────
Shows: Base Site Admin | ZT Supplement (if active) | Total.
.fee-total row has top border separator and bold text.
All values rendered by update() via getEl('sl-admin-val') etc.
─────────────────────────────────────────────────────────────── */
.fee-table { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 14px; }
.fee-table td { padding: 8px 0; color: var(--muted); }
.fee-table td:last-child { text-align: right; font-family: 'DM Mono', monospace; color: var(--ink); }
.fee-table tr.fee-total td { border-top: 1px solid var(--border); padding-top: 14px; color: var(--ink); font-weight: 600; }
/* ── FEATURE CARDS (Section I — What's Covered) ────────────────
Static content — 8 cards in single-column grid.
Each card has icon (inline SVG) + title (Poppins) + desc (Lato).
Not dynamically rendered; content is hard-coded in HTML.
─────────────────────────────────────────────────────────────── */
.feature-card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
margin-top: 16px;
}
.feature-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 14px 16px;
}
.feature-card-title { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 14px; margin-bottom: 5px; display:flex; align-items:center; }
.feature-card-desc { font-size: 13px; color: var(--muted); line-height: 1.65; }
/* ── SIDEBAR (Desktop only, ≤1100px hidden) ─────────────────────
.sidebar-header — accent blue, shows "SVS MSP — LIVE QUOTE" + client name
.sidebar-body — all pricing lines, MRR total, notes, VS comparison,
nudge banner, export button
.sidebar-line — each service line (icon + label + value)
.sidebar-mrr — large Poppins 48px MRR total
IMPORTANT: nudgeBanner MUST live inside .sidebar-body or it will
be clipped when sidebar collapses. Do not add </div> before it.
On mobile: sidebar is hidden; a duplicate (_m IDs) lives inside
.mobile-panel-sheet and is synced by update() via syncEl/syncClass.
─────────────────────────────────────────────────────────────── */
.sidebar {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
margin-top: 100px;
}
.sidebar-header {
padding: 20px 24px;
background: var(--accent);
}
.sidebar-title {
font-family: 'DM Mono', monospace;
font-size: 12px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(255,255,255,0.75);
margin-bottom: 4px;
}
.sidebar-client {
font-family: 'Poppins', sans-serif;
font-weight: 600;
font-size: 22px;
color: #fff;
line-height: 1.25;
}
.sidebar-client.placeholder { color: rgba(255,255,255,0.35); font-weight: 400; font-style: italic; }
.sidebar-body { padding: 24px; }
.sidebar-line {
display: flex;
justify-content: space-between;
align-items: baseline;
font-size: 14px;
color: var(--muted);
padding: 8px 0;
border-bottom: 1px solid var(--border);
}
.sidebar-line .val {
font-family: 'DM Mono', monospace;
color: var(--ink);
font-size: 14px;
}
.sidebar-line .lbl-icon { margin-right: 5px; }
.sidebar-mrr-label {
font-family: 'DM Mono', monospace;
font-size: 13px;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
margin-top: 24px;
margin-bottom: 6px;
}
.sidebar-mrr {
font-family: 'Poppins', sans-serif;
font-weight: 700;
font-size: 48px;
color: var(--ink);
line-height: 1;
margin-bottom: 16px;
}
.sidebar-note {
font-size: 13px;
color: var(--muted);
line-height: 1.65;
padding: 6px 0;
}
.sidebar-note strong { color: var(--ink); }
/* ── VS IN-HOUSE COMPARISON ─────────────────────────────────────
Shown only when users > 0 OR endpoints > 0 (JS toggles .hidden).
Compares SVS MRR (annualised) vs 1-person Ottawa IT hire ($85K+tools)
and 5-person team ($420K+tools). Savings rows turn amber if SVS
costs MORE than the comparison (rare at low seat counts).
updateVsComparison(q) renders this section in update().
─────────────────────────────────────────────────────────────── */
.vs-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.vs-table td { padding: 8px 6px; vertical-align: middle; }
.vs-table td:last-child { text-align: right; font-family: 'DM Mono', monospace; white-space: nowrap; }
.vs-table tr:first-child td { padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.vs-table tr:nth-child(2) td,
.vs-table tr:nth-child(4) td { padding-top: 14px; }
.vs-save-row td { padding: 9px 12px; font-size: 12px; font-family: 'DM Mono', monospace; letter-spacing: 0.05em; }
.vs-save-row td:first-child { border-radius: 6px 0 0 6px; }
.vs-save-row td:last-child { border-radius: 0 6px 6px 0; }
.vs-label {
font-family: 'DM Mono', monospace;
font-size: 10px;
letter-spacing: 0.10em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.vs-label::after { content: ''; flex: 1; height: 1px; background: var(--border); }
/* ── INSIGHT NUDGE BANNER ───────────────────────────────────────
Contextual sales insight shown at bottom of sidebar.
Conditions (evaluated in update() → renderNudge()):
amber — ZT active
green — BYOL selected + users > 0
green — PWM not selected + users > 0
Auto-rotates every 30s via startNudgeRotation() (setInterval).
Manual nav via cycleNudge(dir) — does NOT reset the timer.
.nudge-nav-btn — SVG chevron pills ( ), hidden when only 1 nudge.
BOTH #nudgeBanner and #nudgeBanner_m are updated by renderNudge()
via applyNudge('') and applyNudge('_m').
nudgeBanner MUST stay inside .sidebar-body div.
─────────────────────────────────────────────────────────────── */
.nudge-banner {
margin: 0;
padding: 18px 24px;
font-size: 15px;
line-height: 1.7;
border-top: 1px solid var(--border);
min-height: 130px;
box-sizing: border-box;
}
.nudge-banner.amber {
background: #2a1e06; /* warm amber-tinted dark — was #1f1500 (near-black) */
color: var(--amber); /* use token — was hardcoded #d4901a */
border-left: 3px solid var(--amber);
}
.nudge-banner.green {
background: #162e22; /* match callout-green — was #1a2e20 */
color: var(--green); /* use token — was off-token #3dc472 */
border-left: 3px solid var(--green);
}
.nudge-banner-label {
font-family: 'DM Mono', monospace;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.1em;
opacity: 1;
display: block;
margin-bottom: 8px;
}
#nudgeCounter {
font-size: 12px;
opacity: 0.55;
}
.nudge-nav-btn {
background: rgba(255,255,255,0.08);
border: none;
cursor: pointer;
padding: 0;
width: 28px;
height: 28px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
color: inherit;
flex-shrink: 0;
transition: background 0.15s;
}
.nudge-nav-btn:hover { background: rgba(255,255,255,0.15); }
.nudge-nav-btn svg { display: block; }
/* ── QUOTE SETTINGS BAR ─────────────────────────────────────────
Sits below the client bar, above Section I.
Left: contract term 3-way toggle.
Right: HST checkbox + one-time fee input.
padding-left:96px aligns with section card edges.
─────────────────────────────────────────────────────────────── */
/* ── SECTIONS TOOLBAR (Collapse All / Expand All) ───────────────── */
.sections-toolbar {
display: flex;
justify-content: flex-end;
margin-left: 96px;
margin-bottom: 10px;
}
.btn-toggle-all {
font-family: 'DM Mono', monospace;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
background: none;
border: 1px solid var(--border);
border-radius: 6px;
padding: 5px 14px;
cursor: pointer;
transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.btn-toggle-all:hover {
color: var(--ink);
border-color: var(--accent);
background: rgba(45, 122, 168, 0.07);
}
.quote-settings-bar {
margin-left: 96px;
padding: 18px 24px 20px 24px;
display: flex;
align-items: stretch;
gap: 0;
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.qs-group {
display: flex;
flex-direction: column;
gap: 8px;
flex: 1;
min-width: 260px;
padding: 0 24px 0 0;
}
.qs-label {
font-family: 'DM Mono', monospace;
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
}
.qs-term-wrap { margin-bottom: 0; }
.qs-term-wrap .tier-seg { padding: 10px 8px; }
.qs-term-wrap .tier-name { font-size: 12px; }
.qs-term-wrap .tier-price { display: none; }
/* Best Value badge on 24-month */
.qs-best-badge {
display: inline-block;
font-family: 'DM Mono', monospace;
font-size: 9px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--green);
background: rgba(33, 112, 69, 0.13);
border: 1px solid rgba(33, 112, 69, 0.3);
border-radius: 3px;
padding: 1px 5px;
vertical-align: middle;
margin-left: 5px;
line-height: 1.5;
}
.tier-seg.active .qs-best-badge {
color: rgba(255,255,255,0.9);
background: rgba(255,255,255,0.18);
border-color: rgba(255,255,255,0.35);
}
/* Discount sub-text — green when not active */
.qs-discount-sub { color: var(--green) !important; }
.tier-seg.active .qs-discount-sub { color: rgba(255,255,255,0.8) !important; }
/* Dynamic savings row — appears below selector when discounted term active */
.qs-savings-row {
display: flex;
align-items: center;
gap: 6px;
font-family: 'DM Mono', monospace;
font-size: 11px;
letter-spacing: 0.05em;
color: var(--green);
margin-top: 2px;
}
.qs-savings-row.hidden { display: none; }
#qsSavingsAmt { font-weight: 700; }
/* Vertical divider between contract term and onboarding fee */
.qs-divider {
width: 1px;
background: var(--border);
margin: -18px 0 -20px;
flex-shrink: 0;
}
.qs-right {
display: flex;
flex-direction: column;
gap: 12px;
padding: 0 0 0 24px;
justify-content: center;
}
/* ── Custom toggle switch (replaces native checkbox for Waive) ── */
.qs-toggle-row {
display: flex;
align-items: center;
gap: 9px;
cursor: pointer;
user-select: none;
}
.qs-toggle-row input[type=checkbox] { display: none; }
.qs-switch {
width: 34px;
height: 20px;
background: var(--border);
border-radius: 10px;
position: relative;
transition: background 0.2s;
flex-shrink: 0;
}
.qs-switch::after {
content: '';
position: absolute;
width: 14px;
height: 14px;
background: #fff;
border-radius: 50%;
top: 3px;
left: 3px;
transition: left 0.2s, background 0.2s;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.qs-toggle-row input:checked ~ .qs-switch { background: var(--accent); }
.qs-toggle-row input:checked ~ .qs-switch::after { left: 17px; }
.qs-fee-waive:has(input:disabled) { opacity: 0.5; cursor: default; }
.qs-fee-input:disabled { opacity: 0.4; cursor: not-allowed; }
.qs-toggle-label {
font-family: 'DM Mono', monospace;
font-size: 13px;
color: var(--muted);
letter-spacing: 0.04em;
}
.qs-fee-row {
display: flex;
flex-direction: column;
gap: 6px;
}
.qs-fee-header {
display: flex;
align-items: center;
gap: 10px;
}
.qs-fee-waive { margin-left: 4px; }
.qs-fee-label {
font-family: 'DM Mono', monospace;
font-size: 13px;
color: var(--muted);
white-space: nowrap;
letter-spacing: 0.04em;
}
.qs-fee-input-wrap {
display: flex;
align-items: center;
background: var(--card);
border: 1px solid var(--border);
border-radius: 4px;
overflow: hidden;
}
.qs-fee-dollar {
padding: 6px 8px;
font-family: 'DM Mono', monospace;
font-size: 14px;
color: var(--muted);
background: var(--card);
border-right: 1px solid var(--border);
}
.qs-fee-input {
background: var(--card);
border: none;
color: var(--ink);
font-family: 'DM Mono', monospace;
font-size: 14px;
width: 120px;
text-align: center;
padding: 6px 10px;
outline: none;
}
.qs-fee-input::-webkit-inner-spin-button,
.qs-fee-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.qs-fee-input[type=number] { -moz-appearance: textfield; }
/* ── INLINE-STYLE REPLACEMENT CLASSES ───────────────────────────
These replace presentational style="" attributes that previously
bypassed the design token system. All colours use tokens.
─────────────────────────────────────────────────────────────── */
/* Section I — admin fee display row */
.admin-fee-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; }
.admin-fee-title { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 22px; }
.admin-fee-val { font-family: 'DM Mono', monospace; font-size: 22px; color: var(--accent); }
.admin-fee-sub { font-size: 12px; color: var(--muted); margin-bottom: 12px; }
.floor-note { font-size: 13px; color: var(--muted); margin-top: 8px; margin-bottom: 16px; font-family: 'DM Mono', monospace; }
/* Sidebar sub-line rows (users/endpoints/admin breakdown text) */
.sl-sub { font-size: 13px; color: var(--muted); font-family: 'DM Mono', monospace; padding: 0 0 6px; }
/* Per-user cost section */
.per-user-cost-sub { font-size: 10px; opacity: 0.6; font-weight: 400; }
.sidebar-note-mono { font-size: 12px; padding: 2px 0 6px; font-family: 'DM Mono', monospace; }
/* VS Comparison block */
.vs-comparison-wrap {
margin-top: 16px;
margin-bottom: 15px;
padding: 24px 24px 22px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid var(--border);
border-radius: 10px;
}
.vs-inline-icon { margin-right: 6px; vertical-align: middle; }
.vs-svs-label { font-size: 14px; color: var(--ink); font-weight: 600; }
.vs-val-accent { color: var(--accent); font-weight: 600; font-size: 14px; }
.vs-td-muted { color: var(--muted); font-size: 12px; }
.vs-td-icon { margin-right: 5px; opacity: 0.55; vertical-align: middle; }
.vs-footnote {
font-size: 11px;
color: var(--muted);
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid var(--border);
line-height: 1.55;
font-style: italic;
}
/* Side note icons and savings highlight */
.note-icon { margin-right: 6px; vertical-align: middle; flex-shrink: 0; }
.savings-amount { color: var(--green); }
.sl-otf-waived > span:first-child { color: var(--green); text-decoration: line-through; text-decoration-color: var(--green); }
.sl-otf-waived .val { color: var(--green); font-size: 12px; letter-spacing: 0.04em; }
.sl-otf-waived .otf-amt { text-decoration: line-through; text-decoration-color: var(--green); }
.sl-otf-waived .otf-waived-label { text-decoration: none; font-weight: 600; letter-spacing: 0.06em; }
/* ── ADMIN FEE WAIVED display */
.admin-fee-header { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.admin-fee-waive-toggle { margin-left: auto; }
.admin-fee-strike { text-decoration: line-through; color: var(--muted); text-decoration-color: var(--muted); }
.admin-fee-waived-badge { font-family: 'DM Mono', monospace; font-size: 12px; font-weight: 700; letter-spacing: 0.08em; color: var(--green); background: rgba(33,112,69,0.12); border: 1px solid rgba(33,112,69,0.28); border-radius: 4px; padding: 2px 7px; vertical-align: middle; }
.sl-admin-waived > span:first-child { text-decoration: line-through; text-decoration-color: var(--muted); color: var(--muted); }
.admin-waive-savings { display: flex; align-items: center; gap: 7px; font-family: 'DM Mono', monospace; font-size: 12px; letter-spacing: 0.04em; color: var(--green); background: rgba(33,112,69,0.08); border: 1px solid rgba(33,112,69,0.22); border-radius: 6px; padding: 8px 12px; margin-top: 10px; margin-bottom: 4px; }
.admin-waive-savings.hidden { display: none; }
#adminWaivedAmt { font-weight: 700; }
/* Nudge banner internal flex rows */
.nudge-header-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.nudge-nav-group { display: flex; gap: 4px; }
/* VoIP savings prompt */
.savings-prompt { font-size: 13px; color: var(--muted); margin-top: 8px; }
/* ── SIDEBAR UTILITY CLASSES ─────────────────────────────────────
.sl-muted — de-emphasised row labels/values
.sl-discount-val — green discount amount
.sl-hst-val — muted HST amount
─────────────────────────────────────────────────────────────── */
.sl-muted { color: var(--muted) !important; font-size: 13px; }
.sl-discount-val { color: var(--green) !important; font-size: 13px; }
.sl-hst-val { color: var(--muted) !important; font-size: 13px; }
.sidebar-line-discount { border-bottom-style: dashed; opacity: 0.8; }
.sidebar-line-hst { border-color: transparent; padding-top: 4px; padding-bottom: 4px; }
.sidebar-line-total { font-weight: 600; border-top: 1px solid var(--border); margin-top: 4px; padding-top: 10px; }
.sl-hst-toggle {
display: flex; align-items: center; gap: 6px;
font-size: 12px; color: var(--muted);
font-family: 'DM Mono', monospace; letter-spacing: 0.04em;
cursor: pointer; user-select: none;
margin: 6px 0 4px;
}
.sl-hst-toggle input { accent-color: var(--accent); cursor: pointer; }
/* ── VS COMPARISON CSS CLASSES (replace inline styles) ──────────
.vs-save-green — green "YOU SAVE" row background
.vs-save-amber — amber "Costs more" row background
.vs-val-green — green text for savings 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-amber td { background: rgba(210, 120, 30, 0.13); }
.vs-val-green { color: var(--green) !important; }
.vs-val-amber { color: var(--amber) !important; }
/* ── SECTION CARD HOVER / OPEN POLISH ───────────────────────────
Subtle left accent glow on hover; stronger treatment when open.
─────────────────────────────────────────────────────────────── */
.section {
transition: border-color 0.2s, box-shadow 0.2s;
}
.section:hover {
border-color: rgba(45,122,168,0.35);
box-shadow: -3px 0 0 0 rgba(45,122,168,0.4);
}
.sec-open {
border-color: rgba(45,122,168,0.5) !important;
box-shadow: -3px 0 0 0 rgba(45,122,168,0.7) !important;
}
/* ── ADDON ROW SELECTED — stronger check indicator ──────────────
.selected gets a more prominent border + check indicator via
the checkbox's native accent-color. No pseudo-element needed.
─────────────────────────────────────────────────────────────── */
.addon-row.selected {
background: #1a2a38;
border-color: var(--accent);
box-shadow: inset 3px 0 0 0 var(--accent);
}
.addon-row.selected .addon-name { color: var(--ink); }
.addon-row.selected .addon-price { color: #62c5f0; }
/* ── EXPORT BUTTONS ─────────────────────────────────────────────
Primary CTA: Print / Save PDF
Secondary: Export JSON + Copy
─────────────────────────────────────────────────────────────── */
.export-wrap {
padding: 20px 24px 24px;
background: var(--card);
display: flex;
flex-direction: column;
gap: 8px;
}
.btn-export {
width: 100%;
background: var(--accent);
color: #fff;
border: none;
border-radius: 6px;
padding: 15px 16px;
font-family: 'DM Mono', monospace;
font-size: 14px;
letter-spacing: 0.07em;
text-transform: uppercase;
cursor: pointer;
transition: background 0.15s, transform 0.1s;
display: flex;
align-items: center;
justify-content: center;
}
.btn-export:hover { background: #3a8fc4; }
.btn-export:active { transform: scale(0.98); }
.btn-export-secondary {
background: transparent;
border: 1px solid var(--border);
color: var(--muted);
font-size: 13px;
padding: 11px 16px;
}
.btn-export-secondary:hover { background: var(--card); border-color: var(--accent); color: var(--ink); }
/* ── VOIP PHONE BILL SAVINGS ESTIMATOR (Section VI) ────────────
Optional input: current monthly phone bill.
updateSavings(q) compares against voipTotal and shows green
savings message or amber warning if VoIP costs more.
On mobile stacks vertically (flex-direction:column).
─────────────────────────────────────────────────────────────── */
.savings-input-row {
display: flex;
align-items: center;
gap: 12px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--border);
}
.savings-input-row label {
font-size: 14px;
color: var(--muted);
flex: 1;
}
.savings-input-row input {
background: var(--card);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--ink);
font-family: 'DM Mono', monospace;
font-size: 18px;
width: 120px;
text-align: center;
padding: 7px;
outline: none;
}
.savings-result {
margin-top: 12px;
background: #162e22; /* match callout-green — was #0d2016 (near-black) */
border: 1px solid #245840;
border-radius: 6px;
padding: 12px 16px;
font-family: 'DM Mono', monospace;
font-size: 14px;
color: var(--green);
line-height: 1.65;
}
/* ── BOTTOM PITCH BANNER ────────────────────────────────────────
4-column grid (2-col on tablet/mobile) outside the .outer grid.
.pitch-inner has margin-left:96px to align with section cards.
Columns: Security-First | Ottawa-Based | Flat-Rate | Scales With You
.pitch-footer — green strip at bottom with tagline.
Icons are inline SVG (FA Free 6.5.0 paths), accent blue.
─────────────────────────────────────────────────────────────── */
.pitch-wrap {
width: 100%;
padding: 0;
margin: 0;
}
.pitch-inner {
margin-left: 0;
background: var(--card);
border: none;
border-top: 1px solid var(--border);
border-radius: 0;
overflow: hidden;
}
.pitch-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.pitch-item {
padding: 30px 24px;
border-right: 1px solid var(--border);
}
.pitch-item:last-child { border-right: none; }
.pitch-icon { font-size: 20px; margin-bottom: 12px; color: var(--accent); }
.pitch-title { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 16px; margin-bottom: 8px; }
.pitch-desc { font-size: 14px; color: var(--muted); line-height: 1.7; }
.pitch-footer {
background: #162e22; /* match green callout family — was #1a2e20 */
border-top: 1px solid #245840;
padding: 16px 32px;
font-family: 'DM Mono', monospace;
font-size: 13px;
color: var(--green);
letter-spacing: 0.05em;
text-align: center;
}
/* ═══════════════════════════════════════════════════════
RESPONSIVE BREAKPOINTS — MOBILE FIRST
─────────────────────────────────────────────────────
≤1100px tablet portrait — single col, sidebar hidden,
mobile pill + panel shown
≤ 900px small tablet — tighter spacing, smaller numerals
≤ 600px phone portrait — no numeral gutter, section-num
inline, section-header grid layout
≤ 780px landscape — restore 2-col, sticky sidebar
─────────────────────────────────────────────────────
MOBILE PANEL ARCHITECTURE:
Desktop — .side-col visible, .mobile-quote-panel hidden
≤1100px — .side-col hidden (display:none), pill shown
Pill tap — openMobilePanel() adds .open to #mobileQuotePanel
Panel contains static duplicate sidebar with _m ID suffix
update() syncs all _m elements via syncEl/syncClass/syncStyle
DO NOT add display:none to .side-col at desktop level or the
sidebar will disappear on desktop after panel is opened.
═══════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════
RESPONSIVE — MOBILE FIRST
Breakpoints:
< 600px — phone portrait
600900px — phone landscape / small tablet
9001100px — tablet portrait
11011350px — narrow desktop (2-col, tighter numerals)
> 1350px — desktop (base styles apply)
═══════════════════════════════════════════════════════ */
/* ── NARROW DESKTOP (≤ 1350px, > 1100px) ─────────────────────
Reduces the section numeral gutter and outer gap to give the
content columns more breathing room on small laptops / narrow
monitors before the layout collapses to single-column at 1100px.
─────────────────────────────────────────────────────────────── */
@media (max-width: 1350px) {
.outer {
gap: 36px;
padding: 52px clamp(48px,4vw,60px) 52px;
}
.section { margin-left: 76px; }
.section-num { left: -76px; width: 64px; font-size: 54px; top: 30px; }
.client-bar { padding: 32px 0 32px 76px; }
.quote-settings-bar { margin-left: 76px; }
.sections-toolbar { margin-left: 76px; }
.top-bar-logo { margin-left: 50px; }
}
/* ── TABLET PORTRAIT (≤ 1100px) ── */
@media (max-width: 1100px) {
.outer {
grid-template-columns: 1fr;
gap: 0;
padding: 36px clamp(16px,3vw,32px) 60px;
}
.side-col {
position: static;
margin-top: 0;
}
.sidebar {
margin-top: 0;
border-radius: 12px;
}
/* Sidebar sits ABOVE the form on tablet/mobile */
.main-col { order: 2; }
.side-col { order: 1; }
/* Narrower numeral gutter */
.section { margin-left: 64px; }
.section-num { left: -64px; width: 56px; font-size: 52px; }
.client-bar { padding: 24px 0 24px 64px; }
.quote-settings-bar { margin-left: 64px; padding: 18px 22px 20px 22px; gap: 0; }
.qs-group { padding-right: 20px; }
.qs-right { padding-left: 20px; }
.sections-toolbar { margin-left: 64px; }
.top-bar-logo { margin-left: 38px; }
.pitch-inner { margin-left: 0; }
.pitch-grid { grid-template-columns: repeat(2, 1fr); }
.pitch-item:nth-child(2) { border-right: none; }
.pitch-item:nth-child(3) { border-top: 1px solid var(--border); }
.pitch-item:nth-child(4) { border-top: 1px solid var(--border); border-right: none; }
/* Addon rows — price above title so text has full width */
.addon-row {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto auto;
column-gap: 10px;
row-gap: 6px;
padding: 12px 14px;
align-items: start;
}
.addon-row input[type=checkbox] { grid-column: 1; grid-row: 2; }
.addon-row > div { grid-column: 2; grid-row: 2; }
.addon-price {
grid-column: 1 / -1;
grid-row: 1;
margin-left: 0;
}
}
/* ── SMALL TABLET / LANDSCAPE PHONE (≤ 900px) ── */
@media (max-width: 900px) {
.top-bar { padding: 12px 0; }
.outer { padding: 28px clamp(14px,3vw,28px) 48px; }
.section { margin-left: 52px; padding: 24px 24px 28px; }
.section-num { left: -52px; width: 44px; font-size: 42px; top: 24px; }
.top-bar-logo { margin-left: 26px; }
.client-bar { padding: 20px 0 20px 52px; }
.quote-settings-bar { margin-left: 52px; padding: 16px 18px; gap: 0; }
.qs-group { padding-right: 16px; }
.qs-right { padding-left: 16px; }
.sections-toolbar { margin-left: 52px; }
.pitch-wrap { padding: 0; }
.pitch-inner { margin-left: 0; }
.section-header {
flex-wrap: wrap;
align-items: center;
gap: 8px 12px;
margin-bottom: 24px;
}
.section-title-block { order: 2; flex: 0 0 100%; }
.sec-summary-badge { order: 1; }
.sec-chevron { order: 1; margin-left: auto; }
.section-title { font-size: 20px; }
.main-col { gap: 20px; }
.main-col > .section:first-of-type { margin-top: 16px; }
}
/* ── PHONE (≤ 600px) ── */
@media (max-width: 600px) {
/* No gutter — numerals tuck inline */
.outer { padding: 20px 16px 40px; }
/* Collapse numeral gutter entirely on phones */
.top-bar-logo { margin-left: 0; }
.section {
margin-left: 0;
padding: 20px 18px 24px;
border-radius: 10px;
}
.section-num {
position: static;
display: inline-block;
font-size: 20px;
width: auto;
color: var(--accent);
background: transparent;
border: none;
border-radius: 0;
padding: 0;
margin-bottom: 8px;
letter-spacing: 0.06em;
line-height: 1;
text-align: left;
font-family: 'Cinzel', serif;
opacity: 0.85;
}
/* ── Mobile section header: top row = numeral + right-side controls
bottom row = title block full width ── */
.section-header {
display: grid;
/* Col 1: numeral (auto width) | Col 2: badge+chevron (auto) */
grid-template-columns: auto 1fr auto;
grid-template-rows: auto auto;
column-gap: 10px;
row-gap: 8px;
margin-bottom: 20px;
align-items: center;
}
/* Numeral: top-left */
.section-num {
grid-column: 1;
grid-row: 1;
}
/* Summary badge: top-middle (expands to fill) — right-aligned */
.sec-summary-badge {
grid-column: 2;
grid-row: 1;
text-align: right;
justify-self: end;
white-space: nowrap;
font-size: 12px;
margin-left: 0;
order: 0;
}
/* Chevron: top-right with pill background */
.sec-chevron {
grid-column: 3;
grid-row: 1;
padding: 0;
width: 36px;
height: 36px;
display: flex !important;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.07);
border-radius: 6px;
color: var(--muted);
flex-shrink: 0;
}
.sec-chevron svg { width: 16px; height: 16px; stroke-width: 3; }
/* Title block: second row, full width */
.section-title-block {
grid-column: 1 / -1;
grid-row: 2;
width: 100%;
min-width: 0;
order: 0;
flex: initial;
}
.section-title { font-size: 18px; }
.client-bar { padding: 20px 0 20px 0; }
.client-input { font-size: 22px; max-width: 100%; }
.quote-settings-bar { margin-left: 0; padding: 14px 16px 16px; flex-direction: column; gap: 0; }
.sections-toolbar { margin-left: 0; }
.qs-group { min-width: 0; padding-right: 0; }
/* Convert vertical divider to horizontal rule */
.qs-divider { width: auto; height: 1px; margin: 14px 0; }
.qs-right { padding-left: 0; }
.main-col { gap: 16px; }
.main-col > .section:first-of-type { margin-top: 8px; }
/* Pill toggle — stack vertically on tiny screens */
.pill-toggle {
grid-template-columns: 1fr;
}
.pill-toggle label { border-right: none; border-bottom: 1px solid var(--border); }
.pill-toggle label:last-child { border-bottom: none; }
/* Tier segments — keep 3-col but tighter */
.tier-seg { padding: 12px 6px; }
.tier-seg .tier-price { font-size: 18px; }
.tier-seg .tier-name { font-size: 11px; }
/* Input rows — stack label above input */
.input-row {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.num-stepper { width: 100%; }
.num-input { width: 100%; font-size: 20px; padding: 12px; flex: 1; }
.step-btn { width: 48px; font-size: 22px; }
/* Addon rows — tighter font on phones (grid inherited from ≤1100px) */
.addon-row { padding: 12px 10px; }
.addon-price { font-size: 13px; }
.addon-name { font-size: 14px; }
.addon-desc { font-size: 12px; }
/* Collapsible */
.collapsible-body { padding: 12px 0 16px 16px; }
/* Feature cards — single col already, just tighter */
.feature-card { padding: 12px 14px; }
/* Savings row — stack */
.savings-input-row { flex-direction: column; align-items: flex-start; gap: 8px; }
.savings-input-row input { width: 100%; }
/* Sidebar */
.sidebar-body { padding: 16px; }
.sidebar-header { padding: 16px 18px; }
.sidebar-mrr { font-size: 38px; }
.sidebar-client { font-size: 18px; }
/* VS table — tighten */
.vs-table td { padding: 5px 3px; font-size: 13px; }
/* Pitch footer */
.pitch-wrap { padding: 0; }
.pitch-inner { margin-left: 0; border-radius: 0; }
.pitch-grid { grid-template-columns: 1fr 1fr; }
.pitch-item { padding: 20px 16px; }
.pitch-item:nth-child(2) { border-right: none; }
.pitch-item:nth-child(3) { border-top: 1px solid var(--border); }
.pitch-item:nth-child(4) { border-top: 1px solid var(--border); border-right: none; }
.pitch-title { font-size: 14px; }
.pitch-desc { font-size: 13px; }
.pitch-footer { padding: 14px 16px; font-size: 12px; }
/* Nudge banner */
.nudge-banner { padding: 14px 16px; font-size: 14px; }
.export-wrap { padding: 16px 16px 20px; }
/* Fee table */
.fee-table td { padding: 7px 0; font-size: 13px; }
}
/* ── LANDSCAPE PHONE (≤ 780px, orientation: landscape) ── */
@media (max-width: 780px) and (orientation: landscape) {
.outer {
grid-template-columns: 1fr 1fr;
gap: 24px;
padding: 20px 20px 40px;
align-items: start;
}
.main-col { order: 1; gap: 16px; }
.side-col {
order: 2;
position: sticky;
top: 60px;
align-self: start;
}
.section { margin-left: 44px; padding: 18px 20px 22px; }
.section-num { left: -44px; width: 38px; font-size: 36px; top: 18px; position: absolute; }
.client-bar { padding: 16px 0 16px 44px; }
.sidebar { margin-top: 0; }
.sidebar-mrr { font-size: 32px; }
.pitch-grid { grid-template-columns: repeat(2, 1fr); }
.pitch-inner { margin-left: 0; }
.pitch-wrap { padding: 0; }
}
/* ── MOBILE-ONLY ELEMENTS — hidden at desktop baseline ─────────
MUST be display:none here (outside any media query) so that
the panel doesn't render on top of desktop layout.
The @media (max-width:1100px) block below overrides to display:flex.
─────────────────────────────────────────────────────────────── */
.mobile-quote-pill { display: none; }
.mobile-quote-panel { display: none; }
/* ═══════════════════════════════════════
MOBILE QUOTE PILL + FULL-SCREEN PANEL
═══════════════════════════════════════ */
@media (max-width: 1100px) {
/* Hide the static sidebar entirely on mobile/tablet */
.side-col { display: none; }
/* Show the floating pill */
.mobile-quote-pill {
display: flex;
align-items: center;
gap: 10px;
position: fixed;
top: 82px;
right: 14px;
z-index: 200;
background: var(--accent);
color: #fff;
border-radius: 50px;
padding: 10px 18px 10px 14px;
cursor: pointer;
box-shadow: 0 4px 20px rgba(0,0,0,0.45);
border: none;
font-family: 'DM Mono', monospace;
font-size: 15px;
font-weight: 500;
letter-spacing: 0.04em;
transition: background 0.15s, transform 0.15s;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
.mobile-quote-pill:active { transform: scale(0.96); }
.mobile-quote-pill:hover { background: #3a8fc4; }
.mobile-pill-icon {
width: 28px;
height: 28px;
background: rgba(255,255,255,0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.mobile-pill-mrr {
font-family: 'DM Mono', monospace;
font-size: 16px;
font-weight: 500;
line-height: 1;
}
.mobile-pill-label {
font-size: 10px;
opacity: 0.75;
letter-spacing: 0.1em;
text-transform: uppercase;
line-height: 1;
margin-top: 2px;
}
/* Full-screen overlay panel */
.mobile-quote-panel {
position: fixed;
inset: 0;
z-index: 300;
display: flex;
flex-direction: column;
pointer-events: none;
opacity: 0;
transition: opacity 0.25s ease;
}
.mobile-quote-panel.open {
pointer-events: all;
opacity: 1;
}
/* Dark backdrop */
.mobile-panel-backdrop {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.65);
backdrop-filter: blur(3px);
-webkit-backdrop-filter: blur(3px);
}
/* Slide-up sheet */
.mobile-panel-sheet {
position: absolute;
bottom: 0;
left: 0;
right: 0;
max-height: 92vh;
background: var(--card);
border-radius: 20px 20px 0 0;
overflow-y: auto;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
transform: translateY(100%);
transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
will-change: transform;
border-top: 1px solid var(--border);
}
.mobile-quote-panel.open .mobile-panel-sheet {
transform: translateY(0);
}
/* Drag handle */
.mobile-panel-handle {
width: 40px;
height: 4px;
background: var(--border);
border-radius: 2px;
margin: 14px auto 0;
flex-shrink: 0;
}
/* Close button row */
.mobile-panel-close-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px 12px;
border-bottom: 1px solid var(--border);
}
.mobile-panel-close-title {
font-family: 'DM Mono', monospace;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--muted);
}
.mobile-panel-close-btn {
background: var(--border);
border: none;
color: var(--ink);
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 20px;
line-height: 1;
flex-shrink: 0;
-webkit-tap-highlight-color: transparent;
transition: background 0.15s;
}
.mobile-panel-close-btn:active { background: var(--muted); }
/* Sidebar inside the mobile sheet — strip all desktop positioning */
.mobile-panel-sheet .sidebar {
margin-top: 0 !important;
border-radius: 0 !important;
border: none !important;
box-shadow: none !important;
overflow: visible !important;
}
/* Sidebar-header inside panel — hide it, panel has its own header row */
.mobile-panel-sheet .sidebar-header {
display: none !important;
}
.mobile-panel-sheet .sidebar-body {
padding-top: 4px !important;
}
}
/* Landscape phone — pill stays, sheet max-height smaller */
@media (max-width: 780px) and (orientation: landscape) {
.mobile-panel-sheet { max-height: 88vh; }
}
/* ═══════════════════════════════════════════════════════
PRINT / PDF EXPORT (Export A)
window.print() triggers this via Print / Save PDF button.
Goals:
- Clean, branded quote document
- Hide all interactive controls
- Force all sections expanded (body shown)
- No background colours that waste ink (except header)
- Page-break control so summary never splits
═══════════════════════════════════════════════════════ */
@media print {
/* ── Force light background on body ── */
body { background: #fff !important; color: #1a1a1a !important; font-size: 13px; }
/* ── Hide interactive & mobile-only elements ── */
.mobile-quote-pill,
.mobile-quote-panel,
.step-btn,
.collapsible-header,
.sec-chevron,
.section-toggle,
.tier-seg-wrap,
.pill-toggle,
.addon-row input[type=checkbox],
.savings-input-row,
.export-wrap,
.nudge-banner,
.pitch-wrap,
.quote-settings-bar,
.section-header.section-toggle { pointer-events: none; }
.mobile-quote-pill { display: none !important; }
.mobile-quote-panel { display: none !important; }
.export-wrap { display: none !important; }
.nudge-banner { display: none !important; }
.theme-toggle-btn { display: none !important; }
.pitch-wrap { display: none !important; }
.step-btn { display: none !important; }
.collapsible-header { display: none !important; }
.sec-chevron { display: none !important; }
.sec-summary-badge { display: none !important; }
.sec-collapsed-counter { display: none !important; }
.quote-settings-bar { display: none !important; }
.section-badge { display: none !important; }
#savingsPrompt { display: none !important; }
/* ── Show ALL section bodies (force expand) ── */
.section-body { display: block !important; }
.collapsible-body { max-height: none !important; opacity: 1 !important; overflow: visible !important; }
/* ── Reset layout to single column ── */
.outer {
display: block !important;
padding: 0 !important;
max-width: 100% !important;
}
.main-col, .side-col { width: 100% !important; position: static !important; }
/* ── Top bar: keep accent, reduce height ── */
.top-bar {
position: static !important;
padding: 10px 20px !important;
border-bottom: 2px solid #2d7aa8 !important;
background: #fff !important;
}
.top-bar-inner { padding: 0 !important; }
.top-bar-right { color: #555 !important; }
/* ── Section cards: clean borders, no dark bg ── */
.section {
background: #fff !important;
border: 1px solid #ccc !important;
box-shadow: none !important;
margin-left: 0 !important;
page-break-inside: avoid;
break-inside: avoid;
padding: 16px 20px !important;
margin-bottom: 12px !important;
}
.section-num { color: #bbb !important; }
.section-title { font-size: 16px !important; }
/* ── Sidebar: show inline after sections, styled for print ── */
.sidebar {
background: #fff !important;
border: 2px solid #2d7aa8 !important;
border-radius: 6px !important;
margin: 16px 0 !important;
page-break-inside: avoid;
break-inside: avoid;
}
.sidebar-header { background: #2d7aa8 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.sidebar-mrr { font-size: 36px !important; color: #1a1a1a !important; }
.sidebar-line { color: #444 !important; border-bottom-color: #ddd !important; }
.sidebar-line .val { color: #1a1a1a !important; }
/* ── VS comparison: clean for print ── */
.vs-save-green td { background: #e8f5e9 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.vs-save-amber td { background: #fff3e0 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.vs-save-amber { background: #fff8e1 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* ── Feature cards: minimal ── */
.feature-card { background: #f9f9f9 !important; border-color: #ddd !important; }
.feature-card-grid { grid-template-columns: 1fr 1fr !important; gap: 6px !important; }
/* ── Addon rows ── */
.addon-row { border-color: #ddd !important; }
.addon-row.selected { background: #e8f4fb !important; border-color: #2d7aa8 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* ── Callout boxes ── */
.callout-green { background: #f0faf4 !important; border-color: #3ab870 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.callout-red { background: #fff0f0 !important; border-color: #c4526a !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* ── Progress bar ── */
.progress-fill { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* ── Print footer ── */
.pitch-footer { display: none !important; }
/* ── Page break: force summary sidebar to start fresh ── */
.side-col { page-break-before: always; break-before: always; }
/* ── Input fields: show values as static text ── */
.num-input, .qs-fee-input {
border: none !important;
background: transparent !important;
font-weight: 700 !important;
}
.client-input {
border: none !important;
background: transparent !important;
}
/* ── Print footer note ── */
body::after {
content: 'Prepared by Silicon Valley Services (SVS) MSP · Ottawa, Ontario · This quote is valid for 30 days from date of issue. Questions? Contact your SVS account representative.';
display: block;
font-size: 11px;
color: #888;
border-top: 1px solid #ddd;
padding-top: 10px;
margin-top: 20px;
font-family: 'DM Mono', monospace;
}
}