fix: replace missing hero image with an asset-free lattice

#12
index.html CHANGED
@@ -7,7 +7,7 @@
7
  <meta name="description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
8
  <meta property="og:title" content="a11oy — governance substrate · SZL Holdings"/>
9
  <meta property="og:description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
10
- <meta property="og:image" content="assets/hero_a11oy.png"/>
11
  <meta property="og:type" content="website"/>
12
  <link rel="stylesheet" href="style.css"/>
13
  <link rel="stylesheet" href="brand-tokens.css"/>
@@ -68,8 +68,12 @@
68
  </a>
69
  </div>
70
 
71
- <div class="hero-portrait">
72
- <img src="assets/hero_a11oy.png" alt="a11oy painterly identity portrait" loading="eager"/>
 
 
 
 
73
  </div>
74
  </div>
75
  </section>
 
7
  <meta name="description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
8
  <meta property="og:title" content="a11oy — governance substrate · SZL Holdings"/>
9
  <meta property="og:description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
10
+ <meta name="theme-color" content="#080704"/>
11
  <meta property="og:type" content="website"/>
12
  <link rel="stylesheet" href="style.css"/>
13
  <link rel="stylesheet" href="brand-tokens.css"/>
 
68
  </a>
69
  </div>
70
 
71
+ <div class="hero-sigil" role="img" aria-label="A11oy governed lattice: a signed core inside two verification orbits">
72
+ <span class="sigil-core">A</span>
73
+ <span class="sigil-orbit sigil-orbit-one" aria-hidden="true"></span>
74
+ <span class="sigil-orbit sigil-orbit-two" aria-hidden="true"></span>
75
+ <span class="sigil-node sigil-node-one" aria-hidden="true"></span>
76
+ <span class="sigil-node sigil-node-two" aria-hidden="true"></span>
77
  </div>
78
  </div>
79
  </section>
landing/index.html CHANGED
@@ -7,7 +7,7 @@
7
  <meta name="description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
8
  <meta property="og:title" content="a11oy — governance substrate · SZL Holdings"/>
9
  <meta property="og:description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
10
- <meta property="og:image" content="assets/hero_a11oy.png"/>
11
  <meta property="og:type" content="website"/>
12
  <link rel="stylesheet" href="style.css"/>
13
  <link rel="preconnect" href="https://fonts.googleapis.com"/>
@@ -63,8 +63,12 @@
63
  </a>
64
  </div>
65
 
66
- <div class="hero-portrait">
67
- <img src="assets/hero_a11oy.png" alt="a11oy painterly identity portrait" loading="eager"/>
 
 
 
 
68
  </div>
69
  </div>
70
  </section>
 
7
  <meta name="description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
8
  <meta property="og:title" content="a11oy — governance substrate · SZL Holdings"/>
9
  <meta property="og:description" content="/v1/policy/evaluate · /v1/verify · /v1/ledger — one substrate, hash-chained, deny by default."/>
10
+ <meta name="theme-color" content="#080704"/>
11
  <meta property="og:type" content="website"/>
12
  <link rel="stylesheet" href="style.css"/>
13
  <link rel="preconnect" href="https://fonts.googleapis.com"/>
 
63
  </a>
64
  </div>
65
 
66
+ <div class="hero-sigil" role="img" aria-label="A11oy governed lattice: a signed core inside two verification orbits">
67
+ <span class="sigil-core">A</span>
68
+ <span class="sigil-orbit sigil-orbit-one" aria-hidden="true"></span>
69
+ <span class="sigil-orbit sigil-orbit-two" aria-hidden="true"></span>
70
+ <span class="sigil-node sigil-node-one" aria-hidden="true"></span>
71
+ <span class="sigil-node sigil-node-two" aria-hidden="true"></span>
72
  </div>
73
  </div>
74
  </section>
landing/style.css CHANGED
@@ -219,17 +219,59 @@ a { color: inherit; }
219
  }
220
  .btn-primary:hover { background: var(--gold-bright); }
221
 
222
- .hero-portrait {
 
 
 
223
  margin: 3.5rem auto 0;
224
- max-width: 220px;
225
- }
226
- .hero-portrait img {
227
- width: 100%;
228
- height: auto;
229
- border-radius: 12px;
230
  border: 1px solid var(--gold-line);
231
- display: block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  }
 
 
 
 
233
 
234
  /* ===== FOOTER ===== */
235
  .site-footer {
 
219
  }
220
  .btn-primary:hover { background: var(--gold-bright); }
221
 
222
+ .hero-sigil {
223
+ position: relative;
224
+ width: min(220px, 60vw);
225
+ aspect-ratio: 1;
226
  margin: 3.5rem auto 0;
 
 
 
 
 
 
227
  border: 1px solid var(--gold-line);
228
+ border-radius: 50%;
229
+ overflow: hidden;
230
+ background:
231
+ radial-gradient(circle at center, rgba(215, 185, 107, 0.18), transparent 27%),
232
+ repeating-radial-gradient(circle at center, transparent 0 23px, rgba(215, 185, 107, 0.055) 24px 25px),
233
+ var(--ground);
234
+ box-shadow: inset 0 0 48px rgba(215, 185, 107, 0.08), 0 0 36px rgba(215, 185, 107, 0.07);
235
+ }
236
+ .sigil-core {
237
+ position: absolute;
238
+ inset: 50% auto auto 50%;
239
+ z-index: 2;
240
+ display: grid;
241
+ width: 58px;
242
+ aspect-ratio: 1;
243
+ place-items: center;
244
+ transform: translate(-50%, -50%);
245
+ border: 1px solid var(--gold);
246
+ border-radius: 50%;
247
+ background: rgba(215, 185, 107, 0.08);
248
+ color: var(--gold-bright);
249
+ font: 500 24px/1 var(--mono);
250
+ box-shadow: 0 0 22px rgba(215, 185, 107, 0.25);
251
+ }
252
+ .sigil-orbit {
253
+ position: absolute;
254
+ inset: 50% auto auto 50%;
255
+ border: 1px solid rgba(215, 185, 107, 0.32);
256
+ border-radius: 50%;
257
+ transform: translate(-50%, -50%) rotate(-18deg);
258
+ }
259
+ .sigil-orbit-one { width: 126px; height: 76px; }
260
+ .sigil-orbit-two { width: 78px; height: 154px; transform: translate(-50%, -50%) rotate(32deg); }
261
+ .sigil-node {
262
+ position: absolute;
263
+ z-index: 3;
264
+ width: 7px;
265
+ aspect-ratio: 1;
266
+ border-radius: 50%;
267
+ background: var(--gold-bright);
268
+ box-shadow: 0 0 9px var(--gold);
269
+ animation: sigilPulse 2.8s ease-in-out infinite;
270
  }
271
+ .sigil-node-one { left: 22%; top: 35%; }
272
+ .sigil-node-two { right: 20%; bottom: 30%; animation-delay: -1.4s; }
273
+ @keyframes sigilPulse { 0%, 100% { opacity: 0.35; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1.25); } }
274
+ @media (prefers-reduced-motion: reduce) { .sigil-node, .live-dot, .eyebrow-dot { animation: none; } }
275
 
276
  /* ===== FOOTER ===== */
277
  .site-footer {
style.css CHANGED
@@ -219,17 +219,59 @@ a { color: inherit; }
219
  }
220
  .btn-primary:hover { background: var(--gold-bright); }
221
 
222
- .hero-portrait {
 
 
 
223
  margin: 3.5rem auto 0;
224
- max-width: 220px;
225
- }
226
- .hero-portrait img {
227
- width: 100%;
228
- height: auto;
229
- border-radius: 12px;
230
  border: 1px solid var(--gold-line);
231
- display: block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  }
 
 
 
 
233
 
234
  /* ===== FOOTER ===== */
235
  .site-footer {
 
219
  }
220
  .btn-primary:hover { background: var(--gold-bright); }
221
 
222
+ .hero-sigil {
223
+ position: relative;
224
+ width: min(220px, 60vw);
225
+ aspect-ratio: 1;
226
  margin: 3.5rem auto 0;
 
 
 
 
 
 
227
  border: 1px solid var(--gold-line);
228
+ border-radius: 50%;
229
+ overflow: hidden;
230
+ background:
231
+ radial-gradient(circle at center, rgba(215, 185, 107, 0.18), transparent 27%),
232
+ repeating-radial-gradient(circle at center, transparent 0 23px, rgba(215, 185, 107, 0.055) 24px 25px),
233
+ var(--ground);
234
+ box-shadow: inset 0 0 48px rgba(215, 185, 107, 0.08), 0 0 36px rgba(215, 185, 107, 0.07);
235
+ }
236
+ .sigil-core {
237
+ position: absolute;
238
+ inset: 50% auto auto 50%;
239
+ z-index: 2;
240
+ display: grid;
241
+ width: 58px;
242
+ aspect-ratio: 1;
243
+ place-items: center;
244
+ transform: translate(-50%, -50%);
245
+ border: 1px solid var(--gold);
246
+ border-radius: 50%;
247
+ background: rgba(215, 185, 107, 0.08);
248
+ color: var(--gold-bright);
249
+ font: 500 24px/1 var(--mono);
250
+ box-shadow: 0 0 22px rgba(215, 185, 107, 0.25);
251
+ }
252
+ .sigil-orbit {
253
+ position: absolute;
254
+ inset: 50% auto auto 50%;
255
+ border: 1px solid rgba(215, 185, 107, 0.32);
256
+ border-radius: 50%;
257
+ transform: translate(-50%, -50%) rotate(-18deg);
258
+ }
259
+ .sigil-orbit-one { width: 126px; height: 76px; }
260
+ .sigil-orbit-two { width: 78px; height: 154px; transform: translate(-50%, -50%) rotate(32deg); }
261
+ .sigil-node {
262
+ position: absolute;
263
+ z-index: 3;
264
+ width: 7px;
265
+ aspect-ratio: 1;
266
+ border-radius: 50%;
267
+ background: var(--gold-bright);
268
+ box-shadow: 0 0 9px var(--gold);
269
+ animation: sigilPulse 2.8s ease-in-out infinite;
270
  }
271
+ .sigil-node-one { left: 22%; top: 35%; }
272
+ .sigil-node-two { right: 20%; bottom: 30%; animation-delay: -1.4s; }
273
+ @keyframes sigilPulse { 0%, 100% { opacity: 0.35; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1.25); } }
274
+ @media (prefers-reduced-motion: reduce) { .sigil-node, .live-dot, .eyebrow-dot { animation: none; } }
275
 
276
  /* ===== FOOTER ===== */
277
  .site-footer {
tests/test_landing_asset_contract.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import unittest
3
+
4
+
5
+ ROOT = Path(__file__).resolve().parents[1]
6
+
7
+
8
+ class LandingAssetContractTests(unittest.TestCase):
9
+ def test_both_landing_surfaces_are_asset_independent(self):
10
+ for relative in ("index.html", "landing/index.html"):
11
+ html = (ROOT / relative).read_text(encoding="utf-8")
12
+ with self.subTest(relative=relative):
13
+ self.assertNotIn("assets/hero_a11oy.png", html)
14
+ self.assertIn('class="hero-sigil"', html)
15
+ self.assertIn('role="img"', html)
16
+
17
+ def test_landing_styles_remain_in_sync(self):
18
+ root_css = (ROOT / "style.css").read_text(encoding="utf-8")
19
+ landing_css = (ROOT / "landing/style.css").read_text(encoding="utf-8")
20
+
21
+ self.assertEqual(root_css, landing_css)
22
+ self.assertIn("prefers-reduced-motion", root_css)
23
+
24
+
25
+ if __name__ == "__main__":
26
+ unittest.main()