facelift: the scroll story - bento capabilities, dossier cards, series badges, GitOps receipt
02 Capabilities becomes a 4-col bento (Edge AI 2x2 flagship w/ magenta corner radial, Platform wide, magenta-flavoured security tile, Observability row-completer) driven by span/flavor fields in skills.ts. 03 Selected Work becomes dossier cards: house-style SVG thumbnails (per-project motif via DossierThumb), DOSSIER/00N corner tags, 'the argument' line from the outcome field, chip tags, mono meta footer. 04 Writing cards gain the security-series badge (data/series.ts) and sit three across. Section numbers glow cyan; a circuit divider (gradient hairlines + two diamonds) closes the hero. Footer opens with the GitOps receipt - git sha + build date baked at build time via lib/build-info.ts, zero runtime calls.
This commit is contained in:
+126
-66
@@ -1,94 +1,154 @@
|
||||
---
|
||||
// One bento tile in the capabilities grid — size/flavour driven by the data
|
||||
// (span: hero 2×2 flagship · wide 2×1 · full row · default 1×1).
|
||||
import type { SkillGroup } from "../data/skills";
|
||||
|
||||
interface Props {
|
||||
group: SkillGroup;
|
||||
}
|
||||
const { group } = Astro.props;
|
||||
const spanClass =
|
||||
group.span === "hero"
|
||||
? "tile--hero"
|
||||
: group.span === "wide"
|
||||
? "tile--wide"
|
||||
: group.span === "full"
|
||||
? "tile--full"
|
||||
: "";
|
||||
---
|
||||
|
||||
<article class="skill card" data-reveal>
|
||||
<h3 class="skill__title">{group.title}</h3>
|
||||
<p class="skill__blurb">{group.blurb}</p>
|
||||
<ul class="skill__items">
|
||||
<article
|
||||
class:list={["tile", spanClass, group.flavor === "magenta" && "tile--magenta"]}
|
||||
data-reveal
|
||||
>
|
||||
{group.span === "hero" && <div class="tile__corner" aria-hidden="true" />}
|
||||
{group.flag && <p class="tile__flag mono">{group.flag}</p>}
|
||||
<h3 class="tile__title">{group.title}</h3>
|
||||
<p class="tile__blurb">{group.blurb}</p>
|
||||
<ul class="tile__chips mono" role="list">
|
||||
{group.items.map((item) => (
|
||||
<li class="chip"><span class="chip__node" aria-hidden="true"></span>{item}</li>
|
||||
<li class:list={["chip", group.span === "hero" && "chip--lit"]}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.skill {
|
||||
padding: var(--space-5);
|
||||
.tile {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
gap: 12px;
|
||||
padding: 28px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border-accent);
|
||||
border-radius: 10px;
|
||||
backdrop-filter: var(--panel-blur);
|
||||
-webkit-backdrop-filter: var(--panel-blur);
|
||||
transition:
|
||||
border-color 180ms var(--ease),
|
||||
box-shadow 180ms var(--ease);
|
||||
}
|
||||
.skill__title {
|
||||
font-size: var(--step-1);
|
||||
.tile:hover {
|
||||
border-color: var(--border-accent-hover);
|
||||
box-shadow: var(--glow-card);
|
||||
}
|
||||
.skill__title::before {
|
||||
content: "# ";
|
||||
color: var(--accent);
|
||||
font-family: var(--font-mono);
|
||||
.tile--magenta {
|
||||
border-color: var(--border-magenta);
|
||||
}
|
||||
.skill__blurb {
|
||||
color: var(--text-dim);
|
||||
font-size: var(--step--1);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.skill__items {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: var(--space-2) 0 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
.tile--magenta:hover {
|
||||
border-color: rgba(232, 121, 249, 0.5);
|
||||
box-shadow: var(--glow-card-magenta);
|
||||
}
|
||||
|
||||
/* Circuit-node chips — a glowing cyan→magenta node + mono label, wired to the
|
||||
board palette. Gradient border via padding-box/border-box layering so the
|
||||
radius survives. Lights to a full gradient outline + glow on hover. */
|
||||
.chip {
|
||||
--chip-grad: linear-gradient(100deg, var(--accent), var(--accent-2));
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.01em;
|
||||
.tile--hero {
|
||||
grid-column: span 2;
|
||||
grid-row: span 2;
|
||||
padding: 32px;
|
||||
gap: 16px;
|
||||
border-color: rgba(63, 186, 245, 0.2);
|
||||
}
|
||||
.tile--wide {
|
||||
grid-column: span 2;
|
||||
}
|
||||
.tile--full {
|
||||
/* "full" = the row-completer: 3 columns, sharing its row with the 1×1 before it */
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
.tile__corner {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(
|
||||
500px 320px at 85% 100%,
|
||||
rgba(232, 121, 249, 0.1),
|
||||
transparent 70%
|
||||
);
|
||||
pointer-events: none;
|
||||
}
|
||||
.tile__flag {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.14em;
|
||||
color: var(--accent-2);
|
||||
}
|
||||
.tile__title {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
font-family: var(--font-display);
|
||||
font-size: 19px;
|
||||
font-weight: 600;
|
||||
color: var(--text-strong);
|
||||
}
|
||||
.tile--hero .tile__title {
|
||||
font-size: 26px;
|
||||
}
|
||||
.tile__blurb {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-secondary);
|
||||
text-wrap: pretty;
|
||||
}
|
||||
.tile--hero .tile__blurb {
|
||||
font-size: 15px;
|
||||
color: var(--text-dim);
|
||||
padding: 0.3rem 0.62rem 0.3rem 0.55rem;
|
||||
border-radius: 7px;
|
||||
border: 1px solid var(--accent-line);
|
||||
background: color-mix(in srgb, var(--surface-2) 88%, var(--accent) 12%);
|
||||
transition: color 0.2s var(--ease), transform 0.2s var(--ease),
|
||||
border-color 0.2s var(--ease), box-shadow 0.2s var(--ease),
|
||||
background 0.2s var(--ease);
|
||||
max-width: 420px;
|
||||
}
|
||||
/* The node: a small cyan→magenta square that glows, like a lit via/pad. */
|
||||
.chip__node {
|
||||
flex: none;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 2px;
|
||||
background: var(--chip-grad);
|
||||
box-shadow: 0 0 7px var(--accent-glow);
|
||||
|
||||
.tile__chips {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 7px;
|
||||
margin: auto 0 0;
|
||||
padding: 0;
|
||||
font-size: 11.5px;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.chip:hover {
|
||||
color: var(--text);
|
||||
transform: translateY(-1px);
|
||||
border-color: transparent;
|
||||
/* dark fill (padding-box) inside a live gradient border (border-box) */
|
||||
background: linear-gradient(var(--surface-2), var(--surface-2)) padding-box,
|
||||
var(--chip-grad) border-box;
|
||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.32), 0 0 16px var(--accent-glow);
|
||||
.chip {
|
||||
border: 1px solid rgba(126, 139, 161, 0.25);
|
||||
border-radius: var(--radius-chip);
|
||||
padding: 4px 9px;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.chip {
|
||||
transition: none;
|
||||
}
|
||||
.chip:hover {
|
||||
transform: none;
|
||||
.chip--lit {
|
||||
font-size: 12px;
|
||||
color: var(--text-body-strong);
|
||||
border-color: rgba(63, 186, 245, 0.3);
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
/* bento collapses gracefully on narrow screens (grid goes 2-col then 1-col
|
||||
in the parent; spans clamp automatically via grid auto-placement) */
|
||||
@media (max-width: 720px) {
|
||||
.tile--hero,
|
||||
.tile--wide,
|
||||
.tile--full {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user