mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* global.css
|
||||
* ---------------------------------------------------------------------------
|
||||
* Tailwind v4 entry + global base layer for Greg Kilmer's profile site.
|
||||
*
|
||||
* Tailwind v4 uses a CSS-first config. The `@import "tailwindcss"` pulls in the
|
||||
* engine and the `@theme` block below exposes the project palette as utility
|
||||
* classes (e.g. `bg-surface`, `text-accent`). Section/light-dark tokens live in
|
||||
* themes.css and are referenced here via CSS variables.
|
||||
*
|
||||
* Import order matters: theme tokens first (so @theme can reference them), then
|
||||
* Tailwind, then animations, then base.
|
||||
*/
|
||||
|
||||
/* Palette + light/dark + section surface tokens (CSS variables). */
|
||||
@import "./themes.css";
|
||||
/* Keyframes (gradient shift, fade-up, blur, float). */
|
||||
@import "./animations.css";
|
||||
|
||||
/* Tailwind engine. In v4 this is a single import. */
|
||||
@import "tailwindcss";
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Theme bridge: expose CSS variables from themes.css to Tailwind utilities.
|
||||
* Each entry below generates a utility family, e.g. `--color-surface` -> the
|
||||
* `bg-surface` / `text-surface` / `border-surface` classes.
|
||||
* The values point at the CSS variables so that changing `data-theme` or the
|
||||
* section wrapper (`data-surface`) instantly restyles every component.
|
||||
* ------------------------------------------------------------------------- */
|
||||
@theme {
|
||||
/* Brand colors (fixed, do not change with theme). Night-sky mystical set:
|
||||
* star gold, mystic violet, nebula teal, midnight indigo, star-white. */
|
||||
--color-amber: #e8b54a; /* star gold */
|
||||
--color-amber-soft: #f4cd72; /* brighter gold for hovers */
|
||||
--color-violet: #8b7bd8; /* mystic violet */
|
||||
--color-violet-deep: #6f5fb6;
|
||||
--color-teal: #6fb6ad; /* nebula teal */
|
||||
--color-teal-deep: #4f8c84;
|
||||
--color-slate: #161b3a; /* deep indigo-slate */
|
||||
--color-ink: #0b1026; /* midnight indigo */
|
||||
--color-cream: #f4f1e8; /* star-white */
|
||||
|
||||
/* Semantic tokens (resolve per theme/section via variables). */
|
||||
--color-surface: var(--surface);
|
||||
--color-surface-raised: var(--surface-raised);
|
||||
--color-surface-sunken: var(--surface-sunken);
|
||||
--color-text: var(--text);
|
||||
--color-text-muted: var(--text-muted);
|
||||
--color-text-subtle: var(--text-subtle);
|
||||
--color-border: var(--border);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-contrast: var(--accent-contrast);
|
||||
--color-secondary: var(--secondary);
|
||||
|
||||
/* Typography. */
|
||||
--font-sans: "Plus Jakarta Sans Variable", "Inter Variable", ui-sans-serif,
|
||||
system-ui, sans-serif;
|
||||
--font-body: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: "JetBrains Mono Variable", ui-monospace, "SFMono-Regular", monospace;
|
||||
|
||||
/* Motion tokens (used across reveal + transition classes). */
|
||||
--ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
--ease-in-out-soft: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Base layer: resets, defaults, focus styles.
|
||||
* ------------------------------------------------------------------------- */
|
||||
@layer base {
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
/* Offset so anchor jumps clear the fixed nav. */
|
||||
scroll-padding-top: 6rem;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* Honor reduced motion globally. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.001ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-body);
|
||||
line-height: 1.65;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
/* Strong typographic rhythm for headings. */
|
||||
h1 {
|
||||
font-size: clamp(2.25rem, 5vw + 1rem, 4rem);
|
||||
}
|
||||
h2 {
|
||||
font-size: clamp(1.75rem, 2.5vw + 1rem, 2.5rem);
|
||||
}
|
||||
h3 {
|
||||
font-size: clamp(1.25rem, 1vw + 1rem, 1.5rem);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s var(--ease-out-soft);
|
||||
}
|
||||
a:hover {
|
||||
color: var(--color-amber-soft);
|
||||
}
|
||||
|
||||
/* Visible, on-brand focus ring for keyboard users. */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--color-accent);
|
||||
outline-offset: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--color-amber);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
/* Better default for images: never overflow, lazy by default in components. */
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Component-ish utilities used across the site. Keeping them here (rather than
|
||||
* as repeated Tailwind class strings) makes tone adjustments easy.
|
||||
* ------------------------------------------------------------------------- */
|
||||
@layer components {
|
||||
/* Content width container. */
|
||||
.container-prose {
|
||||
width: 100%;
|
||||
max-width: 72rem;
|
||||
margin-inline: auto;
|
||||
padding-inline: 1.25rem;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.container-prose {
|
||||
padding-inline: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* The recurring "card" surface. */
|
||||
.card {
|
||||
background-color: var(--color-surface-raised);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 1rem;
|
||||
padding: 1.5rem;
|
||||
transition:
|
||||
transform 0.3s var(--ease-out-soft),
|
||||
box-shadow 0.3s var(--ease-out-soft),
|
||||
border-color 0.3s var(--ease-out-soft);
|
||||
}
|
||||
.card-interactive:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 18px 40px -24px rgba(11, 16, 38, 0.55);
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Pill / tag. */
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.25rem 0.7rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
background: color-mix(in srgb, var(--color-accent) 15%, transparent);
|
||||
color: var(--color-text);
|
||||
border: 1px solid color-mix(in srgb, var(--color-accent) 35%, transparent);
|
||||
}
|
||||
|
||||
/* Primary (amber) and secondary (outlined) CTA buttons. */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.6rem;
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
transform 0.2s var(--ease-out-soft),
|
||||
box-shadow 0.2s var(--ease-out-soft),
|
||||
background-color 0.2s var(--ease-out-soft),
|
||||
border-color 0.2s var(--ease-out-soft);
|
||||
}
|
||||
.btn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
.btn-primary {
|
||||
background: var(--color-amber);
|
||||
color: var(--color-ink);
|
||||
box-shadow: 0 10px 30px -12px rgba(245, 158, 11, 0.7);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--color-amber-soft);
|
||||
color: var(--color-ink);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
border: 1.5px solid var(--color-border);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-text);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Visually hidden but available to screen readers. */
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Reveal-on-scroll utility. The Reveal.astro component toggles `.is-visible`.
|
||||
*
|
||||
* The `.no-js` guard below is critical: <html> starts with class="no-js"
|
||||
* (set in BaseLayout.astro) and reveal-init.ts removes it once it has wired up
|
||||
* the observer. If JS is disabled OR the script fails to load, that class is
|
||||
* never removed — so this fallback forces reveals visible rather than leaving
|
||||
* the page blank. This is the safety net against the original invisibility bug.
|
||||
* ------------------------------------------------------------------------- */
|
||||
.no-js .reveal {
|
||||
opacity: 1 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.reveal {
|
||||
opacity: 0;
|
||||
transform: translateY(24px);
|
||||
transition:
|
||||
opacity 0.7s var(--ease-out-soft),
|
||||
transform 0.7s var(--ease-out-soft);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.reveal.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.reveal {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user