fixes and major changes
This commit is contained in:
+10
-10
@@ -5,23 +5,23 @@ export type Area = {
|
|||||||
|
|
||||||
export const practice: Area[] = [
|
export const practice: Area[] = [
|
||||||
{
|
{
|
||||||
title: 'Networking & Systems Administration',
|
title: 'Network and systems administration',
|
||||||
body: 'Design and maintain business network infrastructure. Administer mail servers, web servers, and databases. Implement security and monitoring.',
|
body: 'Design and maintain business networks, Linux servers, mail systems, web servers, and databases. Configure monitoring, backups, and access controls.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Desktop Support & Technical Services',
|
title: 'IT support and endpoint management',
|
||||||
body: 'End-user support across Windows, Mac, and Linux. Hardware and software troubleshooting, system imaging and deployment, IT asset management.',
|
body: 'Support Windows, macOS, and Linux endpoints. Diagnose hardware and software problems, deploy system images, and maintain device inventories.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Programming & Automation Engineering',
|
title: 'Software development and automation',
|
||||||
body: 'Automation through scripting and open-source development. Custom tools for operational workflows, CI/CD pipelines, and system monitoring.',
|
body: 'Write scripts and internal tools for operational workflows, CI/CD pipelines, infrastructure management, and system monitoring.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Web Development & Frontend Engineering',
|
title: 'Web application development',
|
||||||
body: 'Web applications with Svelte and Tailwind. Responsive, accessible interfaces for internal tools and client work.',
|
body: 'Build responsive, accessible web applications and internal tools with TypeScript, Svelte, and Tailwind CSS.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Creative Production & Media Services',
|
title: 'Media systems and production',
|
||||||
body: 'Video production, live audio-visual systems, and digital content for broadcast and clients.',
|
body: 'Operate live audiovisual systems and produce video and digital content for broadcast and client work.',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
export type Project = {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const projects: Project[] = [
|
||||||
|
{
|
||||||
|
name: "FOSSbench",
|
||||||
|
url: "https://fossbench.net",
|
||||||
|
type: "Platform",
|
||||||
|
description: "An open CPU benchmarking platform for submitting, searching, and comparing results across processors, operating systems, and compilers.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wayviewer",
|
||||||
|
url: "https://github.com/owenrummage/wayviewer",
|
||||||
|
type: "Open source",
|
||||||
|
description: "A lightweight VNC viewer for Wayland, written in C++ with SDL2 and libvncclient. Includes command-line options and a graphical connection launcher.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ipinfo",
|
||||||
|
url: "https://github.com/owenrummage/ipinfo",
|
||||||
|
type: "Open source",
|
||||||
|
description: "A Go command-line application for looking up and displaying IP address information.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wii-Linux",
|
||||||
|
url: "https://wii-linux.org",
|
||||||
|
type: "Infrastructure",
|
||||||
|
description: "Provide hosted compute and infrastructure sponsorship through NixLabs for the modern Wii-Linux project, with occasional contributions to project work.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const websites: Project[] = [
|
||||||
|
{
|
||||||
|
name: "NixLabs Networks",
|
||||||
|
url: "https://nixlabs.dev",
|
||||||
|
type: "Website",
|
||||||
|
description: "Designed and built the company website for NixLabs Networks, covering its managed IT, helpdesk, hosting, and infrastructure services.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Simple Logic IT Solutions",
|
||||||
|
url: "https://simplelogic.net",
|
||||||
|
type: "Website",
|
||||||
|
description: "Designed and built the service website for Simple Logic IT Solutions, including its managed IT, on-site support, service areas, and client portal access.",
|
||||||
|
},
|
||||||
|
];
|
||||||
+46
-14
@@ -1,15 +1,47 @@
|
|||||||
export const tools: string[] = [
|
export type Skill = {
|
||||||
'Linux',
|
name: string;
|
||||||
'macOS',
|
proficiency: "Advanced" | "Proficient" | "Working knowledge" | "Familiar";
|
||||||
'Windows',
|
};
|
||||||
'Python',
|
|
||||||
'TypeScript',
|
export const tools: Skill[] = [
|
||||||
'Svelte',
|
{ name: "Linux", proficiency: "Advanced" },
|
||||||
'TailwindCSS',
|
{ name: "Windows", proficiency: "Proficient" },
|
||||||
'Docker',
|
{ name: "macOS", proficiency: "Proficient" },
|
||||||
'Git',
|
{ name: "Bash", proficiency: "Working knowledge" },
|
||||||
'GitHub',
|
{ name: "Python", proficiency: "Proficient" },
|
||||||
'nginx',
|
{ name: "TypeScript", proficiency: "Proficient" },
|
||||||
'Azure',
|
{ name: "Svelte", proficiency: "Proficient" },
|
||||||
'GoogleWorkspace',
|
{ name: "Tailwind CSS", proficiency: "Working knowledge" },
|
||||||
|
{ name: "NGINX", proficiency: "Proficient" },
|
||||||
|
{ name: "Cisco", proficiency: "Proficient" },
|
||||||
|
{ name: "Ubiquiti", proficiency: "Proficient" },
|
||||||
|
{ name: "Juniper", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Aruba", proficiency: "Familiar" },
|
||||||
|
{ name: "MikroTik", proficiency: "Familiar" },
|
||||||
|
{ name: "BGP", proficiency: "Working knowledge" },
|
||||||
|
{ name: "OSPF", proficiency: "Working knowledge" },
|
||||||
|
{ name: "VLANs", proficiency: "Proficient" },
|
||||||
|
{ name: "VPNs", proficiency: "Proficient" },
|
||||||
|
{ name: "DNS", proficiency: "Proficient" },
|
||||||
|
{ name: "DHCP", proficiency: "Proficient" },
|
||||||
|
{ name: "Proxmox", proficiency: "Proficient" },
|
||||||
|
{ name: "VMware", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Hyper-V", proficiency: "Familiar" },
|
||||||
|
{ name: "KVM", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Docker", proficiency: "Proficient" },
|
||||||
|
{ name: "Kubernetes", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Cloudflare", proficiency: "Proficient" },
|
||||||
|
{ name: "Azure", proficiency: "Working knowledge" },
|
||||||
|
{ name: "AWS", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Ansible", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Terraform", proficiency: "Working knowledge" },
|
||||||
|
{ name: "GitHub Actions", proficiency: "Proficient" },
|
||||||
|
{ name: "Git", proficiency: "Working knowledge" },
|
||||||
|
{ name: "GitHub", proficiency: "Advanced" },
|
||||||
|
{ name: "Grafana", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Prometheus", proficiency: "Working knowledge" },
|
||||||
|
{ name: "Zabbix", proficiency: "Working knowledge" },
|
||||||
|
{ name: "pfSense", proficiency: "Proficient" },
|
||||||
|
{ name: "OPNsense", proficiency: "Proficient" },
|
||||||
|
{ name: "Google Workspace", proficiency: "Proficient" },
|
||||||
];
|
];
|
||||||
|
|||||||
+6
-6
@@ -11,36 +11,36 @@ export const work: Role[] = [
|
|||||||
title: "Owner & Operator",
|
title: "Owner & Operator",
|
||||||
company: "NixLabs Networks",
|
company: "NixLabs Networks",
|
||||||
years: "2021 - 2024",
|
years: "2021 - 2024",
|
||||||
description: "Designed, deployed, and maintained secure network infrastructure, hosting platforms, and Linux-based systems for clients. Automated infrastructure management and operational workflows using Bash, Python, and open-source technologies. Provided technical support, troubleshooting, and systems administration for production server environments.",
|
description: "Designed and maintained client network infrastructure, hosting platforms, and Linux systems. Wrote Bash and Python automation for routine infrastructure work, and supported production servers through monitoring, troubleshooting, and system administration.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Technical Specialist",
|
title: "Technical Specialist",
|
||||||
company: "Computer House · Part-time",
|
company: "Computer House · Part-time",
|
||||||
years: "Jun - Aug 2023",
|
years: "Jun - Aug 2023",
|
||||||
description: "Diagnosed and repaired customer computers, including hardware failures and software issues. Set up enterprise networks and servers for contract clients, while also handling storefront sales, customer service, and daily shop operations.",
|
description: "Diagnosed and repaired customer computers with hardware and software problems. Configured networks and servers for contract clients, handled storefront sales, and managed daily shop operations.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "IT Support Intern",
|
title: "IT Support Intern",
|
||||||
company: "Metro Nashville Public Schools · Internship",
|
company: "Metro Nashville Public Schools · Internship",
|
||||||
years: "Jan - Jul 2023",
|
years: "Jan - Jul 2023",
|
||||||
description: "Deployed and configured Windows computers using Windows Deployment Services (WDS). Diagnosed hardware and software problems for staff and students across district facilities, tracked devices, and prepared equipment for technology rollouts.",
|
description: "Deployed Windows computers with Windows Deployment Services (WDS). Resolved hardware and software problems for staff and students, tracked district devices, and prepared equipment for technology rollouts.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "System Architect",
|
title: "System Architect",
|
||||||
company: "Fyra Labs · Part-time",
|
company: "Fyra Labs · Part-time",
|
||||||
years: "Mar - Oct 2022",
|
years: "Mar - Oct 2022",
|
||||||
description: "Designed and maintained the systems architecture behind the company's hosted services. Configured Cloudflare for DNS, traffic routing, and application security, and set up load balancing to keep services available during demand spikes.",
|
description: "Designed and maintained infrastructure for hosted services. Configured Cloudflare for DNS, traffic routing, and application security, then implemented load balancing to distribute traffic across services.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Technical Specialist",
|
title: "Technical Specialist",
|
||||||
company: "Computer House Inc · Seasonal",
|
company: "Computer House Inc · Seasonal",
|
||||||
years: "Jun - Aug 2022",
|
years: "Jun - Aug 2022",
|
||||||
description: "Troubleshot and repaired desktops, laptops, and other computer hardware. Helped customers choose systems, replacement parts, and upgrades, prepared new computers for sale, and supported daily storefront operations.",
|
description: "Troubleshot and repaired desktops, laptops, and related hardware. Recommended systems, replacement parts, and upgrades to customers, prepared new computers for sale, and supported storefront operations.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Software Engineer",
|
title: "Software Engineer",
|
||||||
company: "Innatical · Part-time",
|
company: "Innatical · Part-time",
|
||||||
years: "Apr - Oct 2021",
|
years: "Apr - Oct 2021",
|
||||||
description: "Built and maintained back-end services in TypeScript, including APIs and server-side application features. Diagnosed bugs, reviewed changes, and tested releases with a remote development team.",
|
description: "Built and maintained TypeScript back-end services, APIs, and server-side application features. Diagnosed bugs, reviewed code changes, and tested releases with a remote development team.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
+75
-36
@@ -3,9 +3,10 @@ import Layout from "../layouts/Layout.astro";
|
|||||||
import { work } from "../data/work";
|
import { work } from "../data/work";
|
||||||
import { practice } from "../data/practice";
|
import { practice } from "../data/practice";
|
||||||
import { tools } from "../data/tools";
|
import { tools } from "../data/tools";
|
||||||
|
import { projects, websites } from "../data/projects";
|
||||||
|
|
||||||
const description =
|
const description =
|
||||||
"Systems engineer and founder building open, scalable infrastructure, cloud platforms, and networks that prioritize simplicity over complexity.";
|
"Systems engineer specializing in Linux infrastructure, network engineering, cloud platforms, and automation.";
|
||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -22,9 +23,9 @@ const description =
|
|||||||
</button>
|
</button>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="hero__statement">
|
<p class="hero__statement">
|
||||||
Systems engineer and founder building open, scalable
|
Systems engineer specializing in Linux infrastructure, network
|
||||||
infrastructure, cloud platforms, and networks that prioritize
|
engineering, cloud platforms, and automation. Based in
|
||||||
simplicity over complexity.
|
Nashville, Tennessee.
|
||||||
</p>
|
</p>
|
||||||
<p class="hero__contact">
|
<p class="hero__contact">
|
||||||
<a class="link" href="mailto:hello@rummage.cc"
|
<a class="link" href="mailto:hello@rummage.cc"
|
||||||
@@ -47,7 +48,8 @@ const description =
|
|||||||
|
|
||||||
<hr class="rule" />
|
<hr class="rule" />
|
||||||
|
|
||||||
<section class="work" aria-label="Work history">
|
<section class="work" aria-labelledby="experience-heading">
|
||||||
|
<h2 class="section-heading" id="experience-heading">Experience</h2>
|
||||||
{
|
{
|
||||||
work.map((role) => (
|
work.map((role) => (
|
||||||
<article
|
<article
|
||||||
@@ -62,19 +64,11 @@ const description =
|
|||||||
aria-pressed="false"
|
aria-pressed="false"
|
||||||
data-role-pin
|
data-role-pin
|
||||||
>
|
>
|
||||||
{role.current ? (
|
<span class="role__years">{role.years}</span>
|
||||||
<span class="role__live">
|
|
||||||
<span>{role.years}</span>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span class="role__years">
|
|
||||||
{role.years}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="role__body">
|
<div class="role__body">
|
||||||
<h2 class="role__title">{role.title}</h2>
|
<h3 class="role__title">{role.title}</h3>
|
||||||
<p class="role__company">{role.company}</p>
|
<p class="role__company">{role.company}</p>
|
||||||
<p class="role__description">{role.description}</p>
|
<p class="role__description">{role.description}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,16 +79,17 @@ const description =
|
|||||||
|
|
||||||
<hr class="rule" />
|
<hr class="rule" />
|
||||||
|
|
||||||
<section class="education" aria-label="Education">
|
<section class="education" aria-labelledby="education-heading">
|
||||||
|
<h2 class="section-heading" id="education-heading">Education</h2>
|
||||||
<article class="role">
|
<article class="role">
|
||||||
<div class="role__meta">
|
<div class="role__meta">
|
||||||
<span class="role__years">2023–2026</span>
|
<span class="role__years">2023 - 2026</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="role__body">
|
<div class="role__body">
|
||||||
<h2 class="role__title">
|
<h3 class="role__title">
|
||||||
Associate of Applied Science in Computer Information
|
Associate of Applied Science in Computer Information
|
||||||
Technology
|
Technology
|
||||||
</h2>
|
</h3>
|
||||||
<p class="role__company">
|
<p class="role__company">
|
||||||
Nashville State Community College
|
Nashville State Community College
|
||||||
</p>
|
</p>
|
||||||
@@ -108,17 +103,46 @@ const description =
|
|||||||
|
|
||||||
<hr class="rule" />
|
<hr class="rule" />
|
||||||
|
|
||||||
<section class="practice" aria-label="Areas of practice">
|
<section class="projects" aria-labelledby="projects-heading">
|
||||||
|
<h2 class="section-heading" id="projects-heading">Projects</h2>
|
||||||
|
<div class="project-list">
|
||||||
{
|
{
|
||||||
practice.map((area, i) => (
|
[...projects, ...websites].map((project) => (
|
||||||
<article class="area">
|
<article class="project">
|
||||||
<div class="area__meta">
|
<div class="project__meta">{project.type}</div>
|
||||||
{i === 0 && (
|
<div class="project__body">
|
||||||
<span class="area__label">practice</span>
|
<h3 class="project__title">
|
||||||
)}
|
<a
|
||||||
|
class="link link--ink"
|
||||||
|
href={project.url}
|
||||||
|
rel="noopener"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{project.name}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<p class="project__description">
|
||||||
|
{project.description}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</article>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr class="rule" />
|
||||||
|
|
||||||
|
<section class="practice" aria-labelledby="competencies-heading">
|
||||||
|
<h2 class="section-heading" id="competencies-heading">
|
||||||
|
Core competencies
|
||||||
|
</h2>
|
||||||
|
{
|
||||||
|
practice.map((area) => (
|
||||||
|
<article class="area">
|
||||||
|
<div class="area__meta" aria-hidden="true" />
|
||||||
<div class="area__body">
|
<div class="area__body">
|
||||||
<h2 class="area__title">{area.title}</h2>
|
<h3 class="area__title">{area.title}</h3>
|
||||||
<p class="area__desc">{area.body}</p>
|
<p class="area__desc">{area.body}</p>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -126,31 +150,46 @@ const description =
|
|||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="toolset" aria-label="Tools">
|
<section class="skills" aria-labelledby="skills-heading">
|
||||||
<div class="toolset__meta">
|
<h2 class="section-heading" id="skills-heading">
|
||||||
<span class="toolset__label">tools</span>
|
Technical skills
|
||||||
</div>
|
</h2>
|
||||||
|
<div class="toolset">
|
||||||
|
<div class="toolset__meta" aria-hidden="true"></div>
|
||||||
<ul class="toolset__list">
|
<ul class="toolset__list">
|
||||||
{tools.map((t) => <li>{t}</li>)}
|
{
|
||||||
|
tools.map((skill) => (
|
||||||
|
<li
|
||||||
|
data-skill={skill.name}
|
||||||
|
data-proficiency={skill.proficiency}
|
||||||
|
tabindex="0"
|
||||||
|
aria-label={`${skill.name}: ${skill.proficiency}`}
|
||||||
|
>
|
||||||
|
<span>{skill.name}</span>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<aside class="motto" aria-label="Closing note">
|
<aside class="motto" aria-label="Closing note">
|
||||||
<div class="motto__meta" aria-hidden="true">motto</div>
|
<div class="motto__meta" aria-hidden="true">approach</div>
|
||||||
<button
|
<button
|
||||||
class="motto__text"
|
class="motto__text"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Show another motto"
|
aria-label="Show another professional principle"
|
||||||
data-motto-play
|
data-motto-play
|
||||||
>
|
>
|
||||||
I can explain BGP, but neither of us will enjoy it.
|
I build systems that can be understood and maintained by
|
||||||
|
someone other than me.
|
||||||
</button>
|
</button>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<hr class="rule" />
|
<hr class="rule" />
|
||||||
|
|
||||||
<footer class="foot">
|
<footer class="foot">
|
||||||
<span class="foot__build">build 0.1 / Nashville</span>
|
<span class="foot__build">Nashville, Tennessee</span>
|
||||||
<button
|
<button
|
||||||
class="foot__home"
|
class="foot__home"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
const mottos = [
|
const mottos = [
|
||||||
"I can explain BGP, but neither of us will enjoy it.",
|
"I build systems that can be understood and maintained by someone other than me.",
|
||||||
"It was DNS. Everyone take a drink.",
|
"Reliable infrastructure starts with clear ownership and clear documentation.",
|
||||||
"The server is not haunted. I checked twice.",
|
"Automation should reduce routine work without hiding how the system operates.",
|
||||||
"My favorite alert is the one that fixes itself before I get up.",
|
"Fix the cause, document the change, and leave the system easier to support.",
|
||||||
];
|
];
|
||||||
|
|
||||||
const glyphs = "01#@$%&*+<>/\\";
|
const glyphs = "01#@$%&*+<>/\\";
|
||||||
@@ -84,8 +84,9 @@ function celebrate(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initSecrets(): void {
|
function initSecrets(): void {
|
||||||
const home = document.querySelector<HTMLButtonElement>("[data-home-play]");
|
document
|
||||||
home?.addEventListener("click", celebrate);
|
.querySelector<HTMLButtonElement>("[data-home-play]")
|
||||||
|
?.addEventListener("click", celebrate);
|
||||||
|
|
||||||
const sequence = [
|
const sequence = [
|
||||||
"ArrowUp",
|
"ArrowUp",
|
||||||
@@ -101,7 +102,10 @@ function initSecrets(): void {
|
|||||||
];
|
];
|
||||||
let position = 0;
|
let position = 0;
|
||||||
window.addEventListener("keydown", (event) => {
|
window.addEventListener("keydown", (event) => {
|
||||||
position = event.key.toLowerCase() === sequence[position]?.toLowerCase() ? position + 1 : 0;
|
position =
|
||||||
|
event.key.toLowerCase() === sequence[position]?.toLowerCase()
|
||||||
|
? position + 1
|
||||||
|
: 0;
|
||||||
if (position === sequence.length) {
|
if (position === sequence.length) {
|
||||||
celebrate();
|
celebrate();
|
||||||
position = 0;
|
position = 0;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const SCALE_ACTIVE = 1.06;
|
|||||||
type ChipMap = Map<HTMLLIElement, DOMRect>;
|
type ChipMap = Map<HTMLLIElement, DOMRect>;
|
||||||
|
|
||||||
function tokenOf(el: Element): string {
|
function tokenOf(el: Element): string {
|
||||||
return (el.textContent || '').trim();
|
return (el as HTMLElement).dataset.skill || (el.textContent || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function readReducedMotion(): boolean {
|
function readReducedMotion(): boolean {
|
||||||
|
|||||||
+106
-2
@@ -320,6 +320,25 @@ button {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* Section hierarchy
|
||||||
|
* ============================================================ */
|
||||||
|
.section-heading {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: clamp(1.375rem, 1.2rem + 0.6vw, 1.625rem);
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: var(--leading-tight);
|
||||||
|
letter-spacing: var(--tracking-tight);
|
||||||
|
color: var(--color-ink);
|
||||||
|
font-variation-settings: "wght" 540;
|
||||||
|
margin-bottom: clamp(0.75rem, 2vw, 1.25rem);
|
||||||
|
}
|
||||||
|
.section-heading + .role,
|
||||||
|
.section-heading + .area,
|
||||||
|
.section-heading + .toolset {
|
||||||
|
padding-top: clamp(0.75rem, 1.5vw, 1.25rem);
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Work index (marginalia grid)
|
* Work index (marginalia grid)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
@@ -429,6 +448,50 @@ button {
|
|||||||
color: var(--color-ink);
|
color: var(--color-ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* Selected projects
|
||||||
|
* ============================================================ */
|
||||||
|
.project-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.project {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: var(--col-meta) 1fr;
|
||||||
|
gap: var(--gap-meta);
|
||||||
|
padding-block: clamp(1.5rem, 3vw, 2.25rem);
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.project + .project {
|
||||||
|
border-top-color: var(--color-rule);
|
||||||
|
}
|
||||||
|
.project__meta {
|
||||||
|
padding-top: 0.35rem;
|
||||||
|
color: var(--color-muted);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--fs-meta);
|
||||||
|
letter-spacing: var(--tracking-mono);
|
||||||
|
}
|
||||||
|
.project__body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
max-width: 64ch;
|
||||||
|
}
|
||||||
|
.project__title {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: var(--fs-role-title);
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: var(--leading-tight);
|
||||||
|
letter-spacing: var(--tracking-tight);
|
||||||
|
font-variation-settings: "wght" 520;
|
||||||
|
}
|
||||||
|
.project__description {
|
||||||
|
color: var(--color-ink-soft);
|
||||||
|
font-size: var(--fs-body);
|
||||||
|
line-height: var(--leading-body);
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Practice (areas of competence — marginalia grid)
|
* Practice (areas of competence — marginalia grid)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
@@ -490,6 +553,9 @@ button {
|
|||||||
padding-block: clamp(1.75rem, 3.5vw, 2.5rem);
|
padding-block: clamp(1.75rem, 3.5vw, 2.5rem);
|
||||||
border-top: 1px solid var(--color-rule);
|
border-top: 1px solid var(--color-rule);
|
||||||
}
|
}
|
||||||
|
.skills {
|
||||||
|
margin-top: clamp(2.75rem, 5.5vw, 4rem);
|
||||||
|
}
|
||||||
.toolset__meta {
|
.toolset__meta {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: var(--fs-meta);
|
font-size: var(--fs-meta);
|
||||||
@@ -547,6 +613,9 @@ button {
|
|||||||
.toolset__list li.is-dragging::before {
|
.toolset__list li.is-dragging::before {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
.toolset__list li.is-dragging::after {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
/* Suppress hover styles on other chips while a drag is in flight, so
|
/* Suppress hover styles on other chips while a drag is in flight, so
|
||||||
* they don't flash as the dragged chip sweeps over them. */
|
* they don't flash as the dragged chip sweeps over them. */
|
||||||
.toolset__list.is-dragging-list li:not(.is-dragging):hover {
|
.toolset__list.is-dragging-list li:not(.is-dragging):hover {
|
||||||
@@ -572,15 +641,49 @@ body.is-toolset-dragging * {
|
|||||||
color var(--dur-fast) var(--ease-out-quint),
|
color var(--dur-fast) var(--ease-out-quint),
|
||||||
transform var(--dur-base) var(--ease-out-quint);
|
transform var(--dur-base) var(--ease-out-quint);
|
||||||
}
|
}
|
||||||
.toolset__list li:hover {
|
.toolset__list li::after {
|
||||||
|
content: attr(data-proficiency);
|
||||||
|
position: absolute;
|
||||||
|
z-index: var(--z-focus);
|
||||||
|
left: 50%;
|
||||||
|
bottom: calc(100% + 0.55rem);
|
||||||
|
translate: -50% 0.25rem;
|
||||||
|
width: max-content;
|
||||||
|
max-width: 12rem;
|
||||||
|
padding: 0.4rem 0.55rem;
|
||||||
|
border: 1px solid var(--color-rule-strong);
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--color-surface-rise);
|
||||||
|
color: var(--color-ink);
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: var(--fs-tiny);
|
||||||
|
line-height: 1.25;
|
||||||
|
letter-spacing: 0;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
transition:
|
||||||
|
opacity var(--dur-fast) var(--ease-out-quint),
|
||||||
|
translate var(--dur-fast) var(--ease-out-quint),
|
||||||
|
visibility var(--dur-fast) var(--ease-out-quint);
|
||||||
|
}
|
||||||
|
.toolset__list li:hover,
|
||||||
|
.toolset__list li:focus-visible {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
background-color: var(--color-accent-wash);
|
background-color: var(--color-accent-wash);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
.toolset__list li:hover::before {
|
.toolset__list li:hover::before,
|
||||||
|
.toolset__list li:focus-visible::before {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
transform: rotate(-14deg) translate(-1px, -1px);
|
transform: rotate(-14deg) translate(-1px, -1px);
|
||||||
}
|
}
|
||||||
|
.toolset__list li:hover::after,
|
||||||
|
.toolset__list li:focus-visible::after {
|
||||||
|
translate: -50% 0;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Motto (closing reflection — marginalia grid)
|
* Motto (closing reflection — marginalia grid)
|
||||||
@@ -730,6 +833,7 @@ body.is-toolset-dragging * {
|
|||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.role,
|
.role,
|
||||||
.area,
|
.area,
|
||||||
|
.project,
|
||||||
.toolset,
|
.toolset,
|
||||||
.motto {
|
.motto {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
Reference in New Issue
Block a user