Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/VISUAL_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,11 @@ Structural tests support release review, while visual quality remains a separate
- Independent-policy disclosure remains adjacent to the policy reference
- No ordinary executable JavaScript, remote runtime dependencies, or protected company information
- Responsive single-column mobile transformation and direct-preview behavior

## Protected Partner journey

- **Partner** is the global public pathway for aligned organizations and remains present exactly once in every primary navigation.
- The homepage **Strategic Partners** orbital node and Convergence card both route to Partner.
- Partner and Golden Age cross-link contextually while Golden Age remains outside primary navigation.
- Partner is marked as the current page only on `/partner/`.
- Sticky-anchor destinations remain fully visible below the navigation at desktop and mobile widths.
3 changes: 2 additions & 1 deletion partner/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
section[id]{scroll-margin-top:110px}
body{
margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--text);
background:radial-gradient(circle at 14% 7%,rgba(120,215,255,.15),transparent 28rem),radial-gradient(circle at 86% 13%,rgba(198,167,255,.14),transparent 30rem),radial-gradient(circle at 50% 52%,rgba(241,200,107,.08),transparent 36rem),linear-gradient(180deg,var(--bg),#071425 48%,#04070f);overflow-x:hidden
Expand Down Expand Up @@ -104,7 +105,7 @@
.footer a{color:#fff;display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:6px 4px}
.footer p{line-height:1.7;margin:8px 0}
@media(max-width:920px){.grid-4{grid-template-columns:repeat(2,1fr)}.pathway{grid-template-columns:repeat(3,1fr)}.pathway>div:first-child{grid-column:1/-1;min-height:auto;border-bottom:1px solid var(--line)}.pathway>div:nth-child(2){border-left:0}}
@media(max-width:700px){.nav-inner{padding:12px 16px;flex-direction:column;justify-content:center}.brand{font-size:11.5px;gap:9px}.mark{width:34px;height:34px}.nav-links{width:100%;justify-content:center;gap:6px}.nav-links a{font-size:12px;padding:8px 9px}.shell{padding:0 16px}.hero{padding:54px 0 44px}.actions{display:grid}.btn{width:100%}.pathway,.grid-3,.grid-4,.platform{grid-template-columns:1fr}.pathway>div:first-child{grid-column:auto}.pathway>div+div,.pathway>div:nth-child(2),.platform article+article{border-left:0;border-top:1px solid var(--line)}section{padding:56px 0}.card,.platform article{min-height:auto}.inquiry-box{padding:28px 20px}}
@media(max-width:700px){section[id]{scroll-margin-top:150px}.nav-inner{padding:12px 16px;flex-direction:column;justify-content:center}.brand{font-size:11.5px;gap:9px}.mark{width:34px;height:34px}.nav-links{width:100%;justify-content:center;gap:6px}.nav-links a{font-size:12px;padding:8px 9px}.shell{padding:0 16px}.hero{padding:54px 0 44px}.actions{display:grid}.btn{width:100%}.pathway,.grid-3,.grid-4,.platform{grid-template-columns:1fr}.pathway>div:first-child{grid-column:auto}.pathway>div+div,.pathway>div:nth-child(2),.platform article+article{border-left:0;border-top:1px solid var(--line)}section{padding:56px 0}.card,.platform article{min-height:auto}.inquiry-box{padding:28px 20px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.btn{transition:none}.btn:hover{transform:none}}
</style>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"Partner with Bridge Node 7","url":"https://bridgenode7.com/partner/","isPartOf":{"@type":"WebSite","name":"Bridge Node 7","url":"https://bridgenode7.com/"},"description":"Bridge Node 7 connects advanced materials, resilient supply, and system readiness to transform frontier discovery into dependable commercial and mission capability."}</script>
Expand Down
59 changes: 59 additions & 0 deletions scripts/validate_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@
"404.html": "privacy/index.html#security",
}

EXPECTED_PARTNER_NAV = {
"index.html": "partner/index.html",
"materials/index.html": "../partner/index.html",
"readiness/index.html": "../partner/index.html",
"partner/index.html": "../partner/index.html",
"golden-age/index.html": "../partner/index.html",
"privacy/index.html": "../partner/index.html",
"404.html": "partner/index.html",
}
HOME_PARTNER_NODE = '<a aria-label="Explore Bridge Node 7 Partner" class="node n7" href="partner/index.html">'
HOME_PARTNER_CARD = '<a aria-label="Explore Bridge Node 7 Partner" class="card" href="partner/index.html">'
PARTNER_GOLDEN_AGE_LINK = '<a class="btn secondary" href="../golden-age/index.html">Explore A New Golden Age</a>'
GOLDEN_AGE_PARTNER_LINK = '<a class="btn" href="../partner/index.html">Partner with Bridge Node 7</a>'

class PageParser(HTMLParser):
def __init__(self) -> None:
super().__init__(convert_charrefs=True)
Expand Down Expand Up @@ -208,6 +222,22 @@ def handle_endtag(self, tag: str) -> None:
self._script_text = []



def primary_nav_links(text: str) -> list[tuple[str, str, bool]] | None:
match = re.search(r'<nav\b[^>]*aria-label="Primary navigation"[^>]*>(.*?)</nav>', text, re.I | re.S)
if not match:
return None
links: list[tuple[str, str, bool]] = []
for attrs, body in re.findall(r'<a\b([^>]*)>(.*?)</a>', match.group(1), re.I | re.S):
href_match = re.search(r'\bhref=(["\'])(.*?)\1', attrs, re.I | re.S)
href = href_match.group(2) if href_match else ""
current = bool(re.search(r'\baria-current=(["\'])page\1', attrs, re.I | re.S))
label = re.sub(r'<[^>]+>', '', body)
label = re.sub(r'\s+', ' ', label).strip()
links.append((label, href, current))
return links


def fail(errors: list[str], msg: str) -> None:
errors.append(msg)

Expand Down Expand Up @@ -331,6 +361,22 @@ def main() -> int:

if '<header aria-label="Primary navigation"' in text:
fail(errors, f"{label}: banner and navigation must not share the same accessible name")

expected_partner_href = EXPECTED_PARTNER_NAV[label]
nav_links = primary_nav_links(text)
if nav_links is None:
fail(errors, f"{label}: missing primary navigation")
else:
partner_links = [link for link in nav_links if link[0] == "Partner"]
if len(partner_links) != 1:
fail(errors, f"{label}: primary navigation must contain exactly one Partner link, found {len(partner_links)}")
else:
_, partner_href, partner_current = partner_links[0]
if partner_href != expected_partner_href:
fail(errors, f"{label}: Partner navigation must target {expected_partner_href}")
should_be_current = label == "partner/index.html"
if partner_current != should_be_current:
fail(errors, f"{label}: Partner aria-current state is incorrect")
if "transition:.22s ease" in text:
fail(errors, f"{label}: broad transition may delay keyboard focus visibility")

Expand All @@ -345,6 +391,17 @@ def main() -> int:
fail(errors, f"index.html: expected 22 radial path lines, found {radial_path_count}")
if domain_node_count != 7:
fail(errors, f"index.html: expected 7 domain nodes, found {domain_node_count}")

if home.count(HOME_PARTNER_NODE) != 1:
fail(errors, f"index.html: expected exactly one Strategic Partners orbital link to Partner, found {home.count(HOME_PARTNER_NODE)}")
if home.count(HOME_PARTNER_CARD) != 1:
fail(errors, f"index.html: expected exactly one Strategic Partners card link to Partner, found {home.count(HOME_PARTNER_CARD)}")
partner_text = (ROOT / "partner/index.html").read_text(encoding="utf-8")
if partner_text.count(PARTNER_GOLDEN_AGE_LINK) != 1:
fail(errors, "partner/index.html: exact Golden Age pathway missing")
golden_age_text = (ROOT / "golden-age/index.html").read_text(encoding="utf-8")
if golden_age_text.count(GOLDEN_AGE_PARTNER_LINK) != 1:
fail(errors, "golden-age/index.html: exact Partner pathway missing")
if MAIL_SUBJECT not in home:
fail(errors, "index.html: full strategic inquiry interaction missing")
if "<h2>Strategic Inquiry</h2>" in home:
Expand Down Expand Up @@ -372,6 +429,8 @@ def main() -> int:
print(f"Required files: {len(REQUIRED)}")
print("Direct-preview paths: PASS")
print("Protected homepage interactions: PASS")
print("Protected Partner navigation: PASS")
print("Protected Partner and Golden Age journey: PASS")
print("Protected content-page experience: PASS")
print("Remote runtime dependencies: NONE")
print("Public material-specific routes: NONE")
Expand Down