nk_jtb 0.28.0 → 0.28.2

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.
@@ -51,6 +51,8 @@ and typography helpers.
51
51
  - `preview-class="..."` → class applied to the preview container only, keeps copied code clean
52
52
  - `+demo` / `+demo-folded` → render preview and code together
53
53
 
54
+ Use raw HTML (no demo attribute) when the block is purely visual demonstration and the markup is scaffold — showing the code would add noise rather than value.
55
+
54
56
  For layout/responsive docs, use:
55
57
 
56
58
  ```md
@@ -59,7 +61,9 @@ For layout/responsive docs, use:
59
61
 
60
62
  ## Examples Files
61
63
 
62
- Quick visual references — not comprehensive docs. Two files:
64
+ Quick visual references — not comprehensive docs.
65
+
66
+ **Default files:**
63
67
 
64
68
  - `docs/examples/showcase-typography.md` — font sizes, weights, families, text utilities
65
69
  - `docs/examples/showcase-ui.md` — components and UI elements: buttons, badges, checklist, box etc.
@@ -76,8 +80,6 @@ Format depends on content type:
76
80
 
77
81
  Group by component family under `##` headings. Variants sit under `###` within that group.
78
82
 
79
- Do not create a new examples file for a single component. If it does not fit the two above, discuss with the user.
80
-
81
83
  When a section of a component or utility doc is complete, ask:
82
84
 
83
85
  > Do you want this added to an examples file?
package/AGENTS.md CHANGED
@@ -198,16 +198,26 @@ follow the direction.
198
198
  - When a skill system is available and a skill applies, invoke it before
199
199
  proceeding unless it conflicts with the user's explicit request.
200
200
  - Do not treat reading a `SKILL.md` file as a substitute for invoking the skill.
201
- - When updating prompts, guidelines, or skills, first identify the project's
202
- source-of-truth file before editing.
203
201
  - Skills and guidelines are always edited via `.ai/` — never agent-managed
204
- directories (`.claude/`, `.cursor/`, `.windsurf/`, etc.) directly.
205
- - Check whether the `.ai/` entry is a local file or a symlink before editing.
206
- If it is a symlink, follow it to the target and edit there.
202
+ directories (`.claude/`, `.cursor/`, `.windsurf/`, etc.) directly. The path
203
+ you read from when a skill is invoked is never the path you edit.
204
+ - Before editing any skill or guideline, run `ls -la .ai/skills/` or
205
+ `ls -la .ai/guidelines/` to confirm the correct source path. Do this every
206
+ time — do not skip it, do not rely on Glob, do not edit the path you read from.
207
+ - Glob does not follow or reveal symlinks and will return misleading results.
208
+ Always use `ls -la` to locate files in `.ai/`.
209
+ - If the file cannot be found after checking with `ls -la`, stop and ask.
210
+ Do not assume it does not exist, do not fall back to agent-managed
211
+ directories, and do not proceed without knowing the correct location.
212
+ - Check whether the `.ai/` entry is a local file or a symlink. If it is a
213
+ symlink, follow it to the target and edit there.
207
214
  - Do not update matching copies in parallel or alternate locations unless they
208
215
  are the confirmed source of truth or the user explicitly asks.
209
- - After changing project guidelines or adding/updating skills, run
210
- `php artisan boost:update` in the project so the changes take effect.
216
+ - After changing project guidelines or adding/updating skills, run the
217
+ project's sync command to propagate changes to agent-managed directories.
218
+ Check `package.json` for an `ai:sync` script or equivalent. If no sync
219
+ command is available, note that the change will not propagate until the next
220
+ sync.
211
221
  - When a skill or prompt references a file that cannot be read, first try
212
222
  resolving it from the repository root.
213
223
  - If the file still cannot be found, stop and ask before proceeding.
package/CLAUDE.md CHANGED
@@ -198,16 +198,26 @@ follow the direction.
198
198
  - When a skill system is available and a skill applies, invoke it before
199
199
  proceeding unless it conflicts with the user's explicit request.
200
200
  - Do not treat reading a `SKILL.md` file as a substitute for invoking the skill.
201
- - When updating prompts, guidelines, or skills, first identify the project's
202
- source-of-truth file before editing.
203
201
  - Skills and guidelines are always edited via `.ai/` — never agent-managed
204
- directories (`.claude/`, `.cursor/`, `.windsurf/`, etc.) directly.
205
- - Check whether the `.ai/` entry is a local file or a symlink before editing.
206
- If it is a symlink, follow it to the target and edit there.
202
+ directories (`.claude/`, `.cursor/`, `.windsurf/`, etc.) directly. The path
203
+ you read from when a skill is invoked is never the path you edit.
204
+ - Before editing any skill or guideline, run `ls -la .ai/skills/` or
205
+ `ls -la .ai/guidelines/` to confirm the correct source path. Do this every
206
+ time — do not skip it, do not rely on Glob, do not edit the path you read from.
207
+ - Glob does not follow or reveal symlinks and will return misleading results.
208
+ Always use `ls -la` to locate files in `.ai/`.
209
+ - If the file cannot be found after checking with `ls -la`, stop and ask.
210
+ Do not assume it does not exist, do not fall back to agent-managed
211
+ directories, and do not proceed without knowing the correct location.
212
+ - Check whether the `.ai/` entry is a local file or a symlink. If it is a
213
+ symlink, follow it to the target and edit there.
207
214
  - Do not update matching copies in parallel or alternate locations unless they
208
215
  are the confirmed source of truth or the user explicitly asks.
209
- - After changing project guidelines or adding/updating skills, run
210
- `php artisan boost:update` in the project so the changes take effect.
216
+ - After changing project guidelines or adding/updating skills, run the
217
+ project's sync command to propagate changes to agent-managed directories.
218
+ Check `package.json` for an `ai:sync` script or equivalent. If no sync
219
+ command is available, note that the change will not propagate until the next
220
+ sync.
211
221
  - When a skill or prompt references a file that cannot be read, first try
212
222
  resolving it from the repository root.
213
223
  - If the file still cannot be found, stop and ask before proceeding.
@@ -1,47 +1,14 @@
1
- # Auto Spacing System (review)
1
+ # Auto Spacing
2
2
 
3
3
  <p class="lead">Automatic vertical spacing between block elements without
4
- requiring margin utilities on every element. Content flows naturally with
5
- consistent gaps.</p>
4
+ requiring margin utilities on every element.</p>
6
5
 
7
- - **Relationship-Based** - Spacing determined by what elements follow each other
8
- - **Semantic-Aware** - Distinguishes between content and layout wrappers
9
6
  - **Flex/Grid Safe** - Automatically opts out when using gap-based layouts
10
7
  - **Low Specificity** - Uses `:where()` for easy overrides
11
8
 
12
- ## How It Works (review)
9
+ ## Examples
13
10
 
14
- Two rules apply `margin-top: $base-gap` based on element relationships. Spacing
15
- targets (`p`, `h1-h6`, `table`, `ul`, etc.) add spacing when followed by other
16
- elements. Layout wrappers (`div`, `section`, `article`) only add spacing when
17
- followed by content—not other wrappers.
18
-
19
- ## The Rules (review)
20
-
21
- ### Rule 1: Spacing Targets (review)
22
-
23
- Content elements followed by any block element.
24
-
25
- ```scss +code
26
- :where(#{$spacing-targets}, #{$common-classes}) + :where(*:not(#{$inline-exclusions})) {
27
- margin-block-start: $base-gap;
28
- }
29
- ```
30
-
31
- ### Rule 2: Layout to Content (review)
32
-
33
- Layout wrappers followed by content elements. This prevents `div + div` spacing
34
- while catching `div + p`.
35
-
36
- ```scss +code
37
- :where(div, section, article) + :where(#{$spacing-targets}) {
38
- margin-block-start: $base-gap;
39
- }
40
- ```
41
-
42
- ## Visual Tests (review)
43
-
44
- ### Should Space (review)
11
+ ### Should Space
45
12
 
46
13
  <div class="bx bg-stripes-pink">
47
14
  <h2 class="pxy-075 warning-light rounded-05">Heading 2</h2>
@@ -55,7 +22,7 @@ while catching `div + p`.
55
22
  <pre class="pxy-075 warning-light rounded-05">Pre</pre>
56
23
  </div>
57
24
 
58
- ### Should NOT Space (review)
25
+ ### Should NOT Space
59
26
 
60
27
  <div class="bx bg-stripes-blue">
61
28
  <div class="pxy-075 info-light rounded-05">Div</div>
@@ -66,16 +33,10 @@ while catching `div + p`.
66
33
  <footer class="pxy-075 info-light rounded-05">Footer</footer>
67
34
  </div>
68
35
 
69
- ## Flex and Grid (review)
36
+ ### Flex and Grid
70
37
 
71
38
  Elements inside flex or grid containers have margins reset—these layouts use `gap` instead.
72
39
 
73
- ```scss +code
74
- :where([class*='flex'], [class*='grid']) > * {
75
- margin: 0;
76
- }
77
- ```
78
-
79
40
  <div class="grid cols-2 gap-1">
80
41
  <div>
81
42
  <p class="txt-sm">Flex (uses gap)</p>
@@ -95,3 +56,17 @@ Elements inside flex or grid containers have margins reset—these layouts use `
95
56
  </div>
96
57
  </div>
97
58
  </div>
59
+
60
+ ## How It Works
61
+
62
+ Spacing is applied by element relationship, not position. Two categories determine behaviour:
63
+
64
+ **Spacing targets** — `p`, headings, `ul`, `table`, `form`, `blockquote`, `pre` — add
65
+ `margin-block-start` to whatever follows them.
66
+
67
+ **Layout wrappers** — `div`, `section`, `article` — only add spacing when followed by
68
+ content, not other wrappers. This prevents `div + div` from being spaced while
69
+ still catching `div + p`.
70
+
71
+ Elements inside flex or grid containers are exempt — margins reset to zero and
72
+ `gap` handles spacing instead.
@@ -242,7 +242,7 @@ a doc is confirmed accurate or a utility is completed.
242
242
  | `layouts-and-structures.md` | ✅ | |
243
243
  | `responsive-design-patterns.md` | review | |
244
244
  | `responsive-design.md` | review | |
245
- | `automatic-spacing.md` | review | |
245
+ | `automatic-spacing.md` | | |
246
246
  | `conventions-and-architecture-rules.md` | review | |
247
247
  | `magic-classes.md` | ✅ | |
248
248
  | `themes.md` | review | |
@@ -0,0 +1,416 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>JTB — Homepage Examples</title>
8
+ </head>
9
+
10
+ <body>
11
+
12
+ <!-- ═══════════════════════════════════════════════════════════════
13
+ EXAMPLE 1: AURORA
14
+ Dark gradient hero with floating blob shapes and swirl decoration
15
+ ═══════════════════════════════════════════════════════════════ -->
16
+
17
+ <nav class="navbar bg-slate-900">
18
+ <div class="container">
19
+ <a href="#" class="flex items-center gap-1">
20
+ <svg width="28" height="28" viewBox="0 0 28 28" fill="none" aria-hidden="true">
21
+ <circle cx="14" cy="14" r="14" fill="oklch(60.6% 0.25 292.717deg)" />
22
+ <path d="M8 20 L14 8 L20 20 M10.5 16 H17.5" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
23
+ </svg>
24
+ <span class="txt-white font-bold tracking-tight">Luminary</span>
25
+ </a>
26
+ <ul class="menu">
27
+ <li><a href="#" class="txt-gray-400">Features</a></li>
28
+ <li><a href="#" class="txt-gray-400">Pricing</a></li>
29
+ <li><a href="#" class="txt-gray-400">Docs</a></li>
30
+ <li><a href="#" class="txt-gray-400">Blog</a></li>
31
+ </ul>
32
+ <div class="flex gap-1">
33
+ <button class="btn sm">Sign in</button>
34
+ <button class="btn sm primary">Get Started</button>
35
+ </div>
36
+ </div>
37
+ </nav>
38
+
39
+ <div class="ex-hero bg-linear-to-br from-violet-950 to-indigo-900 relative overflow-hidden flex flex-col items-center justify-center pxy-4">
40
+
41
+ <!-- Blob shapes — organic border-radius via local helper -->
42
+ <div class="blob shape-tl absolute wh-30 bg-violet-500 opacity-20"></div>
43
+ <div class="blob-2 shape-br absolute wh-24 bg-indigo-400 opacity-20"></div>
44
+ <div class="rounded-full shape-mid-r absolute wh-16 bg-fuchsia-500 opacity-10"></div>
45
+ <div class="rounded-full shape-mid-l absolute wh-10 bg-sky-400 opacity-10"></div>
46
+
47
+ <!-- SVG swirl -->
48
+ <svg class="swirl-deco absolute opacity-10" width="600" height="600" viewBox="0 0 600 600" fill="none" aria-hidden="true">
49
+ <path d="M300 300 C300 200, 450 200, 450 300 C450 400, 300 400, 300 300 C300 150, 500 150, 500 300 C500 450, 250 500, 200 350 C150 200, 350 100, 450 200" stroke="white" stroke-width="1.5" fill="none" />
50
+ <path d="M300 300 C250 250, 200 300, 200 350 C200 420, 280 450, 350 420 C420 390, 460 320, 430 250 C400 180, 320 160, 260 200 C180 250, 160 360, 220 420 C280 480, 400 460, 450 380" stroke="white" stroke-width="1" fill="none" opacity="0.6" />
51
+ </svg>
52
+
53
+ <!-- Content -->
54
+ <div class="relative tac ex-hero-content">
55
+ <span class="txt-violet-300 txt-sm font-semibold tracking-widest uppercase">Platform &middot; 2025</span>
56
+ <h1 class="txt-white font-black lh-tight txt-4">Build beyond<br>ordinary limits</h1>
57
+ <p class="txt-indigo-200 lead">The design framework that lets you move fast without breaking things. Clean utilities, beautiful defaults, zero compromise.</p>
58
+ <div class="flex justify-center gap-1">
59
+ <button class="btn lg primary">Start for free</button>
60
+ <button class="btn lg">See the docs</button>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- Bottom fade -->
65
+ <div class="absolute bottom-0 left-0 w-full ex-fade-bottom"></div>
66
+ </div>
67
+
68
+ <div class="ex-spacer bg-slate-900"></div>
69
+
70
+
71
+ <!-- ═══════════════════════════════════════════════════════════════
72
+ EXAMPLE 2: CLARITY
73
+ Light split hero with geometric shapes on the right
74
+ ═══════════════════════════════════════════════════════════════ -->
75
+
76
+ <nav class="navbar bg-white shadow-sm">
77
+ <div class="container">
78
+ <a href="#" class="flex items-center gap-1">
79
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
80
+ <rect x="2" y="2" width="9" height="9" rx="2" fill="oklch(62.3% 0.214 259.815deg)" />
81
+ <rect x="13" y="2" width="9" height="9" rx="2" fill="oklch(70.2% 0.183 293.541deg)" opacity="0.6" />
82
+ <rect x="2" y="13" width="9" height="9" rx="2" fill="oklch(70.2% 0.183 293.541deg)" opacity="0.6" />
83
+ <rect x="13" y="13" width="9" height="9" rx="2" fill="oklch(62.3% 0.214 259.815deg)" />
84
+ </svg>
85
+ <span class="txt-slate-900 font-bold">Nexus</span>
86
+ </a>
87
+ <ul class="menu">
88
+ <li><a href="#" class="txt-gray-600">Product</a></li>
89
+ <li><a href="#" class="txt-gray-600">Solutions</a></li>
90
+ <li><a href="#" class="txt-gray-600">Enterprise</a></li>
91
+ <li><a href="#" class="txt-gray-600">Pricing</a></li>
92
+ </ul>
93
+ <div class="flex gap-1 items-center">
94
+ <a href="#" class="txt-gray-600 txt-sm">Log in</a>
95
+ <button class="btn sm primary">Book a demo</button>
96
+ </div>
97
+ </div>
98
+ </nav>
99
+
100
+ <div class="ex-hero bg-gray-50 relative overflow-hidden flex items-center">
101
+ <div class="container">
102
+ <div class="grid cols-2 items-center ex-hero-grid-gap">
103
+
104
+ <!-- Left: content -->
105
+ <div>
106
+ <div class="flex items-center gap-05 ex-badge-row">
107
+ <span class="badge primary">New</span>
108
+ <span class="txt-sm txt-gray-600">v3.0 is here — <a href="#" class="txt-primary">read the changelog</a></span>
109
+ </div>
110
+ <h1 class="txt-slate-900 font-black lh-tight txt-3">The platform teams<br>actually love using</h1>
111
+ <p class="lead txt-gray-600">Ship faster with infrastructure that gets out of your way. Built for teams who care about developer experience.</p>
112
+ <div class="flex gap-1 items-center">
113
+ <button class="btn lg primary">Get started free</button>
114
+ <a href="#" class="flex items-center gap-05 txt-gray-600 txt-sm">
115
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
116
+ <circle cx="8" cy="8" r="7.5" stroke="currentColor" stroke-width="1" />
117
+ <path d="M6 5.5 L10.5 8 L6 10.5Z" fill="currentColor" />
118
+ </svg>
119
+ Watch 2 min demo
120
+ </a>
121
+ </div>
122
+ <p class="txt-xs txt-muted">No credit card required &middot; 14-day free trial &middot; Cancel anytime</p>
123
+ </div>
124
+
125
+ <!-- Right: geometric decoration -->
126
+ <div class="relative ex-shapes-panel">
127
+ <!-- Background ring -->
128
+ <div class="rounded-full absolute geo-ring bg-blue-50 bdr bdr-blue-200"></div>
129
+ <div class="rounded-full absolute geo-ring-inner bdr-2 bdr-blue-100" style="border-style: dashed;"></div>
130
+
131
+ <!-- Floating cards -->
132
+ <div class="bx shadow-lg absolute geo-card-1 ex-geo-card">
133
+ <div class="flex items-center gap-05">
134
+ <div class="rounded-full wh-2 bg-green-500"></div>
135
+ <span class="txt-sm font-semibold txt-slate-900">Deploy successful</span>
136
+ </div>
137
+ <p class="txt-xs txt-muted">production &middot; 2s ago</p>
138
+ </div>
139
+
140
+ <div class="bx shadow-lg absolute geo-card-2 ex-geo-card">
141
+ <span class="txt-xs txt-muted uppercase tracking-wider font-semibold">Uptime</span>
142
+ <div class="flex items-center gap-05">
143
+ <span class="txt-2 font-black txt-slate-900">99.9%</span>
144
+ </div>
145
+ </div>
146
+
147
+ <div class="bx shadow-lg absolute geo-card-3 ex-geo-card">
148
+ <span class="txt-xs txt-muted uppercase tracking-wider font-semibold">Team members</span>
149
+ <div class="flex items-center">
150
+ <div class="rounded-full wh-2 bg-violet-400 bdr-2 bdr-white" style="margin-inline-start: -0.25rem;"></div>
151
+ <div class="rounded-full wh-2 bg-sky-400 bdr-2 bdr-white" style="margin-inline-start: -0.25rem;"></div>
152
+ <div class="rounded-full wh-2 bg-emerald-400 bdr-2 bdr-white" style="margin-inline-start: -0.25rem;"></div>
153
+ <div class="rounded-full wh-2 bg-rose-400 bdr-2 bdr-white" style="margin-inline-start: -0.25rem;"></div>
154
+ <span class="txt-xs txt-muted mx-0.5">+14 more</span>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Central shape -->
159
+ <div class="geo-center rounded-xl bg-linear-to-br from-blue-500 to-violet-600 shadow-xl flex flex-col items-center justify-center absolute tac pxy-3">
160
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" aria-hidden="true">
161
+ <path d="M24 4 L44 24 L24 44 L4 24Z" fill="white" opacity="0.2" />
162
+ <path d="M24 12 L36 24 L24 36 L12 24Z" fill="white" opacity="0.4" />
163
+ <circle cx="24" cy="24" r="6" fill="white" />
164
+ </svg>
165
+ <span class="txt-white font-bold txt-sm">Nexus Core</span>
166
+ </div>
167
+
168
+ <!-- Swirl SVG -->
169
+ <svg class="geo-swirl absolute opacity-20" width="300" height="300" viewBox="0 0 300 300" fill="none" aria-hidden="true">
170
+ <path d="M150 150 Q200 100 250 150 Q200 200 150 150 Q100 100 50 150 Q100 200 150 150" stroke="oklch(62.3% 0.214 259.815deg)" stroke-width="2" fill="none" />
171
+ <path d="M150 150 Q220 80 290 150 Q220 220 150 150 Q80 80 10 150 Q80 220 150 150" stroke="oklch(62.3% 0.214 259.815deg)" stroke-width="1.5" fill="none" opacity="0.6" />
172
+ <path d="M150 150 Q230 60 310 150" stroke="oklch(70.2% 0.183 293.541deg)" stroke-width="1" fill="none" opacity="0.5" />
173
+ </svg>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ <!-- Bottom wave -->
179
+ <svg class="wave-bottom" viewBox="0 0 1440 80" fill="none" preserveAspectRatio="none" aria-hidden="true">
180
+ <path d="M0 80 L0 40 Q360 0 720 40 Q1080 80 1440 40 L1440 80Z" fill="white" />
181
+ </svg>
182
+ </div>
183
+
184
+ <div class="ex-spacer bg-white"></div>
185
+
186
+
187
+ <!-- ═══════════════════════════════════════════════════════════════
188
+ EXAMPLE 3: DUSK
189
+ Cinematic dark image hero with frosted glass nav and wave divider
190
+ ═══════════════════════════════════════════════════════════════ -->
191
+
192
+ <div class="relative">
193
+ <!-- Nav sits inside hero to overlay it -->
194
+ <nav class="navbar-glass navbar absolute top-0 left-0 w-full z-above">
195
+ <div class="container">
196
+ <a href="#" class="flex items-center gap-1">
197
+ <svg width="26" height="26" viewBox="0 0 26 26" fill="none" aria-hidden="true">
198
+ <circle cx="13" cy="13" r="13" fill="white" opacity="0.15" />
199
+ <path d="M7 13 Q13 5 19 13 Q13 21 7 13Z" fill="white" opacity="0.8" />
200
+ <circle cx="13" cy="13" r="3" fill="white" />
201
+ </svg>
202
+ <span class="txt-white font-bold tracking-tight">Arcadia</span>
203
+ </a>
204
+ <ul class="menu">
205
+ <li><a href="#" class="txt-white opacity-80">Work</a></li>
206
+ <li><a href="#" class="txt-white opacity-80">Studio</a></li>
207
+ <li><a href="#" class="txt-white opacity-80">Journal</a></li>
208
+ <li><a href="#" class="txt-white opacity-80">Contact</a></li>
209
+ </ul>
210
+ <button class="btn sm" style="background: rgb(255 255 255 / 15%); border-color: rgb(255 255 255 / 30%); color: white;">
211
+ Start a project
212
+ </button>
213
+ </div>
214
+ </nav>
215
+
216
+ <!-- Hero — gradient stands in for background image -->
217
+ <div class="ex-hero-dusk bg-linear-to-br from-slate-900 to-indigo-950 relative overflow-hidden">
218
+
219
+ <!-- "Photo" texture shapes -->
220
+ <div class="absolute inset-0 overflow-hidden">
221
+ <div class="rounded-full absolute photo-blob-1 bg-violet-800 opacity-30"></div>
222
+ <div class="rounded-full absolute photo-blob-2 bg-blue-900 opacity-40"></div>
223
+ <div class="blob absolute photo-blob-3 bg-indigo-800 opacity-20"></div>
224
+ </div>
225
+
226
+ <!-- Light streaks SVG -->
227
+ <svg class="absolute inset-0 w-full h-full opacity-10" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice" fill="none" aria-hidden="true">
228
+ <line x1="0" y1="700" x2="600" y2="0" stroke="white" stroke-width="1.5" />
229
+ <line x1="200" y1="700" x2="800" y2="0" stroke="white" stroke-width="0.75" />
230
+ <line x1="600" y1="700" x2="1100" y2="0" stroke="white" stroke-width="1" />
231
+ <line x1="900" y1="700" x2="1400" y2="100" stroke="white" stroke-width="0.5" />
232
+ <ellipse cx="700" cy="200" rx="300" ry="150" stroke="white" stroke-width="0.5" />
233
+ </svg>
234
+
235
+ <!-- Swirl overlay -->
236
+ <svg class="absolute swirl-dusk opacity-10" width="800" height="800" viewBox="0 0 800 800" fill="none" aria-hidden="true">
237
+ <path d="M400 400 C400 200, 650 200, 650 400 C650 600, 400 600, 400 400 C400 100, 750 100, 750 400 C750 700, 300 750, 200 500 C100 250, 450 100, 600 250" stroke="white" stroke-width="2" fill="none" />
238
+ <path d="M400 400 C350 350, 250 400, 250 500 C250 620, 370 660, 500 620 C630 580, 680 470, 640 350 C600 230, 470 200, 370 270 C250 360, 220 520, 320 620" stroke="white" stroke-width="1.2" fill="none" opacity="0.5" />
239
+ <circle cx="400" cy="400" r="180" stroke="white" stroke-width="0.5" opacity="0.3" />
240
+ <circle cx="400" cy="400" r="280" stroke="white" stroke-width="0.5" opacity="0.2" />
241
+ </svg>
242
+
243
+ <!-- Content -->
244
+ <div class="container ex-dusk-content relative">
245
+ <div class="ex-dusk-text">
246
+ <span class="txt-indigo-300 txt-sm font-semibold tracking-widest uppercase">Creative Studio</span>
247
+ <h1 class="txt-white font-black lh-tight txt-4">We craft digital<br>experiences that<br><em class="txt-violet-300">endure.</em></h1>
248
+ <p class="txt-indigo-200 lead">Award-winning design and engineering for brands that refuse to be ordinary.</p>
249
+ <div class="flex gap-1">
250
+ <button class="btn lg primary">View our work</button>
251
+ <button class="btn lg" style="background: rgb(255 255 255 / 10%); border-color: rgb(255 255 255 / 20%); color: white;">
252
+ Our process
253
+ </button>
254
+ </div>
255
+ </div>
256
+ </div>
257
+
258
+ <!-- Wave divider -->
259
+ <svg class="wave-bottom" viewBox="0 0 1440 100" fill="none" preserveAspectRatio="none" aria-hidden="true">
260
+ <path d="M0 100 L0 60 Q200 20 400 50 Q600 80 800 40 Q1000 0 1200 30 Q1320 50 1440 20 L1440 100Z" fill="white" opacity="0.05" />
261
+ <path d="M0 100 L0 70 Q300 30 600 60 Q900 90 1200 50 Q1320 35 1440 40 L1440 100Z" fill="white" opacity="0.05" />
262
+ <path d="M0 100 L0 85 Q360 55 720 75 Q1080 95 1440 65 L1440 100Z" fill="rgb(15 23 42)" />
263
+ </svg>
264
+ </div>
265
+ </div>
266
+
267
+ <div class="ex-spacer bg-slate-950"></div>
268
+
269
+
270
+ <script type="module" src="/main.js"></script>
271
+
272
+ <style>
273
+ /*
274
+ ================================================================
275
+ LOCAL HELPERS — JTB gaps documented here
276
+ ================================================================
277
+
278
+ Gaps identified (candidates for JTB additions):
279
+
280
+ 1. min-h-{vh-fraction} — only min-h-screen (100vh) in JTB.
281
+ Useful: min-h-80vh, min-h-85vh for hero sections that
282
+ shouldn't consume the full viewport.
283
+
284
+ 2. backdrop-filter / blur — utilities commented out in JTB.
285
+ Critical for frosted-glass navbars. Currently relies on
286
+ inline or local CSS.
287
+
288
+ 3. Negative positioning (-top-{n}, -left-{n}) — not generated.
289
+ Needed for off-canvas decorative shapes.
290
+
291
+ 4. Organic blob border-radius — JTB has named/scale values but
292
+ no way to express e.g. "60% 40% 30% 70% / 60% 30% 70% 40%".
293
+ Could be solved with a small set of named blob variants.
294
+
295
+ 5. bg-transparent — transparent is not in JTB color maps.
296
+ Useful for overlay navbars and ghost buttons.
297
+
298
+ 6. gap-05 — JTB spacing values include 0.5 but the class name
299
+ sanitiser may render it as gap-0.5 not gap-05. This local
300
+ helper covers the gap (no pun intended) for sub-1 values
301
+ in flex rows.
302
+
303
+ 7. Gradient via-{color} — JTB gradients only support from/to,
304
+ no mid-stop.
305
+ ================================================================
306
+ */
307
+
308
+ /* --- Hero sizing ------------------------------------------ */
309
+ .ex-hero {
310
+ min-height: 88vh;
311
+ padding-block: 6rem 4rem;
312
+ }
313
+
314
+ .ex-hero-dusk {
315
+ min-height: 90vh;
316
+ padding-block: 6rem 5rem;
317
+ }
318
+
319
+ .ex-spacer { height: 2rem; }
320
+
321
+ /* --- Content max-widths ------------------------------------ */
322
+ .ex-hero-content { max-width: 44rem; }
323
+ .ex-dusk-text { max-width: 36rem; }
324
+ .ex-dusk-content { padding-block: 8rem 6rem; }
325
+
326
+ /* --- Bottom fade overlay ----------------------------------- */
327
+ .ex-fade-bottom {
328
+ height: 6rem;
329
+ background: linear-gradient(to bottom, transparent, rgb(15 10 40 / 60%));
330
+ }
331
+
332
+ /* --- Blob border-radius ------------------------------------ */
333
+ .blob { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; }
334
+ .blob-2 { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
335
+
336
+ /* --- Example 1 blob positions ------------------------------ */
337
+ .shape-tl { top: -8rem; inset-inline-start: -8rem; }
338
+ .shape-br { bottom: -10rem; inset-inline-end: -6rem; }
339
+ .shape-mid-r { top: 25%; inset-inline-end: 6%; }
340
+ .shape-mid-l { bottom: 20%; inset-inline-start: 8%; }
341
+
342
+ /* SVG swirl position */
343
+ .swirl-deco { top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; }
344
+ .swirl-dusk { top: 50%; right: -10%; transform: translateY(-50%); pointer-events: none; }
345
+
346
+ /* --- Example 2 shapes panel -------------------------------- */
347
+ .ex-hero-grid-gap {
348
+ gap: 4rem;
349
+ min-height: 85vh;
350
+ padding-block: 6rem 3rem;
351
+ }
352
+
353
+ .ex-shapes-panel { height: 32rem; }
354
+
355
+ .geo-ring {
356
+ width: 28rem; height: 28rem;
357
+ top: 50%; left: 50%;
358
+ transform: translate(-50%, -50%);
359
+ }
360
+
361
+ .geo-ring-inner {
362
+ width: 20rem; height: 20rem;
363
+ top: 50%; left: 50%;
364
+ transform: translate(-50%, -50%);
365
+ }
366
+
367
+ .geo-center {
368
+ width: 10rem; height: 10rem;
369
+ top: 50%; left: 50%;
370
+ transform: translate(-50%, -50%);
371
+ }
372
+
373
+ .ex-geo-card { min-width: 11rem; }
374
+
375
+ .geo-card-1 { top: 10%; left: -2rem; }
376
+ .geo-card-2 { bottom: 15%; left: 2rem; }
377
+ .geo-card-3 { top: 15%; right: -1rem; }
378
+
379
+ .geo-swirl {
380
+ top: 50%; left: 50%;
381
+ transform: translate(-50%, -50%);
382
+ pointer-events: none;
383
+ }
384
+
385
+ /* --- Example 3 photo blobs --------------------------------- */
386
+ .photo-blob-1 { width: 40rem; height: 40rem; top: -10rem; right: -8rem; }
387
+ .photo-blob-2 { width: 30rem; height: 30rem; bottom: -5rem; left: -5rem; }
388
+ .photo-blob-3 { width: 20rem; height: 20rem; top: 30%; right: 20%; }
389
+
390
+ /* --- Frosted glass navbar ---------------------------------- */
391
+ .navbar-glass {
392
+ background: rgb(255 255 255 / 8%);
393
+ backdrop-filter: blur(12px);
394
+ -webkit-backdrop-filter: blur(12px);
395
+ border-bottom: 1px solid rgb(255 255 255 / 10%);
396
+ }
397
+
398
+ /* Override .navbar component background for glass variant */
399
+ nav.navbar.navbar-glass { background: rgb(255 255 255 / 8%); }
400
+
401
+ /* --- Wave divider ----------------------------------------- */
402
+ .wave-bottom {
403
+ position: absolute;
404
+ bottom: 0;
405
+ left: 0;
406
+ width: 100%;
407
+ height: 100px;
408
+ }
409
+
410
+ /* --- gap-05 fallback (sub-1 rem class name) --------------- */
411
+ .gap-05 { gap: 0.5rem; }
412
+ .mx-0\.5 { margin-inline: 0.25rem; }
413
+ </style>
414
+
415
+ </body>
416
+ </html>
package/index.html CHANGED
@@ -10,18 +10,6 @@
10
10
 
11
11
  <body>
12
12
 
13
-
14
-
15
- <div class="mb-2.5">
16
- <h2>Page loader</h2>
17
- <div class="bx flex-col flex-centered gap-1">
18
- <svg class="animate-dash wh-3 txt-blue-500" viewBox="0 0 44 44">
19
- <circle cx="22" cy="22" r="16" stroke="currentColor" />
20
- </svg>
21
- <p class="txt-sm txt-muted">Loading your workspace…</p>
22
- </div>
23
- </div>
24
-
25
13
  <style>
26
14
  /* ============================================================
27
15
  Local helpers — JTB gaps documented in jtb-conversion-notes.md
@@ -183,6 +171,52 @@
183
171
  </style>
184
172
 
185
173
  <div class="py-1.5 container-md">
174
+ <style>
175
+
176
+ /*SVG arc — @keyframes dash not in JTB animation utilities*/
177
+ @keyframes dash {
178
+ 0% {
179
+ stroke-dasharray: 1, 150;
180
+ stroke-dashoffset: 0;
181
+ }
182
+
183
+ 50% {
184
+ stroke-dasharray: 90, 150;
185
+ stroke-dashoffset: -35;
186
+ }
187
+
188
+ 100% {
189
+ stroke-dasharray: 90, 150;
190
+ stroke-dashoffset: -124;
191
+ }
192
+ }
193
+
194
+ .arc circle {
195
+ fill: none;
196
+ stroke-width: 3;
197
+ stroke-linecap: round;
198
+ animation: dash 1.4s ease-in-out infinite;
199
+ }
200
+ </style>
201
+
202
+ <div class="mb-2.5">
203
+ <h2>SVG arc spinner</h2>
204
+ <div class="bx flex-vac flex-wrap gap-1.5">
205
+ <div class="flex-col flex-vac gap-05">
206
+ <svg class="animate-spin arc wh-2.5 txt-blue-500" viewBox="0 0 36 36">
207
+ <circle cx="18" cy="18" r="14" stroke="currentColor" />
208
+ </svg>
209
+ <span class="txt-xs txt-muted">smooth arc</span>
210
+ </div>
211
+ <div class="flex-col flex-vac gap-05">
212
+ <svg class="animate-spin arc wh-3 txt-emerald-500" viewBox="0 0 48 48">
213
+ <circle cx="24" cy="24" r="18" stroke="currentColor" />
214
+ </svg>
215
+ <span class="txt-xs txt-muted">teal / lg</span>
216
+ </div>
217
+ </div>
218
+ </div>
219
+
186
220
  <div class="mb-2.5">
187
221
  <h2>Dot indicators</h2>
188
222
  <div class="bx flex-vac flex-wrap gap-1.5">
@@ -304,7 +338,15 @@
304
338
  </div>
305
339
  </div>
306
340
 
307
-
341
+ <div class="mb-2.5">
342
+ <h2>Page loader</h2>
343
+ <div class="bx flex-col flex-centered gap-1">
344
+ <svg class="animate-spin arc wh-3 txt-blue-500" viewBox="0 0 44 44">
345
+ <circle cx="22" cy="22" r="16" stroke="currentColor" />
346
+ </svg>
347
+ <p class="txt-sm txt-muted">Loading your workspace…</p>
348
+ </div>
349
+ </div>
308
350
 
309
351
  </div>
310
352
 
@@ -6,7 +6,7 @@ Actionable gaps found during conversion of `loaders_and_spinners.html`.
6
6
 
7
7
  | Gap | Detail |
8
8
  | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
9
- | `@keyframes dash` | Added as `animate-dash` in `_animation.scss`. |
9
+ | `@keyframes dash` | SVG arc morphing — stroke-dasharray animates between values. No JTB equivalent. Candidate for `_animation.scss`. |
10
10
  | `@keyframes grow` | Vertical scale pulse for bar equalizer. No JTB equivalent. |
11
11
  | `@keyframes skeleton` | Gradient sweep shimmer. Very commonly needed. Strong candidate for `_animation.scss`. |
12
12
  | `@keyframes progress-indeterminate` | Horizontal bar sweep for indeterminate progress. No JTB equivalent. |
@@ -24,5 +24,5 @@ Actionable gaps found during conversion of `loaders_and_spinners.html`.
24
24
 
25
25
  | Gap | Detail |
26
26
  | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
27
- | Spinner colour theming | `.spinner` component removedspinner is now utility-based, colour via `txt-*`. |
27
+ | Spinner colour theming | `.spinner` hardcodes `#f3f3f3` and `#3498db` no CSS custom properties for colour. Accent and button-context spinners require local overrides. |
28
28
  | Icon-only button | `.btn` has no square/icon variant. A `btn-icon` or `btn xs` pattern would cover `width = height, padding: 0`. |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nk_jtb",
3
3
  "description": "Yet another utility based framework.",
4
- "version": "0.28.0",
4
+ "version": "0.28.2",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/naykel76/nk_jtb.git"
@@ -15,6 +15,10 @@
15
15
  },
16
16
  "Core Concepts": {
17
17
  "links": [
18
+ {
19
+ "name": "Auto Spacing",
20
+ "route_name": "docs.jtb.automatic-spacing"
21
+ },
18
22
  {
19
23
  "name": "Layout & Structures",
20
24
  "route_name": "docs.jtb.layouts-and-structures",
package/skills-lock.json CHANGED
@@ -23,7 +23,7 @@
23
23
  "source": "naykel76/skills-and-guidelines",
24
24
  "sourceType": "github",
25
25
  "skillPath": "nk-documentation-best-practices/SKILL.md",
26
- "computedHash": "64d145c8e7e332c70805a8faddf1fc2afe276aa6f3300c6c924c8a9f0fba7d85"
26
+ "computedHash": "ee039aac7739637fdab654b4ed156667bbf02937ba3510c1f8d928ce8215bacc"
27
27
  },
28
28
  "skill-creation": {
29
29
  "source": "naykel76/skills-and-guidelines",
@@ -18,6 +18,16 @@ $inline-exclusions: svg, span;
18
18
  margin-block-start: $base-gap;
19
19
  }
20
20
 
21
+ // Headings connect to text content below — tighter gap than $base-gap
22
+ // Block components (.bx etc) fall back to $base-gap via the general rule
23
+ :where(h1) + :where(p, ul, ol, blockquote) {
24
+ margin-block-start: 1rem;
25
+ }
26
+
27
+ :where(h2, h3, h4, h5, h6) + :where(p, ul, ol, blockquote) {
28
+ margin-block-start: 0.75rem;
29
+ }
30
+
21
31
  // Reverse pattern - layout elements followed by content elements
22
32
  // Catches cases like div + p, section + h1, article + table, etc.
23
33
  // We can't add div/section/article to $spacing-targets because that would also
@@ -33,7 +43,7 @@ $inline-exclusions: svg, span;
33
43
  }
34
44
 
35
45
  // opt out for `flex` and `grid` element and use `gap` instead
36
- :where([class*='flex'], [class*='grid']) > * {
46
+ :where([class~='flex'], [class~='flex-col'], [class~='flex-row'], [class~='flex-centered'], [class~='flex-vac'], [class~='flex-hac'], [class*='grid']) > * {
37
47
  margin: 0;
38
48
  }
39
49
 
@@ -2,16 +2,6 @@
2
2
  @use '../maps_and_variables/colors' as *;
3
3
  @use '../maps_and_variables/components' as *;
4
4
  @use '../maps_and_variables/typography' as *;
5
- @use '../functions/color-functions' as *;
6
- @use 'sass:map';
7
-
8
- @mixin define-runtime-theme-vars($theme-name, $theme-color) {
9
- --#{$theme-name}: #{$theme-color};
10
- --#{$theme-name}-hover: color-mix(in srgb, var(--#{$theme-name}), white 5%);
11
- --#{$theme-name}-active: color-mix(in srgb, var(--#{$theme-name}), black 5%);
12
- --#{$theme-name}-border: #{border-contrast($theme-color)};
13
- --on-#{$theme-name}: #{text-color($theme-color)};
14
- }
15
5
 
16
6
  :root {
17
7
  // create css variables including brand colors
@@ -47,10 +37,10 @@
47
37
  --bg-toggle-on: var(--primary);
48
38
  --bg-toggle-ball: var(--white);
49
39
 
50
- // -- Runtime Semantic Theme Colors --
51
- @each $theme-name in $runtime-theme-colors {
52
- @include define-runtime-theme-vars($theme-name, map.get($base-colors, $theme-name));
53
- }
40
+ // -- Brand Colors --
41
+ --primary: #{$primary};
42
+ --secondary: #{$secondary};
43
+ --accent: #{$accent};
54
44
 
55
45
  // -- Text Colors --
56
46
  --text-color: #{$text-color};
@@ -19,7 +19,7 @@
19
19
  text-wrap: balance;
20
20
  }
21
21
 
22
- :where(h2, h3, h4, h5, h6):where(:not(:first-child)) {
22
+ :is(h2, h3, h4, h5, h6):not(:first-child) {
23
23
  margin-block-start: 1.5em;
24
24
  }
25
25
 
@@ -109,19 +109,3 @@
109
109
  @include active($color);
110
110
  }
111
111
  }
112
-
113
- @each $theme-name in $runtime-theme-colors {
114
- .#{$button-prefix}.#{$theme-name} {
115
- &:hover {
116
- background-color: var(--#{$theme-name}-hover);
117
- border-color: var(--#{$theme-name}-border);
118
- color: var(--on-#{$theme-name});
119
- }
120
-
121
- &:active {
122
- background-color: var(--#{$theme-name}-active);
123
- border-color: var(--#{$theme-name}-border);
124
- color: var(--on-#{$theme-name});
125
- }
126
- }
127
- }
@@ -51,10 +51,6 @@ $theme-colors: (
51
51
  'warning': #ffdd57
52
52
  ) !default;
53
53
 
54
- // Semantic theme names that should remain runtime-swappable via CSS custom
55
- // properties. Hue and scale colors stay compile-time tokens.
56
- $runtime-theme-colors: ('primary', 'secondary', 'accent') !default;
57
-
58
54
  // based on Tailwind 500 series colors
59
55
  $base-colors: (
60
56
  'primary': base.$primary,
@@ -22,18 +22,4 @@ $background-color-properties: (
22
22
  )
23
23
  );
24
24
 
25
- $runtime-background-colors: ();
26
-
27
- @each $theme-name in $runtime-theme-colors {
28
- $runtime-background-colors: map.set($runtime-background-colors, $theme-name, var(--#{$theme-name}));
29
- }
30
-
31
- $runtime-background-color-properties: (
32
- background-color: (
33
- prefix: 'bg-',
34
- values: $runtime-background-colors
35
- )
36
- );
37
-
38
25
  @include build-classes($background-color-properties, $responsive: false, $with-state: true);
39
- @include build-classes($runtime-background-color-properties, $responsive: false, $with-state: true);
@@ -51,23 +51,6 @@ $divider-properties-map: (
51
51
  )
52
52
  ) !default;
53
53
 
54
- $runtime-border-colors: ();
55
-
56
- @each $theme-name in $runtime-theme-colors {
57
- $runtime-border-colors: map.set($runtime-border-colors, $theme-name, var(--#{$theme-name}));
58
- }
59
-
60
- $runtime-border-properties-map: (
61
- border-color: (
62
- prefix: #{$border-prefix},
63
- values: $runtime-border-colors
64
- ),
65
- outline-color: (
66
- prefix: 'outline-',
67
- values: $runtime-border-colors
68
- )
69
- );
70
-
71
54
  .divide-y-gradient > :not(:last-child) {
72
55
  border-block-end-width: 3px;
73
56
  border-image-slice: 1;
@@ -85,5 +68,4 @@ $runtime-border-properties-map: (
85
68
  // Builds
86
69
  // ============================================================================
87
70
  @include build-classes($border-properties-map, $responsive: true);
88
- @include build-classes($runtime-border-properties-map, $responsive: true);
89
71
  @include build-composite-classes($divider-properties-map, $responsive: true);
@@ -50,22 +50,3 @@ $themes-map: ();
50
50
  @each $color, $value in map.merge($base-colors, $theme-colors) {
51
51
  @include build-outline-theme('#{$color}-outline', $value);
52
52
  }
53
-
54
- @each $theme-name in $runtime-theme-colors {
55
- .#{$theme-name} {
56
- background-color: var(--#{$theme-name});
57
- border: 1px solid var(--#{$theme-name}-border);
58
- color: var(--on-#{$theme-name});
59
- }
60
-
61
- .#{$theme-name}-outline {
62
- background-color: transparent;
63
- border: 1px solid var(--#{$theme-name});
64
- color: var(--#{$theme-name});
65
-
66
- &:hover:not(:disabled, .disabled) {
67
- background-color: var(--#{$theme-name});
68
- color: var(--on-#{$theme-name});
69
- }
70
- }
71
- }
@@ -124,23 +124,8 @@ $text-classes-map: (
124
124
  )
125
125
  );
126
126
 
127
- $runtime-text-colors: ();
128
-
129
- @each $theme-name in $runtime-theme-colors {
130
- $runtime-text-colors: map.set($runtime-text-colors, $theme-name, var(--#{$theme-name}));
131
- }
132
-
133
- $runtime-typography-properties-map: (
134
- color: (
135
- prefix: '#{$text-prefix}',
136
- values: $runtime-text-colors,
137
- states: ('hover', 'focus')
138
- )
139
- );
140
-
141
127
  // ============================================================================
142
128
  // BUILDS
143
129
  // ============================================================================
144
130
  @include build-classes($typography-properties-map, $responsive: true);
145
- @include build-classes($runtime-typography-properties-map, $responsive: true);
146
131
  @include build-composite-classes($text-classes-map, $responsive: true);