diff --git a/stacks/phasefinal-web/README.md b/stacks/phasefinal-web/README.md index 2265629..15cad63 100644 --- a/stacks/phasefinal-web/README.md +++ b/stacks/phasefinal-web/README.md @@ -1,6 +1,6 @@ # phasefinal-web -The Phase Final, Inc. corporate site — a single static page served by nginx on +The Phase Final, Inc. corporate site — nine static pages served by nginx on **ana-docker**, fronted by Traefik at `www.phasefinal.com`. Built from the design brief at `docs/design/` (boothed 2026-08-29); the markup @@ -57,3 +57,13 @@ The copy is governed by hard legal and voice constraints — client naming rules the never-"military"/"weapons" phrasing rule, no named individuals. **Read the design brief before editing any text.** Edits are made surgically in `conf/site/index.html`; there is no CMS and there will not be one. + +## Structure and design rules (cleanup, 2026-09-28) + +- Every page carries the same site header (wordmark + nav), a real `

`, and the same footer outside `
`. Change the nav in all nine files at once: the labels are Applications, Systems, Hosting, AI, Engagement, Track record, Contact (+ Privacy in the footer). +- **The stylesheet link carries a version** (`/style.css?v=`). CSS is cached for an hour (`nginx.conf`), so markup that changes with the CSS must bump it, or new pages meet old styles at the edge. +- **Anti-slop waivers, operator ruling 2026-09-28:** + - The hero's full-bleed 3px volt rule is a brand device. The Impeccable detector's `side-tab` rule flags it; that is waived. + - Space Grotesk is the brand display face. `overused-font` is waived. + - Everything else must stay clean: 0 other unwaived rows at 1280 and 390, light and dark. + diff --git a/stacks/phasefinal-web/conf/site/contact/index.html b/stacks/phasefinal-web/conf/site/contact/index.html index 9b99862..d534727 100644 --- a/stacks/phasefinal-web/conf/site/contact/index.html +++ b/stacks/phasefinal-web/conf/site/contact/index.html @@ -3,40 +3,45 @@ + Contact — Phase Final, Inc. - + + + + - +
-
- -
-

01Reach us

+
+

Reach us

Email is the front door: inquiry@phasefinal.com. A sentence about the problem and the date it needs to exist by is a complete first message.

    @@ -48,20 +53,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/engagement/index.html b/stacks/phasefinal-web/conf/site/engagement/index.html index 26597ac..940e78e 100644 --- a/stacks/phasefinal-web/conf/site/engagement/index.html +++ b/stacks/phasefinal-web/conf/site/engagement/index.html @@ -3,37 +3,42 @@ + How We Engage — Phase Final, Inc. - + + + + - - -
+

01Engagement models

@@ -64,20 +69,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/index.html b/stacks/phasefinal-web/conf/site/index.html index 73a98a7..fc831e2 100644 --- a/stacks/phasefinal-web/conf/site/index.html +++ b/stacks/phasefinal-web/conf/site/index.html @@ -3,43 +3,49 @@ + Phase Final, Inc. — Systems Engineering Consultancy - - + + + + +
- Phase Final, Inc.
-

A systems engineering consultancy.

+

A systems engineering consultancy.

Phase Final, Inc. has a long track record in hardware, firmware, and software engineering across an unusually wide range of industries: consumer electronics, financial services, health services, government, film and video game production, and industrial automation.

+ Applications Systems engineering - Infrastructure hosting + Hosting AI services Fixed-bid or retainer

- - -
+

01What we do

@@ -109,16 +115,26 @@
-
+

04Contact

inquiry@phasefinal.com

Tell us the spec and the deadline. We'll tell you what it takes to reach the final phase.

-
- Phase Final, Inc. -
-
+ + diff --git a/stacks/phasefinal-web/conf/site/privacy/index.html b/stacks/phasefinal-web/conf/site/privacy/index.html index 84c98a3..7dd1311 100644 --- a/stacks/phasefinal-web/conf/site/privacy/index.html +++ b/stacks/phasefinal-web/conf/site/privacy/index.html @@ -3,40 +3,45 @@ + Privacy — Phase Final, Inc. - + + + + - - -
+
-

01Details

+

Details

  • What this site collects

    Nothing from your browser. Fonts and images are served from this site itself. No advertising or analytics scripts are loaded, so no cross-site profiling occurs on our side.

  • @@ -48,20 +53,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/services/ai/index.html b/stacks/phasefinal-web/conf/site/services/ai/index.html index a46de50..aecb815 100644 --- a/stacks/phasefinal-web/conf/site/services/ai/index.html +++ b/stacks/phasefinal-web/conf/site/services/ai/index.html @@ -3,40 +3,45 @@ + AI Services & Engineering — Phase Final, Inc. - + + + + - - -
+
-

01What we do

+

What we do

A model call is easy. An AI system — with latency budgets, evaluation suites, fallbacks, cost ceilings, and an upgrade story — is engineering. That part is no different from any other discipline the firm practices.

    @@ -61,20 +66,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/services/hosting/index.html b/stacks/phasefinal-web/conf/site/services/hosting/index.html index 2c92324..e6ecf6f 100644 --- a/stacks/phasefinal-web/conf/site/services/hosting/index.html +++ b/stacks/phasefinal-web/conf/site/services/hosting/index.html @@ -3,40 +3,45 @@ + Infrastructure Hosting — Phase Final, Inc. - + + + + - - -
+
-

01What we operate

+

What we operate

The firm runs its own multi-site production infrastructure — colocated servers, virtualization, private networking, backup, and monitoring — and has for years. That is not a brochure claim; it is the same infrastructure that runs the tools this site's owners depend on daily.

    @@ -61,20 +66,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/services/software/index.html b/stacks/phasefinal-web/conf/site/services/software/index.html index 46871a6..6429832 100644 --- a/stacks/phasefinal-web/conf/site/services/software/index.html +++ b/stacks/phasefinal-web/conf/site/services/software/index.html @@ -3,40 +3,45 @@ + Custom Application Development — Phase Final, Inc. - + + + + - - -
+
-

01Scope

+

Scope

An application is never just the app. It is the client binary, the API behind it, the data model, the release train, and the operational story for what happens at 2 a.m. when something breaks. We take the whole problem.

    @@ -65,20 +70,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/services/systems-engineering/index.html b/stacks/phasefinal-web/conf/site/services/systems-engineering/index.html index 6311f64..1a47a96 100644 --- a/stacks/phasefinal-web/conf/site/services/systems-engineering/index.html +++ b/stacks/phasefinal-web/conf/site/services/systems-engineering/index.html @@ -3,40 +3,45 @@ + Systems Engineering — Phase Final, Inc. - + + + + - - -
+
-

01Method

+

Method

Most engineering failures between disciplines happen in the seams: firmware blames the app, the app blames the API, the API blames the infrastructure. Systems engineering is the discipline of refusing those seams — one accountable owner across the stack.

    @@ -61,20 +66,20 @@
-
+
+ + - -
diff --git a/stacks/phasefinal-web/conf/site/style.css b/stacks/phasefinal-web/conf/site/style.css index fbcf54e..1af1209 100644 --- a/stacks/phasefinal-web/conf/site/style.css +++ b/stacks/phasefinal-web/conf/site/style.css @@ -13,16 +13,17 @@ @font-face { font-family: "IBM Plex Mono"; src: url("fonts/IBMPlexMono-SemiBold.woff2") format("woff2"); font-weight: 600; font-display: swap; } :root { + color-scheme: light dark; --ink: #0f1318; --ink-2: #181d22; --text: #0f1318; --text-secondary: #4d5763; - --text-tertiary: #6b7682; + --text-tertiary: #626d78; /* 4.96:1 on paper (was #6b7682, 4.3:1) */ --paper: #f6f8f9; --border: #c2cad2; --border-subtle: #dde2e7; --accent: #90c73e; - --accent-text: #588021; /* AA on light */ + --accent-text: #527a1e; /* 4.74:1 on paper (was #588021, 4.36:1) */ --volt-200: #d0e8a0; --volt-300: #b8db72; --volt-400: #a3d052; @@ -65,6 +66,52 @@ body { ::selection { background: var(--volt-200); color: #0f1318; } a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; } +:focus-visible { outline: 2px solid var(--volt-500); outline-offset: 3px; } + +/* ---- Skip link: first stop for the keyboard, off-screen until focused ---- */ +.skip { + position: absolute; left: 16px; top: 12px; z-index: 10; + transform: translateY(-200%); + padding: 8px 12px; border-radius: 6px; + background: var(--paper); color: var(--text); + font-family: var(--mono); font-size: 12.5px; +} +.skip:focus-visible { transform: none; } + +/* ---- Site header: the brand and the whole site's nav, one row, every page ---- */ +.site-header { background: var(--ink); color: #f6f8f9; } +.site-header-inner { + max-width: 920px; + margin: 0 auto; + padding: 18px 28px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px 32px; + flex-wrap: wrap; +} +.brand { display: block; line-height: 0; } +.brand img { height: 28px; width: auto; display: block; } +.site-nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: wrap; + gap: 4px 22px; +} +.site-nav a { + display: inline-block; + padding: 6px 0; + font-family: var(--mono); + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; + text-decoration: none; + color: var(--slate-300); +} +.site-nav a:hover { color: var(--volt-300); } +.site-nav a[aria-current="page"] { color: #ffffff; box-shadow: inset 0 -2px 0 var(--volt-500); } p { margin: 0; text-wrap: pretty; } /* ---- Hero: ink console surface with engineering grid ---- */ @@ -72,28 +119,37 @@ p { margin: 0; text-wrap: pretty; } background: var(--ink); color: #f6f8f9; position: relative; + isolation: isolate; overflow: hidden; + border-bottom: 3px solid var(--volt-500); +} +/* The engineering grid is its own layer, so the text's background is the ink it + actually sits on (a detector reading the gradient as the background saw 1.1:1). */ +#hero::before, .contact-card::before { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + pointer-events: none; background-image: linear-gradient(rgba(246,248,249,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(246,248,249,0.05) 1px, transparent 1px); background-size: 48px 48px; - border-bottom: 3px solid var(--volt-500); } .hero-inner { max-width: 920px; margin: 0 auto; - padding: clamp(56px, 9vw, 104px) 28px clamp(56px, 8vw, 96px); + padding: clamp(40px, 7vw, 80px) 28px clamp(52px, 8vw, 88px); display: flex; flex-direction: column; gap: clamp(40px, 6vw, 64px); } -.wordmark { height: clamp(48px, 7.5vw, 72px); width: auto; display: block; align-self: flex-start; } - .hero-copy { max-width: 800px; } .lede { + margin: 0; font-family: var(--display); font-size: clamp(32px, 5.6vw, 54px); line-height: 1.1; @@ -128,6 +184,11 @@ p { margin: 0; text-wrap: pretty; } .spec-bar span { padding: 0 18px; border-left: 1px solid var(--slate-700); } .spec-bar span:first-child { padding-left: 0; border-left: none; } .spec-bar .spec-accent { color: var(--volt-300); } +@media (max-width: 600px) { + /* stacked, a divider would only ever start a line: drop it */ + .spec-bar { flex-direction: column; gap: 6px; } + .spec-bar span { padding: 0; border-left: none; } +} /* ---- Body ---- */ main { @@ -143,7 +204,7 @@ section { flex-wrap: wrap; gap: 32px; } -#services { border-top: none; padding-top: clamp(52px, 7vw, 76px); } +main > section:first-of-type { border-top: none; padding-top: 72px; } h2 { margin: 0; @@ -191,9 +252,7 @@ h2 .num { color: var(--accent-text); margin-right: 12px; } .record + .record { border-top: 1px solid var(--border-subtle); } .record dt { font-family: var(--mono); - font-size: 12.5px; - letter-spacing: 0.05em; - text-transform: uppercase; + font-size: 13px; color: var(--text-tertiary); margin-bottom: 6px; } @@ -201,22 +260,20 @@ h2 .num { color: var(--accent-text); margin-right: 12px; } .record dd { margin: 0; font-size: 17.5px; } .record strong { font-family: var(--display); font-weight: 600; } -/* Contact — ink console panel */ -#contact { +/* Contact — ink console panel (the home page's closing card) */ +.contact-card { display: block; + position: relative; + isolation: isolate; + overflow: hidden; border-top: none; background: var(--ink-2); - background-image: - linear-gradient(rgba(246,248,249,0.05) 1px, transparent 1px), - linear-gradient(90deg, rgba(246,248,249,0.05) 1px, transparent 1px); - background-size: 48px 48px; - border-left: 3px solid var(--volt-500); border-radius: 16px; - padding: clamp(40px, 6vw, 72px); + padding: 64px; color: #f6f8f9; } -#contact h2 { color: var(--slate-400); margin-bottom: 20px; } -#contact h2 .num { color: var(--volt-400); } +.contact-card h2 { color: var(--slate-400); margin-bottom: 20px; } +.contact-card h2 .num { color: var(--volt-400); } .contact-address { font-size: clamp(23px, 4vw, 38px); line-height: 1.25; @@ -237,67 +294,49 @@ h2 .num { color: var(--accent-text); margin-right: 12px; } font-size: 16px; } -/* Footer */ -footer { +/* Footer — the same on every page */ +.site-footer { + max-width: 864px; + width: calc(100% - 56px); + margin: 0 auto; + padding: 28px 0 48px; + border-top: 1px solid var(--border-subtle); display: flex; justify-content: space-between; align-items: baseline; - gap: 16px; + gap: 12px 24px; flex-wrap: wrap; - padding-top: 28px; font-family: var(--mono); font-size: 12.5px; color: var(--text-tertiary); } +.site-footer nav { display: flex; flex-wrap: wrap; gap: 4px 18px; } +.site-footer nav a { color: var(--text-tertiary); text-decoration: none; } +.site-footer nav a:hover { color: var(--accent-text); text-decoration: underline; } +.site-footer nav a[aria-current="page"] { color: var(--text); } @media (max-width: 480px) { main { padding: 0 20px 56px; } - .hero-inner { padding-left: 20px; padding-right: 20px; } + .hero-inner, .site-header-inner { padding-left: 20px; padding-right: 20px; } + .site-footer { width: calc(100% - 40px); } section { padding: 40px 0 48px; } + main > section:first-of-type { padding-top: 48px; } + .contact-card { padding: 36px 28px; } + .site-nav ul { gap: 2px 18px; } } /* ---- Multi-page additions (2026-09-28) ---- */ -/* Top nav: monospace strip under the hero rule, matching the spec-bar voice */ -.site-nav { - background: var(--ink-2); - border-bottom: 1px solid var(--border); -} -.site-nav ul { - max-width: 920px; - margin: 0 auto; - padding: 0 28px; - list-style: none; - display: flex; - flex-wrap: wrap; - gap: 4px 0; -} -.site-nav a { - display: block; - padding: 12px 16px; - font-family: var(--mono); - font-size: 12px; - letter-spacing: 0.09em; - text-transform: uppercase; - text-decoration: none; - color: var(--slate-400); -} -.site-nav a:hover { color: var(--volt-300); } -.site-nav a[aria-current="page"] { - color: #f6f8f9; - box-shadow: inset 0 -2px 0 var(--volt-500); -} - /* Sub-pages get a compact page header instead of the full hero */ .page-header { background: var(--ink); border-bottom: 3px solid var(--volt-500); color: #f6f8f9; } -.page-header .hero-inner { gap: 20px; padding-bottom: clamp(36px, 5vw, 56px); padding-top: clamp(36px, 5vw, 56px); } +.page-header .hero-inner { gap: 20px; padding-bottom: clamp(36px, 5vw, 56px); padding-top: clamp(28px, 4vw, 44px); } .page-header .lede { font-size: clamp(26px, 4.4vw, 40px); } .page-header .sublede { margin-top: 14px; } -.page-header .wordmark { height: clamp(30px, 4.5vw, 40px); } +.page-header .lede { line-height: 1.18; } /* Service detail pages */ .detail-lede { font-size: 18.5px; max-width: 62ch; } @@ -330,9 +369,4 @@ footer { text-transform: uppercase; color: var(--text-tertiary); } -.related a { margin-right: 18px; } - -/* Footer grows a nav echo */ -footer nav { display: flex; flex-wrap: wrap; gap: 4px 18px; } -footer nav a { color: var(--text-tertiary); text-decoration: none; } -footer nav a:hover { color: var(--accent-text); } +.related a { margin-right: 18px; display: inline-block; white-space: nowrap; } diff --git a/stacks/phasefinal-web/conf/site/track-record/index.html b/stacks/phasefinal-web/conf/site/track-record/index.html index d988bc9..8ed36a6 100644 --- a/stacks/phasefinal-web/conf/site/track-record/index.html +++ b/stacks/phasefinal-web/conf/site/track-record/index.html @@ -3,40 +3,45 @@ + Track Record — Phase Final, Inc. - + + + + - - -
+
-

01The record

+

The record

@@ -72,20 +77,20 @@
-
+
+ + - -