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>
@@ -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`
|
||||
|
||||
9
projects/acg-website/v2/.htaccess
Normal 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>
|
||||
54
projects/acg-website/v2/IMAGE-SPEC.md
Normal 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
|
||||
BIN
projects/acg-website/v2/assets/about.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
6
projects/acg-website/v2/assets/acg-mark.svg
Normal 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 |
BIN
projects/acg-website/v2/assets/field-gen.png
Normal file
|
After Width: | Height: | Size: 333 KiB |
BIN
projects/acg-website/v2/assets/hero-gen.png
Normal file
|
After Width: | Height: | Size: 220 KiB |
BIN
projects/acg-website/v2/assets/hero.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
projects/acg-website/v2/assets/services.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
projects/acg-website/v2/assets/story.png
Normal file
|
After Width: | Height: | Size: 207 KiB |
730
projects/acg-website/v2/css/v2.css
Normal 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; }
|
||||
343
projects/acg-website/v2/index.html
Normal 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 & 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>☀</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 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 IT</span>
|
||||
<span class="hero__line hero__line--city reveal" aria-hidden="true"><span class="accent-word">for <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">→</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 — 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–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">→</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 & 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 & Recovery</h3>
|
||||
<p class="svc__desc">Tested backups, offsite copies, and ransomware rollback.</p>
|
||||
</div>
|
||||
<div class="svc__meta mono">in GPS-Pro & 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 & 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 & 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">→</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">→</span></a>
|
||||
<a class="more-link" href="pricing.html">Full pricing breakdown <span class="arrow" aria-hidden="true">→</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 & 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">→</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">→</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">© <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>
|
||||
113
projects/acg-website/v2/js/v2.js
Normal 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 ? "☾" : "☀";
|
||||
}
|
||||
|
||||
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"); });
|
||||
}
|
||||
})();
|
||||