openvibers/afresume Commits

Layout audit, second pass: tablets, the strengths, stats, cards and what opens

OP OpenVibers committed 26 Sept 2026 · aee01184b2 · 7 files, +31 −18

Checked at 390, 460, 768, 1000 and 1280 px, in the light theme, and with every expandable part open.
- Strengths: the icon sits on the title line and the text runs the full card width (an icon column
  squeezed every line); one per row on phones, two on tablets with the fifth spanning the row, five
  across on wide screens; content pinned to the top so a taller neighbour adds no gaps inside.
- Stats: the icon moves to the card's top-right corner (no row of its own); four across down to
  700px instead of a 2x4 stack on tablets.
- Work groups: as many columns as cards, up to four (two on tablets), so no group ends on a lone
  card beside empty cells.
- Hero tags use the full width once the hero is one column (four across on tablets).
- Portfolio cards: tighter body padding, gaps, icon and link button.
- OpenVibe explainer: the open toggle says "Show less".
- Résumé: the twelve themed-PDF swatches sit in two even rows of six on phones.

Changes

ddiff --git a/src/components/Hero.astro b/src/components/Hero.astro
iindex 6743614..c7668e8 100644
---- a/src/components/Hero.astro
++++ b/src/components/Hero.astro
@@@ -227,6 +227,7 @@ import fcAlbum from "../data/fc-album.json";
.hero__eq i { height: 70%; }
}
.hero__tags { max-width: 620px; }
++ @media (max-width: 920px) { .hero__tags { max-width: none; } }
.hero__tags-label { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font: 500 .72rem var(--font-mono); letter-spacing: .16em; text-transform: uppercase; color: var(--dim); }
.hero__tags-label i { color: var(--accent); }
.hero__tags-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
ddiff --git a/src/components/Metrics.astro b/src/components/Metrics.astro
iindex df7cb4c..daab6da 100644
---- a/src/components/Metrics.astro
++++ b/src/components/Metrics.astro
@@@ -23,19 +23,20 @@ const metrics = profile.metrics;
.metric {
position: relative; overflow: hidden;
display: flex; flex-direction: column; gap: 10px;
-- padding: 22px 20px 20px; border-radius: var(--radius);
++ padding: 20px 20px 18px; backdrop-filter: none; border-radius: var(--radius);
background: var(--surface); border: 1px solid var(--border);
-- backdrop-filter: blur(12px);
transition: transform .5s var(--ease), border-color .3s var(--ease), box-shadow .5s var(--ease);
}
.metric:hover { border-color: rgba(var(--accent-rgb), .4); box-shadow: var(--shadow-glow); }
.metric::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--grad); transform: scaleX(0); transform-origin: 0 50%; transition: transform .6s var(--ease); }
.metric:hover::after { transform: scaleX(1); }
-- .metric__icon { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 10px; background: rgba(var(--accent-rgb), .12); color: var(--accent); font-size: .95rem; }
++ /* The icon sits in the card's top-right corner instead of a row of its own above the number. */
++ .metric__icon { position: absolute; top: 14px; right: 14px; width: 32px; height: 32px; display: inline-grid; place-items: center; border-radius: 10px; background: rgba(var(--accent-rgb), .12); color: var(--accent); font-size: .95rem; }
.metric__num { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.9rem, 3vw, 2.5rem); letter-spacing: -.03em; color: var(--fg); line-height: 1; font-variant-numeric: tabular-nums; }
.metric__lbl { font-size: .84rem; color: var(--muted); line-height: 1.4; }
-- @media (max-width: 980px) { .metrics__grid { grid-template-columns: repeat(2, 1fr); } }
-- @media (max-width: 420px) { .metrics__grid { grid-template-columns: 1fr 1fr; gap: 8px; } .metric { padding: 16px 14px; } }
++ @media (max-width: 700px) { .metrics__grid { grid-template-columns: repeat(2, 1fr); } }
++ @media (min-width: 701px) and (max-width: 980px) { .metric { padding: 16px 14px; } }
++ @media (max-width: 420px) { .metrics__grid { grid-template-columns: 1fr 1fr; gap: 8px; } .metric { padding: 16px 14px; } .metric__icon { top: 12px; right: 12px; width: 28px; height: 28px; font-size: .82rem; } }
</style>
<script>
ddiff --git a/src/components/Now.astro b/src/components/Now.astro
iindex b88c952..abdbb53 100644
---- a/src/components/Now.astro
++++ b/src/components/Now.astro
@@@ -69,13 +69,18 @@ const statusAlsoParts = linkify(profile.status.also, LINK_TERMS);
.now__pitch { padding: clamp(24px, 3.5vw, 40px); }
.now__text { font-size: 1.08rem; line-height: 1.8; color: var(--muted); }
.now__text:first-child { color: var(--fg); font-size: clamp(1.1rem, 1.6vw, 1.3rem); font-weight: 500; line-height: 1.6; letter-spacing: -.005em; }
-- .now__hl { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
-- .now__hl li { display: flex; gap: 14px; align-items: flex-start; padding: 12px 14px; border-radius: 14px; background: var(--surface); border: 1px solid var(--border); transition: border-color .3s var(--ease), transform .3s var(--ease); }
-- @media (min-width: 901px) { .now__hl li { flex-direction: column; gap: 10px; } }
++ /* Strengths: the icon sits on the title line and the text runs the full card width (an icon column
++ beside the text left a strip of empty space and squeezed every line). One per row on phones, two
++ on tablets (the fifth spans the row), five across on wide screens. */
++ .now__hl { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; gap: 10px; }
++ @media (min-width: 561px) { .now__hl { grid-template-columns: 1fr 1fr; } .now__hl li:last-child:nth-child(odd) { grid-column: 1 / -1; } }
++ @media (min-width: 1100px) { .now__hl { grid-template-columns: repeat(5, 1fr); } .now__hl li:last-child:nth-child(odd) { grid-column: auto; } }
++ .now__hl li { display: grid; grid-template-columns: auto 1fr; grid-template-areas: "ico title" "text text"; gap: 8px 10px; align-items: center; align-content: start; padding: 12px 14px; border-radius: 14px; background: var(--surface); border: 1px solid var(--border); transition: border-color .3s var(--ease), transform .3s var(--ease); }
.now__hl li:hover { border-color: rgba(var(--accent-rgb), .5); transform: translateX(4px); }
-- .now__hl i { flex: none; width: 36px; height: 36px; border-radius: 10px; display: inline-grid; place-items: center; background: rgba(var(--accent-rgb), .12); color: var(--accent); font-size: .95rem; }
-- .now__hl strong { display: block; color: var(--fg); font-size: .98rem; margin-bottom: 2px; }
-- .now__hl span { color: var(--muted); font-size: .9rem; line-height: 1.55; }
++ .now__hl li > div { display: contents; }
++ .now__hl i { grid-area: ico; flex: none; width: 30px; height: 30px; border-radius: 10px; display: inline-grid; place-items: center; background: rgba(var(--accent-rgb), .12); color: var(--accent); font-size: .95rem; }
++ .now__hl strong { grid-area: title; display: block; color: var(--fg); font-size: .98rem; line-height: 1.3; }
++ .now__hl span { grid-area: text; color: var(--muted); font-size: .9rem; line-height: 1.55; }
.now__cta { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
@media (max-width: 560px) { .now__cta { display: grid; grid-template-columns: 1fr 1fr; } .now__cta .btn { justify-content: center; padding: 12px 14px; } .now__pitch { padding: 20px; } }
.now__side { display: grid; gap: 18px; }
ddiff --git a/src/components/OpenVibeBento.astro b/src/components/OpenVibeBento.astro
iindex ef8bb92..95c2df4 100644
---- a/src/components/OpenVibeBento.astro
++++ b/src/components/OpenVibeBento.astro
@@@ -63,7 +63,7 @@ const edges = [
<div class="eyebrow"><i class="fa-solid fa-diagram-project" aria-hidden="true"></i> How it fits together</div>
<h3>One login, one wallet, seven products that feel like one.</h3>
<details class="arch__more" open>
-- <summary>Read more</summary>
++ <summary><span class="arch__more-closed">Read more</span><span class="arch__more-open">Show less</span></summary>
<p>Sign in once and every OpenVibe site knows who you are, what you own and what you look like. The identity service in the middle handles accounts, security and the shared virtual currency; every other product plugs into it through clear, documented APIs. That's the same playbook I bring to any company: secure single sign-on, payments and APIs designed so new products can be added without breaking the old ones.</p>
</details>
<ul class="arch__facts">
@@@ -200,6 +200,8 @@ const edges = [
.arch__more summary::after { content: "▾"; transition: transform .2s; }
.arch__more[open] summary::after { transform: rotate(180deg); }
.arch__more[open] summary { margin-bottom: 4px; }
++ .arch__more-open, .arch__more[open] .arch__more-closed { display: none; }
++ .arch__more[open] .arch__more-open { display: inline; }
}
</style>
ddiff --git a/src/components/ProjectGrid.astro b/src/components/ProjectGrid.astro
iindex 21c972a..6fef1bf 100644
---- a/src/components/ProjectGrid.astro
++++ b/src/components/ProjectGrid.astro
@@@ -99,9 +99,9 @@ const cats = Array.from(new Set(projects.map((p) => p.data.category)));
.pcard__deco-grid { position: absolute; inset: 0; background-image: linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px); background-size: 28px 28px; mask-image: radial-gradient(60% 60% at 50% 50%, #000, transparent); -webkit-mask-image: radial-gradient(60% 60% at 50% 50%, #000, transparent); }
.cat-powerchat .pcard__deco { background: linear-gradient(135deg, rgba(var(--accent-2-rgb), .22), rgba(139,92,246,.14)); }
.cat-ai .pcard__deco, .cat-amazon .pcard__deco { background: linear-gradient(135deg, rgba(var(--accent-3-rgb), .18), rgba(var(--accent-rgb), .14)); }
-- .pcard__body { position: relative; z-index: 1; padding: 20px 20px 18px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
++ .pcard__body { position: relative; z-index: 1; padding: 14px 16px 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.pcard__top { display: flex; align-items: center; gap: 10px; }
-- .pcard__icon { width: 34px; height: 34px; border-radius: 10px; display: inline-grid; place-items: center; background: rgba(var(--accent-rgb), .12); color: var(--accent); border: 1px solid rgba(var(--accent-rgb), .18); font-size: .85rem; }
++ .pcard__icon { width: 28px; height: 28px; border-radius: 10px; display: inline-grid; place-items: center; background: rgba(var(--accent-rgb), .12); color: var(--accent); border: 1px solid rgba(var(--accent-rgb), .18); font-size: .85rem; }
.cat-powerchat .pcard__icon { background: rgba(var(--accent-2-rgb), .12); color: var(--accent-2); border-color: rgba(var(--accent-2-rgb), .22); }
.cat-amazon .pcard__icon, .cat-ai .pcard__icon { background: rgba(var(--accent-3-rgb), .12); color: var(--accent-3); border-color: rgba(var(--accent-3-rgb), .22); }
.cat-infra .pcard__icon { background: rgba(139, 92, 246, .14); color: var(--violet); border-color: rgba(139, 92, 246, .25); }
@@@ -113,9 +113,9 @@ const cats = Array.from(new Set(projects.map((p) => p.data.category)));
.pcard__tech { list-style: none; margin: auto 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.pcard__tech li { font: 500 .68rem var(--font-mono); padding: 3px 8px; border-radius: 6px; background: var(--surface-2); color: var(--muted); border: 1px solid var(--border); }
.pcard__tech .more { color: var(--dim); }
-- .pcard__foot { display: flex; align-items: center; justify-content: space-between; padding-top: 6px; }
++ .pcard__foot { display: flex; align-items: center; justify-content: space-between; padding-top: 2px; }
.pcard__more { font: 600 .78rem var(--font-mono); color: var(--accent); }
-- .pcard__ext { position: relative; z-index: 3; width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; color: var(--muted); border: 1px solid var(--border); transition: all .25s; }
++ .pcard__ext { position: relative; z-index: 3; width: 28px; height: 28px; border-radius: 50%; display: inline-grid; place-items: center; color: var(--muted); border: 1px solid var(--border); transition: all .25s; }
.pcard__ext:hover { color: var(--fg); border-color: var(--accent); text-decoration: none; background: rgba(var(--accent-rgb), .12); }
@media (max-width: 1000px) { .pgrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .pgrid { grid-template-columns: 1fr; } }
ddiff --git a/src/components/WorkShowcase.astro b/src/components/WorkShowcase.astro
iindex c0fab56..59adc20 100644
---- a/src/components/WorkShowcase.astro
++++ b/src/components/WorkShowcase.astro
@@@ -83,7 +83,7 @@ const groups = [
</ul>
</div>
)}
-- <ul class="wk-grid" data-stagger hidden={g.items.length === 0}>
++ <ul class="wk-grid" data-stagger hidden={g.items.length === 0} style={`--cols:${Math.min(Math.max(g.items.length, 1), 4)};--cols-t:${Math.min(Math.max(g.items.length, 1), 2)}`}>
{g.items.map((it) => (
<li class={`wk-card ${it.image ? "wk-card--img" : ""} ${it.soon ? "wk-card--soon" : ""}`}>
<a href={it.href} class="wk-card__link" target={it.external ? "_blank" : undefined} rel={it.external ? "noopener" : undefined}>
@@@ -144,7 +144,9 @@ const groups = [
.wk-group__all:hover { text-decoration: none; background: rgba(var(--g-rgb), .16); border-color: rgba(var(--g-rgb), .6); transform: translateY(-1px); }
.wk-group__all:hover .wk-group__arrow { transform: translateX(3px); }
-- .wk-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
++ /* As many columns as cards, up to four (two on tablets), so a group never ends on a lone card. */
++ .wk-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--cols, 4), 1fr); gap: 10px; }
++ @media (max-width: 1100px) { .wk-grid { grid-template-columns: repeat(var(--cols-t, 2), 1fr); } }
.wk-card { min-width: 0; }
.wk-card__link { display: flex; flex-direction: column; height: 100%; border-radius: 16px; overflow: hidden; background: var(--surface); border: 1px solid var(--border); color: var(--fg); text-decoration: none; transition: transform .4s var(--ease), border-color .3s var(--ease), box-shadow .4s var(--ease), background .3s var(--ease); }
.wk-card__link:hover { text-decoration: none; transform: translateY(-3px); border-color: rgba(var(--g-rgb), .5); background: var(--surface-2); box-shadow: var(--shadow-card), 0 0 0 1px rgba(var(--g-rgb), .12), 0 16px 40px -22px rgba(var(--g-rgb), .7); }
ddiff --git a/src/pages/resume.astro b/src/pages/resume.astro
iindex bddbb10..66d8806 100644
---- a/src/pages/resume.astro
++++ b/src/pages/resume.astro
@@@ -126,6 +126,8 @@ const pitchParts = linkify(profile.pitch, LINK_TERMS);
border-radius: 16px; border: 1px dashed var(--border-strong); background: var(--surface);
}
.themed-pdf-swatches[hidden] { display: none; }
++ /* Phones: twelve swatches as two even rows of six instead of seven and five. */
++ @media (max-width: 560px) { .themed-pdf-swatches:not([hidden]) { display: grid; grid-template-columns: repeat(6, 1fr); justify-items: center; } }
.themed-pdf-swatch {
width: 34px; height: 34px; border-radius: 50%; background: var(--sw);
border: 2px solid transparent; box-shadow: inset 0 0 0 1px rgba(0,0,0,.1);