@toybreaker/fiko 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,8 +21,6 @@ fiko takes a third path: a minimal, layered foundation you override by design, n
21
21
  ## Install
22
22
 
23
23
  ```bash
24
- npm install @toybreaker/fiko
25
- # or
26
24
  pnpm add @toybreaker/fiko
27
25
  ```
28
26
 
@@ -37,7 +35,7 @@ pnpm add @toybreaker/fiko
37
35
  @import "@toybreaker/fiko";
38
36
  ```
39
37
 
40
- This imports `omg/` — the brand-agnostic framework. It declares six cascade layers and imports all `omg/` sheets in the correct order.
38
+ This imports `omg/` — the brand-agnostic framework. It declares seven cascade layers and imports all `omg/` sheets in the correct order.
41
39
 
42
40
  ### 2. Add your brand (copy the template)
43
41
 
@@ -52,18 +50,18 @@ Then import your brand tokens **after** the framework, inside the same layers:
52
50
  @import "@toybreaker/fiko";
53
51
 
54
52
  /* brand palette — loads in the tokens layer */
55
- @import url(./branding/1client_vars.css) layer(tokens);
53
+ @import url(./branding/palette.css) layer(tokens);
56
54
 
57
55
  /* semantic aliases (surface, text, cta) — loads in the theme layer */
58
- @import url(./branding/2client_datatheme.css) layer(theme);
56
+ @import url(./branding/roles.css) layer(theme);
59
57
 
60
58
  /* element defaults, heading scale — loads in the theme layer */
61
- @import url(./branding/3client_theme.css) layer(theme);
59
+ @import url(./branding/overrides.css) layer(theme);
62
60
  ```
63
61
 
64
62
  ### 3. Customize your brand
65
63
 
66
- Edit `branding/1client_vars.css` — change the hue angle for your brand color:
64
+ Edit `branding/palette.css` — change the hue angle for your brand color:
67
65
 
68
66
  ```css
69
67
  --brand: oklch(0.55 0.19 28); /* orange — change the hue (0–360) */
@@ -85,9 +83,9 @@ fiko/
85
83
  │ └── utils/ ← atomic utility classes
86
84
 
87
85
  └── branding/ ← YOUR BRAND — per-client, fully owned, never extracted
88
- ├── 1client_vars.css ← raw palette (OKLCH colors)
89
- ├── 2client_datatheme.css ← semantic aliases (surface, text, cta…)
90
- └── 3client_theme.css ← element defaults, heading scale, brand specifics
86
+ ├── palette.css ← raw brand colors (OKLCH tokens)
87
+ ├── roles.css ← semantic aliases (surface, text, cta…)
88
+ └── overrides.css ← element defaults, heading scale, brand specifics
91
89
  ```
92
90
 
93
91
  **The rule:** if it could work on any website → `omg/`. If it's specific to one brand → `branding/`.
@@ -97,20 +95,23 @@ fiko/
97
95
  ## Cascade Layers
98
96
 
99
97
  ```css
100
- @layer reset, tokens, theme, layout, components, utilities;
98
+ @layer reset, tokens, base, theme, layout, components, utilities;
101
99
  ```
102
100
 
103
- | Layer | Purpose |
104
- |---|---|
105
- | `reset` | Margin/padding zero, box-sizing, smooth scroll |
106
- | `tokens` | CSS custom properties: spacing, type, color |
107
- | `theme` | Semantic aliases + element defaults |
108
- | `layout` | Body, container, grid, nav |
109
- | `components` | Buttons, inputs, links |
110
- | `utilities` | Atomic helpers: `.hide`, `.flex`, `.center`, etc. |
101
+ | Layer | Purpose | Your files |
102
+ |---|---|---|
103
+ | `reset` | Margin/padding zero, box-sizing, smooth scroll | — |
104
+ | `tokens` | CSS custom properties: spacing, type, color | `branding/palette.css` |
105
+ | `base` | Element defaults (h1–h6, p, blockquote) | — |
106
+ | `theme` | Semantic aliases + brand overrides | `branding/roles.css`, `branding/overrides.css` |
107
+ | `layout` | Body, container, grid, nav | — |
108
+ | `components` | Buttons, inputs, links | |
109
+ | `utilities` | Atomic helpers: `.hide`, `.flex`, `.center`, etc. | — |
111
110
 
112
111
  `@layer` makes specificity predictable. A utility class in `utilities` always beats a component in `components` — no `!important` wars.
113
112
 
113
+ **Why `theme` after `base`?** `base` sets sensible element defaults (e.g. `h1` size). Your `overrides.css` in `theme` always wins over them — no high-specificity selectors needed.
114
+
114
115
  ---
115
116
 
116
117
  ## OKLCH Colors
@@ -138,7 +139,8 @@ All color tokens use OKLCH:
138
139
  | `.pad_block_sm` | block padding small |
139
140
  | `.h1` – `.h6` | heading scale classes |
140
141
  | `.dim` | secondary text color + smaller size |
141
- | `.typewriter` | `max-width: 66ch; margin-inline: auto` |
142
+ | `.typewriter` | `font-family: var(--font_serif)` "Courier New", Courier, monospace |
143
+ | `.prose` | `max-width: 66ch; margin-inline: auto` |
142
144
  | `.aspect_square` | `aspect-ratio: 1` |
143
145
  | `.aspect_video` | `aspect-ratio: 16/9` |
144
146
 
@@ -153,6 +155,23 @@ All color tokens use OKLCH:
153
155
 
154
156
  ---
155
157
 
158
+ ## Local Development
159
+
160
+ ```bash
161
+ # dev server — opens http://localhost:3000/demo/ automatically
162
+ pnpm dev
163
+
164
+ # build demo into dist/
165
+ pnpm build
166
+
167
+ # build + deploy to Netlify
168
+ pnpm deploy
169
+ ```
170
+
171
+ `pnpm dev` serves the repo root (so `demo/index.html` can load `../index.css`) and opens the browser automatically. Edit any file in `omg/` or `demo/` and reload — no build step needed during development.
172
+
173
+ ---
174
+
156
175
  ## Pairing with Astro
157
176
 
158
177
  fiko was designed to pair with Astro scoped styles:
package/index.css CHANGED
@@ -16,11 +16,11 @@
16
16
  *
17
17
  * your-project/404.css
18
18
  * ├── @import "@junglesta/404css"; ← this file (tokens + layout + components + utils)
19
- * ├── @import "./000/1client_vars.css" layer(tokens);
20
- * ├── @import "./000/2client_datatheme.css" layer(theme);
21
- * └── @import "./000/3client_theme.css" layer(theme);
19
+ * ├── @import "./000/palette.css" layer(tokens);
20
+ * ├── @import "./000/roles.css" layer(theme);
21
+ * └── @import "./000/overrides.css" layer(theme);
22
22
  *
23
- * Starter 000/ templates are in node_modules/@junglesta/404css/template/000/
23
+ * Starter templates are in node_modules/fiko/template/branding/
24
24
  * ─────────────────────────────────────────────
25
25
  */
26
26
 
@@ -50,3 +50,5 @@
50
50
  @import url(omg/utils/aspect.css) layer(utilities);
51
51
  @import url(omg/utils/gradients.css) layer(utilities);
52
52
  @import url(omg/utils/misc.css) layer(utilities);
53
+
54
+ @import url(omg/utils/fiko.css) layer(utilities);
package/omg/1vars.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /*! 🐉 404.css | MIT License */
2
2
  /* 1vars.css — layout, spacing, typography tokens */
3
- /* Brand palette overrides live in branding/1client_vars.css */
3
+ /* Brand palette overrides live in branding/palette.css */
4
4
 
5
5
  :root {
6
6
  /* ── COLOR NEUTRALS ──────────────────────────── */
package/omg/4layout.css CHANGED
@@ -76,29 +76,51 @@ nav li {
76
76
  }
77
77
 
78
78
  /* ── BENTO BOX ──────────────────────────────────── */
79
- /* Mosaic product grid. Wrap cards in <div class="bento"> */
79
+ /* Mosaic product grid. Wrap cards in <div class="bento">
80
+ *
81
+ * Token-driven: adjust --bento_cols / --bento_rows at any level.
82
+ * aspect-ratio keeps cells proportional automatically.
83
+ * grid-auto-flow: dense fills gaps — add items in any order.
84
+ *
85
+ * Quick override examples:
86
+ * style="--bento_cols:4; --bento_rows:2" → 4×2 landscape
87
+ * style="--bento_cols:2; --bento_rows:4" → 2×4 portrait
88
+ *
89
+ * Span modifiers on children:
90
+ * .bento_col_2 / .bento_col_3 → span N columns
91
+ * .bento_row_2 / .bento_row_3 → span N rows
92
+ * .bento_full → full width
93
+ */
80
94
 
81
95
  .bento {
96
+ --bento_cols: 3;
97
+ --bento_rows: 3;
82
98
  display: grid;
83
- grid-template-columns: 1fr;
99
+ grid-template-columns: repeat(var(--bento_cols), 1fr);
100
+ grid-template-rows: repeat(var(--bento_rows), 1fr);
101
+ grid-auto-flow: dense;
84
102
  gap: calc(var(--spaceV) * 0.5) calc(var(--spaceH) * 0.5);
85
103
  width: 100%;
104
+ aspect-ratio: var(--bento_cols) / var(--bento_rows);
86
105
  }
87
106
 
88
- .bento > :first-child { grid-column: 1 / -1; }
107
+ /* Featured first child: 2×2 */
108
+ .bento > :first-child { grid-column: span 2; grid-row: span 2; }
89
109
 
90
- .bento > :nth-child(7n + 1):not(:first-child) { grid-column: 1 / -1; }
110
+ /* ── Span modifiers ─────────────────────────────── */
111
+ .bento > .bento_col_2 { grid-column: span 2; }
112
+ .bento > .bento_col_3 { grid-column: span 3; }
113
+ .bento > .bento_full { grid-column: 1 / -1; }
114
+ .bento > .bento_row_2 { grid-row: span 2; }
115
+ .bento > .bento_row_3 { grid-row: span 3; }
91
116
 
92
- @container main-container (min-width: 480px) {
93
- .bento { grid-template-columns: 1fr 1fr; }
117
+ /* ── Responsive defaults ────────────────────────── */
118
+ @container main-container (max-width: 479px) {
119
+ .bento { --bento_cols: 1; --bento_rows: 6; }
120
+ .bento > :first-child { grid-column: span 1; grid-row: span 1; }
94
121
  }
95
122
 
96
- @container main-container (min-width: 640px) {
97
- .bento { grid-template-columns: 1fr 1fr 1fr; }
98
- .bento > :first-child { grid-column: 1 / 3; grid-row: 1 / 3; }
99
- }
100
-
101
- @container main-container (min-width: 960px) {
102
- .bento { grid-template-columns: repeat(4, 1fr); }
103
- .bento > :first-child { grid-column: 1 / 3; grid-row: 1 / 3; }
123
+ @container main-container (min-width: 480px) and (max-width: 639px) {
124
+ .bento { --bento_cols: 2; --bento_rows: 4; }
125
+ .bento > :first-child { grid-column: span 2; grid-row: span 2; }
104
126
  }
@@ -126,11 +126,15 @@ svg:not(:root) {
126
126
  text-underline-offset: 3px;
127
127
  }
128
128
 
129
- .typewriter {
129
+ .prose {
130
130
  max-width: 66ch;
131
131
  margin-inline: auto;
132
132
  }
133
133
 
134
+ .typewriter {
135
+ font-family: var(--font_serif);
136
+ }
137
+
134
138
  .cat { text-transform: capitalize; }
135
139
 
136
140
  /* ── LAYOUT UTILITIES ───────────────────────────── */
@@ -140,7 +144,7 @@ svg:not(:root) {
140
144
  margin-right: var(--maximise);
141
145
  }
142
146
 
143
- .clipped-circle {
147
+ .clipped_circle {
144
148
  clip-path: circle(50px at center);
145
149
  }
146
150
 
@@ -202,6 +206,40 @@ details.accordion > :not(summary) {
202
206
  padding: var(--spaceV) var(--spaceH);
203
207
  }
204
208
 
209
+ /* ── ACCORDION CHEVRON — SVG arrow marker ────────── */
210
+ /* Modifier: <details class="accordion accordion_chevron">
211
+ * Replaces +/× text with an animated SVG chevron via mask-image.
212
+ * Closed: → pointing right. Open: rotated 90° pointing down.
213
+ * Composable: stack with other modifiers for full editorial style.
214
+ * Color inherits --cta; override with: style="--cta: var(--brand)"
215
+ */
216
+
217
+ details.accordion.accordion_chevron > summary::after,
218
+ details.accordion.accordion_chevron[open] > summary::after {
219
+ content: '';
220
+ display: block;
221
+ width: 1.25em;
222
+ height: 1.25em;
223
+ flex-shrink: 0;
224
+ background-color: var(--cta);
225
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9 6L15 12L9 18'/%3E%3C/svg%3E");
226
+ -webkit-mask-size: contain;
227
+ -webkit-mask-repeat: no-repeat;
228
+ -webkit-mask-position: center;
229
+ mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9 6L15 12L9 18'/%3E%3C/svg%3E");
230
+ mask-size: contain;
231
+ mask-repeat: no-repeat;
232
+ mask-position: center;
233
+ transform: rotate(0deg);
234
+ transition: transform 200ms ease, background-color var(--transition);
235
+ line-height: 1;
236
+ font-size: 1em;
237
+ }
238
+
239
+ details.accordion.accordion_chevron[open] > summary::after {
240
+ transform: rotate(90deg);
241
+ }
242
+
205
243
  /* ── DOT LEADER ─────────────────────────────────── */
206
244
  /* Usage: <span class="dots"> between label and value in menus/TOC */
207
245
 
@@ -0,0 +1,66 @@
1
+ /*! fiko | MIT License */
2
+ /* utils/fiko.css — .fiko signature class
3
+ *
4
+ * Adds the warm animated orb glow to any element.
5
+ * Usage: <section class="fiko"> … </section>
6
+ *
7
+ * Requirements: the element needs dimensions (height/min-height).
8
+ * Pseudo-elements carry the orbs; direct children stay above via z-index.
9
+ * Override orb colors with --fiko_orb_a / --fiko_orb_b.
10
+ */
11
+
12
+ .fiko {
13
+ --fiko_orb_a: oklch(0.65 0.22 40); /* warm orange */
14
+ --fiko_orb_b: oklch(0.72 0.20 65); /* amber */
15
+ position: relative;
16
+ overflow: hidden;
17
+ background: var(--dark, oklch(0.12 0.01 265));
18
+ }
19
+
20
+ .fiko::before,
21
+ .fiko::after {
22
+ content: '';
23
+ position: absolute;
24
+ border-radius: 50%;
25
+ pointer-events: none;
26
+ z-index: 0;
27
+ }
28
+
29
+ /* primary orb — top-right */
30
+ .fiko::before {
31
+ width: 60%;
32
+ aspect-ratio: 1;
33
+ background: var(--fiko_orb_a);
34
+ filter: blur(80px);
35
+ opacity: 0.22;
36
+ top: -20%;
37
+ right: -10%;
38
+ animation: fiko_orb_drift 9s ease-in-out infinite;
39
+ }
40
+
41
+ /* secondary orb — bottom-right */
42
+ .fiko::after {
43
+ width: 40%;
44
+ aspect-ratio: 1;
45
+ background: var(--fiko_orb_b);
46
+ filter: blur(60px);
47
+ opacity: 0.15;
48
+ bottom: -10%;
49
+ right: 25%;
50
+ animation: fiko_orb_drift 13s ease-in-out infinite reverse;
51
+ }
52
+
53
+ /* keep children above orbs */
54
+ .fiko > * { position: relative; z-index: 1; }
55
+
56
+ @keyframes fiko_orb_drift {
57
+ 0% { transform: translate(0, 0) scale(1); }
58
+ 33% { transform: translate(30px, -20px) scale(1.05); }
59
+ 66% { transform: translate(-20px, 15px) scale(0.96); }
60
+ 100% { transform: translate(0, 0) scale(1); }
61
+ }
62
+
63
+ @media (prefers-reduced-motion: reduce) {
64
+ .fiko::before,
65
+ .fiko::after { animation: none; }
66
+ }
@@ -1,5 +1,7 @@
1
1
  /*! 🐉 404.css | MIT License */
2
2
  /* utils/gradients.css — gradient utility classes */
3
3
 
4
- .gradient_brand { background: var(--gradient_brand); }
5
- .gradient_warm { background: var(--gradient_warm); }
4
+ .gradient_o { background: var(--gradient_o); }
5
+ .gradient_h { background: var(--gradient_h); }
6
+ .gradient_v { background: var(--gradient_v); }
7
+ .gradient_warm { background: var(--gradient_warm); }
@@ -25,3 +25,7 @@
25
25
  .pretty {
26
26
  text-wrap: pretty;
27
27
  }
28
+
29
+ .mono {
30
+ font-family: ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, monospace;
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toybreaker/fiko",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "LOOK GOOD OR DIE! — cascade layers, OKLCH colors, design tokens. Zero specificity wars. Smiling DX.",
5
5
  "license": "MIT",
6
6
  "author": "Toybreaker <hello@junglestar.co>",
@@ -21,6 +21,11 @@
21
21
  "utility-css",
22
22
  "modern-css"
23
23
  ],
24
+ "scripts": {
25
+ "dev": "serve . & sleep 1 && open http://localhost:3000/demo/",
26
+ "build": "node scripts/build-demo.mjs",
27
+ "deploy": "node scripts/build-demo.mjs && netlify deploy --prod --dir=dist"
28
+ },
24
29
  "main": "index.css",
25
30
  "style": "index.css",
26
31
  "exports": {
@@ -32,5 +37,8 @@
32
37
  "index.css",
33
38
  "omg/",
34
39
  "template/"
35
- ]
40
+ ],
41
+ "devDependencies": {
42
+ "serve": "^14.2.6"
43
+ }
36
44
  }
@@ -0,0 +1,15 @@
1
+ /*! fiko | MIT License */
2
+ /* branding/overrides.css — brand-specific overrides
3
+ *
4
+ * Injected into the `theme` layer:
5
+ * @import url(./branding/overrides.css) layer(theme);
6
+ *
7
+ * .h1–.h6, .dim, .underline, .typewriter, .prose, .dots, .maximise,
8
+ * .cat, .bento, .accordion, [lang] switching are in fiko core (omg/).
9
+ * Add brand/client-specific rules here only.
10
+ */
11
+
12
+ /* ── EXAMPLE OVERRIDES ──────────────────────────── */
13
+
14
+ /* .typewriter { font-family: var(--font_serif); } */
15
+ /* blockquote.typewriter { border-left-style: dotted; } */
@@ -1,10 +1,13 @@
1
- /*! 🐉 404.css | MIT License */
2
- /* branding/1client_vars.css — brand palette tokens
1
+ /*! fiko | MIT License */
2
+ /* branding/palette.css — raw brand color tokens
3
3
  *
4
- * Neutrals (--dark, --light and alpha variants) are defined in
5
- * omg/1vars.css — override here only if your brand uses a tinted surface.
4
+ * Injected into the `tokens` layer:
5
+ * @import url(./branding/palette.css) layer(tokens);
6
6
  *
7
- * Add brand-specific tokens: --brand, --nobori, --surface_*, gradients, etc.
7
+ * Neutrals (--dark, --light and alpha variants) are defined in omg/1vars.css.
8
+ * Override here only if your brand uses a tinted surface.
9
+ *
10
+ * Add brand-specific tokens: --brand, --surface_*, gradients, etc.
8
11
  */
9
12
 
10
13
  :root {
@@ -1,8 +1,11 @@
1
- /*! 🐉 404.css | MIT License */
2
- /* 000/2client_datatheme.css — semantic theme aliases
1
+ /*! fiko | MIT License */
2
+ /* branding/roles.css — semantic theme aliases
3
+ *
4
+ * Maps raw palette tokens (from palette.css) to semantic roles.
5
+ *
6
+ * Injected into the `theme` layer:
7
+ * @import url(./branding/roles.css) layer(theme);
3
8
  *
4
- * Maps raw palette tokens (from 1client_vars.css) to semantic roles.
5
- * This file loads in the `theme` layer.
6
9
  * Permanent light mode — dark mode intentionally excluded.
7
10
  */
8
11
 
@@ -1,12 +0,0 @@
1
- /*! 🐉 404.css | MIT License */
2
- /* branding/3client_theme.css — brand-specific overrides
3
- *
4
- * .h1–.h6, .dim, .underline, .typewriter, .dots, .maximise,
5
- * .clipped-circle, .cat, .bento, [lang] switching are in fiko core.
6
- * Add brand/client-specific rules here only.
7
- */
8
-
9
- /* ── EXAMPLE OVERRIDES ──────────────────────────── */
10
-
11
- /* .typewriter { font-family: var(--font_serif); } */
12
- /* blockquote.typewriter { border-left-style: dotted; } */