implicant 0.7.1__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {implicant-0.7.1 → implicant-0.7.2}/PKG-INFO +1 -1
- {implicant-0.7.1 → implicant-0.7.2}/pyproject.toml +1 -1
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/copy.py +56 -15
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/app.css +56 -23
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/app.js +31 -7
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/index.html +7 -0
- {implicant-0.7.1 → implicant-0.7.2}/.dockerignore +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/.github/workflows/publish-pypi.yml +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/.github/workflows/release.yml +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/.gitignore +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/LICENSE +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/README.md +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/docker/Dockerfile +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/__init__.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/binarize.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/cli/__init__.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/cli/main.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/client.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/config.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/README.txt +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L6-3631b8781e3a/public_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L6-3631b8781e3a/secret_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L7-a394f2ee7032/public_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L7-a394f2ee7032/secret_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L8-5f657f27f77c/public_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/demo_keys/bgv-n16384-L8-5f657f27f77c/secret_key.bin +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/envelope.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/keys.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/manifest.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/models.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/postprocess.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/samples/bankfraud.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/samples/cancer.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/samples/credit.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/samples/diabetes.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/samples/heartdisease.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/transport/__init__.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/transport/base.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/transport/errors.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/transport/http.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/transport/mock.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/README.md +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/__init__.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/ceremony_meta.json +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/events.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/server.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/service.py +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/frieza_fire.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/frieza_idle.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/frieza_point.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/goku_charge.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/goku_fire.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fanart/goku_stance.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/FONTS.md +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2 +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/ibm-plex-mono/IBMPlexMono-Medium.woff2 +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2 +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/ibm-plex-mono/OFL.txt +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/inter/Inter-Bold.woff2 +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/fonts/inter/OFL.txt +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/logo.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/models/bankfraud.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/models/cancer.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/models/credit.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/models/diabetes.png +0 -0
- {implicant-0.7.1 → implicant-0.7.2}/src/implicant/ui/static/models/heartdisease.png +0 -0
|
@@ -35,7 +35,9 @@ __all__ = [
|
|
|
35
35
|
"INTRO_TITLE",
|
|
36
36
|
"INTRO_PARAS",
|
|
37
37
|
"INTRO_FLOW",
|
|
38
|
-
"
|
|
38
|
+
"INTRO_OUTRO",
|
|
39
|
+
"INTRO_CONTACT_LEAD",
|
|
40
|
+
"INTRO_PANELS",
|
|
39
41
|
"MODEL_NAMES",
|
|
40
42
|
"FHE_FIG_CLIENT",
|
|
41
43
|
"FHE_FIG_SERVER",
|
|
@@ -176,24 +178,63 @@ DISCLOSURE = (
|
|
|
176
178
|
"set aside."
|
|
177
179
|
)
|
|
178
180
|
|
|
179
|
-
# The Technology-page intro. Owner's copy VERBATIM (2026-09-04
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
# it
|
|
181
|
+
# The Technology-page intro. Owner's copy VERBATIM (2026-09-04 rewrite,
|
|
182
|
+
# second pass): three paragraphs, then the pipeline line, then the
|
|
183
|
+
# "At Implicant" paragraph (INTRO_OUTRO) — all in the hero's left column.
|
|
184
|
+
# Below the hero, the four INTRO_PANELS, then a centered line where
|
|
185
|
+
# INTRO_CONTACT_LEAD is plain text and ONLY the Contact us button beside
|
|
186
|
+
# it is clickable — the page reuses the header CTA's label
|
|
187
|
+
# (NAV_TABS["contact"]) and target (NAV_LINKS["contact"]) so the two
|
|
188
|
+
# buttons can never drift apart. The demo-honesty caveat lives in
|
|
189
|
+
# DISCLOSURE, permanently visible on the Models page.
|
|
185
190
|
INTRO_TITLE = "Run AI on Sensitive Data. Keep It Encrypted."
|
|
186
191
|
INTRO_PARAS = (
|
|
187
|
-
"
|
|
188
|
-
"encrypted
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
192
|
+
"Encryption is the internet's everyday lock. Bank sessions, messages, "
|
|
193
|
+
"files, and backups are encrypted into ciphertext — data that carries "
|
|
194
|
+
"no meaning without the matching key.",
|
|
195
|
+
"But traditional encryption has a fundamental limitation: to do "
|
|
196
|
+
"anything useful with encrypted data, it normally has to be decrypted "
|
|
197
|
+
"first. This means that even if your data is protected in transit and "
|
|
198
|
+
"at rest, it becomes exposed while it is being processed.",
|
|
199
|
+
"Fully Homomorphic Encryption (FHE) changes this. It allows "
|
|
200
|
+
"computations — including AI inference — to be performed directly on "
|
|
201
|
+
"encrypted data, without ever converting it back to plaintext.",
|
|
194
202
|
)
|
|
195
203
|
INTRO_FLOW = "Encrypt locally → Compute while encrypted → Decrypt the result locally"
|
|
196
|
-
|
|
204
|
+
INTRO_OUTRO = (
|
|
205
|
+
"At Implicant, we use FHE to build AI models that can operate on your "
|
|
206
|
+
"data while it remains encrypted throughout the entire computation. "
|
|
207
|
+
"Your data is encrypted before it is sent to the server, and neither "
|
|
208
|
+
"Implicant nor the server ever receives, sees, or decrypts it."
|
|
209
|
+
)
|
|
210
|
+
INTRO_CONTACT_LEAD = (
|
|
211
|
+
"If you want to train, deploy, or use AI models while keeping your "
|
|
212
|
+
"data private,"
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# The four capability panels under the hero (owner's request 2026-09-04,
|
|
216
|
+
# zama.org card-row reference): title + one short sentence each. The
|
|
217
|
+
# accuracy figure is MEASURED, not marketing: artifacts/*/benchmark.md
|
|
218
|
+
# (same held-out folds) has the rule models above XGBoost's AUC on
|
|
219
|
+
# bankfraud (0.8829 vs 0.8490, 71 vs 10,983 rules -> ~150x), diabetes,
|
|
220
|
+
# credit and heartdisease, and statistically level on cancer (served
|
|
221
|
+
# bundle 0.9884 vs 0.9924 on n=114 — hence "matches or beats", owner-
|
|
222
|
+
# approved wording 2026-09-04). Cross-checked against the served bundles
|
|
223
|
+
# in splits/ACCURACY.md.
|
|
224
|
+
INTRO_PANELS: tuple[tuple[str, str], ...] = (
|
|
225
|
+
("Sparse truth-table rules",
|
|
226
|
+
"AI distilled into a few dozen sparse truth-table rules — compact, "
|
|
227
|
+
"auditable logic instead of millions of opaque weights."),
|
|
228
|
+
("Accuracy that holds up",
|
|
229
|
+
"Matches or beats XGBoost across all five demo benchmarks — e.g. "
|
|
230
|
+
"0.88 vs 0.85 AUC on fraud screening, with about 150× fewer rules."),
|
|
231
|
+
("FHE on BGV",
|
|
232
|
+
"Inference runs under fully homomorphic encryption (BGV): the server "
|
|
233
|
+
"computes on ciphertext and returns ciphertext, end to end."),
|
|
234
|
+
("Quantum safe",
|
|
235
|
+
"The encryption is lattice-based (Ring-LWE) — the same mathematics "
|
|
236
|
+
"behind post-quantum standards, with no known quantum attack."),
|
|
237
|
+
)
|
|
197
238
|
|
|
198
239
|
# The decorative FHE explainer figure beside the intro (act 1). Educational
|
|
199
240
|
# only: NOT a status surface, never bound to live pipeline events (HON-6.3
|
|
@@ -213,12 +213,15 @@ input.invalid { border-color: var(--err); }
|
|
|
213
213
|
/* Two animations: the cascade's rise AND the frame pulse — this selector
|
|
214
214
|
outranks bare .fhe-fig, so the pulse MUST ride here or it never runs
|
|
215
215
|
(root cause of the invisible bounce, live review). fig-pulse is listed
|
|
216
|
-
last so it owns `transform`; rise keeps opacity+blur.
|
|
217
|
-
#act1
|
|
216
|
+
last so it owns `transform`; rise keeps opacity+blur. Scoped #tech, not
|
|
217
|
+
#act1: the figure moved to the Technology page with the 2026-09-01 tab
|
|
218
|
+
split and the stale #act1 scope had silently dropped the entrance rise
|
|
219
|
+
(the base .fhe-fig rule kept the pulse and hover alive). */
|
|
220
|
+
#tech .fhe-fig {
|
|
218
221
|
animation: rise .35s var(--ease-settle) 80ms both,
|
|
219
222
|
fig-pulse 2.6s ease-in-out infinite;
|
|
220
223
|
}
|
|
221
|
-
#
|
|
224
|
+
#tech .fhe-fig:hover, #tech .fhe-fig:focus-visible {
|
|
222
225
|
animation: rise .35s var(--ease-settle) 80ms both;
|
|
223
226
|
transform: scale(1.05);
|
|
224
227
|
}
|
|
@@ -228,27 +231,57 @@ input.invalid { border-color: var(--err); }
|
|
|
228
231
|
animation-delay: calc(160ms + var(--i, 0) * 40ms);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
|
-
/*
|
|
232
|
-
|
|
234
|
+
/* Tech-page hero (owner, 2026-09-04, zama.org reference): a centered
|
|
235
|
+
one-line title over the whole hero, then the left-aligned story beside
|
|
236
|
+
the animated FHE figure, the two halves vertically centered against
|
|
237
|
+
each other. Generous air; stacks on narrow windows. */
|
|
233
238
|
.intro-grid {
|
|
234
|
-
display: grid; grid-template-columns: 1fr 1fr; gap: clamp(
|
|
239
|
+
display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2.5rem, 5vw, 6rem);
|
|
235
240
|
align-items: center; margin-bottom: 2.2rem;
|
|
236
241
|
}
|
|
237
242
|
@media (max-width: 46rem) { .intro-grid { grid-template-columns: 1fr; } }
|
|
238
|
-
|
|
243
|
+
/* Centered, sized against the viewport so the sentence holds ONE line on
|
|
244
|
+
desktop widths (it may wrap on phones — nowrap would overflow there);
|
|
245
|
+
the bottom margin is the owner's asked-for title-to-body gap. */
|
|
246
|
+
#intro-title {
|
|
247
|
+
text-align: center; font-size: clamp(1.6rem, 3.2vw, 2.6rem);
|
|
248
|
+
line-height: 1.15;
|
|
249
|
+
margin: clamp(1rem, 3vh, 2.2rem) 0 clamp(2.2rem, 6vh, 4rem);
|
|
250
|
+
}
|
|
251
|
+
#intro-paras p { color: var(--ink); line-height: 1.65; margin: 0 0 1.1rem; }
|
|
239
252
|
#intro-paras p:last-child { margin-bottom: 0; }
|
|
240
|
-
/* Owner's copy 2026-09-04: the pipeline line reads as its own strip
|
|
241
|
-
|
|
253
|
+
/* Owner's copy 2026-09-04: the pipeline line reads as its own strip; the
|
|
254
|
+
closing lead is plain text + the SAME .nav-cta pill as the header's
|
|
255
|
+
Contact button — only the button is clickable. */
|
|
242
256
|
#intro-paras .intro-flow {
|
|
243
|
-
font-weight: 600; margin
|
|
257
|
+
font-weight: 600; margin: 1.6rem 0;
|
|
258
|
+
}
|
|
259
|
+
/* The four capability panels under the hero (owner, 2026-09-04, zama.org
|
|
260
|
+
card-row reference): one row of four on desktop, 2x2 on middling
|
|
261
|
+
widths, stacked on phones. */
|
|
262
|
+
#intro-panels {
|
|
263
|
+
display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.1rem;
|
|
264
|
+
margin: clamp(1.6rem, 4vh, 3rem) 0 0;
|
|
265
|
+
animation: rise .35s var(--ease-settle) both; animation-delay: 120ms;
|
|
266
|
+
}
|
|
267
|
+
@media (max-width: 64rem) { #intro-panels { grid-template-columns: 1fr 1fr; } }
|
|
268
|
+
@media (max-width: 34rem) { #intro-panels { grid-template-columns: 1fr; } }
|
|
269
|
+
#intro-panels .panel {
|
|
270
|
+
background: var(--panel); border-radius: .6rem; box-shadow: var(--ring);
|
|
271
|
+
padding: 1.15rem 1.25rem;
|
|
272
|
+
}
|
|
273
|
+
#intro-panels .panel h3 { margin: 0 0 .45rem; font-size: 1rem; }
|
|
274
|
+
#intro-panels .panel p {
|
|
275
|
+
margin: 0; color: var(--dim); font-size: .88rem; line-height: 1.55;
|
|
276
|
+
}
|
|
277
|
+
/* The centered contact row below the panels: plain lead text + the SAME
|
|
278
|
+
.nav-cta pill as the header's Contact button. */
|
|
279
|
+
#intro-contact {
|
|
280
|
+
display: flex; flex-wrap: wrap; justify-content: center;
|
|
281
|
+
align-items: center; gap: .8rem;
|
|
282
|
+
margin: clamp(1.8rem, 4vh, 3rem) 0 1rem;
|
|
283
|
+
animation: rise .35s var(--ease-settle) both; animation-delay: 200ms;
|
|
244
284
|
}
|
|
245
|
-
#intro-paras .intro-contact {
|
|
246
|
-
display: inline-block; margin-top: 1.1rem;
|
|
247
|
-
color: var(--accent); text-decoration: none;
|
|
248
|
-
border-bottom: 1px solid var(--accent-dim);
|
|
249
|
-
transition: border-color 150ms ease;
|
|
250
|
-
}
|
|
251
|
-
#intro-paras .intro-contact:hover { border-color: var(--accent); }
|
|
252
285
|
|
|
253
286
|
/* ---- the FHE explainer figure ----
|
|
254
287
|
Decorative and educational ONLY: aria-hidden SVG, never bound to live
|
|
@@ -262,12 +295,12 @@ input.invalid { border-color: var(--err); }
|
|
|
262
295
|
slightly on the floating 1011's rhythm (2.6s ease-in-out); hovering
|
|
263
296
|
(or focusing) settles it smoothly into the swollen form. */
|
|
264
297
|
.fhe-fig {
|
|
265
|
-
/*
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
margin: 0; justify-self: center; cursor: default; max-width:
|
|
298
|
+
/* History: the 2026-08-28 pass widened the PLAYGROUND only (viewBox
|
|
299
|
+
360 -> 400, container 31rem -> 34.5rem at the original item scale).
|
|
300
|
+
2026-09-04 (owner, hero pass): the whole figure now scales UP with
|
|
301
|
+
its column — the cap rises to 42rem, so items grow proportionally
|
|
302
|
+
with the SVG until the grid column runs out of width. */
|
|
303
|
+
margin: 0; justify-self: center; cursor: default; max-width: 42rem; width: 100%;
|
|
271
304
|
background: transparent; border: 0;
|
|
272
305
|
padding: .8rem .8rem .5rem;
|
|
273
306
|
transition: transform .35s var(--ease-settle);
|
|
@@ -149,16 +149,40 @@ function applyCopy(C) {
|
|
|
149
149
|
p.textContent = text;
|
|
150
150
|
introHolder.append(p);
|
|
151
151
|
}
|
|
152
|
-
// Owner's copy 2026-09-04: the pipeline line, then the
|
|
153
|
-
//
|
|
152
|
+
// Owner's copy 2026-09-04: the pipeline line, then the "At Implicant"
|
|
153
|
+
// paragraph close the left column.
|
|
154
154
|
const flow = document.createElement("p");
|
|
155
155
|
flow.className = "intro-flow";
|
|
156
156
|
flow.textContent = C.INTRO_FLOW;
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
157
|
+
const outro = document.createElement("p");
|
|
158
|
+
outro.textContent = C.INTRO_OUTRO;
|
|
159
|
+
introHolder.append(flow, outro);
|
|
160
|
+
// The four capability panels under the hero (owner, 2026-09-04,
|
|
161
|
+
// zama.org card-row reference): title + one short sentence each.
|
|
162
|
+
const panelHolder = $("intro-panels");
|
|
163
|
+
panelHolder.replaceChildren();
|
|
164
|
+
for (const [title, body] of C.INTRO_PANELS) {
|
|
165
|
+
const panel = document.createElement("div");
|
|
166
|
+
panel.className = "panel";
|
|
167
|
+
const h = document.createElement("h3");
|
|
168
|
+
h.textContent = title;
|
|
169
|
+
const p = document.createElement("p");
|
|
170
|
+
p.textContent = body;
|
|
171
|
+
panel.append(h, p);
|
|
172
|
+
panelHolder.append(panel);
|
|
173
|
+
}
|
|
174
|
+
// Below the panels, a centered lead sentence where ONLY the Contact us
|
|
175
|
+
// button is clickable — the exact same .nav-cta pill as the header's
|
|
176
|
+
// CTA (label AND target reused, so they never drift).
|
|
177
|
+
const contact = $("intro-contact");
|
|
178
|
+
contact.replaceChildren();
|
|
179
|
+
const lead = document.createElement("span");
|
|
180
|
+
lead.textContent = C.INTRO_CONTACT_LEAD;
|
|
181
|
+
const cta = document.createElement("a");
|
|
182
|
+
cta.className = "nav-cta";
|
|
183
|
+
cta.textContent = C.NAV_TABS.contact;
|
|
184
|
+
cta.href = C.NAV_LINKS.contact;
|
|
185
|
+
contact.append(lead, cta);
|
|
162
186
|
for (const el of document.querySelectorAll("[data-copy-title]"))
|
|
163
187
|
el.textContent = C.ACT_TITLES[el.dataset.copyTitle];
|
|
164
188
|
$("access-prompt").textContent = C.ACCESS_PROMPT;
|
|
@@ -57,6 +57,11 @@
|
|
|
57
57
|
reference): the intro paragraphs + the figure, reached from the
|
|
58
58
|
header's first tab. -->
|
|
59
59
|
<section id="tech" class="act" hidden>
|
|
60
|
+
<!-- Hero layout (owner, 2026-09-04, zama.org reference): the title is
|
|
61
|
+
a centered single line over the whole hero; below it, copy and
|
|
62
|
+
animation sit as two balanced, vertically centered halves; then
|
|
63
|
+
the four capability panels, then the centered contact row (all
|
|
64
|
+
filled from /api/copy in applyCopy). -->
|
|
60
65
|
<h2 id="intro-title"></h2>
|
|
61
66
|
<div class="intro-grid">
|
|
62
67
|
<div id="intro-paras"></div>
|
|
@@ -205,6 +210,8 @@
|
|
|
205
210
|
<figcaption id="fhe-caption"></figcaption>
|
|
206
211
|
</figure>
|
|
207
212
|
</div>
|
|
213
|
+
<div id="intro-panels"></div>
|
|
214
|
+
<p id="intro-contact"></p>
|
|
208
215
|
</section>
|
|
209
216
|
|
|
210
217
|
<!-- The Models page: the key ceremony, then the model list. -->
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|