Merge branch 'feature/ui-components'
Some checks failed
Build and Deploy DAVE | DMGs Site / deploy (push) Failing after 1m28s

This commit is contained in:
2025-09-29 17:18:52 +02:00
58 changed files with 4884 additions and 1511 deletions

View File

@@ -0,0 +1,142 @@
{
"items": [
{
"name": "Metatron",
"path": "/meta",
"gridPosition": "area_1",
"variant": "meta",
"sublinks": {
"discriminant": false
},
"subtitle": {
"discriminant": false
}
},
{
"name": "Kitchensink",
"path": "/",
"gridPosition": "area_2",
"variant": "kitchensink",
"sublinks": {
"discriminant": true,
"value": [
{
"name": "The Pomarj",
"path": "/kitchensink/the-pomarj"
},
{
"name": "Burning Pavis",
"path": "/kitchensink/burning-pavis"
},
{
"name": "SLA Armies",
"path": "/kitchensink/sla-armies"
}
]
},
"subtitle": {
"discriminant": false
}
},
{
"name": "AWQ",
"path": "/awq",
"gridPosition": "area_3",
"variant": "awq",
"sublinks": {
"discriminant": true,
"value": [
{
"name": "The Crunch",
"path": "/awq/core-rules"
},
{
"name": "Sigmar's Heirs",
"path": "/awq/character"
},
{
"name": "Armory",
"path": "/awq/equipment"
},
{
"name": "The Winds of Magic",
"path": "/awq/magic"
},
{
"name": "Beastiary",
"path": "/awq/bestiary"
},
{
"name": "Duveldal",
"path": "/awq/pregens"
},
{
"name": "Plundered Vaults",
"path": "/awq/expansions"
},
{
"name": "Tools",
"path": "/awq/tools"
}
]
},
"subtitle": {
"discriminant": false
}
},
{
"name": "Worldburner",
"path": "/worldburner",
"gridPosition": "area_4",
"variant": "worldburner",
"sublinks": {
"discriminant": true,
"value": [
{
"name": "Burning Lands",
"path": "/worldburner/geography"
},
{
"name": "Burning People",
"path": "/worldburner/cultures"
},
{
"name": "Burning Faiths",
"path": "/worldburner/religion"
},
{
"name": "Burning Witches",
"path": "/worldburner/magic"
},
{
"name": "Burning Realms",
"path": "/worldburner/states"
}
]
},
"subtitle": {
"discriminant": false
}
},
{
"name": "Chainbreaker",
"path": "/chainbreaker",
"gridPosition": "area_5",
"variant": "chainbreaker",
"background": "/images/categories/items/4/background.png",
"sublinks": {
"discriminant": false
},
"subtitle": {
"discriminant": true,
"value": {
"content": "Spear & Animism",
"divider": {
"discriminant": true,
"value": "⎊"
}
}
}
}
]
}

View File

@@ -1,8 +1,11 @@
import { config } from '@keystatic/core';
import navigation from '@/keystatic/singletons/navigation';
export default config({
storage: {
kind: 'local',
},
collections: {},
singletons: { navigation },
});

View File

@@ -10,11 +10,11 @@ import postcssNesting from 'postcss-nesting';
import postcssPresetEnv from 'postcss-preset-env';
import postcssUtilities from 'postcss-utilities';
import postcssFunctions from 'postcss-functions';
import customFunctions from './src/postcss/functions';
import customFunctions from './src/lib/postcss/functions';
const plugins = [
postcssGlobalData({
files: ['./src/styles/variables/custom-media.css'],
files: ['./src/styles/globals/custom-media.css'],
}),
postcssMixins({
mixinsDir: './src/styles/mixins/',

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

@@ -1,5 +1,15 @@
import { MenuProvider } from '@/contexts/MenuContext';
import PageHeader from '@/components/Page/Header';
import PageMenu from '@/components/Page/Menu';
export default function SiteLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return <main>{children}</main>;
return (
<MenuProvider>
<PageHeader />
<PageMenu />
<main>{children}</main>
</MenuProvider>
);
}

View File

@@ -1,3 +1,82 @@
.content {
.wrapper {
@mixin responsive-wrapper;
& body {
margin: 0;
padding: 2rem;
font-family: monospace;
color: #1a1a1d;
background: #f7f9fb;
}
& h1 {
margin-bottom: 2rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.1em;
}
& .grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
}
& .demoCard {
border: 3px solid #1a1a1d;
background: white;
}
& .demoTitle {
margin: 0;
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: bold;
color: white;
text-transform: uppercase;
letter-spacing: 0.05em;
background: #1a1a1d;
}
& .imageContainer {
cursor: pointer;
position: relative;
overflow: hidden;
width: 100%;
height: 200px;
}
& .demoImage {
width: 100%;
height: 100%;
object-fit: cover;
filter: grayscale(100) contrast(150) brightness(100);
transition: none;
}
& .instructions {
margin-top: 2rem;
padding: 1rem;
font-family: monospace;
color: white;
background: #1a1a1d;
}
& .instructions h2 {
margin-top: 0;
text-transform: uppercase;
letter-spacing: 0.1em;
}
}

View File

@@ -2,531 +2,492 @@ import styles from './page.module.css';
export default function Home() {
return (
<div className={styles.content}>
<h1>Rods pursued studies dearer dangers Mellon spears lodgings.</h1>
<div className={styles.wrapper}>
<h1>
DAVE! DAVE! Do Not Let Us Die In The Dark Night Of This Cold Winter!
</h1>
<h2>Background / Image effects</h2>
<div className={styles.grid}>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Overexposure Blast</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-overexposure`}
src="https://images.pexels.com/photos/1096925/pexels-photo-1096925.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Contrast Slam</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-contrastslam`}
src="https://images.pexels.com/photos/119809/pexels-photo-119809.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Colorbleed</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-colorbleed`}
src="https://images.pexels.com/photos/12924931/pexels-photo-12924931.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Film Burn</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-filmburn`}
src="https://images.pexels.com/photos/1031357/pexels-photo-1031357.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Photocopier Malfunction</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-malfunction`}
src="https://images.pexels.com/photos/3054252/pexels-photo-3054252.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Toner Starvation</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-tonerstarvation`}
src="https://images.pexels.com/photos/3822728/pexels-photo-3822728.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Digital Corruption</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-corruption`}
src="https://images.pexels.com/photos/220793/pexels-photo-220793.jpeg"
alt="Demo"
/>
</div>
</div>
<div className={`${styles.demoCard}`}>
<h3 className={styles.demoTitle}>Stark Flash</h3>
<div className={styles.imageContainer}>
<img
className={`${styles.demoImage} anim-starkflash`}
src="https://images.pexels.com/photos/13744675/pexels-photo-13744675.jpeg"
alt="Demo"
/>
</div>
</div>
</div>
<div className={styles.instructions}>
<h2>Instructions</h2>
<p>
Language Sméagol where? Forest cesspits talked reclaim verse dungeon
Envenom 60 then venerable prolonging! There is only one Lord of the
Ring.
Hover over each image to see the effect. These are designed to work
with your base filter:
</p>
<h2>Breeding job clothing talks caught Freda trust.</h2>
<code>filter: grayscale(1) contrast(150%) brightness(120%)</code>
<p>
East dry because slinker deeper quarry knocks Sit. Treachery Front whim.
Even the smallest person can change the course of the future.
You can replace the demo images with your own by changing the src
attributes. All effects use stepped animations or sharp transitions to
maintain that industrial, non-digital feel.
</p>
<h3>Fence Toby reaction greed fired parting!</h3>
<p>
Do not take me for some conjurer of cheap tricks. Room aged Hobbitses!
Wall odds force simply shield hmm Tuckborough pearl privilege grows.
Ride amazing seeps lake guardian pretty Arwen retrieve stroke steps?
The effects range from subtle (Contrast Slam) to more dramatic
(Digital Corruption). Choose based on how aggressive you want the
interaction to feel.
</p>
</div>
<h2>Link Effects</h2>
<div className={styles.grid}>
{/* Your Ideas */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Strikethrough Mark (Marker)</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-strikethroughmarker">
strikethrough link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Strikethrough Mark (Industrial)</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-strikethroughindustrial">
strikethrough link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Marker Highlight [Industrial]</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-markerhighlightindustrial">
marker highlight link
</a>{' '}
in the middle of it.
</p>
</div>
{/* Stamping/Punching Effects */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Label Maker</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-labelmaker">
label maker link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Rubber Stamp</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-rubberstamp">
rubber stamp link
</a>{' '}
in the middle of it.
</p>
</div>
{/* Industrial/Mechanical */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Press/Stamp</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-pressstamp">
pressed link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Typewriter Underline</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-typewriter">
typewriter link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Hard Invert</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-hardInvert">
hard invert link
</a>{' '}
in the middle of it.
</p>
</div>
{/* Marking/Annotation */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Bracket Annotation</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-pointer">
bracket link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Corner Box</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-cornerbox">
corner box link
</a>{' '}
in the middle of it.
</p>
</div>
{/* Glitch/Digital */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Character Glitch</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-characterglitch">
glitch link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Pixel Shift</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-pixelshift">
shifting link
</a>{' '}
in the middle of it.
</p>
</div>
{/* Extra Ideas */}
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>Redacted/Censored</h3>
<p>
This is some text with a{' '}
<a href="#" className="anim-redacted">
redacted link
</a>{' '}
in the middle of it.
</p>
</div>
<div className={styles.demoCard}>
<h3 className={styles.demoTitle}>X-Ray/Negative</h3>
<p>
This is some text with an{' '}
<a href="#" className="anim-xray">
x-ray link
</a>{' '}
in the middle of it.
</p>
</div>
</div>
<div className="content">
<h1>
Successful Isildur's brink again throttle flank tightening splash.
</h1>
<p>
Help illusion embrace liquor tightening intelligence Maggot's whips
bit forests. 17 sing impassable helps Southrons beheading. What's the
Elvish word for 'friend'?
</p>
<h2>Give Hobbitses lend yours lads picking uniting sometime.</h2>
<p>
Inferno shaken skin undo wars close circles verse suck Dwarves. I gave
you the chance of aiding me willingly, but you have elected the way of
pain! Precautions tower tied Rivendell everyone agents wouldn't?
</p>
<h3>Doorway Mithrandir clearing wielder strengths floor?</h3>
<p>
Pillaged pointy-eared mix charm Grond confounded able-bodied tact
glimpse instruction open dear. Suffering powerful capable gulls
famousest stroke breathes Bilbo squeaked pace chances. Let the
Ring-bearer decide.
</p>
<ul>
<li>
Primary Equipment Loadout - Every adventurer must carry essential gear
including weapons, armor, survival tools, and emergency supplies that
could mean the difference between life and death in the depths of
forgotten dungeons and abandoned ruins.
</li>
<li>
Weapon Categories and Combat Applications
<ul>
<li>
Melee Weapons - Close combat instruments ranging from simple clubs
and daggers to sophisticated swords and war hammers, each designed
for specific tactical situations and requiring different skill
sets to master effectively.
</li>
<li>
Ranged Weapons and Projectile Systems
<ul>
<li>
Bows and Crossbows - Traditional projectile weapons that rely
on mechanical tension to launch arrows and bolts with deadly
accuracy across considerable distances, favored by hunters and
scouts.
</li>
<li>
Firearms and Explosive Devices
<ul>
<li>
Pistols - Compact handheld firearms suitable for
close-quarters combat and as backup weapons when primary
armaments fail or become unusable in tight spaces.
</li>
<li>
Rifles - Long-barreled precision weapons designed for
accuracy at extended ranges, ideal for eliminating threats
before they can close to melee distance.
</li>
<li>
Heavy Weapons - Devastating armaments including cannons,
siege engines, and experimental warpstone-powered devices
that can breach fortifications and eliminate multiple
enemies.
</li>
</ul>
</li>
<li>
Thrown Weapons - Projectiles designed for manual deployment
including knives, axes, and specialized implements that
require significant skill and practice to use effectively in
combat situations.
</li>
</ul>
</li>
<li>
Magic Items and Enchanted Artifacts - Supernatural implements that
harness arcane energies to produce effects beyond the capabilities
of mundane equipment, often requiring specific knowledge or
bloodlines to activate safely.
</li>
</ul>
</li>
<li>
Protective Gear and Defensive Equipment - Armor systems, shields, and
other defensive measures designed to reduce incoming damage and
improve survival chances against the horrors that lurk in the darkness
below.
</li>
<li>Mirkwood.</li>
<li>Tom.</li>
<li>Bilbo's.</li>
<li>Gandalf's.</li>
<li>Dwarvish.</li>
</ul>
<ul>
<li>Helm&apos;s Deep saws rip outer special bowl determined.</li>
<li>Queen wants Oin loose heads decay piety!</li>
<li>Large happening arrived owes legends wit war bled Durin's.</li>
<li>
Breached forgive Hornblowers galumphing drums respectable wretched.
Pursuit exactly during relief mission meats cause Noldorin ablaze
tracked.
</li>
<li>Mellon slightest uttermost Isildur&apos;s sakes em.</li>
<li>Degree bone rift where sleep judgment Mordor.</li>
<li>Darken knife midday meat Goblinses.</li>
<li>
Tickle watchful lightest dry very teaching pushes picking Shire root.
Your Rabble-rousers greatest could beast thirty-four t wizards
slumbers reforge.
</li>
</ul>
<h3>Maggot devils tea resisted person Sauron the White mist.</h3>
<h3>Late vagabond knowing Ent legends there flattened cultured?</h3>
<p>
You shall not pass! Pelennor squash least crunchable feel faithless
years well-done fun. Rock ending almost shared extend crooked alliances
possible nightfall Dwarf fine risky.
Swords are no more use here. Deny Chubbs restored. Scare rebuild
Argonath tracked day's large.
</p>
<ol>
<li>
Character Creation Process - The systematic approach to developing a
playable character including attribute generation, skill selection,
equipment procurement, and background development that establishes the
foundation for all future adventures.
</li>
<li>
Combat Rules and Tactical Systems
<ol>
<li>
Initiative Phase Determination - The method by which turn order is
established at the beginning of combat encounters, typically
involving dice rolls modified by relevant characteristics and
environmental factors.
</li>
<li>
Action Resolution Mechanics and Probability Systems
<ol>
<li>
Roll percentile dice against relevant skill values - The core
mechanic requiring players to generate random numbers between
1 and 100 and compare the result to their character&apos;s
applicable skill rating.
</li>
<li>
Compare results to skill values and apply situational
modifiers
<ol>
<li>
Success conditions require rolling under the target skill
value after applying all relevant bonuses and penalties
from equipment, positioning, and environmental conditions.
</li>
<li>
Failure occurs when the dice result exceeds the modified
skill value, resulting in missed attacks, failed attempts,
or other negative outcomes depending on the specific
action attempted.
</li>
<li>
Critical results happen on natural rolls of 01-05 for
automatic success or 96-00 for catastrophic failure,
regardless of skill levels or modifiers applied to the
attempt.
</li>
</ol>
</li>
<li>
Apply environmental modifiers, equipment bonuses, and
situational penalties that reflect the current tactical
situation and the character&apos;s preparation level for the
specific challenge being attempted.
</li>
</ol>
</li>
<li>
Damage Resolution and Wound Tracking - The system for determining
injury severity, applying armor protection values, and tracking
the cumulative effects of combat damage on character performance
and survival.
</li>
</ol>
</li>
<li>
Experience and Advancement Systems - The mechanisms by which
characters improve their capabilities over time through successful
completion of adventures, skill usage, and deliberate training between
expeditions.
</li>
<li>Easterlings!</li>
<li>Bill.</li>
<li>Dúnedain!</li>
<li>Gandalf.</li>
<li>Orcrist.</li>
</ol>
<ol>
<li>Spent begins Saruman become interrupt thing arts wide.</li>
<li>Barad-dûr gives forest worm closer.</li>
<li>Answers feelings Elrond conjurer runs.</li>
<li>Sul nudge powerless jelly dumping hair grows log forgave?</li>
<li>
Comings mission province Haleth character chill special service?
Retaken succumbed funeral courtyard Glóin incident mere somewhere
commander assistance?
</li>
<li>
Fine mean hours triumph loyal jelly league someone&apos;s raze
Bagshot!
</li>
<li>Bars ostler crack spreads should spring too dissuade s World.</li>
<li>Bore outrun stead fight Athelas guardroom willing contains.</li>
<li>Hunted Angmar wager noose arguing?</li>
</ol>
<h3>Else ah Bolger torment minutes hours.</h3>
<h3>Elros next own wisp whence cakehole right!</h3>
<p>
Possibly Moon effect utterly tipsy overcrowd next misplaced? Covet
parting Brandybuck hungers crevice hours pork haven&apos;t tempted
clothing. All right, then. Keep your secrets.
Thank hid its lessened lined tells prefers were Stone-Giants thousand
troubles. Earendil staff pines bog finest mushroom consumption.
Mistaken streaming fates paths arts puppet Barad-dûr uniting? You
shall not pass!
</p>
<table>
<thead>
<tr>
<th></th>
<th>Unfold</th>
<th>Grumbling</th>
<th>Ago</th>
<th>Lifetime</th>
<th>Pillaged</th>
<th>Ales</th>
<th>Deeply</th>
<th>Mortality</th>
<th>Open</th>
<th>Single-handedly</th>
</tr>
</thead>
<tbody>
<tr>
<td>Lad</td>
<td>whip</td>
<td>arrows</td>
<td>fairer</td>
<td>begged</td>
<td>stabs</td>
<td>Band</td>
<td>appeared</td>
<td>waited</td>
<td>whose</td>
<td>plate</td>
<td>marshaling</td>
</tr>
<tr>
<td>Appreciation</td>
<td>trouble-making</td>
<td>alone</td>
<td>horrid</td>
<td>prove</td>
<td>they&apos;ll</td>
<td>Meat</td>
<td>nest</td>
<td>thatched</td>
<td>rallying</td>
<td>claimed</td>
<td>hungers</td>
</tr>
<tr>
<td>Filthy</td>
<td>tombs</td>
<td>vest</td>
<td>torches</td>
<td>barrels</td>
<td>powerful</td>
<td>Mouse</td>
<td>also</td>
<td>birdses</td>
<td>moons</td>
<td>strain</td>
<td>brightest</td>
</tr>
<tr>
<td>Instead</td>
<td>foretold</td>
<td>ranks</td>
<td>stare</td>
<td>joy</td>
<td>unequaled</td>
<td>Hate</td>
<td>different</td>
<td>arrangements</td>
<td>chiefest</td>
<td>think</td>
<td>try</td>
</tr>
<tr>
<td>Knew</td>
<td>relations</td>
<td>fighting</td>
<td>spirits</td>
<td>gongs</td>
<td>bears</td>
<td>Something's</td>
<td>task</td>
<td>here's</td>
<td>decent</td>
<td>someone</td>
<td>uses</td>
</tr>
<tr>
<td>Seasoning</td>
<td>nut</td>
<td>one&apos;s</td>
<td>approve</td>
<td>gray</td>
<td>blessing</td>
<td>Shirt</td>
<td>tonight</td>
<td>bay</td>
<td>beautifully</td>
<td>tad</td>
<td>cloaks</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>beheading</td>
<td>disturber</td>
<td>laid</td>
<td>forth</td>
<td>watching</td>
<td>domains</td>
<td>revenge</td>
<td>teaching</td>
<td>mischief</td>
<td>shores</td>
<td>dreams</td>
<td>tested</td>
</tr>
</tfoot>
</table>
<h4>Sodding tongue Elros leaves perceived south pocket.</h4>
<h4>Stage dishcloth 20 horses Tooks souls crawl crime.</h4>
<p>
Born revenge utterly that&apos;ll Goblin-town gladness. Chips sustained
times apocalypse closest Alfrid grow. I can cut across country easily
enough. Clearing toss unhappy Smeagol&apos;s gifted?
Approve Sul wilderness grave embellishment greatly over these rack
struggle. End ringing bell Anor halls pairs thirst fortress curtain
cleared? Dwelt language 1296 Underhill nasty. I gave you the chance of
aiding me willingly, but you have elected the way of pain!
</p>
<blockquote>
<p>Sam... I&apos;m glad you are with me.</p>
<p>You are full of surprises, Master Baggins.</p>
<footer>
Ravens, <cite>shore wizards skin harpoon</cite>
Girion, <cite>warmongering appears</cite>
</footer>
</blockquote>
<figure>
<figure>
<img
src="https://picsum.photos/1280/1024"
alt="Industrial machinery in abandoned factory"
width="1280"
height="1024"
/>
<figcaption>
Rusted conveyor systems in the former Blackwater Manufacturing
plant, photographed during demolition in 2023.
</figcaption>
</figure>
</figure>
<figure>
<blockquote>
<p>
More glad painted Sauron the White troop holidays captive has. Many
pierced repel bathroom absence glimpse Tom. All right, then. Keep
your secrets.
</p>
</blockquote>
<figcaption>
Common saying among veteran adventurers in the Undercity.
</figcaption>
</figure>
<details>
<summary>Equipment Requirements</summary>
<p>
All adventurers must carry a minimum of: one weapon (melee or ranged),
basic armor or protective gear, emergency rations for 3 days, torch or
light source, 50 feet of rope, and a first aid kit.
</p>
<p>
Optional but recommended: lockpicks, crowbar, grappling hook, healing
potions, and backup weapon.
</p>
</details>
<details>
<summary>Combat Mechanics Overview</summary>
<h4>Initiative System</h4>
<p>Roll 1d10 + Initiative characteristic. Highest goes first.</p>
<h4>Attack Resolution</h4>
<p>
Roll percentile dice under your relevant skill. Success means you hit,
failure means you miss.
</p>
<ul>
<li>Melee combat uses Weapon Skill</li>
<li>Ranged combat uses Ballistic Skill</li>
<li>Damage equals weapon damage + Strength bonus</li>
</ul>
</details>
<details open>
<summary>Currently Expanded Section</summary>
<p>
This details element starts open to test the expanded state styling.
</p>
</details>
<h5>
Raised Morgoth powerless roaming sing fire-breather regurgitation was.
Sung outscoring fingers Fundin reaction inquiries buggers deadliest.
</h5>
<p>
More glad painted Sauron the White troop holidays captive has. Many
pierced repel bathroom absence glimpse Tom. All right, then. Keep your
secrets.
Mustn't powerless pierces Muil sorry crossing diamond brandy. Rip
rockets hinder Braga go had web ought sakes hail. A wizard is never
late, Frodo Baggins. Nor is he early. He arrives precisely when he
means to. Ashes tie Gamgee dicky!
</p>
<pre>
Prepared Tilda adventure characters crush. Wilds overlook blessed walk
requested. Ligulas sat eavesdropping breathes exceeding dim. Deeper
clever becomes regain Dimholt fronts.
Rhudaur fancy tilled heart beggars. Dwarf nothing talked foot club.
Slaughtered flatten Hobbit journey's four-day?
</pre>
<h6>Resilient closest regret vile birthright innards Middle-earth.</h6>
<h6>Pearl tact tomb bits Arwen Evenstar worry?</h6>
<p>
Shire herald <strong>dear hard army carry without</strong> proposition.
Thranduil faint me chiefest{' '}
<a>middle hey-diddle-diddle squeaked sawed landlord</a>.{' '}
<del>Hallway clot-head&apos;s injury</del> journey Minas Morgul hasty?
Ring sight fit Boffins <kbd>S</kbd>. Manage Bifur ways{' '}
<mark>pity&apos;s swarming</mark> doubt. Wilderness breathing woe liege
<ins>Khazad-dum King&apos;s</ins> handy! Join corpses{' '}
<code>rack tongs knockers gongs</code> four-day Théoden&apos;s idiot.{' '}
<var>Hooded</var> Kingsfoil biding may. Extra{' '}
<time>Radagast the Brown</time> passion cutting skinned. Hurry problem{' '}
<sup>delays</sup> Bucklebury. Corks hell <small>hundred deal</small>{' '}
Barahir unprepared. What&apos;ll Dwarvish down
<em>bought haunted steps</em>. Master&apos;s given Hobbit{' '}
<dfn>afterwards bodies gibbet</dfn>. Towers stars <sub>productive</sub>{' '}
Baggins. Juicy <samp>opinion note</samp> Déagol tough books spreads.
Decide imaginable <q>Goblin-mutant Silvan</q> fellow.{' '}
<cite>Sit Agreed</cite> thick drink pearl tale. Legolas approve
night&apos;s
<abbr>retrieve</abbr> endless.
Times unspoiled <time>defenses</time> Silvan.{' '}
<del>Sigrid Pippin Gandalf</del> thin stubbornness noises easily
spread. Eldar warriors <code>won answered</code> filth yourself
pocket. Showing store consistency <kbd>M</kbd> crevice. Decision
feverfew <sup>giving</sup> Misty Mountain lord supplant. Gorgoroth{' '}
<dfn>load born fulfilled plenty</dfn> fates serpent. Doorstep Pippin's{' '}
<cite>pity bridge</cite> long weak weep? Brightest <abbr>Chubbs</abbr>{' '}
jewels understand. Somewhat Erebor <sub>noise</sub> squealing moved?
Pippin's <mark>feels overrun</mark> hours brown burns. <var>Anor</var>{' '}
turning pick prophecy. Surrounded <q>entered needlessly weary</q> vile
hmm Bagshot Row. Consent <ins>outwitted dotage slug</ins> Homely hear.
Parapet <strong>protected favored defied roam</strong> quiet Dori sick
bent. <samp>Homage store hurricane</samp> prove ferret Helm's Deep
lately? <small>Excellent regret fun often</small> returned Wood-elves
apocalypse. Théodred's rights rat drawing{' '}
<a>examine dared bygone residence deeply</a>.{' '}
<em>Greenway Girion Rohirrim</em> trammel waiting edge.
</p>
<hr />
<dl>
<dt>How</dt>
<dt>Turn</dt>
<dd>
Looks resilient eggs Tauriel higher supplant evisceration idiot
barely.
Bare protuberance arrived forging funny salvage Cair except first
banners.
</dd>
<dt>Names</dt>
<dd>Slugs play Dwalin late parapet ending how morning?</dd>
<dt>Foes</dt>
<dd>Bore river large house shadows it's Tuckborough warn.</dd>
<dd>
Holidays even disease thunder-battle nice irregular cooked
trouble&apos;ll Minas Tirith mistaken!
Stirring Greenwood nest sapphire grant gob flagon famous mean!
</dd>
<dt>Mice</dt>
<dt>Unprepared</dt>
<dd>
Productive Sit mend ones raiding hutch couldn&apos;t thirty-four.
Single-handed wriggling creatures lock canopy anytime horses defense
Hobbit's?
</dd>
<dd>
Facing others act doing lives usually pity Legolas laws daughter.
</dd>
<dd>
Lords embalmed nature we&apos;d grievances Thror shelter tragedy.
Nûmenor dungeons achieving encourage fretting dines believes
understand.
</dd>
<dd>Ease love shine legs wee harbor Udùn adventure tumble stays.</dd>
</dl>
<form>
<fieldset>
<legend>Need bandy council</legend>
<div>
<label>Text</label>
<input type="text" />
</div>
<div>
<label>Email</label>
<input type="email" />
</div>
<div>
<label>Password</label>
<input type="password" />
</div>
<div>
<label>Url</label>
<input type="url" />
</div>
<div>
<label>Number</label>
<input type="number" />
</div>
<div>
<label>Tel</label>
<input type="tel" />
</div>
<div>
<label>Search</label>
<input type="search" />
</div>
<div>
<label>Time</label>
<input type="time" />
</div>
<div>
<label>Date</label>
<input type="date" />
</div>
<div>
<label>Datetime-local</label>
<input type="datetime-local" />
</div>
<div>
<label>Week</label>
<input type="week" />
</div>
<div>
<label>Textarea</label>
<textarea></textarea>
</div>
</fieldset>
<fieldset>
<legend>Wring moments</legend>
<div>
<label>Month</label>
<input type="month" />
</div>
<div>
<label>
<input type="checkbox" name="checkbox" />
tipsy smuggler
</label>
</div>
<div>
<label>Color</label>
<input type="color" />
</div>
<div>
<label>File</label>
<input type="file" />
</div>
<div>
<label>Hidden</label>
<input type="hidden" />
</div>
<div>
<label>Image</label>
<input type="image" src="https://picsum.photos/96" />
</div>
<div>
<label>malt grass fall door&apos;s infested red</label>
<label>
<input type="radio" name="radio" />
rain joy
</label>
<label>
<input type="radio" name="radio" />
plates grieve
</label>
<label>
<input type="radio" name="radio" />
arranged listened
</label>
</div>
<div>
<label>Range</label>
<input type="range" />
</div>
<div>
<input type="button" value="Button" />
</div>
<div>
<input type="reset" value="Reset" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
<button>infected awoke</button>
<div>
<label>Select</label>
<select>
<optgroup label="rubbish waited tastes">
<option>myth</option>
<option>metals</option>
<option>would</option>
</optgroup>
<optgroup label="thunderstorm particularly breach">
<option>began</option>
<option>threads</option>
<option>tight</option>
</optgroup>
</select>
</div>
</fieldset>
</form>
</div>
);
}

View File

@@ -1,4 +1,6 @@
@import url("../styles/variables.css");
@import url("../styles/utilities.css");
@import url("../styles/foundation.css");
@import url("../styles/base.css");
@layer reset, tokens, base, layout, content, components, utilities, animations;
@import url("../styles/tokens.css");
@import url("../styles/globals/foundation.css");
@import url("../styles/globals/base.css");
@import url("../styles/globals/content.css");

View File

@@ -69,12 +69,11 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
<html
lang="en"
className={`${geistSans.variable} ${blaka.variable} ${iosevkaSlab.variable} ${iosevkaMono.variable}`}
>
{children}
</body>
<body>{children}</body>
</html>
);
}

View File

@@ -0,0 +1,77 @@
@layer components {
.header {
@mixin py var(--el-header-paddingY);
position: sticky;
z-index: 9;
top: 0;
width: var(--dim-full);
color: var(--color-text-inverse);
background-color: var(--color-surface-inverse);
}
.inner {
@mixin responsive-wrapper;
display: flex;
flex-direction: row;
gap: var(--spacing-cozy);
align-items: center;
justify-content: flex-start;
font-size: var(--el-header-font-size);
line-height: var(--el-header-line-height);
}
.logo {
@mixin anim-txt-characterglitch;
font-family: var(--font-mono);
animation:
logo-pulse 5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
&:hover {
transform: translate(0, 0);
color: var(--color-secondary);
}
}
.pagename {
font-family: var(--font-mono);
& .bracket {
color: var(--color-secondary);
}
}
.menutoggle {
@mixin ml auto;
& button {
cursor: pointer;
font-family: var(--font-mono);
transition: color 0.2s ease-out;
&:hover {
color: var(--color-primary);
}
&:active {
transform: scale(0.95);
transition: transform 0.1s ease-out;
}
}
}
@keyframes logo-pulse {
0% { opacity: 1; }
25% { opacity: 0.66; }
50% { opacity: 0.33; }
75% { opacity: 0.66; }
100% { opacity: 1; }
}
}

View File

@@ -0,0 +1,48 @@
'use client';
import Link from 'next/link';
import { useMenu } from '@/contexts/MenuContext';
import styles from './Header.module.css';
export default function Header() {
const { isMenuOpen, closeMenu, openMenu, startClosing, resetClosing } =
useMenu();
const handleMenuToggle = () => {
if (isMenuOpen) {
startClosing();
setTimeout(() => {
closeMenu();
resetClosing();
}, 800);
} else {
openMenu();
}
};
return (
<header className={styles.header}>
<div className={styles.inner}>
<div className={styles.logo}>
<Link href="/"></Link>
</div>
<div className={styles.pagename}>
<span>
dave <span className={styles.bracket}>[</span>dmg
<span className={styles.bracket}>]</span>
</span>
</div>
<div className={styles.menutoggle}>
<button
onClick={() => handleMenuToggle()}
aria-label={isMenuOpen ? 'Close menu' : 'Open menu'}
aria-expanded={isMenuOpen}
aria-controls="main-menu"
>
{isMenuOpen ? '[×]' : '[⚍]'}
</button>
</div>
</div>
</header>
);
}

View File

@@ -0,0 +1,403 @@
@layer components {
/* === MenuGrid === */
.menu {
pointer-events: none;
position: fixed;
z-index: 9;
top: var(--el-header-height);
left: 0;
display: grid;
grid-auto-columns: 1fr;
grid-template-areas:
"area_1"
"area_2"
"area_3"
"area_4"
"area_5";
grid-template-columns: 1fr;
grid-template-rows: repeat(5, auto);
gap: 0;
gap: var(--spacing-cozy);
width: 100vw;
height: 100%;
max-height: calc(100vh - var(--el-header-height));
visibility: hidden;
opacity: 0;
background-color: var(--color-palette-charcoal-gray);
transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
&.isOpen {
pointer-events: auto;
visibility: visible;
opacity: 1;
}
@media screen and (--bp-tablet) {
@mixin px var(--spacing-comfortable);
grid-template-areas:
"area_1"
"area_2"
"area_3"
"area_4"
"area_5";
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: var(--spacing-comfortable);
}
@media screen and (--bp-desktop) {
display: grid;
grid-template-areas:
"area_4 area_4 area_3 area_3 area_3 area_3 area_2"
"area_4 area_4 area_3 area_3 area_3 area_3 area_2"
"area_5 area_5 area_3 area_3 area_3 area_3 area_2"
"area_5 area_5 area_3 area_3 area_3 area_3 area_1"
"area_5 area_5 area_3 area_3 area_3 area_3 area_1";
grid-template-columns: 2.5fr 1fr 3fr 1.5fr 1fr 1fr 4fr;
grid-template-rows: 3fr 1fr 2.5fr 1.5fr 2fr;
}
}
/* === MenuArea === */
.area {
/* === AREA VARIABLES === */
--area-bg: transparent;
--area-border: transparent;
--area-animation-keyframe: none;
--area-animation-duration: 0s;
--area-animation-timing: linear;
--area-bg-filter: grayscale(100%) contrast(150) brightness(150);
/** === TITLE VARIABLES === */
--title-color: var(--color-palette-light-silver);
--title-font: var(--font-header);
--title-font-size: var(--typo-size-2xl);
--title-font-weight: var(--typo-weight-black);
--title-line-height: 1;
--title-transform: uppercase;
--title-spacing: var(--typo-spacing-comfortable);
--title-hover-color: var(--color-tertiary);
--title-current-color: var(--color-primary);
--title-current-bg: var(--color-primary);
/** === SUBLINK VARIABLES === */;
--sublink-color: var(--color-palette-light-silver);
--sublink-font: var(--font-header);
--sublink-font-size: var(--typo-size-2xl);
--sublink-font-weight: var(--typo-weight-black);
--sublink-transform: uppercase;
--sublink-spacing: var(--typo-spacing-relaxed);
--sublink-line-height: var(--typo-leading-relaxed);
--sublink-letter-spacing: var(--typo-spacing-relaxed);
--sublink-current-color: var(--color-primary);
--sublink-current-bg: var(--color-primary);
/** === SUBTITLE VARIABLES === **/
--divider-color: var(--color-palette-light-silver);
--divider-width: var(--size-6);
--divider-height: var(--size-2);
--divider-font: var(--font-mono);
--divider-symbol: ;
--divider-font-size: var(--typo-size-2xl);
--divider-padding: 0 var(--typo-spacing-cozy);
--subtitle-color: var(--color-palette-light-silver);
--subtitle-font: var(--font-mono);
--subtitle-font-size: var(--typo-size-2xl);
--subtitle-text-transform: uppercase;
--subtitle-letter-spacing: var(--typo-spacing-cozy);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: var(--size-1) solid var(--area-border);
text-align: center;
background: var(--area-bg);
transition: all 0.2s ease-in-out;
&:not(.current) {
&:hover {
animation: var(--area-animation-keyframe) var(--area-animation-duration) var(--area-animation-timing);
}
}
}
.area_1 { grid-area: area_1; }
.area_2 { grid-area: area_2; }
.area_3 { grid-area: area_3; }
.area_4 { grid-area: area_4; }
.area_5 { grid-area: area_5; }
.hasBGImg {
&:hover {
.bgImg {
animation: var(--area-animation-keyframe) var(--area-animation-duration) var(--area-animation-timing);
}
}
}
.bgImg {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
object-fit: cover;
filter: var(--area-bg-filter);
@media screen and (--bp-tablet-down) {
display: none;
}
}
/* === MenuTitle === */
.title {
position: relative;
}
.mainlink {
position: relative;
font-family: var(--title-font);
font-size: var(--title-font-size);
font-weight: var(--title-font-weight);
line-height: var(--title-line-height);
color: var(--title-color);
text-transform: var(--title-transform);
letter-spacing: var(--title-spacing);
transition: any 0.5s ease-in-out;
&:focus {
&:hover {
color: var(--title-current-color);
}
@media screen and (--bp-tablet-down) {
outline: none;
&:hover {
color: var(--title-current-color);
}
}
}
&.current {
pointer-events: none;
@media screen and (--bp-tablet-down) {
&:hover {
color: var(--title-current-color);
}
}
@media screen and (--bp-desktop) {
}
}
@media screen and (--bp-tablet-down) {
transition: border 0.5s ease-in-out;
}
}
/* === MenuSublinks === */
.list {
@media screen and (--bp-tablet-down) {
display: none;
}
}
.item {
position: relative;
}
.sublink {
position: relative;
font-family: var(--sublink-font);
font-size: var(--sublink-font-size);
font-weight: var(--sublink-font-weight);
line-height: var(--sublink-line-height);
color: var(--sublink-color);
text-transform: var(--sublink-transform);
letter-spacing: var(--sublink-spacing);;
&:not(.current),
&:not(.focus) {
transition: var(--sublink-hover-transition);
&::after,
&::before {
position: absolute;
font-family: var(--sublink-hover-decorator-font);
opacity: 0;
transition: var(--sublink-hover-decorator-transition);
}
&::before {
content: var(--sublink-hover-decorator-left-symbol);
left: 0;
}
&::after {
content: var(--sublink-hover-decorator-right-symbol);
right: 0;
}
&:hover {
color: var(--sublink-hover-color);
&::before {
top: var(--sublink-hover-decorator-left-pos-y);
left: var(--sublink-hover-decorator-left-pos-x);
transform: var(--sublink-hover-decorator-left-transform);
opacity: 1;
}
&::after {
top: var(--sublink-hover-decorator-right-pos-y);
right: var(--sublink-hover-decorator-rightt-pos-x);
transform: var(--sublink-hover-decorator-right-transform);
opacity: 1;
}
}
&:focus {
&:hover {
color: var(--sublink-current-color);
}
}
&.current {
pointer-events: none;
}
}
}
/* === MenuSubtitle === */
.wrapper {
position: relative;
@media screen and (--bp-tablet-down) {
display: none;
}
}
/* === UTILITY Classes */
@media screen and (--bp-desktop) {
.pos_tr {
position: absolute;
top: 1em;
right: 1em;
}
.pos_tc {
position: absolute;
top: 1em;
left: 50%;
transform: translateX(-50%);
}
.pos_tl {
position: absolute;
top: 1em;
left: 1em;
}
.pos_cr {
position: absolute;
top: 50%;
right: 1em;
transform: translateY(-50%);
}
.pos_c {
position: absolute;
bottom: 50%;
left: 50%;
transform: translate(-50%, 50%);
}
.pos_cl {
position: absolute;
top: 50%;
right: 1em;
transform: translateY(-50%);
}
.pos_br {
position: absolute;
right: 1em;
bottom: 1em;
}
.pos_bc {
position: absolute;
bottom: 1em;
left: 50%;
transform: translateX(-50%);
}
.pos_bl {
position: absolute;
bottom: 1em;
left: 1em;
}
.vertical-rl {
writing-mode: vertical-rl;
& * {
writing-mode: vertical-rl;
}
}
.vertical-lr {
writing-mode: vertical-lr;
& * {
writing-mode: vertical-lr;
}
}
.sideways-rl {
writing-mode: sideways-rl;
& * {
writing-mode: sideways-rl;
}
}
.sideways-lr {
writing-mode: sideways-lr;
& * {
writing-mode: sideways-lr;
}
}
}
/* === CATEGORY Variants === */
@media screen and (--bp-desktop) {
.meta {}
.kitchensink {}
.awq {}
.worldburner {}
.chainbreaker {}
}
}

View File

@@ -0,0 +1,121 @@
@layer components {
.area {
--area-bg: transparent;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
background: var(--area-bg);
@media screen and (--bp-tablet-down) {
border-bottom: var(--size-1) solid var(--color-palette-gunmetal);
&:last-child {
border-bottom: none;
}
}
}
.area_1 {
position: relative;
grid-area: area_1;
}
.area_2 {
position: relative;
grid-area: area_2;
}
.area_3 {
position: relative;
grid-area: area_3;
}
.area_4 {
position: relative;
grid-area: area_4;
}
.area_5 {
position: relative;
grid-area: area_5;
}
.hasBGImg {
position: relative;
&:hover {
& .bgImg {
animation: var(--area-animation-keyframe) var(--area-animation-duration) var(--area-animation-timing);
}
}
}
.bgImg {
--area-bg-animation-keyframe: none;
--area-bg--animation-duration: 0s;
--area-bg--animation-timing: linear;
--area-bg-filter: grayscale(100%) contrast(150) brightness(150);
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
object-fit: cover;
filter: var(--area-bg-filter);
@media screen and (--bp-tablet-down) {
display: none;
}
}
@media screen and (--bp-desktop) {
.chainbreaker {
--area-animation-keyframe: var(--kf-color-bleed);
--area-animation-duration: var(--img-colorbleed-duration);
--area-animation-timing: var(--img-colorbleed-timing);
& .bgImg {
z-index: -2;
}
&.hasBGImg {
--divider-color: transparent;
--title-color: transparent;
--subtitle-color: transparent;
--subtitle-transition: all 0.3s ease-in-out;
--title-transition: color 0.3s ease-in-out;
&::before {
content: "";
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
opacity: 0;
background: alpharize(var(--grid-bg), 0.66);
}
&:hover {
--divider-color: var(--color-tertiary);
--title-color: var(--color-tertiary);
--subtitle-color: var(--color-tertiary);
&::before {
opacity: 1;
}
}
}
}
}
}

View File

@@ -0,0 +1,46 @@
import React from 'react';
import MenuItem from '@/components/Page/Menu//MenuItem/';
import { useCurrentPath } from '@/hooks/useCurrentPath';
import styles from './MenuArea.module.css';
import { NavigationItem } from '@/lib/types/navigation';
interface MenuAreaProps {
item: NavigationItem;
}
const MenuArea = React.memo(({ item }: MenuAreaProps) => {
const hasBGImg = !!item.background;
const { isCurrentPath } = useCurrentPath();
const areaClasses = React.useMemo(() => {
return [
styles.area,
styles[item.gridPosition],
styles[item.variant],
isCurrentPath(item.path) ? styles.current : '',
item.background ? styles.hasBGImg : null,
]
.filter(Boolean)
.join(' ');
}, [item.background, isCurrentPath]);
return (
<section className={areaClasses}>
{hasBGImg && (
<img
className={styles.bgImg}
src={item.background}
alt={`Background Image for ${item.name}`}
/>
)}
<MenuItem item={item} />
</section>
);
});
MenuArea.displayName = 'MenuArea';
export default MenuArea;

View File

@@ -0,0 +1,115 @@
@layer components {
.menu {
--grid-bg: var(--color-palette-charcoal-gray);
--grid-fg: var(--color-palette-light-silver);
/* === MenuTitle Vars === */
--title-color: var(--grid-fg);
--title-font: var(--font-mono);
--title-font-size: var(--typo-size-2xl);
--title-font-weight: var(--typo-weight-black);
--title-line-height: 1;
--title-transform: uppercase;
--title-spacing: var(--typo-spacing-comfortable);
--title-hover-fg: var(--primary);
--title-hover-bg: transparent;
--title-current-bg: var(--color-tertiary);
--title-current-fg: var(--grid-bg);
--title-focus-fg: var(--color-secondary);
--title-focus-bg: var(--grid-bg);
--title-transition: none;
/* === MenuSublinks Vars === */
--sublink-color: var(--grid-fg);
--sublink-font: var(--font-mono);
--sublink-font-size: var(--typo-size-xl);
--sublink-font-weight: var(--typo-weight-light);
--sublink-transform: uppercase;
--sublink-line-height: var(--typo-leading-relaxed);
--sublink-spacing: var(--typo-spacing-loosest);
--sublink-hover-fg: var(--color-tertiary);
--sublink-hover-bg: transparent;
--sublink-current-fg: var(--grid-bg);
--sublink-current-bg: var(--color-primary);
--sublink-focus-fg: var(--color-secondary);
--sublink-focus-bg: var(--grid-bg);
--sublink-transition: none;
/* === MenuSubtitle Vars === */
--divider-color: var(--grid-fg);
--divider-width: var(--size-12);
--divider-height: var(--size-2);
--divider-font: var(--font-mono);
--divider-font-size: var(--typo-size-2xl);
--divider-padding: 0 var(--typo-spacing-cozy);
--subtitle-font: var(--font-mono);
--subtitle-color: var(--grid-fg);
--subtitle-font-size: var(--typo-size-xl);
--subtitle-text-transform: uppercase;
--subtitle-letter-spacing: var(--typo-spacing-cozy);
--subtitle-transition: none;
pointer-events: none;
position: fixed;
z-index: 9;
top: var(--el-header-height);
left: 0;
display: grid;
grid-auto-columns: 1fr;
grid-template-areas:
"area_1"
"area_2"
"area_3"
"area_4"
"area_5";
grid-template-columns: 1fr;
grid-template-rows: repeat(5, auto);
width: 100vw;
height: calc(100vh - var(--el-header-height));
color: var(--grid-fg);
visibility: hidden;
opacity: 0;
background-color: var(--grid-bg);
clip-path: inset(0 0 100% 0);
transition: clip-path 0.35s steps(8, end);
&.isOpen {
pointer-events: auto;
transform: translateY(0);
visibility: visible;
opacity: 1;
clip-path: inset(0 0 0 0);
}
&.isClosing {
clip-path: inset(0 0 100% 0);
transition: clip-path 0.25s steps(6, end);
&.isOpen {
clip-path: inset(0 0 100% 0);
transition: clip-path 0.25s steps(6, end);
}
}
@media screen and (--bp-desktop) {
display: grid;
grid-template-areas:
"area_4 area_4 area_3 area_3 area_3 area_3 area_2"
"area_4 area_4 area_3 area_3 area_3 area_3 area_2"
"area_5 area_5 area_3 area_3 area_3 area_3 area_2"
"area_5 area_5 area_3 area_3 area_3 area_3 area_1"
"area_5 area_5 area_3 area_3 area_3 area_3 area_1";
grid-template-columns: 2.5fr 1fr 3fr 1.5fr 1fr 1fr 4fr;
grid-template-rows: 3fr 1fr 2.5fr 1.5fr 2fr;
}
}
}

View File

@@ -0,0 +1,66 @@
'use client';
import React from 'react';
import { useMenu } from '@/contexts/MenuContext';
import MenuArea from '@/components/Page/Menu/MenuArea/';
import styles from './MenuGrid.module.css';
interface MenuGridProps {
navigationData: Awaited<
ReturnType<
typeof import('@/lib/readers/system/navigation').getNavigationData
>
>;
}
export default function MenuGrid({ navigationData }: MenuGridProps) {
const { isMenuOpen, closeMenu, isClosing, startClosing, resetClosing } =
useMenu();
const menuRef = React.useRef<HTMLElement>(null);
const handleClose = React.useCallback(() => {
startClosing();
setTimeout(() => {
closeMenu();
resetClosing();
}, 800);
}, [closeMenu, startClosing, resetClosing]);
React.useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape' && isMenuOpen) {
handleClose();
}
};
document.addEventListener('keydown', handleEscape);
return () => document.removeEventListener('keydown', handleEscape);
}, [isMenuOpen, handleClose]);
React.useEffect(() => {
if (isMenuOpen && menuRef.current) {
const initialFocus = menuRef.current.querySelector(
'a, button'
) as HTMLElement;
initialFocus?.focus();
}
}, [isMenuOpen]);
if (!navigationData) return null;
const { items } = navigationData;
return (
<nav
ref={menuRef}
className={`${styles.menu} ${isMenuOpen ? styles.isOpen : ''} ${isClosing ? styles.isClosing : ''}`}
aria-hidden={!isMenuOpen}
aria-label="Main navigation"
>
{items.map((item, index) => (
<MenuArea key={item.gridPosition} item={item} />
))}
</nav>
);
}

View File

@@ -0,0 +1,24 @@
import { hasSublinks, hasSubtitle } from '@/lib/types/navigation';
import MenuTitle from '@/components/Page/Menu/MenuTitle/';
import MenuSublinks from '@/components/Page/Menu/MenuSublinks/';
import MenuSubtitle from '@/components/Page/Menu/MenuSubtitle/';
import { NavigationItem } from '@/lib/types/navigation';
interface MenuItem {
item: NavigationItem;
}
export default function MenuItem({ item }: MenuItem) {
return (
<>
<MenuTitle path={item.path} name={item.name} variant={item.variant} />
{hasSublinks(item) && (
<MenuSublinks sublinks={item.sublinks.value} variant={item.variant} />
)}
{hasSubtitle(item) && (
<MenuSubtitle subtitle={item.subtitle.value} variant={item.variant} />
)}
</>
);
}

View File

@@ -0,0 +1,57 @@
@layer components {
.list {
@media screen and (--bp-tablet-down) {
@util hide-visually;
}
}
.item {
position: relative;
}
.sublink {
font-family: var(--sublink-font);
font-size: var(--sublink-font-size);
font-weight: var(--sublink-font-weight);
line-height: var(--sublink-line-height);
color: var(--sublink-color);
text-transform: var(--sublink-transform);
letter-spacing: var(--sublink-spacing);
&.current {
padding: var(--spacing-snug) var(--spacing-tight);
color: var(--title-current-fg);
animation: var(--kf-text-glitch) 5s infinite;
&::before {
content: "⟩";
}
}
&:not(.current) {
--pointer-left-symbol: "▶";
--pointer-right-symbol: "◀";
--pointer-distance: 1em;
@mixin anim-txt-pointer_focus;
@mixin px var(--spacing-tight);
&:focus {
color: var(--sublink-focus-fg);
outline: none;
}
&:not(:focus) {
--pointer-left-symbol: "{";
--pointer-right-symbol: "}";
--pointer-distance: 0.5em;
@mixin anim-txt-pointer;
&:hover {
--sublink-color: var(--color-primary);
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
import Link from 'next/link';
import styles from './MenuSublinks.module.css';
import { SubNavigationItem } from '@/lib/types/navigation';
import { useCurrentPath } from '@/hooks/useCurrentPath';
interface MenuSublinks {
sublinks: readonly SubNavigationItem[];
variant: string;
}
export default function MenuSublinks({ sublinks, variant }: MenuSublinks) {
const { isCurrentPath } = useCurrentPath();
return (
<ul className={`${styles.list} ${styles[`${variant}`]}`}>
{sublinks.map((sublink: SubNavigationItem) => (
<li className={styles.item} key={sublink.path}>
<Link
href={sublink.path}
className={`${styles.sublink} ${isCurrentPath(sublink.path) ? styles.current : ''}`}
>
{sublink.name}
</Link>
</li>
))}
</ul>
);
}

View File

@@ -0,0 +1,57 @@
@layer components {
.claim {
@media screen and (--bp-tablet-down) {
display: none;
}
}
.divider {
position: relative;
width: 100%;
text-align: center;
}
.dividersymbol {
position: relative;
font-family: var(--divider-font);
font-size: var(--divider-font-size);
line-height: var(--divider-line-height);
color: var(--divider-color);
transition: var(--subtitle-transition);
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
width: var(--divider-width);
height: var(--divider-height);
background-color: var(--divider-color);
}
&::before {
left: calc(var(--divider-width) *-1);
}
&::after {
right: calc(var(--divider-width) *-1);
}
}
.subtitle {
font-family: var(--subtitle-font);
font-size: var(--subtitle-font-size);
color: var(--subtitle-color);
text-transform: var(--subtitle-text-transform);
letter-spacing: var(--subtitle-letter-spacing);
transition: var(--subtitle-transition);
}
}

View File

@@ -0,0 +1,26 @@
import { Subtitle, hasDivider } from '@/lib/types/navigation';
import styles from './MenuSubtitle.module.css';
interface MenuSubtitleProps {
subtitle: Subtitle;
variant: string;
}
export default function MenuSubtitle({ subtitle, variant }: MenuSubtitleProps) {
const divider = hasDivider(subtitle) ? (
<div className={styles.divider}>
<span className={`${styles.dividersymbol}`}>
{subtitle.divider.value}
</span>
</div>
) : (
''
);
return (
<div className={`${styles.claim} ${styles[`${variant}`]}`}>
{divider}
<p className={`${styles.subtitle}`}>{subtitle.content}</p>
</div>
);
}

View File

@@ -0,0 +1,63 @@
@layer components {
.heading {
position: relative;
&:has(+ ul) {
@mixin my var(--spacing-comfortable);
}
}
.mainlink {
position: relative;
border: none;
font-family: var(--title-font);
font-size: var(--title-font-size);
font-weight: var(--title-font-weight);
line-height: var(--title-line-height);
color: var(--title-color);
text-transform: var(--title-transform);
letter-spacing: var(--title-spacing);
background: transparent;
transition: var(--title-transition);
&.current {
padding: var(--spacing-snug) var(--spacing-tight);
color: var(--title-current-fg);
animation: var(--kf-text-glitch) 5s infinite;
&::before {
content: "⟩";
}
}
&:not(.current) {
--pointer-left-symbol: "▶";
--pointer-right-symbol: "◀";
--pointer-distance: 1em;
@mixin anim-txt-pointer_focus;
@mixin px var(--spacing-tight);
&:focus {
color: var(--title-focus-fg);
outline: none;
}
&:not(:focus) {
--pointer-left-symbol: "{";
--pointer-right-symbol: "}";
--pointer-distance: 0.5em;
@mixin anim-txt-pointer;
&:hover {
--title-color: var(--color-primary);
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
import Link from 'next/link';
import styles from './MenuTitle.module.css';
import { useCurrentPath } from '@/hooks/useCurrentPath';
interface MenuTitleProps {
name: string;
path: string;
variant: string;
}
export default function MenuTitle({ name, path, variant }: MenuTitleProps) {
const { isCurrentPath } = useCurrentPath();
return (
<h2 className={`${styles.heading} ${styles[`${variant}`]}`}>
<Link
className={`${styles.mainlink} ${isCurrentPath(path) ? styles.current : ''}`}
href={path}
>
{name}
</Link>
</h2>
);
}

View File

@@ -0,0 +1,7 @@
import { getNavigationData } from '@/lib/readers/system/navigation';
import MenuGrid from '@/components/Page/Menu/MenuGrid';
export default async function Menu() {
const navigation = await getNavigationData();
return <MenuGrid navigationData={navigation} />;
}

View File

@@ -0,0 +1,62 @@
'use client';
import React, { useContext, useEffect } from 'react';
interface MenuContextType {
isMenuOpen: boolean;
isClosing: boolean;
closeMenu: () => void;
openMenu: () => void;
startClosing: () => void;
resetClosing: () => void;
}
const MenuContext = React.createContext<MenuContextType | undefined>(undefined);
interface MenuProviderProps {
children: React.ReactNode;
}
export const MenuProvider = ({ children }: MenuProviderProps) => {
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false);
const closeMenu = () => setIsMenuOpen(false);
const openMenu = () => setIsMenuOpen(true);
const startClosing = () => setIsClosing(true);
const resetClosing = () => setIsClosing(false);
useEffect(() => {
if (isMenuOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
return () => {
document.body.style.overflow = 'unset';
};
}, [isMenuOpen]);
return (
<MenuContext.Provider
value={{
isMenuOpen,
openMenu,
closeMenu,
isClosing,
startClosing,
resetClosing,
}}
>
{children}
</MenuContext.Provider>
);
};
export const useMenu = () => {
const context = useContext(MenuContext);
if (context === undefined) {
throw new Error('useMenu must be used within a MenuProvider');
}
return context;
};

View File

@@ -0,0 +1,8 @@
import { usePathname } from 'next/navigation';
export const useCurrentPath = () => {
const pathname = usePathname();
const isCurrentPath = (path: string) => path === pathname;
return { isCurrentPath, pathname };
};

View File

@@ -0,0 +1,116 @@
// ============= KEYSTATIC SCHEMA =============
import { fields, singleton } from '@keystatic/core';
export default singleton({
label: 'Navigation',
path: 'content/system/navigation',
format: 'json',
schema: {
items: fields.array(
fields.object({
name: fields.text({
label: 'Name',
validation: { isRequired: true },
}),
path: fields.url({
label: 'Path',
description: 'Omit starting slash (/)',
validation: { isRequired: true },
}),
gridPosition: fields.select({
label: 'Grid Position',
defaultValue: '',
options: [
{ label: 'None', value: '' },
{ label: 'Area 1', value: 'area_1' },
{ label: 'Area 2', value: 'area_2' },
{ label: 'Area 3', value: 'area_3' },
{ label: 'Area 4', value: 'area_4' },
{ label: 'Area 5', value: 'area_5' },
],
}),
variant: fields.select({
label: 'Style Variant',
description: 'Visual style and animations for this menu item',
defaultValue: 'default',
options: [
{ label: 'Default', value: 'default' },
{ label: 'Advanced Warhammer Quest', value: 'awq' },
{ label: 'The Metatron', value: 'meta' },
{ label: 'Kitchensink', value: 'kitchensink' },
{ label: 'Worldburner', value: 'worldburner' },
{ label: 'Chainbreaker', value: 'chainbreaker' },
],
}),
background: fields.image({
label: 'Background Image',
description: 'Optional background image for this menu area',
directory: 'public/images/categories',
publicPath: '/images/categories',
}),
sublinks: fields.conditional(
fields.checkbox({ label: 'Show Sublinks' }),
{
false: fields.empty(),
true: fields.array(
fields.object({
name: fields.text({
label: 'Name',
validation: { isRequired: true },
}),
path: fields.url({
label: 'Path',
validation: { isRequired: true },
}),
}),
{
label: 'Sub Navigation Items',
itemLabel: (props) =>
props.fields.name.value || 'Untitled Sub Item',
}
),
}
),
subtitle: fields.conditional(
fields.checkbox({ label: 'Show Subtitle' }),
{
false: fields.empty(),
true: fields.object({
content: fields.text({
label: 'Subtitle Text',
validation: { isRequired: true },
}),
divider: fields.conditional(
fields.checkbox({
label: 'Show Divider',
defaultValue: false,
}),
{
true: fields.text({
label: 'Symbol',
description: 'Decorative symbol (e.g., ⚡, ◆, ▲)',
defaultValue: '◆',
}),
false: fields.empty(),
}
),
}),
}
),
}),
{
label: 'Menu Items',
itemLabel: (props) =>
`${props.fields.name.value || 'Untitled'} (${props.fields.gridPosition.value || 'No Position'})`,
}
),
},
});

View File

@@ -1,5 +1,5 @@
module.exports = {
alpharize: (color: string, opacity: number) => {
return `oklch(from ${color} l c h / ${opacity}`;
return `oklch(from ${color} l c h / ${opacity})`;
},
};

6
src/lib/readers/base.ts Normal file
View File

@@ -0,0 +1,6 @@
import { createReader } from '@keystatic/core/reader';
import { cache } from 'react';
import keystaticConfig from '~/keystatic.config';
export const reader = createReader(process.cwd(), keystaticConfig);
export { cache };

View File

@@ -0,0 +1,5 @@
import { cache, reader } from '../base';
export const getNavigationData = cache(async () => {
return await reader.singletons.navigation.read();
});

View File

@@ -0,0 +1,70 @@
export type MenuVariant =
| 'default'
| 'awq'
| 'meta'
| 'kitchensink'
| 'worldburner'
| 'chainbreaker';
export type GridPosition =
| 'area_1'
| 'area_2'
| 'area_3'
| 'area_4'
| 'area_5'
| '';
export interface SubNavigationItem {
readonly name: string;
readonly path: string;
}
export interface Subtitle {
readonly content: string;
readonly divider:
| { readonly discriminant: true; readonly value: string }
| { readonly discriminant: false };
}
export interface NavigationItem {
readonly name: string;
readonly path: string;
readonly gridPosition: GridPosition;
readonly variant: MenuVariant;
readonly background: string | null;
readonly sublinks:
| { readonly discriminant: false }
| {
readonly discriminant: true;
readonly value: readonly SubNavigationItem[];
};
readonly subtitle:
| { readonly discriminant: false }
| { readonly discriminant: true; readonly value: Subtitle };
}
export interface Navigation {
readonly items: readonly NavigationItem[];
}
// Type guards for conditional fields
export function hasSublinks(item: NavigationItem): item is NavigationItem & {
readonly sublinks: {
readonly discriminant: true;
readonly value: readonly SubNavigationItem[];
};
} {
return item.sublinks.discriminant === true;
}
export function hasSubtitle(item: NavigationItem): item is NavigationItem & {
readonly subtitle: { readonly discriminant: true; readonly value: Subtitle };
} {
return item.subtitle.discriminant === true;
}
export function hasDivider(subtitle: Subtitle): subtitle is Subtitle & {
readonly divider: { readonly discriminant: true; readonly value: string };
} {
return subtitle.divider.discriminant === true;
}

View File

@@ -0,0 +1,8 @@
export const mapClassnames = (
classnames: readonly string[],
styles: Record<string, string>
) =>
classnames
.map((cn) => styles[cn])
.filter(Boolean)
.join(' ');

View File

@@ -1,13 +0,0 @@
html {
font-size: var(--font-size-base);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: var(--font-geist-sans);
font-weight: var(--typo-weight-normal);
color: var(--color-text-primary);
background-color: var(--color-surface-base);
}

View File

@@ -1,370 +0,0 @@
/*
Foundation inspired by Tailwind CSS Preflight. (https://tailwindcss.com/docs/preflight)
*/
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-style: solid; /* 2 */
border-width: 0; /* 2 */
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the system's `sans` font-family by default.
*/
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
line-height: 1.5; /* 1 */
text-size-adjust: 100%; /* 2 */
tab-size: 4; /* 3 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
border-top-width: 1px; /* 3 */
color: inherit; /* 2 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the system's `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
border-collapse: collapse; /* 3 */
border-color: inherit; /* 2 */
text-indent: 0; /* 1 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
margin: 0; /* 2 */
padding: 0; /* 3 */
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
appearance: auto; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type="search"] {
appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
font: inherit; /* 2 */
appearance: auto; /* 1 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
margin: 0;
padding: 0;
list-style: none;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
*/
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden] {
display: none;
}

View File

@@ -0,0 +1,418 @@
@layer animations {
:root {
/* === IMAGE ANIMATION VARIABLES === */
--img-overexposure-duration: 0.3s;
--img-overexposure-timing: ease-out forwards;
--img-contrastslam-duration: 0.1s;
--img-contrastslam-timing: steps(3, end);
--img-colorbleed-duration: 0.5s;
--img-colorbleed-timing: steps(6, end) forwards;
--img-filmburn-duration: 0.4s;
--img-filmburn-timing: steps(4, end) forwards;
--img-malfunction-duration: 0.6s;
--img-malfunction-timing: steps(6, end) forwards;
--img-tonerstarvation-duration: 0.5s;
--img-tonerstarvation-timing: steps(5, end) forwards;
--img-corruption-duration: 0.4s;
--img-corruption-timing: steps(8, end) forwards;
--img-starkflash-duration: 0.2s;
--img-starkflash-timing: linear forwards;
/* == Base filter values == */
--base-grayscale: 100;
--base-contrast: 150;
--base-brightness: 120;
/* === TEXT ANIMATION VARIABLES === */
/* == Strike Variables == */
--strike-color: var(--color-primary);
--strike-duration: 0.3s;
--strike-timing: cubic-bezier(0.4, 0, 0.2, 1);
--strike-radius: 50% / 0.25em 0.5em 0.9em 0.7em;
--strike-border-width: 0.25em;
--strike-height: 0.1875em;
/* == Marker Highlight Variables == */
--marker-bg: var(--color-surface-inverse);
--marker-fg: var(--color-text-inverse);
--marker-duration: 0.4s;
--marker-timing: cubic-bezier(0.68, -0.55, 0.265, 1.55);
/* == Label Maker Variables == */
--label-duration: 0.1s;
--label-timing: cubic-bezier(0.68, -0.55, 0.265, 1.55);
--label-bg: var(--color-surface-inverse);
--label-fg: var(--color-text-inverse);
--label-margin: -0.2em -0.4em;
--label-padding: 0.2em 0.4em;
--label-border-width: 0.125em;
--label-weight: bold;
--label-transform: uppercase;
--label-spacing: 0.05em;
--label-shadow-offset: 0.125em 0.125em;
--label-shadow-color: alpharize(var(--label-bg), 0.3);
/* == Rubber Stamp Variables == */
--stamp-duration: 0.08s;
--stamp-timing: steps(2, end);
--stamp-bg: var(--color-surface-inverse);
--stamp-fg: var(--color-text-inverse);
--stamp-rotate: -2deg;
--stamp-scale: 0.95;
--stamp-translate: 1px;
--stamp-margin: -0.2em -0.4em;
--stamp-padding: 0.2em 0.4em;
--stamp-border-width: 0.25em;
--stamp-weight: 900;
--stamp-transform: uppercase;
--stamp-spacing: 0.2em;
--stamp-shadow-offset: 0.125em 0.125em;
--stamp-shadow-color: alpharize(var(--stamp-fg), 0.8);
/* Press Stamp Variables */
--press-duration: 0.06s;
--press-timing: c linear;
--press-bg: var(--color-surface-elevated-4);
--press-fg: var(--color-text-inverse);
--press-scale-y: 0.85;
--press-scale-x: 1.05;
--press-translate: 3px;
--press-margin: -0.05em -0.15em;
--press-padding: 0.05em 0.15em;
--press-weight: 900;
--press-spacing: 0.1em;
--press-border-color: var(--color-surface-elevated-4);
--press-shadow-1: var(--color-surface-inverse);
--press-shadow-2: alpharize(var(--stamp-fg), 0.7);
/* Typewriter Variables */
--typewriter-color: var(--color-text-primary);
--typewriter-duration: 0.6s;
--typewriter-timing: steps(15, end);
--typewriter-offset: -3px;
--typewriter-height: 2px;
--typewriter-dash-length: 0.4em;
--typewriter-gap-length: 0.45em;
/* Hard Invert Variables */
--invert-duration: 0.8s;
--invert-timing: steps(2, end);
--invert-bg: var(--color-surface-inverse);
--invert-fg: var(--color-text-inverse);
--invert-scale: 1.02;
--invert-weight: 900;
--invert-spacing: 0.05em;
/* Pointer Variables */
--pointer-color: inherit;
--pointer-transition: all 0.3s ease-out;
--pointer-left-symbol: '[';
--pointer-right-symbol: ']';
--pointer-distance: 0.375em;
/* Corner Box Variables */
--corner-margin: -0.3em;
--corner-padding: 0.3em;
--corner-size: 0.5em;
--corner-border: 2px solid var(--color-text-primary);
--corner-transition: all 0.75s ease-out;
--corner-font-weight: 600;
/* Character Glitch Variables */
--glitch-duration: 0.3s;
--glitch-timing: steps(8, end);
--glitch-text-shadow-1: 2px 0 var(--color-palette-heliotrope), -2px 0 var(--color-palette-electric-blue);
--glitch-text-shadow-2: 1px 0 var(--color-palette-ruby), -1px 0 var(--color-palette-electric-green);
--glitch-fg-step: var(--color-text-inverse);
--glitch-bg-step: var(--color-surface-inverse);
/* Pixel Shift Variables */
--pixel-bg: var(--color-surface-inverse);
--pixel-fg: var(--color-text-inverse);
--pixel-duration: 0.5s;
--pixel-timing: steps(2, start) forwards;
--pixel-line-height: 0.5em;
--pixel-text-shadow: 2px 0 var(--color-primary), -1px 0 var(--color-secondary);
--pixel-line-color-step: var(--color-primary);
--pixel-line-color-end: var(--color-text-inverse);
/* Redacted Variables */
--redacted-bg: var(--color-text-primary);
--redacted-duration: 0.4s;
--redacted-timing: steps(3, end);
--redacted-shadow: 0 0 8px alpharize(var(--color-palette-woodsmoke), 0.5);
/* X-Ray Variables */
--xray-duration: 0.2s;
--xray-timing: steps(3, end);
--xray-bg: var(--color-palette-ice-blue);
--xray-fg: var(--color-text-inverse);
--xray-weight: 900;
--xray-glow: var(--color-surface-inverse);
--xray-invert: 1;
--xray-contrast: 300%;
--xray-brightness: 150%;
--xray-saturate: 0;
--xray-border: var(--color-surface-inverse);
--xray-outer-glow: alpharize(var(--color-palette-ice-blue), 0.5);
/* === KEYFRAME NAME VARIABLES === */
--kf-overexposure: overexposure;
--kf-color-bleed: color-bleed;
--kf-film-burn: film-burn;
--kf-malfunction: malfunction;
--kf-toner-fade: toner-fade;
--kf-digital-corrupt: digital-corrupt;
--kf-stark-flash: stark-flash;
--kf-bd-overexposure: bd-overexposure;
--kf-bd-color-bleed: bd-color-bleed;
--kf-bd-film-burn: bd-film-burn;
--kf-bd-malfunction: bd-malfunction;
--kf-bd-toner-fade: bd-toner-fade;
--kf-bd-digital-corrupt: bd-digital-corrupt;
--kf-bd-stark-flash: bd-stark-flash;
--kf-strike-slam: strike-slam;
--kf-text-glitch: text-glitch;
--kf-char-scramble: char-scramble;
--kf-glitch-line: glitch-line;
--kf-text-entry-glitch: text-entry-glitch;
}
/* === IMAGE KEYFRAMES === */
@keyframes overexposure {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
50% { filter: grayscale(var(--base-grayscale)) contrast(100%) brightness(350%); }
100% { filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(180%); }
}
@keyframes color-bleed {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
16% { filter: grayscale(0.7) contrast(200%) brightness(180%) saturate(300); }
33% { filter: grayscale(0.4) contrast(300%) brightness(150%) saturate(500) hue-rotate(15deg); }
50% { filter: grayscale(0.8) contrast(250%) brightness(200%) saturate(400) hue-rotate(-10deg); }
66% { filter: grayscale(0.3) contrast(400%) brightness(160%) saturate(600) hue-rotate(25deg); }
83% { filter: grayscale(0.6) contrast(300%) brightness(180%) saturate(300) hue-rotate(-5deg); }
100% { filter: grayscale(0.5) contrast(250%) brightness(170%) saturate(400); }
}
@keyframes film-burn {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
25% { filter: invert(1) contrast(200%) brightness(150%); }
50% { filter: grayscale(var(--base-grayscale)) contrast(300%) brightness(80%); }
75% { filter: grayscale(var(--base-grayscale)) contrast(100%) brightness(250%); }
100% { filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(160%); }
}
@keyframes malfunction {
0% {
transform: scaleX(1);
filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness));
}
16% {
transform: scaleX(0.95) translateX(2px);
filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(200%);
}
33% {
transform: scaleX(1.05) translateX(-2px);
filter: grayscale(var(--base-grayscale)) contrast(300%) brightness(80%);
}
50% {
transform: scaleX(0.98) translateX(1px);
filter: grayscale(var(--base-grayscale)) contrast(100%) brightness(250%);
}
66% {
transform: scaleX(1.02) translateX(-1px);
filter: grayscale(var(--base-grayscale)) contrast(250%) brightness(100%);
}
100% {
transform: scaleX(1) translateX(0);
filter: grayscale(var(--base-grayscale)) contrast(180%) brightness(140%);
}
}
@keyframes toner-fade {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
20% { filter: grayscale(var(--base-grayscale)) contrast(80%) brightness(180%); }
40% { filter: grayscale(var(--base-grayscale)) contrast(50%) brightness(220%); }
60% { filter: grayscale(var(--base-grayscale)) contrast(100%) brightness(160%); }
80% { filter: grayscale(var(--base-grayscale)) contrast(120%) brightness(140%); }
100% { filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(130%); }
}
@keyframes digital-corrupt {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
12.5% { filter: grayscale(var(--base-grayscale)) contrast(300%) brightness(50%) blur(1px); }
25% { filter: grayscale(var(--base-grayscale)) contrast(80%) brightness(300%) saturate(2); }
37.5% { filter: grayscale(var(--base-grayscale)) contrast(400%) brightness(80%) hue-rotate(180deg); }
50% { filter: grayscale(var(--base-grayscale)) contrast(100%) brightness(400%) invert(0.3); }
62.5% { filter: grayscale(var(--base-grayscale)) contrast(500%) brightness(60%); }
75% { filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(200%) blur(0.5px); }
87.5% { filter: grayscale(var(--base-grayscale)) contrast(180%) brightness(150%); }
100% { filter: grayscale(var(--base-grayscale)) contrast(200%) brightness(140%); }
}
@keyframes stark-flash {
0% { filter: grayscale(var(--base-grayscale)) contrast(var(--base-contrast)) brightness(var(--base-brightness)); }
30% { filter: grayscale(var(--base-grayscale)) contrast(800%) brightness(800%) invert(1); }
70% { filter: grayscale(var(--base-grayscale)) contrast(600%) brightness(600%); }
100% { filter: grayscale(var(--base-grayscale)) contrast(300%) brightness(180%); }
}
/* === TEXT KEYFRAMES === */
@keyframes strike-slam {
0% {
left: 0;
width: 0%;
}
100% {
left: -0.125em;
width: calc(100% + 0.25em);
}
}
@keyframes text-glitch {
0% {
transform: translateX(0);
color: var(--color-palette-light-silver);
}
50% {
transform: translateX(-2px);
color: var(--pixel-fg);
text-shadow: var(--pixel-text-shadow);
}
100% {
transform: translateX(0);
color: var(--pixel-fg);
}
}
@keyframes char-scramble {
0% {
transform: translateX(0);
text-shadow: none;
filter: none;
}
12.5% {
font-family: monospace;
text-shadow: var(--glitch-text-shadow-1);
}
25% {
transform: translateX(2px);
filter: contrast(200%) brightness(150%);
}
37.5% {
transform: translateX(-1px) scaleY(1.1);
letter-spacing: 0.2em;
}
50% {
transform: translateX(1px) scaleX(0.9);
color: var(--glitch-fg-step);
background: var(--glitch-bg-step);
}
62.5% {
transform: translateX(-2px);
filter: invert(1) contrast(300%);
}
75% {
transform: translateX(1px);
text-shadow: var(--glitch-text-shadow-2);
}
87.5% {
letter-spacing: 0.1em;
filter: contrast(150%) brightness(120%);
}
100% {
transform: translateX(0);
color: var(--color-text-primary);
text-shadow: none;
filter: none;
}
}
@keyframes glitch-line {
0% {
transform: translateX(0) scaleX(1);
opacity: 0;
}
50% {
transform: translateX(3px) scaleX(0.7);
opacity: 1;
background: var(--pixel-line-color-step);
}
100% {
transform: translateX(0) scaleX(1);
opacity: 1;
background: var(--pixel-line-color-end);
}
}
}
@keyframes text-entry-glitch {
0% {
transform: translateX(-10px) scale(0.8);
color: transparent;
opacity: 0;
filter: blur(2px);
}
25% {
transform: translateX(3px) scale(1.05);
color: var(--color-palette-light-silver);
text-shadow: 2px 0 var(--color-primary), -1px 0 var(--color-secondary);
opacity: 0.7;
filter: blur(1px);
}
50% {
transform: translateX(-2px) scale(0.95);
color: var(--pixel-fg);
text-shadow: var(--pixel-text-shadow);
opacity: 0.9;
filter: blur(0.5px);
}
75% {
transform: translateX(1px) scale(1.02);
color: var(--color-text-inverse);
text-shadow: 1px 0 var(--color-primary);
opacity: 1;
filter: none;
}
100% {
transform: translateX(0) scale(1);
color: var(--pixel-line-color-end);
text-shadow: none;
opacity: 1;
filter: none;
}
}

View File

@@ -0,0 +1,16 @@
@layer base {
html {
font-size: var(--font-size-base);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: var(--font-geist-sans);
font-weight: var(--typo-weight-normal);
color: var(--color-text-primary);
background-color: var(--color-surface-base);
}
}

View File

@@ -0,0 +1,155 @@
@layer tokens {
:root {
/* === Default Palette === */
/* == Blacks, Grays & Off-Whites == */
--color-palette-woodsmoke: oklch(15.5% 0.009 274.276deg); /* Woodsmoke: #0B0C10 */
--color-palette-black-ink: oklch(21.9% 0.006 285.911deg); /* Shark: #1A1A1D */
--color-palette-charcoal: oklch(26.6% 0.008 240.166deg); /* Shark2: #222629 */
--color-palette-charcoal-gray: oklch(33.7% 0.026 266.801deg); /* Bright Gray: #313745 */
--color-palette-slate-gray: oklch(33.3% 0 89.876deg); /* Mineshaft: #363636 */
--color-palette-gunmetal: oklch(41.1% 0.008 248.035deg); /* Abbey2: #474B4F */
--color-palette-carbon: oklch(39.8% 0 89.876deg); /* Tundora: #474747 */
--color-palette-steel-gray: oklch(42.5% 0.003 286.26deg); /* Abbey: #4e4e50 */
--color-palette-dusty-black: oklch(43.7% 0.013 17.672deg); /* DonJuan: #594F4F */
--color-palette-stone: oklch(64.3% 0.005 91.471deg); /* Natural Gray: #8E8D8A */
--color-palette-cloud-gray: oklch(53.6% 0.005 236.565deg); /* Nevada: #6B6E70 */
--color-palette-silver: oklch(72.9% 0.001 17.185deg); /* Silver Chalice: #A8A7A7 */
--color-palette-light-silver: oklch(82.6% 0.002 247.844deg); /* Silversand: #C5C6C7 */
--color-palette-pale-gray: oklch(91.3% 0.004 91.449deg); /* Westar: #E3E2DF */
--color-palette-pale-stone: oklch(89.7% 0.004 106.481deg); /* Quillgray: #DDDDDA */
--color-palette-very-pale-gray: oklch(94.3% 0 89.876deg); /* Gallery: #ECECEC */
--color-palette-off-white: oklch(98.1% 0.003 247.858deg); /* Catskill White: #F7F9fB */
--color-palette-cat-squeeze: oklch(98.3% 0.004 236.496deg); /* Cat Squeeze: #F7FAFC */
/* == Reds == */
--color-palette-oxblood: oklch(30.5% 0.122 12.109deg); /* Bordeaux: #5D001E */
--color-palette-deep-maroon: oklch(37.6% 0.109 11.682deg); /* Crown of Thorns: #6F2232 */
--color-palette-crimson: oklch(43.2% 0.169 7.14deg); /* Monarch: #950740 */
--color-palette-cherry-red: oklch(45.4% 0.168 1.454deg); /* Disco: #9A1750 */
--color-palette-ruby: oklch(52.1% 0.206 15.782deg); /* Shiraz: #C3073F */
--color-palette-red-clay: oklch(65.1% 0.178 27.507deg); /* Burnt Sienna: #E85A4F */
--color-palette-lava: oklch(63.6% 0.193 17.075deg); /* Mandy: #E84A5F */
--color-palette-vivid-scarlet: oklch(66.6% 0.221 15.669deg); /* Radical Red: #FE4365 */
/* == Pinks & Magentas == */
--color-palette-heliotrope: oklch(68.3% 0.217 353.666deg); /* Heliotrope: #F74FA3 */
--color-palette-hot-pink: oklch(65.4% 0.2 6.69deg); /* French Rose: #EE4C7C */
--color-palette-cerise: oklch(60.7% 0.23 18.554deg); /* Amaranth: #EC2049 */
--color-palette-fuchsia: oklch(49.6% 0.181 351.176deg); /* Hibiscus: #A7226E */
--color-palette-dusty-rose: oklch(63.2% 0.11 2.384deg); /* Turkish Rose: #C06C84 */
--color-palette-berry: oklch(60.8% 0.159 2.621deg); /* Mulberry: #CC527A */
--color-palette-petal-pink: oklch(80.5% 0.063 1.992deg); /* Rose Fog: #E3AFBC */
--color-palette-coral-pink: oklch(71.2% 0.162 15.607deg); /* Froly: #F67280 */
--color-palette-sweet-pink: oklch(79.2% 0.114 21.911deg); /* Sweet Pink: #FC9D9A */
/* == Oranges & Browns == */
--color-palette-persimmon: oklch(68.6% 0.179 40.01deg); /* Flamingo: #F26B38 */
--color-palette-terracotta: oklch(71.3% 0.131 27.646deg); /* Apricot: #E98074 */
--color-palette-tan: oklch(82.7% 0.047 76.752deg); /* Akaroa: #D8C3A5 */
--color-palette-peach: oklch(88.5% 0.072 57.746deg); /* Flesh: #FECEAB */
--color-palette-pastel-orange: oklch(82.1% 0.092 42.408deg); /* Rosebud: #F8B195 */
--color-palette-light-apricot: oklch(87.8% 0.066 57.778deg); /* Vivid Tangerine: #F9CDAD */
--color-palette-bone-white: oklch(92.7% 0.015 94.206deg); /* Satin Linen: #EAE7DC */
/* == Yellows == */
--color-palette-ripe-lemon: oklch(83.9% 0.167 91.469deg); /* Ripe Lemon: #F2C51D */
--color-palette-bright-canary: oklch(89% 0.157 97.726deg); /* Energy Yellow: #F7DB4F */
--color-palette-pale-lemon: oklch(95.6% 0.104 121.573deg); /* Mimosa: #E5FCAD */
/* == Greens == */
--color-palette-forest-green: oklch(58.1% 0.127 130.001deg); /* Crete: #61892F */
--color-palette-lime-green: oklch(74.6% 0.18 129.939deg); /* Atlantis: #86C232 */
--color-palette-electric-green: oklch(87.7% 0.227 137.099deg); /* Screaming Green: #87f74f */
--color-palette-sage: oklch(75.1% 0.056 144.175deg); /* Norway: #87f74f */
--color-palette-mint-green: oklch(84.8% 0.098 151.333deg); /* Chinook: #9de0ad */
--color-palette-olive-drab: oklch(82.5% 0.042 107.285deg); /* Olive Drap: #C8C8A9 */
--color-palette-seafoam: oklch(71.6% 0.056 165.214deg); /* Acapulco: #83AF9B */
/* == Blues & Teals == */
--color-palette-dark-navy: oklch(27.3% 0.024 253.693deg); /* Ebony Clay: #1F2833 */
--color-palette-deep-teal: oklch(32.4% 0.018 225.132deg); /* Outer Space: #2A363B */
--color-palette-royal-blue: oklch(46.1% 0.07 245.64deg); /* Ming: #355C7D */
--color-palette-sky-blue: oklch(76.3% 0.129 233.891deg); /* Picton Blue: #4FBFF7 */
--color-palette-slate-blue: oklch(55.1% 0.043 210.602deg); /* Cutty Sark: #547980 */
--color-palette-turquoise: oklch(61.5% 0.091 198.865deg); /* Lochinvar: #2F9599 */
--color-palette-aqua: oklch(68.6% 0.095 190.758deg); /* Keppel: #45ADA8 */
--color-palette-electric-blue: oklch(90.8% 0.128 188.419deg); /* Aquamarine: #66FCF1 */
--color-palette-powder-blue: oklch(88.2% 0.062 187.276deg); /* Powder Blue: #a9e6df */
--color-palette-ice-blue: oklch(99.9% 0.001 197.139deg); /* Twilight Blue: #feffff */
/* === Semantic Colors === */
/* == Primary Colors == */
--color-primary: var(--color-palette-lava);
--color-primary-surface: oklch(from var(--color-primary) calc(l + 0.1) c h);
--color-primary-emphasis: oklch(from var(--color-primary) calc(l - 0.15) c h);
/* == Secondary Colors == */
--color-secondary: var(--color-palette-slate-blue);
--color-secondary-surface: oklch(from var(--color-secondary) calc(l + 0.1) c h);
--color-secondary-emphasis: oklch(from var(--color-secondary) calc(l - 0.15) c h);
/* == Tertiary Colors == */
--color-tertiary: var(--color-palette-bright-canary);
--color-tertiary-surface: oklch(from var(--color-tertiary) calc(l + 0.1) c h);
--color-tertiary-emphasis: oklch(from var(--color-tertiary) calc(l - 0.15) c h);
/* == Text Base Colors == */
--color-text-primary: var(--color-palette-black-ink); /* Main Body Texts, headlines */
--color-text-secondary: var(--color-palette-charcoal); /* Subheading, Secondary Info */
--color-text-tertiary: var(--color-palette-charcoal-gray); /* Captions, Meta Text */
--color-text-quarternary: var(--color-palette-carbon); /* Placeholder Text */
--color-text-inverse: var(--color-palette-ice-blue); /* Text on dark backgrounds */
--color-text-disabled: var(--color-palette-cloud-gray); /* Disabled form labels, inactive text */
/* == Surface Base Colors == */
--color-surface-base: var(--color-palette-ice-blue); /* Main page background */
--color-surface-elevated-1: var(--color-palette-off-white); /* Cards, Panels */
--color-surface-elevated-2: var(--color-palette-very-pale-gray); /* Modals, Dropdowns */
--color-surface-elevated-3: var(--color-palette-pale-gray); /* Tooltips, popovers */
--color-surface-elevated-4: var(--color-palette-light-silver); /* Highest Elevation */
--color-surface-inverse: var(--color-palette-black-ink); /* Darkest Surface for Contrast */
/* == Border Base Colors == */
--color-border-subtle: var(--color-palette-silver); /* Subtle Dividers, Card Borders */
--color-border-normal: var(--color-palette-stone); /* Standard Borders, form fields */
--color-border-strong: var(--color-palette-charcoal-gray); /* Emphasized Borders */
/* == State Colors == */
--color-state-error: var(--color-palette-cerise); /* Error Text, Container, icons */
--color-state-warning: var(--color-palette-persimmon); /* Warning Text, Container, Icons */
--color-state-success: var(--color-palette-lime-green); /* Success Text, Container, Icons */
--color-state-info: var(--color-palette-royal-blue); /* Info Text, Container, Icons */
/* == Link Colors == */
--color-text-link: var(--color-text-tertiary);
--color-text-link-hover: var(--color-secondary);
--color-text-link-visited: var(--color-palette-fuchsia);
/* == Focus States == */
--color-focus-ring: var(--color-primary);
--color-focus-ring-offset: var(--color-primary);
--color-focus-indicator: var(--color-primary-emphasis)
/* == Overlays == */;
--color-utility-overlay-light: oklch(15.5% 0.009 274.276deg / 10%); /* Light overlays */
--color-utility-overlay-medium: oklch(15.5% 0.009 274.276deg / 30%); /* Medium overlays */
--color-utility-overlay-heavy: oklch(15.5% 0.009 274.276deg / 60%); /* Heavy overlays, modal backdrops */
--color-surface-overlay: var(--color-utility-overlay-medium); /* Modal overlays, backdrop */
--color-surface-backdrop: var(--color-utility-overlay-heavy); /* Full screen overlays */
/* == Dividers == */
--color-utility-divider: var(--color-border-subtle); /* Section dividers, HR elements */
--color-utility-divider-strong: var(--color-border-normal); /* Emphasized dividers */
/* == Shadows == */
--color-utility-shadow-light: oklch(15.5% 0.009 274.276deg / 10%); /* Drop shadows */
--color-utility-shadow-medium: oklch(15.5% 0.009 274.276deg / 20%); /* Drop shadows */
--color-utility-shadow-strong: oklch(15.5% 0.009 274.276deg / 25%); /* Strong shadows */
/* == Highlights == */
--color-utility-highlight: var(--color-tertiary-surface); /* Text highlighting, search results */
--color-utility-highlight-strong: var(--color-tertiary); /* Strong highlighting */
}
}

View File

@@ -0,0 +1,555 @@
@layer content {
.content {
& h1 {
margin-block: var(--el-h1-vspace-top) var(--el-h1-vspace-bottom);
padding-bottom: var(--spacing-snug);
border-bottom: var(--size-4) solid var(--el-h1-color);
font-family: var(--el-h1-font-family), serif;
font-size: var(--el-h1-font-size);
font-weight: var(--el-h1-font-weight);
line-height: var(--el-h1-line-height);
color: var(--el-h1-color);
text-transform: var(--el-h1-text-transform);
letter-spacing: var(--el-h1-letter-spacing);
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block:
calc(1em * var(--typo-leading-normal) * var(--vspace-tight))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
& + h2 {
margin-block:
calc(1em * var(--el-h1-line-height) * var(--vspace-snug))
calc(1em * var(--el-h1-line-height) * var(--vspace-normal));
}
}
& h2 {
margin-block: var(--el-h2-vspace-top) var(--el-h2-vspace-bottom);
padding-left: var(--spacing-snug);
border-left: var(--size-4) solid var(--el-h2-color);
font-family: var(--el-h2-font-family), serif;
font-size: var(--el-h2-font-size);
font-weight: var(--el-h2-font-weight);
line-height: var(--el-h2-line-height);
color: var(--el-h2-color);
text-transform: var(--el-h2-text-transform);
letter-spacing: var(--el-h2-letter-spacing);
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block:
calc(1em * var(--typo-leading-normal) * var(--vspace-tight))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
& + h3 {
margin-block:
calc(1em * var(--el-h1-line-height) * var(--vspace-compressed))
calc(1em * var(--el-h1-line-height) * var(--vspace-snug));
}
}
& h3 {
margin-block: var(--el-h3-vspace-top) var(--el-h3-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
font-family: var(--el-h3-font-family), serif;
font-size: var(--el-h3-font-size);
font-weight: var(--el-h3-font-weight);
line-height: var(--el-h3-line-height);
color: var(--color-surface-base);
text-transform: var(--el-h3-text-transform);
letter-spacing: var(--el-h3-letter-spacing);
background: var(--el-h3-color);
}
& h4 {
margin-block: var(--el-h4-vspace-top) var(--el-h4-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
border-top: var(--size-3 ) solid var(--el-h4-color);
border-bottom: var(--size-3 ) solid var(--el-h4-color);
font-family: var(--el-h4-font-family), serif;
font-size: var(--el-h4-font-size);
font-weight: var(--el-h4-font-weight);
line-height: var(--el-h4-line-height);
text-transform: var(--el-h4-text-transform);
letter-spacing: var(--el-h4-letter-spacing);
}
& h5 {
margin-block: var(--el-h5-vspace-top) var(--el-h5-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
font-family: var(--el-h5-font-family), serif;
font-size: var(--el-h5-font-size);
font-weight: var(--el-h5-font-weight);
line-height: var(--el-h5-line-height);
color: var(--el-h5-color);
text-transform: var(--el-h5-text-transform);
letter-spacing: var(--el-h5-letter-spacing);
&::before,
&::after {
content: "";
padding-right: var(--spacing-tight);
line-height: 1;
}
&::before {
content: "❭";
}
&::after {
content: "";
}
}
& h6 {
margin-block: var(--el-h6-vspace-top) var(--el-h6-vspace-bottom);
font-family: var(--el-h6-font-family), serif;
font-size: var(--el-h6-font-size);
font-weight: var(--el-h6-font-weight);
line-height: var(--el-h6-line-height);
color: var(--el-h6-color);
text-transform: var(--el-h6-text-transform);
letter-spacing: var(--el-h6-letter-spacing);
}
& h3,
& h4,
& h5,
& h6 {
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block:
calc(1em * var(--typo-leading-normal) * var(--vspace-compressed))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
}
& p {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
font-family: var(--el-p-font-family), sans-serif;
font-size: var(--el-p-font-size);
font-weight: var(--el-p-font-weight);
line-height: var(--el-p-line-height);
color: var(--el-p-color);
text-align: var(--el-p-text-align);
}
& blockquote {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
padding: var(--spacing-snug) 0 var(--spacing-snug) var(--spacing-comfortable);
border-left: var(--size-4) solid var(--color-text-tertiary);
font-family: var(--el-blockquote-font-family), serif;
font-size: var(--el-blockquote-font-size);
font-weight: var(--el-blockquote-font-weight);
font-style: var(--el-blockquote-font-style);
line-height: var(--el-blockquote-line-height);
color: var(--el-blockquote-color);
}
& pre {
margin-block: var(--el-pre-vspace-top) var(--el-pre-vspace-bottom);
padding: var(--spacing-comfortable);
font-family: var(--el-pre-font-family), monospace;
font-size: var(--el-pre-font-size);
line-height: var(--el-pre-line-height);
color: var(--el-pre-color);
background: var(--el-pre-background);
}
& ul,
& ol {
margin-block: var(--el-list-vspace-top) var(--el-list-vspace-bottom);
font-size: var(--el-list-font-size);
line-height: var(--el-list-line-height);
color: var(--el-list-color);
& ul,
& ol {
margin-block: var(--el-list-nested-vspace-top) var(--el-list-nested-vspace-bottom);
}
& li {
margin-block: var(--el-li-vspace-top) var(--el-li-vspace-bottom);
list-style-position: outside;
& li {
margin-block: var(--el-li-nested-vspace-top) var(--el-li-nested-vspace-bottom);
}
}
}
& ul {
padding-left: var(--el-ul-indent-l1);
list-style: none;
& li {
padding-left: var(--el-ul-item-padding);
&::marker {
content: var(--el-ul-symbol-l1);
color: var(--el-ul-symbol-l1-color);
}
}
& ul,
& ol {
padding-left: var(--el-ul-indent-l2);
& li::marker {
content: var(--el-ul-symbol-l2);
color: var(--el-ul-symbol-l2-color);
}
& ul,
& ol {
padding-left: var(--el-ul-indent-l3);
& li::marker {
content: var(--el-ul-symbol-l3);
color: var(--el-ul-symbol-l3-color);
}
& ul,
& ol {
padding-left: var(--el-ul-indent-l4);
& li::marker {
content: var(--el-ul-symbol-l4);
color: var(--el-ul-symbol-l4-color);
}
}
}
}
}
ol {
counter-reset: ol-l1;
contain: style;
padding-left: var(--el-ol-indent-l1);
list-style: none;
& > li {
counter-increment: ol-l1;
margin-left: var(--el-ol-item-indent-l1);
padding-left: var(--el-ol-item-padding);
&::marker {
content: var(--el-ol-prefix-l1) counter(ol-l1, var(--el-ol-style-l1)) var(--el-ol-suffix-l1);
color: var(--el-ol-marker-color-l1);
}
& > ol {
counter-reset: ol-l2;
padding-left: var(--el-ol-indent-l2);
& > li {
counter-increment: ol-l2;
margin-left: var(--el-ol-item-indent-l2);
&::marker {
content: var(--el-ol-prefix-l2) counter(ol-l2, var(--el-ol-style-l2)) var(--el-ol-suffix-l2);
color: var(--el-ol-marker-color-l2);
}
& > ol {
counter-reset: ol-l3;
margin-left: var(--el-ol-item-indent-l3);
padding-left: var(--el-ol-indent-l3);
& > li {
counter-increment: ol-l3;
&::marker {
content: var(--el-ol-prefix-l3) counter(ol-l3, var(--el-ol-style-l3)) var(--el-ol-suffix-l3);
color: var(--el-ol-marker-color-l3);
}
& > ol {
counter-reset: ol-l4;
margin-left: var(--el-ol-item-indent-l4);
padding-left: var(--el-ol-indent-l4);
& > li {
counter-increment: ol-l4;
&::marker {
content: var(--el-ol-prefix-l4) counter(ol-l4, var(--el-ol-style-l4)) var(--el-ol-suffix-l4);
color: var(--el-ol-marker-color-l4);
}
}
}
& > ul {
padding-left: var(--el-ol-indent-l4);
}
}
}
& > ul {
padding-left: var(--el-ol-indent-l3);
}
}
}
& > ul {
padding-left: var(--el-ol-indent-l2);
}
}
}
& dl {
margin-block: var(--el-dl-vspace-top) var(--el-dl-vspace-bottom);
font-size: var(--el-dl-font-size);
line-height: var(--el-dl-line-height);
}
& dt {
margin-block: var(--el-dt-vspace-top) var(--el-dt-vspace-bottom);
padding: var(--el-dt-padding);
font-family: var(--el-dt-font-family), serif;
font-size: var(--el-dt-font-size);
font-weight: var(--el-dt-font-weight);
line-height: var(--el-dt-line-height);
color: var(--el-dt-color);
text-transform: var(--el-dt-text-transform);
letter-spacing: var(--el-dt-letter-spacing);
background: var(--el-dt-background);
}
& dd {
margin-block: var(--el-dd-vspace-top) var(--el-dd-vspace-bottom);
padding: var(--el-dd-indent);
font-family: var(--el-dd-font-family), sans-serif;
font-size: var(--el-dd-font-size);
line-height: var(--el-dd-line-height);
color: var(--el-dd-color);
}
& table {
border-collapse: collapse;
width: 100%;
margin-block: var(--el-table-vspace-top) var(--el-table-vspace-bottom);
border: var(--el-table-border);
font-size: var(--el-table-font-size);
line-height: var(--el-table-line-height);
& thead th,
& th {
padding: var(--el-th-padding);
font-family: var(--el-th-font-family), serif;
font-size: var(--el-th-font-size);
font-weight: var(--el-th-font-weight);
line-height: var(--el-th-line-height);
color: var(--el-th-color);
text-transform: var(--el-th-text-transform);
background: var(--el-th-background);
}
& tbody td,
& td {
padding: var(--el-td-padding);
border: var(--el-td-border);
font-family: var(--el-td-font-family), monospace;
font-size: var(--el-td-font-size);
line-height: var(--el-td-line-height);
color: var(--el-td-color);
text-align: center;
}
}
& hr{
position: relative;
overflow: visible;
height: var(--hr-height);
margin-block: var(--hr-margin);
border: none;
background: var(--hr-color);
&::after {
content: var(--hr-symbol-content);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: var(--hr-symbol-space);
font-size: var(--hr-symbol-size);
line-height: var(--hr-symbol-line-height);
color: var(--hr-symbol-color);
background: var(--hr-symbol-background);
}
}
& em,
& i {
padding: 0.1em 0.2em;
font-style: normal;
color: var(--color-text-inverse);
background: var(--color-surface-inverse);
}
& strong,
& b {
font-weight: var(--typo-weight-black);
letter-spacing: var(--typo-spacing-relaxed);
}
a {
@mixin anim-txt-pixelshift 0.6s steps(15, end), var(--color-primary);
color: var(--color-text-tertiary);
transition: color 0.2s ease-in-out;
&:hover {
cursor: pointer;
color: var(--color-primary);
}
&:visited,
&:active {
color: var(--color-primary-emphasis);
}
}
& code {
padding: 0.1em 0.3em;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-inverse);
background: var(--color-surface-inverse);
}
& kbd {
padding: 0.1em 0.3em;
border: 1px solid var(--color-text-primary);
border-radius: 2px;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-xs);
color: var(--color-text-inverse);
text-transform: uppercase;
background: var(--color-surface-inverse);
}
& samp {
padding: 0.1em 0.3em;
border-left: var(--size-1) solid var(--color-text-tertiary);
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-primary);
background: var(--color-surface-elevated-2);
}
& var {
font-family: var(--font-mono), monospace;
font-weight: var(--typo-weight-semibold);
font-style: normal;
color: var(--color-text-secondary);
}
& small {
font-size: var(--typo-size-xs);
color: var(--color-text-tertiary);
}
& sub,
& sup {
font-size: var(--typo-size-2xs);
font-weight: var(--typo-weight-semibold);
color: var(--color-text-secondary);
}
& del,
& s {
color: var(--color-text-disabled);
text-decoration: line-through;
text-decoration-thickness: var(--size-1);
}
& ins {
font-weight: var(--typo-weight-semibold);
color: var(--color-text-primary);
text-decoration: underline;
text-decoration-color: var(--color-primary);
text-decoration-thickness: var(--size-1);
background: transparent;
}
& abbr {
cursor: help;
text-decoration: underline dotted;
text-underline-offset: var(--size-1);
}
& dfn {
font-weight: var(--typo-weight-bold);
font-style: normal;
color: var(--color-text-primary);
}
& cite {
font-weight: var(--typo-weight-semibold);
font-style: normal;
color: var(--color-text-secondary);
}
& q {
font-style: normal;
&::before {
content: "»";
}
&::after {
content: "«";
}
}
& time {
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-secondary);
}
}
}

View File

@@ -0,0 +1,7 @@
@layer tokens {
@custom-media --bp-mobile (width < 48rem);
@custom-media --bp-tablet (width >= 48rem) and (width < 80rem);
@custom-media --bp-tablet-up (width >= 48rem);
@custom-media --bp-tablet-down (width < 80rem);
@custom-media --bp-desktop (width >= 80rem);
}

View File

@@ -0,0 +1,95 @@
@layer tokens {
:root {
/* === DIMENSIONS === */
/* == Base Size Units == */
--size-0: 0;
--size-px: 1px;
--size-05: 0.125rem;
--size-1: 0.25rem;
--size-2: 0.5rem;
--size-3: 0.75rem;
--size-4: 1rem;
--size-5: 1.25rem;
--size-6: 1.5rem;
--size-8: 2rem;
--size-10: 2.5rem;
--size-12: 3rem;
--size-16: 4rem;
--size-20: 5rem;
--size-24: 6rem;
--size-32: 8rem;
--size-40: 10rem;
--size-48: 12rem;
--size-64: 16rem;
--size-80: 20rem;
--size-96: 24rem;
--size-128: 32rem;
--size-160: 40rem;
--size-192: 48rem;
--size-256: 64rem;
--size-320: 80rem;
--size-384: 96rem;
--size-360: 90rem;
--size-400: 100rem;
--size-480: 120rem;
/* == Flexible Dimensions == */
--dim-full: 100%;
--dim-1-2: 50%;
--dim-1-3: 33.3333%;
--dim-2-3: 66.6667%;
--dim-1-4: 25%;
--dim-2-4: var(--dim-1-2);
--dim-3-4: 75%;
--dim-1-5: 20%;
--dim-2-5: 40%;
--dim-3-5: 60%;
--dim-4-5: 80%;
--dim-1-6: 16.6667%;
--dim-2-6: var(--dim-1-3);
--dim-3-6: var(--dim-1-2);
--dim-4-6: var(--dim-2-3);
--dim-5-6: 83.3333%;
--dim-1-8: 12.5%;
--dim-2-8: var(--dim-1-4);
--dim-3-8: 37.5%;
--dim-4-8: var(--dim-1-2);
--dim-5-8: 62.5%;
--dim-6-8: var(--dim-3-4);
--dim-7-8: 87.5%;
--dim-1-10: 10%;
--dim-2-10: var(--dim-1-5);
--dim-3-10: 30%;
--dim-4-10: var(--dim-2-5);
--dim-5-10: var(--dim-1-2);
--dim-6-10: var(--dim-3-5);
--dim-7-10: 70%;
--dim-8-10: var(--dim-4-5);
--dim-9-10: 90%;
--dim-1-12: 8.3333%;
--dim-2-12: var(--dim-1-6);
--dim-3-12: var(--dim-1-4);
--dim-4-12: var(--dim-1-3);
--dim-5-12: 41.6667%;
--dim-6-12: var(--dim-1-2);
--dim-7-12: 58.3333%;
--dim-8-12: var(--dim-2-3);
--dim-9-12: var(--dim-3-4);
--dim-10-12: 83.3333%;
--dim-11-12: 91.6667%;
/* == Semantic Spacing == */;
--spacing-none: var(--size-0);
--spacing-hairline: var(--size-px);
--spacing-tight: var(--size-1);
--spacing-snug: var(--size-2);
--spacing-cozy: var(--size-4);
--spacing-comfortable: var(--size-6);
--spacing-relaxed: var(--size-8);
--spacing-spacious: var(--size-12);
--spacing-generous: var(--size-16);
--spacing-luxurious: var(--size-24);
--spacing-expansive: var(--size-32);
}
}

View File

@@ -0,0 +1,266 @@
@layer tokens {
:root {
/* === H1 VARIABLES === */
--el-h1-color: var(--color-text-primary);
--el-h1-font-family: var(--font-display);
--el-h1-font-size: var(--typo-size-7xl);
--el-h1-font-weight: var(--typo-weight-black);
--el-h1-letter-spacing: -0.0137em;
--el-h1-line-height: 1.125;
--el-h1-text-transform: uppercase;
--el-h1-vspace-base: calc(1em * var(--el-h1-line-height));
--el-h1-vspace-top: calc(var(--el-h1-vspace-base) * var(--vspace-spacious));
--el-h1-vspace-bottom: calc(var(--el-h1-vspace-base) * var(--vspace-comfortable));
/* === H2 VARIABLES === */
--el-h2-color: var(--color-text-primary);
--el-h2-font-family: var(--font-header);
--el-h2-font-size: var(--typo-size-5xl);
--el-h2-font-weight: var(--typo-weight-black);
--el-h2-letter-spacing: -0.0096em;;
--el-h2-line-height: 1.1765;
--el-h2-text-transform: uppercase;
--el-h2-vspace-base: calc(1em * var(--el-h2-line-height));
--el-h2-vspace-top: calc(var(--el-h2-vspace-base) * var(--vspace-snug));
--el-h2-vspace-bottom: calc(var(--el-h2-vspace-base) * var(--vspace-compressed));
/* === H3 VARIABLES === */
--el-h3-color: var(--color-text-secondary);
--el-h3-font-family: var(--font-header);
--el-h3-font-size: var(--typo-size-4xl);
--el-h3-font-weight: var(--typo-weight-extrabold);
--el-h3-letter-spacing: -0.004em;
--el-h3-line-height: 1.2;
--el-h3-text-transform: uppercase;
--el-h3-vspace-base: calc(1em * var(--el-h3-line-height));
--el-h3-vspace-top: calc(var(--el-h3-vspace-base) * var(--vspace-cozy));
--el-h3-vspace-bottom: calc(var(--el-h3-vspace-base) * var(--vspace-snug));
/* === H4 VARIABLES === */
--el-h4-color: var(--color-text-secondary);
--el-h4-font-family: var(--font-header);
--el-h4-font-size: var(--typo-size-3xl);
--el-h4-font-weight: var(--typo-weight-extrabold);
--el-h4-letter-spacing: 0.0025em;
--el-h4-line-height: 1.125;
--el-h4-text-transform: uppercase;
--el-h4-vspace-base: calc(1em * var(--el-h4-line-height));
--el-h4-vspace-top: calc(var(--el-h4-vspace-base) * var(--vspace-normal));
--el-h4-vspace-bottom: calc(var(--el-h4-vspace-base) * var(--vspace-tight));
/* === H5 VARIABLES === */
--el-h5-color: var(--color-text-secondary);
--el-h5-font-family: var(--font-header);
--el-h5-font-size: var(--typo-size-2xl);
--el-h5-font-weight: var(--typo-weight-extrabold);
--el-h5-letter-spacing: 0.05em;
--el-h5-line-height: 1.28;
--el-h5-text-transform: uppercase;
--el-h5-vspace-base: calc(1em * var(--el-h5-line-height));
--el-h5-vspace-top: calc(var(--el-h5-vspace-base) * var(--vspace-cozy));
--el-h5-vspace-bottom: calc(var(--el-h5-vspace-base) * var(--vspace-tight));
/* === H6 VARIABLES === */
--el-h6-color: var(--color-text-secondary);
--el-h6-font-family: var(--font-header);
--el-h6-font-size: var(--typo-size-xl);
--el-h6-font-weight: var(--typo-weight-black);
--el-h6-letter-spacing: 0.035em;
--el-h6-line-height: 1.4;
--el-h6-text-transform: uppercase;
--el-h6-vspace-base: calc(1em * var(--el-h6-line-height));
--el-h6-vspace-top: calc(var(--el-h6-vspace-base) * var(--vspace-snug));
--el-h6-vspace-bottom: calc(var(--el-h6-vspace-base) * var(--vspace-compressed));
/* === PARAGRAPH VARIABLES === */
--el-p-color: var(--color-text-primary);
--el-p-font-family: var(--font-body);
--el-p-font-size: var(--typo-size-md);
--el-p-font-weight: var(--typo-weight-regular);
--el-p-line-height: var(--typo-leading-normal);
--el-p-text-align: justify;
--el-p-vspace-base: calc(1em * var(--el-p-line-height));
--el-p-vspace-top: calc(var(--el-p-vspace-base) * var(--vspace-snug));
--el-p-vspace-bottom: calc(var(--el-p-vspace-base) * var(--vspace-snug));
/* === BLOCKQUOTE VARIABLES === */
--el-blockquote-color: var(--color-text-tertiary);
--el-border-color: var(--color-text-tertiary);
--el-blockquote-font-family: var(--font-body);
--el-blockquote-font-size: var(--typo-size-md);
--el-blockquote-font-style: var(--typo-weight-regular);
--el-blockquote-font-weight: var(--typo-weight-medium);
--el-blockquote-line-height: var(--typo-leading-comfortable);
--el-blockquote-vspace-base: calc(1em * var(--el-blockquote-line-height));
--el-blockquote-vspace-top: calc(var(--el-blockquote-vspace-base) * var(--vspace-snug));
--el-blockquote-vspace-bottom: calc(var(--el-blockquote-vspace-base) * var(--vspace-snug));
/* === PRE VARIABLES === */
--el-pre-color: var(--color-text-inverse);
--el-pre-background: var(--color-surface-inverse);
--el-pre-font-family: var(--font-mono);
--el-pre-font-size: var(--typo-size-sm);
--el-pre-line-height: 1.5385;
--el-pre-vspace-base: calc(1em * var(--el-pre-line-height));
--el-pre-vspace-top: calc(var(--el-pre-vspace-base) * var(--vspace-normal));
--el-pre-vspace-bottom: calc(var(--el-pre-vspace-base) * var(--vspace-normal));
/* === CODE VARIABLES === */
--el-code-color: var(--color-text-inverse);
--el-code-background: var(--color-surface-inverse);
--el-code-font-family: var(--font-mono);
--el-code-font-size: var(--typo-size-sm);
/* === List Variables (For UL/OL) === */
--el-list-color: var(--color-text-primary);
--el-list-line-height: var(--typo-leading-normal);
--el-list-font-size: var(--typo-size-md);
--el-list-vspace-base: calc(1em * var(--el-list-line-height));
--el-list-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-nested-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-nested-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-nested-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-tight));
--el-li-nested-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-tight));
/* === UL VARIABLES === */
--el-ul-indent-l1: var(--spacing-cozy);
--el-ul-indent-l2: var(--spacing-cozy);
--el-ul-indent-l3: var(--spacing-cozy);
--el-ul-indent-l4: var(--spacing-cozy);
--el-ul-item-padding: var(--spacing-cozy);
--el-ul-symbol-l1: '⯃';
--el-ul-symbol-l1-color: var(--color-text-primary);
--el-ul-symbol-l2: '⯁';
--el-ul-symbol-l2-color: var(--color-text-primary);
--el-ul-symbol-l3: '⯆';
--el-ul-symbol-l3-color: var(--color-text-primary);
--el-ul-symbol-l4: '⯀';
--el-ul-symbol-l4-color: var(--color-text-primary);
/* === OL VARIABLES === */
--el-ol-indent-l1: var(--spacing-cozy);
--el-ol-item-indent-l1: 1.5em;
--el-ol-indent-l2: var(--spacing-cozy);
--el-ol-item-indent-l2: 0.825em;
--el-ol-indent-l3: var(--spacing-cozy);
--el-ol-item-indent-l3: 0;
--el-ol-indent-l4: var(--spacing-cozy);
--el-ol-item-indent-l4: 0;
--el-ol-item-padding: var(--spacing-cozy);
--el-ol-line-height: var(--typo-leading-normal);
--el-ol-marker-color-l1: var(--color-text-primary);
--el-ol-prefix-l1: '';
--el-ol-style-l1: decimal-leading-zero;
--el-ol-suffix-l1: '.)';
--el-ol-marker-color-l2: var(--color-text-primary);
--el-ol-prefix-l2: '';
--el-ol-style-l2: lower-alpha;
--el-ol-suffix-l2: '.)';
--el-ol-marker-color-l3: var(--color-text-primary);
--el-ol-prefix-l3: '';
--el-ol-style-l3: upper-roman;
--el-ol-suffix-l3: '.)';
--el-ol-marker-color-l4: var(--color-text-primary);
--el-ol-prefix-l4: '';
--el-ol-style-l4: lower-greek;
--el-ol-suffix-l4: '.)';
/* === DL VARIABLES === */
--el-dl-font-size: var(--typo-size-md);
--el-dl-line-height: var(--typo-leading-normal);
--el-dl-vspace-base: calc(1em * var(--el-dl-line-height));
--el-dl-vspace-top: calc(var(--el-dl-vspace-base) * var(--vspace-snug));
--el-dl-vspace-bottom: calc(var(--el-dl-vspace-base) * var(--vspace-compressed));
/* === DT VARIABLES === */
--el-dt-color: var(--color-text-inverse);
--el-dt-background: var(--color-surface-inverse);
--el-dt-font-family: var(--font-header);
--el-dt-font-size: var(--typo-size-lg);
--el-dt-font-weight: var(--typo-weight-bold);
--el-dt-line-height: 1.4;
--el-dt-text-transform: uppercase;
--el-dt-letter-spacing: 0.035em;
--el-dt-padding: var(--spacing-snug);
--el-dt-vspace-base: calc(1em * var(--el-dt-line-height));
--el-dt-vspace-top: calc(var(--el-dt-vspace-base) * var(--vspace-snug));
--el-dt-vspace-bottom: calc(var(--el-dt-vspace-base) * var(--vspace-compressed));
/* === DD VARIABLES === */
--el-dd-color: var(--color-text-primary);
--el-dd-font-family: var(--font-body);
--el-dd-font-size: var(--typo-size-md);
--el-dd-line-height: var(--typo-leading-normal);
--el-dd-indent: 0 var(--spacing-comfortable);
--el-dd-vspace-base: calc(1em * var(--el-dd-line-height));
--el-dd-vspace-top: calc(var(--el-dd-vspace-base) * var(--vspace-compressed));
--el-dd-vspace-bottom: calc(var(--el-dd-vspace-base) * var(--vspace-tight));
/* === TABLE VARIABLES === */
--el-table-font-size: var(--typo-size-sm);
--el-table-line-height: 1.2;
--el-table-border: var(--size-2) solid var(--color-text-primary);
--el-table-vspace-top: var(--spacing-tight);
--el-table-vspace-bottom: var(--spacing-tight);
/* === TH VARIABLES === */
--el-th-color: var(--color-text-inverse);
--el-th-background: var(--color-surface-inverse);
--el-th-font-family: var(--font-header);
--el-th-font-size: var(--typo-size-sm);
--el-th-font-weight: var(--typo-weight-black);
--el-th-text-transform: uppercase;
--el-th-line-height: var(--el-table-line-height);
--el-th-padding: 0 var(--spacing-snug) var(--spacing-snug);
/* === TD VARIABLES === */
--el-td-color: var(--color-text-primary);
--el-td-font-family: var(--font-mono);
--el-td-font-size: var(--typo-size-sm);
--el-td-line-height: var(--el-table-line-height);
--el-td-padding: var(--spacing-snug);
--el-td-border: var(--size-1) solid var(--color-text-secondary);
/* === CAPTION VARIABLES === */
--el-caption-color: var(--color-text-tertiary);
--el-caption-font-family: var(--font-body);
--el-caption-font-size: var(--typo-size-sm);
--el-caption-font-style: italic;
--el-caption-text-align: center;
/* === FIGCAPTION VARIABLES === */
--el-figcaption-color: var(--color-text-tertiary);
--el-figcaption-font-family: var(--font-body);
--el-figcaption-font-size: var(--typo-size-xs);
--el-figcaption-font-style: italic;
--el-figcaption-text-align: center;
/* === SMALL VARIABLES === */
--el-small-color: var(--color-text-tertiary);
--el-small-font-family: var(--font-body);
--el-small-font-size: var(--typo-size-xs);
/* HR */
--hr-height: var(--size-3);
--hr-margin: var(--spacing-relaxed) 0;
--hr-color: var(--color-text-tertiary);
--hr-symbol-content: "▼";
--hr-symbol-size: var(--typo-size-4xl);
--hr-symbol-space: 0 0.25em;
--hr-symbol-line-height: var(--typo-leading-compressed);
--hr-symbol-color: var(--color-text-tertiary);
--hr-symbol-background: var(--color-surface-base);
/* Header */
--el-header-font-size: var(--typo-size-responsive);
--el-header-line-height: var(--typo-leading-snug);
--el-header-paddingY: var(--spacing-snug);
--el-header-height: calc(
(var(--typo-size-responsive) * var(--el-header-line-height)) +
(var(--el-header-paddingY) * 2)
);
}
}

373
src/styles/globals/foundation.css vendored Normal file
View File

@@ -0,0 +1,373 @@
@layer reset {
/*
Foundation inspired by Tailwind CSS Preflight. (https://tailwindcss.com/docs/preflight)
*/
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-style: solid; /* 2 */
border-width: 0; /* 2 */
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the system's `sans` font-family by default.
*/
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
line-height: 1.5; /* 1 */
text-size-adjust: 100%; /* 2 */
tab-size: 4; /* 3 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
border-top-width: 1px; /* 3 */
color: inherit; /* 2 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the system's `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
border-collapse: collapse; /* 3 */
border-color: inherit; /* 2 */
text-indent: 0; /* 1 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
margin: 0; /* 2 */
padding: 0; /* 3 */
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
appearance: auto; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type="search"] {
appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
font: inherit; /* 2 */
appearance: auto; /* 1 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
margin: 0;
padding: 0;
list-style: none;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
*/
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden] {
display: none;
}
}

View File

@@ -0,0 +1,73 @@
@layer tokens {
:root {
/* === TYPOGRAPHY === */
/* == Font Families == */
--font-header: var(--font-geist-sans);
--font-display: var(--font-blaka);
--font-body: var(--font-iosevka-slab);
--font-mono: var(--font-iosevka-mono);
/* == Font Sizes == */
--typo-size-responsive: clamp(1rem, 2.5vw, 1.25rem);
--typo-size-base: 16px;
--typo-size-8xl: 8em;
--typo-size-7xl: 6.375em;
--typo-size-6xl: 5.0625em;
--typo-size-5xl: 4em;
--typo-size-4xl: 3.1875em;
--typo-size-3xl: 2.5em;
--typo-size-2xl: 2em;
--typo-size-xl: 1.5625em;
--typo-size-lg: 1.25em;
--typo-size-md: 1em;
--typo-size-sm: 0.8125em;
--typo-size-xs: 0.625em;
--typo-size-2xs: 0.5em;
/* == Font Weights == */
--typo-weight-thin: 100;
--typo-weight-extralight: 200;
--typo-weight-light: 300;
--typo-weight-normal: 400;
--typo-weight-medium: 500;
--typo-weight-semibold: 600;
--typo-weight-bold: 700;
--typo-weight-extrabold: 800;
--typo-weight-black: 900;
/* == Letter Spacing == */
--typo-spacing-tightest: -0.05em;
--typo-spacing-tighter: -0.025em;
--typo-spacing-tight: -0.0125em;
--typo-spacing-normal: 0em;
--typo-spacing-relaxed: 0.025em;
--typo-spacing-comfortable: 0.05em;
--typo-spacing-loose: 0.1em;
--typo-spacing-looser: 0.15em;
--typo-spacing-loosest: 0.2em;
/* == Line Height == */
--typo-leading-compressed: 1.0;
--typo-leading-tight: 1.125;
--typo-leading-snug: 1.25;
--typo-leading-cozy: 1.375;
--typo-leading-normal: 1.5;
--typo-leading-relaxed: 1.625;
--typo-leading-comfortable: 1.75;
--typo-leading-loose: 1.875;
--typo-leading-spacious: 2.0;
/* == Vertical Spacing == */
--vspace-compressed: 0.25;
--vspace-tight: 0.5;
--vspace-snug: 0.75;
--vspace-cozy: 1;
--vspace-normal: 1.25;
--vspace-relaxed: 1.5;
--vspace-comfortable: 1.75;
--vspace-loose: 2;
--vspace-spacious: 2.5;
}
}

View File

@@ -0,0 +1,688 @@
@define-mixin anim-img-overexposure {
&:hover {
animation: var(--kf-overexposure) var(--img-overexposure-timing);
}
}
@define-mixin anim-img-contrastslam {
&:hover {
filter: grayscale(var(--base-grayscale)) contrast(var(--contrast-amount)) brightness(var(--brightness-amount));
transition: filter var(--img-contrastslam-duration) var(--img-contrastslam-timing);
}
}
@define-mixin anim-img-colorbleed {
&:hover {
animation: var(--kf-color-bleed) var(--img-colorbleed-duration) var(--img-colorbleed-timing);
}
}
@define-mixin anim-img-filmburn {
&:hover {
animation: var(--kf-film-burn) var(--img-filmburn-duration) var(--img-filmburn-timing);
}
}
@define-mixin anim-img-malfunction {
&:hover {
animation: var(--kf-malfunction) var(--img-malfunction-duration) var(--img-malfunction-timing);
}
}
@define-mixin anim-img-tonerstarvation {
&:hover {
animation: var(--kf-toner-fade) var(--img-tonerstarvation-duration) var(--img-tonerstarvation-timing);
}
}
@define-mixin anim-img-corruption {
&:hover {
animation: var(--kf-digital-corrupt) var(--img-corruption-duration) var(--img-corruption-timing);
}
}
@define-mixin anim-img-starkflash {
&:hover {
animation: var(--kf-stark-flash) var(--img-starkflash-duration) var(--img-starkflash-timing);
}
}
/* === TEXT ANIMATION MIXINS === */
@define-mixin anim-txt-strikethrough-marker {
position: relative;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 0%;
height: 1px;
border: 0 solid var(--strike-color);
border-radius: var(--strike-radius);
border-bottom-right-radius: 16px;
background: var(--strike-color);
transition: width var(--strike-duration) var(--strike-timing), border-width var(--strike-duration) var(--strike-timing);
corner-shape: bevel;
}
&:hover::after {
width: 100%;
border-width: var(--strike-border-width);
}
}
@define-mixin anim-txt-strikethrough-industrial {
position: relative;
&:hover::after {
content: '';
position: absolute;
top: 50%;
right: -0.125em;
left: -0.125em;
transform: translateY(-50%);
height: var(--strike-height);
background: var(--strike-color);
animation: var(--kf-strike-slam) var(--strike-duration) var(--strike-timing);
}
}
@define-mixin anim-txt-markerhighlight {
background: linear-gradient(to right, var(--marker-bg) 0%, var(--marker-bg) 0%);
background-repeat: no-repeat;
background-size: 0% 100%;
transition: background-size var(--marker-duration) var(--marker-timing) , color var(--marker-duration) var(--marker-timing) ;
&:hover {
color: var(--marker-fg);
background-size: 100% 100%;
}
}
@define-mixin anim-txt-labelmaker {
transition: all var(--label-duration) var(--label-timing);
&:hover {
margin: var(--label-margin);
padding: var(--label-padding);
border: var(--label-border-width) solid var(--label-bg);
font-weight: var(--label-weight);
color: var(--label-fg);
text-transform: var(--label-transform);
letter-spacing: var(--label-spacing);
background: var(--label-bg);
box-shadow: var(--label-shadow-offset) 0 var(--label-shadow-color);
}
}
@define-mixin anim-txt-rubberstamp {
transition: all var(--stamp-duration) var(--stamp-timing);
&:hover {
transform: rotate(var(--stamp-rotate)) scale(var(--stamp-scale)) translateY(var(--stamp-translate));
margin: var(--stamp-margin);
padding: var(--stamp-padding);
border: var(--stamp-border-width) solid var(--stamp-bg);
font-weight: var(--stamp-weight);
color: var(--stamp-fg);
text-transform: var(--stamp-transform);
letter-spacing: var(--stamp-spacing);
background: var(--stamp-bg);
box-shadow: inset 0 0 0 2px var(--stamp-fg), var(--stamp-shadow-offset) 0 var(--stamp-shadow-color);
}
}
@define-mixin anim-txt-pressstamp {
transition: all var(--press-duration) var(--press-timing);
&:hover {
transform: scaleY(var(--press-scale-y)) scaleX(var(--press-scale-x)) translateY(var(--press-translate));
margin: var(--press-margin);
padding: var(--press-padding);
font-weight: var(--press-weight);
color: var(--press-fg);
letter-spacing: var(--press-spacing);
background: var(--press-bg);
box-shadow: 0 0 0 1px var(--press-border-color), 0 2px 0 var(--press-shadow-1), 0 4px 0 var(--press-shadow-2);
}
}
@define-mixin anim-txt-typewriter {
position: relative;
&::after {
content: '';
position: absolute;
bottom: var(--typewriter-offset);
left: 0;
width: 0%;
height: var(--typewriter-height);
background: repeating-linear-gradient(to right, var(--typewriter-color) 0, var(--typewriter-color) var(--typewriter-dash-length), transparent var(--typewriter-dash-length), transparent var(--typewriter-gap-length));
transition: width var(--typewriter-duration) var(--typewriter-timing);
}
&:hover::after {
width: 100%;
}
}
@define-mixin anim-txt-hardinvert {
transition: all var(--invert-duration) var(--invert-timing);
&:hover {
transform: scale(var(--invert-scale));
font-weight: var(--invert-weight);
color: var(--invert-fg);
letter-spacing: var(--invert-spacing);
background: var(--invert-bg);
}
}
@define-mixin anim-txt-pointer {
position: relative;
&::before,
&::after {
position: absolute;
color: var(--pointer-color);
opacity: 0;
transition: var(--pointer-transition);
}
&::before {
content: var(--pointer-left-symbol);
left: 0;
}
&::after {
content: var(--pointer-right-symbol);
right: 0;
}
&:hover::before {
transform: translateX(calc(var(--pointer-distance) * -1));
opacity: 1;
}
&:hover::after {
transform: translateX(var(--pointer-distance));
opacity: 1;
}
}
@define-mixin anim-txt-cornerbox {
position: relative;
margin: var(--corner-margin);
padding: var(--corner-padding);
&::before,
&::after {
content: '';
position: absolute;
width: var(--corner-size);
height: var(--corner-size);
border: var(--corner-border);
opacity: 0;
transition: var(--corner-transition);
}
&::before {
top: 0;
left: 0;
border-right: none;
border-bottom: none;
}
&::after {
right: 0;
bottom: 0;
border-top: none;
border-left: none;
}
&:hover {
&::before,
&::after {
opacity: 1;
}
}
}
@define-mixin anim-txt-characterglitch {
&:hover {
animation: var(--kf-char-scramble) var(--glitch-duration) var(--glitch-timing);
}
}
@define-mixin anim-txt-pixelshift {
position: relative;
&::before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: var(--pixel-line-height);
opacity: 0;
background: var(--pixel-bg);
}
&:hover {
color: var(--pixel-fg);
animation: var(--kf-text-glitch) var(--pixel-duration) var(--pixel-timing);
&::before {
opacity: 1;
animation: var(--kf-glitch-line) var(--pixel-duration) var(--pixel-timing);
}
}
}
@define-mixin anim-txt-redacted {
transition: all var(--redacted-duration) var(--redacted-timing);
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background: var(--redacted-bg);
transition: width var(--redacted-duration) var(--redacted-timing);
}
&:hover {
color: transparent;
text-shadow: var(--redacted-shadow);
&::after {
width: 100%;
}
}
}
@define-mixin anim-txt-xray {
transition: all var(--xray-duration) var(--xray-timing);
&:hover {
font-weight: var(--xray-weight);
color: var(--xray-fg);
text-shadow: 0 0 2px var(--xray-glow);
background: var(--xray-bg);
filter: invert(var(--xray-invert)) contrast(var(--xray-contrast)) brightness(var(--xray-brightness)) saturate(var(--xray-saturate));
box-shadow: inset 0 0 0 1px var(--xray-border), 0 0 15px var(--xray-outer-glow);
}
}
@define-mixin anim-txt-strikethrough-marker_focus {
position: relative;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 0%;
height: 1px;
border: 0 solid var(--strike-color);
border-radius: var(--strike-radius);
border-bottom-right-radius: 16px;
background: var(--strike-color);
transition: width var(--strike-duration) var(--strike-timing), border-width var(--strike-duration) var(--strike-timing);
corner-shape: bevel;
}
&:focus::after {
width: 100%;
border-width: var(--strike-border-width);
}
}
@define-mixin anim-txt-strikethrough-industrial_focus {
position: relative;
&:focus::after {
content: '';
position: absolute;
top: 50%;
right: -0.125em;
left: -0.125em;
transform: translateY(-50%);
height: var(--strike-height);
background: var(--strike-color);
animation: var(--kf-strike-slam) var(--strike-duration) var(--strike-timing);
}
}
@define-mixin anim-txt-markerhighlight_focus {
background: linear-gradient(to right, var(--marker-bg) 0%, var(--marker-bg) 0%);
background-repeat: no-repeat;
background-size: 0% 100%;
transition: background-size var(--marker-duration) var(--marker-timing) , color var(--marker-duration) var(--marker-timing) ;
&:focus {
color: var(--marker-fg);
background-size: 100% 100%;
}
}
@define-mixin anim-txt-labelmaker_focus {
transition: all var(--label-duration) var(--label-timing);
&:focus {
margin: var(--label-margin);
padding: var(--label-padding);
border: var(--label-border-width) solid var(--label-bg);
font-weight: var(--label-weight);
color: var(--label-fg);
text-transform: var(--label-transform);
letter-spacing: var(--label-spacing);
background: var(--label-bg);
box-shadow: var(--label-shadow-offset) 0 var(--label-shadow-color);
}
}
@define-mixin anim-txt-rubberstamp_focus {
transition: all var(--stamp-duration) var(--stamp-timing);
&:focus {
transform: rotate(var(--stamp-rotate)) scale(var(--stamp-scale)) translateY(var(--stamp-translate));
margin: var(--stamp-margin);
padding: var(--stamp-padding);
border: var(--stamp-border-width) solid var(--stamp-bg);
font-weight: var(--stamp-weight);
color: var(--stamp-fg);
text-transform: var(--stamp-transform);
letter-spacing: var(--stamp-spacing);
background: var(--stamp-bg);
box-shadow: inset 0 0 0 2px var(--stamp-fg), var(--stamp-shadow-offset) 0 var(--stamp-shadow-color);
}
}
@define-mixin anim-txt-pressstamp_focus {
transition: all var(--press-duration) var(--press-timing);
&:focus {
transform: scaleY(var(--press-scale-y)) scaleX(var(--press-scale-x)) translateY(var(--press-translate));
margin: var(--press-margin);
padding: var(--press-padding);
font-weight: var(--press-weight);
color: var(--press-fg);
letter-spacing: var(--press-spacing);
background: var(--press-bg);
box-shadow: 0 0 0 1px var(--press-border-color), 0 2px 0 var(--press-shadow-1), 0 4px 0 var(--press-shadow-2);
}
}
@define-mixin anim-txt-typewriter_focus {
position: relative;
&::after {
content: '';
position: absolute;
bottom: var(--typewriter-offset);
left: 0;
width: 0%;
height: var(--typewriter-height);
background: repeating-linear-gradient(to right, var(--typewriter-color) 0, var(--typewriter-color) var(--typewriter-dash-length), transparent var(--typewriter-dash-length), transparent var(--typewriter-gap-length));
transition: width var(--typewriter-duration) var(--typewriter-timing);
}
&:focus::after {
width: 100%;
}
}
@define-mixin anim-txt-hardinvert_focus {
transition: all var(--invert-duration) var(--invert-timing);
&:focus {
transform: scale(var(--invert-scale));
font-weight: var(--invert-weight);
color: var(--invert-fg);
letter-spacing: var(--invert-spacing);
background: var(--invert-bg);
}
}
@define-mixin anim-txt-pointer_focus {
position: relative;
&::before,
&::after {
position: absolute;
color: var(--pointer-color);
opacity: 0;
transition: var(--pointer-transition);
}
&::before {
content: var(--pointer-left-symbol);
left: 0;
}
&::after {
content: var(--pointer-right-symbol);
right: 0;
}
&:focus::before {
transform: translateX(calc(var(--pointer-distance) * -1));
opacity: 1;
}
&:focus::after {
transform: translateX(var(--pointer-distance));
opacity: 1;
}
}
@define-mixin anim-txt-cornerbox_focus {
position: relative;
margin: var(--corner-margin);
padding: var(--corner-padding);
&::before,
&::after {
content: '';
position: absolute;
width: var(--corner-size);
height: var(--corner-size);
border: var(--corner-border);
opacity: 0;
transition: var(--corner-transition);
}
&::before {
top: 0;
left: 0;
border-right: none;
border-bottom: none;
}
&::after {
right: 0;
bottom: 0;
border-top: none;
border-left: none;
}
&:focus {
&::before,
&::after {
opacity: 1;
}
}
}
@define-mixin anim-txt-characterglitch_focus {
&:focus {
animation: var(--kf-char-scramble) var(--glitch-duration) var(--glitch-timing);
}
}
@define-mixin anim-txt-pixelshift {
position: relative;
&::before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: var(--pixel-line-height);
opacity: 0;
background: var(--pixel-bg);
}
&:hover {
color: var(--pixel-fg);
animation: var(--kf-text-glitch) var(--pixel-duration) var(--pixel-timing);
&::before {
opacity: 1;
animation: var(--kf-glitch-line) var(--pixel-duration) var(--pixel-timing);
}
}
}
@define-mixin anim-txt-pixelshift_focus {
position: relative;
&::before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: var(--pixel-line-height);
opacity: 0;
background: var(--pixel-bg);
}
&:focus {
color: var(--pixel-fg);
animation: var(--kf-text-glitch) var(--pixel-duration) var(--pixel-timing);
&::before {
opacity: 1;
animation: var(--kf-glitch-line) var(--pixel-duration) var(--pixel-timing);
}
}
}
@define-mixin anim-txt-redacted_focus {
transition: all var(--redacted-duration) var(--redacted-timing);
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background: var(--redacted-bg);
transition: width var(--redacted-duration) var(--redacted-timing);
}
&:focus {
color: transparent;
text-shadow: var(--redacted-shadow);
&::after {
width: 100%;
}
}
}
@define-mixin anim-txt-xray_focus {
transition: all var(--xray-duration) var(--xray-timing);
&:focus {
font-weight: var(--xray-weight);
color: var(--xray-fg);
text-shadow: 0 0 2px var(--xray-glow);
background: var(--xray-bg);
filter: invert(var(--xray-invert)) contrast(var(--xray-contrast)) brightness(var(--xray-brightness)) saturate(var(--xray-saturate));
box-shadow: inset 0 0 0 1px var(--xray-border), 0 0 15px var(--xray-outer-glow);
}
}

View File

@@ -1,7 +1,8 @@
@define-mixin responsive-wrapper $vspacing: 0 $hspacing: var(--spacing-comfortable) {
@define-mixin responsive-wrapper $vspacing: 0, $hspacing: var(--spacing-cozy), $fontSize: var(--typo-size-responsive) {
@mixin mx auto;
max-width: clamp(60ch, 90vw, 90ch);
padding: $vspacing $hspacing;
font-size: var(--typo-size-responsive);
font-family: var(--font-body);
font-size: $fontSize;
}

View File

@@ -0,0 +1,49 @@
@define-mixin decorator-bb {
padding: var(--bb-spacing, 0);
border: var(--bb-border, var(--size-1) solid var(--color-primary));
border-top-left-radius: var(--bb-radius-tl, var(--size-1));
border-top-right-radius: var(--bb-radius-tr, 0);
border-bottom-right-radius: var(--bb-radius-br, 0);
border-bottom-left-radius: var(--bb-radius-bl, 0);
color: var(--bb-fg, var(--color-text-primary));
background-color: var(--bb-bg, var(--color-primary));
corner-shape: var(--bb-shapes, bevel);
}
@define-mixin decorator-torn {
position: relative;
transform: rotate(1.5deg);
display: block;
padding: 0.4em 0.8em;
border-radius: 0.3em 0.6em 0.4em 0.5em / 0.5em 0.4em 0.6em 0.3em;
color: var(--torn-fg);
background: var(--torn-bg);
clip-path: polygon(
8px 0%,
12px 8%,
6px 18%,
14px 32%,
4px 45%,
12px 58%,
7px 72%,
15px 85%,
8px 100%,
calc(100% - 8px) 100%,
calc(100% - 15px) 85%,
calc(100% - 7px) 72%,
calc(100% - 12px) 58%,
calc(100% - 4px) 45%,
calc(100% - 14px) 32%,
calc(100% - 6px) 18%,
calc(100% - 12px) 8%,
calc(100% - 8px) 0%
);
box-shadow: 2px 2px 4px rgb(0 0 0 / 30%);
}

View File

@@ -1,11 +1,11 @@
@define-mixin grid-col $col $spacing {
@define-mixin grid-col $col, $spacing {
display: grid;
grid-template-columns: repeat($col, minmax(0, 1fr));
gap: $spacing;
}
@define-mixin grid-rows $row $spacing {
@define-mixin grid-rows $row, $spacing {
display: grid;
grid-template-rows: repeat(1, minmax(0, 1fr));
gap: $spacing;

View File

@@ -0,0 +1,4 @@
@define-mixin position $position: absolute, $inset-values {
position: $position;
inset: $inset-values;
}

View File

@@ -1,4 +1,4 @@
@efine-mixin m $spacing {
@efine-mixin ma $spacing {
margin: $spacing;
}
@@ -41,7 +41,7 @@
}
}
@efine-mixin p $spacing {
@efine-mixin pa $spacing {
padding: $spacing;
}
@@ -77,7 +77,7 @@
padding-line-end: $spacing;
}
@define-mixin space-y $spacing $reverse: 0 {
@define-mixin space-y $spacing, $reverse: 0 {
& > :not(:last-child) {
margin-block-start: calc($spacing * $reverse);
margin-block-end: calc($spacing * (1 - $reverse));

View File

@@ -40,37 +40,37 @@
letter-spacing: 0.0025em;
}
@define-mixin text-xl {
@define-mixin text-xl $leading:1{
font-size: var(--typo-size-xl);
line-height: calc($leading * 1.28);
letter-spacing: 0.0116em;
}
@define-mixin text-lg {
@define-mixin text-lg $leading:1 {
font-size: var(--typo-size-lg);
line-height: calc($leading * 1.4);
letter-spacing: 0.022em;
}
@define-mixin text-md {
@define-mixin text-md $leading:1 {
font-size: var(--typo-size-md);
line-height: calc($leading * 1.5);
letter-spacing: 0.035em;
}
@define-mixin text-sm {
@define-mixin text-sm $leading:1 {
font-size: var(--typo-size-sm);
line-height: calc($leading * 1.5385);
letter-spacing: 0.05em;
}
@define-mixin text-xs {
@define-mixin text-xs $leading:1 {
font-size: var(--typo-size-xs);
line-height: calc($leading * 2);
letter-spacing: 0.074em;
}
@define-mixin text-2xs {
@define-mixin text-2xs $leading:1 {
font-size: var(--typo-size-2xs);
line-height: calc($leading * 2);
letter-spacing: 0.1em;

6
src/styles/tokens.css Normal file
View File

@@ -0,0 +1,6 @@
@import url('globals/custom-media.css');
@import url('globals/typography.css');
@import url('globals/colors.css');
@import url('globals/dimensions.css');
@import url('globals/elements.css');
@import url('globals/animations.css');

View File

@@ -1,5 +0,0 @@
@import url('./variables/custom-media.css');
@import url('./variables/typography.css');
@import url('./variables/colors.css');
@import url('./variables/dimensions.css');
@import url('./variables/elements.css');

View File

@@ -1,156 +0,0 @@
:root {
/* === Default Palette === */
/* == Blacks, Grays & Off-Whites == */
--color-palette-woodsmoke: oklch(15.5% 0.009 274.276deg); /* Woodsmoke: #0B0C10 */
--color-palette-black-ink: oklch(21.9% 0.006 285.911deg); /* Shark: #1A1A1D */
--color-palette-charcoal: oklch(26.6% 0.008 240.166deg); /* Shark2: #222629 */
--color-palette-charcoal-gray: oklch(33.7% 0.026 266.801deg); /* Bright Gray: #313745 */
--color-palette-slate-gray: oklch(33.3% 0 89.876deg); /* Mineshaft: #363636 */
--color-palette-gunmetal: oklch(41.1% 0.008 248.035deg); /* Abbey2: #474B4F */
--color-palette-carbon: oklch(39.8% 0 89.876deg); /* Tundora: #474747 */
--color-palette-steel-gray: oklch(42.5% 0.003 286.26deg); /* Abbey: #4e4e50 */
--color-palette-dusty-black: oklch(43.7% 0.013 17.672deg); /* DonJuan: #594F4F */
--color-palette-stone: oklch(64.3% 0.005 91.471deg); /* Natural Gray: #8E8D8A */
--color-palette-cloud-gray: oklch(53.6% 0.005 236.565deg); /* Nevada: #6B6E70 */
--color-palette-silver: oklch(72.9% 0.001 17.185deg); /* Silver Chalice: #A8A7A7 */
--color-palette-light-silver: oklch(82.6% 0.002 247.844deg); /* Silversand: #C5C6C7 */
--color-palette-pale-gray: oklch(91.3% 0.004 91.449deg); /* Westar: #E3E2DF */
--color-palette-pale-stone: oklch(89.7% 0.004 106.481deg); /* Quillgray: #DDDDDA */
--color-palette-very-pale-gray: oklch(94.3% 0 89.876deg); /* Gallery: #ECECEC */
--color-palette-off-white: oklch(98.1% 0.003 247.858deg); /* Catskill White: #F7F9fB */
--color-palette-cat-squeeze: oklch(98.3% 0.004 236.496deg); /* Cat Squeeze: #F7FAFC */
/* == Reds == */
--color-palette-oxblood: oklch(30.5% 0.122 12.109deg); /* Bordeaux: #5D001E */
--color-palette-deep-maroon: oklch(37.6% 0.109 11.682deg); /* Crown of Thorns: #6F2232 */
--color-palette-crimson: oklch(43.2% 0.169 7.14deg); /* Monarch: #950740 */
--color-palette-cherry-red: oklch(45.4% 0.168 1.454deg); /* Disco: #9A1750 */
--color-palette-ruby: oklch(52.1% 0.206 15.782deg); /* Shiraz: #C3073F */
--color-palette-red-clay: oklch(65.1% 0.178 27.507deg); /* Burnt Sienna: #E85A4F */
--color-palette-lava: oklch(63.6% 0.193 17.075deg); /* Mandy: #E84A5F */
--color-palette-vivid-scarlet: oklch(66.6% 0.221 15.669deg); /* Radical Red: #FE4365 */
/* == Pinks & Magentas == */
--color-palette-heliotrope: oklch(68.3% 0.217 353.666deg); /* Heliotrope: #F74FA3 */
--color-palette-hot-pink: oklch(65.4% 0.2 6.69deg); /* French Rose: #EE4C7C */
--color-palette-cerise: oklch(60.7% 0.23 18.554deg); /* Amaranth: #EC2049 */
--color-palette-fuchsia: oklch(49.6% 0.181 351.176deg); /* Hibiscus: #A7226E */
--color-palette-dusty-rose: oklch(63.2% 0.11 2.384deg); /* Turkish Rose: #C06C84 */
--color-palette-berry: oklch(60.8% 0.159 2.621deg); /* Mulberry: #CC527A */
--color-palette-petal-pink: oklch(80.5% 0.063 1.992deg); /* Rose Fog: #E3AFBC */
--color-palette-coral-pink: oklch(71.2% 0.162 15.607deg); /* Froly: #F67280 */
--color-palette-sweet-pink: oklch(79.2% 0.114 21.911deg); /* Sweet Pink: #FC9D9A */
/* == Oranges & Browns == */
--color-palette-persimmon: oklch(68.6% 0.179 40.01deg); /* Flamingo: #F26B38 */
--color-palette-terracotta: oklch(71.3% 0.131 27.646deg); /* Apricot: #E98074 */
--color-palette-tan: oklch(82.7% 0.047 76.752deg); /* Akaroa: #D8C3A5 */
--color-palette-peach: oklch(88.5% 0.072 57.746deg); /* Flesh: #FECEAB */
--color-palette-pastel-orange: oklch(82.1% 0.092 42.408deg); /* Rosebud: #F8B195 */
--color-palette-light-apricot: oklch(87.8% 0.066 57.778deg); /* Vivid Tangerine: #F9CDAD */
--color-palette-bone-white: oklch(92.7% 0.015 94.206deg); /* Satin Linen: #EAE7DC */
/* == Yellows == */
--color-palette-ripe-lemon: oklch(83.9% 0.167 91.469deg); /* Ripe Lemon: #F2C51D */
--color-palette-bright-canary: oklch(89% 0.157 97.726deg); /* Energy Yellow: #F7DB4F */
--color-palette-pale-lemon: oklch(95.6% 0.104 121.573deg); /* Mimosa: #E5FCAD */
/* == Greens == */
--color-palette-forest-green: oklch(58.1% 0.127 130.001deg); /* Crete: #61892F */
--color-palette-lime-green: oklch(74.6% 0.18 129.939deg); /* Atlantis: #86C232 */
--color-palette-electric-green: oklch(87.7% 0.227 137.099deg); /* Screaming Green: #87f74f */
--color-palette-sage: oklch(75.1% 0.056 144.175deg); /* Norway: #87f74f */
--color-palette-mint-green: oklch(84.8% 0.098 151.333deg); /* Chinook: #9de0ad */
--color-palette-olive-drab: oklch(82.5% 0.042 107.285deg); /* Olive Drap: #C8C8A9 */
--color-palette-seafoam: oklch(71.6% 0.056 165.214deg); /* Acapulco: #83AF9B */
/* == Blues & Teals == */
--color-palette-dark-navy: oklch(27.3% 0.024 253.693deg); /* Ebony Clay: #1F2833 */
--color-palette-deep-teal: oklch(32.4% 0.018 225.132deg); /* Outer Space: #2A363B */
--color-palette-royal-blue: oklch(46.1% 0.07 245.64deg); /* Ming: #355C7D */
--color-palette-sky-blue: oklch(76.3% 0.129 233.891deg); /* Picton Blue: #4FBFF7 */
--color-palette-slate-blue: oklch(55.1% 0.043 210.602deg); /* Cutty Sark: #547980 */
--color-palette-turquoise: oklch(61.5% 0.091 198.865deg); /* Lochinvar: #2F9599 */
--color-palette-aqua: oklch(68.6% 0.095 190.758deg); /* Keppel: #45ADA8 */
--color-palette-electric-blue: oklch(90.8% 0.128 188.419deg); /* Aquamarine: #66FCF1 */
--color-palette-powder-blue: oklch(88.2% 0.062 187.276deg); /* Powder Blue: #a9e6df */
--color-palette-ice-blue: oklch(99.9% 0.001 197.139deg); /* Twilight Blue: #feffff */
/* === Semantic Colors === */
/* == Primary Colors == */
--color-primary: var(--color-palette-lava);
--color-primary-surface: oklch(from var(--color-primary) calc(l + 0.1) c h);
--color-primary-emphasis: oklch(from var(--color-primary) calc(l - 0.15) c h);
/* == Secondary Colors == */
--color-secondary: var(--color-palette-electric-blue);
--color-secondary-surface: oklch(from var(--color-secondary) calc(l + 0.1) c h);
--color-secondary-emphasis: oklch(from var(--color-secondary) calc(l - 0.15) c h);
/* == Tertiary Colors == */
--color-tertiary: var(--color-palette-bright-canary);
--color-tertiary-surface: oklch(from var(--color-tertiary) calc(l + 0.1) c h);
--color-tertiary-emphasis: oklch(from var(--color-tertiary) calc(l - 0.15) c h);
/* == Text Base Colors == */
--color-text-primary: var(--color-palette-black-ink); /* Main Body Texts, headlines */
--color-text-secondary: var(--color-palette-charcoal); /* Subheading, Secondary Info */
--color-text-tertiary: var(--color-palette-charcoal-gray); /* Captions, Meta Text */
--color-text-quarternary: var(--color-palette-carbon); /* Placeholder Text */
--color-text-inverse: var(--color-palette-ice-blue); /* Text on dark backgrounds */
--color-text-disabled: var(--color-palette-cloud-gray); /* Disabled form labels, inactive text */
/* == Surface Base Colors == */
--color-surface-base: var(--color-palette-ice-blue); /* Main page background */
--color-surface-elevated-1: var(--color-palette-off-white); /* Cards, Panels */
--color-surface-elevated-2: var(--color-palette-very-pale-gray); /* Modals, Dropdowns */
--color-surface-elevated-3: var(--color-palette-pale-gray); /* Tooltips, popovers */
--color-surface-elevated-4: var(--color-palette-light-silver); /* Highest Elevation */
--color-surface-inverse: var(--color-palette-black-ink); /* Darkest Surface for Contrast */
/* == Border Base Colors == */
--color-border-subtle: var(--color-palette-silver); /* Subtle Dividers, Card Borders */
--color-border-normal: var(--color-palette-stone); /* Standard Borders, form fields */
--color-border-strong: var(--color-palette-charcoal-gray); /* Emphasized Borders */
/* == State Colors == */
--color-state-error: var(--color-palette-cerise); /* Error Text, Container, icons */
--color-state-warning: var(--color-palette-persimmon); /* Warning Text, Container, Icons */
--color-state-success: var(--color-palette-lime-green); /* Success Text, Container, Icons */
--color-state-info: var(--color-palette-royal-blue); /* Info Text, Container, Icons */
/* == Link Colors == */
--color-text-link: var(--color-text-tertiary);
--color-text-link-hover: var(--color-secondary);
--color-text-link-visited: var(--color-palette-fuchsia);
/* == Focus States == */
--color-focus-ring: var(--color-primary);
--color-focus-ring-offset: var(--color-primary);
--color-focus-indicator: var(--color-primary-emphasis)
/* == Overlays == */;
--color-utility-overlay-light: oklch(0% 0 0deg / 10%); /* Light overlays */
--color-utility-overlay-medium: oklch(0% 0 0deg / 30%); /* Medium overlays */
--color-utility-overlay-heavy: oklch(0% 0 0deg / 60%); /* Heavy overlays, modal backdrops */
--color-surface-overlay: var(--color-utility-overlay-medium); /* Modal overlays, backdrop */
--color-surface-backdrop: var(--color-utility-overlay-heavy); /* Full screen overlays */
/* == Loading/Skeleton == */
--color-utility-skeleton-base: var(--color-surface-elevated-2); /* Skeleton loader base */
--color-utility-skeleton-shimmer: var(--color-surface-elevated-1); /* Skeleton shimmer effect */
/* == Dividers == */
--color-utility-divider: var(--color-border-subtle); /* Section dividers, HR elements */
--color-utility-divider-strong: var(--color-border-normal); /* Emphasized dividers */
/* == Shadows == */
--color-utility-shadow: oklch(0% 0 0deg / 10%); /* Drop shadows */
--color-utility-shadow-strong: oklch(0% 0 0deg / 25%); /* Strong shadows */
/* == Highlights == */
--color-utility-highlight: var(--color-tertiary-surface); /* Text highlighting, search results */
--color-utility-highlight-strong: var(--color-tertiary); /* Strong highlighting */
}

View File

@@ -1,5 +0,0 @@
@custom-media --bp-mobile (width < 48rem);
@custom-media --bp-tablet (width >= 48rem) and (width < 80rem);
@custom-media --bp-tablet-up (width >= 48rem);
@custom-media --bp-tablet-down (width < 80rem);
@custom-media --bp-desktop (width >= 80rem);

View File

@@ -1,93 +0,0 @@
:root {
/* === DIMENSIONS === */
/* == Base Size Units == */
--size-0: 0;
--size-px: 1px;
--size-05: 0.125rem;
--size-1: 0.25rem;
--size-2: 0.5rem;
--size-3: 0.75rem;
--size-4: 1rem;
--size-5: 1.25rem;
--size-6: 1.5rem;
--size-8: 2rem;
--size-10: 2.5rem;
--size-12: 3rem;
--size-16: 4rem;
--size-20: 5rem;
--size-24: 6rem;
--size-32: 8rem;
--size-40: 10rem;
--size-48: 12rem;
--size-64: 16rem;
--size-80: 20rem;
--size-96: 24rem;
--size-128: 32rem;
--size-160: 40rem;
--size-192: 48rem;
--size-256: 64rem;
--size-320: 80rem;
--size-384: 96rem;
--size-360: 90rem;
--size-400: 100rem;
--size-480: 120rem;
/* == Flexible Dimensions == */
--dim-full: 100%;
--dim-1-2: 50%;
--dim-1-3: 33.3333%;
--dim-2-3: 66.6667%;
--dim-1-4: 25%;
--dim-2-4: var(--dim-1-2);
--dim-3-4: 75%;
--dim-1-5: 20%;
--dim-2-5: 40%;
--dim-3-5: 60%;
--dim-4-5: 80%;
--dim-1-6: 16.6667%;
--dim-2-6: var(--dim-1-3);
--dim-3-6: var(--dim-1-2);
--dim-4-6: var(--dim-2-3);
--dim-5-6: 83.3333%;
--dim-1-8: 12.5%;
--dim-2-8: var(--dim-1-4);
--dim-3-8: 37.5%;
--dim-4-8: var(--dim-1-2);
--dim-5-8: 62.5%;
--dim-6-8: var(--dim-3-4);
--dim-7-8: 87.5%;
--dim-1-10: 10%;
--dim-2-10: var(--dim-1-5);
--dim-3-10: 30%;
--dim-4-10: var(--dim-2-5);
--dim-5-10: var(--dim-1-2);
--dim-6-10: var(--dim-3-5);
--dim-7-10: 70%;
--dim-8-10: var(--dim-4-5);
--dim-9-10: 90%;
--dim-1-12: 8.3333%;
--dim-2-12: var(--dim-1-6);
--dim-3-12: var(--dim-1-4);
--dim-4-12: var(--dim-1-3);
--dim-5-12: 41.6667%;
--dim-6-12: var(--dim-1-2);
--dim-7-12: 58.3333%;
--dim-8-12: var(--dim-2-3);
--dim-9-12: var(--dim-3-4);
--dim-10-12: 83.3333%;
--dim-11-12: 91.6667%;
/* == Semantic Spacing == */;
--spacing-none: var(--size-0);
--spacing-hairline: var(--size-px);
--spacing-tight: var(--size-1);
--spacing-snug: var(--size-2);
--spacing-cozy: var(--size-4);
--spacing-comfortable: var(--size-6);
--spacing-relaxed: var(--size-8);
--spacing-spacious: var(--size-12);
--spacing-generous: var(--size-16);
--spacing-luxurious: var(--size-24);
--spacing-expansive: var(--size-32);
}

View File

@@ -1,255 +0,0 @@
:root {
/* === H1 VARIABLES === */
--el-h1-color: var(--color-text-primary);
--el-h1-font-family: var(--font-display);
--el-h1-font-size: var(--typo-size-7xl);
--el-h1-font-weight: var(--typo-weight-black);
--el-h1-letter-spacing: -0.0137em;
--el-h1-line-height: 1.125;
--el-h1-text-transform: uppercase;
--el-h1-vspace-base: calc(1em * var(--el-h1-line-height));
--el-h1-vspace-top: calc(var(--el-h1-vspace-base) * var(--vspace-spacious));
--el-h1-vspace-bottom: calc(var(--el-h1-vspace-base) * var(--vspace-comfortable));
/* === H2 VARIABLES === */
--el-h2-color: var(--color-text-primary);
--el-h2-font-family: var(--font-heading);
--el-h2-font-size: var(--typo-size-5xl);
--el-h2-font-weight: var(--typo-weight-black);
--el-h2-letter-spacing: -0.0096em;;
--el-h2-line-height: 1.1765;
--el-h2-text-transform: uppercase;
--el-h2-vspace-base: calc(1em * var(--el-h2-line-height));
--el-h2-vspace-top: calc(var(--el-h2-vspace-base) * var(--vspace-snug));
--el-h2-vspace-bottom: calc(var(--el-h2-vspace-base) * var(--vspace-compressed));
/* === H3 VARIABLES === */
--el-h3-color: var(--color-text-secondary);
--el-h3-font-family: var(--font-heading);
--el-h3-font-size: var(--typo-size-4xl);
--el-h3-font-weight: var(--typo-weight-extrabold);
--el-h3-letter-spacing: -0.004em;
--el-h3-line-height: 1.2;
--el-h3-text-transform: uppercase;
--el-h3-vspace-base: calc(1em * var(--el-h3-line-height));
--el-h3-vspace-top: calc(var(--el-h3-vspace-base) * var(--vspace-cozy));
--el-h3-vspace-bottom: calc(var(--el-h3-vspace-base) * var(--vspace-snug));
/* === H4 VARIABLES === */
--el-h4-color: var(--color-text-secondary);
--el-h4-font-family: var(--font-heading);
--el-h4-font-size: var(--typo-size-3xl);
--el-h4-font-weight: var(--typo-weight-extrabold);
--el-h4-letter-spacing: 0.0025em;
--el-h4-line-height: 1.125;
--el-h4-text-transform: uppercase;
--el-h4-vspace-base: calc(1em * var(--el-h4-line-height));
--el-h4-vspace-top: calc(var(--el-h4-vspace-base) * var(--vspace-normal));
--el-h4-vspace-bottom: calc(var(--el-h4-vspace-base) * var(--vspace-tight));
/* === H5 VARIABLES === */
--el-h5-color: var(--color-text-secondary);
--el-h5-font-family: var(--font-heading);
--el-h5-font-size: var(--typo-size-2xl);
--el-h5-font-weight: var(--typo-weight-extrabold);
--el-h5-letter-spacing: 0.05em;
--el-h5-line-height: 1.28;
--el-h5-text-transform: uppercase;
--el-h5-vspace-base: calc(1em * var(--el-h5-line-height));
--el-h5-vspace-top: calc(var(--el-h5-vspace-base) * var(--vspace-cozy));
--el-h5-vspace-bottom: calc(var(--el-h5-vspace-base) * var(--vspace-tight));
/* === H6 VARIABLES === */
--el-h6-color: var(--color-text-secondary);
--el-h6-font-family: var(--font-heading);
--el-h6-font-size: var(--typo-size-xl);
--el-h6-font-weight: var(--typo-weight-black);
--el-h6-letter-spacing: 0.035em;
--el-h6-line-height: 1.4;
--el-h6-text-transform: uppercase;
--el-h6-vspace-base: calc(1em * var(--el-h6-line-height));
--el-h6-vspace-top: calc(var(--el-h6-vspace-base) * var(--vspace-snug));
--el-h6-vspace-bottom: calc(var(--el-h6-vspace-base) * var(--vspace-compressed));
/* === PARAGRAPH VARIABLES === */
--el-p-color: var(--color-text-primary);
--el-p-font-family: var(--font-body);
--el-p-font-size: var(--typo-size-md);
--el-p-font-weight: var(--typo-weight-regular);
--el-p-line-height: var(--typo-leading-normal);
--el-p-text-align: justify;
--el-p-vspace-base: calc(1em * var(--el-p-line-height));
--el-p-vspace-top: calc(var(--el-p-vspace-base) * var(--vspace-snug));
--el-p-vspace-bottom: calc(var(--el-p-vspace-base) * var(--vspace-snug));
/* === BLOCKQUOTE VARIABLES === */
--el-blockquote-color: var(--color-text-tertiary);
--el-border-color: var(--color-text-tertiary);
--el-blockquote-font-family: var(--font-body);
--el-blockquote-font-size: var(--typo-size-md);
--el-blockquote-font-style: var(--typo-weight-regular);
--el-blockquote-font-weight: var(--typo-weight-medium);
--el-blockquote-line-height: var(--typo-leading-comfortable);
--el-blockquote-vspace-base: calc(1em * var(--el-blockquote-line-height));
--el-blockquote-vspace-top: calc(var(--el-blockquote-vspace-base) * var(--vspace-snug));
--el-blockquote-vspace-bottom: calc(var(--el-blockquote-vspace-base) * var(--vspace-snug));
/* === PRE VARIABLES === */
--el-pre-color: var(--color-text-inverse);
--el-pre-background: var(--color-surface-inverse);
--el-pre-font-family: var(--font-mono);
--el-pre-font-size: var(--typo-size-sm);
--el-pre-line-height: 1.5385;
--el-pre-vspace-base: calc(1em * var(--el-pre-line-height));
--el-pre-vspace-top: calc(var(--el-pre-vspace-base) * var(--vspace-normal));
--el-pre-vspace-bottom: calc(var(--el-pre-vspace-base) * var(--vspace-normal));
/* === CODE VARIABLES === */
--el-code-color: var(--color-text-inverse);
--el-code-background: var(--color-surface-inverse);
--el-code-font-family: var(--font-mono);
--el-code-font-size: var(--typo-size-sm);
/* === List Variables (For UL/OL) === */
--el-list-color: var(--color-text-primary);
--el-list-line-height: var(--typo-leading-normal);
--el-list-font-size: var(--typo-size-md);
--el-list-vspace-base: calc(1em * var(--el-list-line-height));
--el-list-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-nested-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-list-nested-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-snug));
--el-li-nested-vspace-top: calc(var(--el-list-vspace-base) * var(--vspace-tight));
--el-li-nested-vspace-bottom: calc(var(--el-list-vspace-base) * var(--vspace-tight));
/* === UL VARIABLES === */
--el-ul-indent-l1: var(--spacing-cozy);
--el-ul-indent-l2: var(--spacing-cozy);
--el-ul-indent-l3: var(--spacing-cozy);
--el-ul-indent-l4: var(--spacing-cozy);
--el-ul-item-padding: var(--spacing-cozy);
--el-ul-symbol-l1: '⯃';
--el-ul-symbol-l1-color: var(--color-text-primary);
--el-ul-symbol-l2: '⯁';
--el-ul-symbol-l2-color: var(--color-text-primary);
--el-ul-symbol-l3: '⯆';
--el-ul-symbol-l3-color: var(--color-text-primary);
--el-ul-symbol-l4: '⯀';
--el-ul-symbol-l4-color: var(--color-text-primary);
/* === OL VARIABLES === */
--el-ol-indent-l1: var(--spacing-cozy);
--el-ol-item-indent-l1: 1.5em;
--el-ol-indent-l2: var(--spacing-cozy);
--el-ol-item-indent-l2: 0.825em;
--el-ol-indent-l3: var(--spacing-cozy);
--el-ol-item-indent-l3: 0;
--el-ol-indent-l4: var(--spacing-cozy);
--el-ol-item-indent-l4: 0;
--el-ol-item-padding: var(--spacing-cozy);
--el-ol-line-height: var(--typo-leading-normal);
--el-ol-marker-color-l1: var(--color-text-primary);
--el-ol-prefix-l1: '';
--el-ol-style-l1: decimal-leading-zero;
--el-ol-suffix-l1: '.)';
--el-ol-marker-color-l2: var(--color-text-primary);
--el-ol-prefix-l2: '';
--el-ol-style-l2: lower-alpha;
--el-ol-suffix-l2: '.)';
--el-ol-marker-color-l3: var(--color-text-primary);
--el-ol-prefix-l3: '';
--el-ol-style-l3: upper-roman;
--el-ol-suffix-l3: '.)';
--el-ol-marker-color-l4: var(--color-text-primary);
--el-ol-prefix-l4: '';
--el-ol-style-l4: lower-greek;
--el-ol-suffix-l4: '.)';
/* === DL VARIABLES === */
--el-dl-font-size: var(--typo-size-md);
--el-dl-line-height: var(--typo-leading-normal);
--el-dl-vspace-base: calc(1em * var(--el-dl-line-height));
--el-dl-vspace-top: calc(var(--el-dl-vspace-base) * var(--vspace-snug));
--el-dl-vspace-bottom: calc(var(--el-dl-vspace-base) * var(--vspace-compressed));
/* === DT VARIABLES === */
--el-dt-color: var(--color-text-inverse);
--el-dt-background: var(--color-surface-inverse);
--el-dt-font-family: var(--font-heading);
--el-dt-font-size: var(--typo-size-lg);
--el-dt-font-weight: var(--typo-weight-bold);
--el-dt-line-height: 1.4;
--el-dt-text-transform: uppercase;
--el-dt-letter-spacing: 0.035em;
--el-dt-padding: var(--spacing-snug);
--el-dt-vspace-base: calc(1em * var(--el-dt-line-height));
--el-dt-vspace-top: calc(var(--el-dt-vspace-base) * var(--vspace-snug));
--el-dt-vspace-bottom: calc(var(--el-dt-vspace-base) * var(--vspace-compressed));
/* === DD VARIABLES === */
--el-dd-color: var(--color-text-primary);
--el-dd-font-family: var(--font-body);
--el-dd-font-size: var(--typo-size-md);
--el-dd-line-height: var(--typo-leading-normal);
--el-dd-indent: 0 var(--spacing-comfortable);
--el-dd-vspace-base: calc(1em * var(--el-dd-line-height));
--el-dd-vspace-top: calc(var(--el-dd-vspace-base) * var(--vspace-compressed));
--el-dd-vspace-bottom: calc(var(--el-dd-vspace-base) * var(--vspace-tight));
/* === TABLE VARIABLES === */
--el-table-font-size: var(--typo-size-sm);
--el-table-line-height: 1.2;
--el-table-border: var(--size-2) solid var(--color-text-primary);
--el-table-vspace-top: var(--spacing-tight);
--el-table-vspace-bottom: var(--spacing-tight);
/* === TH VARIABLES === */
--el-th-color: var(--color-text-inverse);
--el-th-background: var(--color-surface-inverse);
--el-th-font-family: var(--font-heading);
--el-th-font-size: var(--typo-size-sm);
--el-th-font-weight: var(--typo-weight-black);
--el-th-text-transform: uppercase;
--el-th-line-height: var(--el-table-line-height);
--el-th-padding: 0 var(--spacing-snug) var(--spacing-snug);
/* === TD VARIABLES === */
--el-td-color: var(--color-text-primary);
--el-td-font-family: var(--font-mono);
--el-td-font-size: var(--typo-size-sm);
--el-td-line-height: var(--el-table-line-height);
--el-td-padding: var(--spacing-snug);
--el-td-border: var(--size-1) solid var(--color-text-secondary);
/* === CAPTION VARIABLES === */
--el-caption-color: var(--color-text-tertiary);
--el-caption-font-family: var(--font-body);
--el-caption-font-size: var(--typo-size-sm);
--el-caption-font-style: italic;
--el-caption-text-align: center;
/* === FIGCAPTION VARIABLES === */
--el-figcaption-color: var(--color-text-tertiary);
--el-figcaption-font-family: var(--font-body);
--el-figcaption-font-size: var(--typo-size-xs);
--el-figcaption-font-style: italic;
--el-figcaption-text-align: center;
/* === SMALL VARIABLES === */
--el-small-color: var(--color-text-tertiary);
--el-small-font-family: var(--font-body);
--el-small-font-size: var(--typo-size-xs);
/* HR */
--hr-height: var(--size-3);
--hr-margin: var(--spacing-relaxed) 0;
--hr-color: var(--color-text-tertiary);
--hr-symbol-content: "▼";
--hr-symbol-size: var(--typo-size-4xl);
--hr-symbol-space: 0 0.25em;
--hr-symbol-line-height: var(--typo-leading-compressed);
--hr-symbol-color: var(--color-text-tertiary);
--hr-symbol-background: var(--color-surface-base);
}

View File

@@ -1,71 +0,0 @@
:root {
/* === TYPOGRAPHY === */
/* == Font Families == */
--font-header: var(--font-geist-sans);
--font-display: var(--font-blaka);
--font-body: var(--font-iosevka-slab);
--font-mono: var(--font-iosevka-mono);
/* == Font Sizes == */
--typo-size-responsive: clamp(1rem, 2.5vw, 1.25rem);
--typo-size-base: 16px;
--typo-size-8xl: 8em;
--typo-size-7xl: 6.375em;
--typo-size-6xl: 5.0625em;
--typo-size-5xl: 4em;
--typo-size-4xl: 3.1875em;
--typo-size-3xl: 2.5em;
--typo-size-2xl: 2em;
--typo-size-xl: 1.5625em;
--typo-size-lg: 1.25em;
--typo-size-md: 1em;
--typo-size-sm: 0.8125em;
--typo-size-xs: 0.625em;
--typo-size-2xs: 0.5em;
/* == Font Weights == */
--typo-weight-thin: 100;
--typo-weight-extralight: 200;
--typo-weight-light: 300;
--typo-weight-normal: 400;
--typo-weight-medium: 500;
--typo-weight-semibold: 600;
--typo-weight-bold: 700;
--typo-weight-extrabold: 800;
--typo-weight-black: 900;
/* == Letter Spacing == */
--typo-spacing-tightest: -0.05em;
--typo-spacing-tighter: -0.025em;
--typo-spacing-tight: -0.0125em;
--typo-spacing-normal: 0em;
--typo-spacing-relaxed: 0.025em;
--typo-spacing-comfortable: 0.05em;
--typo-spacing-loose: 0.1em;
--typo-spacing-looser: 0.15em;
--typo-spacing-loosest: 0.2em;
/* == Line Height == */
--typo-leading-compressed: 1.0;
--typo-leading-tight: 1.125;
--typo-leading-snug: 1.25;
--typo-leading-cozy: 1.375;
--typo-leading-normal: 1.5;
--typo-leading-relaxed: 1.625;
--typo-leading-comfortable: 1.75;
--typo-leading-loose: 1.875;
--typo-leading-spacious: 2.0;
/* == Vertical Spacing == */
--vspace-compressed: 0.25;
--vspace-tight: 0.5;
--vspace-snug: 0.75;
--vspace-cozy: 1;
--vspace-normal: 1.25;
--vspace-relaxed: 1.5;
--vspace-comfortable: 1.75;
--vspace-loose: 2;
--vspace-spacious: 2.5;
}