sync: auto-sync from GURU-5070 at 2026-06-14 20:04:14

Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-14 20:04:14
This commit is contained in:
2026-06-14 20:05:02 -07:00
parent 30933bd35d
commit c5d4d3527c
119 changed files with 5204 additions and 1 deletions

View File

@@ -0,0 +1,51 @@
# DESIGN.md — "Sonoran Ledger" (multipage)
The locked design language for the ACG site. A trusted local bookkeeper's ledger,
rendered for the web: warm paper, precise rules, mono numerals. Pricing, the
calculator, and the concierge story are treated as a transparent, permanent record.
## Color strategy: Committed (warm paper carries the surface), one accent as "ink"
Use OKLCH; neutrals tinted toward the brand hue (~30 hue). Never pure #000/#fff.
- **Light:** paper `#F7F3EB`, surface `#EDE6D9`, surface-2 `#E4DACA`,
ink `#2A2521`, ink-2 `#5A5148`, ink-3 `#6D6456` (AA on cream).
- **Dark:** paper `#1C1814`, surface `#2A2520`, surface-2 `#322B24`,
ink `#E8DFCE`, ink-2 `#C4B8A3`, ink-3 `#9A8C77`.
- **Accent (the "ink"):** amber `#F2922E` (light) / `#F2A24E` (dark) for fills,
underlines, marks, the single primary CTA. Orange TEXT on light must use
`#BD5A00` (AA); on dark `#F4A85C`.
- Accent is ≤ ~10% of any view. It marks active data, never fills big blocks.
## Theme
Both light and dark are first-class. Scene: a Tucson business owner reading at a
sunlit desk by day, or late at night deciding on a provider. Warm in both. System
preference is honored and remembered, set before first paint (no flash).
## Typography
- Display: **Barlow Condensed** 600/700 (headlines, tier names, the "since 2001" lockup).
- Body: **Lexend** 300/400/500 (body capped 6575ch).
- Mono: **JetBrains Mono**, tabular-nums, for ALL money, the calculator, endpoint
counts, eyebrows, and ledger micro-labels.
- Scale steps keep ≥1.25 contrast; hierarchy via scale + weight.
## Layout & rhythm
- Strict 24px baseline. Faint continuous ledger rulings align to body line-height.
- Vary spacing per page; do not repeat one padding everywhere. Avoid identical card
grids. Cards only where they are the right affordance (pricing tiers).
- Radius 02px only. Sharp = precise, manual, honest.
## Motion
- Reveal on scroll (opacity + small translate), ease-out only, respects reduced-motion.
- Never animate layout properties.
## House laws (impeccable)
- **No em dashes** anywhere in copy. Use commas, colons, semicolons, periods, parentheses.
- **No side-stripe accent borders** (no border-left/right > 1px as a colored accent).
Use full borders, leading numerals/marks, background tints, or nothing.
- No gradient text, no decorative glassmorphism, no hero-metric template, no AI slop.
## Multipage specifics
- Shared sticky header (brand + nav + theme toggle + mobile menu) and footer on every page.
- Active nav state per page (`aria-current="page"`).
- Pages: Home, Services, Pricing, Calculator, About, Contact. Each has its own
opening rhythm so the set never feels templated.

View File

@@ -0,0 +1,44 @@
# PRODUCT.md — Arizona Computer Guru (ACG) website
register: brand
## Product purpose
A multipage marketing website for Arizona Computer Guru, a Tucson managed-IT and
cybersecurity provider operating since 2001. The site sells trust before it sells
services: the goal is for a small-business owner to feel they have found honest,
local people who will go further than the last IT company, then to reach out or
build an estimate. Design IS the product here.
## Users
- Tucson / southern-Arizona small-business owners and office managers (roughly
5 to 100 employees): law firms, medical practices, accounting, construction,
property management, retail, manufacturing.
- Often burned before: surprise bills, offshore call centers, three-year lock-ins,
"unlimited support" that wasn't. Skeptical, value-conscious, not deeply technical.
- They want a real person, fast local help, and to know what it costs before a call.
## Brand & tone
- The differentiator is **concierge IT**: genuine relationships, going much further
than typical IT companies, at reasonable prices.
- Voice: kind, direct, transparent, plain-spoken, confident without arrogance.
Never condescending, never sales-pressure, never hype. "We built it the way we'd
want to be treated." Publishes its prices on purpose.
- Local and rooted: Tucson since 2001, physical office at 7437 E. 22nd St, onsite
in 1 to 2 hours, month-to-month terms.
## Anti-references (do NOT look like these)
- Generic SaaS/MSP slop: blue/purple gradients, floating 3D isometrics, server-rack
clip art, glowing shields, "hero metric" stat templates, identical icon-card grids.
- Hard-sell landing pages: countdown timers, fake scarcity, manufactured testimonials.
- Cold enterprise-security navy-and-gold. Cold healthcare white-and-teal.
## Strategic principles
- Transparency is the aesthetic. Show real numbers, real pricing, real process.
- Warmth and place: Tucson light, paper, ledgers, honest materials. Photographic,
not illustrated.
- Every word earns its place. No restated headings, no filler.
## Integrity rules
- No fabricated named client testimonials. Proof is built from verifiable facts.
- The contact form is a demo (not wired to a mailbox). Pricing is illustrative of
published GPS rates. Photography is representational.

View File

@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>About | Arizona Computer Guru</title>
<meta name="description" content="A Tucson IT company since 2001. We started as a break-fix shop, then built GPS to align our incentives with our clients. Concierge IT, the way we'd want to be treated." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>(function(){try{var s=localStorage.getItem("acg-theme");var m=s||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");}catch(e){}})();</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span><span class="brand__name">Arizona Computer Guru</span><br /><span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span></span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html">Home</a>
<a class="nav__link" href="services.html">Services</a>
<a class="nav__link" href="pricing.html">Pricing</a>
<a class="nav__link" href="calculator.html">Estimate</a>
<a class="nav__link" href="about.html" aria-current="page">About</a>
<a class="nav__link" href="contact.html">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<section class="page-head page-head--img ledger">
<div class="wrap">
<div class="reveal">
<p class="eyebrow">Tucson, since 2001</p>
<h1>The IT partner that actually picks up</h1>
<p class="lead">We are not a national chain and we are not venture-backed. We are a local Tucson team that has been here for two decades because we do right by the businesses we serve.</p>
</div>
<figure class="reveal">
<img src="assets/images/about.png" width="1248" height="832" alt="A friendly handshake over a wooden desk with a laptop and a handwritten notebook, an Arizona map framed on the wall." />
</figure>
</div>
</section>
<!-- Origin story -->
<section class="story" aria-labelledby="origin-h">
<div class="wrap">
<div class="story__copy reveal">
<p class="section-tag">Why we work this way <span>/ the short version</span></p>
<h2 id="origin-h">We used to be the company we now warn you about</h2>
<p class="muted">We started in 2001 as a break-fix shop. We charged by the hour, showed up when things broke, and quietly made more money when our clients had more problems. That did not sit right.</p>
<p class="muted">So we built Guru Protection Services: proactive monitoring, transparent published pricing, and month-to-month terms. The point was to put our incentives on the same side of the table as yours. We make more when your systems stay healthy, not when they fail.</p>
<p class="muted">Today we look after businesses across Tucson, from small offices to busy practices and job sites. We have stopped ransomware before a single file was encrypted, replaced failing drives before anyone noticed, and helped owners meet the cyber-insurance requirements that used to keep them up at night.</p>
<blockquote>We built our service the way we'd want to be treated if we were the customer.</blockquote>
</div>
<figure class="story__img reveal">
<img src="assets/images/story.png" width="1248" height="832" alt="Warm afternoon desert light raking across a white stucco wall meeting a clean wooden windowsill." loading="lazy" />
</figure>
</div>
</section>
<!-- Philosophy -->
<section class="home-services ledger" aria-labelledby="phil-h">
<div class="wrap">
<p class="section-tag">What concierge means, concretely <span>/ five choices</span></p>
<h2 id="phil-h">The promises behind the work</h2>
<div class="svc-list">
<article class="svc reveal"><div class="svc__no">01</div><div><h3 class="svc__name">Transparent pricing</h3><p class="svc__desc">Published per-endpoint rates. You know what you pay before you call us. No games, no "call for quote," no fees that appear at the bottom of an invoice.</p></div><div class="svc__meta">$19&ndash;$39 /endpoint</div></article>
<article class="svc reveal"><div class="svc__no">02</div><div><h3 class="svc__name">Local Tucson team</h3><p class="svc__desc">A real office at 7437 E. 22nd St since 2001. When your server dies at 3pm you do not want a ticket, you want someone at your door by 3:45. We can usually be onsite within an hour or two.</p></div><div class="svc__meta">onsite 1&ndash;2 hr</div></article>
<article class="svc reveal"><div class="svc__no">03</div><div><h3 class="svc__name">Proactive, not reactive</h3><p class="svc__desc">24/7 monitoring, automated patching, and alerts that reach us before they reach you. The goal is that you never have to call because something broke.</p></div><div class="svc__meta">24/7 monitoring</div></article>
<article class="svc reveal"><div class="svc__no">04</div><div><h3 class="svc__name">Month-to-month terms</h3><p class="svc__desc">No three-year lock-ins, no early-termination fees. If we stop earning your business, you can leave with 30 days' notice. We would rather keep you by choice.</p></div><div class="svc__meta">cancel in 30 days</div></article>
<article class="svc reveal"><div class="svc__no">05</div><div><h3 class="svc__name">Plain English, always</h3><p class="svc__desc">Many IT people are dismissive or condescending. That is never tolerated here. We are kind, direct, and honest, and we will never make you feel small for asking a question.</p></div><div class="svc__meta">no jargon walls</div></article>
</div>
</div>
</section>
<!-- Big quote band -->
<section aria-labelledby="bq-h">
<div class="wrap" style="max-width:900px;">
<h2 id="bq-h" class="sr-only">Our standard</h2>
<p class="bigquote reveal">You might not choose us. That's okay. But you'll make a better decision because we told you the truth.</p>
<p class="signature reveal">// Arizona Computer Guru, Tucson</p>
</div>
</section>
<section class="cta-band" aria-labelledby="cta-h">
<div class="wrap">
<div class="reveal">
<h2 id="cta-h">Come see for yourself</h2>
<p>Stop by the office, or have us out to look at the server closet that runs hot and the printer that jams every Tuesday. The first conversation is free, and there is no pitch.</p>
</div>
<div class="cta-band__actions reveal">
<a class="btn btn--primary" href="contact.html">Talk to a human <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost" href="calculator.html">Estimate your cost</a>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View File

@@ -0,0 +1,143 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Estimate your IT cost | Arizona Computer Guru</title>
<meta name="description" content="Build a transparent IT estimate in seconds: endpoints, protection tier, support plan, Microsoft 365, phones, and hosting. No email wall, no sales call." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>(function(){try{var s=localStorage.getItem("acg-theme");var m=s||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");}catch(e){}})();</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span><span class="brand__name">Arizona Computer Guru</span><br /><span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span></span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html">Home</a>
<a class="nav__link" href="services.html">Services</a>
<a class="nav__link" href="pricing.html">Pricing</a>
<a class="nav__link" href="calculator.html" aria-current="page">Estimate</a>
<a class="nav__link" href="about.html">About</a>
<a class="nav__link" href="contact.html">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<section class="page-head ledger">
<div class="wrap reveal">
<p class="eyebrow">Live estimate &middot; no email wall</p>
<h1>Your IT, accounted for</h1>
<p class="lead">Move the numbers, watch the total. This is the same math we would walk you through in person, with nothing hidden behind a "contact sales" button.</p>
</div>
</section>
<section class="calc ledger" id="calculator" aria-labelledby="calc-h" style="padding-top:calc(var(--base)*2);">
<div class="wrap">
<h2 id="calc-h" class="sr-only">IT cost estimator</h2>
<div class="calc__shell">
<div class="calc__grid">
<form class="calc__inputs" id="calcForm" aria-label="IT cost estimator">
<div class="calc__row">
<label for="endpoints">Computers &amp; servers <span class="hint">Every monitored endpoint</span></label>
<div class="calc__control"><div class="stepper" data-step="endpoints">
<button type="button" data-dir="-1" aria-label="Fewer endpoints">&minus;</button>
<input id="endpoints" name="endpoints" type="number" inputmode="numeric" min="0" max="500" value="22" />
<button type="button" data-dir="1" aria-label="More endpoints">+</button>
</div></div>
</div>
<div class="calc__row">
<label for="gpsTier">Protection tier <span class="hint">Per-endpoint monitoring level</span></label>
<div class="calc__control"><select id="gpsTier" name="gpsTier">
<option value="19">GPS-Basic &middot; $19</option>
<option value="26" selected>GPS-Pro &middot; $26</option>
<option value="39">GPS-Advanced &middot; $39</option>
</select></div>
</div>
<div class="calc__row">
<label for="equip">Equipment monitoring <span class="hint">Network gear, printers, NAS. $25/mo</span></label>
<div class="calc__control toggle-row"><span class="switch">
<input type="checkbox" id="equip" name="equip" />
<span class="track" aria-hidden="true"></span><span class="knob" aria-hidden="true"></span>
</span></div>
</div>
<div class="calc__row">
<label for="support">Support plan <span class="hint">Bundled labor hours each month</span></label>
<div class="calc__control"><select id="support" name="support">
<option value="0">None, pay as you go</option>
<option value="200">Essential &middot; $200 (2 hr)</option>
<option value="380" selected>Standard &middot; $380 (4 hr)</option>
<option value="540">Premium &middot; $540 (6 hr)</option>
<option value="850">Priority &middot; $850 (10 hr)</option>
</select></div>
</div>
<div class="calc__row">
<label for="m365">Microsoft 365 users <span class="hint">Business Standard, $14/user</span></label>
<div class="calc__control"><div class="stepper" data-step="m365">
<button type="button" data-dir="-1" aria-label="Fewer Microsoft 365 users">&minus;</button>
<input id="m365" name="m365" type="number" inputmode="numeric" min="0" max="500" value="0" />
<button type="button" data-dir="1" aria-label="More Microsoft 365 users">+</button>
</div></div>
</div>
<div class="calc__row">
<label for="voip">Business phone users <span class="hint">GPS-Voice Standard, $28/user</span></label>
<div class="calc__control"><div class="stepper" data-step="voip">
<button type="button" data-dir="-1" aria-label="Fewer phone users">&minus;</button>
<input id="voip" name="voip" type="number" inputmode="numeric" min="0" max="500" value="0" />
<button type="button" data-dir="1" aria-label="More phone users">+</button>
</div></div>
</div>
<div class="calc__row" style="border-bottom:0;">
<label for="hosting">Web hosting <span class="hint">Managed, with SSL &amp; backups</span></label>
<div class="calc__control"><select id="hosting" name="hosting">
<option value="0" selected>None</option>
<option value="15">Starter &middot; $15</option>
<option value="35">Business &middot; $35</option>
<option value="65">Commerce &middot; $65</option>
</select></div>
</div>
</form>
<div class="calc__out">
<h3>Monthly statement</h3>
<div class="ledger-lines" id="ledgerLines"></div>
<hr class="calc__divider" />
<div class="calc__total" aria-live="polite">
<span class="tlabel">Per month</span>
<span class="tnum mono" id="totalMonthly">$0</span>
</div>
<div class="calc__annual mono" id="totalAnnual">$0 / year</div>
<div class="calc__perep mono" id="perEndpoint">all-in, per endpoint / mo</div>
<a class="btn btn--primary calc__cta" href="contact.html#contact" id="sendEstimate">Send me this estimate <span class="arrow" aria-hidden="true">&rarr;</span></a>
<p class="calc__foot">Estimate only, your real quote is tailored to your setup. No card, no commitment, and we will tell you if you are buying more than you need.</p>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Contact | Arizona Computer Guru</title>
<meta name="description" content="Talk to a human in Tucson. Call 520.304.8300, email info@azcomputerguru.com, or visit 7437 E. 22nd St. No pressure, no pitch." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>(function(){try{var s=localStorage.getItem("acg-theme");var m=s||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");}catch(e){}})();</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"LocalBusiness","name":"Arizona Computer Guru","image":"assets/images/contact.png","address":{"@type":"PostalAddress","streetAddress":"7437 E. 22nd St","addressLocality":"Tucson","addressRegion":"AZ","postalCode":"85710","addressCountry":"US"},"telephone":"+1-520-304-8300","email":"info@azcomputerguru.com","url":"https://azcomputerguru.com","openingHours":"Mo-Fr 09:00-17:00"}
</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span><span class="brand__name">Arizona Computer Guru</span><br /><span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span></span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html">Home</a>
<a class="nav__link" href="services.html">Services</a>
<a class="nav__link" href="pricing.html">Pricing</a>
<a class="nav__link" href="calculator.html">Estimate</a>
<a class="nav__link" href="about.html">About</a>
<a class="nav__link" href="contact.html" aria-current="page">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<section class="contact ledger" id="contact" aria-labelledby="contact-h" style="padding-top:calc(var(--base)*3);">
<div class="wrap">
<div class="contact__intro reveal">
<p class="section-tag">No pressure, no pitch <span>/ let's talk</span></p>
<h1 id="contact-h">Talk to a human</h1>
<p class="muted">Tell us what is frustrating you, or send over an estimate from the calculator. We will give you honest feedback, even if that is "your current setup is fine, here is one thing to fix."</p>
<div class="contact__lines">
<div><span class="k">Phone</span><br /><a class="v" href="tel:+15203048300">520.304.8300</a></div>
<div><span class="k">Email</span><br /><a class="v" href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></div>
<div><span class="k">Office</span><br /><span class="v">7437 E. 22nd St, Tucson, AZ 85710</span></div>
<div><span class="k">Hours</span><br /><span class="v">Mon&ndash;Fri 9&ndash;5 &middot; 24/7 emergency for Priority clients</span></div>
</div>
<figure class="office-figure">
<img src="assets/images/contact.png" width="1248" height="832" alt="A warm southwestern stucco storefront at golden hour with a saguaro and the Santa Catalina mountains in the distance, Tucson." loading="lazy" />
<figcaption><span>East side, Tucson</span><span>come say hello</span></figcaption>
</figure>
</div>
<form class="contact__form reveal" id="contactForm" novalidate>
<div class="form-field">
<label for="cf-name">Your name</label>
<input id="cf-name" name="name" type="text" autocomplete="name" required />
</div>
<div class="form-field">
<label for="cf-biz">Business</label>
<input id="cf-biz" name="business" type="text" autocomplete="organization" />
</div>
<div class="form-field">
<label for="cf-contact">Phone or email</label>
<input id="cf-contact" name="contact" type="text" autocomplete="email" required />
</div>
<div class="form-field">
<label for="cf-msg">What can we help with?</label>
<textarea id="cf-msg" name="message"></textarea>
</div>
<button class="btn btn--primary" type="submit">Send message <span class="arrow" aria-hidden="true">&rarr;</span></button>
<p class="form-note" id="formNote" aria-live="polite">We reply the same business day. (Demo build: this form is not wired to a mailbox.)</p>
</form>
</div>
</section>
<section class="faq" id="faq" aria-labelledby="faq-h">
<div class="wrap wrap--narrow">
<p class="section-tag">Straight answers <span>/ ask us anything</span></p>
<h2 id="faq-h">Questions worth asking any IT company</h2>
<div class="faq__list" id="faqList">
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>Will I get a real person, or an offshore call center?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">A real, local person. Our team works out of our Tucson office at 7437 E. 22nd St. You can visit, and after hours you reach an on-call tech who is also local, not a queue overseas.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>What's your contract term?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">Month-to-month. Cancel with 30 days' notice, no early-termination fee. We would rather earn your business every month than trap you in a three-year agreement.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>What happens if I use more support hours than my plan includes?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">Plan hours are used first. After that we draw from any pre-paid block time you have banked ($100 to $150/hr), which never expires. No block time? Overage is billed at $175/hr, and we will always flag it before the meter runs.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>How fast do you respond to an emergency?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">By plan: Standard is 8 hours, Premium 4 hours, Priority 2 hours around the clock. A total outage is escalated immediately regardless of plan, and for local clients we are typically onsite within 1 to 2 hours.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>What security is actually included?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">GPS-Pro and above include advanced EDR, email security, dark-web monitoring, and monthly security-awareness training. GPS-Advanced adds compliance tooling and ransomware rollback. Basic antivirus alone is not enough anymore, so we do not pretend it is.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>Can you help me meet cyber-insurance requirements?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">Yes. GPS-Pro covers most of what insurers ask for: MFA enforcement, EDR, training, and cloud backups, and we will provide documentation for your agent. We work with several Tucson insurance agents regularly.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>What if my team grows or shrinks?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">Billing is per endpoint, so it just follows your headcount. Add three people, add three endpoints; downsize and it drops the next month. No contract amendments, no penalties.</div></div></div>
<div class="faq__item"><button class="faq__q" aria-expanded="false"><span>Do you really publish your pricing?</span><span class="pm" aria-hidden="true">+</span></button><div class="faq__a"><div class="faq__a-inner">You are looking at it. Our rates are on the pricing page and in the estimator. We think hiding prices is a red flag, in any IT company, including us.</div></div></div>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,206 @@
/* ===========================================================================
ARIZONA COMPUTER GURU - "BLOWOUT" (radical direction)
Poster brutalism: ultra-condensed display, drenched signal-orange,
scrolling marquee, giant numerals, hard edges, zero ledger calm.
Self-contained (does not use styles.css).
=========================================================================== */
:root {
--ink: #0C0A09; /* near-black canvas */
--ink-2: #16120F; /* raised black panel */
--bone: #F4EDE1; /* primary text */
--bone-2: #B8AE9E; /* secondary */
--hot: #FF5A1F; /* signal orange, used BIG */
--hot-2: #FF8A4D; /* lighter orange for fine text */
--line: rgba(244, 237, 225, 0.16);
--maxw: 1280px;
--f-poster: "Anton", "Arial Narrow", system-ui, sans-serif;
--f-body: "Hanken Grotesk", system-ui, -apple-system, Segoe UI, sans-serif;
--f-mono: "JetBrains Mono", ui-monospace, Consolas, monospace;
}
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
.marquee__track { animation: none !important; }
}
body {
background: var(--ink); color: var(--bone);
font-family: var(--f-body); font-size: 1.0625rem; line-height: 1.5;
-webkit-font-smoothing: antialiased; overflow-x: hidden;
}
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
::selection { background: var(--hot); color: var(--ink); }
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.wrap { width: min(100% - 3rem, var(--maxw)); margin-inline: auto; }
.hot { color: var(--hot); }
/* ---- Header ------------------------------------------------------------- */
.rx-header {
position: sticky; top: 0; z-index: 50;
background: var(--ink); border-bottom: 2px solid var(--bone);
}
.rx-header .wrap { display: flex; align-items: center; gap: 1.5rem;
height: 68px; }
.rx-brand { font-family: var(--f-poster); font-size: 1.6rem; letter-spacing: 0.02em;
text-transform: uppercase; line-height: 1; }
.rx-brand b { color: var(--hot); }
.rx-nav { margin-left: auto; display: flex; align-items: center; gap: 1.75rem; }
.rx-nav a { font-family: var(--f-mono); font-size: 0.8rem; letter-spacing: 0.08em;
text-transform: uppercase; color: var(--bone-2); }
.rx-nav a:hover { color: var(--hot); }
.rx-cta-sm { border: 2px solid var(--hot); color: var(--bone) !important;
padding: 0.45rem 0.9rem; }
.rx-cta-sm:hover { background: var(--hot); color: var(--ink) !important; }
@media (max-width: 760px) { .rx-nav a:not(.rx-cta-sm) { display: none; } }
/* ---- Hero --------------------------------------------------------------- */
.rx-hero { padding-block: clamp(2.5rem, 7vw, 6rem) clamp(2rem, 5vw, 4rem);
border-bottom: 2px solid var(--bone); position: relative; overflow: hidden; }
.rx-hero__eyebrow { font-family: var(--f-mono); font-size: 0.8rem; letter-spacing: 0.25em;
text-transform: uppercase; color: var(--hot); margin-bottom: 1.5rem; }
.rx-hero h1 {
font-family: var(--f-poster); font-weight: 400; text-transform: uppercase;
font-size: clamp(3.5rem, 16vw, 13rem); line-height: 0.86; letter-spacing: -0.01em;
margin-left: -0.06em;
}
.rx-hero h1 .stroke {
color: transparent; -webkit-text-stroke: 2px var(--bone); text-stroke: 2px var(--bone);
}
.rx-hero__sub { font-size: clamp(1.1rem, 2vw, 1.5rem); color: var(--bone-2);
max-width: 30ch; margin-top: 2rem; }
.rx-hero__cta { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2.25rem; }
.rx-hero__art {
position: absolute; right: -4%; top: 50%; transform: translateY(-50%);
width: 42vw; max-width: 620px; aspect-ratio: 3/2; pointer-events: none;
filter: grayscale(1) contrast(1.15) brightness(0.62);
-webkit-mask-image: linear-gradient(90deg, transparent, #000 35%);
mask-image: linear-gradient(90deg, transparent, #000 35%);
opacity: 0.55; z-index: -1;
}
.rx-hero__art::after { content: ""; position: absolute; inset: 0; background: var(--hot);
mix-blend-mode: overlay; }
.rx-hero__art img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 900px) { .rx-hero__art { display: none; } }
/* ---- Buttons ------------------------------------------------------------ */
.rx-btn { font-family: var(--f-poster); text-transform: uppercase; letter-spacing: 0.02em;
font-size: 1.15rem; display: inline-flex; align-items: center; gap: 0.6rem;
padding: 0.85rem 1.6rem; border: 2px solid transparent; cursor: pointer; }
.rx-btn--hot { background: var(--hot); color: var(--ink); }
.rx-btn--hot:hover { background: var(--bone); }
.rx-btn--out { border-color: var(--bone); color: var(--bone); }
.rx-btn--out:hover { background: var(--bone); color: var(--ink); }
.rx-btn .x { font-family: var(--f-mono); }
:focus-visible { outline: 3px solid var(--hot); outline-offset: 3px; }
/* ---- Marquee ------------------------------------------------------------ */
.marquee { background: var(--hot); color: var(--ink); border-bottom: 2px solid var(--bone);
overflow: hidden; padding-block: 0.7rem; }
.marquee__track { display: inline-flex; white-space: nowrap; will-change: transform;
animation: marquee 26s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee span { font-family: var(--f-poster); text-transform: uppercase;
font-size: 1.4rem; letter-spacing: 0.03em; padding-inline: 1.25rem; }
.marquee span::after { content: "\273F"; margin-left: 2.5rem; opacity: 0.6; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* ---- Section scaffold --------------------------------------------------- */
.rx-sec { padding-block: clamp(3rem, 7vw, 6.5rem); border-bottom: 2px solid var(--bone); position: relative; }
.rx-kicker { font-family: var(--f-mono); font-size: 0.8rem; letter-spacing: 0.22em;
text-transform: uppercase; color: var(--hot); display: flex; gap: 1rem; align-items: center; }
.rx-kicker::before { content: ""; width: 40px; height: 2px; background: var(--hot); }
.rx-h2 { font-family: var(--f-poster); text-transform: uppercase; font-weight: 400;
font-size: clamp(2.4rem, 6vw, 4.5rem); line-height: 0.92; margin-top: 1rem; }
.rx-ghost { position: absolute; right: 2%; top: 0.5rem; font-family: var(--f-poster);
font-size: clamp(6rem, 18vw, 16rem); line-height: 1; color: transparent;
-webkit-text-stroke: 1px var(--line); pointer-events: none; user-select: none; z-index: 0; }
.rx-sec > .wrap { position: relative; z-index: 1; }
/* ---- Services (giant rows) ---------------------------------------------- */
.rx-svc { display: grid; grid-template-columns: 4.5rem 1fr auto; align-items: baseline;
gap: 1.5rem; padding-block: 1.4rem; border-top: 2px solid var(--line);
transition: background 0.18s, padding-left 0.18s; }
.rx-svc:last-child { border-bottom: 2px solid var(--line); }
.rx-svc:hover { background: var(--ink-2); padding-left: 1rem; }
.rx-svc__n { font-family: var(--f-mono); color: var(--hot); font-size: 0.95rem; }
.rx-svc__name { font-family: var(--f-poster); text-transform: uppercase;
font-size: clamp(1.6rem, 3.6vw, 2.6rem); line-height: 0.95; }
.rx-svc__d { color: var(--bone-2); font-size: 0.98rem; max-width: 52ch; margin-top: 0.4rem; }
.rx-svc__meta { font-family: var(--f-mono); color: var(--hot-2); font-size: 0.85rem;
white-space: nowrap; text-align: right; }
@media (max-width: 640px) {
.rx-svc { grid-template-columns: 2.5rem 1fr; }
.rx-svc__meta { grid-column: 2; text-align: left; }
}
/* ---- Pricing (blowout numerals) ----------------------------------------- */
.rx-prices { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 2.5rem;
border: 2px solid var(--bone); }
.rx-price { padding: clamp(1.5rem, 3vw, 2.5rem); border-right: 2px solid var(--bone); }
.rx-price:last-child { border-right: 0; }
.rx-price--pop { background: var(--hot); color: var(--ink); }
.rx-price__tier { font-family: var(--f-mono); text-transform: uppercase; letter-spacing: 0.1em;
font-size: 0.85rem; }
.rx-price__big { font-family: var(--f-poster); font-size: clamp(4rem, 11vw, 8.5rem);
line-height: 0.8; margin-top: 0.75rem; }
.rx-price__u { font-family: var(--f-mono); font-size: 0.8rem; color: var(--bone-2); display: block;
margin-top: 0.75rem; }
.rx-price--pop .rx-price__u { color: var(--ink); opacity: 0.7; }
.rx-price__list { list-style: none; padding: 0; margin-top: 1.25rem; display: grid; gap: 0.4rem;
font-size: 0.9rem; color: var(--bone-2); }
.rx-price--pop .rx-price__list { color: var(--ink); }
.rx-price__list li::before { content: "+ "; font-family: var(--f-mono); }
@media (max-width: 760px) {
.rx-prices { grid-template-columns: 1fr; }
.rx-price { border-right: 0; border-bottom: 2px solid var(--bone); }
.rx-price:last-child { border-bottom: 0; }
}
/* ---- Calculator teaser -------------------------------------------------- */
.rx-calc { background: var(--ink-2); }
.rx-calc .wrap { display: grid; grid-template-columns: 1.4fr auto; gap: 2rem; align-items: center; }
.rx-calc__big { font-family: var(--f-poster); text-transform: uppercase;
font-size: clamp(2.2rem, 6vw, 4.5rem); line-height: 0.9; }
.rx-calc p { color: var(--bone-2); margin-top: 1rem; max-width: 46ch; }
@media (max-width: 760px) { .rx-calc .wrap { grid-template-columns: 1fr; } }
/* ---- CTA drench --------------------------------------------------------- */
.rx-cta { background: var(--hot); color: var(--ink); border-bottom: 0; text-align: center; }
.rx-cta__big { font-family: var(--f-poster); text-transform: uppercase;
font-size: clamp(3rem, 13vw, 10rem); line-height: 0.85; }
.rx-cta__row { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; margin-top: 2rem; }
.rx-cta .rx-btn--hot { background: var(--ink); color: var(--hot); }
.rx-cta .rx-btn--hot:hover { background: var(--bone); color: var(--ink); }
.rx-cta .rx-btn--out { border-color: var(--ink); color: var(--ink); }
.rx-cta .rx-btn--out:hover { background: var(--ink); color: var(--hot); }
/* ---- Footer ------------------------------------------------------------- */
.rx-footer { padding-block: 2.5rem; }
.rx-footer .wrap { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; }
.rx-footer p { font-family: var(--f-mono); font-size: 0.8rem; color: var(--bone-2); }
.rx-footer a { color: var(--bone); }
.rx-footer a:hover { color: var(--hot); }
.rx-note { width: 100%; font-size: 0.72rem; color: var(--bone-2); opacity: 0.7;
border-top: 2px solid var(--line); padding-top: 1rem; margin-top: 0.5rem; }
/* reveal */
.rx-up { opacity: 0; transform: translateY(18px); transition: opacity 0.6s cubic-bezier(0.2,0.7,0.2,1), transform 0.6s cubic-bezier(0.2,0.7,0.2,1); }
.rx-up.in { opacity: 1; transform: none; }
/* ---- narrow-screen polish ---------------------------------------------- */
@media (max-width: 480px) {
.rx-header .wrap { gap: 0.75rem; }
.rx-brand { font-size: 1.15rem; }
.rx-cta-sm { font-size: 0.72rem; padding: 0.4rem 0.6rem; }
.rx-hero__cta { flex-direction: column; align-items: stretch; }
.rx-hero__cta .rx-btn { justify-content: center; }
.marquee span { font-size: 1.1rem; }
.rx-calc .rx-btn { justify-self: start; }
}

View File

@@ -0,0 +1,694 @@
/* ===========================================================================
ARIZONA COMPUTER GURU - "Sonoran Ledger"
Hand-built. Warm paper, precise rules, mono numerals. No framework.
Baseline grid: 24px. Radius: 02px. Orange = ink, used sparingly.
=========================================================================== */
/* ---- Tokens ------------------------------------------------------------- */
:root {
--paper: #F7F3EB;
--surface: #EDE6D9;
--surface-2: #E4DACA;
--ink: #2A2521;
--ink-2: #5A5148;
--ink-3: #6D6456; /* AA-safe for small text on cream (~4.6:1) */
--rule: rgba(90, 81, 72, 0.16);
--rule-soft: rgba(90, 81, 72, 0.09);
--accent: #F2922E; /* the amber "ink" - fills, marks, underlines */
--accent-ink: #BD5A00; /* orange TEXT on light paper (AA-safe ~4.9:1) */
--on-accent: #2A2521; /* text sitting on an amber fill */
--good: #4F7A3F;
--maxw: 1140px;
--base: 24px; /* baseline unit */
--f-display: "Barlow Condensed", "Arial Narrow", system-ui, sans-serif;
--f-body: "Lexend", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
--f-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
--shadow: 0 1px 0 var(--rule), 0 18px 40px -28px rgba(40, 33, 25, 0.45);
}
[data-theme="dark"] {
--paper: #1C1814;
--surface: #2A2520;
--surface-2: #322B24;
--ink: #E8DFCE;
--ink-2: #C4B8A3;
--ink-3: #9A8C77;
--rule: rgba(196, 184, 163, 0.16);
--rule-soft: rgba(196, 184, 163, 0.08);
--accent: #F2A24E;
--accent-ink: #F4A85C; /* orange text on dark paper (AA-safe) */
--on-accent: #1C1814;
--good: #8FB97E;
--shadow: 0 1px 0 var(--rule), 0 22px 48px -30px rgba(0, 0, 0, 0.7);
}
/* ---- Skin: Midnight Concierge (cool dark-premium) ----------------------- */
html[data-skin="midnight"] { /* Midnight, light mode (cool slate-grey) */
--paper: #F2F4F7;
--surface: #E6EAEF;
--surface-2: #DBE1E9;
--ink: #1A222E;
--ink-2: #46505E;
--ink-3: #5F6977; /* AA on cool light (~5:1) */
--rule: rgba(40, 55, 75, 0.16);
--rule-soft: rgba(40, 55, 75, 0.07);
--accent: #E4831A; /* amber, deepened a touch for cool light fills */
--accent-ink: #A8530A; /* amber TEXT on cool light (AA ~5:1) */
--on-accent: #14202C;
--good: #2F7D55;
--shadow: 0 1px 0 var(--rule), 0 18px 40px -28px rgba(20, 30, 45, 0.35);
}
html[data-skin="midnight"][data-theme="dark"] { /* Midnight, dark (the primary mood) */
--paper: #10151C;
--surface: #1B2430;
--surface-2: #232E3C;
--ink: #E7ECF2;
--ink-2: #AAB4C2;
--ink-3: #7E8A9A;
--rule: rgba(180, 200, 225, 0.15);
--rule-soft: rgba(180, 200, 225, 0.07);
--accent: #F2A24E;
--accent-ink: #F4AC62; /* amber text on deep slate (AA) */
--on-accent: #10151C;
--good: #6FC08C;
--shadow: 0 1px 0 var(--rule), 0 24px 50px -30px rgba(0, 0, 0, 0.8);
}
/* ---- Skin: Verdigris Gate (Grok-designed) ------------------------------- */
html[data-skin="verdigris"] { /* fonts (both modes) + light palette */
--f-display: "Fraunces", Georgia, "Times New Roman", serif;
--f-body: "Source Sans 3", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
--f-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
--grain: rgba(0, 0, 0, 0.035);
--paper: #E9EDEA;
--surface: #FFFFFF;
--surface-2: #DFE5E1;
--ink: #1C2421;
--ink-2: #3F4F49;
--ink-3: #4A5853; /* AA on surface-2 band too (~5.8:1) */
--rule: rgba(28, 36, 33, 0.14);
--rule-soft: rgba(28, 36, 33, 0.07);
--accent: #2F7A6B; /* verdigris */
--accent-ink: #1F5F52; /* verdigris TEXT on plaster (AA) */
--on-accent: #FFFFFF; /* white on the teal fill clears AA (button label)*/
--good: #2F7A6B;
--shadow: 0 1px 0 var(--rule), 0 18px 40px -28px rgba(28, 40, 36, 0.4);
}
html[data-skin="verdigris"][data-theme="dark"] { /* Verdigris, dark (wet courtyard) */
--grain: rgba(255, 255, 255, 0.05);
--paper: #141A18;
--surface: #1C2421;
--surface-2: #25302C;
--ink: #E4EBE8;
--ink-2: #A8B5AF;
--ink-3: #8FA098; /* AA on surface-2 band in dark (~5:1) */
--rule: rgba(228, 235, 232, 0.12);
--rule-soft: rgba(228, 235, 232, 0.06);
--accent: #4DA896;
--accent-ink: #6BC4B0; /* verdigris text on dark (AA) */
--on-accent: #0D1614;
--good: #6BC4B0;
--shadow: 0 1px 0 var(--rule), 0 24px 50px -30px rgba(0, 0, 0, 0.8);
}
/* Verdigris signature treatments */
html[data-skin="verdigris"] .site-header {
background-color: var(--surface-2);
background-image: repeating-linear-gradient(90deg, transparent, transparent 2px,
var(--grain) 2px, var(--grain) 3px);
backdrop-filter: none;
}
html[data-skin="verdigris"] .calc__shell,
html[data-skin="verdigris"] .rate-card,
html[data-skin="verdigris"] .contact__form {
box-shadow: inset 0 0 0 4px var(--paper), inset 0 0 0 5px var(--rule), var(--shadow);
}
html[data-skin="verdigris"] .contact__form {
border: 1px solid var(--rule); background: var(--surface);
padding: calc(var(--base) * 1.25);
}
html[data-skin="verdigris"] .nav__link:hover {
background-image: linear-gradient(var(--accent), var(--accent));
background-size: 100% 2px; background-position: 0 100%; background-repeat: no-repeat;
padding-bottom: 3px; color: var(--ink);
}
html[data-skin="verdigris"] h1, html[data-skin="verdigris"] h2 { letter-spacing: -0.005em; }
/* ---- Skin: Bold (dialed-back radical) ----------------------------------- */
html[data-skin="bold"] { /* fonts (both modes) + LIGHT palette */
--f-display: "Anton", "Arial Narrow Bold", system-ui, sans-serif;
--f-body: "Hanken Grotesk", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
--f-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
--paper: #F4EDE1;
--surface: #FBF7F0;
--surface-2: #EAE2D4;
--ink: #16120F;
--ink-2: #46403A;
--ink-3: #6B6359;
--rule: rgba(22, 18, 15, 0.22);
--rule-soft: rgba(22, 18, 15, 0.10);
--accent: #E24A12; /* signal orange, deepened for bone (button fill) */
--accent-ink: #C23A0A; /* orange TEXT on bone (AA ~5.3:1) */
--on-accent: #FBF7F0;
--good: #1F7A4A;
--shadow: 0 2px 0 var(--ink), 0 24px 44px -30px rgba(22, 18, 15, 0.4);
}
html[data-skin="bold"][data-theme="dark"] { /* Bold, dark (the primary mood) */
--paper: #0C0A09;
--surface: #16120F;
--surface-2: #1E1814;
--ink: #F4EDE1;
--ink-2: #C9C1B5;
--ink-3: #9A9082;
--rule: rgba(244, 237, 225, 0.20);
--rule-soft: rgba(244, 237, 225, 0.08);
--accent: #FF5A1F;
--accent-ink: #FF8A4D; /* orange text on near-black (AA) */
--on-accent: #0C0A09;
--good: #8FD0A0;
--shadow: 0 2px 0 var(--ink), 0 24px 50px -30px rgba(0, 0, 0, 0.85);
}
/* Bold signature treatments: poster type, hard ink borders, mono photos */
html[data-skin="bold"] .ledger { background-image: none; } /* drop ledger rulings */
html[data-skin="bold"] h1, html[data-skin="bold"] h2,
html[data-skin="bold"] .tier__name, html[data-skin="bold"] .svc__name,
html[data-skin="bold"] .faq__q, html[data-skin="bold"] .brand__name {
text-transform: uppercase; letter-spacing: 0.005em; font-weight: 400;
}
html[data-skin="bold"] .hero h1 { font-size: clamp(2.8rem, 7vw, 5.5rem); line-height: 0.9; }
html[data-skin="bold"] .hero h1 .amp { -webkit-text-stroke: 0; }
html[data-skin="bold"] h2 { line-height: 0.95; }
/* hard borders */
html[data-skin="bold"] .site-header { border-bottom: 2px solid var(--ink); backdrop-filter: none;
background: var(--paper); }
html[data-skin="bold"] .trust { border-block: 2px solid var(--ink); }
html[data-skin="bold"] .rate-card, html[data-skin="bold"] .calc__shell { border: 2px solid var(--ink); }
html[data-skin="bold"] .pricing, html[data-skin="bold"] .faq,
html[data-skin="bold"] .home-services, html[data-skin="bold"] .cta-band { border-block: 2px solid var(--ink); }
/* poster numerals via Anton */
html[data-skin="bold"] .tier__price { font-family: var(--f-display); font-weight: 400;
font-size: clamp(2.8rem, 6vw, 4.25rem); letter-spacing: 0.01em; }
html[data-skin="bold"] .trust__num { font-family: var(--f-display); font-weight: 400; font-size: 2.6rem; }
html[data-skin="bold"] .calc__total .tnum { font-family: var(--f-display); font-weight: 400; }
/* sharp corners everywhere */
html[data-skin="bold"] .btn, html[data-skin="bold"] .tier, html[data-skin="bold"] .calc__shell,
html[data-skin="bold"] .rate-card, html[data-skin="bold"] select, html[data-skin="bold"] input,
html[data-skin="bold"] textarea, html[data-skin="bold"] .stepper, html[data-skin="bold"] .theme-toggle,
html[data-skin="bold"] .nav__toggle, html[data-skin="bold"] .skin-toggle,
html[data-skin="bold"] .brand__mark { border-radius: 0; }
/* monochrome documentary photos to match the palette */
html[data-skin="bold"] img { filter: grayscale(1) contrast(1.08); }
html[data-skin="bold"] .nav__link[aria-current="page"] {
background-image: linear-gradient(var(--accent), var(--accent)); }
/* ---- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
body {
background: var(--paper);
color: var(--ink);
font-family: var(--f-body);
font-size: 1rem;
line-height: 1.5; /* 24px at 16px → on-grid */
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
transition: background 0.4s ease, color 0.4s ease;
}
img { display: block; max-width: 100%; height: auto; }
a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }
::selection { background: var(--accent); color: var(--on-accent); }
.sr-only {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
/* ---- Layout primitives -------------------------------------------------- */
.wrap { width: min(100% - 3rem, var(--maxw)); margin-inline: auto; }
.wrap--narrow { width: min(100% - 3rem, 760px); margin-inline: auto; }
section { padding-block: calc(var(--base) * 3.5); }
.section-tag {
font-family: var(--f-mono);
font-size: 0.72rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--accent-ink);
display: flex; align-items: center; gap: 0.75rem;
margin-bottom: var(--base);
}
.section-tag::before { /* precision mark, not an icon font */
content: ""; width: 28px; height: 0;
border-top: 2px solid var(--accent);
}
.section-tag span { color: var(--ink-3); }
h1, h2, h3, h4 { font-family: var(--f-display); font-weight: 600; line-height: 1.04;
letter-spacing: -0.01em; color: var(--ink); }
h2 { font-size: clamp(2rem, 4.5vw, 3.25rem); margin-bottom: var(--base); }
h3 { font-size: 1.5rem; font-weight: 600; }
.lead { font-size: 1.18rem; color: var(--ink-2); max-width: 60ch; }
.muted { color: var(--ink-2); }
.mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
/* underline "ink" used on key phrases */
.ul { background-image: linear-gradient(var(--accent), var(--accent));
background-size: 100% 2px; background-position: 0 92%; background-repeat: no-repeat;
padding-bottom: 1px; }
/* ---- Buttons ------------------------------------------------------------ */
.btn {
font-family: var(--f-display); font-weight: 600; font-size: 1.05rem;
letter-spacing: 0.01em;
display: inline-flex; align-items: center; gap: 0.6rem;
padding: 0.7rem 1.4rem; border: 1px solid transparent; border-radius: 2px;
cursor: pointer; text-decoration: none; transition: transform 0.15s ease, background 0.2s ease;
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { color: var(--on-accent); filter: brightness(1.05); }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn--ghost:hover { border-color: var(--accent); color: var(--ink); }
.btn .arrow { font-family: var(--f-mono); }
/* ---- Header ------------------------------------------------------------- */
.site-header {
position: sticky; top: 0; z-index: 50;
background: color-mix(in srgb, var(--paper) 86%, transparent);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--rule);
}
.site-header .wrap { display: flex; align-items: center; gap: 1.5rem;
min-height: calc(var(--base) * 3); }
.brand { display: flex; align-items: baseline; gap: 0.6rem; text-decoration: none; color: var(--ink); }
.brand__mark { /* CSS-drawn monogram, not an image icon */
font-family: var(--f-display); font-weight: 700; font-size: 1.05rem;
letter-spacing: 0.05em; color: var(--on-accent); background: var(--accent);
padding: 0.15rem 0.5rem; border-radius: 2px; align-self: center;
}
.brand__name { font-family: var(--f-display); font-weight: 600; font-size: 1.35rem;
letter-spacing: 0.005em; }
.brand__since { font-family: var(--f-mono); font-size: 0.66rem; letter-spacing: 0.18em;
text-transform: uppercase; color: var(--ink-3); }
.nav { margin-left: auto; display: flex; align-items: center; gap: 1.2rem; }
.nav__links { display: flex; align-items: center; gap: 1.6rem; }
.nav a { font-family: var(--f-body); font-size: 0.92rem; color: var(--ink-2);
text-decoration: none; }
.nav a:hover { color: var(--ink); }
.nav__phone { font-family: var(--f-mono); color: var(--ink) !important; font-weight: 500; }
.theme-toggle, .nav__toggle {
background: transparent; border: 1px solid var(--rule); border-radius: 2px;
width: 44px; height: 44px; cursor: pointer; color: var(--ink);
display: grid; place-items: center; font-size: 1.1rem; transition: border-color 0.2s;
}
.theme-toggle:hover, .nav__toggle:hover { border-color: var(--accent); }
.nav__toggle { display: none; font-family: var(--f-mono); line-height: 1; }
@media (max-width: 880px) {
.nav__toggle { display: grid; }
.nav__links {
position: absolute; top: 100%; left: 0; right: 0;
flex-direction: column; align-items: stretch; gap: 0;
background: var(--paper); border-bottom: 1px solid var(--rule);
box-shadow: var(--shadow); padding: 0.5rem 0;
max-height: 0; overflow: hidden; visibility: hidden;
transition: max-height 0.25s ease, visibility 0.25s ease;
}
.site-header.nav-open .nav__links { max-height: 80vh; overflow-y: auto; visibility: visible; }
.nav__links a { padding: 0.85rem 1.5rem; font-size: 1.05rem;
border-top: 1px solid var(--rule-soft); }
}
/* ---- Hero --------------------------------------------------------------- */
.hero { padding-block: calc(var(--base) * 3) calc(var(--base) * 4); position: relative; }
.hero .wrap { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: calc(var(--base) * 2);
align-items: center; }
.hero__eyebrow { font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.2em;
text-transform: uppercase; color: var(--accent-ink); margin-bottom: var(--base); }
.hero h1 { font-size: clamp(2.6rem, 6vw, 4.6rem); font-weight: 700; }
.hero h1 .amp { color: var(--accent-ink); }
.hero__sub { font-size: 1.3rem; color: var(--ink-2); margin-top: var(--base);
max-width: 38ch; }
.hero__cta { display: flex; gap: 1rem; margin-top: calc(var(--base) * 1.5); flex-wrap: wrap; }
.hero__note { font-family: var(--f-mono); font-size: 0.78rem; color: var(--ink-3);
margin-top: var(--base); }
.hero__frame {
border: 1px solid var(--rule); border-radius: 2px; overflow: hidden;
box-shadow: var(--shadow); background: var(--surface); position: relative;
}
.hero__frame img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.hero__caption {
font-family: var(--f-mono); font-size: 0.72rem; color: var(--ink-2);
padding: 0.6rem 0.9rem; border-top: 1px solid var(--rule);
display: flex; justify-content: space-between; background: var(--surface);
}
@media (max-width: 860px) {
.hero .wrap { grid-template-columns: 1fr; }
.hero__frame { order: -1; }
}
/* ---- Ledger ruling background (signature) ------------------------------- */
.ledger {
background-image: repeating-linear-gradient(
to bottom, transparent, transparent 23px, var(--rule-soft) 23px, var(--rule-soft) 24px);
background-position: 0 0;
}
/* ---- Trust strip -------------------------------------------------------- */
.trust { border-block: 1px solid var(--rule); background: var(--surface); }
.trust .wrap { display: grid; grid-template-columns: repeat(4, 1fr);
gap: 1px; background: var(--rule); }
.trust__cell { background: var(--surface); padding: calc(var(--base) * 1.25) 1.25rem; }
.trust__num { font-family: var(--f-mono); font-size: 1.9rem; font-weight: 600;
color: var(--ink); line-height: 1; }
.trust__num .u { color: var(--accent-ink); }
.trust__label { font-size: 0.86rem; color: var(--ink-2); margin-top: 0.5rem; }
@media (max-width: 720px) { .trust .wrap { grid-template-columns: repeat(2, 1fr); } }
/* ---- Concierge story ---------------------------------------------------- */
.story .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--base) * 2.2);
align-items: center; }
.story__img { border: 1px solid var(--rule); border-radius: 2px; overflow: hidden;
box-shadow: var(--shadow); }
.story__img img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }
.story p + p { margin-top: var(--base); }
.story blockquote {
font-family: var(--f-display); font-weight: 500; font-size: 1.7rem; line-height: 1.18;
color: var(--ink); margin-top: calc(var(--base) * 1.5);
padding-block: var(--base); border-block: 1px solid var(--rule);
}
.story blockquote::before {
content: "\201C"; font-family: var(--f-display); color: var(--accent-ink);
font-size: 2.4rem; line-height: 0; vertical-align: -0.4em; margin-right: 0.2rem;
}
@media (max-width: 820px) {
.story .wrap { grid-template-columns: 1fr; }
.story__img { order: -1; }
}
/* ---- Services (continuous ledger list, not cards) ----------------------- */
.svc-list { border-top: 1px solid var(--rule); margin-top: var(--base); }
.svc {
display: grid; grid-template-columns: 2.4rem 1fr auto; gap: 1.25rem;
align-items: baseline; padding-block: calc(var(--base) * 0.9);
border-bottom: 1px solid var(--rule); transition: background 0.2s ease;
}
.svc:hover { background: var(--surface); }
.svc__no { font-family: var(--f-mono); font-size: 0.8rem; color: var(--ink-3); }
.svc__name { font-family: var(--f-display); font-size: 1.5rem; font-weight: 600; }
.svc__desc { color: var(--ink-2); font-size: 0.98rem; margin-top: 0.25rem; max-width: 60ch; }
.svc__meta { font-family: var(--f-mono); font-size: 0.82rem; color: var(--accent-ink);
text-align: right; white-space: nowrap; }
@media (max-width: 680px) {
.svc { grid-template-columns: 1.8rem 1fr; }
.svc__meta { grid-column: 2; text-align: left; }
}
/* ---- Pricing rate card -------------------------------------------------- */
.pricing { background: var(--surface); border-block: 1px solid var(--rule); }
.rate-card { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
background: var(--rule); border: 1px solid var(--rule); border-radius: 2px; overflow: hidden; }
.tier { background: var(--paper); padding: calc(var(--base) * 1.5) 1.5rem; position: relative;
align-self: stretch; }
.tier--pop { background: var(--surface-2); box-shadow: inset 0 3px 0 var(--accent); }
.tier__flag { position: absolute; top: 0; right: 0; font-family: var(--f-mono);
font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase;
background: var(--accent); color: var(--on-accent); padding: 0.25rem 0.6rem; }
.tier__name { font-family: var(--f-display); font-size: 1.7rem; font-weight: 600; }
.tier__price { font-family: var(--f-mono); font-size: 2.6rem; font-weight: 700;
color: var(--ink); margin-top: 0.5rem; line-height: 1; }
.tier__price .per { font-size: 0.9rem; color: var(--ink-3); font-weight: 400; }
.tier__blurb { color: var(--ink-2); font-size: 0.92rem; margin-top: 0.75rem;
padding-bottom: var(--base); border-bottom: 1px solid var(--rule); }
.tier ul { list-style: none; padding: 0; margin-top: var(--base); display: grid; gap: 0.5rem; }
.tier li { font-size: 0.92rem; color: var(--ink-2); padding-left: 1.4rem; position: relative; }
.tier li::before { content: "+"; position: absolute; left: 0; color: var(--accent-ink);
font-family: var(--f-mono); font-weight: 700; }
.tier li.is-base::before { content: "\2713"; }
@media (max-width: 820px) { .rate-card { grid-template-columns: 1fr; } }
.plans { margin-top: calc(var(--base) * 2); }
.plan-table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
.plan-table caption { text-align: left; font-family: var(--f-mono); font-size: 0.74rem;
letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-3);
padding-bottom: 0.75rem; }
.plan-table th, .plan-table td { text-align: left; padding: 0.7rem 0.9rem;
border-bottom: 1px solid var(--rule); }
.plan-table thead th { font-family: var(--f-mono); font-size: 0.72rem; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--ink-3); font-weight: 500; }
.plan-table td.num, .plan-table th.num { font-family: var(--f-mono); text-align: right;
font-variant-numeric: tabular-nums; }
.plan-table tr:hover td { background: var(--surface); }
.plan-table .pop td { color: var(--ink); }
.plan-table .pop td:first-child::after { content: " \25C6"; color: var(--accent-ink); }
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.plan-table { min-width: 460px; }
/* visible keyboard focus everywhere interactive */
.btn:focus-visible, a:focus-visible, button:focus-visible, .faq__q:focus-visible,
.theme-toggle:focus-visible, .nav__toggle:focus-visible {
outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px;
}
/* ---- Calculator (centerpiece) ------------------------------------------ */
.calc { position: relative; }
.calc__shell {
border: 1px solid var(--rule); border-radius: 2px; box-shadow: var(--shadow);
background: var(--paper); overflow: hidden;
}
.calc__grid { display: grid; grid-template-columns: 1.15fr 0.85fr; }
.calc__inputs { padding: calc(var(--base) * 1.5); border-right: 1px solid var(--rule); }
.calc__row { display: grid; grid-template-columns: 1fr auto; align-items: center;
gap: 1rem; padding-block: calc(var(--base) * 0.6); border-bottom: 1px dashed var(--rule); }
.calc__row label { font-size: 0.98rem; color: var(--ink); }
.calc__row .hint { display: block; font-size: 0.78rem; color: var(--ink-3); margin-top: 0.15rem; }
.calc__control { display: flex; align-items: center; gap: 0.5rem; }
.stepper { display: inline-flex; align-items: stretch; border: 1px solid var(--rule);
border-radius: 2px; overflow: hidden; }
.stepper button { width: 44px; min-height: 44px; border: 0; background: var(--surface);
color: var(--ink); font-family: var(--f-mono); font-size: 1.2rem; cursor: pointer; }
.stepper button:hover { background: var(--accent); color: var(--on-accent); }
.stepper input { width: 64px; height: 44px; border: 0; text-align: center; background: var(--paper);
color: var(--ink); font-family: var(--f-mono); font-size: 1.05rem; font-weight: 600;
appearance: textfield; -moz-appearance: textfield; }
.stepper input::-webkit-outer-spin-button, .stepper input::-webkit-inner-spin-button {
-webkit-appearance: none; margin: 0; }
select, .calc__control select {
font-family: var(--f-body); font-size: 0.95rem; color: var(--ink);
background: var(--paper); border: 1px solid var(--rule); border-radius: 2px;
padding: 0.5rem 2rem 0.5rem 0.7rem; cursor: pointer;
appearance: none;
background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
background-position: calc(100% - 16px) 55%, calc(100% - 11px) 55%;
background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
select:focus, .stepper input:focus, input:focus { outline: 2px solid var(--accent);
outline-offset: 1px; }
.toggle-row { display: flex; align-items: center; gap: 0.6rem; }
.switch { position: relative; width: 44px; height: 24px; flex: none; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.switch .track { position: absolute; inset: 0; background: var(--surface-2);
border: 1px solid var(--rule); border-radius: 2px; transition: background 0.2s; }
.switch .knob { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
background: var(--ink-3); border-radius: 1px; transition: transform 0.2s, background 0.2s; }
.switch input:checked + .track { background: color-mix(in srgb, var(--accent) 35%, var(--surface)); }
.switch input:checked + .track + .knob, .switch input:checked ~ .knob { transform: translateX(20px);
background: var(--accent); }
/* ledger output side */
.calc__out { padding: calc(var(--base) * 1.5); background: var(--surface);
display: flex; flex-direction: column; }
.calc__out h3 { font-size: 1.15rem; }
.ledger-lines { margin-top: var(--base); flex: 1; }
.lline { display: grid; grid-template-columns: 1fr auto; align-items: baseline;
font-family: var(--f-mono); font-size: 0.9rem; padding-block: 0.45rem;
color: var(--ink-2); }
.lline .lcost { color: var(--ink); font-variant-numeric: tabular-nums; }
.lline.dots .lname { position: relative; }
.lline.is-zero { display: none; }
.calc__divider { border: 0; border-top: 1px solid var(--ink-3); margin-block: 0.75rem; }
.calc__total { display: grid; grid-template-columns: 1fr auto; align-items: end; }
.calc__total .tlabel { font-family: var(--f-display); font-size: 1.1rem; letter-spacing: 0.02em;
text-transform: uppercase; color: var(--ink-2); }
.calc__total .tnum { font-family: var(--f-mono); font-size: 2.9rem; font-weight: 700;
color: var(--ink); line-height: 1; }
.calc__annual { font-family: var(--f-mono); font-size: 0.82rem; color: var(--ink-2);
text-align: right; margin-top: 0.4rem; }
.calc__perep { font-family: var(--f-mono); font-size: 0.82rem; color: var(--accent-ink);
margin-top: 0.2rem; text-align: right; }
.calc__cta { margin-top: var(--base); }
.calc__foot { font-size: 0.78rem; color: var(--ink-2); margin-top: 1rem; }
@media (max-width: 820px) {
.calc__grid { grid-template-columns: 1fr; }
.calc__inputs { border-right: 0; border-bottom: 1px solid var(--rule); }
}
/* ---- FAQ ---------------------------------------------------------------- */
.faq { background: var(--surface); border-block: 1px solid var(--rule); }
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__q { width: 100%; text-align: left; background: transparent; border: 0; cursor: pointer;
padding: calc(var(--base) * 0.9) 0; display: flex; justify-content: space-between;
gap: 1.5rem; align-items: center; color: var(--ink); font-family: var(--f-display);
font-size: 1.25rem; font-weight: 600; }
.faq__q .pm { font-family: var(--f-mono); color: var(--accent-ink); font-size: 1.4rem;
flex: none; transition: transform 0.2s; }
.faq__q[aria-expanded="true"] .pm { transform: rotate(45deg); }
.faq__a { overflow: hidden; max-height: 0; visibility: hidden;
transition: max-height 0.3s ease, visibility 0.3s ease; }
.faq__q[aria-expanded="true"] + .faq__a { visibility: visible; }
.faq__a-inner { padding-bottom: calc(var(--base) * 1.1); color: var(--ink-2); max-width: 70ch; }
/* ---- Contact ------------------------------------------------------------ */
.contact { padding-block: calc(var(--base) * 4.5); }
.contact .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--base) * 2.5);
align-items: start; }
.contact__lines { font-family: var(--f-mono); margin-top: var(--base); display: grid; gap: 0.6rem; }
.contact__lines .k { color: var(--ink-3); font-size: 0.72rem; letter-spacing: 0.14em;
text-transform: uppercase; }
.contact__lines .v { color: var(--ink); font-size: 1.05rem; }
.contact__lines a { color: var(--ink); }
.contact__lines a:hover { color: var(--accent-ink); }
.form-field { margin-bottom: var(--base); }
.form-field label { display: block; font-size: 0.85rem; color: var(--ink-2);
margin-bottom: 0.4rem; font-family: var(--f-mono); letter-spacing: 0.06em;
text-transform: uppercase; }
.form-field input, .form-field textarea {
width: 100%; font-family: var(--f-body); font-size: 1rem; color: var(--ink);
background: var(--paper); border: 1px solid var(--rule); border-radius: 2px;
padding: 0.65rem 0.8rem; }
.form-field textarea { min-height: calc(var(--base) * 4); resize: vertical; }
.form-note { font-size: 0.82rem; color: var(--ink-3); margin-top: 0.5rem; }
@media (max-width: 820px) { .contact .wrap { grid-template-columns: 1fr; } }
/* ---- Footer ------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--rule); padding-block: calc(var(--base) * 1.5);
background: var(--paper); }
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
align-items: center; }
.site-footer p { font-size: 0.84rem; color: var(--ink-3); font-family: var(--f-mono); }
.site-footer .disclaimer { width: 100%; font-size: 0.74rem; color: var(--ink-3);
border-top: 1px dashed var(--rule); padding-top: 0.9rem; margin-top: 0.5rem; }
/* reveal-on-scroll (gated on .js so content is visible if JS fails to run) */
.js .reveal { opacity: 0; transform: translateY(12px); transition: opacity 0.6s ease, transform 0.6s ease; }
.js .reveal.in { opacity: 1; transform: none; }
/* ===========================================================================
MULTIPAGE additions
=========================================================================== */
/* active nav */
.nav__link[aria-current="page"] {
color: var(--ink);
background-image: linear-gradient(var(--accent-ink), var(--accent-ink));
background-size: 100% 2px; background-position: 0 100%; background-repeat: no-repeat;
padding-bottom: 3px;
}
@media (max-width: 880px) {
.nav__links a[aria-current="page"] { background: var(--surface);
background-image: none; padding-bottom: 0.85rem; }
}
/* page header band (inner pages) */
.page-head { padding-block: calc(var(--base) * 2.75) calc(var(--base) * 1.75);
border-bottom: 1px solid var(--rule); }
.page-head.ledger { background-position: 0 0; }
.page-head .eyebrow { font-family: var(--f-mono); font-size: 0.76rem; letter-spacing: 0.2em;
text-transform: uppercase; color: var(--accent-ink); margin-bottom: 0.75rem; }
.page-head h1 { font-size: clamp(2.3rem, 5vw, 3.7rem); font-weight: 700; max-width: 18ch; }
.page-head .lead { margin-top: var(--base); }
.page-head--img .wrap { display: grid; grid-template-columns: 1.1fr 0.9fr;
gap: calc(var(--base) * 2); align-items: center; }
.page-head--img figure { border: 1px solid var(--rule); border-radius: 2px; overflow: hidden;
box-shadow: var(--shadow); }
.page-head--img img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }
@media (max-width: 820px) {
.page-head--img .wrap { grid-template-columns: 1fr; }
.page-head--img figure { order: -1; }
}
/* breadcrumb-ish kicker reused; group titles in services */
.svc-group { margin-top: calc(var(--base) * 2); }
.svc-group:first-of-type { margin-top: var(--base); }
.svc-group__title { font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.18em;
text-transform: uppercase; color: var(--ink-3); display: flex; align-items: center; gap: 0.75rem; }
.svc-group__title::after { content: ""; flex: 1; border-top: 1px solid var(--rule); }
/* principle list (About) reuses .svc-list; quote callout */
.bigquote { font-family: var(--f-display); font-weight: 500;
font-size: clamp(1.6rem, 3.5vw, 2.4rem); line-height: 1.2; color: var(--ink);
max-width: 24ch; }
.bigquote::before { content: "\201C"; color: var(--accent-ink); margin-right: 0.15rem; }
.signature { font-family: var(--f-mono); font-size: 0.85rem; color: var(--ink-2);
margin-top: var(--base); }
/* simple price tables grid for hosting / voip / email on pricing page */
.price-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: calc(var(--base) * 1.5); margin-top: var(--base); }
.price-block h3 { font-size: 1.3rem; }
.price-block .table-wrap { margin-top: 0.75rem; }
/* CTA band */
.cta-band { background: var(--surface); border-block: 1px solid var(--rule); }
.cta-band .wrap { display: grid; grid-template-columns: 1.3fr auto; gap: var(--base);
align-items: center; }
.cta-band h2 { margin-bottom: 0.4rem; }
.cta-band p { color: var(--ink-2); max-width: 52ch; }
.cta-band__actions { display: flex; gap: 1rem; flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 760px) {
.cta-band .wrap { grid-template-columns: 1fr; }
.cta-band__actions { justify-content: flex-start; }
}
/* teaser link */
.more-link { font-family: var(--f-display); font-weight: 600; font-size: 1.05rem;
color: var(--accent-ink); text-decoration: none; display: inline-flex; gap: 0.4rem;
align-items: center; margin-top: var(--base); }
.more-link:hover { color: var(--ink); }
.more-link .arrow { font-family: var(--f-mono); transition: transform 0.15s ease; }
.more-link:hover .arrow { transform: translateX(3px); }
/* home section spacing variety so pages don't feel templated */
.home-services { background: var(--surface); border-block: 1px solid var(--rule); }
.home-pricing .rate-card { margin-top: var(--base); }
/* contact: office figure */
.office-figure { border: 1px solid var(--rule); border-radius: 2px; overflow: hidden;
box-shadow: var(--shadow); margin-top: var(--base); }
.office-figure img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.office-figure figcaption { font-family: var(--f-mono); font-size: 0.74rem; color: var(--ink-2);
padding: 0.6rem 0.9rem; border-top: 1px solid var(--rule); background: var(--surface);
display: flex; justify-content: space-between; }
/* utilities + small-screen calculator stacking */
.inline-actions { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-top: var(--base); }
.contact__intro h1 { font-family: var(--f-display); font-weight: 700;
font-size: clamp(2.2rem, 4.5vw, 3.2rem); line-height: 1.04; }
@media (max-width: 440px) {
.calc__row { grid-template-columns: 1fr; gap: 0.5rem; }
.calc__row .calc__control { justify-self: start; }
}
/* skin switcher (Paper / Midnight) */
.skin-toggle { background: transparent; border: 1px solid var(--rule); border-radius: 2px;
width: 44px; height: 44px; cursor: pointer; display: grid; place-items: center;
transition: border-color 0.2s; padding: 0; }
.skin-toggle:hover { border-color: var(--accent); }
.skin-toggle .sw { width: 18px; height: 18px; border: 1px solid var(--rule); border-radius: 1px;
background: linear-gradient(135deg, var(--surface-2) 0 50%, var(--accent) 50% 100%); }
.skin-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 560px) { .nav__phone { display: none; } }

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

View File

@@ -0,0 +1 @@
Error: bundled detector not found.

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -u
ROOT=/d/ClaudeTools
GROK="$ROOT/.claude/skills/grok/scripts/ask-grok.sh"
OUT="$ROOT/projects/acg-website-showcase/multipage/assets/images"
cd "$ROOT"
echo "=== [1/3] services / hardware ==="
bash "$GROK" image "Photorealistic editorial close-up of a tidy small-office network setup in warm afternoon light: a clean wall-mounted patch panel and a small network switch with neatly dressed cables on a light wooden shelf against a smooth white stucco wall. Orderly, honest, premium, no logos, no text. Warm cream, tan and soft amber palette, gentle film grain, shallow depth of field. No people. Wide 3:2 landscape." "$OUT/services.png"
echo "=== [2/3] about / relationship ==="
bash "$GROK" image "Photorealistic editorial photograph, warm afternoon window light: a friendly handshake across a light-wood desk in a small Tucson office, mid-shot focusing on the two hands meeting above the desk, with a modern laptop and an open paper notebook nearby. Genuine, human, welcoming. Warm cream and tan palette, soft fine film grain, shallow depth of field. No logos, no visible faces, no text. Wide 3:2 landscape." "$OUT/about.png"
echo "=== [3/3] contact / Tucson exterior ==="
bash "$GROK" image "Photorealistic golden-hour photograph: the exterior of a modest single-story southwestern commercial building with warm hand-troweled stucco walls and a clean simple storefront, a saguaro cactus and the soft silhouette of the Santa Catalina mountains in the distance, Tucson Arizona. Calm, local, welcoming. No signage text, no people, no logos. Warm cream and amber palette, soft film grain. Wide 3:2 landscape." "$OUT/contact.png"
echo "=== DONE ==="
ls -la "$OUT"

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -u
ROOT=/d/ClaudeTools
GROK="$ROOT/.claude/skills/grok/scripts/ask-grok.sh"
OUT="$ROOT/projects/acg-website-showcase/multipage/assets/images/verdigris"
mkdir -p "$OUT"
cd "$ROOT"
echo "=== [1/4] hero: copper gate latch ==="
bash "$GROK" image "Photorealistic documentary close-up: a verdigris-patinated copper gate latch on a whitewashed stucco wall, soft cool morning side light, the latch in sharp focus and the plaster softly blurred behind it. Neutral-to-cool white balance, desaturated palette, the verdigris blue-green patina is the only saturated hue in frame, shallow depth of field, fine grain. No people, no text, no lens flare. Wide 3:2 landscape." "$OUT/hero.png"
echo "=== [2/4] services: patch panel labeling ==="
bash "$GROK" image "Photorealistic documentary photo: a pair of hands labeling a network patch panel with small neat handwritten tags, careful and human, cool neutral light, shallow depth of field, desaturated palette with a faint hint of verdigris green. Industrial, orderly, transparent process. No faces, no logos, no text on screen. Wide 3:2 landscape." "$OUT/services.png"
echo "=== [3/4] about: weathered enamel storefront sign ==="
bash "$GROK" image "Photorealistic documentary photo: a weathered hand-painted enamel storefront service sign mounted on a whitewashed Tucson stucco wall, cared-for but not glossy, the lettering soft and partly out of focus, partial sidewalk and plaster visible. Cool neutral white balance, side light, desaturated palette with verdigris-green and aged-metal accents. No people. Wide 3:2 landscape." "$OUT/about.png"
echo "=== [4/4] contact: cool Tucson storefront ==="
bash "$GROK" image "Photorealistic documentary photo: the exterior of a tidy 1950s single-story Tucson stucco storefront in cool overcast morning light, whitewashed plaster walls, a weathered copper-patina door pull and trim, clean simple windows. Calm, local, cared-for. Cool neutral white balance, desaturated palette, verdigris-green the only saturated hue. No signage text, no people. Wide 3:2 landscape." "$OUT/contact.png"
echo "=== DONE ==="; ls -la "$OUT"

View File

@@ -0,0 +1,20 @@
You are the lead designer. Originate ONE complete, opinionated, buildable art direction for a website. I will implement it exactly, then put it through an independent design critique, so be concrete and commit.
THE SITE: A multipage marketing website for "Arizona Computer Guru" (ACG), a Tucson managed-IT and cybersecurity company since 2001. Differentiator: "concierge IT" (genuine relationships, going far beyond typical IT companies, transparent honest pricing, kind and direct, local). Audience: Tucson small-business owners, often burned before by surprise bills, offshore call centers, three-year lock-ins. The site sells trust first. Pages: Home, Services, Pricing, Calculator (interactive IT-cost estimator), About, Contact.
HARD CONSTRAINTS:
- Hand-built static HTML/CSS/vanilla-JS, driven by CSS custom-property design tokens. So give me CONCRETE values.
- Must be genuinely premium and distinctive, and must NOT look like generic AI-slop SaaS (no blue/purple gradient blobs, no floating 3D isometrics, no glowing shields, no hero-metric template, no identical icon-card grids).
- ALL text must be readable (WCAG AA, ~4.5:1 body) in BOTH a light theme AND a dark theme.
- It must be DISTINCT from the two skins this site already has: (1) "Sonoran Ledger" = warm cream paper, ledger rulings, mono numerals, burnt-amber accent; (2) "Midnight Concierge" = cool slate dark-premium with amber accent. Do not give me a third variation on warm-paper or cool-slate. Go somewhere new.
DELIVER, in this structure:
1. NAME.
2. CONCEPT: one tight paragraph. Name a real-world reference object/aesthetic so it is not generic.
3. COLOR TOKENS, explicit hex, for BOTH modes. Give exactly these roles for LIGHT and for DARK: paper (bg), surface, surface-2, ink (primary text), ink-2 (secondary), ink-3 (muted), rule (hairline rgba), accent (the one signal color used <=10%), accent-ink (the accent as TEXT, AA-safe on that mode's bg), on-accent (text on an accent fill). Keep chroma sane at extremes. State the accent hue you chose and why (you may keep ACG's amber or pick a new brand-justified color).
4. TYPOGRAPHY: display + body + mono families (real Google Fonts). You MAY change from the current Barlow Condensed / Lexend / JetBrains Mono if your concept needs it; justify. Note weights and the hierarchy approach.
5. SIGNATURE MOVES: 2-4 concrete, distinctive treatments that define the look (what replaces ledger rulings, corner radius, dividers, the way pricing/the calculator are framed, motion). Be specific enough to build.
6. IMAGERY: describe the hero image + 2 section images you want (photographic, so I can generate them with an image model), and the overall art-direction of photography (light, palette, mood). Say if existing warm golden-hour Tucson photos (desk-with-ledger, handshake, stucco storefront) should be reused or replaced.
7. ANTI-SLOP: 3 specific reasons this will not read as AI-generated, and name the single biggest risk that it DOES, plus how to avoid it.
Keep it tight and decisive, under ~750 words. Commit to specifics; do not hedge with ranges.

View File

@@ -0,0 +1,96 @@
# 1. NAME
**Verdigris Gate**
---
# 2. CONCEPT
Reference object: the **oxidized copper hardware on a maintained 1950s Tucson stucco storefront** — whitewashed plaster, brushed aluminum door pulls weathered to verdigris, hand-painted enamel service signage. Premium through material honesty, not dashboard gloss. Concierge IT is the gate you walk through: labeled, direct, locally kept. The site should feel like that buildings fascia and service counter, not a SaaS landing template.
---
# 3. COLOR TOKENS
**Accent hue: Verdigris (#2F7A6B light / #4DA896 dark).** Copper oxidation is Tucson-native (pipes, roof flashings, desert hardware) and signals stewardship and longevity — not alarm-red security or fintech amber. Used ≤10%: primary CTA, active nav rule, calculator totals, one pull-quote bar.
### Light (plaster day)
| Role | Value |
|---|---|
| paper | `#E9EDEA` |
| surface | `#FFFFFF` |
| surface-2 | `#DFE5E1` |
| ink | `#1C2421` |
| ink-2 | `#3F4F49` |
| ink-3 | `#5C6B65` |
| rule | `rgba(28, 36, 33, 0.12)` |
| accent | `#2F7A6B` |
| accent-ink | `#1F5F52` |
| on-accent | `#F0F7F5` |
### Dark (wet courtyard night)
| Role | Value |
|---|---|
| paper | `#141A18` |
| surface | `#1C2421` |
| surface-2 | `#25302C` |
| ink | `#E4EBE8` |
| ink-2 | `#A8B5AF` |
| ink-3 | `#7A8A84` |
| rule | `rgba(228, 235, 232, 0.10)` |
| accent | `#4DA896` |
| accent-ink | `#6BC4B0` |
| on-accent | `#0D1614` |
All body pairs (`ink` on `paper`, `ink-2` on `surface`) exceed 4.5:1. `accent-ink` is for text links and inline emphasis on backgrounds, never large accent fills.
---
# 4. TYPOGRAPHY
**Display: Fraunces** (Google Fonts) — weights 500 (H1), 400 (H2H3). Soft, old-metal signage energy; breaks SaaS sans uniformity without ledger nostalgia.
**Body: Source Sans 3** — 400 body, 600 labels/nav. Humanist, plainspoken; reads kind and direct at 18px/1.6.
**Mono: IBM Plex Mono** — 400 inputs, 500 calculator totals and pricing figures. Clinical where money is discussed.
**Hierarchy:** One Fraunces H1 per page (max 48px). Sections lead with Source Sans 600 uppercase tracked labels (11px, `letter-spacing: 0.08em`, `ink-3`) — enamel caption style. No hero metrics; trust copy is body-scale, not billboard numbers.
---
# 5. SIGNATURE MOVES
1. **Enamel double-rule frames** — Pricing tiers, calculator shell, and contact form sit inside a 1px `rule` border with a second 1px border 4px inset (no outer glow). `border-radius: 2px` everywhere. Max corner radius site-wide: 4px on buttons only.
2. **Gate-rail header** — Nav lives on a full-width `surface-2` band with a CSS brushed-metal grain (`repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(0,0,0,0.03) 2px, rgba(0,0,0,0.03) 3px)` in light; `0.06` opacity in dark). Not floating, not sticky glass.
3. **Verdigris underscore navigation** — Links are `ink`; hover/active = 2px `accent` bottom border. One filled `accent` button per viewport (primary CTA). Secondary actions are outlined `rule` borders, never ghost gradients.
4. **Calculator as meter tape** — The estimator is a vertical stack on `surface-2`, top edge perforated via `radial-gradient(circle, paper 30%, transparent 31%)` spaced 8px. Live total in IBM Plex Mono 28px `accent-ink` on `paper` strip — receipt, not widget card. Sliders are 2px track + square 12px thumb (no pill toggles).
**Motion:** 180ms ease on border-color and underscore only. No parallax, no blob drift. Theme toggle cross-fades `color`/`background-color` 200ms.
---
# 6. IMAGERY
**Photography direction:** Documentary maintenance photography — neutral-to-cool white balance, side light, shallow depth of field, desaturated greens and plaster whites, verdigris as the only saturated hue in frame. No lens flare, no neon, no server-room blue wash.
- **Hero:** Close-up of a **verdigris-patinated copper gate latch** on white stucco, morning side light, latch sharp / stucco soft blur. Conveys “local gatekeeper,” not “cyber shield.”
- **Services section:** **Hands labeling a network patch panel** with handwritten tags — neat, human, transparent process.
- **About section:** **Weathered hand-painted enamel “Computer Guru” sign** on a Tucson storefront, cared-for not glossy, partial stucco and sidewalk visible.
**Reuse verdict:** **Replace** golden-hour desk-with-ledger (too Sonoran Ledger), **replace** generic handshake (stock trust cliché). **Adapt** stucco storefront only if re-shot cooler/plaster-toned with enamel-sign framing; do not reuse warm golden-hour grade.
---
# 7. ANTI-SLOP
**Why this wont read AI-generated:**
1. Verdigris-on-plaster palette — neither blue-purple SaaS nor amber concierge variants already in the repo.
2. Fraunces serif + enamel double-rules — explicitly rejects icon-card grids and rounded-16px component libraries.
3. Calculator-as-meter-tape and gate-rail nav are site-specific behaviors, not interchangeable hero-metric templates.
**Biggest risk:** Fraunces + muted green reads **boutique wellness spa**, not MSP.
**Avoid it:** Keep photography industrial (patch panels, hardware, signage). Use IBM Plex Mono and plain-dollar copy on Pricing. No leaf motifs, no “wellness” whitespace — use `surface-2` bands and double-rules to maintain civic/commercial weight. Fraunces only on headlines; body stays Source Sans at 18px minimum.

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

View File

@@ -0,0 +1,45 @@
**index.html**
- [WARN] Cross-page consistency: The inline theme `<script>` in the `<head>` is unminified, whereas it is a minified one-liner in the other 5 pages (line 12).
- [WARN] Cross-page consistency: Footer `<p class="disclaimer">` text heavily drifts/diverges from the strings used on other pages (line 109).
- [WARN] Inline styling: Uses a hardcoded `<div style="display:flex;gap:1.5rem;flex-wrap:wrap;margin-top:var(--base);">` instead of a CSS utility class (line 94).
**services.html**
- [ERROR] Accessibility: Missing semantic headings. Item titles use `<div class="svc__name">` inside `<article>` tags instead of heading elements (line 46). Group titles use `<p class="svc-group__title">` instead of headings (line 44).
- [WARN] Cross-page consistency: Footer disclaimer text drifts from other pages (line 78).
**pricing.html**
- [ERROR] Accessibility: Missing semantic headings. The rate cards use `<div class="tier__name">` instead of `<h3>` elements (line 37).
- [WARN] Cross-page consistency: Footer disclaimer text drifts from other pages (line 107).
**calculator.html**
- [OK] Accessibility: Form controls are properly labeled, input modes are specified, and `aria-live` is correctly placed on the total output.
- [WARN] Cross-page consistency: Footer disclaimer text drifts from other pages (line 90).
**about.html**
- [ERROR] Accessibility: Missing semantic headings. Similar to the services page, item names inside the `.svc-list` are structured as `<div class="svc__name">` instead of headings (line 51).
- [WARN] Cross-page consistency: Footer disclaimer text drifts from other pages (line 81).
**contact.html**
- [WARN] Inline styling: The main page heading uses heavy inline styles `<h1 id="contact-h" style="...">` rather than pulling from the stylesheet (line 39).
- [WARN] Cross-page consistency: Footer disclaimer text drifts from other pages (line 80).
**styles.css**
- [ERROR] House Rules: An em dash (`—`) is used in the header comment string block, violating the strict no em dash rule (line 2).
- [ERROR] WCAG AA Contrast: The `active nav underline` uses `var(--accent)` (orange) on `--paper` (cream), which fails the 3:1 non-text contrast requirement in light mode (line 348).
- [ERROR] WCAG AA Contrast: The `.bigquote::before` quotation mark uses `var(--accent)` on `--paper`, failing the 3:1 ratio for large text in light mode (line 364).
- [ERROR] WCAG AA Contrast: The `.office-figure figcaption` uses `var(--ink-3)` on `var(--surface)`. While `--ink-3` passes on `--paper`, the darker `--surface` background causes this to fail the 4.5:1 ratio for small text in light mode (line 386).
- [WARN] Responsive risk: The mobile nav `.nav__links` relies on `max-height: 60vh; overflow: hidden;`. On short landscape viewports, overflowed links will clip and become entirely inaccessible because it lacks `overflow-y: auto` (line 103).
- [OK] House Rules: Verified no side-stripe accent borders (`border-left` / `border-right`) are used on components.
**app.js**
- [OK] Calculator handoff logic: Cleanly captures `.lname` and `.lcost` strings, utilizes `.textContent` to safely strip nested spans/HTML entities (like `&times;`), and successfully targets the contact textarea via `sessionStorage`.
- [INFO] Handoff edge case: The `acg-estimate` payload is *only* saved when clicking the specific `#sendEstimate` button (line 125). If a user builds an estimate and manually clicks the "Contact" header link, their built estimate is lost.
### Prioritized Fix List
1. **WCAG Contrast Check:** In `styles.css`, darken `--accent` (or swap to `--accent-ink`) for active nav underlines and `.bigquote` marks in light mode. Change the `.office-figure figcaption` text color to `--ink-2` to pass 4.5:1 contrast on `--surface`.
2. **Semantic Hierarchy:** Convert `<div class="svc__name">`, `<div class="tier__name">`, and `<p class="svc-group__title">` elements to appropriate heading tags (`<h3>`, `<h4>`) across `services.html`, `pricing.html`, and `about.html`.
3. **Mobile Nav Overflow Risk:** Add `overflow-y: auto` to `.nav__links` within the `@media (max-width: 880px)` query in `styles.css` to prevent clipping.
4. **Markup Unification:** Standardize the varying footer `.disclaimer` text into a single unified string across all 6 HTML pages to resolve cross-page drift. Do the same for the `<head>` theme inline `<script>`.
5. **CSS Cleanup:** Relocate the inline styles from `index.html` (line 94) and `contact.html` (line 39) into utility or block classes in `styles.css`.
6. **House Rules:** Delete the em dash on line 2 of `styles.css`.
7. **Handoff Improvement (Optional):** Bind the `sessionStorage.setItem` call to the `recalc` function in `app.js` so the estimate auto-saves, preventing data loss if a user navigates to the contact page manually.

View File

@@ -0,0 +1,48 @@
[INFO] INDEPENDENT DESIGN & CODE REVIEW
Verdict: The 'Blowout' concept effectively shatters boring MSP templates, but heavily overshoots "trust" into "retail clearance" territory. It requires strategic dialing back to balance radical boldness with B2B stability.
---
### 1. DIAL-BACK STRATEGY (Ranked)
1. [ERROR] Overshoot: 13rem poster-typography (`radical.css:54`). Screams "event poster", refuting stability.
> Alternative: Cap clamp at ~5-6rem. Keep Anton, but size it for authority, not alarm.
2. [ERROR] Overshoot: Drenched signal-orange background blocks (`radical.css:80`, `radical.css:143`). Triggers urgency/warning semantics.
> Alternative: Restrict orange exclusively to interactive elements/accents. Use `--ink` for section backgrounds.
3. [WARN] Overshoot: 8.5rem blowout price numerals (`radical.css:128`). Reads as a discount warehouse.
> Alternative: Scale down to 3-4rem. Keep the transparent grid, but refine the typography.
4. [WARN] Overshoot: Infinite scrolling marquee (`radical.html:36`). Associated with aggressive retail.
> Alternative: Replace with a static, horizontal trust bar (logos or key features) below the hero.
5. [INFO] Overshoot: 16rem transparent ghost numerals (`radical.css:102`). Adds meaningless visual noise.
> Alternative: Remove entirely. Rely on the stark grid and whitespace.
### 2. WHAT TO KEEP
[OK] The `--ink` and `--bone` palette foundation: highly premium and tech-forward.
[OK] The brutalist structural borders (`2px solid var(--bone)`): communicates transparency and zero-BS.
[OK] Direct, no-fluff copywriting ("Everything, handled", "No games").
[OK] JetBrains Mono for metadata: adds legitimate engineering credibility.
### 3. WCAG AA CONTRAST
[ERROR] Orange text on `--ink`: `#FF5A1F` on `#0C0A09` yields ~4.3:1. Fails AA for body text.
> Corrected hex: Use `--hot-2` (`#FF8A4D`) for all orange text on dark backgrounds. Confidence: High.
[ERROR] Black on `#FF5A1F` (`rx-price--pop` unit text): `#0C0A09` on `#FF5A1F` at `opacity: 0.7` (`radical.css:131`). Fails functional contrast.
> Corrected hex: Remove opacity. Use solid `#0C0A09`. Confidence: High.
[ERROR] Stroke headline (`radical.css:57`): Transparent fill with 2px stroke fails functional contrast for low-vision users. Shape is lost.
> Corrected hex: Replace `color: transparent;` with solid `color: #F4EDE1;` (`var(--bone)`). Confidence: High.
[WARN] Bone-2 on `--ink`: `#B8AE9E` on `#0C0A09`. Technically passes (~7.3:1), but thin font (`radical.css:13`) makes it functionally weak.
> Corrected hex: Lighten to `#C9C1B5` or increase font-weight to 500. Confidence: Medium.
### 4. ACCESSIBILITY
[ERROR] Marquee data loss (`radical.html:35`): Claim: `aria-hidden="true"` is fine for decorative elements. Refutation: The values ("Since 2001", "No offshore") are not exposed to screen readers *anywhere else* in the DOM. Core value propositions are completely lost. Confidence: High.
[WARN] Focus management (`radical.css:76`): Claim: Global `:focus-visible` outline is visible. Refutation: Uses `--hot`. For `.rx-btn--hot` placed on a `--hot` background (like the CTA section), the outline relies entirely on `outline-offset`, becoming invisible. Confidence: High.
[OK] `prefers-reduced-motion` (`radical.css:21`): Correctly zeroes out animations.
[OK] Decorative image (`radical.html:26`): `alt=""` and `aria-hidden="true"` correctly implemented.
### 5. RESPONSIVE RISKS
[ERROR] Layout break (`radical.css:122`): 3-column pricing grid persists down to 761px. At ~761px-950px, 8.5rem text will overflow column bounds.
[WARN] Hover reflow (`radical.css:112`): `.rx-svc:hover` increases `padding-left: 1rem;` without initial padding compensation, causing text to abruptly jump right.
[WARN] Viewport overflow (`radical.css:54`): `clamp(3.5rem, ...)` sets a 56px minimum. The word "picks" may exceed a 320px width viewport, triggering horizontal scroll.
### 6. REAL CODE / MARKUP BUGS
[ERROR] Negative margin clip (`radical.css:55`): `margin-left: -0.06em;` on `h1` risks clipping the first letter ("I") outside the scrollable area.
[WARN] Inline styles (`radical.html:46`): `<div class="rx-svc-list" style="margin-top:2.5rem;">` violates structural separation.
[INFO] Legacy prefixing (`radical.css:58`): `text-stroke` is non-standard. `-webkit-text-stroke` is sufficient for all modern engines.

View File

@@ -0,0 +1,25 @@
[VERDICT] Verdigris Gate is structurally safe, cleanly scoped, and transitions reliably. However, it requires a minor contrast fix and a critical font-weight correction to prevent text degradation.
### 1. WCAG AA Contrast
- [ERROR] Light Primary Button: `--on-accent` (#F0F7F5) on `--accent` (#2F7A6B) yields ~4.4:1 contrast. At 1.05rem (16.8px) 600-weight, this fails the 4.5:1 requirement for normal-sized text.
*Fix: Lighten `--on-accent` to `#FFFFFF` (yields 4.9:1) or darken `--accent` to `#2B7364`.*
- [OK] Light Mode Base: Body text (10.9:1), muted text (6.4:1), and accent-ink (#1F5F52, 5.6:1) on #E9EDEA all comfortably pass.
- [OK] Dark Mode Base: Body text, muted text (7.6:1), accent-ink (#6BC4B0, 8.5:1), and primary button (#0D1614 on #4DA896, 6.5:1) on #141A18 all pass.
### 2. Typography & Faux-Bold Risk
- [ERROR] Missing Font Weights: Fraunces and IBM Plex Mono are loaded at 400;500 but are heavily applied at 600 and 700 across headings, buttons, and pricing tiers. This will force destructive, browser-synthesized faux-bolding.
*Fix: Append `600;700` to both Fraunces and IBM Plex Mono in the `<link>` Google Fonts payload.*
### 3. app.js Logic & Skin Swapping
- [OK] 3-Way Cycle: Modulo logic (`(cur + 1) % SKINS.length`) safely iterates `ledger -> midnight -> verdigris` and gracefully fails to index 0 (`ledger`) on null or corrupt local storage states.
- [OK] Image Swapping: `swapSkinImages` uses `getAttribute("src")` to correctly capture the un-resolved relative string, strictly matching `VERDIGRIS_IMG` keys. Reversal logic using `data-orig-src` is sound.
- [WARN] Double-Download (LCP impact): Because image `src` is hardcoded in HTML, direct loads into the Verdigris skin will fetch the `orig` image first, then immediately request the Verdigris variant.
### 4. Specificity & Token Leaks
- [OK] Token Scoping: No token leakage. `html[data-skin="verdigris"]` (0,1,1) securely overrides `:root` (0,1,0) and detaches entirely when the attribute changes.
- [OK] Signature Elements: Override rules like `html[data-skin="verdigris"] .site-header` (0,2,1) successfully trump base class styles `.site-header` (0,1,0) without relying on `!important`.
### 5. Accessibility Regressions
- [OK] Focus Navigation: Verdigris `--accent` maintains strong visibility as an outline color (4.47:1 against paper), preserving keyboard interaction cues.
- [INFO] Stale Static Tooltip: The static HTML `title` and `aria-label` for `#skinToggle` only declare "Paper / Midnight".
*Fix: Update the initial static HTML to "Paper / Midnight / Verdigris" so pre-JS screen readers announce it accurately.*

View File

@@ -0,0 +1,161 @@
Reading all eight files for an independent review across the listed defect categories.
Searching for em dashes, side-stripe patterns, and verifying assets exist.
## Verdict
**[OK] Ship-ready demo with one real handoff gap and a few UX/mobile nits.** Nav/`aria-current` are correct per page, calculator math matches published rates, assets resolve, and the normal left-click estimate flow works. I found no broken internal links and no user-facing em dashes or side-stripe accent borders.
**Confidence: high** on nav/math/links; **medium** on narrow-mobile layout (CSS-only inference, not browser-tested).
---
## 1. Cross-page header / footer / nav
**[OK] Header structure is consistent** across all six pages: same brand, six nav links, phone, theme toggle, mobile menu (`navLinks`, `navToggle`, `themeToggle`).
**[OK] `aria-current="page"` is correct** on every page:
| Page | Active link |
|------|-------------|
| `index.html:38` | Home |
| `services.html:26` | Services |
| `pricing.html:27` | Pricing |
| `calculator.html:28` | Estimate |
| `about.html:29` | About |
| `contact.html:33` | Contact |
**[WARN] Footer disclaimer copy drifts** (not broken, but inconsistent):
- `index.html:152` — longest (estimator + tailored quote)
- `about.html:112` — no pricing disclaimer at all
- `contact.html:106` — form-not-wired note only
**[INFO] Cosmetic head-script formatting** differs (`index.html` expanded vs minified on other pages). No functional impact.
---
## 2. Calculator → contact estimate handoff
**[OK] Normal left-click path works.** Flow:
```140:153:D:\ClaudeTools\projects\acg-website-showcase\multipage\js\app.js
var sendBtn = $("#sendEstimate");
if (sendBtn) {
sendBtn.addEventListener("click", function () {
// ... builds summary from #ledgerLines ...
try { sessionStorage.setItem("acg-estimate", summary); } catch (e) {}
});
}
```
```192:201:D:\ClaudeTools\projects\acg-website-showcase\multipage\js\app.js
var msg = $("#cf-msg");
if (msg) {
try {
var est = sessionStorage.getItem("acg-estimate");
if (est) {
msg.value = est;
sessionStorage.removeItem("acg-estimate");
```
- `#sendEstimate` is an `<a href="contact.html#contact">` (`calculator.html:124`)
- Click handler is synchronous before navigation — `sessionStorage` is set in time
- `app.js` is at end of `<body>` on `contact.html:109`, so `#cf-msg` exists before prefill runs
- Anchor target `#contact` exists (`contact.html:43`)
**[OK] JS-before/after hash jump is not a data bug.** Script runs after DOM parse; hash scroll does not block prefill.
**[ERROR] Middle-click / “Open in new tab” drops the estimate.** `#sendEstimate` is a plain link; middle-click and some modifier opens navigate without firing the `click` listener, so `acg-estimate` is never written. Left-click only.
**[WARN] Hash lands on section top, not the form.** `contact.html#contact` scrolls to the section (`id="contact"`), not `#cf-msg` / `#contactForm`. On desktop two-column layout, the prefilled textarea can be off-screen right; user may not see the handoff without scrolling.
**[WARN] No focus management after prefill** — textarea is filled but never focused/scrolled into view.
**[INFO] One-shot storage** — reload clears the estimate (`removeItem` on read). Intentional, but worth knowing.
---
## 3. Calculator math and stepper clamp
**[OK] Math matches pricing page rates:**
| Input | Rate | Source |
|-------|------|--------|
| GPS tiers | $19 / $26 / $39 | `app.js:99`, `pricing.html:56-82` |
| Equipment | $25 flat | `app.js:78`, `pricing.html:94` |
| Support | $200$850 | `app.js:94`, `pricing.html:108-111` |
| M365 | $14/user | `app.js:78`, `pricing.html:154` |
| VoIP | $28/user | `app.js:78`, `pricing.html:166` |
| Hosting | $15 / $35 / $65 | `app.js:97`, `pricing.html:141-143` |
Default (22 endpoints, Pro, Standard support): **$952/mo** — arithmetic checks out.
**[OK] Stepper clamp** — `clampInt` 0500 (`app.js:80`), HTML `min="0" max="500"`, buttons use clamp + `recalc()`.
**[WARN] Typing invalid numbers** — `recalc()` uses clamped value on `input`, but the visible field can still show garbage until `change` blur clamp (`app.js:136`). Totals can disagree with displayed digits briefly.
---
## 4. Links, assets, duplicate IDs
**[OK] All internal page links resolve** — `index`, `services`, `pricing`, `calculator`, `about`, `contact`, `tel:`, `mailto:`.
**[OK] Referenced images exist** under `assets/images/`: `hero.png`, `about.png`, `services.png`, `story.png`, `contact.png`.
**[WARN] Duplicate `id="cta-h"`** on four pages (`index.html:137`, `services.html:88`, `pricing.html:179`, `about.html:97`). Harmless in multipage navigation; invalid if pages were ever combined.
**[WARN] Shared IDs across pages** (`year`, `navLinks`, `themeToggle`, etc.) — same note; one page at a time so no runtime collision.
---
## 5. Light + dark contrast (new components)
**[OK] Token design is deliberate** — `--ink-3` annotated AA-safe on light paper (`styles.css:14`); dark tokens mirrored (`styles.css:32-44`).
**[OK] New multipage components** (active nav underline, page-head eyebrow, contact labels, CTA band, office figure) use `--ink`, `--ink-2`, `--ink-3`, `--accent-ink` — consistent with the system.
**[WARN] `.calc__foot` at 0.78rem / `--ink-3`** (`styles.css:374`) — likely fine in light mode; dark-mode small muted text is the usual borderline case. Worth a quick contrast pass in browser, not a confirmed fail.
**[OK] Primary buttons** — `--on-accent` on `--accent` is an intentional pairing (`styles.css:18-19, 118`).
---
## 6. Em dashes and side-stripe accents
**[OK] No em dashes in user-facing HTML** across any of the six pages.
**[WARN] Em dashes only in CSS comments** (`styles.css:2, 17`) — violates house style in source, not visible to visitors.
**[OK] No forbidden side-stripe accent borders.** Only structural rules: `.calc__inputs { border-right: 1px solid var(--rule) }` (`styles.css:310`), `.tier--pop` top inset accent (`styles.css:263`). Matches DESIGN intent (no colored left/right accent stripes).
---
## 7. Mobile
**[OK] Major breakpoints covered** — nav drawer @880px, hero/story/calc/contact/CTA stack @760820px, trust 2-col @720px, tables scroll via `.table-wrap`.
**[WARN] Calculator rows stay two-column on all widths** — `.calc__row { grid-template-columns: 1fr auto }` (`styles.css:311-312`) with no narrow override. Stepper is ~152px fixed; on ~320px viewports labels + controls may crush or overflow.
**[WARN] `.svc__meta { white-space: nowrap }`** (`styles.css:251`) — on very narrow screens, right-aligned meta could overflow when not yet in stacked mobile layout.
**[OK] Mobile nav** — `aria-expanded` toggles, Escape closes, link click closes drawer (`app.js:57-69`).
**[ERROR] Progressive enhancement gap** — `.reveal { opacity: 0 }` (`styles.css:427`) until `app.js` adds `.in`. If JS fails, large sections stay invisible sitewide.
---
## Ranked top fixes
| Rank | Severity | Issue | Where |
|------|----------|-------|-------|
| **1** | **[ERROR]** | Estimate handoff fails on middle-click / open-in-new-tab because storage write is click-only on an `<a>` | `calculator.html:124`, `app.js:140-153` |
| **2** | **[ERROR]** | Content hidden without JS (`.reveal` starts at `opacity: 0`) | `styles.css:427-428`, all pages |
| **3** | **[WARN]** | After handoff, user may not see prefilled message (hash → section, not form; no focus/scroll) | `calculator.html:124`, `contact.html:43-76`, `app.js:192-201` |
| **4** | **[WARN]** | Calculator input rows dont stack on very narrow phones | `styles.css:311-312, 375-378` |
| **5** | **[WARN]** | Invalid stepper text vs calculated total until blur | `app.js:136-137, 156-157` |
| **6** | **[INFO]** | Footer disclaimer text inconsistent | all footers |
| **7** | **[INFO]** | Duplicate `id="cta-h"` across four pages | see §4 |
| **8** | **[INFO]** | Em dashes in CSS comments only | `styles.css:2, 17` |
---
**Bottom line:** The multipage shell is coherent and the primary estimate workflow is sound. Fix **#1** (handoff reliability) and **#2** (no-JS visibility) first; the rest are polish. I did not modify any files per your instruction.

View File

@@ -0,0 +1,58 @@
**VERDICT**
[INFO] Radical "Blowout" poster concept (Anton 13rem, #FF5A1F drench, marquee, stroke outline, giant pricing) succeeds at raw visual arrest and hierarchy but oversteps for a Tucson MSP selling long-term trust and concierge reliability. It reads like a one-day sale flyer more than a stable partner. radical.html + radical.css reviewed in full. No modifications performed.
**(1) DIAL-BACK list (ranked 1 = most damaging for trust sale)**
1. [HIGH] Hero headline scale + Anton ultra-condensed at clamp(3.5rem, 16vw, 13rem) (radical.html:36, radical.css:70). 13rem on desktop and still 7-9rem on tablets feels like carnival signage, not enterprise IT. Tamer: cap at clamp(2.75rem, 7vw, 5.75rem); keep Anton for one word only or add 0.03-0.04em tracking and switch subheads to Hanken Grotesk 700.
2. [HIGH] Full-bleed #FF5A1F CTA section + multiple hot buttons and pop pricing tier (radical.html:112, radical.css:175, 148, 96). Orange overload + "Talk to a human" at 10rem screams urgency/deal, erodes calm authority. Tamer: limit full-bleed hot to one primary CTA band only; use bone/ink inverted or bone-bordered buttons elsewhere; reserve solid hot for the single highest-value action.
3. [MED] 26s continuous marquee on full #FF5A1F bar (radical.html:46-50, radical.css:104, 107). Perpetual motion + saturated strip reads gimmicky for a 2001-established MSP. Tamer: 48-60s duration or convert to static centered pills row; keep hot only for text if bar must remain.
4. [MED] Transparent-fill -webkit-text-stroke headline on "up." (radical.html:36, radical.css:73-75). 2px bone outline with no interior fill creates thin, haloed, low-density letters that feel unfinished and hard to parse at speed. Tamer: solid bone or hot fill + 1px hot or bone underline/shadow; drop stroke entirely for body copy sizes.
5. [MED] Volume and placement of hot / hot-2 accents (kickers, eyebrow, svc__n, svc__meta, price pop, cta) (radical.css:42, 67, 117, 136, 148, 175). Too many saturated hits dilute focus and hierarchy. Tamer: restrict #FF5A1F to 1-2 CTAs + one price highlight; use bone-2 or ink-2 for meta; replace most hot-2 with bone or a darker orange variant.
6. [LOW] Giant ghost section numerals (16rem clamp) + 8.5rem pricing numerals (radical.css:121, 151). Poster numerals compete with actual content and make pricing feel theatrical. Tamer: ghost max 5-6rem; pricing bigs to clamp(2.5rem, 5vw, 4rem) or switch to weighted Hanken Grotesk for numerals while keeping Anton for true headlines.
**(2) KEEP (moves that are genuinely strong)**
- Direct "no email wall" calculator teaser and published per-endpoint grid with clear tiering and "most chosen" callout (radical.html:100-107, 76-95). Honest pricing posture is the single biggest trust signal here.
- Service row hover + IntersectionObserver reveal (radical.html:134-140, radical.css:194-195, 131). Subtle progressive disclosure without heavy JS.
- Mono + poster font pairing for scannability and brand lockup in header (radical.css:18-20, 51-56).
- Sticky header, phone CTA, and immediate human contact paths without friction.
- Self-contained file, proper lang/meta, skip link, and existing reduced-motion rule (radical.html:15, 8-12, radical.css:26-30).
**(3) WCAG AA contrast failures**
- Black #0C0A09 on #FF5A1F (rx-btn--hot, marquee text, rx-cta hot buttons, price pop): estimated 8-10:1+. Passes AA/AAA for large text and UI components. [OK]
- #FF5A1F on #0C0A09 (`.hot`, rx-kicker, rx-hero__eyebrow, rx-svc__n): ~3.6-4.0:1. FAILS AA for normal text (needs 4.5:1). Passes only if treated strictly as large text. Corrected hex for reliable AA: #FF7A4D or #FF8F60 (brighter) or switch accent text to #F4EDE1 bone on dark.
- #FF8A4D on #0C0A09 (svc__meta, some price units): ~2.8-3.2:1. FAILS AA. Corrected: #FFB57A or replace with #F4EDE1 / #CFC6B4.
- #B8AE9E (bone-2) on #0C0A09 (rx-hero__sub, rx-svc__d, rx-price__list, footer, calc p): ~4.1-4.4:1. FAILS AA 4.5:1 for body text under ~18pt/14pt bold. Corrected: #CFC6B4 or #D8D0C0 (lighten ~10-12%).
- -webkit-text-stroke headline (transparent fill + 2px bone): effective contrast fails. Thin outline only allows background bleed between strokes; no solid interior. Not reliably readable per WCAG for text. Fails even large-text criteria in practice. Corrected approach: solid #F4EDE1 fill + optional 1px #FF5A1F stroke or 2-3px text-shadow; never rely on stroke-only for critical headlines.
**(4) Accessibility**
- Marquee: aria-hidden="true" present (radical.html:46). Reduced-motion rule already kills the animation (radical.css:29). [OK] Gaps: hover-only pause (css:108) is useless on touch; content is duplicated for seamlessness but animation still runs for keyboard/screen-reader users who do not use hover. Recommend static fallback or `prefers-reduced-motion` + `aria-hidden` already good; add `role="presentation"` or convert to non-animated row for production.
- focus-visible: global rule exists (radical.css:101) with 3px hot outline. [OK] Risk: hot outline on #FF5A1F backgrounds has insufficient contrast. No legacy :focus fallback. Test on hot CTAs; consider conditional darker/bone outline for hot elements.
- Decorative hero image: container aria-hidden="true", img alt="", masked/grayscale + overlay (radical.html:33, radical.css:79-88). [OK] Correct for pure decoration. Mid-width (760-900px) absolute positioning could cause visual layering surprises if image ever gains meaning.
**(5) Responsive risks (ranked)**
- [CRITICAL] Nav collapse at 760px hides all links except phone CTA with no mobile menu or fallback (radical.css:61, radical.html:20-26). On phones/tablets users lose Work/Pricing/Estimate/Contact access.
- [HIGH] 16vw hero type + 13vw CTA type still produce 6-9rem sizes on 700-900px widths; risk of clipping, tall first fold, and poor line wrapping (radical.css:70, 177).
- [MED] Marquee text 1.4rem only shrinks at 480px; separators and long phrases can overflow or crowd on 320-360px (radical.css:204, 110).
- [MED] Pricing 3-col grid + service grid changes at 760/640px are clean but the orange pop tier loses visual weight when stacked.
- [LOW] Absolute hero art (42vw) + mask can cause text overlap or empty right gutter on 900-1100px before hiding (radical.css:90, 80-84). Body overflow-x:hidden can mask real scroll bugs.
**(6) Real code bugs (severity-tagged, ranked)**
- [ERROR] Stroke-only "up." headline uses non-standard `text-stroke` (radical.css:74). Only `-webkit-text-stroke` is reliable; other engines leave color:transparent text invisible or barely stroked.
- [ERROR] Marquee relies on exact duplicate span blocks for infinite loop (radical.html:48-49). Any content edit, font timing, or resize breaks the seam.
- [HIGH] `.marquee:hover .marquee__track` pause (radical.css:108) has no keyboard, focus, or touch equivalent. Animation cannot be stopped on mobile or by non-mouse users.
- [MED] Service hover applies `padding-left:1rem` (radical.css:131). Causes layout shift on every hover; better to use transform or background change only.
- [MED] Global `* { margin:0 }` + late :focus-visible (radical.css:24, 101) + reduced-motion rules are broad; some transitions on .rx-up and .rx-svc may still leak on older reduced-motion implementations.
- [LOW] rx-ghost and stroke elements use pointer-events:none + user-select:none but remain in tab order or selection edge cases in some engines (radical.css:123, 74).
- [LOW] Year script and IO observer are safe (radical.html:132-140). No console errors obvious from static source. Assets path and missing calculator.html are out-of-scope for this file pair.
[OK] End of review. All analysis derived strictly from the two read files.

View File

@@ -0,0 +1,94 @@
Reading all four files for an independent review of the Verdigris Gate skin and skin system.
Computing WCAG contrast ratios for Verdigris token pairs.
Checking image paths across pages and additional contrast edge cases (small text, hover states).
**Verdict:** Verdigris Gate is cleanly scoped and does not break ledger/midnight. Primary button and accent-text pass AA in both modes at rest. Real issues: small muted text on `surface-2` (including the gate-rail header), light-mode button hover, missing font weights 600/700, and stale skin-switcher copy. Confidence: **high** on tokens/contrast/JS; **medium** on live rendering (no browser pass).
---
### Ranked fix list
**1. [ERROR] `--ink-3` fails AA normal text on `surface-2` (both modes)**
`styles.css:91,107` — Header uses `surface-2` (`styles.css:118-119`); `.brand__since` is `ink-3` at 0.66rem (`styles.css:233-234`). Also hits 0.720.78rem hints/captions on `surface-2`.
| Mode | Pair | Ratio | Need |
|------|------|-------|------|
| Light | `#5C6B65` / `#DFE5E1` | 4.39:1 | 4.5:1 |
| Dark | `#7A8A84` / `#25302C` | 3.77:1 | 4.5:1 |
**Corrected hex:** light `--ink-3: #4A5853` (5.84:1 on `#DFE5E1`, 6.32:1 on paper); dark `--ink-3: #8FA098` (4.97:1 on `#25302C`, 5.78:1 on surface).
---
**2. [ERROR] Font loading vs CSS weights — faux-bold on Verdigris**
`index.html:11` loads `Fraunces:wght@400;500` and `IBM Plex Mono:wght@400;500`, but CSS uses **600700**:
- Fraunces: `h1h4`, `.btn`, `.brand__mark` at 600700 (`styles.css:188-191,203,227,270`)
- IBM Plex Mono: `.tier__price`, `.calc__total .tnum`, `.trust__num` at 600700 (`styles.css:304,360,459`)
Source Sans 3 loads 400;600 but `.nav__phone` uses `font-weight: 500` (`styles.css:240`) → synthesized medium.
**Fix:** load `Fraunces:wght@400;500;600;700`, `IBM Plex Mono:wght@400;500;600;700`, add `500` to Source Sans 3 (or change phone to 600).
---
**3. [WARN] Light primary button hover drops below AA**
`styles.css:211``filter: brightness(1.05)` on `#2F7A6B``#F0F7F5` contrast **4.34:1** (need 4.5:1). Dark hover stays fine (7.05:1).
**At-rest button passes:** light `#F0F7F5` / `#2F7A6B` = 4.69:1; dark `#0D1614` / `#4DA896` = 6.44:1.
**Fix options:** drop hover brighten; darken hover fill to `#2A6F61` (5.45:1); or light `--on-accent: #FFFFFF` (5.10:1 rest, 4.60:1 hover).
---
**4. [WARN] `swapSkinImages` — path fragility + duplicate art**
`app.js:63-69`
- Lookup is exact string on `data-orig-src`; resolved URLs, relative variants, or `?cache` params miss the map and stay on ledger art.
- `story.png``verdigris/hero.png` (`app.js:61`) duplicates hero latch on about (`about.html:66`) — likely unintentional; no dedicated `story` asset.
- `$$("img")` is broad but safe: non-mapped images restore via `orig`; `data-orig-src` caching is correct for the 3-skin cycle.
- Invalid/missing `data-skin``indexOf` = -1 → cycles to `ledger` (`app.js:86-87`) — OK but silent.
---
**5. [WARN] Skin switcher HTML still 2-skin**
`index.html:46`, `calculator.html:33``title="Switch skin: Paper / Midnight"` while JS cycles three skins (`app.js:53-54`). `aria-label` updates at runtime; static `title` does not.
---
**6. [INFO] Double-rule inset frames — mostly fine; rate-card frame weak**
`styles.css:124-127``inset 4px paper + 5px rule` on `.calc__shell`, `.rate-card`, `.contact__form`.
- `.calc__shell` / `.rate-card` have `overflow: hidden` (`styles.css:352,399`) — no scroll bleed.
- `.contact__form` has no overflow rule; inset shadows are paint-only — low risk.
- On `.rate-card`, child tiers fill the grid and likely **cover** most of the inset ring — frame may barely show. Calculator/contact are the visible wins.
---
**7. [INFO] Gate-rail header grain — no overflow concern**
`styles.css:118-122` — Opaque `surface-2` + 3px repeating gradient; `backdrop-filter: none` correctly drops ledger glass. Subtle moiré possible on low-DPI; not a layout issue.
---
**8. [OK] Accent-as-text and muted body copy**
Light: `--accent-ink #1F5F52` 6.31:1 on paper; `--ink-2 #3F4F49` 7.32:1 on paper.
Dark: `--accent-ink #6BC4B0` 8.52:1 on paper; `--ink-2 #A8B5AF` 8.31:1 on paper.
`::selection` accent/on-accent: 4.69:1 light, 6.44:1 dark.
---
**9. [OK] Ledger / Midnight isolation**
Verdigris tokens and treatments are scoped to `html[data-skin="verdigris"]` (`styles.css:81-138`). `ledger` falls through to `:root`; `midnight` overrides stay separate (`styles.css:49-78`). Extra font families in the shared Google Fonts URL add weight for all skins but do not alter their palettes or typography tokens. Image swap only runs for `verdigris`; ledger/midnight always get `orig` src.
---
### Summary table (requested checks)
| Check | Result |
|-------|--------|
| Primary button AA | Pass at rest; light hover fail |
| Accent-as-text | Pass both modes |
| Muted text | `--ink-2` pass; `--ink-3` fail on `surface-2` |
| Font weights | Fail — load 600/700 (and 500 for Source Sans) |
| Image swap | Logic sound; path/exact-match + story duplicate |
| Double-rule / grain | No overflow; rate-card frame may be invisible |
| Other skins | Not broken |

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

View File

@@ -0,0 +1,40 @@
{"rect": [861, 145, 874, 481], "text": "Migrations, licensing, and email that is configured, secured, and\nsupported."},
{"rect": [850, 808, 854, 895], "text": "from $2 /mailbox"},
{"rect": [894, 104, 899, 114], "text": "05"},
{"rect": [895, 145, 904, 283], "text": "Business Phones"},
{"rect": [909, 145, 922, 481], "text": "Cloud phone systems with mobile and desktop apps, porting, and no\nusage surprises."},
{"rect": [898, 819, 903, 895], "text": "from $22 /user"},
{"rect": [943, 104, 947, 114], "text": "06"},
{"rect": [943, 145, 952, 311], "text": "Web & Email Hosting"},
{"rect": [957, 145, 971, 481], "text": "Managed hosting with free SSL, daily backups, and real humans on\nsupport."},
{"rect": [946, 830, 951, 895], "text": "from $15 /mo"},
{"rect": [989, 104, 995, 199], "text": "See all services →"}, "text": "See all services →"},
{"rect": [1050, 131, 1054, 434], "text": "PUBLISHED, NOT \"CALL FOR QUOTE\" / PER ENDPOINT"},
{"rect": [1067, 104, 1088, 581], "text": "Pricing with nothing hidden"},
{"rect": [1098, 104, 1118, 481], "text": "You pay for exactly the computers you have. No rounding you up into a\nbigger package tier."},
{"rect": [1147, 120, 1157, 214], "text": "GPS-Basic"},
{"rect": [1160, 120, 1180, 175], "text": "$19"},
{"rect": [1170, 191, 1175, 280], "text": "/ endpoint / mo"},
{"rect": [1189, 120, 1195, 340], "text": "Essential monitoring for small, simple environments."},
{"rect": [1135, 564, 1140, 626], "text": "MOST CHOSEN"},
{"rect": [1147, 384, 1157, 463], "text": "GPS-Pro"},
{"rect": [1160, 384, 1180, 439], "text": "$26"},
{"rect": [1170, 455, 1175, 544], "text": "/ endpoint / mo"},
{"rect": [1189, 384, 1195, 602], "text": "Comprehensive protection for growing businesses."},
{"rect": [1147, 648, 1157, 781], "text": "GPS-Advanced"},
{"rect": [1160, 648, 1180, 703], "text": "$39"},
{"rect": [1170, 719, 1175, 808], "text": "/ endpoint / mo"},
{"rect": [1189, 648, 1195, 829], "text": "Enterprise-grade security and compliance."},
{"rect": [1235, 104, 1240, 246], "text": "Full pricing breakdown →"},
{"rect": [1235, 261, 1240, 370], "text": "Build an estimate →"},
{"rect": [1309, 104, 1330, 426], "text": "Let's talk, no pitch."},
{"rect": [1340, 104, 1360, 481], "text": "Tell us what is frustrating you, and we'll give you honest\nfeedback. Even if that is \"your current setup is fine, here is one\nthing to fix.\""},
{"rect": [1365, 652, 1370, 757], "text": "Talk to a human →"},
{"rect": [1365, 801, 1370, 880], "text": "520.304.8300"},
{"rect": [1412, 104, 1417, 497], "text": "© 2026 Arizona Computer Guru . Protecting Tucson businesses since 2001"},
{"rect": [1412, 683, 1417, 750], "text": "520.304.8300"},
{"rect": [1412, 757, 1417, 762], "text": "."},
{"rect": [1412, 768, 1417, 895], "text": "info@azcomputerguru.com"},
{"rect": [1433, 104, 1445, 895], "text": "Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote\nis tailored to your environment. The contact form is not wired to a mailbox. Photography is representational."}
]
```

View File

@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Arizona Computer Guru | Concierge IT for Tucson, since 2001</title>
<meta name="description" content="Tucson's concierge managed IT and cybersecurity partner since 2001. Transparent per-endpoint pricing, local people, month-to-month terms. Build an estimate in seconds." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>
(function () { try {
var s = localStorage.getItem("acg-theme");
var m = s || (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");
} catch (e) {} })();
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"LocalBusiness","name":"Arizona Computer Guru","image":"assets/images/hero.png","description":"Concierge managed IT and cybersecurity for Tucson businesses since 2001.","address":{"@type":"PostalAddress","streetAddress":"7437 E. 22nd St","addressLocality":"Tucson","addressRegion":"AZ","postalCode":"85710","addressCountry":"US"},"telephone":"+1-520-304-8300","url":"https://azcomputerguru.com","foundingDate":"2001","areaServed":"Tucson, Arizona","openingHours":"Mo-Fr 09:00-17:00"}
</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span>
<span class="brand__name">Arizona Computer Guru</span><br />
<span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span>
</span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html" aria-current="page">Home</a>
<a class="nav__link" href="services.html">Services</a>
<a class="nav__link" href="pricing.html">Pricing</a>
<a class="nav__link" href="calculator.html">Estimate</a>
<a class="nav__link" href="about.html">About</a>
<a class="nav__link" href="contact.html">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<!-- HERO -->
<section class="hero ledger" aria-labelledby="hero-h">
<div class="wrap">
<div class="hero__copy reveal">
<p class="hero__eyebrow">Tucson &middot; Managed IT &amp; Security &middot; Est. 2001</p>
<h1 id="hero-h">Concierge IT for Tucson,<br /><span class="amp">every number on the table.</span></h1>
<p class="hero__sub">We go further than your last IT company, build a real relationship, and never hide the math. Honest pricing, local people, problems fixed before you feel them.</p>
<div class="hero__cta">
<a class="btn btn--primary" href="calculator.html">Estimate your cost <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost" href="contact.html">Talk to a human</a>
</div>
<p class="hero__note mono">// Month-to-month. No lock-in. No offshore call centers.</p>
</div>
<figure class="hero__frame reveal">
<img src="assets/images/hero.png" width="1248" height="832" alt="A wooden desk at golden hour with an open paper ledger, a laptop, and a coffee cup; the Santa Catalina mountains and a saguaro through the window." />
<figcaption class="hero__caption"><span>Tucson, AZ</span><span>open book, nothing hidden</span></figcaption>
</figure>
</div>
</section>
<!-- TRUST -->
<section class="trust" aria-label="Why businesses stay with us" style="padding-block:0;">
<div class="wrap">
<div class="trust__cell"><div class="trust__num">20<span class="u">01</span></div><div class="trust__label">Serving Tucson businesses since</div></div>
<div class="trust__cell"><div class="trust__num">1&ndash;2<span class="u">hr</span></div><div class="trust__label">Typical onsite emergency response</div></div>
<div class="trust__cell"><div class="trust__num">100<span class="u">%</span></div><div class="trust__label">Local team, never offshore</div></div>
<div class="trust__cell"><div class="trust__num">30<span class="u">day</span></div><div class="trust__label">Cancel anytime, no penalty</div></div>
</div>
</section>
<!-- CONCIERGE TEASER -->
<section class="story" aria-labelledby="story-h">
<div class="wrap">
<div class="story__copy reveal">
<p class="section-tag">Our difference <span>/ concierge</span></p>
<h2 id="story-h">What "concierge" actually means</h2>
<p class="muted">Most IT companies wait for things to break, route you to a call center three time zones away, and lock you into a three-year contract. We built Arizona Computer Guru to be the opposite. We learn your business, pick up the phone, and explain things in plain English. Because we charge the same whether your systems break or not, our only incentive is to keep them running.</p>
<a class="more-link" href="about.html">Read our story <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
<figure class="story__img reveal">
<img src="assets/images/about.png" width="1248" height="832" alt="A friendly handshake over a wooden desk with a laptop and a handwritten notebook, an Arizona map framed on the wall." loading="lazy" />
</figure>
</div>
</section>
<!-- SERVICES TEASER -->
<section class="home-services ledger" aria-labelledby="hsvc-h">
<div class="wrap">
<p class="section-tag">Everything you need <span>/ one local partner</span></p>
<h2 id="hsvc-h">What we do</h2>
<div class="svc-list">
<article class="svc reveal"><div class="svc__no">01</div><div><h3 class="svc__name">Managed IT (GPS)</h3><p class="svc__desc">24/7 monitoring, automated patching, and a help desk that knows your name.</p></div><div class="svc__meta">from&nbsp;$19&nbsp;/endpoint</div></article>
<article class="svc reveal"><div class="svc__no">02</div><div><h3 class="svc__name">Cybersecurity</h3><p class="svc__desc">EDR, email security, dark-web monitoring, and training that catch what antivirus misses.</p></div><div class="svc__meta">in GPS-Pro &amp; up</div></article>
<article class="svc reveal"><div class="svc__no">03</div><div><h3 class="svc__name">Backup &amp; Recovery</h3><p class="svc__desc">Tested backups, offsite copies, and ransomware rollback.</p></div><div class="svc__meta">in GPS-Pro &amp; up</div></article>
<article class="svc reveal"><div class="svc__no">04</div><div><h3 class="svc__name">Microsoft 365 &amp; Email</h3><p class="svc__desc">Migrations, licensing, and email that is configured, secured, and supported.</p></div><div class="svc__meta">from&nbsp;$2&nbsp;/mailbox</div></article>
<article class="svc reveal"><div class="svc__no">05</div><div><h3 class="svc__name">Business Phones</h3><p class="svc__desc">Cloud phone systems with mobile and desktop apps, porting, and no usage surprises.</p></div><div class="svc__meta">from&nbsp;$22&nbsp;/user</div></article>
<article class="svc reveal"><div class="svc__no">06</div><div><h3 class="svc__name">Web &amp; Email Hosting</h3><p class="svc__desc">Managed hosting with free SSL, daily backups, and real humans on support.</p></div><div class="svc__meta">from&nbsp;$15&nbsp;/mo</div></article>
</div>
<a class="more-link" href="services.html">See all services <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
</section>
<!-- PRICING TEASER -->
<section class="home-pricing" aria-labelledby="hp-h">
<div class="wrap">
<p class="section-tag">Published, not "call for quote" <span>/ per endpoint</span></p>
<h2 id="hp-h">Pricing with nothing hidden</h2>
<p class="lead">You pay for exactly the computers you have. No rounding you up into a bigger package tier.</p>
<div class="rate-card" role="list">
<div class="tier" role="listitem"><h3 class="tier__name">GPS-Basic</h3><div class="tier__price">$19 <span class="per">/ endpoint / mo</span></div><p class="tier__blurb" style="border-bottom:0;">Essential monitoring for small, simple environments.</p></div>
<div class="tier tier--pop" role="listitem"><div class="tier__flag">Most chosen</div><h3 class="tier__name">GPS-Pro</h3><div class="tier__price">$26 <span class="per">/ endpoint / mo</span></div><p class="tier__blurb" style="border-bottom:0;">Comprehensive protection for growing businesses.</p></div>
<div class="tier" role="listitem"><h3 class="tier__name">GPS-Advanced</h3><div class="tier__price">$39 <span class="per">/ endpoint / mo</span></div><p class="tier__blurb" style="border-bottom:0;">Enterprise-grade security and compliance.</p></div>
</div>
<div class="inline-actions">
<a class="more-link" href="pricing.html">Full pricing breakdown <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="more-link" href="calculator.html">Build an estimate <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-band" aria-labelledby="cta-h">
<div class="wrap">
<div class="reveal">
<h2 id="cta-h">Let's talk, no pitch.</h2>
<p>Tell us what is frustrating you, and we'll give you honest feedback. Even if that is "your current setup is fine, here is one thing to fix."</p>
</div>
<div class="cta-band__actions reveal">
<a class="btn btn--primary" href="contact.html">Talk to a human <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost" href="tel:+15203048300">520.304.8300</a>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,283 @@
/* ===========================================================================
Arizona Computer Guru, Sonoran Ledger (multipage)
Shared vanilla JS across all pages. Each block guards on its own DOM.
=========================================================================== */
(function () {
"use strict";
var $ = function (s, c) { return (c || document).querySelector(s); };
var $$ = function (s, c) { return Array.prototype.slice.call((c || document).querySelectorAll(s)); };
/* ---- Theme ------------------------------------------------------------ */
var root = document.documentElement;
var toggle = $("#themeToggle");
var icon = $("[data-theme-icon]");
var STORE = "acg-theme";
function applyTheme(mode) {
root.setAttribute("data-theme", mode);
var dark = mode === "dark";
if (toggle) {
toggle.setAttribute("aria-pressed", String(dark));
toggle.setAttribute("aria-label", dark ? "Switch to light theme" : "Switch to dark theme");
}
if (icon) icon.innerHTML = dark ? "&#9790;" : "&#9728;";
}
var saved = null;
try { saved = localStorage.getItem(STORE); } catch (e) {}
var prefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
applyTheme(saved || (prefersDark ? "dark" : "light"));
if (toggle) {
toggle.addEventListener("click", function () {
var next = root.getAttribute("data-theme") === "dark" ? "light" : "dark";
applyTheme(next);
try { localStorage.setItem(STORE, next); } catch (e) {}
});
}
if (window.matchMedia) {
var mq = window.matchMedia("(prefers-color-scheme: dark)");
var onChange = function (e) {
var explicit = null;
try { explicit = localStorage.getItem(STORE); } catch (err) {}
if (!explicit) applyTheme(e.matches ? "dark" : "light");
};
if (mq.addEventListener) mq.addEventListener("change", onChange);
else if (mq.addListener) mq.addListener(onChange);
}
/* ---- Skin (Paper / Midnight / Verdigris) ----------------------------- */
var skinToggle = $("#skinToggle");
var SKIN = "acg-skin";
var SKINS = ["ledger", "midnight", "verdigris", "bold"];
var SKIN_NAME = { ledger: "Paper", midnight: "Midnight", verdigris: "Verdigris", bold: "Bold" };
// Verdigris uses its own cooler documentary photography.
var VERDIGRIS_IMG = {
"assets/images/hero.png": "assets/images/verdigris/hero.png",
"assets/images/about.png": "assets/images/verdigris/about.png",
"assets/images/services.png": "assets/images/verdigris/services.png",
"assets/images/contact.png": "assets/images/verdigris/contact.png",
"assets/images/story.png": "assets/images/verdigris/contact.png"
};
function swapSkinImages(skin) {
$$("img").forEach(function (img) {
var orig = img.getAttribute("data-orig-src");
if (orig === null) { orig = img.getAttribute("src"); img.setAttribute("data-orig-src", orig); }
if (skin === "verdigris" && VERDIGRIS_IMG[orig]) img.setAttribute("src", VERDIGRIS_IMG[orig]);
else img.setAttribute("src", orig);
});
}
function applySkin(skin) {
if (SKINS.indexOf(skin) < 0) skin = "ledger";
root.setAttribute("data-skin", skin);
swapSkinImages(skin);
if (skinToggle) {
var name = SKIN_NAME[skin];
skinToggle.setAttribute("aria-label", "Current skin: " + name + ". Switch.");
skinToggle.setAttribute("title", "Skin: " + name + " (click to switch)");
}
}
var savedSkin = "ledger";
try { savedSkin = localStorage.getItem(SKIN) || "ledger"; } catch (e) {}
applySkin(savedSkin);
if (skinToggle) {
skinToggle.addEventListener("click", function () {
var cur = SKINS.indexOf(root.getAttribute("data-skin"));
var next = SKINS[(cur + 1) % SKINS.length];
applySkin(next);
try { localStorage.setItem(SKIN, next); } catch (e) {}
});
}
/* ---- Dynamic year ----------------------------------------------------- */
var yr = $("#year");
if (yr) yr.textContent = String(new Date().getFullYear());
/* ---- Mobile nav ------------------------------------------------------- */
var header = $(".site-header");
var navToggle = $("#navToggle");
if (navToggle && header) {
var closeNav = function () {
header.classList.remove("nav-open");
navToggle.setAttribute("aria-expanded", "false");
navToggle.setAttribute("aria-label", "Open menu");
};
navToggle.addEventListener("click", function () {
var open = header.classList.toggle("nav-open");
navToggle.setAttribute("aria-expanded", String(open));
navToggle.setAttribute("aria-label", open ? "Close menu" : "Open menu");
});
$$("#navLinks a").forEach(function (a) { a.addEventListener("click", closeNav); });
document.addEventListener("keydown", function (e) { if (e.key === "Escape") closeNav(); });
}
/* ---- Money helper ----------------------------------------------------- */
function money(n) { return "$" + Math.round(n).toLocaleString("en-US"); }
/* ---- Calculator (calculator.html) ------------------------------------ */
var form = $("#calcForm");
if (form) {
var EQUIP = 25, M365_RATE = 14, VOIP_RATE = 28;
function clampInt(v) { if (isNaN(v) || v < 0) return 0; return v > 500 ? 500 : v; }
function intVal(id) { return clampInt(parseInt(($("#" + id) || {}).value, 10)); }
function numSelect(id) { var v = parseFloat(($("#" + id) || {}).value); return isNaN(v) ? 0 : v; }
function lineRow(name, detail, cost) {
return '<div class="lline' + (cost <= 0 ? " is-zero" : "") + '">' +
'<span class="lname">' + name + (detail ? ' <span class="muted">' + detail + "</span>" : "") + "</span>" +
'<span class="lcost">' + money(cost) + "</span></div>";
}
function recalc() {
var endpoints = intVal("endpoints");
var tier = numSelect("gpsTier");
var equip = $("#equip").checked;
var support = numSelect("support");
var m365 = intVal("m365");
var voip = intVal("voip");
var hosting = numSelect("hosting");
var gpsCost = endpoints * tier;
var equipCost = equip ? EQUIP : 0;
var m365Cost = m365 * M365_RATE;
var voipCost = voip * VOIP_RATE;
var tierName = tier === 19 ? "GPS-Basic" : tier === 39 ? "GPS-Advanced" : "GPS-Pro";
var supportName = support === 0 ? "" : support === 200 ? "Essential" :
support === 380 ? "Standard" : support === 540 ? "Premium" : "Priority";
var hostingName = hosting === 0 ? "" : hosting === 15 ? "Starter" :
hosting === 35 ? "Business" : "Commerce";
var lines = "";
lines += lineRow(tierName + " monitoring", endpoints + " &times; " + money(tier), gpsCost);
lines += lineRow("Equipment monitoring", "up to 10 devices", equipCost);
lines += lineRow((supportName || "Support plan") + " support", supportName ? "bundled labor" : "none", support);
lines += lineRow("Microsoft 365", m365 + " &times; " + money(M365_RATE), m365Cost);
lines += lineRow("Business phones", voip + " &times; " + money(VOIP_RATE), voipCost);
lines += lineRow((hostingName || "Web hosting") + " hosting", hostingName ? "managed" : "none", hosting);
var total = gpsCost + equipCost + support + m365Cost + voipCost + hosting;
$("#ledgerLines").innerHTML = lines;
$("#totalMonthly").textContent = money(total);
$("#totalAnnual").textContent = money(total * 12) + " / year";
$("#perEndpoint").innerHTML = endpoints > 0
? money(total / endpoints) + " all-in, per endpoint / mo"
: "add endpoints to see per-seat cost";
}
$$(".stepper").forEach(function (st) {
var input = $("input", st);
$$("button", st).forEach(function (b) {
b.addEventListener("click", function () {
input.value = clampInt(parseInt(input.value, 10) + parseInt(b.getAttribute("data-dir"), 10));
recalc();
});
});
input.addEventListener("change", function () { input.value = clampInt(parseInt(input.value, 10)); });
});
// Carry the built estimate across to the contact page.
var sendBtn = $("#sendEstimate");
if (sendBtn) {
var storeEstimate = function () {
var lines = $$("#ledgerLines .lline")
.filter(function (l) { return !l.classList.contains("is-zero"); })
.map(function (l) {
return "- " + $(".lname", l).textContent.replace(/\s+/g, " ").trim() +
": " + $(".lcost", l).textContent.trim();
});
var summary = "Here is the estimate I built:\n" + lines.join("\n") +
"\n\nMonthly: " + $("#totalMonthly").textContent +
" (" + $("#totalAnnual").textContent + ")\n\nI'd like to talk it through.";
try { sessionStorage.setItem("acg-estimate", summary); } catch (e) {}
};
// 'click' covers keyboard + left-click; 'pointerdown' also catches
// middle-click / cmd-click / open-in-new-tab, which never fire 'click'.
sendBtn.addEventListener("click", storeEstimate);
sendBtn.addEventListener("pointerdown", storeEstimate);
}
form.addEventListener("input", recalc);
form.addEventListener("change", recalc);
form.addEventListener("submit", function (e) { e.preventDefault(); });
recalc();
}
/* ---- FAQ accordion (contact.html) ------------------------------------ */
$$(".faq__q").forEach(function (q, i) {
var panel = q.nextElementSibling;
var inner = panel ? panel.firstElementChild : null;
if (panel) {
var pid = "faq-a-" + (i + 1), qid = "faq-q-" + (i + 1);
panel.id = pid; q.id = qid;
panel.setAttribute("role", "region");
panel.setAttribute("aria-labelledby", qid);
q.setAttribute("aria-controls", pid);
}
q.addEventListener("click", function () {
var open = q.getAttribute("aria-expanded") === "true";
q.setAttribute("aria-expanded", String(!open));
if (panel) panel.style.maxHeight = open ? "0px" : (inner.scrollHeight + 8) + "px";
});
});
window.addEventListener("resize", function () {
$$(".faq__q").forEach(function (q) {
if (q.getAttribute("aria-expanded") === "true") {
var panel = q.nextElementSibling, inner = panel ? panel.firstElementChild : null;
if (panel && inner) panel.style.maxHeight = (inner.scrollHeight + 8) + "px";
}
});
});
/* ---- Contact form (contact.html) ------------------------------------- */
var contact = $("#contactForm");
if (contact) {
// Prefill from a calculator estimate, if one was just built.
var msg = $("#cf-msg");
if (msg) {
try {
var est = sessionStorage.getItem("acg-estimate");
if (est) {
msg.value = est;
sessionStorage.removeItem("acg-estimate");
var fn = $("#formNote");
if (fn) fn.textContent = "Your estimate is attached below. Add your name and we'll take it from there.";
// Bring the form into view and focus it so the handoff is visible.
if (contact.scrollIntoView) contact.scrollIntoView({ behavior: "smooth", block: "start" });
var nameField = $("#cf-name");
if (nameField) nameField.focus({ preventScroll: true });
}
} catch (e) {}
}
contact.addEventListener("submit", function (e) {
e.preventDefault();
var name = $("#cf-name"), contactField = $("#cf-contact"), note = $("#formNote");
if (!name.value.trim() || !contactField.value.trim()) {
note.textContent = "Please add your name and a phone or email so we can reach you.";
note.style.color = "var(--accent-ink)";
(name.value.trim() ? contactField : name).focus();
return;
}
note.textContent = "Thanks, " + name.value.trim().split(" ")[0] +
". In a live build this reaches our Tucson team. (Demo: nothing was sent.)";
note.style.color = "var(--good)";
contact.reset();
});
}
/* ---- Reveal on scroll ------------------------------------------------- */
var reveals = $$(".reveal");
if ("IntersectionObserver" in window && reveals.length) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting) { en.target.classList.add("in"); io.unobserve(en.target); }
});
}, { rootMargin: "0px 0px -8% 0px", threshold: 0.08 });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add("in"); });
}
})();

View File

@@ -0,0 +1,200 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pricing | Arizona Computer Guru</title>
<meta name="description" content="Published, transparent IT pricing: GPS monitoring tiers, support plans, non-expiring block time, hosting, Microsoft 365, and business phones." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>(function(){try{var s=localStorage.getItem("acg-theme");var m=s||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");}catch(e){}})();</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span><span class="brand__name">Arizona Computer Guru</span><br /><span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span></span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html">Home</a>
<a class="nav__link" href="services.html">Services</a>
<a class="nav__link" href="pricing.html" aria-current="page">Pricing</a>
<a class="nav__link" href="calculator.html">Estimate</a>
<a class="nav__link" href="about.html">About</a>
<a class="nav__link" href="contact.html">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<section class="page-head ledger">
<div class="wrap reveal">
<p class="eyebrow">Published, not "call for quote"</p>
<h1>Pricing with nothing hidden</h1>
<p class="lead">We think hiding prices is a red flag, in any IT company, including us. Here is the whole list. You pay for exactly what you have.</p>
</div>
</section>
<!-- GPS tiers -->
<section aria-labelledby="gps-h">
<div class="wrap">
<p class="section-tag">Per endpoint <span>/ monitoring &amp; protection</span></p>
<h2 id="gps-h">GPS monitoring tiers</h2>
<div class="rate-card" role="list" style="margin-top:var(--base);">
<div class="tier" role="listitem">
<h3 class="tier__name">GPS-Basic</h3>
<div class="tier__price">$19 <span class="per">/ endpoint / mo</span></div>
<p class="tier__blurb">Essential monitoring for small, simple environments.</p>
<ul>
<li class="is-base">Remote monitoring &amp; management</li>
<li class="is-base">Automated patch management</li>
<li class="is-base">Business-grade antivirus</li>
<li class="is-base">8&times;5 help desk</li>
<li class="is-base">Monthly health reports</li>
</ul>
</div>
<div class="tier tier--pop" role="listitem">
<div class="tier__flag">Most chosen</div>
<h3 class="tier__name">GPS-Pro</h3>
<div class="tier__price">$26 <span class="per">/ endpoint / mo</span></div>
<p class="tier__blurb">Comprehensive protection for growing businesses.</p>
<ul>
<li class="is-base">Everything in Basic</li>
<li>24&times;7 help desk</li>
<li>Advanced EDR &amp; email security</li>
<li>Dark-web monitoring</li>
<li>Backup &amp; disaster recovery</li>
<li>Security-awareness training</li>
</ul>
</div>
<div class="tier" role="listitem">
<h3 class="tier__name">GPS-Advanced</h3>
<div class="tier__price">$39 <span class="per">/ endpoint / mo</span></div>
<p class="tier__blurb">Enterprise-grade security and compliance.</p>
<ul>
<li class="is-base">Everything in Pro</li>
<li>Compliance management (HIPAA/SOC)</li>
<li>Ransomware rollback</li>
<li>Virtual CIO services</li>
<li>Priority response SLA</li>
<li>Dedicated account manager</li>
</ul>
</div>
</div>
<p class="muted" style="margin-top:1rem;font-size:0.9rem;">Add equipment monitoring (routers, switches, printers, NAS) for <span class="mono">$25/mo</span> up to 10 devices.</p>
</div>
</section>
<!-- Support + block -->
<section class="pricing" aria-labelledby="sup-h">
<div class="wrap">
<p class="section-tag">Labor <span>/ predictable rates</span></p>
<h2 id="sup-h">Support plans &amp; block time</h2>
<div class="table-wrap">
<table class="plan-table">
<caption>Support plans, bundled labor at a lower effective rate</caption>
<thead><tr><th scope="col">Plan</th><th class="num" scope="col">Monthly</th><th class="num" scope="col">Hours</th><th class="num" scope="col">Effective&nbsp;rate</th><th scope="col">Response</th></tr></thead>
<tbody>
<tr><td>Essential</td><td class="num">$200</td><td class="num">2</td><td class="num">$100/hr</td><td>Next business day</td></tr>
<tr class="pop"><td>Standard</td><td class="num">$380</td><td class="num">4</td><td class="num">$95/hr</td><td>8 hours</td></tr>
<tr><td>Premium</td><td class="num">$540</td><td class="num">6</td><td class="num">$90/hr</td><td>4 hours</td></tr>
<tr><td>Priority</td><td class="num">$850</td><td class="num">10</td><td class="num">$85/hr</td><td>2 hours, 24/7</td></tr>
</tbody>
</table>
</div>
<div class="table-wrap">
<table class="plan-table" style="margin-top:var(--base);">
<caption>Block time, pre-paid hours that never expire</caption>
<thead><tr><th scope="col">Block</th><th class="num" scope="col">Price</th><th class="num" scope="col">Effective&nbsp;rate</th><th scope="col">Notes</th></tr></thead>
<tbody>
<tr><td>10 hours</td><td class="num">$1,500</td><td class="num">$150/hr</td><td>Use anytime, no expiry</td></tr>
<tr><td>20 hours</td><td class="num">$2,600</td><td class="num">$130/hr</td><td>Bank &amp; draw down</td></tr>
<tr><td>30 hours</td><td class="num">$3,000</td><td class="num">$100/hr</td><td>Best per-hour value</td></tr>
</tbody>
</table>
</div>
<p class="muted" style="margin-top:1rem;font-size:0.9rem;">Off-plan labor is <span class="mono">$175/hr</span>. Plans and block time bring that down, and there is never a charge to find out what something will cost.</p>
</div>
</section>
<!-- Hosting / 365 / Phones -->
<section aria-labelledby="more-h">
<div class="wrap">
<p class="section-tag">Hosting, email &amp; phones <span>/ the rest of the stack</span></p>
<h2 id="more-h">Everything else, also published</h2>
<div class="price-cols">
<div class="price-block reveal">
<h3>Web hosting</h3>
<div class="table-wrap"><table class="plan-table">
<thead><tr><th scope="col">Tier</th><th class="num" scope="col">Monthly</th><th scope="col">Includes</th></tr></thead>
<tbody>
<tr><td>Starter</td><td class="num">$15</td><td>5&nbsp;GB, 1 site</td></tr>
<tr class="pop"><td>Business</td><td class="num">$35</td><td>25&nbsp;GB, 5 sites</td></tr>
<tr><td>Commerce</td><td class="num">$65</td><td>50&nbsp;GB, unlimited</td></tr>
</tbody>
</table></div>
</div>
<div class="price-block reveal">
<h3>Microsoft 365 &amp; email</h3>
<div class="table-wrap"><table class="plan-table">
<thead><tr><th scope="col">Plan</th><th class="num" scope="col">Per user</th><th scope="col">For</th></tr></thead>
<tbody>
<tr><td>Hosted email</td><td class="num">$2&ndash;$10</td><td>IMAP/POP, by storage</td></tr>
<tr><td>M365 Basic</td><td class="num">$7</td><td>Web apps, Teams</td></tr>
<tr class="pop"><td>M365 Standard</td><td class="num">$14</td><td>Desktop Office</td></tr>
<tr><td>M365 Premium</td><td class="num">$24</td><td>Security &amp; device mgmt</td></tr>
</tbody>
</table></div>
<p class="muted" style="font-size:0.84rem;margin-top:0.6rem;">Email security add-on: <span class="mono">$3</span>/mailbox.</p>
</div>
<div class="price-block reveal">
<h3>Business phones</h3>
<div class="table-wrap"><table class="plan-table">
<thead><tr><th scope="col">Tier</th><th class="num" scope="col">Per user</th><th scope="col">Highlights</th></tr></thead>
<tbody>
<tr><td>Basic</td><td class="num">$22</td><td>Unlimited US, app, e911</td></tr>
<tr class="pop"><td>Standard</td><td class="num">$28</td><td>Ring groups, recording</td></tr>
<tr><td>Pro</td><td class="num">$35</td><td>SMS, analytics, CRM</td></tr>
<tr><td>Call Center</td><td class="num">$55</td><td>Queues, supervisor tools</td></tr>
</tbody>
</table></div>
</div>
</div>
</div>
</section>
<section class="cta-band" aria-labelledby="cta-h">
<div class="wrap">
<div class="reveal">
<h2 id="cta-h">Add it up for your business</h2>
<p>Put in your numbers and watch the total. No email wall, no sales call required.</p>
</div>
<div class="cta-band__actions reveal">
<a class="btn btn--primary" href="calculator.html">Build an estimate <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost" href="contact.html">Ask a question</a>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,143 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Arizona Computer Guru | IT that picks up</title>
<meta name="description" content="Concierge IT for Tucson since 2001. We go further, answer the phone, and fix it before you feel it. Transparent per-endpoint pricing, month-to-month." />
<meta name="color-scheme" content="dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Anton&family=Hanken+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/radical.css" />
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="rx-header">
<div class="wrap">
<a class="rx-brand" href="radical.html">ARIZONA <b>COMPUTER</b> GURU</a>
<nav class="rx-nav" aria-label="Primary">
<a href="#work">Work</a>
<a href="#pricing">Pricing</a>
<a href="#calc">Estimate</a>
<a href="#contact">Contact</a>
<a class="rx-cta-sm" href="tel:+15203048300">520.304.8300</a>
</nav>
</div>
</header>
<main id="main">
<!-- HERO -->
<section class="rx-hero">
<div class="rx-hero__art" aria-hidden="true"><img src="assets/images/hero.png" alt="" /></div>
<div class="wrap">
<p class="rx-hero__eyebrow">Tucson &middot; Managed IT &amp; Security &middot; Est. 2001</p>
<h1>IT that<br /><span class="hot">picks</span> <span class="stroke">up.</span></h1>
<p class="rx-hero__sub">Concierge IT for Tucson. We go further, we answer the phone, and we fix it before you feel it.</p>
<div class="rx-hero__cta">
<a class="rx-btn rx-btn--hot" href="#calc">Estimate your cost <span class="x" aria-hidden="true">&rarr;</span></a>
<a class="rx-btn rx-btn--out" href="#contact">Talk to a human</a>
</div>
</div>
</section>
<!-- MARQUEE -->
<div class="marquee" aria-hidden="true">
<div class="marquee__track">
<span>Since 2001</span><span>Local Tucson team</span><span>Month to month</span><span>No offshore</span><span>Onsite in 1-2 hrs</span><span>Published pricing</span>
<span>Since 2001</span><span>Local Tucson team</span><span>Month to month</span><span>No offshore</span><span>Onsite in 1-2 hrs</span><span>Published pricing</span>
</div>
</div>
<!-- WORK / SERVICES -->
<section class="rx-sec" id="work">
<span class="rx-ghost" aria-hidden="true">01</span>
<div class="wrap">
<p class="rx-kicker">What we run</p>
<h2 class="rx-h2">Everything, <span class="hot">handled.</span></h2>
<div class="rx-svc-list" style="margin-top:2.5rem;">
<article class="rx-svc rx-up"><div class="rx-svc__n">01</div><div><div class="rx-svc__name">Managed IT</div><p class="rx-svc__d">24/7 monitoring, automated patching, and a help desk that already knows your setup.</p></div><div class="rx-svc__meta">from $19/endpoint</div></article>
<article class="rx-svc rx-up"><div class="rx-svc__n">02</div><div><div class="rx-svc__name">Cybersecurity</div><p class="rx-svc__d">EDR, email security, dark-web monitoring, and training that catch what antivirus misses.</p></div><div class="rx-svc__meta">in GPS-Pro &amp; up</div></article>
<article class="rx-svc rx-up"><div class="rx-svc__n">03</div><div><div class="rx-svc__name">Backup &amp; Recovery</div><p class="rx-svc__d">Tested backups, offsite copies, ransomware rollback. A bad day stays a bad day, not a closure.</p></div><div class="rx-svc__meta">in GPS-Pro &amp; up</div></article>
<article class="rx-svc rx-up"><div class="rx-svc__n">04</div><div><div class="rx-svc__name">Microsoft 365</div><p class="rx-svc__d">Migrations, licensing, and email configured, secured, and supported by people you can call.</p></div><div class="rx-svc__meta">from $2/mailbox</div></article>
<article class="rx-svc rx-up"><div class="rx-svc__n">05</div><div><div class="rx-svc__name">Business Phones</div><p class="rx-svc__d">Cloud phone systems, mobile and desktop apps, free porting. No per-minute surprises.</p></div><div class="rx-svc__meta">from $22/user</div></article>
<article class="rx-svc rx-up"><div class="rx-svc__n">06</div><div><div class="rx-svc__name">Web &amp; Hosting</div><p class="rx-svc__d">Managed hosting with free SSL, daily backups, and a real human when something needs a hand.</p></div><div class="rx-svc__meta">from $15/mo</div></article>
</div>
</div>
</section>
<!-- PRICING -->
<section class="rx-sec" id="pricing">
<span class="rx-ghost" aria-hidden="true">$</span>
<div class="wrap">
<p class="rx-kicker">Published, not "call for quote"</p>
<h2 class="rx-h2">Per endpoint.<br />Per month. <span class="hot">No games.</span></h2>
<div class="rx-prices rx-up">
<div class="rx-price">
<div class="rx-price__tier">GPS-Basic</div>
<div class="rx-price__big">$19</div>
<span class="rx-price__u">/ endpoint / month</span>
<ul class="rx-price__list"><li>Monitoring &amp; patching</li><li>Antivirus</li><li>8x5 help desk</li></ul>
</div>
<div class="rx-price rx-price--pop">
<div class="rx-price__tier">GPS-Pro &mdash; most chosen</div>
<div class="rx-price__big">$26</div>
<span class="rx-price__u">/ endpoint / month</span>
<ul class="rx-price__list"><li>Everything in Basic</li><li>EDR + email security</li><li>Dark-web monitoring</li><li>Backup &amp; recovery</li></ul>
</div>
<div class="rx-price">
<div class="rx-price__tier">GPS-Advanced</div>
<div class="rx-price__big">$39</div>
<span class="rx-price__u">/ endpoint / month</span>
<ul class="rx-price__list"><li>Everything in Pro</li><li>Compliance (HIPAA/SOC)</li><li>Ransomware rollback</li><li>Virtual CIO</li></ul>
</div>
</div>
</div>
</section>
<!-- CALCULATOR TEASER -->
<section class="rx-sec rx-calc" id="calc">
<div class="wrap">
<div>
<p class="rx-kicker">No email wall</p>
<div class="rx-calc__big">Do the math <span class="hot">yourself.</span></div>
<p>Move the numbers, watch the total. The same math we would walk you through in person, with nothing hidden behind a "contact sales" button.</p>
</div>
<a class="rx-btn rx-btn--hot" href="calculator.html">Open the estimator <span class="x" aria-hidden="true">&rarr;</span></a>
</div>
</section>
<!-- CTA -->
<section class="rx-sec rx-cta" id="contact">
<div class="wrap">
<div class="rx-cta__big">Talk to a<br />human.</div>
<div class="rx-cta__row">
<a class="rx-btn rx-btn--hot" href="tel:+15203048300">520.304.8300</a>
<a class="rx-btn rx-btn--out" href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a>
</div>
</div>
</section>
</main>
<footer class="rx-footer">
<div class="wrap">
<p>&copy; <span id="yr">2026</span> Arizona Computer Guru &middot; Tucson since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="rx-note">Radical concept build of a proposed azcomputerguru.com. One dark, poster-scale direction; pricing reflects published GPS rates and is illustrative. This is a separate experiment from the Paper / Midnight / Verdigris skin set.</p>
</div>
</footer>
<script>
document.getElementById("yr").textContent = String(new Date().getFullYear());
(function () {
var els = [].slice.call(document.querySelectorAll(".rx-up"));
if (!("IntersectionObserver" in window) || !els.length) { els.forEach(function(e){e.classList.add("in");}); return; }
var io = new IntersectionObserver(function (en) {
en.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
}, { threshold: 0.12, rootMargin: "0px 0px -6% 0px" });
els.forEach(function (e) { io.observe(e); });
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,9 @@
# Serve the ACG multipage showcase locally, then open it.
# Usage: powershell -ExecutionPolicy Bypass -File serve.ps1 [port]
param([int]$Port = 4328)
$ErrorActionPreference = "Stop"
Set-Location -Path $PSScriptRoot
Write-Host "Arizona Computer Guru - showcase (multipage)" -ForegroundColor Yellow
Write-Host "Serving $PSScriptRoot at http://localhost:$Port/ (Ctrl+C to stop)"
Start-Process "http://localhost:$Port/"
if (Get-Command py -ErrorAction SilentlyContinue) { py -m http.server $Port } else { python -m http.server $Port }

View File

@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Services | Arizona Computer Guru</title>
<meta name="description" content="Managed IT, cybersecurity, backup, Microsoft 365, business phones, and hosting for Tucson businesses. One local partner, plainly laid out." />
<meta name="color-scheme" content="light dark" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Lexend:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600;700&family=Fraunces:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&family=Anton&family=Hanken+Grotesk:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
<script>(function(){try{var s=localStorage.getItem("acg-theme");var m=s||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.setAttribute("data-theme",m);document.documentElement.setAttribute("data-skin",(localStorage.getItem("acg-skin")||"ledger"));document.documentElement.classList.add("js");}catch(e){}})();</script>
</head>
<body>
<a href="#main" class="sr-only">Skip to content</a>
<header class="site-header">
<div class="wrap">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true">ACG</span>
<span><span class="brand__name">Arizona Computer Guru</span><br /><span class="brand__since">Concierge IT &middot; Tucson &middot; since 2001</span></span>
</a>
<nav class="nav" aria-label="Primary">
<div class="nav__links" id="navLinks">
<a class="nav__link" href="index.html">Home</a>
<a class="nav__link" href="services.html" aria-current="page">Services</a>
<a class="nav__link" href="pricing.html">Pricing</a>
<a class="nav__link" href="calculator.html">Estimate</a>
<a class="nav__link" href="about.html">About</a>
<a class="nav__link" href="contact.html">Contact</a>
</div>
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="skin-toggle" id="skinToggle" type="button" aria-label="Switch visual skin (Paper, Midnight, Verdigris, or Bold)" title="Switch skin: Paper / Midnight / Verdigris / Bold"><span class="sw" aria-hidden="true"></span></button>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme" title="Toggle light / dark"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
<button class="nav__toggle" id="navToggle" type="button" aria-expanded="false" aria-controls="navLinks" aria-label="Open menu">&#8801;</button>
</nav>
</div>
</header>
<main id="main">
<section class="page-head page-head--img ledger">
<div class="wrap">
<div class="reveal">
<p class="eyebrow">What we do</p>
<h1>Services, laid out plainly</h1>
<p class="lead">One local partner for the whole stack: the computers, the security, the phones, the email, and the people who keep it all running. No bundles you do not need.</p>
</div>
<figure class="reveal">
<img src="assets/images/services.png" width="1248" height="832" alt="A tidy wall-mounted patch panel and small network switch with neatly dressed cables on a wooden shelf in warm light." />
</figure>
</div>
</section>
<section aria-label="All services">
<div class="wrap">
<div class="svc-group">
<h2 class="svc-group__title">Run your systems</h2>
<div class="svc-list">
<article class="svc reveal"><div class="svc__no">01</div><div><h3 class="svc__name">Managed IT (GPS)</h3><p class="svc__desc">Guru Protection Services keeps every endpoint healthy: 24/7 monitoring, automated patching, and a help desk that already knows your setup. You get monthly health reports showing what we fixed before it broke.</p></div><div class="svc__meta">from&nbsp;$19&nbsp;/endpoint</div></article>
<article class="svc reveal"><div class="svc__no">02</div><div><h3 class="svc__name">Backup &amp; Recovery</h3><p class="svc__desc">Tested backups, offsite copies, and ransomware rollback. A bad day becomes an inconvenience instead of a closure, and we prove the restores actually work.</p></div><div class="svc__meta">in GPS-Pro &amp; up</div></article>
<article class="svc reveal"><div class="svc__no">03</div><div><h3 class="svc__name">Projects &amp; Block Time</h3><p class="svc__desc">Migrations, network buildouts, new-office setups, and one-off work, billed against pre-paid hours that never expire. Bank the hours, draw them down when you need them.</p></div><div class="svc__meta">from&nbsp;$100&nbsp;/hr</div></article>
</div>
</div>
<div class="svc-group">
<h2 class="svc-group__title">Protect your business</h2>
<div class="svc-list">
<article class="svc reveal"><div class="svc__no">04</div><div><h3 class="svc__name">Cybersecurity</h3><p class="svc__desc">Advanced EDR, email security, dark-web monitoring, and security-awareness training. Basic antivirus alone is not enough anymore, so we do not pretend it is.</p></div><div class="svc__meta">in GPS-Pro &amp; up</div></article>
<article class="svc reveal"><div class="svc__no">05</div><div><h3 class="svc__name">vCIO &amp; Compliance</h3><p class="svc__desc">Strategy, budgeting, and cyber-insurance readiness. We help you check the boxes auditors and insurers ask for (HIPAA, SOC, MFA, documented backups) and hand you the paperwork.</p></div><div class="svc__meta">in GPS-Advanced</div></article>
</div>
</div>
<div class="svc-group">
<h2 class="svc-group__title">Connect your people</h2>
<div class="svc-list">
<article class="svc reveal"><div class="svc__no">06</div><div><h3 class="svc__name">Microsoft 365 &amp; Email</h3><p class="svc__desc">Migrations, Business Standard or Premium licensing, or budget-friendly hosted email. Configured, secured, and supported by people you can call.</p></div><div class="svc__meta">from&nbsp;$2&nbsp;/mailbox</div></article>
<article class="svc reveal"><div class="svc__no">07</div><div><h3 class="svc__name">Business Phones (GPS-Voice)</h3><p class="svc__desc">Cloud phone systems with mobile and desktop apps, auto-attendants, and free number porting for managed clients. Four tiers, no per-minute surprises.</p></div><div class="svc__meta">from&nbsp;$22&nbsp;/user</div></article>
<article class="svc reveal"><div class="svc__no">08</div><div><h3 class="svc__name">Web &amp; Email Hosting</h3><p class="svc__desc">Managed hosting with free SSL, daily backups, and a real person (not a ticket robot) when something needs a hand.</p></div><div class="svc__meta">from&nbsp;$15&nbsp;/mo</div></article>
</div>
</div>
</div>
</section>
<section class="cta-band" aria-labelledby="cta-h">
<div class="wrap">
<div class="reveal">
<h2 id="cta-h">See what it costs</h2>
<p>Every service above is on our published price list. Build your own estimate, or read the full breakdown.</p>
</div>
<div class="cta-band__actions reveal">
<a class="btn btn--primary" href="calculator.html">Estimate your cost <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost" href="pricing.html">Full pricing</a>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap">
<p>&copy; <span id="year">2026</span> Arizona Computer Guru &middot; Protecting Tucson businesses since 2001</p>
<p><a href="tel:+15203048300">520.304.8300</a> &middot; <a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="disclaimer">Local demonstration build of a proposed azcomputerguru.com (multipage). Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. The contact form is not wired to a mailbox. Photography is representational.</p>
</div>
</footer>
<script src="js/app.js"></script>
</body>
</html>