facelift: fleet constellation hero + Bat-Computer type/token layer
Chakra Petch site-wide (300-700) + JetBrains Mono variable, all self-hosted (CSP zero-external holds). Token layer gains the mock-exact text tiers, glass panel, cyan-tinted borders, glows, tighter radii; light 'blueprint' variants included. New Constellation.astro: the six real nodes as IC chips on dual-trace PCB paths (cyan out / magenta back, dasharray packets), radar ring on the cave hub, vias at bends - pure SVG + scoped CSS keyframes, full reduced-motion fallback. Hero rebuilt: scrim stack + masked grid over the board art, two-line gradient nameplate, typing bar cycling six real fleet facts via the external site.js (facts from src/data/fleet.ts), scroll indicator. Facts wrap, never clip.
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+43
-1
@@ -38,9 +38,51 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Hero typing loop (fleet facts) -------------------------------------
|
||||||
|
// Facts arrive via a data attribute (no inline JS → script-src 'self' holds).
|
||||||
|
// Reduced motion or JS-off: the first fact renders statically from markup.
|
||||||
|
var factBox = document.getElementById("fleet-fact");
|
||||||
|
var factText = document.getElementById("fleet-fact-text");
|
||||||
|
var reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
|
if (factBox && factText && !reduced) {
|
||||||
|
var facts;
|
||||||
|
try {
|
||||||
|
facts = JSON.parse(factBox.dataset.facts || "[]");
|
||||||
|
} catch (e) {
|
||||||
|
facts = [];
|
||||||
|
}
|
||||||
|
if (facts.length > 1) {
|
||||||
|
var fi = 0; // current fact
|
||||||
|
var ci = facts[0].length; // start fully typed (matches SSR markup)
|
||||||
|
var deleting = false;
|
||||||
|
var tick = function () {
|
||||||
|
var fact = facts[fi];
|
||||||
|
if (!deleting && ci === fact.length) {
|
||||||
|
// hold at end of fact, then start the next
|
||||||
|
deleting = true;
|
||||||
|
setTimeout(tick, 3200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (deleting) {
|
||||||
|
// swap instantly to the next fact (clean cut, like a terminal)
|
||||||
|
deleting = false;
|
||||||
|
fi = (fi + 1) % facts.length;
|
||||||
|
ci = 0;
|
||||||
|
factText.textContent = "";
|
||||||
|
setTimeout(tick, 260);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ci++;
|
||||||
|
factText.textContent = facts[fi].slice(0, ci);
|
||||||
|
setTimeout(tick, 45);
|
||||||
|
};
|
||||||
|
setTimeout(tick, 3200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scroll reveals, hero entrance, backdrop parallax, scroll-progress bar,
|
// Scroll reveals, hero entrance, backdrop parallax, scroll-progress bar,
|
||||||
// nav underline and button springs all live in the Motion layer
|
// nav underline and button springs all live in the Motion layer
|
||||||
// (src/scripts/anim.ts → bundled /_astro/*.js). This file owns only the
|
// (src/scripts/anim.ts → bundled /_astro/*.js). This file owns only the
|
||||||
// pre-paint theme so it can stay a tiny blocking <head> script.
|
// pre-paint theme + the typing loop so it stays a tiny blocking <head> script.
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { chromium } from "playwright";
|
||||||
|
import { preview } from "astro";
|
||||||
|
|
||||||
|
const server = await preview({ server: { port: 4399 } });
|
||||||
|
const base = "http://localhost:4399";
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
|
||||||
|
async function shot(name, { theme = "dark", scrollY = 0, selector = null, path = "/", fullPage = false } = {}) {
|
||||||
|
const page = await browser.newPage({
|
||||||
|
viewport: { width: 1440, height: 900 },
|
||||||
|
deviceScaleFactor: 2,
|
||||||
|
});
|
||||||
|
await page.addInitScript((t) => {
|
||||||
|
try { localStorage.setItem("theme", t); } catch {}
|
||||||
|
}, theme);
|
||||||
|
await page.goto(base + path, { waitUntil: "networkidle" });
|
||||||
|
await page.evaluate(
|
||||||
|
(t) => document.documentElement.setAttribute("data-theme", t),
|
||||||
|
theme
|
||||||
|
);
|
||||||
|
if (scrollY) {
|
||||||
|
await page.evaluate((y) => window.scrollTo(0, y), scrollY);
|
||||||
|
await page.waitForTimeout(400);
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(2700);
|
||||||
|
if (selector) {
|
||||||
|
const el = await page.$(selector);
|
||||||
|
await el.scrollIntoViewIfNeeded();
|
||||||
|
await page.waitForTimeout(2700);
|
||||||
|
await el.screenshot({ path: `/tmp/site-${name}.png` });
|
||||||
|
} else {
|
||||||
|
await page.screenshot({ path: `/tmp/site-${name}.png`, fullPage });
|
||||||
|
}
|
||||||
|
await page.close();
|
||||||
|
console.log("wrote /tmp/site-" + name + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
await shot("light-hero", { theme: "light" });
|
||||||
|
await shot("dark-hero", { theme: "dark" });
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
await server.stop();
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
---
|
||||||
|
// The fleet constellation — 6 real nodes as IC chips on PCB traces.
|
||||||
|
// Pure SVG + scoped CSS keyframes (zero JS; reduced-motion turns every animation off).
|
||||||
|
// Anatomy per the design handoff: each route is TWO parallel traces (offset ±(2,-3)) —
|
||||||
|
// one carries a cyan packet outbound, the other a magenta packet inbound. Packets are
|
||||||
|
// stroke-dasharray 9/127 sliding via stroke-dashoffset. Hub = cave (56px chip, radar ring).
|
||||||
|
---
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class="constellation"
|
||||||
|
viewBox="0 0 760 640"
|
||||||
|
role="img"
|
||||||
|
aria-label="Live topology of the six-node homelab fleet: hub cave reconciling alfred, robin, kate, wgirl and elfastc"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="var(--accent)"></stop>
|
||||||
|
<stop offset="1" stop-color="var(--accent-2)"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- ── PCB traces: dual parallel lines per route (out = cyan, back = magenta) ── -->
|
||||||
|
<!-- alfred -->
|
||||||
|
<g transform="translate(2,-3)">
|
||||||
|
<path class="t-glow t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
<path class="t-base t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
<path class="t-pkt pkt-fwd" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-2,3)">
|
||||||
|
<path class="t-glow t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
<path class="t-base t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
<path class="t-pkt t-pkt--mag pkt-rev-slow" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||||||
|
</g>
|
||||||
|
<!-- robin -->
|
||||||
|
<g transform="translate(2,-3)">
|
||||||
|
<path class="t-glow t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
<path class="t-base t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
<path class="t-pkt pkt-fwd-slow" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-2,3)">
|
||||||
|
<path class="t-glow t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
<path class="t-base t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
<path class="t-pkt t-pkt--mag pkt-rev" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||||||
|
</g>
|
||||||
|
<!-- kate (standby — dimmer) -->
|
||||||
|
<g transform="translate(2,-3)" class="standby">
|
||||||
|
<path class="t-glow t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
<path class="t-base t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
<path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-2,3)" class="standby">
|
||||||
|
<path class="t-glow t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
<path class="t-base t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||||||
|
</g>
|
||||||
|
<!-- wgirl (standby) -->
|
||||||
|
<g transform="translate(2,-3)" class="standby">
|
||||||
|
<path class="t-glow t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
<path class="t-base t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
<path class="t-pkt t-pkt--solid pkt-fwd" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-2,3)" class="standby">
|
||||||
|
<path class="t-glow t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
<path class="t-base t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev-slow" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||||||
|
</g>
|
||||||
|
<!-- elfastc (standby) -->
|
||||||
|
<g transform="translate(3,2)" class="standby">
|
||||||
|
<path class="t-glow t-cyan" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
<path class="t-base t-cyan" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
<path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-3,-2)" class="standby">
|
||||||
|
<path class="t-glow t-mag" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
<path class="t-base t-mag" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 V400 L452 472 V532"></path>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- vias at trace bends -->
|
||||||
|
<circle class="via via--cyan" cx="460" cy="310" r="3"></circle>
|
||||||
|
<circle class="via via--cyan" cx="520" cy="250" r="3"></circle>
|
||||||
|
<circle class="via via--cyan" cx="520" cy="180" r="3"></circle>
|
||||||
|
<circle class="via via--mag" cx="470" cy="310" r="3"></circle>
|
||||||
|
<circle class="via via--mag" cx="540" cy="380" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="300" cy="310" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="240" cy="250" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="310" cy="310" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="244" cy="376" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="380" cy="400" r="3"></circle>
|
||||||
|
<circle class="via via--dim" cx="452" cy="472" r="3"></circle>
|
||||||
|
|
||||||
|
<!-- ── hub: cave ── -->
|
||||||
|
<circle class="ring" cx="380" cy="310" r="46" fill="none" stroke="url(#lgA)" stroke-width="1.5"></circle>
|
||||||
|
<circle cx="380" cy="310" r="46" fill="rgba(63,186,245,0.05)" stroke="rgba(63,186,245,0.3)" stroke-width="1"></circle>
|
||||||
|
<!-- pin stubs -->
|
||||||
|
<g class="pins-cyan">
|
||||||
|
<line x1="352" y1="296" x2="340" y2="296"></line><line x1="352" y1="310" x2="340" y2="310"></line>
|
||||||
|
<line x1="352" y1="324" x2="340" y2="324"></line><line x1="366" y1="282" x2="366" y2="270"></line>
|
||||||
|
<line x1="380" y1="282" x2="380" y2="270"></line><line x1="366" y1="338" x2="366" y2="350"></line>
|
||||||
|
<line x1="380" y1="338" x2="380" y2="350"></line>
|
||||||
|
</g>
|
||||||
|
<g class="pins-mag">
|
||||||
|
<line x1="408" y1="296" x2="420" y2="296"></line><line x1="408" y1="310" x2="420" y2="310"></line>
|
||||||
|
<line x1="408" y1="324" x2="420" y2="324"></line><line x1="394" y1="282" x2="394" y2="270"></line>
|
||||||
|
<line x1="394" y1="338" x2="394" y2="350"></line>
|
||||||
|
</g>
|
||||||
|
<rect class="chip chip--hub" x="352" y="282" width="56" height="56" rx="8" stroke="url(#lgA)"></rect>
|
||||||
|
<rect x="364" y="294" width="32" height="32" rx="4" fill="none" stroke="rgba(63,186,245,0.4)" stroke-width="1"></rect>
|
||||||
|
<circle class="core core--cyan pulse" cx="380" cy="310" r="5"></circle>
|
||||||
|
<rect class="plate plate--hub" x="338" y="352" width="84" height="24" rx="4"></rect>
|
||||||
|
<text class="lbl lbl--hub" x="380" y="368" text-anchor="middle">cave</text>
|
||||||
|
<text class="cap cap--hub" x="380" y="392" text-anchor="middle">139 apps · reconciling</text>
|
||||||
|
|
||||||
|
<!-- ── awake: alfred ── -->
|
||||||
|
<circle cx="612" cy="128" r="24" fill="rgba(63,186,245,0.07)"></circle>
|
||||||
|
<rect class="chip chip--cyan" x="595" y="111" width="34" height="34" rx="5"></rect>
|
||||||
|
<circle class="core core--cyan pulse" cx="612" cy="128" r="4"></circle>
|
||||||
|
<rect class="plate plate--cyan" x="576" y="152" width="72" height="20" rx="3"></rect>
|
||||||
|
<text class="lbl" x="612" y="166" text-anchor="middle">alfred</text>
|
||||||
|
|
||||||
|
<!-- ── awake: robin ── -->
|
||||||
|
<circle cx="656" cy="420" r="24" fill="rgba(232,121,249,0.07)"></circle>
|
||||||
|
<rect class="chip chip--mag" x="639" y="403" width="34" height="34" rx="5"></rect>
|
||||||
|
<circle class="core core--mag pulse-slow" cx="656" cy="420" r="4"></circle>
|
||||||
|
<rect class="plate plate--mag" x="620" y="444" width="72" height="20" rx="3"></rect>
|
||||||
|
<text class="lbl" x="656" y="458" text-anchor="middle">robin</text>
|
||||||
|
|
||||||
|
<!-- ── standby: kate ── -->
|
||||||
|
<rect class="chip chip--cyan" x="145" y="135" width="30" height="30" rx="5"></rect>
|
||||||
|
<circle class="core core--cyan pulse-slow" cx="160" cy="150" r="3.5"></circle>
|
||||||
|
<rect class="plate plate--dim" x="126" y="172" width="68" height="20" rx="3"></rect>
|
||||||
|
<text class="lbl lbl--dim" x="160" y="186" text-anchor="middle">kate</text>
|
||||||
|
<text class="cap cap--dim" x="160" y="206" text-anchor="middle">standby · 33 apps known</text>
|
||||||
|
|
||||||
|
<!-- ── standby: wgirl ── -->
|
||||||
|
<rect class="chip chip--mag" x="199" y="471" width="30" height="30" rx="5"></rect>
|
||||||
|
<circle class="core core--mag pulse" cx="214" cy="486" r="3.5"></circle>
|
||||||
|
<rect class="plate plate--dim" x="180" y="508" width="68" height="20" rx="3"></rect>
|
||||||
|
<text class="lbl lbl--dim" x="214" y="522" text-anchor="middle">wgirl</text>
|
||||||
|
|
||||||
|
<!-- ── standby: elfastc ── -->
|
||||||
|
<rect class="chip chip--cyan" x="437" y="533" width="30" height="30" rx="5"></rect>
|
||||||
|
<circle class="core core--cyan pulse-slow" cx="452" cy="548" r="3.5"></circle>
|
||||||
|
<rect class="plate plate--dim" x="412" y="570" width="80" height="20" rx="3"></rect>
|
||||||
|
<text class="lbl lbl--dim" x="452" y="584" text-anchor="middle">elfastc</text>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.constellation {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* trace layers */
|
||||||
|
.t-glow { fill: none; stroke-width: 7; }
|
||||||
|
.t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.12); }
|
||||||
|
.t-glow.t-mag { stroke: rgba(232, 121, 249, 0.1); }
|
||||||
|
.standby .t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.1); }
|
||||||
|
.standby .t-glow.t-mag { stroke: rgba(232, 121, 249, 0.08); }
|
||||||
|
.t-base { fill: none; stroke-width: 2; }
|
||||||
|
.t-base.t-cyan { stroke: rgba(63, 186, 245, 0.45); }
|
||||||
|
.t-base.t-mag { stroke: rgba(232, 121, 249, 0.38); }
|
||||||
|
.standby .t-base.t-cyan { stroke: rgba(63, 186, 245, 0.35); }
|
||||||
|
.standby .t-base.t-mag { stroke: rgba(232, 121, 249, 0.3); }
|
||||||
|
|
||||||
|
/* the moving packets */
|
||||||
|
.t-pkt {
|
||||||
|
fill: none;
|
||||||
|
stroke: url(#lgA);
|
||||||
|
stroke-width: 3;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-dasharray: 9 127;
|
||||||
|
filter: drop-shadow(0 0 6px rgba(63, 186, 245, 0.9));
|
||||||
|
}
|
||||||
|
.t-pkt--mag { filter: drop-shadow(0 0 6px rgba(232, 121, 249, 0.9)); }
|
||||||
|
.t-pkt--solid { stroke: rgba(63, 186, 245, 0.85); }
|
||||||
|
.t-pkt--solid.t-pkt--mag { stroke: rgba(232, 121, 249, 0.85); }
|
||||||
|
|
||||||
|
.pkt-fwd { animation: bzDash 8s linear infinite; }
|
||||||
|
.pkt-fwd-slow { animation: bzDash 11s linear infinite; }
|
||||||
|
.pkt-rev { animation: bzDashRev 9s linear infinite; }
|
||||||
|
.pkt-rev-slow { animation: bzDashRev 13s linear infinite; }
|
||||||
|
|
||||||
|
/* vias */
|
||||||
|
.via { fill: var(--panel-solid); stroke-width: 1; }
|
||||||
|
.via--cyan { stroke: rgba(63, 186, 245, 0.6); }
|
||||||
|
.via--mag { stroke: rgba(232, 121, 249, 0.6); }
|
||||||
|
.via--dim { stroke: rgba(126, 139, 161, 0.5); }
|
||||||
|
|
||||||
|
/* chips + cores + plates + labels */
|
||||||
|
.chip { fill: var(--panel-solid); }
|
||||||
|
.chip--hub { stroke-width: 2; filter: drop-shadow(0 0 10px rgba(63, 186, 245, 0.45)); }
|
||||||
|
.chip--cyan { stroke: var(--accent); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(63, 186, 245, 0.55)); }
|
||||||
|
.chip--mag { stroke: var(--accent-2); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(232, 121, 249, 0.55)); }
|
||||||
|
.core--cyan { fill: var(--accent); filter: drop-shadow(0 0 6px rgba(63, 186, 245, 1)); }
|
||||||
|
.core--mag { fill: var(--accent-2); filter: drop-shadow(0 0 5px rgba(232, 121, 249, 1)); }
|
||||||
|
.pulse { animation: bzPulse 2.4s ease-in-out infinite; }
|
||||||
|
.pulse-slow { animation: bzPulse 3.4s ease-in-out infinite; }
|
||||||
|
.pins-cyan line { stroke: rgba(63, 186, 245, 0.6); stroke-width: 1.5; }
|
||||||
|
.pins-mag line { stroke: rgba(232, 121, 249, 0.6); stroke-width: 1.5; }
|
||||||
|
.plate { fill: rgba(13, 19, 34, 0.92); stroke-width: 1; }
|
||||||
|
.plate--hub { stroke: rgba(63, 186, 245, 0.4); }
|
||||||
|
.plate--cyan { stroke: rgba(63, 186, 245, 0.35); }
|
||||||
|
.plate--mag { stroke: rgba(232, 121, 249, 0.35); }
|
||||||
|
.plate--dim { stroke: rgba(126, 139, 161, 0.3); }
|
||||||
|
.lbl {
|
||||||
|
fill: #e8f2fb;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.lbl--hub { font-size: 12px; font-weight: 700; }
|
||||||
|
.lbl--dim { fill: #9fb0c8; }
|
||||||
|
.cap { font-family: var(--font-mono); }
|
||||||
|
.cap--hub {
|
||||||
|
fill: var(--accent);
|
||||||
|
font-size: 9.5px;
|
||||||
|
filter: drop-shadow(0 0 4px rgba(63, 186, 245, 0.7));
|
||||||
|
}
|
||||||
|
.cap--dim { fill: #5c6a82; font-size: 9px; }
|
||||||
|
|
||||||
|
/* radar ring off the hub */
|
||||||
|
.ring {
|
||||||
|
transform-box: fill-box;
|
||||||
|
transform-origin: center;
|
||||||
|
animation: bzRing 3.6s ease-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bzDash { to { stroke-dashoffset: -260; } }
|
||||||
|
@keyframes bzDashRev { to { stroke-dashoffset: 260; } }
|
||||||
|
@keyframes bzPulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
|
||||||
|
@keyframes bzRing {
|
||||||
|
0% { transform: scale(0.5); opacity: 0.9; }
|
||||||
|
100% { transform: scale(1.7); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.pkt-fwd, .pkt-fwd-slow, .pkt-rev, .pkt-rev-slow, .pulse, .pulse-slow, .ring {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.ring { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+202
-31
@@ -1,10 +1,20 @@
|
|||||||
---
|
---
|
||||||
import { site } from "../data/site";
|
import { site } from "../data/site";
|
||||||
import { cvAvailable } from "../lib/assets";
|
import { cvAvailable } from "../lib/assets";
|
||||||
|
import { fleetFacts } from "../data/fleet";
|
||||||
|
import Constellation from "./Constellation.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
|
<!-- hero-scoped atmosphere over the site-wide board art: directional scrims,
|
||||||
|
a static radial glow, and a 56px grid masked to an ellipse -->
|
||||||
|
<div class="hero__scrim hero__scrim--x" aria-hidden="true"></div>
|
||||||
|
<div class="hero__scrim hero__scrim--y" aria-hidden="true"></div>
|
||||||
|
<div class="hero__glow" aria-hidden="true"></div>
|
||||||
|
<div class="hero__grid" aria-hidden="true"></div>
|
||||||
|
|
||||||
<div class="container hero__inner">
|
<div class="container hero__inner">
|
||||||
|
<div class="hero__copy">
|
||||||
<p class="eyebrow hero__eyebrow">{site.role}</p>
|
<p class="eyebrow hero__eyebrow">{site.role}</p>
|
||||||
|
|
||||||
<h1 class="hero__title">
|
<h1 class="hero__title">
|
||||||
@@ -23,7 +33,7 @@ import { cvAvailable } from "../lib/assets";
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="hero__cta">
|
<div class="hero__cta">
|
||||||
<a class="btn btn--primary" href="/#projects">View Projects</a>
|
<a class="btn btn--primary" href="/#projects">View Projects →</a>
|
||||||
{cvAvailable && (
|
{cvAvailable && (
|
||||||
<a class="btn" href="/cv.pdf" download>
|
<a class="btn" href="/cv.pdf" download>
|
||||||
Download CV
|
Download CV
|
||||||
@@ -31,40 +41,136 @@ import { cvAvailable } from "../lib/assets";
|
|||||||
)}
|
)}
|
||||||
<a class="btn" href="/#contact">Contact</a>
|
<a class="btn" href="/#contact">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- the typing fleet-fact bar: real numbers, cycled by site.js (external, CSP-safe);
|
||||||
|
with JS off / reduced motion it shows the first fact statically -->
|
||||||
|
<div
|
||||||
|
class="hero__fact mono"
|
||||||
|
id="fleet-fact"
|
||||||
|
data-facts={JSON.stringify(fleetFacts)}
|
||||||
|
>
|
||||||
|
<span class="hero__fact-prompt">~/{site.handle} ▸</span>
|
||||||
|
<span class="hero__fact-line"
|
||||||
|
><span id="fleet-fact-text">{fleetFacts[0]}</span><span
|
||||||
|
class="hero__caret"
|
||||||
|
aria-hidden="true">▮</span
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero__viz" aria-hidden="false">
|
||||||
|
<Constellation />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero__scroll mono" aria-hidden="true">
|
||||||
|
<span class="hero__diamond"></span>
|
||||||
|
<span>SCROLL — DESCENDING: EDGE / CLUSTER / WORKLOAD / SECURITY</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.hero {
|
.hero {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: min(88vh, 760px);
|
min-height: min(92vh, 820px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border-accent);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* atmosphere layers (scoped to the hero, over the global board art) */
|
||||||
|
.hero__scrim,
|
||||||
|
.hero__glow,
|
||||||
|
.hero__grid {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.hero__scrim--x {
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(9, 12, 20, 0.96) 0%,
|
||||||
|
rgba(9, 12, 20, 0.88) 42%,
|
||||||
|
rgba(9, 12, 20, 0.62) 70%,
|
||||||
|
rgba(9, 12, 20, 0.55) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.hero__scrim--y {
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(9, 12, 20, 0.55) 0%,
|
||||||
|
transparent 30%,
|
||||||
|
transparent 70%,
|
||||||
|
rgba(9, 12, 20, 0.9) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
[data-theme="light"] .hero__scrim--x {
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(246, 248, 251, 0.96) 0%,
|
||||||
|
rgba(246, 248, 251, 0.86) 42%,
|
||||||
|
rgba(246, 248, 251, 0.6) 70%,
|
||||||
|
rgba(246, 248, 251, 0.5) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
[data-theme="light"] .hero__scrim--y {
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(246, 248, 251, 0.55) 0%,
|
||||||
|
transparent 30%,
|
||||||
|
transparent 70%,
|
||||||
|
rgba(246, 248, 251, 0.92) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.hero__glow {
|
||||||
|
background:
|
||||||
|
radial-gradient(900px 600px at 78% 40%, rgba(232, 121, 249, 0.1), transparent 65%),
|
||||||
|
radial-gradient(1000px 700px at 15% 25%, rgba(63, 186, 245, 0.12), transparent 60%);
|
||||||
|
}
|
||||||
|
.hero__grid {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--grid-line) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
|
||||||
|
background-size: 56px 56px;
|
||||||
|
mask-image: radial-gradient(ellipse 80% 70% at 60% 40%, black 30%, transparent 75%);
|
||||||
|
}
|
||||||
|
|
||||||
.hero__inner {
|
.hero__inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 640px) minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-6);
|
||||||
padding-block: var(--space-9);
|
padding-block: var(--space-9);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.hero__copy {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.hero__viz {
|
||||||
|
justify-self: end;
|
||||||
|
width: min(48vw, 720px);
|
||||||
|
margin-right: -4%;
|
||||||
|
}
|
||||||
|
|
||||||
.hero__eyebrow {
|
.hero__eyebrow {
|
||||||
margin-bottom: var(--space-4);
|
margin-bottom: var(--space-4);
|
||||||
|
letter-spacing: 0.18em;
|
||||||
|
text-shadow: 0 0 14px rgba(63, 186, 245, 0.5);
|
||||||
}
|
}
|
||||||
.hero__title {
|
.hero__title {
|
||||||
font-family: var(--font-display);
|
font-family: var(--font-display);
|
||||||
font-size: var(--step-5);
|
font-size: var(--step-5);
|
||||||
line-height: 1.12;
|
line-height: 1.05;
|
||||||
/* Chakra Petch is geometric/wide — looser tracking than Inter's -0.03em. */
|
|
||||||
letter-spacing: -0.005em;
|
letter-spacing: -0.005em;
|
||||||
/* Extend the paint box below the baseline so background-clip:text doesn't
|
|
||||||
crop glyph descenders (the "g" in Wright). */
|
|
||||||
padding-bottom: 0.14em;
|
padding-bottom: 0.14em;
|
||||||
/* Vivid electric nameplate — a full cyan→violet→magenta fill (theme-aware via
|
/* two-line nameplate (mock parity) — wrap at the space, keep the column clear
|
||||||
the accent tokens: deep on light, bright on dark) so the name is unmissable
|
of the constellation's left-most node labels */
|
||||||
on EITHER backdrop. Two layers: a light sheen band on top that glides across
|
max-width: min-content;
|
||||||
once on load (heroSheen) then rests off-screen, over the solid gradient.
|
|
||||||
A tight dark edge-shadow keeps the colour crisp on the light board; the
|
|
||||||
wide accent glow gives the electric halo. */
|
|
||||||
background:
|
background:
|
||||||
linear-gradient(
|
linear-gradient(
|
||||||
105deg,
|
105deg,
|
||||||
@@ -79,19 +185,18 @@ import { cvAvailable } from "../lib/assets";
|
|||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
/* Override the light-mode body text-halo (which washed the clipped fill). */
|
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
filter: drop-shadow(0 1px 1px rgba(2, 6, 23, 0.22))
|
filter: drop-shadow(0 1px 1px rgba(2, 6, 23, 0.22))
|
||||||
drop-shadow(0 6px 22px var(--accent-glow));
|
drop-shadow(0 6px 22px var(--accent-glow));
|
||||||
}
|
}
|
||||||
.hero__positioning {
|
.hero__positioning {
|
||||||
margin-top: var(--space-5);
|
margin-top: var(--space-5);
|
||||||
max-width: 42rem;
|
max-width: 32rem;
|
||||||
font-size: var(--step-2);
|
font-size: var(--step-1);
|
||||||
line-height: 1.35;
|
line-height: 1.55;
|
||||||
color: var(--text);
|
color: var(--text-dim);
|
||||||
font-weight: 500;
|
font-weight: 400;
|
||||||
letter-spacing: -0.01em;
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
.hero__tags {
|
.hero__tags {
|
||||||
margin: var(--space-5) 0 0;
|
margin: var(--space-5) 0 0;
|
||||||
@@ -101,7 +206,7 @@ import { cvAvailable } from "../lib/assets";
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.4rem 0.6rem;
|
gap: 0.4rem 0.6rem;
|
||||||
font-size: var(--step--1);
|
font-size: var(--step--1);
|
||||||
color: var(--text-dim);
|
color: var(--text-label);
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
.hero__sep {
|
.hero__sep {
|
||||||
@@ -114,23 +219,89 @@ import { cvAvailable } from "../lib/assets";
|
|||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The staggered fade-up entrance is driven by the Motion layer
|
/* the typing bar — glass panel */
|
||||||
(src/scripts/anim.ts). What stays here is the one-shot electric sheen that
|
.hero__fact {
|
||||||
sweeps across the nameplate once on load — a pure background-position paint
|
margin-top: var(--space-6);
|
||||||
effect (no transform/opacity), motion-aware. */
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px 18px;
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid var(--border-accent);
|
||||||
|
border-radius: var(--radius-btn);
|
||||||
|
backdrop-filter: var(--panel-blur);
|
||||||
|
-webkit-backdrop-filter: var(--panel-blur);
|
||||||
|
max-width: 600px;
|
||||||
|
min-height: 22px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.hero__fact-prompt {
|
||||||
|
color: var(--accent);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.hero__fact-line {
|
||||||
|
color: var(--text-body-strong);
|
||||||
|
/* real facts don't get clipped — wrap like a terminal would */
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.hero__caret {
|
||||||
|
color: var(--accent);
|
||||||
|
animation: bzCaret 1.1s step-end infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero__scroll {
|
||||||
|
position: absolute;
|
||||||
|
left: max(calc((100vw - var(--measure)) / 2), var(--space-5));
|
||||||
|
bottom: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-faint);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.hero__diamond {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bzCaret {
|
||||||
|
0%, 49% { opacity: 1; }
|
||||||
|
50%, 100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
.hero__title {
|
.hero__title {
|
||||||
animation: heroSheen 1.6s var(--ease) 0.7s both;
|
animation: heroSheen 1.6s var(--ease) 0.7s both;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* The light sheen band (1st layer) sweeps left across the glyphs once, then
|
@media (prefers-reduced-motion: reduce) {
|
||||||
parks off-screen so only the vivid gradient (2nd layer, static) remains. */
|
.hero__caret { animation: none; }
|
||||||
|
}
|
||||||
@keyframes heroSheen {
|
@keyframes heroSheen {
|
||||||
from {
|
from { background-position: 135% 0, 0 0; }
|
||||||
background-position: 135% 0, 0 0;
|
to { background-position: -35% 0, 0 0; }
|
||||||
}
|
}
|
||||||
to {
|
|
||||||
background-position: -35% 0, 0 0;
|
/* responsive: constellation folds under, then hides on small screens */
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.hero__inner {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
.hero__viz {
|
||||||
|
justify-self: center;
|
||||||
|
width: min(88vw, 560px);
|
||||||
|
margin-right: 0;
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.hero__viz { display: none; }
|
||||||
|
.hero__fact { font-size: 12px; }
|
||||||
|
.hero__scroll { display: none; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// The fleet, as data — drives the hero constellation + typing facts.
|
||||||
|
// REAL numbers, captured 2026-07-03; refresh from the fleet at rebuild
|
||||||
|
// (kubectl get applications -n argocd | wc -l · kubectl get cnp -A | wc -l per cluster).
|
||||||
|
|
||||||
|
// Facts the hero typing bar cycles through. Real, verbatim — no invented numbers.
|
||||||
|
export const fleetFacts = [
|
||||||
|
"6 single-node Talos clusters · 0 SSH daemons · every machine is a document",
|
||||||
|
"139 ArgoCD Applications reconciled from one hub",
|
||||||
|
"170+ CiliumNetworkPolicies fleet-wide — every namespace starts at default-deny",
|
||||||
|
"zero open inbound ports — the origin dials out",
|
||||||
|
"*.bztmon.org — a Let's Encrypt wildcard per cluster · DNS-01 · auto-renewed",
|
||||||
|
"~140 pods running right now, reconciled by git",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
// Node roster for the constellation (positions live in the SVG component).
|
||||||
|
export const fleetNodes = {
|
||||||
|
hub: { name: "cave", caption: "139 apps · reconciling" },
|
||||||
|
satellites: ["alfred", "robin", "kate", "wgirl", "elfastc"],
|
||||||
|
standbyCaption: "standby · 33 apps known", // kate
|
||||||
|
} as const;
|
||||||
@@ -18,6 +18,36 @@
|
|||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("/fonts/chakra-petch-700.woff2") format("woff2");
|
src: url("/fonts/chakra-petch-700.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
/* Facelift: Chakra Petch becomes the site-wide face (300–700), body included. */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Chakra Petch";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/chakra-petch-300.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Chakra Petch";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/chakra-petch-400.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Chakra Petch";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/chakra-petch-500.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
/* JetBrains Mono — one variable file covers 400–700 (nav, chips, eyebrows, receipt). */
|
||||||
|
@font-face {
|
||||||
|
font-family: "JetBrains Mono";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/jetbrains-mono-var.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Base ---------------------------------------------------------------- */
|
/* ---- Base ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|||||||
+43
-9
@@ -29,13 +29,13 @@
|
|||||||
/* Grid / topology motif */
|
/* Grid / topology motif */
|
||||||
--grid-line: rgba(148, 163, 184, 0.06);
|
--grid-line: rgba(148, 163, 184, 0.06);
|
||||||
|
|
||||||
/* Fonts — system stacks (zero external requests) + one self-hosted display face. */
|
/* Fonts — ALL self-hosted (zero external requests). Facelift pairing:
|
||||||
--font-sans: "Inter var", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
|
Chakra Petch (300–700) is the site-wide face, display AND body;
|
||||||
Roboto, Helvetica, Arial, sans-serif;
|
JetBrains Mono carries the terminal register (nav, chips, eyebrows, receipt). */
|
||||||
--font-mono: ui-monospace, "JetBrains Mono", "Cascadia Code", "SF Mono",
|
--font-sans: "Chakra Petch", ui-sans-serif, system-ui, -apple-system,
|
||||||
|
"Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
--font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", "SF Mono",
|
||||||
Menlo, Consolas, "Liberation Mono", monospace;
|
Menlo, Consolas, "Liberation Mono", monospace;
|
||||||
/* Display face — Chakra Petch (self-hosted woff2, OFL). Used ONLY on the hero
|
|
||||||
name + section titles; body stays in --font-sans for readability. */
|
|
||||||
--font-display: "Chakra Petch", var(--font-sans);
|
--font-display: "Chakra Petch", var(--font-sans);
|
||||||
|
|
||||||
/* Fluid type scale */
|
/* Fluid type scale */
|
||||||
@@ -58,13 +58,33 @@
|
|||||||
--space-8: 4.5rem;
|
--space-8: 4.5rem;
|
||||||
--space-9: 7rem;
|
--space-9: 7rem;
|
||||||
|
|
||||||
/* Layout */
|
/* Layout — facelift geometry: tighter radii (3–4 chips, 6 buttons, 8–12 cards) */
|
||||||
--measure: 68rem;
|
--measure: 68rem;
|
||||||
--radius: 14px;
|
--radius: 12px;
|
||||||
--radius-sm: 9px;
|
--radius-sm: 8px;
|
||||||
|
--radius-btn: 6px;
|
||||||
|
--radius-chip: 4px;
|
||||||
--ring: 0 0 0 1px var(--border);
|
--ring: 0 0 0 1px var(--border);
|
||||||
--shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
|
--shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
|
||||||
--ease: cubic-bezier(0.22, 1, 0.36, 1);
|
--ease: cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
|
||||||
|
/* Facelift: text tiers (mock-exact) */
|
||||||
|
--text-strong: #eef5fd; /* headings */
|
||||||
|
--text-body-strong: #dbe6f4;
|
||||||
|
/* --text (#e7edf4) / --text-dim / --text-faint keep existing consumers working */
|
||||||
|
--text-secondary: #8fa2bd;
|
||||||
|
--text-label: #7e8ba1;
|
||||||
|
|
||||||
|
/* Facelift: glass panels + cyan-tinted borders + glows */
|
||||||
|
--panel: rgba(13, 19, 34, 0.72);
|
||||||
|
--panel-solid: #0d1322;
|
||||||
|
--panel-blur: blur(10px);
|
||||||
|
--border-accent: rgba(63, 186, 245, 0.14);
|
||||||
|
--border-accent-hover: rgba(63, 186, 245, 0.5);
|
||||||
|
--border-magenta: rgba(232, 121, 249, 0.18);
|
||||||
|
--glow-num: 0 0 12px rgba(63, 186, 245, 0.6);
|
||||||
|
--glow-card: 0 0 32px rgba(63, 186, 245, 0.14);
|
||||||
|
--glow-card-magenta: 0 0 32px rgba(232, 121, 249, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="light"] {
|
[data-theme="light"] {
|
||||||
@@ -96,4 +116,18 @@
|
|||||||
--grid-line: rgba(15, 23, 42, 0.05);
|
--grid-line: rgba(15, 23, 42, 0.05);
|
||||||
|
|
||||||
--shadow: 0 24px 60px rgba(15, 23, 42, 0.12);
|
--shadow: 0 24px 60px rgba(15, 23, 42, 0.12);
|
||||||
|
|
||||||
|
/* Facelift tiers, blueprint-adjusted for light */
|
||||||
|
--text-strong: #0b1422;
|
||||||
|
--text-body-strong: #1d2a3d;
|
||||||
|
--text-secondary: #3d4d63;
|
||||||
|
--text-label: #4a5a72;
|
||||||
|
--panel: rgba(255, 255, 255, 0.78);
|
||||||
|
--panel-solid: #ffffff;
|
||||||
|
--border-accent: rgba(12, 143, 206, 0.2);
|
||||||
|
--border-accent-hover: rgba(12, 143, 206, 0.55);
|
||||||
|
--border-magenta: rgba(192, 38, 211, 0.22);
|
||||||
|
--glow-num: 0 0 12px rgba(12, 143, 206, 0.35);
|
||||||
|
--glow-card: 0 0 32px rgba(12, 143, 206, 0.1);
|
||||||
|
--glow-card-magenta: 0 0 32px rgba(192, 38, 211, 0.08);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user