acg-website: v2 premium redesign (Fable) — now the main ww9 site

The editorial-brutalist reimagining built on Fable, promoted to the ww9 root
(ww9.azcomputerguru.com). Homepage flagship establishing the new design language:
giant Anton hero with an animated city rotator (Tucson -> Phoenix -> Scottsdale ->
Flagstaff -> EVERYWHERE, odometer roll, ~3.3s, reduced-motion safe), dark manifesto
inversion band, "THE INDEX" services ledger, poster-scale "NOTHING HIDDEN" pricing,
Dispatch board, mono-metadata signature motif + faint structural grid. Grok-generated
art-directed imagery (monsoon-Tucson hero, patch-panel field shot) replaces the stock
photos. AGY sign-off: "bespoke, high-end studio delivery."

Geo-broadened beyond Tucson (Mike): all AZ cities in a crawlable service-area strip +
LocalBusiness areaServed JSON-LD, copy widened to Arizona-wide/everywhere while keeping
the local-authority signals (radio show, since-2001, roots). Staging no-cache .htaccess.

Homepage nav rewritten root-relative for the root deploy. Subpages remain v1 (redesign
next). Source: projects/acg-website/v2/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-22 20:49:06 -07:00
parent 2abf660cd1
commit 35eec1efb8
13 changed files with 1271 additions and 0 deletions

View File

@@ -49,6 +49,22 @@ stacked; needs Mike's call on which to keep (his show). Numbers ARE consistent (
520.304.8300 — AGY's number-mismatch read was OCR error). Minor: svc calc-link wraps to its own line on rows
03/04 (text-length) — trivial `display:block` fix if wanted. Grok dead all session (no vision mode + empty text).
**v2 = the redesign, built on Fable (Mike: "use Fable for this"), NOW THE MAIN ww9 SITE (2026-07-22).**
Source `projects/acg-website/v2/` (index.html + css/v2.css + js/v2.js + assets/ incl. Grok-gen `hero-gen.png`
monsoon-Tucson + `field-gen.png` patch-panel). Premium editorial-brutalist: giant Anton hero, dark manifesto
inversion band ("WE CHARGE THE SAME WHETHER YOUR SYSTEMS BREAK OR NOT"), "THE INDEX"/"NOTHING HIDDEN" sections,
poster pricing, mono-metadata signature motif + faint grid. AGY pass-2: "bespoke, high-end studio delivery."
**Animated hero city rotator** (Mike's idea): odometer/mask roll, Tucson->Phoenix->Scottsdale->Flagstaff->EVERYWHERE
(~3.3s, runs once, underline-slab payoff; reduced-motion shows EVERYWHERE static; all 10 AZ cities stay in the
crawlable SERVICE-AREA strip + LocalBusiness `areaServed` JSON-LD for SEO — Mike wants to target beyond Tucson).
**Promoted to ww9 ROOT 2026-07-22**: copied v2 to `/home/azcomputerguru/public_html/ww9/` (index.html overwritten,
css/v2.css+js/v2.js+assets ADDED; v1 css/styles.css+js/app.js KEPT for the still-v1 subpages), rewrote v2's nav
`../page.html`->`page.html` (root-relative), added no-cache `.htaccess` (staging; 1yr max-age default was hiding
updates), backed up v1 home as `index- v1-backup.html`. The `/v2/` subfolder still exists (redundant now).
CAVEAT: only the HOMEPAGE is redesigned — about/pricing/services/contact/calculator are STILL v1 (design mismatch)
until redesigned. Repo v2/ is UNCOMMITTED. **ff.py capture gotcha (bit me twice): persistent ff-profile caches
old js/css — verify with a FRESH `FF_PROFILE` temp dir, not `?cb=` on the page URL (doesn't bust linked assets).**
**AutoSSL fix (2026-07-22):** ww9 had a self-signed cert (browser warnings) because it was in the account's
AutoSSL **exclude list** (`/var/cpanel/ssl/autossl/excludes/azcomputerguru.json`, alongside proxied/external
subdomains). Removed ww9+www.ww9 from excludes, triggered `uapi --user=azcomputerguru SSL start_autossl_check`

View File

@@ -0,0 +1,9 @@
# Staging: force revalidation so design iterations are always visible (no stale css/js).
# Replace with versioned filenames + long cache at go-live.
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|html)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header unset Expires
</FilesMatch>
</IfModule>

View File

@@ -0,0 +1,54 @@
# v2 IMAGE-SPEC: AI art direction shot list
All images render through the CSS treatment system (`.frame--duo`): grayscale source
multiplied over a signal-orange plate (ink + orange duotone), halftone dot screen,
film grain, 3px ink border, hard offset slab shadow. Generate sources as normal
color/grayscale photographs; the CSS does the treatment. High contrast and strong
shadows in the source read best after the multiply pass. No text in any image.
Status legend: [FINAL-CANDIDATE] = a Grok-generated image is already in place and
approved-quality; [PLACEHOLDER] = still using a v1 asset, generate per spec.
## Slot 1: Hero band (assets/hero-gen.png) [FINAL-CANDIDATE]
- Scene: monsoon storm over the Tucson valley at dusk, saguaro silhouettes in
foreground, Santa Catalina mountains, rain columns, city lights below.
- Mood: dramatic, rooted-in-place, weathered confidence.
- Composition: wide landscape, horizon in lower third, tall saguaros left of
center (page crops to 21:8 on desktop, 3:2 mobile; keep key subjects central).
- Aspect: generate 16:9 or wider, at least 1600px wide.
- Prompt used: "High-contrast editorial photograph, dramatic monsoon storm clouds
over the Tucson valley at dusk, saguaro cactus silhouettes in foreground, Santa
Catalina mountains, moody documentary style, strong shadows, no text"
## Slot 2: Manifesto field shot (assets/field-gen.png) [FINAL-CANDIDATE]
- Scene: technician's hands terminating cat6 at a dense patch panel, neat cable
bundles, hard side light. No faces.
- Mood: hands-on, technical, honest labor.
- Composition: hands centered (page crops portrait source to 21:9; regenerate in
landscape 3:2 if a wider field of the rack is wanted).
- Prompt used: "Documentary photograph, close-up of a technician's hands
terminating ethernet cable at a dense server rack patch panel, neat cable
bundles, shallow depth of field, hard side light, gritty editorial style,
no faces, no text"
## Slot 3 (future, services/about pages): bench repair
- Scene: open desktop tower on a workbench, screwdriver in hand, parts trays,
anti-static mat, warm workshop light through a window, Tucson desert visible
outside.
- Mood: craftsmanship, 25 years of reps.
- Aspect: 3:2 landscape, 1600px+.
## Slot 4 (future, contact page): the shop
- Scene: single-story storefront on East 22nd St at golden hour, clean signage
band (blank, no legible text), desert landscaping, long shadows.
- Mood: local, physical, findable.
- Aspect: 3:2 landscape.
## Slot 5 (future, dispatch/report headers): abstract technical
- Scene options: coiled patch cable macro on bone paper; rack LEDs bokeh through
a perforated door; a UPS battery row; tape/loose drives on a desk (backup story).
- Mood: evidence photography, field documentation.
- Aspect: 16:9, cropped to 21:9 in card headers.
## Regeneration command
bash .claude/skills/grok/scripts/ask-grok.sh image "<prompt>" projects/acg-website/v2/assets/<name>.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 104" role="img" aria-label="Arizona Computer Guru">
<g transform="rotate(20 50 54)" fill="none" stroke="#F2922E" stroke-width="11" stroke-linecap="round" stroke-linejoin="round">
<path d="M61.2 26.2 A30 30 0 1 1 38.8 26.2" />
<line x1="50" y1="14" x2="50" y2="50" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

View File

@@ -0,0 +1,730 @@
/* ===========================================================================
ARIZONA COMPUTER GURU - v2 "Signal"
Premium brutalist, refined craft. Anton poster scale, signal orange,
duotone treated imagery, mono metadata motif, hard offset shadows.
=========================================================================== */
/* ---- Tokens ------------------------------------------------------------- */
:root {
/* bone / ink neutrals, tinted toward the brand hue (hex fallback first) */
--paper: #F4EDE1;
--surface: #FBF7F0;
--surface-2: #EAE2D4;
--ink: #16120F;
--ink-2: #46403A;
--ink-3: #5C544B;
--accent: #E24A12; /* fills only */
--accent-ink: #C23A0A; /* orange TEXT on bone, AA 4.62:1 */
--on-accent: #16120F;
--paper: oklch(0.944 0.017 84);
--surface: oklch(0.972 0.011 84);
--surface-2: oklch(0.912 0.022 84);
--ink: oklch(0.175 0.009 55);
--ink-2: oklch(0.37 0.012 55);
--ink-3: oklch(0.445 0.014 55);
--accent: oklch(0.585 0.185 38);
--accent-ink: oklch(0.51 0.175 38);
--rule: color-mix(in srgb, var(--ink) 24%, transparent);
--rule-soft: color-mix(in srgb, var(--ink) 10%, transparent);
--grid-line: color-mix(in srgb, var(--ink) 7%, transparent);
/* dark band (in-page inversion, independent of theme; literal constants
so the band stays charcoal + bone in BOTH themes) */
--band-bg: #1A1410;
--band-bg: oklch(0.205 0.012 55);
--band-ink: #F4EDE1;
--band-ink: oklch(0.944 0.017 84);
--band-muted: #C9BFB2;
--band-muted: oklch(0.80 0.018 84);
--band-accent: #FF5A1F;
--band-accent: oklch(0.66 0.20 38);
--band-accent-ink: #FF8A4D;
--band-accent-ink: oklch(0.735 0.155 45);
--band-rule: color-mix(in srgb, #F4EDE1 18%, transparent);
--shadow-c: var(--ink); /* hard offset shadow color */
--border-w: 3px;
--maxw: 1240px;
--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;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* expo-ish */
--t-fast: 90ms;
--t-med: 180ms;
}
[data-theme="dark"] {
--paper: #0E0B09;
--surface: #171310;
--surface-2: #201A15;
--ink: #F4EDE1;
--ink-2: #C9C1B5;
--ink-3: #9A9082;
--accent: #FF5A1F;
--accent-ink: #FF8A4D;
--on-accent: #16120F;
--paper: oklch(0.155 0.008 55);
--surface: oklch(0.205 0.010 55);
--surface-2: oklch(0.245 0.012 55);
--ink: oklch(0.944 0.017 84);
--ink-2: oklch(0.82 0.016 84);
--ink-3: oklch(0.665 0.016 70);
--accent: oklch(0.66 0.20 38);
--accent-ink: oklch(0.735 0.155 45);
--on-accent: oklch(0.175 0.009 55);
--rule: color-mix(in srgb, var(--ink) 26%, transparent);
--rule-soft: color-mix(in srgb, var(--ink) 10%, transparent);
--grid-line: color-mix(in srgb, var(--ink) 8%, transparent);
/* the inversion band goes deeper than the page so pacing survives dark theme */
--band-bg: #070504;
--band-bg: oklch(0.115 0.006 55);
--shadow-c: #000000;
--shadow-c: oklch(0.08 0.004 55);
}
/* ---- Reset -------------------------------------------------------------- */
*, *::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;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}
body {
background: var(--paper);
color: var(--ink);
font-family: var(--f-body);
font-size: 1rem;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: clip;
}
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); }
.mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
.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;
}
.skip-link {
position: absolute; left: 0.75rem; top: -100px; z-index: 200;
background: var(--ink); color: var(--paper); font-family: var(--f-mono);
padding: 0.6rem 1rem; border: var(--border-w) solid var(--accent);
transition: top 120ms var(--ease-out);
}
.skip-link:focus-visible { top: 0.75rem; color: var(--paper); }
a:focus-visible, button:focus-visible {
outline: 3px solid var(--accent); outline-offset: 3px;
}
.wrap { width: min(100% - 3rem, var(--maxw)); margin-inline: auto; }
/* ---- Header ------------------------------------------------------------- */
.site-header {
position: sticky; top: 0; z-index: 100;
background: var(--paper);
border-bottom: var(--border-w) solid var(--ink);
}
.header-grid {
width: min(100% - 3rem, var(--maxw)); margin-inline: auto;
display: flex; align-items: center; gap: 1.5rem;
min-height: 4.25rem;
}
.brand { display: flex; align-items: center; gap: 0.7rem; text-decoration: none; color: var(--ink); }
.brand__mark { color: var(--accent); line-height: 0; }
.brand__mark svg { width: 32px; height: 33px; }
.brand__text { display: flex; flex-direction: column; line-height: 1.15; }
.brand__name {
font-family: var(--f-display); font-weight: 400; font-size: 1.15rem;
text-transform: uppercase; letter-spacing: 0.02em;
}
.brand__since {
font-family: var(--f-mono); font-size: 0.6rem; letter-spacing: 0.2em;
text-transform: uppercase; color: var(--ink-3);
}
.nav { margin-left: auto; display: flex; gap: 1.4rem; }
.nav__link {
font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.12em;
text-transform: uppercase; text-decoration: none; color: var(--ink-2);
padding-block: 0.35rem; position: relative;
}
.nav__link::after {
content: ""; position: absolute; left: 0; bottom: 0; height: 3px; width: 0;
background: var(--accent); transition: width var(--t-med) var(--ease-out);
}
.nav__link:hover { color: var(--ink); }
.nav__link:hover::after { width: 100%; }
.header-actions { display: flex; align-items: center; gap: 0.9rem; }
.nav__phone {
font-family: var(--f-mono); font-size: 0.88rem; font-weight: 700;
color: var(--ink); text-decoration: none;
border: var(--border-w) solid var(--ink); padding: 0.45rem 0.8rem;
transition: background var(--t-med) var(--ease-out), color var(--t-med) var(--ease-out);
}
.nav__phone:hover { background: var(--ink); color: var(--paper); }
.theme-toggle {
background: transparent; border: var(--border-w) solid var(--ink);
width: 44px; height: 44px; cursor: pointer; color: var(--ink);
display: grid; place-items: center; font-size: 1.05rem;
transition: background var(--t-med), color var(--t-med);
}
.theme-toggle:hover { background: var(--ink); color: var(--paper); }
@media (max-width: 900px) { .nav { display: none; } }
@media (max-width: 560px) {
.brand__since { display: none; }
.nav__phone { box-shadow: none; border-width: 2px; padding: 0.4rem 0.6rem; font-size: 0.8rem; }
}
/* ---- Frame: treated imagery system -------------------------------------- */
/* Any image dropped into .frame--duo reads as art-directed: grayscale source
multiplied over a signal-orange plate (ink+orange duotone), halftone dot
screen, film grain, hard border + offset slab. */
.frame {
position: relative; overflow: clip;
border: var(--border-w) solid var(--ink);
box-shadow: 12px 12px 0 var(--shadow-c);
background: var(--surface);
}
.frame--duo { background: #E24A12; background: oklch(0.585 0.185 38); }
.frame--duo img {
width: 100%; height: 100%; object-fit: cover;
filter: grayscale(1) contrast(1.28) brightness(1.06);
mix-blend-mode: multiply;
}
/* halftone screen */
.frame--duo::before {
content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
background-image: radial-gradient(circle, rgba(12, 8, 5, 0.5) 1px, transparent 1.4px);
background-size: 5px 5px;
mix-blend-mode: overlay;
opacity: 0.55;
}
/* film grain */
.frame--duo::after {
content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)' opacity='0.5'/></svg>");
mix-blend-mode: overlay; opacity: 0.35;
}
.frame__meta {
position: absolute; z-index: 3;
font-size: 0.62rem; letter-spacing: 0.14em;
background: var(--ink); color: var(--paper);
padding: 0.25rem 0.5rem;
}
[data-theme="dark"] .frame__meta { background: oklch(0.115 0.006 55); color: oklch(0.944 0.017 84); }
.frame__meta--tl { top: 0; left: 0; }
.frame__meta--br { bottom: 0; right: 0; }
.frame--band { border-color: var(--band-ink); box-shadow: 12px 12px 0 var(--band-accent); }
/* ---- Buttons ------------------------------------------------------------ */
.btn {
font-family: var(--f-display); font-weight: 400; font-size: 1.08rem;
letter-spacing: 0.03em; text-transform: uppercase;
display: inline-flex; align-items: center; gap: 0.65rem;
padding: 0.85rem 1.6rem; cursor: pointer; text-decoration: none;
border: var(--border-w) solid var(--ink);
box-shadow: 6px 6px 0 var(--shadow-c);
transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out),
background var(--t-med) var(--ease-out), color var(--t-med) var(--ease-out);
}
.btn:hover { transform: translate(-2px, -2px); box-shadow: 8px 8px 0 var(--shadow-c); }
.btn:active { transform: translate(4px, 4px); box-shadow: 1px 1px 0 var(--shadow-c); }
.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--ink); color: var(--paper); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); }
.btn .arrow { font-family: var(--f-mono); }
/* band variants sit on the dark inversion band */
.btn--band { border-color: var(--band-ink); box-shadow: 6px 6px 0 var(--band-accent); background: var(--band-accent); color: #16120F; }
.btn--band:hover { background: var(--band-ink); color: var(--band-bg); box-shadow: 8px 8px 0 var(--band-accent); }
.btn--band-ghost { border-color: var(--band-ink); color: var(--band-ink); box-shadow: 6px 6px 0 var(--band-accent); background: transparent; font-family: var(--f-mono); font-weight: 700; }
.btn--band-ghost:hover { background: var(--band-ink); color: var(--band-bg); box-shadow: 8px 8px 0 var(--band-accent); }
/* ---- Shared section furniture ------------------------------------------- */
.section-head { position: relative; display: flex; align-items: baseline; gap: 1.2rem; margin-bottom: 1.4rem; }
.section-no {
font-family: var(--f-display); font-size: clamp(3.2rem, 7vw, 5.5rem); line-height: 0.8;
color: transparent;
-webkit-text-stroke: 2px var(--band-accent-ink);
}
.section-no--ink { -webkit-text-stroke: 2px var(--accent-ink); }
.kicker {
font-size: 0.72rem; letter-spacing: 0.22em; text-transform: uppercase;
color: var(--accent-ink); display: flex; align-items: center; gap: 0.75rem;
}
.kicker::before { content: ""; width: 30px; border-top: 3px solid var(--accent); }
.band-ink .kicker { color: var(--band-accent-ink); }
.band-ink .kicker::before { border-color: var(--band-accent); }
.lead { font-size: 1.15rem; color: var(--ink-2); max-width: 62ch; margin-bottom: 2rem; }
.accent-word { color: var(--accent-ink); font-style: normal; }
.more-link {
font-family: var(--f-display); font-weight: 400; font-size: 1.05rem;
letter-spacing: 0.02em; text-transform: uppercase;
color: var(--accent-ink); text-decoration: none;
display: inline-flex; gap: 0.5rem; align-items: center;
border-bottom: 3px solid var(--accent); padding-bottom: 2px;
}
.more-link:hover { color: var(--ink); border-color: var(--ink); }
.more-link .arrow { font-family: var(--f-mono); transition: transform 0.15s var(--ease-out); }
.more-link:hover .arrow { transform: translateX(4px); }
.more-link--band { color: var(--band-accent-ink); border-color: var(--band-accent); }
.more-link--band:hover { color: var(--band-ink); border-color: var(--band-ink); }
.inline-actions { display: flex; gap: 2rem; align-items: center; flex-wrap: wrap; }
/* visible structural grid motif */
.grid-bg {
background-image:
repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 120px);
}
/* ---- Hero ---------------------------------------------------------------- */
.hero {
position: relative;
padding: clamp(1.2rem, 3vw, 2.5rem) clamp(1rem, 3vw, 2.5rem) 0;
border-bottom: var(--border-w) solid var(--ink);
background-image:
repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 120px);
}
.hero__rail {
position: absolute; top: 8.5rem; right: 0.4rem;
writing-mode: vertical-rl;
font-family: var(--f-mono); font-size: 0.62rem; letter-spacing: 0.34em;
text-transform: uppercase; color: var(--ink-3);
user-select: none;
}
.hero__meta {
display: flex; flex-wrap: wrap; gap: 0.55rem 2.2rem;
font-size: 0.7rem; letter-spacing: 0.18em; color: var(--ink-3);
border-bottom: 1px solid var(--rule); padding-bottom: 0.8rem;
margin-bottom: clamp(1.2rem, 3vw, 2.4rem);
}
.hero__meta-wide { margin-left: auto; color: var(--accent-ink); }
.hero__title {
font-family: var(--f-display); font-weight: 400;
text-transform: uppercase;
font-size: clamp(3.4rem, 11.6vw, 10.6rem);
line-height: 0.9; letter-spacing: 0.005em;
color: var(--ink);
margin-bottom: clamp(1.6rem, 3.5vw, 2.75rem);
}
.hero__line { display: block; }
.hero__line--hollow {
color: transparent;
-webkit-text-stroke: 4px var(--ink);
font-size: 0.62em; line-height: 0.95;
margin-top: 0.08em;
}
@media (max-width: 700px) { .hero__line--hollow { -webkit-text-stroke-width: 2px; } }
.hero__deck {
display: grid; grid-template-columns: minmax(0, 44ch) auto;
justify-content: space-between; align-items: start;
gap: 1.5rem 4rem;
border-top: 1px solid var(--rule);
padding-top: clamp(1.4rem, 2.5vw, 2rem);
padding-bottom: clamp(2.25rem, 4.5vw, 3.75rem);
}
.hero__sub { font-size: 1.22rem; color: var(--ink-2); max-width: 34ch; }
.hero__cta { display: flex; gap: 1.2rem; flex-wrap: wrap; align-items: flex-start; justify-content: flex-end; }
.hero__note {
grid-column: 1 / -1;
display: flex; flex-wrap: wrap; gap: 0.4rem 2.4rem;
font-size: 0.74rem; letter-spacing: 0.06em; color: var(--ink-3);
}
@media (max-width: 820px) {
.hero__deck { grid-template-columns: 1fr; }
.hero__cta { justify-content: flex-start; }
}
.hero__figure { margin-inline: 0; }
.hero__figure img { aspect-ratio: 21 / 8; object-fit: cover; }
.hero__figure {
margin-bottom: clamp(2rem, 4vw, 3rem);
margin-right: 12px; /* room for the offset slab */
}
@media (max-width: 700px) {
.hero__figure img { aspect-ratio: 3 / 2; }
.hero__rail { display: none; }
}
/* ---- Hero city rotator ---------------------------------------------------- */
/* Words stack in one inline-grid cell: the cell is as wide as the widest word
(EVERYWHERE), so swaps cause zero layout shift. Trailing slack after short
words is invisible because the comma travels inside each word's cell and the
line ends there.
Swap = vertical odometer roll: the stack is a clipped cell (static clip-path
with small outsets so the comma, hollow stroke, and underline slab are never
sheared); words only translate. Outgoing rolls up out of the cell, incoming
rises from below, both on the SAME ease-out-expo so they travel as one rigid
column — no overshoot, no settle wobble. */
.city-stack { display: inline-grid; clip-path: inset(-0.1em -0.15em -0.18em -0.15em); }
.city-word { grid-area: 1 / 1; white-space: nowrap; visibility: hidden; }
/* no JS: skip the cycle, rest on the payoff word */
html:not(.js) .city-word--final { visibility: visible; }
html:not(.js) .city-word--final .city-word__t::after { transform: scaleX(1); }
.js .city-word.is-on,
.js .city-word.is-off { visibility: visible; }
.js .city-word.is-on { animation: city-roll-in 240ms cubic-bezier(0.16, 1, 0.3, 1) both; }
.js .city-word.is-off { animation: city-roll-out 240ms cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes city-roll-in {
from { transform: translateY(1.15em); }
to { transform: none; }
}
@keyframes city-roll-out {
from { transform: none; }
to { transform: translateY(-1.15em); }
}
/* EVERYWHERE lands hollow (brief outline flourish), then rests solid with a
permanent accent underline slab drawing left to right */
.city-word--final { transition: color 240ms var(--ease-out); }
.city-word--final.is-hollow { color: transparent; -webkit-text-stroke: 4px var(--accent); }
@media (max-width: 700px) { .city-word--final.is-hollow { -webkit-text-stroke-width: 2px; } }
.city-word__t { position: relative; display: inline-block; }
.city-word__t::after {
content: ""; position: absolute; left: 0.02em; right: 0.02em; bottom: -0.03em;
height: 0.06em; background: var(--accent);
transform: scaleX(0); transform-origin: left;
}
.city-word--final.is-settled .city-word__t::after {
transform: scaleX(1);
transition: transform 560ms var(--ease-out) 80ms;
}
/* EVERYWHERE is 4 glyphs longer than TUCSON: the city line runs a hair tighter
than line 1 (11vw vs 11.6vw, invisible side by side) so "for everywhere,"
holds one line at laptop widths, and steps down on narrow viewports */
.hero__line--city { font-size: clamp(3.4rem, 11vw, 10.6rem); }
@media (max-width: 540px) { .hero__line--city { font-size: 0.7em; } }
/* ---- Service area strip ---------------------------------------------------- */
.svc-area {
background: var(--surface);
border-bottom: var(--border-w) solid var(--ink);
padding: 0.95rem clamp(1rem, 3vw, 2.5rem) 1.05rem;
display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem 1.7rem;
}
.svc-area__label {
font-size: 0.7rem; font-weight: 700; letter-spacing: 0.22em;
text-transform: uppercase; color: var(--accent-ink);
}
.svc-area__list {
list-style: none; padding: 0;
display: flex; flex-wrap: wrap; gap: 0.3rem 0;
font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--ink-2);
}
.svc-area__list li { white-space: nowrap; }
.svc-area__list li + li::before { content: "/"; margin-inline: 0.6rem; color: var(--ink-3); }
.svc-area__wide { color: var(--accent-ink); font-weight: 700; }
.svc-area__note {
flex-basis: 100%;
font-size: 0.84rem; color: var(--ink-3); max-width: 76ch;
}
/* ---- Radio ticker -------------------------------------------------------- */
.ticker {
background: var(--ink); color: var(--paper);
border-bottom: var(--border-w) solid var(--accent);
overflow: clip; padding-block: 0.85rem;
}
[data-theme="dark"] .ticker { background: oklch(0.115 0.006 55); }
.ticker__track {
display: flex; width: max-content;
animation: ticker-scroll 32s linear infinite;
}
.ticker:hover .ticker__track { animation-play-state: paused; }
.ticker__item {
font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.12em;
text-transform: uppercase; white-space: nowrap; padding-inline: 2.6rem;
color: var(--paper);
}
[data-theme="dark"] .ticker__item { color: oklch(0.944 0.017 84); }
.ticker__item strong { color: #FF8A4D; color: oklch(0.735 0.155 45); font-weight: 700; }
.ticker__item::before { content: "\25CF"; color: var(--accent); margin-right: 1.1rem; }
@keyframes ticker-scroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
.ticker__track { animation: none; }
}
/* ---- Trust stats ---------------------------------------------------------- */
.trust { border-bottom: var(--border-w) solid var(--ink); background: var(--surface); }
.trust__grid {
display: grid; grid-template-columns: repeat(4, 1fr);
}
.trust__cell {
position: relative;
padding: clamp(2rem, 4vw, 3.4rem) clamp(1.1rem, 2.2vw, 2rem) clamp(1.8rem, 3.2vw, 2.9rem);
border-right: var(--border-w) solid var(--ink);
}
.trust__cell:last-child { border-right: 0; }
.trust__num {
font-family: var(--f-display); font-weight: 400;
font-size: clamp(2.6rem, 5.6vw, 4.9rem); line-height: 0.9;
letter-spacing: 0.01em;
}
.trust__num .u { font-size: 0.42em; color: var(--accent-ink); letter-spacing: 0.06em; }
.trust__label { font-size: 0.88rem; color: var(--ink-2); margin-top: 0.7rem; max-width: 18ch; }
.trust__tag {
position: absolute; top: 0.55rem; right: 0.7rem;
font-size: 0.6rem; letter-spacing: 0.16em; color: var(--ink-3);
}
@media (max-width: 760px) {
.trust__grid { grid-template-columns: 1fr 1fr; }
.trust__cell:nth-child(2) { border-right: 0; }
.trust__cell:nth-child(-n+2) { border-bottom: var(--border-w) solid var(--ink); }
}
/* ---- Dark inversion band -------------------------------------------------- */
.band-ink {
background: var(--band-bg);
color: var(--band-ink);
border-bottom: var(--border-w) solid var(--accent);
background-image:
repeating-linear-gradient(90deg, color-mix(in srgb, var(--band-ink) 6%, transparent) 0 1px, transparent 1px 120px);
}
.band-wrap { width: min(100% - 3rem, var(--maxw)); margin-inline: auto; }
/* Manifesto */
.manifesto { padding-block: clamp(5rem, 11vw, 10rem) clamp(2.5rem, 5vw, 4.5rem); }
.manifesto__title {
font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
font-size: clamp(2.5rem, 7.4vw, 6.7rem);
line-height: 0.92; letter-spacing: 0.005em;
color: var(--band-ink);
margin-bottom: clamp(1.75rem, 4vw, 3rem);
max-width: 14em;
}
.manifesto__title span { display: block; }
.manifesto__title .accent-word { color: var(--band-accent-ink); }
.manifesto__body {
display: grid; gap: 1.4rem; max-width: 62ch;
font-size: 1.12rem; color: var(--band-muted);
margin-bottom: clamp(2.5rem, 5vw, 4rem);
justify-items: start;
}
.manifesto__punch {
font-weight: 700; color: var(--band-ink); font-size: 1.22rem;
border-block: 3px solid var(--band-accent);
padding-block: 1rem; max-width: 46ch;
}
.manifesto__figure { max-width: 900px; margin-right: 12px; }
.manifesto__figure img { aspect-ratio: 21 / 9; object-fit: cover; }
/* Services index (inside the band) */
.services { padding-block: clamp(1.5rem, 3vw, 2.5rem) clamp(3.5rem, 7vw, 6rem); }
.services__title {
font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
font-size: clamp(2.6rem, 6vw, 5.2rem); line-height: 0.92;
color: var(--band-ink); margin-bottom: 2rem;
}
.svc-index { border-top: 1px solid var(--band-rule); margin-bottom: 2.25rem; }
.svc {
display: grid; grid-template-columns: 4.5rem 1fr auto;
gap: 1.4rem; align-items: baseline;
padding-block: 1.15rem;
border-bottom: 1px solid var(--band-rule);
transition: background var(--t-med) var(--ease-out), padding-left var(--t-med) var(--ease-out);
}
.svc:hover { background: color-mix(in srgb, var(--band-ink) 5%, transparent); }
.svc__no {
font-family: var(--f-display); font-size: 2rem; line-height: 1;
color: var(--band-accent-ink);
}
.svc__name {
font-family: var(--f-display); font-weight: 400; font-size: clamp(1.35rem, 2.4vw, 1.9rem);
letter-spacing: 0.015em; text-transform: uppercase; color: var(--band-ink);
}
.svc__desc { color: var(--band-muted); font-size: 0.96rem; margin-top: 0.3rem; max-width: 58ch; }
.svc__meta {
font-size: 0.92rem; font-weight: 700; color: var(--band-accent-ink);
text-align: right; white-space: nowrap;
}
.svc__per { color: var(--band-muted); font-weight: 400; font-size: 0.8em; }
@media (max-width: 680px) {
.svc { grid-template-columns: 2.6rem 1fr; }
.svc__no { font-size: 1.4rem; }
.svc__meta { grid-column: 2; text-align: left; }
}
/* ---- Pricing -------------------------------------------------------------- */
.pricing {
padding-block: clamp(4.5rem, 9vw, 8rem) clamp(3.5rem, 7vw, 6.5rem);
border-bottom: var(--border-w) solid var(--ink);
}
.pricing__title {
font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
font-size: clamp(3rem, 8.5vw, 7.6rem); line-height: 0.88;
margin-bottom: 1.5rem;
}
.cta__accent { color: var(--band-accent-ink); }
.tiers {
display: grid; grid-template-columns: repeat(3, 1fr);
gap: clamp(1.5rem, 3vw, 2.5rem);
align-items: stretch;
margin-bottom: clamp(2.5rem, 5vw, 3.5rem);
padding-right: 14px; /* room for offset slabs */
}
.tier {
position: relative;
background: var(--surface);
border: 4px solid var(--ink);
box-shadow: 10px 10px 0 var(--shadow-c);
padding: 2rem 1.6rem 1.8rem;
transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.tier:hover { transform: translate(-3px, -3px); box-shadow: 14px 14px 0 var(--shadow-c); }
.tier--pop {
background: var(--ink); color: var(--paper);
box-shadow: 10px 10px 0 var(--accent);
}
.tier--pop:hover { box-shadow: 14px 14px 0 var(--accent); }
[data-theme="dark"] .tier--pop { background: oklch(0.115 0.006 55); border-color: var(--accent); color: var(--ink); }
.tier__flag {
position: absolute; top: -4px; right: -4px;
font-size: 0.66rem; letter-spacing: 0.18em; text-transform: uppercase;
background: var(--accent); color: var(--on-accent);
padding: 0.4rem 0.7rem;
}
.tier__name {
font-family: var(--f-display); font-weight: 400; font-size: 1.5rem;
letter-spacing: 0.02em; text-transform: uppercase;
}
.tier__price {
font-family: var(--f-display); font-weight: 400;
font-size: clamp(4.4rem, 8vw, 6.8rem); line-height: 0.9;
margin-top: 1rem; letter-spacing: 0.01em;
}
.tier__cur { font-size: 0.45em; vertical-align: 0.75em; color: var(--accent-ink); }
.tier--pop .tier__cur { color: #FF8A4D; color: oklch(0.735 0.155 45); }
.tier__per { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
color: var(--ink-3); margin-top: 0.7rem; }
.tier--pop .tier__per { color: oklch(0.80 0.018 84); }
.tier__blurb { font-size: 0.95rem; color: var(--ink-2); margin-top: 1.1rem; max-width: 30ch; }
.tier--pop .tier__blurb { color: oklch(0.80 0.018 84); }
.tier__tag { position: absolute; bottom: 0.6rem; right: 0.75rem; font-size: 0.6rem;
letter-spacing: 0.16em; color: var(--ink-3); }
.tier--pop .tier__tag { color: oklch(0.665 0.016 70); }
@media (max-width: 860px) {
.tiers { grid-template-columns: 1fr; max-width: 460px; }
}
/* ---- Dispatch board -------------------------------------------------------- */
.dispatch {
padding-block: clamp(3.5rem, 7vw, 6rem);
background: var(--surface);
border-bottom: var(--border-w) solid var(--ink);
}
.dispatch__title {
font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
font-size: clamp(2.4rem, 5.5vw, 4.6rem); line-height: 0.92;
margin-bottom: 1.25rem;
}
.dispatch-grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: clamp(1.4rem, 2.5vw, 2.2rem);
margin-bottom: 2.5rem;
padding-right: 10px;
}
/* flat by design: the slab shadows are reserved for buttons, tiers, and frames
so the page keeps contrast between flatness and sudden depth */
.report {
background: var(--paper);
border: var(--border-w) solid var(--ink);
display: flex; flex-direction: column;
transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.report:hover { transform: translate(-3px, -3px); box-shadow: 6px 6px 0 var(--shadow-c); }
.report__bar {
display: flex; justify-content: space-between; gap: 0.8rem;
font-size: 0.64rem; letter-spacing: 0.16em;
background: var(--ink); color: var(--paper);
padding: 0.65rem 1rem;
}
[data-theme="dark"] .report__bar { background: oklch(0.115 0.006 55); color: var(--ink); }
.report__title {
font-family: var(--f-display); font-weight: 400; font-size: 1.45rem;
line-height: 1.08; letter-spacing: 0.01em;
padding: 1.4rem 1.2rem 0.7rem;
}
.report__excerpt { color: var(--ink-2); font-size: 0.94rem; padding: 0 1.2rem 1.5rem; flex: 1; }
.report__meta {
display: flex; justify-content: space-between; align-items: center;
font-size: 0.7rem; color: var(--ink-3);
border-top: 1px solid var(--rule);
padding: 0.7rem 1.2rem;
}
.report__tag {
background: var(--accent); color: var(--on-accent);
padding: 0.2rem 0.55rem; letter-spacing: 0.06em; text-transform: uppercase;
font-size: 0.64rem;
}
/* ---- CTA band --------------------------------------------------------------- */
.band-ink--cta { border-bottom: 0; }
.cta { padding-block: clamp(4rem, 9vw, 7.5rem); }
.cta .kicker { margin-bottom: 1.6rem; }
.cta__title {
font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
font-size: clamp(3.2rem, 10.5vw, 9.5rem); line-height: 0.88;
color: var(--band-ink);
margin-bottom: 1.8rem;
}
.cta__title span { display: block; }
.cta__sub { color: var(--band-muted); font-size: 1.15rem; max-width: 52ch; margin-bottom: 2.4rem; }
.cta__actions { display: flex; gap: 1.4rem; flex-wrap: wrap; }
/* ---- Footer ------------------------------------------------------------------ */
.site-footer {
background: var(--paper);
border-top: var(--border-w) solid var(--ink);
padding-block: 2.5rem 2rem;
}
.footer-grid {
display: grid; grid-template-columns: repeat(3, auto);
justify-content: space-between; gap: 2rem;
}
.footer-brand {
font-family: var(--f-display); font-weight: 400; font-size: 1.2rem;
text-transform: uppercase; letter-spacing: 0.02em; margin-bottom: 0.5rem;
}
.footer-line { font-size: 0.76rem; color: var(--ink-3); letter-spacing: 0.04em; line-height: 1.9; }
.footer-line a { color: var(--ink-2); }
.footer-line a:hover { color: var(--accent-ink); }
.footer-col--meta { text-align: right; }
.disclaimer {
grid-column: 1 / -1;
font-size: 0.68rem; color: var(--ink-3); letter-spacing: 0.02em;
border-top: 1px dashed var(--rule); padding-top: 1rem; margin-top: 0.5rem;
max-width: 90ch;
}
@media (max-width: 760px) {
.footer-grid { grid-template-columns: 1fr; }
.footer-col--meta { text-align: left; }
}
/* ---- Reveal on scroll (JS-gated; content never stuck hidden without JS) ---- */
.js .reveal {
opacity: 0; transform: translateY(16px);
transition: opacity 0.65s var(--ease-out), transform 0.65s var(--ease-out);
}
.js .reveal.in { opacity: 1; transform: none; }

View File

@@ -0,0 +1,343 @@
<!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, Phoenix &amp; all of Arizona</title>
<meta name="description" content="Concierge managed IT and cybersecurity from Tucson, serving Phoenix, Mesa, Scottsdale, and businesses across Arizona since 2001. Transparent per-endpoint pricing, local people, remote support everywhere." />
<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=Anton&family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/v2.css" />
<link rel="icon" href="assets/acg-mark.svg" type="image/svg+xml" />
<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.classList.add("js");
} catch (e) {} })();
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"LocalBusiness","name":"Arizona Computer Guru","description":"Concierge managed IT and cybersecurity for Arizona businesses since 2001. Headquartered in Tucson, on-site across southern Arizona and the Phoenix metro, remote support everywhere.","address":{"@type":"PostalAddress","streetAddress":"7437 E. 22nd St","addressLocality":"Tucson","addressRegion":"AZ","postalCode":"85710","addressCountry":"US"},"geo":{"@type":"GeoCoordinates","latitude":32.2226,"longitude":-110.9747},"telephone":"+1-520-304-8300","email":"info@azcomputerguru.com","url":"https://azcomputerguru.com","foundingDate":"2001","areaServed":[{"@type":"City","name":"Tucson"},{"@type":"City","name":"Phoenix"},{"@type":"City","name":"Mesa"},{"@type":"City","name":"Scottsdale"},{"@type":"City","name":"Chandler"},{"@type":"City","name":"Tempe"},{"@type":"City","name":"Oro Valley"},{"@type":"City","name":"Marana"},{"@type":"City","name":"Sierra Vista"},{"@type":"City","name":"Flagstaff"},{"@type":"State","name":"Arizona"},{"@type":"Country","name":"United States"}]}
</script>
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>
<header class="site-header">
<div class="header-grid">
<a class="brand" href="index.html" aria-label="Arizona Computer Guru home">
<span class="brand__mark" aria-hidden="true"><svg viewBox="0 0 100 104" fill="none" stroke="currentColor" stroke-width="11" stroke-linecap="round" stroke-linejoin="round"><g transform="rotate(20 50 54)"><path d="M61.2 26.2 A30 30 0 1 1 38.8 26.2"/><line x1="50" y1="14" x2="50" y2="50"/></g></svg></span>
<span class="brand__text">
<span class="brand__name">Arizona Computer Guru</span>
<span class="brand__since">Concierge IT / Tucson / Est. 2001</span>
</span>
</a>
<nav class="nav" aria-label="Primary">
<a class="nav__link" href="#manifesto">Manifesto</a>
<a class="nav__link" href="#services">Index</a>
<a class="nav__link" href="#pricing">Rates</a>
<a class="nav__link" href="#dispatch">Dispatch</a>
</nav>
<div class="header-actions">
<a class="nav__phone" href="tel:+15203048300">520.304.8300</a>
<button class="theme-toggle" id="themeToggle" type="button" aria-pressed="false" aria-label="Switch to dark theme"><span aria-hidden="true" data-theme-icon>&#9728;</span></button>
</div>
</div>
</header>
<main id="main">
<!-- ============ HERO ============ -->
<section class="hero" aria-labelledby="hero-h">
<div class="hero__rail" aria-hidden="true">FIELD-TESTED IN THE SONORAN DESERT SINCE 2001</div>
<p class="hero__meta mono reveal">
<span>TUCSON_HQ / AZ_WIDE</span>
<span>32.2226N&nbsp;110.9747W</span>
<span>EST.2001</span>
<span class="hero__meta-wide">MANAGED IT + SECURITY</span>
</p>
<h1 id="hero-h" class="hero__title">
<span class="sr-only">Concierge IT for Arizona and beyond, every number on the table.</span>
<span class="hero__line reveal" aria-hidden="true">Concierge&nbsp;IT</span>
<span class="hero__line hero__line--city reveal" aria-hidden="true"><span class="accent-word">for&nbsp;<span class="city-stack" id="cityStack"><span class="city-word is-on">Tucson,</span><span class="city-word">Phoenix,</span><span class="city-word">Scottsdale,</span><span class="city-word">Flagstaff,</span><span class="city-word city-word--final"><span class="city-word__t">everywhere</span>,</span></span></span></span>
<span class="hero__line hero__line--hollow reveal" aria-hidden="true">every number<br />on the table.</span>
</h1>
<div class="hero__deck">
<p class="hero__sub reveal">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 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="contact.html">Talk to a human</a>
</div>
<p class="hero__note mono reveal"><span>// month-to-month</span><span>// no lock-in</span><span>// no offshore call centers</span></p>
</div>
<figure class="hero__figure frame frame--duo reveal">
<img src="assets/hero-gen.png" width="1280" height="720" alt="Monsoon light over the Tucson valley, saguaro silhouettes against the Santa Catalina mountains." />
<span class="frame__meta frame__meta--tl mono" aria-hidden="true">FIG.001 / HERO</span>
<span class="frame__meta frame__meta--br mono" aria-hidden="true">32.2226N 110.9747W / DUO-INK+ORG</span>
</figure>
</section>
<!-- ============ SERVICE AREA STRIP ============ -->
<section class="svc-area" aria-labelledby="svcarea-h">
<h2 id="svcarea-h" class="svc-area__label mono">Service area //</h2>
<ul class="svc-area__list mono">
<li>Tucson</li>
<li>Phoenix</li>
<li>Mesa</li>
<li>Scottsdale</li>
<li>Chandler</li>
<li>Tempe</li>
<li>Oro Valley</li>
<li>Marana</li>
<li>Sierra Vista</li>
<li>Flagstaff</li>
<li class="svc-area__wide">All of Arizona</li>
<li class="svc-area__wide">Remote: everywhere</li>
</ul>
<p class="svc-area__note">Headquartered in Tucson since 2001 &mdash; on-site across southern Arizona and the Phoenix metro, remote support anywhere your business runs.</p>
</section>
<!-- ============ RADIO TICKER ============ -->
<aside class="ticker" aria-label="The Computer Guru Show radio information">
<div class="ticker__track" aria-hidden="true">
<span class="ticker__item"><strong>The Computer Guru Show</strong> / Saturdays 9AM / KVOI 1030AM</span>
<span class="ticker__item">Call in live: <strong>520-790-2020</strong></span>
<span class="ticker__item">Tucson's trusted tech talk since 2001</span>
<span class="ticker__item"><strong>The Computer Guru Show</strong> / Saturdays 9AM / KVOI 1030AM</span>
<span class="ticker__item">Call in live: <strong>520-790-2020</strong></span>
<span class="ticker__item">Tucson's trusted tech talk since 2001</span>
</div>
<p class="sr-only">The Computer Guru Show, Saturdays 9AM on KVOI 1030AM. Call in live: 520-790-2020. Tucson's trusted tech talk since 2001.</p>
</aside>
<!-- ============ TRUST STATS ============ -->
<section class="trust" aria-label="Why businesses stay with us">
<div class="trust__grid">
<div class="trust__cell reveal">
<div class="trust__num">2001</div>
<div class="trust__label">Serving Arizona businesses since</div>
<span class="trust__tag mono" aria-hidden="true">REC.01</span>
</div>
<div class="trust__cell reveal">
<div class="trust__num">1&ndash;2<span class="u">HR</span></div>
<div class="trust__label">Typical onsite emergency response</div>
<span class="trust__tag mono" aria-hidden="true">REC.02</span>
</div>
<div class="trust__cell reveal">
<div class="trust__num">100<span class="u">%</span></div>
<div class="trust__label">Local team, never offshore</div>
<span class="trust__tag mono" aria-hidden="true">REC.03</span>
</div>
<div class="trust__cell reveal">
<div class="trust__num">30<span class="u">DAY</span></div>
<div class="trust__label">Cancel anytime, no penalty</div>
<span class="trust__tag mono" aria-hidden="true">REC.04</span>
</div>
</div>
</section>
<!-- ============ DARK BAND: MANIFESTO + SERVICES INDEX ============ -->
<div class="band-ink">
<section class="manifesto" id="manifesto" aria-labelledby="manifesto-h">
<div class="band-wrap">
<div class="section-head">
<span class="section-no" aria-hidden="true">02</span>
<p class="kicker mono">Our difference / what concierge actually means</p>
</div>
<h2 id="manifesto-h" class="manifesto__title">
<span class="reveal">We charge the same</span>
<span class="reveal">whether your systems</span>
<span class="reveal"><em class="accent-word">break or not.</em></span>
</h2>
<div class="manifesto__body">
<p class="reveal">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.</p>
<p class="manifesto__punch reveal">Because we charge the same whether your systems break or not, our only incentive is to keep them running.</p>
<a class="more-link more-link--band reveal" href="about.html">Read our story <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
<figure class="manifesto__figure frame frame--duo frame--band reveal">
<img src="assets/field-gen.png" width="864" height="1152" alt="A technician's hands terminating network cable at a dense patch panel." loading="lazy" />
<span class="frame__meta frame__meta--tl mono" aria-hidden="true">FIG.002 / FIELD</span>
<span class="frame__meta frame__meta--br mono" aria-hidden="true">7437 E 22ND ST / TUCSON</span>
</figure>
</div>
</section>
<section class="services" id="services" aria-labelledby="services-h">
<div class="band-wrap">
<div class="section-head">
<span class="section-no" aria-hidden="true">03</span>
<p class="kicker mono">Everything you need / one local partner</p>
</div>
<h2 id="services-h" class="services__title reveal">The index</h2>
<div class="svc-index">
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">01</div>
<div class="svc__body">
<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 mono">from $19<span class="svc__per">/endpoint</span></div>
</article>
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">02</div>
<div class="svc__body">
<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 mono">in GPS-Pro &amp; up</div>
</article>
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">03</div>
<div class="svc__body">
<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 mono">in GPS-Pro &amp; up</div>
</article>
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">04</div>
<div class="svc__body">
<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 mono">from $2<span class="svc__per">/mailbox</span></div>
</article>
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">05</div>
<div class="svc__body">
<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 mono">from $22<span class="svc__per">/user</span></div>
</article>
<article class="svc reveal">
<div class="svc__no" aria-hidden="true">06</div>
<div class="svc__body">
<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 mono">from $15<span class="svc__per">/mo</span></div>
</article>
</div>
<a class="more-link more-link--band reveal" href="services.html">See all services <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
</section>
</div>
<!-- ============ PRICING ============ -->
<section class="pricing grid-bg" id="pricing" aria-labelledby="pricing-h">
<div class="wrap">
<div class="section-head">
<span class="section-no section-no--ink" aria-hidden="true">04</span>
<p class="kicker mono">Published, not "call for quote" / per endpoint</p>
</div>
<h2 id="pricing-h" class="pricing__title reveal">Nothing<br /><span class="accent-word">hidden.</span></h2>
<p class="lead reveal">You pay for exactly the computers you have. No rounding you up into a bigger package tier.</p>
<div class="tiers" role="list">
<div class="tier reveal" role="listitem">
<h3 class="tier__name">GPS-Basic</h3>
<div class="tier__price"><span class="tier__cur" aria-hidden="true">$</span>19</div>
<div class="tier__per mono">per endpoint / mo</div>
<p class="tier__blurb">Essential monitoring for small, simple environments.</p>
<span class="tier__tag mono" aria-hidden="true">PLAN.A</span>
</div>
<div class="tier tier--pop reveal" role="listitem">
<div class="tier__flag mono">Most chosen</div>
<h3 class="tier__name">GPS-Pro</h3>
<div class="tier__price"><span class="tier__cur" aria-hidden="true">$</span>26</div>
<div class="tier__per mono">per endpoint / mo</div>
<p class="tier__blurb">Comprehensive protection for growing businesses.</p>
<span class="tier__tag mono" aria-hidden="true">PLAN.B</span>
</div>
<div class="tier reveal" role="listitem">
<h3 class="tier__name">GPS-Advanced</h3>
<div class="tier__price"><span class="tier__cur" aria-hidden="true">$</span>39</div>
<div class="tier__per mono">per endpoint / mo</div>
<p class="tier__blurb">Enterprise-grade security and compliance.</p>
<span class="tier__tag mono" aria-hidden="true">PLAN.C</span>
</div>
</div>
<div class="inline-actions reveal">
<a class="btn btn--primary" href="calculator.html">Build your exact price <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="more-link" href="pricing.html">Full pricing breakdown <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
</div>
</section>
<!-- ============ DISPATCH BOARD ============ -->
<section class="dispatch" id="dispatch" aria-labelledby="dispatch-h">
<div class="wrap">
<div class="section-head">
<span class="section-no section-no--ink" aria-hidden="true">05</span>
<p class="kicker mono">Field intelligence / community blog</p>
</div>
<h2 id="dispatch-h" class="dispatch__title reveal">Dispatch board</h2>
<p class="lead reveal">Real fixes, real lessons, real clients. What we learned this week so you do not have to.</p>
<div class="dispatch-grid">
<article class="report reveal">
<div class="report__bar mono"><span>RPT-142</span><span>BACKUP+RECOVERY</span><span>14.2KB</span></div>
<h3 class="report__title">Why Your Backup Is Not Actually a Backup</h3>
<p class="report__excerpt">Three Tucson businesses discovered their backups were corrupted only after ransomware hit. Here is what they missed.</p>
<div class="report__meta mono"><span>2026-06-14</span><span class="report__tag">Backup &amp; Recovery</span></div>
</article>
<article class="report reveal">
<div class="report__bar mono"><span>RPT-141</span><span>EMAIL-SEC</span><span>11.8KB</span></div>
<h3 class="report__title">The $47,000 Phishing Email</h3>
<p class="report__excerpt">How a single wire transfer approval almost bankrupted a local law firm, and the one setting that would have stopped it.</p>
<div class="report__meta mono"><span>2026-06-11</span><span class="report__tag">Email Security</span></div>
</article>
<article class="report reveal">
<div class="report__bar mono"><span>RPT-140</span><span>M365</span><span>12.5KB</span></div>
<h3 class="report__title">Microsoft Copilot Is Leaking Your Data</h3>
<p class="report__excerpt">Default Copilot settings expose internal emails and documents to the entire company. Here is how to lock it down.</p>
<div class="report__meta mono"><span>2026-06-07</span><span class="report__tag">Microsoft 365</span></div>
</article>
</div>
<a class="more-link reveal" href="https://community.azcomputerguru.com" target="_blank" rel="noopener">Read all field reports <span class="arrow" aria-hidden="true">&rarr;</span></a>
</div>
</section>
<!-- ============ CTA BAND (DARK) ============ -->
<div class="band-ink band-ink--cta">
<section class="cta" aria-labelledby="cta-h">
<div class="band-wrap">
<p class="kicker mono reveal">No pressure / no pitch deck / no countdown timer</p>
<h2 id="cta-h" class="cta__title">
<span class="reveal">Let's talk,</span>
<span class="cta__accent reveal">no pitch.</span>
</h2>
<p class="cta__sub reveal">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 class="cta__actions reveal">
<a class="btn btn--primary btn--band" href="contact.html">Talk to a human <span class="arrow" aria-hidden="true">&rarr;</span></a>
<a class="btn btn--ghost btn--band-ghost mono" href="tel:+15203048300">520.304.8300</a>
</div>
</div>
</section>
</div>
</main>
<footer class="site-footer">
<div class="wrap footer-grid">
<div class="footer-col">
<p class="footer-brand">Arizona Computer Guru</p>
<p class="mono footer-line">Tucson-born / Arizona-wide / since 2001</p>
<p class="mono footer-line">7437 E. 22nd St, Tucson, AZ 85710</p>
</div>
<div class="footer-col">
<p class="mono footer-line"><a href="tel:+15203048300">520.304.8300</a></p>
<p class="mono footer-line"><a href="mailto:info@azcomputerguru.com">info@azcomputerguru.com</a></p>
<p class="mono footer-line">The Computer Guru Show / Sat 9AM / KVOI 1030AM</p>
</div>
<div class="footer-col footer-col--meta">
<p class="mono footer-line">&copy; <span id="year">2026</span> ACG / 32.2226N 110.9747W</p>
<p class="mono footer-line">100% local. Never offshore.</p>
</div>
<p class="disclaimer mono">Local demonstration build of a proposed azcomputerguru.com. Pricing reflects published GPS rates and is illustrative for the estimator; a real quote is tailored to your environment. Photography is representational.</p>
</div>
</footer>
<script src="js/v2.js"></script>
</body>
</html>

View File

@@ -0,0 +1,113 @@
/* ===========================================================================
ACG v2 homepage. Theme toggle + robust reveal-on-scroll.
=========================================================================== */
(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);
}
/* ---- Hero city rotator: home, statewide, then EVERYWHERE --------------- */
/* Runs once on load and stops on the final word. Words are real DOM text
(crawlable); JS only toggles visibility classes. Reduced motion or no JS
rests on EVERYWHERE with no cycle. */
var cityStack = $("#cityStack");
if (cityStack) {
var cities = $$(".city-word", cityStack);
var lastCity = cities.length - 1;
var reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
var settleFinal = function () {
cities[lastCity].classList.remove("is-hollow");
cities[lastCity].classList.add("is-settled");
};
if (reduceMotion || cities.length < 2) {
cities.forEach(function (w, i) {
w.classList.toggle("is-on", i === lastCity);
w.classList.remove("is-off", "is-hollow");
});
settleFinal();
} else {
/* dwell per word before the next swap; opens on home, tightens through
the state, breathes before the payoff */
var holds = [950, 650, 600, 700];
var idx = 0;
var step = function () {
var out = cities[idx];
idx += 1;
var inw = cities[idx];
out.classList.remove("is-on");
out.classList.add("is-off");
if (idx === lastCity) inw.classList.add("is-hollow"); /* land hollow */
inw.classList.add("is-on");
window.setTimeout(function () { out.classList.remove("is-off"); }, 260);
if (idx === lastCity) {
window.setTimeout(settleFinal, 550); /* flourish, then rest solid */
} else {
window.setTimeout(step, holds[idx] || 700);
}
};
window.setTimeout(step, holds[0]);
}
}
/* ---- Dynamic year ------------------------------------------------------ */
var yr = $("#year");
if (yr) yr.textContent = String(new Date().getFullYear());
/* ---- Reveal on scroll (robust: fallback reveals everything) ------------ */
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 -6% 0px", threshold: 0.06 });
reveals.forEach(function (el, i) {
el.style.transitionDelay = Math.min((i % 6) * 60, 300) + "ms";
io.observe(el);
});
} else {
reveals.forEach(function (el) { el.classList.add("in"); });
}
})();