@danieldeusing/design 0.4.0 → 0.6.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/dist/danieldeusing-design.css +27 -2
- package/dist/danieldeusing-design.min.css +2 -2
- package/package.json +2 -1
- package/src/tokens.css +26 -1
- package/templates/documentation.html +414 -0
- package/templates/page-chrome.html +140 -0
- package/tokens/tokens.json +33 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! danieldeusing-design v0.
|
|
1
|
+
/*! danieldeusing-design v0.6.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
|
|
2
2
|
/* ===== reset.css ===== */
|
|
3
3
|
/*
|
|
4
4
|
* danieldeusing-design — minimal reset.
|
|
@@ -100,13 +100,30 @@ table {
|
|
|
100
100
|
* A gap of 0.0692 with nothing in it. So NO single hex can serve four themes:
|
|
101
101
|
* the two near-black themes need a light tint, the two light themes a dark one,
|
|
102
102
|
* and every compromise fails both. That is arithmetic, not taste — which is why
|
|
103
|
-
* --destructive, --success and --
|
|
103
|
+
* --destructive, --success, --warning, --info and --pending are each declared
|
|
104
|
+
* four times.
|
|
104
105
|
*
|
|
105
106
|
* Cockpit carried twelve hardcoded accents that predate these tokens; every one
|
|
106
107
|
* missed AA on at least one theme and four sat inside the gap, clearing neither
|
|
107
108
|
* side. Adding a status colour? Add a TOKEN here with its measured worst-case
|
|
108
109
|
* ratio in a trailing comment. Do not tune a literal at the call site — that
|
|
109
110
|
* forks the palette and fixes exactly one theme.
|
|
111
|
+
*
|
|
112
|
+
* ── FIVE STATUS ACCENTS, BECAUSE A STATE MACHINE HAS MORE THAN THREE STATES ──
|
|
113
|
+
* good / attention / bad covers a verdict. It does not cover the two states a
|
|
114
|
+
* dashboard spends most of its time showing, and cockpit forked a literal for
|
|
115
|
+
* each of them rather than go without:
|
|
116
|
+
*
|
|
117
|
+
* --info a state, not a verdict. In flight, informational, recorded and
|
|
118
|
+
* fine but not a win: dispatching, gated, started-by-hand, "silent
|
|
119
|
+
* for a reason". Blue, so it never reads as an alarm.
|
|
120
|
+
* --pending NO verdict yet. Still running, timed out, could not determine,
|
|
121
|
+
* not recorded: the answer is absent, which is different from the
|
|
122
|
+
* answer being bad. Violet, so it never reads as --destructive.
|
|
123
|
+
*
|
|
124
|
+
* Both are peers of --success/--warning/--destructive and obey the same rule:
|
|
125
|
+
* one value for the two light themes, one for the two near-black ones, each
|
|
126
|
+
* measured against --background, --card AND --muted.
|
|
110
127
|
*/
|
|
111
128
|
|
|
112
129
|
:root {
|
|
@@ -127,6 +144,8 @@ table {
|
|
|
127
144
|
--destructive: #a02c2c;
|
|
128
145
|
--success: #1a6b2e; /* 5.16:1 worst surface */
|
|
129
146
|
--warning: #845600; /* 4.97:1 worst surface */
|
|
147
|
+
--info: #1c5f9e; /* 5.17:1 worst surface */
|
|
148
|
+
--pending: #5f3dc4; /* 5.58:1 worst surface */
|
|
130
149
|
--border: #d9cdb6;
|
|
131
150
|
--input: #d9cdb6;
|
|
132
151
|
--ring: #8a4516;
|
|
@@ -159,6 +178,8 @@ html[data-theme="green"] {
|
|
|
159
178
|
--destructive: #ff5c5c;
|
|
160
179
|
--success: #4ade80; /* 10.76:1 worst surface */
|
|
161
180
|
--warning: #f5b32b; /* 10.15:1 worst surface */
|
|
181
|
+
--info: #4dabf7; /* 7.57:1 worst surface */
|
|
182
|
+
--pending: #b197fc; /* 7.77:1 worst surface */
|
|
162
183
|
--border: #1c4a2c;
|
|
163
184
|
--input: #1c4a2c;
|
|
164
185
|
--ring: #33ff66;
|
|
@@ -186,6 +207,8 @@ html[data-theme="mono"] {
|
|
|
186
207
|
--destructive: #ff5c5c;
|
|
187
208
|
--success: #4ade80; /* 10.84:1 worst surface */
|
|
188
209
|
--warning: #f5b32b; /* 10.22:1 worst surface */
|
|
210
|
+
--info: #4dabf7; /* 7.63:1 worst surface */
|
|
211
|
+
--pending: #b197fc; /* 7.82:1 worst surface */
|
|
189
212
|
--border: #333333;
|
|
190
213
|
--input: #333333;
|
|
191
214
|
--ring: #ffffff;
|
|
@@ -213,6 +236,8 @@ html[data-theme="paper"] {
|
|
|
213
236
|
--destructive: #b3261e;
|
|
214
237
|
--success: #1a7031; /* 5.36:1 worst surface */
|
|
215
238
|
--warning: #8f5d00; /* 4.89:1 worst surface */
|
|
239
|
+
--info: #1c5f9e; /* 5.74:1 worst surface */
|
|
240
|
+
--pending: #5f3dc4; /* 6.19:1 worst surface */
|
|
216
241
|
--border: #d4d4d4;
|
|
217
242
|
--input: #d4d4d4;
|
|
218
243
|
--ring: #000000;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! danieldeusing-design v0.
|
|
2
|
-
*,*::before,*::after{box-sizing: border-box}*{margin: 0}html{-webkit-text-size-adjust: 100%;text-size-adjust: 100%;tab-size: 4}body{min-height: 100vh;min-height: 100dvh;line-height: 1.5}img,picture,video,canvas,svg{display: block;max-width: 100%}input,button,textarea,select{font: inherit;color: inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap: break-word}ul,ol{list-style: none;padding: 0}a{color: inherit;text-decoration: none}table{border-collapse: collapse}:root{--background: #f5efe2;--foreground: #43352a;--card: #efe7d4;--card-foreground: #43352a;--popover: #efe7d4;--popover-foreground: #43352a;--primary: #8a4516;--primary-foreground: #f8f3e8;--secondary: #ece3cf;--secondary-foreground: #43352a;--muted: #ece3cf;--muted-foreground: #71614e;--accent: #8a4516;--accent-foreground: #f8f3e8;--destructive: #a02c2c;--success: #1a6b2e;--warning: #845600;--border: #d9cdb6;--input: #d9cdb6;--ring: #8a4516;--glow: rgba(160,82,45,0.1);--glow-soft: rgba(160,82,45,0.05);--scanline-opacity: 0.15;--radius: 0rem;--font-mono: "JetBrains Mono Variable","JetBrains Mono","Menlo",monospace}html[data-theme="green"]{--background: #020604;--foreground: #4fdd7d;--card: #04110a;--card-foreground: #4fdd7d;--popover: #04110a;--popover-foreground: #4fdd7d;--primary: #33ff66;--primary-foreground: #02160a;--secondary: #071509;--secondary-foreground: #4fdd7d;--muted: #071509;--muted-foreground: #3da45e;--accent: #33ff66;--accent-foreground: #02160a;--destructive: #ff5c5c;--success: #4ade80;--warning: #f5b32b;--border: #1c4a2c;--input: #1c4a2c;--ring: #33ff66;--glow: rgba(51,255,102,0.35);--glow-soft: rgba(51,255,102,0.12);--scanline-opacity: 0.5}html[data-theme="mono"]{--background: #050505;--foreground: #d4d4d4;--card: #0d0d0d;--card-foreground: #d4d4d4;--popover: #0d0d0d;--popover-foreground: #d4d4d4;--primary: #ffffff;--primary-foreground: #050505;--secondary: #111111;--secondary-foreground: #d4d4d4;--muted: #111111;--muted-foreground: #8a8a8a;--accent: #ffffff;--accent-foreground: #050505;--destructive: #ff5c5c;--success: #4ade80;--warning: #f5b32b;--border: #333333;--input: #333333;--ring: #ffffff;--glow: rgba(255,255,255,0.25);--glow-soft: rgba(255,255,255,0.08);--scanline-opacity: 0.45}html[data-theme="paper"]{--background: #fafafa;--foreground: #1f1f1f;--card: #f1f1f1;--card-foreground: #1f1f1f;--popover: #f1f1f1;--popover-foreground: #1f1f1f;--primary: #000000;--primary-foreground: #fafafa;--secondary: #efefef;--secondary-foreground: #1f1f1f;--muted: #efefef;--muted-foreground: #595959;--accent: #000000;--accent-foreground: #fafafa;--destructive: #b3261e;--success: #1a7031;--warning: #8f5d00;--border: #d4d4d4;--input: #d4d4d4;--ring: #000000;--glow: rgba(0,0,0,0.06);--glow-soft: rgba(0,0,0,0.04);--scanline-opacity: 0.12}:root{--content-w: 78rem;--content-pad: 1.5rem;--fs-xs: 0.625rem;--fs-sm: 0.6875rem;--fs-base: 0.75rem;--fs-md: 0.8125rem;--fs-lg: 0.9375rem;--fs-xl: 1.125rem;--fs-2xl: 1.5rem;--lh-tight: 1.3;--lh-base: 1.5}html{scroll-behavior: smooth}*,*::before,*::after{border-color: var(--border)}:focus-visible{outline: 2px solid var(--ring);outline-offset: 2px}body{background: var(--background);color: var(--foreground);font-family: var(--font-mono);font-size: var(--fs-base);line-height: var(--lh-base);overflow-x: hidden;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale}button:not(:disabled),summary,[role="button"]{cursor: pointer}body::after{content: "";position: fixed;inset: 0;z-index: 40;pointer-events: none;background: repeating-linear-gradient( 0deg,rgba(0,0,0,0.25) 0px,rgba(0,0,0,0.25) 1px,transparent 1px,transparent 3px );opacity: var(--scanline-opacity)}::selection{background: var(--primary);color: var(--primary-foreground)}.glow{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.glow-lg{color: var(--primary);text-shadow: 0 0 12px var(--glow)}.prompt{font-size: 0.75rem;font-weight: 700;color: var(--muted-foreground)}.prompt::before{content: "$ ";color: var(--primary)}.comment::before{content: "# ";color: var(--border)}.cursor-block{display: inline-block;width: 0.55em;height: 1em;margin-left: 8px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em);animation: ddd-blink 1.1s step-end infinite}@keyframes ddd-blink{50%{opacity: 0}}.btn-terminal{display: inline-block;background: var(--primary);color: var(--primary-foreground);font-weight: 700;padding: 12px 24px;box-shadow: 0 0 16px var(--glow);transition: box-shadow 0.15s ease,transform 0.15s ease}.btn-terminal::before{content: "> "}.btn-terminal:hover{box-shadow: 0 0 28px var(--glow);transform: translateY(-2px)}.link-quiet{color: var(--muted-foreground);text-decoration: underline;text-underline-offset: 4px;transition: color 0.15s ease}.link-quiet:hover{color: var(--primary)}.anim-toggle{display: inline-flex;align-items: center;gap: 6px;font: inherit;color: var(--muted-foreground);background: none;border: 0;cursor: pointer;transition: color 0.15s ease}.anim-toggle:hover{color: var(--primary)}.anim-toggle[aria-pressed="true"] [data-anim-box]{color: var(--primary)}.dd-dot{display: inline-block;width: 11px;height: 11px;flex: none;border-radius: 50%;background: currentColor}.dd-flag{display: inline-block;width: 15px;height: 10px;flex: none;border: 1px solid var(--border);background-size: cover;background-repeat: no-repeat}.dd-flag-de{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='4' fill='%23262626'/><rect y='4' width='18' height='4' fill='%23c83232'/><rect y='8' width='18' height='4' fill='%23e8be32'/></svg>")}.dd-flag-en{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='12' fill='%23b22234'/><rect y='4' width='18' height='4' fill='%23ececec'/><rect width='8' height='6' fill='%233c3b6e'/></svg>")}.dd-flag-pt{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='12' fill='%231c9148'/><polygon points='9,1.5 15.5,6 9,10.5 2.5,6' fill='%23e8c832'/><rect x='8' y='5' width='2' height='2' fill='%232c3f87'/></svg>")}.dd-flag-es{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='6' height='12' fill='%2315734c'/><rect x='6' width='6' height='12' fill='%23ececec'/><rect x='12' width='6' height='12' fill='%23bf2233'/><rect x='8' y='5' width='2' height='2' fill='%237a5c3a'/></svg>")}.ascii-rule{margin: 1rem 0;border: 0;color: var(--border);line-height: 1;white-space: nowrap;overflow: hidden;user-select: none}.ascii-rule::before{content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"}.card-terminal{background: var(--card);border: 1px solid var(--border);transition: border-color 0.15s ease,box-shadow 0.15s ease}.card-terminal:hover{border-color: var(--primary);box-shadow: 0 0 20px var(--glow-soft)}.dropdown{position: relative}.dropdown>summary{display: inline-flex;align-items: center;gap: 6px;cursor: pointer;user-select: none;list-style: none;color: var(--muted-foreground);transition: color 0.15s ease}.dropdown>summary::-webkit-details-marker{display: none}.dropdown>summary:hover,.dropdown[open]>summary{color: var(--primary)}.dropdown-panel{position: absolute;right: 0;bottom: calc(100% + 12px);z-index: 50;min-width: 128px;margin: 0;padding: 4px 0;list-style: none;background: var(--card);border: 1px solid var(--border);border-radius: 0;box-shadow: 0 0 20px var(--glow-soft)}.dropdown-panel--down{top: calc(100% + 8px);bottom: auto;left: 0;right: auto}.dropdown-item{display: flex;align-items: center;gap: 8px;width: 100%;padding: 5px 14px;text-align: left;font: inherit;line-height: 1.5;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;white-space: nowrap;transition: color 0.15s ease}.dropdown-item:hover{color: var(--primary);background: var(--muted)}.dropdown-item[aria-current="true"],html:not([data-theme]) .dropdown-item[data-theme-value="warm"],html[data-theme="green"] .dropdown-item[data-theme-value="green"],html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],html[data-theme="warm"] .dropdown-item[data-theme-value="warm"]{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.eli5{margin: 1.25em 0;padding: 0.7em 1em;color: var(--foreground);background: color-mix(in srgb,var(--primary) 7%,var(--card));border: 1px solid var(--border);border-left: 3px solid var(--primary);border-radius: var(--radius);font-size: 0.92em;line-height: 1.6}.eli5::before{content: "ELI5";display: inline-flex;align-items: center;justify-content: center;margin-right: 0.6em;vertical-align: 0.08em;font-family: var(--font-mono);font-size: 0.72em;font-weight: 700;line-height: 1;letter-spacing: 0.04em;padding: 0.34em 0.6em;border-radius: 5px;background: #b42318;color: #fff}.eli5-term{font-weight: 700;color: var(--primary)}html.anim-off *,html.anim-off *::before,html.anim-off *::after{animation: none !important}html.anim-off .cursor-block{display: none}@media (prefers-reduced-motion: no-preference){html.term-anim [data-term] .prompt:not(.term-live),html.term-anim [data-term] .prompt:not(.term-live)::before{color: transparent}html.term-anim [data-term] [data-term-out]:not(.term-show){visibility: hidden}html.term-anim [data-term] [data-term-out].term-show{animation: ddd-term-output 0.2s steps(3,end) both}@keyframes ddd-term-output{from{opacity: 0}}html.term-anim [data-term] [data-term-out].term-show>*{animation: ddd-term-output 0.25s steps(3,end) both}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(2){animation-delay: 0.09s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(3){animation-delay: 0.18s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(4){animation-delay: 0.27s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(5){animation-delay: 0.36s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(6){animation-delay: 0.45s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(7){animation-delay: 0.54s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(8){animation-delay: 0.63s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(9){animation-delay: 0.72s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(10){animation-delay: 0.81s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(n + 11){animation-delay: 0.9s}.term-caret{display: inline-block;width: 0.55em;height: 1em;margin-left: 2px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em)}}.tabs{display: flex;flex-wrap: wrap;gap: 0.15rem;margin: 1.35rem 0 0;border-bottom: 2px solid color-mix(in srgb,var(--border) 80%,transparent)}.tab{background: transparent;border: 0;margin-bottom: -2px;font: inherit;font-size: 0.86em;cursor: pointer;padding: 0.5rem 0.95rem;color: var(--muted-foreground);transition: background 0.12s ease,color 0.12s ease}.tab:hover{color: var(--primary);background: color-mix(in srgb,var(--primary) 10%,transparent)}.tab[aria-selected="true"]{background: var(--primary);color: var(--background);font-weight: 700}.tab:focus-visible{outline: 2px solid color-mix(in srgb,var(--primary) 55%,transparent);outline-offset: -2px}@media (pointer: coarse),(max-width: 40rem){.tab{padding: 0.7rem 0.8rem;min-height: 44px}}section.doc.tab-panel{margin-top: 1.35rem}details.fold{border-top: 1px solid color-mix(in srgb,currentColor 15%,transparent)}details.fold>summary{display: flex;align-items: center;gap: 0.5rem;cursor: pointer;list-style: none;padding: 0.55rem 0;font-size: 0.85rem;color: var(--muted-foreground)}details.fold>summary::-webkit-details-marker{display: none}details.fold>summary::before{content: "\25B8";flex: none;opacity: 0.6}details.fold[open]>summary::before{content: "\25BE"}details.fold>summary:hover{color: var(--primary)}details.fold>summary:focus-visible{outline: 2px solid color-mix(in srgb,currentColor 45%,transparent);outline-offset: 2px}.fold-body{font-size: 0.9rem;padding: 0 0 0.7rem 1.1rem}.fold-body>* + *{margin-top: 0.6rem}.legend{list-style: none;padding: 0;margin: 0.7rem 0 0;display: grid;gap: 0.4rem 1.4rem;font-size: 0.86rem}@media (min-width: 52rem){.legend{grid-template-columns: repeat(2,minmax(0,1fr))}}.legend>li{line-height: 1.6}.legend>li>:first-child{margin-right: 0.45rem}.tickstrip:not(:empty){border: 1px solid var(--border);background: var(--card);margin: 1.6rem 0 1.5rem}.ticktable{width: 100%;border-collapse: collapse;font-size: 0.82rem}.ticktable td{padding: 0.5rem 0.75rem;vertical-align: baseline;border: 0;white-space: nowrap}.ticktable td.tick-stats{width: 100%;white-space: normal}.tick{border-bottom: 1px solid color-mix(in srgb,var(--border) 55%,transparent)}.tick:last-child{border-bottom: 0}.tick-dot{font-size: 0.7em;width: 1.5rem;padding-right: 0 !important;border-left: 3px solid transparent;padding-left: 0.6rem !important}.tick--ok .tick-dot{color: var(--success);border-left-color: color-mix(in srgb,var(--success) 45%,transparent)}.tick--stale .tick-dot{color: var(--destructive);border-left-color: var(--destructive)}.tick--never .tick-dot{color: var(--muted-foreground);border-left-color: color-mix(in srgb,var(--muted-foreground) 35%,transparent)}.tick-name{font-weight: 700;color: var(--foreground);letter-spacing: 0.01em}.tick-last,.tick-next{font-variant-numeric: tabular-nums;color: var(--muted-foreground)}.tick-next{opacity: 0.72}.tick--stale .tick-last{color: var(--destructive);font-weight: 700}.tick--never .tick-last{font-style: italic}.tick-stats{color: var(--muted-foreground)}.tick-stats b{font-weight: 700;color: var(--primary);font-variant-numeric: tabular-nums}.tick-sep{font-style: normal;opacity: 0.35;margin: 0 0.5rem}.tick--stale{background: color-mix(in srgb,var(--destructive) 8%,transparent)}@media (max-width: 40rem){.ticktable,.ticktable tbody,.tick,.ticktable td{display: block}.tick{padding: 0.4rem 0.5rem}.ticktable td{display: inline-block;padding: 0.1rem 0.5rem 0.1rem 0}.ticktable td.tick-stats{display: block;width: auto}}.dgm-zoomable{position: relative;cursor: zoom-in}.dgm-zoomable::after{content: "⤢";position: absolute;top: 0.4rem;right: 0.5rem;font-size: 0.85rem;line-height: 1;opacity: 0.45;pointer-events: none;color: var(--muted-foreground)}.dgm-zoomable:hover::after,.dgm-zoomable:focus-visible::after{opacity: 1;color: var(--primary)}.dgm-zoomable:focus-visible{outline: 2px solid var(--primary);outline-offset: 3px}html.dgm-locked,html.dgm-locked body{overflow: hidden}.dgm-overlay{display: none;position: fixed;inset: 0;z-index: 90;background: color-mix(in srgb,var(--background) 96%,transparent);flex-direction: column}.dgm-overlay.open{display: flex}.dgm-bar{flex: none;display: flex;align-items: center;justify-content: flex-end;gap: 0.4rem;padding: 0.5rem 0.75rem;border-bottom: 1px solid var(--border);background: var(--card)}.dgm-btn{font: inherit;font-size: 0.82rem;cursor: pointer;padding: 0.3rem 0.7rem;min-height: 32px;background: transparent;border: 1px solid var(--border);color: var(--foreground)}.dgm-btn:hover{border-color: var(--primary);color: var(--primary)}.dgm-btn:focus-visible{outline: 2px solid var(--primary);outline-offset: 1px}.dgm-close{border-color: color-mix(in srgb,var(--destructive) 55%,transparent);color: var(--destructive)}.dgm-close:hover{border-color: var(--destructive);color: var(--destructive)}.dgm-stage{flex: 1;overflow: hidden;display: grid;place-items: center;cursor: grab;touch-action: none}.dgm-stage.is-grabbing{cursor: grabbing}.dgm-art{transform-origin: center center;will-change: transform}.dgm-art>svg,.dgm-art>img{display: block;max-width: none;max-height: none}@media print{.dgm-overlay,.dgm-zoomable::after{display: none !important}}.wrap{max-width: var(--content-w);margin-inline: auto;padding-inline: var(--content-pad)}.skip-link{position: absolute;left: -999px;top: 0;z-index: 100;background: var(--card);border: 1px solid var(--primary);padding: 0.5rem 1rem;color: var(--primary)}.skip-link:focus{left: 0.5rem;top: 0.5rem}.visually-hidden{position: absolute;width: 1px;height: 1px;overflow: hidden;clip: rect(0 0 0 0);white-space: nowrap}header.bar{position: sticky;top: 0;z-index: 30;display: flex;align-items: center;justify-content: space-between;gap: 1rem;padding: 0.6rem 1.25rem;border-bottom: 1px solid var(--border);background: var(--card)}header.bar .brand{display: inline-flex;align-items: center;font-weight: 700;font-size: 1rem}header.bar .brand,header.bar .brand a{color: inherit;text-decoration: none}header.bar .dropdown summary{padding: 0.6rem 0.4rem}.bar-right{display: flex;align-items: center;gap: 1rem;flex-shrink: 0}footer.status{position: fixed;inset-inline: 0;bottom: 0;z-index: 50;min-height: 2rem;display: flex;align-items: center;justify-content: space-between;gap: 1rem;padding: 0.35rem 1.25rem;border-top: 1px solid var(--border);background: var(--card);font-size: 0.7rem}footer.status .dropdown summary,footer.status .anim-toggle{padding: 0.55rem 0.4rem}.status-left{color: var(--muted-foreground);min-width: 0;overflow: hidden;text-overflow: ellipsis;white-space: nowrap}.status-right{display: flex;align-items: center;gap: 1rem;flex-shrink: 0}.sep{width: 1px;height: 0.9rem;background: var(--border)}.doc-link{color: var(--muted-foreground);text-decoration: none;transition: color 0.15s ease}.doc-link:hover{color: var(--primary)}.ls-row{display: flex;align-items: baseline;gap: 0.9rem}.ls-perm{color: var(--muted-foreground);font-size: 0.72rem;letter-spacing: 0}.ls-row--sub .ls-name{margin-left: 0.55rem;padding-left: 0.75rem;border-left: 1px solid color-mix(in srgb,var(--muted-foreground) 40%,transparent)}.ls-row--sub2 .ls-name{margin-left: 1.7rem}.ls-panel .ls-name{color: var(--muted-foreground)}.ls-panel .ls-row--dir .ls-name{color: var(--primary);font-weight: 700}.dropdown-panel.ls-panel{min-width: 17rem;left: auto !important;right: 0}:root{--ls-nav-w: 17rem;--ls-nav-top: 3rem;--ls-nav-bottom: 2.2rem}@media (min-width: 48.0625rem){html{--ls-nav-inset: 0rem}html:has(.ls-nav):not([data-ls-nav="off"]){--ls-nav-inset: var(--ls-nav-w)}body{padding-right: var(--ls-nav-inset)}header.bar{margin-right: calc(-1 * var(--ls-nav-inset))}.ls-nav{position: fixed;top: var(--ls-nav-top);right: 0;bottom: var(--ls-nav-bottom);width: var(--ls-nav-w);z-index: 25;display: flex;flex-direction: column;overflow: hidden;background: var(--card);border-left: 1px solid var(--border)}html:not(.anim-off) .ls-nav{transition: transform 0.18s ease}html[data-ls-nav="off"] .ls-nav{transform: translateX(100%)}.ls-nav-head{display: inline-flex;align-items: center;gap: 0.5rem;margin-left: 0.75rem}.ls-nav-title{font-weight: 700;font-size: 0.9rem}.ls-nav .ls-panel{flex: 1;min-height: 0;overflow-y: auto;list-style: none;margin: 0;padding: 0.5rem 0 1rem}.ls-nav-toggle{background: none;border: 0;font: inherit;cursor: pointer;line-height: 1;color: var(--muted-foreground);padding: 0.4rem 0.55rem}.ls-nav-toggle::after{content: "\00BB"}html[data-ls-nav="off"] .ls-nav-toggle::after{content: "\00AB"}.ls-nav-toggle:hover{color: var(--primary)}.ls-nav-toggle:focus-visible{outline: 2px solid color-mix(in srgb,var(--primary) 55%,transparent);outline-offset: -2px}}.nav-burger{display: none;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;padding: 0.55rem;margin: -0.3rem -0.3rem -0.3rem 0}.nav-burger:hover{color: var(--primary)}.mobile-nav{display: none;list-style: none;margin: 0;padding: 0}.mobile-footer{display: none}@media (max-width: 48rem){.nav-burger{display: inline-flex;align-items: center}.site-nav{display: none;position: absolute;top: 100%;left: 0;right: 0;z-index: 40;background: var(--card);border-bottom: 1px solid var(--border);padding: 0.4rem 1.25rem 0.9rem;max-height: calc(100vh - 6rem);overflow-y: auto}.site-nav.open{display: block}.site-nav>.ls-nav,.mobile-nav{display: flex;flex-direction: column}.mobile-nav .mobile-item{display: flex;align-items: baseline;gap: 0.9rem;padding: 0.65rem 0;text-decoration: none;color: var(--foreground);font-size: 0.9rem;border-bottom: 1px solid var(--border)}.mobile-nav li:last-child .mobile-item{border-bottom: 0}.mobile-nav .mobile-item:active .ls-name,.mobile-nav .mobile-item:hover .ls-name{color: var(--primary)}footer.status{display: none}.mobile-footer{display: flex;flex-direction: column;gap: 0.55rem;margin-top: 0.8rem;border-top: 1px solid var(--border);padding-top: 0.8rem;font-size: 0.85rem}.mobile-footer .doc-link{padding: 0.2rem 0}.mobile-footer .mobile-theme summary{list-style: none;display: flex;align-items: center;gap: 0.5rem;color: var(--muted-foreground);cursor: pointer;padding: 0.2rem 0}.mobile-footer .mobile-theme summary::-webkit-details-marker{display: none}.mobile-footer .mf-chev{margin-left: auto;opacity: 0.7}.mobile-footer .mf-panel{display: flex;flex-direction: column;margin-top: 0.3rem}.mobile-footer .mf-panel .dropdown-item{text-align: left;padding: 0.4rem 0.6rem}.mobile-footer .anim-toggle{display: inline-flex;gap: 0.5rem;align-items: center;background: none;border: 0;padding: 0.2rem 0;color: var(--muted-foreground);font: inherit;cursor: pointer}}[data-tip]{cursor: help}span[data-tip],th[data-tip]{border-bottom: 1px dotted var(--muted-foreground)}#ddtip{position: fixed;z-index: 9999;display: none;max-width: 340px;background: var(--background);color: var(--foreground);border: 1px solid var(--muted-foreground);border-radius: 4px;padding: 7px 10px;font-size: 0.72rem;line-height: 1.45;font-weight: 400;text-align: left;white-space: normal;pointer-events: none;box-shadow: 0 4px 14px rgba(0,0,0,0.25)}@media print{@page{margin: 14mm 12mm}:root,html,html[data-theme]{--background: #ffffff;--foreground: #111111;--card: #ffffff;--card-foreground: #111111;--popover: #ffffff;--popover-foreground: #111111;--primary: #000000;--primary-foreground: #ffffff;--secondary: #ffffff;--secondary-foreground: #111111;--muted: #ffffff;--muted-foreground: #444444;--accent: #000000;--accent-foreground: #ffffff;--destructive: #7a1c1c;--border: #9a9a9a;--input: #9a9a9a;--ring: #000000;--glow: transparent;--glow-soft: transparent;--scanline-opacity: 0}html{zoom: 1 !important;font-size: 16px;scroll-behavior: auto}body{background: #ffffff;color: var(--foreground);font-size: 12px;line-height: 1.45;overflow: visible}body::after{display: none !important}*,*::before,*::after{animation: none !important;transition: none !important;text-shadow: none !important;box-shadow: none !important}html.term-anim [data-term] [data-term-out],html.term-anim [data-term] [data-term-out]:not(.term-show),html.term-anim [data-term] [data-term-out]>*{visibility: visible !important;opacity: 1 !important}html.term-anim [data-term] .prompt:not(.term-live){color: var(--muted-foreground) !important}html.term-anim [data-term] .prompt:not(.term-live)::before{color: var(--primary) !important}header.bar,footer.status,.site-nav,.nav-burger,.mobile-nav,.mobile-footer,.skip-link,.dropdown,.dropdown-panel,.anim-toggle,.cursor-block,.term-caret,.ascii-rule,.toc,#ddtip{display: none !important}body{padding-right: 0 !important}[data-tip]{cursor: auto}span[data-tip],th[data-tip]{border-bottom: 0}.wrap{max-width: none !important;margin: 0 !important;padding: 0 !important}.layout{display: block !important}.content{min-width: 0}h1,.title{font-size: 1.5rem !important}h2{font-size: 1.15rem !important}h3,.sub{font-size: 1rem !important}h4{font-size: 0.9rem !important}.prompt{font-size: 0.7rem}h1,h2,h3,h4,.prompt,.toc-label{break-after: avoid-page;break-inside: avoid}p,li,blockquote{orphans: 3;widows: 3}pre,figure,blockquote,tr,img,.eli5,.card-terminal{break-inside: avoid}svg{break-inside: auto}thead{display: table-header-group}.table-scroll,pre,.diagram{overflow: visible !important;max-width: 100% !important}pre{white-space: pre-wrap !important;overflow-wrap: anywhere;font-size: 0.75rem !important;background: transparent !important}pre.mermaid[data-processed]{white-space: normal !important}code{background: transparent !important;overflow-wrap: anywhere}table{width: 100% !important;table-layout: auto;border-collapse: collapse;font-size: 0.75rem !important}th,td{overflow-wrap: break-word;white-space: normal !important}td code,th code,td a,th a{overflow-wrap: anywhere}a{color: inherit;text-decoration: underline;text-underline-offset: 2px}a.card-terminal,a[class*="card"]{text-decoration: none}.glow,.glow-lg{color: inherit}.btn-terminal{border: 1px solid var(--border);background: transparent;color: var(--foreground)}.mermaid svg{display: block;margin-inline: auto;width: auto !important;height: auto !important;max-width: 100% !important;max-height: 235mm !important}.mermaid svg .node rect,.mermaid svg .node polygon,.mermaid svg .node circle,.mermaid svg .node path,.mermaid svg .label-container,.mermaid svg .cluster rect,.mermaid svg .actor,.mermaid svg .note{fill: #ffffff !important;stroke: #333333 !important}.mermaid svg .edgePath path,.mermaid svg .flowchart-link,.mermaid svg line,.mermaid svg .messageLine0,.mermaid svg .messageLine1{stroke: #333333 !important}.mermaid svg .arrowheadPath,.mermaid svg marker path,.mermaid svg marker polygon{fill: #333333 !important;stroke: #333333 !important}.mermaid svg text,.mermaid svg .nodeLabel,.mermaid svg .edgeLabel,.mermaid svg .cluster-label,.mermaid svg .messageText,.mermaid svg foreignObject div,.mermaid svg foreignObject span,.mermaid svg p{fill: #111111 !important;color: #111111 !important;background: transparent !important}.mermaid svg .edgeLabel rect,.mermaid svg .edgeLabel foreignObject>div{fill: #ffffff !important;background: #ffffff !important}}
|
|
1
|
+
/*! danieldeusing-design v0.6.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
|
|
2
|
+
*,*::before,*::after{box-sizing: border-box}*{margin: 0}html{-webkit-text-size-adjust: 100%;text-size-adjust: 100%;tab-size: 4}body{min-height: 100vh;min-height: 100dvh;line-height: 1.5}img,picture,video,canvas,svg{display: block;max-width: 100%}input,button,textarea,select{font: inherit;color: inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap: break-word}ul,ol{list-style: none;padding: 0}a{color: inherit;text-decoration: none}table{border-collapse: collapse}:root{--background: #f5efe2;--foreground: #43352a;--card: #efe7d4;--card-foreground: #43352a;--popover: #efe7d4;--popover-foreground: #43352a;--primary: #8a4516;--primary-foreground: #f8f3e8;--secondary: #ece3cf;--secondary-foreground: #43352a;--muted: #ece3cf;--muted-foreground: #71614e;--accent: #8a4516;--accent-foreground: #f8f3e8;--destructive: #a02c2c;--success: #1a6b2e;--warning: #845600;--info: #1c5f9e;--pending: #5f3dc4;--border: #d9cdb6;--input: #d9cdb6;--ring: #8a4516;--glow: rgba(160,82,45,0.1);--glow-soft: rgba(160,82,45,0.05);--scanline-opacity: 0.15;--radius: 0rem;--font-mono: "JetBrains Mono Variable","JetBrains Mono","Menlo",monospace}html[data-theme="green"]{--background: #020604;--foreground: #4fdd7d;--card: #04110a;--card-foreground: #4fdd7d;--popover: #04110a;--popover-foreground: #4fdd7d;--primary: #33ff66;--primary-foreground: #02160a;--secondary: #071509;--secondary-foreground: #4fdd7d;--muted: #071509;--muted-foreground: #3da45e;--accent: #33ff66;--accent-foreground: #02160a;--destructive: #ff5c5c;--success: #4ade80;--warning: #f5b32b;--info: #4dabf7;--pending: #b197fc;--border: #1c4a2c;--input: #1c4a2c;--ring: #33ff66;--glow: rgba(51,255,102,0.35);--glow-soft: rgba(51,255,102,0.12);--scanline-opacity: 0.5}html[data-theme="mono"]{--background: #050505;--foreground: #d4d4d4;--card: #0d0d0d;--card-foreground: #d4d4d4;--popover: #0d0d0d;--popover-foreground: #d4d4d4;--primary: #ffffff;--primary-foreground: #050505;--secondary: #111111;--secondary-foreground: #d4d4d4;--muted: #111111;--muted-foreground: #8a8a8a;--accent: #ffffff;--accent-foreground: #050505;--destructive: #ff5c5c;--success: #4ade80;--warning: #f5b32b;--info: #4dabf7;--pending: #b197fc;--border: #333333;--input: #333333;--ring: #ffffff;--glow: rgba(255,255,255,0.25);--glow-soft: rgba(255,255,255,0.08);--scanline-opacity: 0.45}html[data-theme="paper"]{--background: #fafafa;--foreground: #1f1f1f;--card: #f1f1f1;--card-foreground: #1f1f1f;--popover: #f1f1f1;--popover-foreground: #1f1f1f;--primary: #000000;--primary-foreground: #fafafa;--secondary: #efefef;--secondary-foreground: #1f1f1f;--muted: #efefef;--muted-foreground: #595959;--accent: #000000;--accent-foreground: #fafafa;--destructive: #b3261e;--success: #1a7031;--warning: #8f5d00;--info: #1c5f9e;--pending: #5f3dc4;--border: #d4d4d4;--input: #d4d4d4;--ring: #000000;--glow: rgba(0,0,0,0.06);--glow-soft: rgba(0,0,0,0.04);--scanline-opacity: 0.12}:root{--content-w: 78rem;--content-pad: 1.5rem;--fs-xs: 0.625rem;--fs-sm: 0.6875rem;--fs-base: 0.75rem;--fs-md: 0.8125rem;--fs-lg: 0.9375rem;--fs-xl: 1.125rem;--fs-2xl: 1.5rem;--lh-tight: 1.3;--lh-base: 1.5}html{scroll-behavior: smooth}*,*::before,*::after{border-color: var(--border)}:focus-visible{outline: 2px solid var(--ring);outline-offset: 2px}body{background: var(--background);color: var(--foreground);font-family: var(--font-mono);font-size: var(--fs-base);line-height: var(--lh-base);overflow-x: hidden;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale}button:not(:disabled),summary,[role="button"]{cursor: pointer}body::after{content: "";position: fixed;inset: 0;z-index: 40;pointer-events: none;background: repeating-linear-gradient( 0deg,rgba(0,0,0,0.25) 0px,rgba(0,0,0,0.25) 1px,transparent 1px,transparent 3px );opacity: var(--scanline-opacity)}::selection{background: var(--primary);color: var(--primary-foreground)}.glow{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.glow-lg{color: var(--primary);text-shadow: 0 0 12px var(--glow)}.prompt{font-size: 0.75rem;font-weight: 700;color: var(--muted-foreground)}.prompt::before{content: "$ ";color: var(--primary)}.comment::before{content: "# ";color: var(--border)}.cursor-block{display: inline-block;width: 0.55em;height: 1em;margin-left: 8px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em);animation: ddd-blink 1.1s step-end infinite}@keyframes ddd-blink{50%{opacity: 0}}.btn-terminal{display: inline-block;background: var(--primary);color: var(--primary-foreground);font-weight: 700;padding: 12px 24px;box-shadow: 0 0 16px var(--glow);transition: box-shadow 0.15s ease,transform 0.15s ease}.btn-terminal::before{content: "> "}.btn-terminal:hover{box-shadow: 0 0 28px var(--glow);transform: translateY(-2px)}.link-quiet{color: var(--muted-foreground);text-decoration: underline;text-underline-offset: 4px;transition: color 0.15s ease}.link-quiet:hover{color: var(--primary)}.anim-toggle{display: inline-flex;align-items: center;gap: 6px;font: inherit;color: var(--muted-foreground);background: none;border: 0;cursor: pointer;transition: color 0.15s ease}.anim-toggle:hover{color: var(--primary)}.anim-toggle[aria-pressed="true"] [data-anim-box]{color: var(--primary)}.dd-dot{display: inline-block;width: 11px;height: 11px;flex: none;border-radius: 50%;background: currentColor}.dd-flag{display: inline-block;width: 15px;height: 10px;flex: none;border: 1px solid var(--border);background-size: cover;background-repeat: no-repeat}.dd-flag-de{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='4' fill='%23262626'/><rect y='4' width='18' height='4' fill='%23c83232'/><rect y='8' width='18' height='4' fill='%23e8be32'/></svg>")}.dd-flag-en{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='12' fill='%23b22234'/><rect y='4' width='18' height='4' fill='%23ececec'/><rect width='8' height='6' fill='%233c3b6e'/></svg>")}.dd-flag-pt{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='18' height='12' fill='%231c9148'/><polygon points='9,1.5 15.5,6 9,10.5 2.5,6' fill='%23e8c832'/><rect x='8' y='5' width='2' height='2' fill='%232c3f87'/></svg>")}.dd-flag-es{background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'><rect width='6' height='12' fill='%2315734c'/><rect x='6' width='6' height='12' fill='%23ececec'/><rect x='12' width='6' height='12' fill='%23bf2233'/><rect x='8' y='5' width='2' height='2' fill='%237a5c3a'/></svg>")}.ascii-rule{margin: 1rem 0;border: 0;color: var(--border);line-height: 1;white-space: nowrap;overflow: hidden;user-select: none}.ascii-rule::before{content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"}.card-terminal{background: var(--card);border: 1px solid var(--border);transition: border-color 0.15s ease,box-shadow 0.15s ease}.card-terminal:hover{border-color: var(--primary);box-shadow: 0 0 20px var(--glow-soft)}.dropdown{position: relative}.dropdown>summary{display: inline-flex;align-items: center;gap: 6px;cursor: pointer;user-select: none;list-style: none;color: var(--muted-foreground);transition: color 0.15s ease}.dropdown>summary::-webkit-details-marker{display: none}.dropdown>summary:hover,.dropdown[open]>summary{color: var(--primary)}.dropdown-panel{position: absolute;right: 0;bottom: calc(100% + 12px);z-index: 50;min-width: 128px;margin: 0;padding: 4px 0;list-style: none;background: var(--card);border: 1px solid var(--border);border-radius: 0;box-shadow: 0 0 20px var(--glow-soft)}.dropdown-panel--down{top: calc(100% + 8px);bottom: auto;left: 0;right: auto}.dropdown-item{display: flex;align-items: center;gap: 8px;width: 100%;padding: 5px 14px;text-align: left;font: inherit;line-height: 1.5;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;white-space: nowrap;transition: color 0.15s ease}.dropdown-item:hover{color: var(--primary);background: var(--muted)}.dropdown-item[aria-current="true"],html:not([data-theme]) .dropdown-item[data-theme-value="warm"],html[data-theme="green"] .dropdown-item[data-theme-value="green"],html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],html[data-theme="warm"] .dropdown-item[data-theme-value="warm"]{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.eli5{margin: 1.25em 0;padding: 0.7em 1em;color: var(--foreground);background: color-mix(in srgb,var(--primary) 7%,var(--card));border: 1px solid var(--border);border-left: 3px solid var(--primary);border-radius: var(--radius);font-size: 0.92em;line-height: 1.6}.eli5::before{content: "ELI5";display: inline-flex;align-items: center;justify-content: center;margin-right: 0.6em;vertical-align: 0.08em;font-family: var(--font-mono);font-size: 0.72em;font-weight: 700;line-height: 1;letter-spacing: 0.04em;padding: 0.34em 0.6em;border-radius: 5px;background: #b42318;color: #fff}.eli5-term{font-weight: 700;color: var(--primary)}html.anim-off *,html.anim-off *::before,html.anim-off *::after{animation: none !important}html.anim-off .cursor-block{display: none}@media (prefers-reduced-motion: no-preference){html.term-anim [data-term] .prompt:not(.term-live),html.term-anim [data-term] .prompt:not(.term-live)::before{color: transparent}html.term-anim [data-term] [data-term-out]:not(.term-show){visibility: hidden}html.term-anim [data-term] [data-term-out].term-show{animation: ddd-term-output 0.2s steps(3,end) both}@keyframes ddd-term-output{from{opacity: 0}}html.term-anim [data-term] [data-term-out].term-show>*{animation: ddd-term-output 0.25s steps(3,end) both}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(2){animation-delay: 0.09s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(3){animation-delay: 0.18s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(4){animation-delay: 0.27s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(5){animation-delay: 0.36s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(6){animation-delay: 0.45s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(7){animation-delay: 0.54s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(8){animation-delay: 0.63s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(9){animation-delay: 0.72s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(10){animation-delay: 0.81s}html.term-anim [data-term] [data-term-out].term-show>*:nth-child(n + 11){animation-delay: 0.9s}.term-caret{display: inline-block;width: 0.55em;height: 1em;margin-left: 2px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em)}}.tabs{display: flex;flex-wrap: wrap;gap: 0.15rem;margin: 1.35rem 0 0;border-bottom: 2px solid color-mix(in srgb,var(--border) 80%,transparent)}.tab{background: transparent;border: 0;margin-bottom: -2px;font: inherit;font-size: 0.86em;cursor: pointer;padding: 0.5rem 0.95rem;color: var(--muted-foreground);transition: background 0.12s ease,color 0.12s ease}.tab:hover{color: var(--primary);background: color-mix(in srgb,var(--primary) 10%,transparent)}.tab[aria-selected="true"]{background: var(--primary);color: var(--background);font-weight: 700}.tab:focus-visible{outline: 2px solid color-mix(in srgb,var(--primary) 55%,transparent);outline-offset: -2px}@media (pointer: coarse),(max-width: 40rem){.tab{padding: 0.7rem 0.8rem;min-height: 44px}}section.doc.tab-panel{margin-top: 1.35rem}details.fold{border-top: 1px solid color-mix(in srgb,currentColor 15%,transparent)}details.fold>summary{display: flex;align-items: center;gap: 0.5rem;cursor: pointer;list-style: none;padding: 0.55rem 0;font-size: 0.85rem;color: var(--muted-foreground)}details.fold>summary::-webkit-details-marker{display: none}details.fold>summary::before{content: "\25B8";flex: none;opacity: 0.6}details.fold[open]>summary::before{content: "\25BE"}details.fold>summary:hover{color: var(--primary)}details.fold>summary:focus-visible{outline: 2px solid color-mix(in srgb,currentColor 45%,transparent);outline-offset: 2px}.fold-body{font-size: 0.9rem;padding: 0 0 0.7rem 1.1rem}.fold-body>* + *{margin-top: 0.6rem}.legend{list-style: none;padding: 0;margin: 0.7rem 0 0;display: grid;gap: 0.4rem 1.4rem;font-size: 0.86rem}@media (min-width: 52rem){.legend{grid-template-columns: repeat(2,minmax(0,1fr))}}.legend>li{line-height: 1.6}.legend>li>:first-child{margin-right: 0.45rem}.tickstrip:not(:empty){border: 1px solid var(--border);background: var(--card);margin: 1.6rem 0 1.5rem}.ticktable{width: 100%;border-collapse: collapse;font-size: 0.82rem}.ticktable td{padding: 0.5rem 0.75rem;vertical-align: baseline;border: 0;white-space: nowrap}.ticktable td.tick-stats{width: 100%;white-space: normal}.tick{border-bottom: 1px solid color-mix(in srgb,var(--border) 55%,transparent)}.tick:last-child{border-bottom: 0}.tick-dot{font-size: 0.7em;width: 1.5rem;padding-right: 0 !important;border-left: 3px solid transparent;padding-left: 0.6rem !important}.tick--ok .tick-dot{color: var(--success);border-left-color: color-mix(in srgb,var(--success) 45%,transparent)}.tick--stale .tick-dot{color: var(--destructive);border-left-color: var(--destructive)}.tick--never .tick-dot{color: var(--muted-foreground);border-left-color: color-mix(in srgb,var(--muted-foreground) 35%,transparent)}.tick-name{font-weight: 700;color: var(--foreground);letter-spacing: 0.01em}.tick-last,.tick-next{font-variant-numeric: tabular-nums;color: var(--muted-foreground)}.tick-next{opacity: 0.72}.tick--stale .tick-last{color: var(--destructive);font-weight: 700}.tick--never .tick-last{font-style: italic}.tick-stats{color: var(--muted-foreground)}.tick-stats b{font-weight: 700;color: var(--primary);font-variant-numeric: tabular-nums}.tick-sep{font-style: normal;opacity: 0.35;margin: 0 0.5rem}.tick--stale{background: color-mix(in srgb,var(--destructive) 8%,transparent)}@media (max-width: 40rem){.ticktable,.ticktable tbody,.tick,.ticktable td{display: block}.tick{padding: 0.4rem 0.5rem}.ticktable td{display: inline-block;padding: 0.1rem 0.5rem 0.1rem 0}.ticktable td.tick-stats{display: block;width: auto}}.dgm-zoomable{position: relative;cursor: zoom-in}.dgm-zoomable::after{content: "⤢";position: absolute;top: 0.4rem;right: 0.5rem;font-size: 0.85rem;line-height: 1;opacity: 0.45;pointer-events: none;color: var(--muted-foreground)}.dgm-zoomable:hover::after,.dgm-zoomable:focus-visible::after{opacity: 1;color: var(--primary)}.dgm-zoomable:focus-visible{outline: 2px solid var(--primary);outline-offset: 3px}html.dgm-locked,html.dgm-locked body{overflow: hidden}.dgm-overlay{display: none;position: fixed;inset: 0;z-index: 90;background: color-mix(in srgb,var(--background) 96%,transparent);flex-direction: column}.dgm-overlay.open{display: flex}.dgm-bar{flex: none;display: flex;align-items: center;justify-content: flex-end;gap: 0.4rem;padding: 0.5rem 0.75rem;border-bottom: 1px solid var(--border);background: var(--card)}.dgm-btn{font: inherit;font-size: 0.82rem;cursor: pointer;padding: 0.3rem 0.7rem;min-height: 32px;background: transparent;border: 1px solid var(--border);color: var(--foreground)}.dgm-btn:hover{border-color: var(--primary);color: var(--primary)}.dgm-btn:focus-visible{outline: 2px solid var(--primary);outline-offset: 1px}.dgm-close{border-color: color-mix(in srgb,var(--destructive) 55%,transparent);color: var(--destructive)}.dgm-close:hover{border-color: var(--destructive);color: var(--destructive)}.dgm-stage{flex: 1;overflow: hidden;display: grid;place-items: center;cursor: grab;touch-action: none}.dgm-stage.is-grabbing{cursor: grabbing}.dgm-art{transform-origin: center center;will-change: transform}.dgm-art>svg,.dgm-art>img{display: block;max-width: none;max-height: none}@media print{.dgm-overlay,.dgm-zoomable::after{display: none !important}}.wrap{max-width: var(--content-w);margin-inline: auto;padding-inline: var(--content-pad)}.skip-link{position: absolute;left: -999px;top: 0;z-index: 100;background: var(--card);border: 1px solid var(--primary);padding: 0.5rem 1rem;color: var(--primary)}.skip-link:focus{left: 0.5rem;top: 0.5rem}.visually-hidden{position: absolute;width: 1px;height: 1px;overflow: hidden;clip: rect(0 0 0 0);white-space: nowrap}header.bar{position: sticky;top: 0;z-index: 30;display: flex;align-items: center;justify-content: space-between;gap: 1rem;padding: 0.6rem 1.25rem;border-bottom: 1px solid var(--border);background: var(--card)}header.bar .brand{display: inline-flex;align-items: center;font-weight: 700;font-size: 1rem}header.bar .brand,header.bar .brand a{color: inherit;text-decoration: none}header.bar .dropdown summary{padding: 0.6rem 0.4rem}.bar-right{display: flex;align-items: center;gap: 1rem;flex-shrink: 0}footer.status{position: fixed;inset-inline: 0;bottom: 0;z-index: 50;min-height: 2rem;display: flex;align-items: center;justify-content: space-between;gap: 1rem;padding: 0.35rem 1.25rem;border-top: 1px solid var(--border);background: var(--card);font-size: 0.7rem}footer.status .dropdown summary,footer.status .anim-toggle{padding: 0.55rem 0.4rem}.status-left{color: var(--muted-foreground);min-width: 0;overflow: hidden;text-overflow: ellipsis;white-space: nowrap}.status-right{display: flex;align-items: center;gap: 1rem;flex-shrink: 0}.sep{width: 1px;height: 0.9rem;background: var(--border)}.doc-link{color: var(--muted-foreground);text-decoration: none;transition: color 0.15s ease}.doc-link:hover{color: var(--primary)}.ls-row{display: flex;align-items: baseline;gap: 0.9rem}.ls-perm{color: var(--muted-foreground);font-size: 0.72rem;letter-spacing: 0}.ls-row--sub .ls-name{margin-left: 0.55rem;padding-left: 0.75rem;border-left: 1px solid color-mix(in srgb,var(--muted-foreground) 40%,transparent)}.ls-row--sub2 .ls-name{margin-left: 1.7rem}.ls-panel .ls-name{color: var(--muted-foreground)}.ls-panel .ls-row--dir .ls-name{color: var(--primary);font-weight: 700}.dropdown-panel.ls-panel{min-width: 17rem;left: auto !important;right: 0}:root{--ls-nav-w: 17rem;--ls-nav-top: 3rem;--ls-nav-bottom: 2.2rem}@media (min-width: 48.0625rem){html{--ls-nav-inset: 0rem}html:has(.ls-nav):not([data-ls-nav="off"]){--ls-nav-inset: var(--ls-nav-w)}body{padding-right: var(--ls-nav-inset)}header.bar{margin-right: calc(-1 * var(--ls-nav-inset))}.ls-nav{position: fixed;top: var(--ls-nav-top);right: 0;bottom: var(--ls-nav-bottom);width: var(--ls-nav-w);z-index: 25;display: flex;flex-direction: column;overflow: hidden;background: var(--card);border-left: 1px solid var(--border)}html:not(.anim-off) .ls-nav{transition: transform 0.18s ease}html[data-ls-nav="off"] .ls-nav{transform: translateX(100%)}.ls-nav-head{display: inline-flex;align-items: center;gap: 0.5rem;margin-left: 0.75rem}.ls-nav-title{font-weight: 700;font-size: 0.9rem}.ls-nav .ls-panel{flex: 1;min-height: 0;overflow-y: auto;list-style: none;margin: 0;padding: 0.5rem 0 1rem}.ls-nav-toggle{background: none;border: 0;font: inherit;cursor: pointer;line-height: 1;color: var(--muted-foreground);padding: 0.4rem 0.55rem}.ls-nav-toggle::after{content: "\00BB"}html[data-ls-nav="off"] .ls-nav-toggle::after{content: "\00AB"}.ls-nav-toggle:hover{color: var(--primary)}.ls-nav-toggle:focus-visible{outline: 2px solid color-mix(in srgb,var(--primary) 55%,transparent);outline-offset: -2px}}.nav-burger{display: none;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;padding: 0.55rem;margin: -0.3rem -0.3rem -0.3rem 0}.nav-burger:hover{color: var(--primary)}.mobile-nav{display: none;list-style: none;margin: 0;padding: 0}.mobile-footer{display: none}@media (max-width: 48rem){.nav-burger{display: inline-flex;align-items: center}.site-nav{display: none;position: absolute;top: 100%;left: 0;right: 0;z-index: 40;background: var(--card);border-bottom: 1px solid var(--border);padding: 0.4rem 1.25rem 0.9rem;max-height: calc(100vh - 6rem);overflow-y: auto}.site-nav.open{display: block}.site-nav>.ls-nav,.mobile-nav{display: flex;flex-direction: column}.mobile-nav .mobile-item{display: flex;align-items: baseline;gap: 0.9rem;padding: 0.65rem 0;text-decoration: none;color: var(--foreground);font-size: 0.9rem;border-bottom: 1px solid var(--border)}.mobile-nav li:last-child .mobile-item{border-bottom: 0}.mobile-nav .mobile-item:active .ls-name,.mobile-nav .mobile-item:hover .ls-name{color: var(--primary)}footer.status{display: none}.mobile-footer{display: flex;flex-direction: column;gap: 0.55rem;margin-top: 0.8rem;border-top: 1px solid var(--border);padding-top: 0.8rem;font-size: 0.85rem}.mobile-footer .doc-link{padding: 0.2rem 0}.mobile-footer .mobile-theme summary{list-style: none;display: flex;align-items: center;gap: 0.5rem;color: var(--muted-foreground);cursor: pointer;padding: 0.2rem 0}.mobile-footer .mobile-theme summary::-webkit-details-marker{display: none}.mobile-footer .mf-chev{margin-left: auto;opacity: 0.7}.mobile-footer .mf-panel{display: flex;flex-direction: column;margin-top: 0.3rem}.mobile-footer .mf-panel .dropdown-item{text-align: left;padding: 0.4rem 0.6rem}.mobile-footer .anim-toggle{display: inline-flex;gap: 0.5rem;align-items: center;background: none;border: 0;padding: 0.2rem 0;color: var(--muted-foreground);font: inherit;cursor: pointer}}[data-tip]{cursor: help}span[data-tip],th[data-tip]{border-bottom: 1px dotted var(--muted-foreground)}#ddtip{position: fixed;z-index: 9999;display: none;max-width: 340px;background: var(--background);color: var(--foreground);border: 1px solid var(--muted-foreground);border-radius: 4px;padding: 7px 10px;font-size: 0.72rem;line-height: 1.45;font-weight: 400;text-align: left;white-space: normal;pointer-events: none;box-shadow: 0 4px 14px rgba(0,0,0,0.25)}@media print{@page{margin: 14mm 12mm}:root,html,html[data-theme]{--background: #ffffff;--foreground: #111111;--card: #ffffff;--card-foreground: #111111;--popover: #ffffff;--popover-foreground: #111111;--primary: #000000;--primary-foreground: #ffffff;--secondary: #ffffff;--secondary-foreground: #111111;--muted: #ffffff;--muted-foreground: #444444;--accent: #000000;--accent-foreground: #ffffff;--destructive: #7a1c1c;--border: #9a9a9a;--input: #9a9a9a;--ring: #000000;--glow: transparent;--glow-soft: transparent;--scanline-opacity: 0}html{zoom: 1 !important;font-size: 16px;scroll-behavior: auto}body{background: #ffffff;color: var(--foreground);font-size: 12px;line-height: 1.45;overflow: visible}body::after{display: none !important}*,*::before,*::after{animation: none !important;transition: none !important;text-shadow: none !important;box-shadow: none !important}html.term-anim [data-term] [data-term-out],html.term-anim [data-term] [data-term-out]:not(.term-show),html.term-anim [data-term] [data-term-out]>*{visibility: visible !important;opacity: 1 !important}html.term-anim [data-term] .prompt:not(.term-live){color: var(--muted-foreground) !important}html.term-anim [data-term] .prompt:not(.term-live)::before{color: var(--primary) !important}header.bar,footer.status,.site-nav,.nav-burger,.mobile-nav,.mobile-footer,.skip-link,.dropdown,.dropdown-panel,.anim-toggle,.cursor-block,.term-caret,.ascii-rule,.toc,#ddtip{display: none !important}body{padding-right: 0 !important}[data-tip]{cursor: auto}span[data-tip],th[data-tip]{border-bottom: 0}.wrap{max-width: none !important;margin: 0 !important;padding: 0 !important}.layout{display: block !important}.content{min-width: 0}h1,.title{font-size: 1.5rem !important}h2{font-size: 1.15rem !important}h3,.sub{font-size: 1rem !important}h4{font-size: 0.9rem !important}.prompt{font-size: 0.7rem}h1,h2,h3,h4,.prompt,.toc-label{break-after: avoid-page;break-inside: avoid}p,li,blockquote{orphans: 3;widows: 3}pre,figure,blockquote,tr,img,.eli5,.card-terminal{break-inside: avoid}svg{break-inside: auto}thead{display: table-header-group}.table-scroll,pre,.diagram{overflow: visible !important;max-width: 100% !important}pre{white-space: pre-wrap !important;overflow-wrap: anywhere;font-size: 0.75rem !important;background: transparent !important}pre.mermaid[data-processed]{white-space: normal !important}code{background: transparent !important;overflow-wrap: anywhere}table{width: 100% !important;table-layout: auto;border-collapse: collapse;font-size: 0.75rem !important}th,td{overflow-wrap: break-word;white-space: normal !important}td code,th code,td a,th a{overflow-wrap: anywhere}a{color: inherit;text-decoration: underline;text-underline-offset: 2px}a.card-terminal,a[class*="card"]{text-decoration: none}.glow,.glow-lg{color: inherit}.btn-terminal{border: 1px solid var(--border);background: transparent;color: var(--foreground)}.mermaid svg{display: block;margin-inline: auto;width: auto !important;height: auto !important;max-width: 100% !important;max-height: 235mm !important}.mermaid svg .node rect,.mermaid svg .node polygon,.mermaid svg .node circle,.mermaid svg .node path,.mermaid svg .label-container,.mermaid svg .cluster rect,.mermaid svg .actor,.mermaid svg .note{fill: #ffffff !important;stroke: #333333 !important}.mermaid svg .edgePath path,.mermaid svg .flowchart-link,.mermaid svg line,.mermaid svg .messageLine0,.mermaid svg .messageLine1{stroke: #333333 !important}.mermaid svg .arrowheadPath,.mermaid svg marker path,.mermaid svg marker polygon{fill: #333333 !important;stroke: #333333 !important}.mermaid svg text,.mermaid svg .nodeLabel,.mermaid svg .edgeLabel,.mermaid svg .cluster-label,.mermaid svg .messageText,.mermaid svg foreignObject div,.mermaid svg foreignObject span,.mermaid svg p{fill: #111111 !important;color: #111111 !important;background: transparent !important}.mermaid svg .edgeLabel rect,.mermaid svg .edgeLabel foreignObject>div{fill: #ffffff !important;background: #ffffff !important}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danieldeusing/design",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The danieldeusing terminal design system — framework-agnostic CSS tokens, components, and a vanilla-JS runtime for the CRT/JetBrains-Mono look used across danieldeusing.de, seedr, and briefs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"files": [
|
|
45
45
|
"src",
|
|
46
|
+
"templates",
|
|
46
47
|
"runtime",
|
|
47
48
|
"dist",
|
|
48
49
|
"tokens",
|
package/src/tokens.css
CHANGED
|
@@ -22,13 +22,30 @@
|
|
|
22
22
|
* A gap of 0.0692 with nothing in it. So NO single hex can serve four themes:
|
|
23
23
|
* the two near-black themes need a light tint, the two light themes a dark one,
|
|
24
24
|
* and every compromise fails both. That is arithmetic, not taste — which is why
|
|
25
|
-
* --destructive, --success and --
|
|
25
|
+
* --destructive, --success, --warning, --info and --pending are each declared
|
|
26
|
+
* four times.
|
|
26
27
|
*
|
|
27
28
|
* Cockpit carried twelve hardcoded accents that predate these tokens; every one
|
|
28
29
|
* missed AA on at least one theme and four sat inside the gap, clearing neither
|
|
29
30
|
* side. Adding a status colour? Add a TOKEN here with its measured worst-case
|
|
30
31
|
* ratio in a trailing comment. Do not tune a literal at the call site — that
|
|
31
32
|
* forks the palette and fixes exactly one theme.
|
|
33
|
+
*
|
|
34
|
+
* ── FIVE STATUS ACCENTS, BECAUSE A STATE MACHINE HAS MORE THAN THREE STATES ──
|
|
35
|
+
* good / attention / bad covers a verdict. It does not cover the two states a
|
|
36
|
+
* dashboard spends most of its time showing, and cockpit forked a literal for
|
|
37
|
+
* each of them rather than go without:
|
|
38
|
+
*
|
|
39
|
+
* --info a state, not a verdict. In flight, informational, recorded and
|
|
40
|
+
* fine but not a win: dispatching, gated, started-by-hand, "silent
|
|
41
|
+
* for a reason". Blue, so it never reads as an alarm.
|
|
42
|
+
* --pending NO verdict yet. Still running, timed out, could not determine,
|
|
43
|
+
* not recorded: the answer is absent, which is different from the
|
|
44
|
+
* answer being bad. Violet, so it never reads as --destructive.
|
|
45
|
+
*
|
|
46
|
+
* Both are peers of --success/--warning/--destructive and obey the same rule:
|
|
47
|
+
* one value for the two light themes, one for the two near-black ones, each
|
|
48
|
+
* measured against --background, --card AND --muted.
|
|
32
49
|
*/
|
|
33
50
|
|
|
34
51
|
:root {
|
|
@@ -49,6 +66,8 @@
|
|
|
49
66
|
--destructive: #a02c2c;
|
|
50
67
|
--success: #1a6b2e; /* 5.16:1 worst surface */
|
|
51
68
|
--warning: #845600; /* 4.97:1 worst surface */
|
|
69
|
+
--info: #1c5f9e; /* 5.17:1 worst surface */
|
|
70
|
+
--pending: #5f3dc4; /* 5.58:1 worst surface */
|
|
52
71
|
--border: #d9cdb6;
|
|
53
72
|
--input: #d9cdb6;
|
|
54
73
|
--ring: #8a4516;
|
|
@@ -81,6 +100,8 @@ html[data-theme="green"] {
|
|
|
81
100
|
--destructive: #ff5c5c;
|
|
82
101
|
--success: #4ade80; /* 10.76:1 worst surface */
|
|
83
102
|
--warning: #f5b32b; /* 10.15:1 worst surface */
|
|
103
|
+
--info: #4dabf7; /* 7.57:1 worst surface */
|
|
104
|
+
--pending: #b197fc; /* 7.77:1 worst surface */
|
|
84
105
|
--border: #1c4a2c;
|
|
85
106
|
--input: #1c4a2c;
|
|
86
107
|
--ring: #33ff66;
|
|
@@ -108,6 +129,8 @@ html[data-theme="mono"] {
|
|
|
108
129
|
--destructive: #ff5c5c;
|
|
109
130
|
--success: #4ade80; /* 10.84:1 worst surface */
|
|
110
131
|
--warning: #f5b32b; /* 10.22:1 worst surface */
|
|
132
|
+
--info: #4dabf7; /* 7.63:1 worst surface */
|
|
133
|
+
--pending: #b197fc; /* 7.82:1 worst surface */
|
|
111
134
|
--border: #333333;
|
|
112
135
|
--input: #333333;
|
|
113
136
|
--ring: #ffffff;
|
|
@@ -135,6 +158,8 @@ html[data-theme="paper"] {
|
|
|
135
158
|
--destructive: #b3261e;
|
|
136
159
|
--success: #1a7031; /* 5.36:1 worst surface */
|
|
137
160
|
--warning: #8f5d00; /* 4.89:1 worst surface */
|
|
161
|
+
--info: #1c5f9e; /* 5.74:1 worst surface */
|
|
162
|
+
--pending: #5f3dc4; /* 6.19:1 worst surface */
|
|
138
163
|
--border: #d4d4d4;
|
|
139
164
|
--input: #d4d4d4;
|
|
140
165
|
--ring: #000000;
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!--
|
|
3
|
+
danieldeusing-design — one-page documentation template ("danieldeusing-docs").
|
|
4
|
+
|
|
5
|
+
A single self-contained HTML file: the design system loads build-free from the
|
|
6
|
+
jsDelivr CDN, so this opens directly in a browser with no build step.
|
|
7
|
+
|
|
8
|
+
Fill the {{PLACEHOLDERS}}. The CDN URLs are deliberately UNPINNED — one design system, every
|
|
9
|
+
surface on the current version (Daniel, 2026-08-05). A surface that ships the system's own
|
|
10
|
+
MARKUP against a specific release pins instead (cockpit does); see the danieldeusing-design
|
|
11
|
+
skill. Unpinned costs this page nothing visible ONLY because it is defended twice: the
|
|
12
|
+
`onerror` snapshot below covers a CDN that cannot be reached, and every token in the <style>
|
|
13
|
+
block carries a literal fallback for the window where a browser still holds an older build
|
|
14
|
+
(jsDelivr caches an unpinned url for SEVEN DAYS). Keep both when editing.
|
|
15
|
+
|
|
16
|
+
Chrome (fixed by the template, do not restyle):
|
|
17
|
+
- top-left : the "danieldeusing-docs" wordmark (always).
|
|
18
|
+
- top-right : a navigation dropdown — INCLUDE ONLY when the doc set has more
|
|
19
|
+
than one page; for a single-page doc, delete the <details id="nav">.
|
|
20
|
+
- bottom-left : [{{FOLDER}}] {{DOC_TITLE}} e.g. "[pagr] Source Code documentation".
|
|
21
|
+
- bottom-right : the link to danieldeusing.de + the theme (page settings) dropdown.
|
|
22
|
+
Content (you fill): the title, the full-width lede, and the <section> blocks. Every
|
|
23
|
+
section has an id and a matching entry in the "On this page" table of contents.
|
|
24
|
+
-->
|
|
25
|
+
<html lang="en">
|
|
26
|
+
<head>
|
|
27
|
+
<meta charset="utf-8" />
|
|
28
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
29
|
+
<title>{{DOC_TITLE}}</title>
|
|
30
|
+
<meta name="description" content="{{DOC_DESCRIPTION}}" />
|
|
31
|
+
<meta name="theme-color" content="#f5efe2" />
|
|
32
|
+
|
|
33
|
+
<!-- pre-paint: apply the saved theme + animation gate before first paint -->
|
|
34
|
+
<script>
|
|
35
|
+
(() => {
|
|
36
|
+
const bg = { warm: "#f5efe2", green: "#020604", mono: "#050505", paper: "#fafafa" };
|
|
37
|
+
let theme = "warm";
|
|
38
|
+
try {
|
|
39
|
+
const stored = localStorage.getItem("theme");
|
|
40
|
+
if (stored && stored in bg) theme = stored;
|
|
41
|
+
} catch {}
|
|
42
|
+
document.documentElement.dataset.theme = theme;
|
|
43
|
+
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", bg[theme]);
|
|
44
|
+
|
|
45
|
+
let animOff = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
46
|
+
try {
|
|
47
|
+
if (localStorage.getItem("anim") === "off") animOff = true;
|
|
48
|
+
} catch {}
|
|
49
|
+
if (animOff) document.documentElement.classList.add("anim-off");
|
|
50
|
+
})();
|
|
51
|
+
|
|
52
|
+
// Resolution-independent zoom: lay out at a fixed 1920px reference, then scale the
|
|
53
|
+
// whole view up on wider screens so the empty side-margins never exceed their
|
|
54
|
+
// 1920-reference proportion (a true zoom of everything, never below 1×). Pre-paint
|
|
55
|
+
// to avoid a flash.
|
|
56
|
+
(() => {
|
|
57
|
+
const REFERENCE_WIDTH = 1920;
|
|
58
|
+
const applyZoom = () => {
|
|
59
|
+
document.documentElement.style.zoom = String(Math.max(1, window.innerWidth / REFERENCE_WIDTH));
|
|
60
|
+
};
|
|
61
|
+
applyZoom();
|
|
62
|
+
window.addEventListener("resize", applyZoom);
|
|
63
|
+
})();
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<!-- The design system, tracked LIVE (unpinned): a doc always wears the current look.
|
|
67
|
+
`onerror` swaps in a byte-for-byte snapshot of the release this doc was written
|
|
68
|
+
against, served from this site — so a reader with no route to the CDN still gets
|
|
69
|
+
the page as it stood that day. Snapshots are stored ONCE per version under
|
|
70
|
+
/_design/, not once per doc, and /_design/ is served without a login (a published
|
|
71
|
+
stylesheet is not a secret, and a client scope must be able to read it too).
|
|
72
|
+
The version below is the snapshot this doc was written against — bump it (and add
|
|
73
|
+
the snapshot to danieldeusing-docs) when the design system moves; see the html-doc
|
|
74
|
+
skill, step 3. NOTE the path is site-absolute: it resolves on
|
|
75
|
+
docs.danieldeusing.de, NOT for a doc opened from disk over file://. -->
|
|
76
|
+
<link
|
|
77
|
+
rel="stylesheet"
|
|
78
|
+
href="https://cdn.jsdelivr.net/npm/@danieldeusing/design/dist/danieldeusing-design.min.css"
|
|
79
|
+
onerror="this.onerror=null;this.href='/_design/danieldeusing-design-0.4.0.min.css'"
|
|
80
|
+
/>
|
|
81
|
+
<link
|
|
82
|
+
rel="stylesheet"
|
|
83
|
+
href="https://cdn.jsdelivr.net/npm/@danieldeusing/design/src/fonts.css"
|
|
84
|
+
onerror="this.onerror=null;this.href='/_design/danieldeusing-design-0.4.0.fonts.css'"
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<style>
|
|
88
|
+
/* Page-only layout. The design system ships the visual identity AND the measurements
|
|
89
|
+
(--content-w / --content-pad / --fs-*), so every value below is a TOKEN.
|
|
90
|
+
|
|
91
|
+
Each one carries a literal fallback on purpose. This page loads the design system
|
|
92
|
+
UNPINNED, and jsDelivr serves that url `max-age=604800` — seven days in the browser,
|
|
93
|
+
12h at the edge — so a reader can be holding a build that predates these tokens
|
|
94
|
+
(0.2.0 has neither `.wrap` nor `--fs-*`). A bare `var(--content-w)` would resolve to
|
|
95
|
+
nothing there and the page would go full-bleed with collapsed type. `var(--token,
|
|
96
|
+
literal)` takes the published value whenever it arrived and the old one when it did
|
|
97
|
+
not — the same contract as the offline <link> fallback above.
|
|
98
|
+
|
|
99
|
+
Note `padding-block` + `padding-inline`, never the `padding` shorthand: the
|
|
100
|
+
shorthand resets padding-inline and silently drops the left/right margins. */
|
|
101
|
+
.wrap { max-width: var(--content-w, 78rem); margin-inline: auto;
|
|
102
|
+
padding-block: 2.5rem 5rem; padding-inline: var(--content-pad, 1.5rem); }
|
|
103
|
+
|
|
104
|
+
/* header/footer chrome + nav now ship with the design system (src/chrome.css) */
|
|
105
|
+
|
|
106
|
+
/* content + table-of-contents layout (mirrors danieldeusing.de articles) */
|
|
107
|
+
.layout { display: grid; gap: 2.5rem; }
|
|
108
|
+
@media (min-width: 64rem) { .layout { grid-template-columns: minmax(0, 1fr) 13rem; } }
|
|
109
|
+
.content { min-width: 0; }
|
|
110
|
+
h1.title { font-size: var(--fs-2xl, 1.7rem); font-weight: 700; margin: 0.4rem 0 0.5rem; }
|
|
111
|
+
.lede { color: var(--muted-foreground); } /* full width — no max-width cap */
|
|
112
|
+
|
|
113
|
+
.toc { display: none; }
|
|
114
|
+
@media (min-width: 64rem) { .toc { display: block; } }
|
|
115
|
+
.toc-inner { position: sticky; top: 4.5rem; border-top: 1px solid var(--border); padding-top: 0.9rem; }
|
|
116
|
+
.toc-label { font-size: var(--fs-sm, 0.66rem); text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted-foreground); }
|
|
117
|
+
.toc nav { margin-top: 0.6rem; display: flex; flex-direction: column; }
|
|
118
|
+
.toc a { padding: 0.22rem 0; font-size: var(--fs-base, 0.76rem); color: var(--muted-foreground); text-decoration: none; transition: color 0.15s ease; }
|
|
119
|
+
.toc a:hover, .toc a.active { color: var(--primary); }
|
|
120
|
+
|
|
121
|
+
section.doc { margin-top: 2.5rem; scroll-margin-top: 4rem; }
|
|
122
|
+
.body { margin-top: 0.85rem; }
|
|
123
|
+
.body > * + * { margin-top: 0.75rem; }
|
|
124
|
+
|
|
125
|
+
/* content components the generator uses */
|
|
126
|
+
ol.steps { counter-reset: step; padding: 0; }
|
|
127
|
+
ol.steps > li { position: relative; padding-left: 2.25rem; margin-top: 0.6rem; counter-increment: step; }
|
|
128
|
+
ol.steps > li::before { content: counter(step); position: absolute; left: 0; top: 0; width: 1.5rem; text-align: right; color: var(--primary); font-weight: 700; }
|
|
129
|
+
ul.plain { padding-left: 1.1rem; }
|
|
130
|
+
ul.plain > li { margin-top: 0.3rem; }
|
|
131
|
+
.grid { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
|
|
132
|
+
.pad { padding: 1rem; }
|
|
133
|
+
.muted { color: var(--muted-foreground); }
|
|
134
|
+
code.inline { font-family: inherit; background: var(--muted); border: 1px solid var(--border); border-radius: 4px; padding: 0.05rem 0.35rem; font-size: 0.92em; }
|
|
135
|
+
pre.block { margin: 0; padding: 0.9rem 1rem; overflow-x: auto; font-size: var(--fs-md, 0.86rem); line-height: var(--lh-base, 1.5); background: var(--muted); border: 1px solid var(--border); border-radius: 6px; white-space: pre; }
|
|
136
|
+
/* Wide tables must scroll inside their own container, never the page.
|
|
137
|
+
Always wrap table.kv (and any custom table variant) like this:
|
|
138
|
+
<div class="table-scroll"><table class="kv">...</table></div>
|
|
139
|
+
Without the wrapper, a long code snippet or a multi-item cell forces
|
|
140
|
+
the table wider than its column and the WHOLE PAGE gains a horizontal
|
|
141
|
+
scrollbar instead of just the table — easy to miss until content is
|
|
142
|
+
wide enough to trigger it (many-column tables, file-path lists, long
|
|
143
|
+
inline code). Never set `white-space: nowrap` on a table cell that can
|
|
144
|
+
hold more than one short token (e.g. a list of file names) — nowrap on
|
|
145
|
+
a multi-item cell is what forces the runaway width in the first place. */
|
|
146
|
+
.table-scroll { overflow-x: auto; max-width: 100%; }
|
|
147
|
+
table.kv { width: 100%; border-collapse: collapse; font-size: var(--fs-lg, 0.92rem); }
|
|
148
|
+
table.kv th, table.kv td { text-align: left; vertical-align: top; padding: 0.4rem 0.75rem 0.4rem 0; border-bottom: 1px solid var(--border); }
|
|
149
|
+
table.kv th { color: var(--primary); font-weight: 700; white-space: nowrap; }
|
|
150
|
+
|
|
151
|
+
/* Mermaid diagrams. Before rendering, the <pre> shows the raw diagram source —
|
|
152
|
+
so with JS disabled (or if the CDN is unreachable) the page degrades to a
|
|
153
|
+
readable text diagram instead of an empty box. */
|
|
154
|
+
pre.mermaid { margin: 0; padding: 0.9rem 1rem; overflow-x: auto; font-size: var(--fs-md, 0.86rem); line-height: var(--lh-base, 1.5); background: var(--muted); border: 1px solid var(--border); border-radius: 6px; white-space: pre; }
|
|
155
|
+
pre.mermaid[data-processed] { white-space: normal; text-align: center; }
|
|
156
|
+
pre.mermaid svg { max-width: 100%; height: auto; }
|
|
157
|
+
</style>
|
|
158
|
+
</head>
|
|
159
|
+
|
|
160
|
+
<body>
|
|
161
|
+
<a href="#top" class="skip-link">skip to content</a>
|
|
162
|
+
<header class="bar">
|
|
163
|
+
<!-- top-left: ALWAYS danieldeusing-docs -->
|
|
164
|
+
<a href="#top" class="brand">
|
|
165
|
+
<span class="glow">danieldeusing-docs</span>
|
|
166
|
+
<span class="cursor-block" aria-hidden="true"></span>
|
|
167
|
+
</a>
|
|
168
|
+
<!-- top-right: navigation. Desktop = the `ls -l` dropdown; mobile = the
|
|
169
|
+
burger button toggling a full-width menu with the footer folded in
|
|
170
|
+
(chrome kit: src/chrome.css + runtime initBurgerNav). For a
|
|
171
|
+
single-page doc, delete the whole <nav> + burger. -->
|
|
172
|
+
<button type="button" class="nav-burger" data-nav-toggle aria-label="menu" aria-controls="site-nav" aria-expanded="false">
|
|
173
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M3 12h18"/><path d="M3 18h18"/></svg>
|
|
174
|
+
</button>
|
|
175
|
+
<nav aria-label="site" id="site-nav" class="site-nav"><details class="dropdown" id="nav">
|
|
176
|
+
<summary class="prompt" style="font-weight: 700" aria-label="site navigation">ls -l <span aria-hidden="true">▾</span></summary>
|
|
177
|
+
<ul class="dropdown-panel dropdown-panel--down ls-panel" role="list">
|
|
178
|
+
<li><a class="dropdown-item ls-row" href="{{NAV_1_HREF}}"><span class="ls-perm" aria-hidden="true">drwxr-xr-x</span><span class="ls-name">{{NAV_1_LABEL}}</span></a></li>
|
|
179
|
+
<li><a class="dropdown-item ls-row" href="{{NAV_2_HREF}}"><span class="ls-perm" aria-hidden="true">drwxr-xr-x</span><span class="ls-name">{{NAV_2_LABEL}}</span></a></li>
|
|
180
|
+
</ul>
|
|
181
|
+
</details>
|
|
182
|
+
<ul class="mobile-nav" role="list">
|
|
183
|
+
<li><a class="mobile-item ls-row" href="{{NAV_1_HREF}}"><span class="ls-perm" aria-hidden="true">drwxr-xr-x</span><span class="ls-name">{{NAV_1_LABEL}}</span></a></li>
|
|
184
|
+
<li><a class="mobile-item ls-row" href="{{NAV_2_HREF}}"><span class="ls-perm" aria-hidden="true">drwxr-xr-x</span><span class="ls-name">{{NAV_2_LABEL}}</span></a></li>
|
|
185
|
+
</ul>
|
|
186
|
+
<div class="mobile-footer">
|
|
187
|
+
<a class="doc-link" href="https://danieldeusing.de">danieldeusing.de</a>
|
|
188
|
+
<details class="mobile-theme">
|
|
189
|
+
<summary>
|
|
190
|
+
<svg width="11" height="11" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.5" fill="currentColor"></circle></svg>
|
|
191
|
+
<span data-theme-label>warm</span>
|
|
192
|
+
<span class="mf-chev" aria-hidden="true">▾</span>
|
|
193
|
+
</summary>
|
|
194
|
+
<div class="mf-panel">
|
|
195
|
+
<button type="button" class="dropdown-item" data-theme-value="warm">warm</button>
|
|
196
|
+
<button type="button" class="dropdown-item" data-theme-value="green">green</button>
|
|
197
|
+
<button type="button" class="dropdown-item" data-theme-value="mono">mono</button>
|
|
198
|
+
<button type="button" class="dropdown-item" data-theme-value="paper">paper</button>
|
|
199
|
+
</div>
|
|
200
|
+
</details>
|
|
201
|
+
<button type="button" class="anim-toggle" data-anim-toggle aria-pressed="true" title="Toggle animations">
|
|
202
|
+
<span data-anim-box aria-hidden="true">[x]</span>
|
|
203
|
+
<span>anim</span>
|
|
204
|
+
</button>
|
|
205
|
+
</div></nav>
|
|
206
|
+
</header>
|
|
207
|
+
|
|
208
|
+
<main class="wrap" id="top">
|
|
209
|
+
<div class="layout">
|
|
210
|
+
<div class="content">
|
|
211
|
+
<p class="prompt">cat {{FOLDER}}/README.md</p>
|
|
212
|
+
<h1 class="title">{{DOC_TITLE}}</h1>
|
|
213
|
+
<p class="lede">{{TAGLINE}}</p>
|
|
214
|
+
|
|
215
|
+
<!-- one <section> per topic; each id must match a TOC entry. -->
|
|
216
|
+
<section class="doc" id="overview" data-term>
|
|
217
|
+
<p class="prompt">echo overview</p>
|
|
218
|
+
<div class="body" data-term-out>
|
|
219
|
+
<p>{{OVERVIEW}}</p>
|
|
220
|
+
</div>
|
|
221
|
+
</section>
|
|
222
|
+
|
|
223
|
+
<section class="doc" id="steps" data-term>
|
|
224
|
+
<p class="prompt">cat steps.txt</p>
|
|
225
|
+
<div class="body" data-term-out>
|
|
226
|
+
<ol class="steps">
|
|
227
|
+
<li>{{STEP_1}}</li>
|
|
228
|
+
<li>{{STEP_2}}</li>
|
|
229
|
+
</ol>
|
|
230
|
+
</div>
|
|
231
|
+
</section>
|
|
232
|
+
|
|
233
|
+
<!-- Flow diagrams use Mermaid — never hand-drawn ASCII art.
|
|
234
|
+
IMPORTANT: inside a <pre>, write line breaks in node labels as the
|
|
235
|
+
ESCAPED entity <br/>. A raw <br/> would be parsed as an HTML
|
|
236
|
+
element by the browser, and the renderer (which reads textContent)
|
|
237
|
+
would receive a label with the break silently stripped out. -->
|
|
238
|
+
<section class="doc" id="flow" data-term>
|
|
239
|
+
<p class="prompt">cat flow.mmd</p>
|
|
240
|
+
<div class="body" data-term-out>
|
|
241
|
+
<pre class="mermaid">
|
|
242
|
+
flowchart TD
|
|
243
|
+
A["{{FLOW_START}}"] --> B{"{{FLOW_DECISION}}"}
|
|
244
|
+
B -- yes --> C["{{FLOW_YES}}"]
|
|
245
|
+
B -- no --> D["{{FLOW_NO}}"]
|
|
246
|
+
|
|
247
|
+
class D warn
|
|
248
|
+
classDef warn fill:#a02c2c22,stroke:#a02c2c,stroke-width:2px
|
|
249
|
+
</pre>
|
|
250
|
+
</div>
|
|
251
|
+
</section>
|
|
252
|
+
|
|
253
|
+
<section class="doc" id="notes" data-term>
|
|
254
|
+
<p class="prompt">cat notes.md</p>
|
|
255
|
+
<div class="body" data-term-out>
|
|
256
|
+
<p class="eli5"><span class="eli5-term">Note</span> {{NOTES}}</p>
|
|
257
|
+
</div>
|
|
258
|
+
</section>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<aside class="toc">
|
|
262
|
+
<div class="toc-inner">
|
|
263
|
+
<p class="toc-label">On this page</p>
|
|
264
|
+
<nav>
|
|
265
|
+
<a href="#overview" data-toc-link="overview">Overview</a>
|
|
266
|
+
<a href="#steps" data-toc-link="steps">Steps</a>
|
|
267
|
+
<a href="#flow" data-toc-link="flow">Flow</a>
|
|
268
|
+
<a href="#notes" data-toc-link="notes">Notes</a>
|
|
269
|
+
</nav>
|
|
270
|
+
</div>
|
|
271
|
+
</aside>
|
|
272
|
+
</div>
|
|
273
|
+
</main>
|
|
274
|
+
|
|
275
|
+
<footer class="status">
|
|
276
|
+
<!-- bottom-left: [folder] + the doc title -->
|
|
277
|
+
<span class="status-left"><span class="glow">[{{FOLDER}}]</span> {{DOC_TITLE}}</span>
|
|
278
|
+
<!-- bottom-right: danieldeusing.de link + theme (page settings) dropdown -->
|
|
279
|
+
<nav class="status-right">
|
|
280
|
+
<a class="doc-link" href="https://danieldeusing.de">danieldeusing.de</a>
|
|
281
|
+
<span class="sep" aria-hidden="true"></span>
|
|
282
|
+
<details class="dropdown">
|
|
283
|
+
<summary aria-label="theme">
|
|
284
|
+
<svg width="11" height="11" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.5" fill="currentColor"></circle></svg>
|
|
285
|
+
<span data-theme-label>warm</span>
|
|
286
|
+
<span aria-hidden="true">▾</span>
|
|
287
|
+
</summary>
|
|
288
|
+
<ul class="dropdown-panel" role="list">
|
|
289
|
+
<li><button type="button" class="dropdown-item" data-theme-value="warm">warm</button></li>
|
|
290
|
+
<li><button type="button" class="dropdown-item" data-theme-value="green">green</button></li>
|
|
291
|
+
<li><button type="button" class="dropdown-item" data-theme-value="mono">mono</button></li>
|
|
292
|
+
<li><button type="button" class="dropdown-item" data-theme-value="paper">paper</button></li>
|
|
293
|
+
</ul>
|
|
294
|
+
</details>
|
|
295
|
+
<button type="button" class="anim-toggle" data-anim-toggle aria-pressed="true" title="Toggle animations">
|
|
296
|
+
<span data-anim-box aria-hidden="true">[x]</span>
|
|
297
|
+
<span>anim</span>
|
|
298
|
+
</button>
|
|
299
|
+
</nav>
|
|
300
|
+
</footer>
|
|
301
|
+
|
|
302
|
+
<script type="module">
|
|
303
|
+
import { applyStoredTheme, initThemeSwitcher, initDropdowns, initTerminal, initAnimToggle, initBurgerNav } from
|
|
304
|
+
"https://cdn.jsdelivr.net/npm/@danieldeusing/design/runtime/index.js";
|
|
305
|
+
applyStoredTheme();
|
|
306
|
+
initThemeSwitcher();
|
|
307
|
+
initDropdowns();
|
|
308
|
+
initTerminal();
|
|
309
|
+
initAnimToggle();
|
|
310
|
+
initBurgerNav();
|
|
311
|
+
|
|
312
|
+
// Mermaid diagrams — themed from the design tokens, re-rendered on theme switch.
|
|
313
|
+
// Delete this block (and the pre.mermaid CSS) if the page has no diagrams.
|
|
314
|
+
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11.16.0/dist/mermaid.esm.min.mjs";
|
|
315
|
+
|
|
316
|
+
const diagrams = Array.from(document.querySelectorAll("pre.mermaid"));
|
|
317
|
+
if (diagrams.length) {
|
|
318
|
+
// capture the sources before the first render replaces them with SVG
|
|
319
|
+
for (const node of diagrams) node.dataset.mermaidSource = node.textContent;
|
|
320
|
+
|
|
321
|
+
// Renders are serialized: applyStoredTheme() writes data-theme on startup, so an
|
|
322
|
+
// unguarded observer would kick off a second pass while the first is still
|
|
323
|
+
// running — two passes mutating the same nodes stack every diagram into one box.
|
|
324
|
+
let renderPass = 0;
|
|
325
|
+
let pending = Promise.resolve();
|
|
326
|
+
|
|
327
|
+
const renderDiagrams = () => {
|
|
328
|
+
pending = pending.then(async () => {
|
|
329
|
+
const pass = (renderPass += 1);
|
|
330
|
+
const styles = getComputedStyle(document.documentElement);
|
|
331
|
+
const token = (name, fallback) => styles.getPropertyValue(name).trim() || fallback;
|
|
332
|
+
mermaid.initialize({
|
|
333
|
+
startOnLoad: false,
|
|
334
|
+
securityLevel: "strict",
|
|
335
|
+
fontFamily: token("--font-mono", "monospace"),
|
|
336
|
+
flowchart: { htmlLabels: true, useMaxWidth: true },
|
|
337
|
+
themeVariables: {
|
|
338
|
+
background: token("--background", "#f5efe2"),
|
|
339
|
+
primaryColor: token("--card", "#efe7d4"),
|
|
340
|
+
primaryTextColor: token("--foreground", "#43352a"),
|
|
341
|
+
primaryBorderColor: token("--border", "#d9cdb6"),
|
|
342
|
+
secondaryColor: token("--muted", "#ece3cf"),
|
|
343
|
+
tertiaryColor: token("--muted", "#ece3cf"),
|
|
344
|
+
lineColor: token("--muted-foreground", "#71614e"),
|
|
345
|
+
textColor: token("--foreground", "#43352a"),
|
|
346
|
+
mainBkg: token("--card", "#efe7d4"),
|
|
347
|
+
nodeBorder: token("--border", "#d9cdb6"),
|
|
348
|
+
clusterBkg: token("--muted", "#ece3cf"),
|
|
349
|
+
clusterBorder: token("--border", "#d9cdb6"),
|
|
350
|
+
edgeLabelBackground: token("--background", "#f5efe2"),
|
|
351
|
+
titleColor: token("--primary", "#8a4516"),
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
// render ids must be unique per pass, or a re-render collides with itself
|
|
355
|
+
for (const [index, node] of diagrams.entries()) {
|
|
356
|
+
try {
|
|
357
|
+
const { svg } = await mermaid.render(`mermaid-svg-${index}-${pass}`, node.dataset.mermaidSource);
|
|
358
|
+
node.innerHTML = svg;
|
|
359
|
+
node.dataset.processed = "true";
|
|
360
|
+
} catch {
|
|
361
|
+
// a broken diagram falls back to its source — it must never blank the box
|
|
362
|
+
node.textContent = node.dataset.mermaidSource;
|
|
363
|
+
node.removeAttribute("data-processed");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
return pending;
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// Wait for the terminal reveal: a diagram inside a not-yet-revealed
|
|
371
|
+
// [data-term-out] is visibility:hidden, and Mermaid would size it against a
|
|
372
|
+
// container it cannot measure properly. With animation off, render at once.
|
|
373
|
+
if (document.documentElement.classList.contains("anim-off") || window.termContentDone) {
|
|
374
|
+
void renderDiagrams();
|
|
375
|
+
} else {
|
|
376
|
+
window.addEventListener("term:contentdone", () => void renderDiagrams(), { once: true });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// re-render with the new palette, but only when the theme actually changed
|
|
380
|
+
let lastTheme = document.documentElement.dataset.theme;
|
|
381
|
+
new MutationObserver(() => {
|
|
382
|
+
const theme = document.documentElement.dataset.theme;
|
|
383
|
+
if (theme === lastTheme) return;
|
|
384
|
+
lastTheme = theme;
|
|
385
|
+
void renderDiagrams();
|
|
386
|
+
}).observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// table-of-contents scroll-spy: highlight the section currently in view
|
|
390
|
+
const tocLinks = Array.from(document.querySelectorAll("[data-toc-link]"));
|
|
391
|
+
const sections = tocLinks
|
|
392
|
+
.map((link) => document.getElementById(link.dataset.tocLink))
|
|
393
|
+
.filter(Boolean);
|
|
394
|
+
if (sections.length) {
|
|
395
|
+
const setActive = (id) => {
|
|
396
|
+
for (const link of tocLinks) link.classList.toggle("active", link.dataset.tocLink === id);
|
|
397
|
+
};
|
|
398
|
+
const visible = new Set();
|
|
399
|
+
const observer = new IntersectionObserver(
|
|
400
|
+
(entries) => {
|
|
401
|
+
for (const entry of entries) {
|
|
402
|
+
if (entry.isIntersecting) visible.add(entry.target.id);
|
|
403
|
+
else visible.delete(entry.target.id);
|
|
404
|
+
}
|
|
405
|
+
const topmost = sections.find((section) => visible.has(section.id));
|
|
406
|
+
if (topmost) setActive(topmost.id);
|
|
407
|
+
},
|
|
408
|
+
{ rootMargin: "0px 0px -70% 0px" },
|
|
409
|
+
);
|
|
410
|
+
for (const section of sections) observer.observe(section);
|
|
411
|
+
}
|
|
412
|
+
</script>
|
|
413
|
+
</body>
|
|
414
|
+
</html>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
THE STANDARD PAGE CHROME. Copy this; do not re-invent it per surface.
|
|
3
|
+
|
|
4
|
+
Every danieldeusing surface wears the same three pieces, in this order:
|
|
5
|
+
|
|
6
|
+
header.bar brand on the left, the `ls -l` head on the right
|
|
7
|
+
.ls-nav the sticky right RAIL — the site navigation, always the rail,
|
|
8
|
+
never a dropdown
|
|
9
|
+
footer.status fixed, full width, and the home of EVERY control: theme,
|
|
10
|
+
language, animation toggle, links
|
|
11
|
+
|
|
12
|
+
Written down because it drifted. netmon grew its own header with the theme picker
|
|
13
|
+
inside it and no footer at all; the docs pages and danieldeusing.de kept the
|
|
14
|
+
pre-rail dropdown long after cockpit moved on. Each was locally reasonable and the
|
|
15
|
+
estate stopped looking like one thing — which is the entire problem the design
|
|
16
|
+
system exists to prevent. A surface that needs a different arrangement should say
|
|
17
|
+
so here, not solve it privately.
|
|
18
|
+
|
|
19
|
+
── WHY THE RAIL AND NOT A DROPDOWN ──
|
|
20
|
+
A dropdown answers "where can I go?" only while you hold it open, and it covers the
|
|
21
|
+
content you were reading to do it. The rail is the page's table of contents: always
|
|
22
|
+
visible, always in the same place, and hideable when you want the width back (the
|
|
23
|
+
state persists in localStorage under "ls-nav"). It is also why the `ls -l` HEAD sits
|
|
24
|
+
in the header bar rather than in the rail — the toggle must stay put whether the
|
|
25
|
+
rail is open or closed, so opening and closing changes the arrow and nothing else
|
|
26
|
+
moves.
|
|
27
|
+
|
|
28
|
+
── WHY EVERY CONTROL LIVES IN THE FOOTER ──
|
|
29
|
+
The header names the page; the footer operates it. Theme, language and animation are
|
|
30
|
+
session preferences, not navigation, and mixing them into the header put a colour
|
|
31
|
+
picker next to a brand on one surface and nowhere at all on another. One place, on
|
|
32
|
+
every surface, so a reader who has found it once has found it everywhere.
|
|
33
|
+
|
|
34
|
+
── WHAT YOU MUST WIRE UP (the CSS alone is not enough) ──
|
|
35
|
+
1. Pre-paint, INLINE in <head>, before any stylesheet — see the <head> block below.
|
|
36
|
+
Both the theme and the rail state must be applied before first paint, or the page
|
|
37
|
+
visibly flashes the default and jumps.
|
|
38
|
+
2. At the end of <body>, import and call the runtime:
|
|
39
|
+
import { initLsNav, initThemeSwitcher, initDropdowns, initAnimToggle }
|
|
40
|
+
from "@danieldeusing/design/runtime";
|
|
41
|
+
3. `initLsNav()` measures header and footer height and publishes --ls-nav-top /
|
|
42
|
+
--ls-nav-bottom, which is how the rail sits BETWEEN the chrome instead of under
|
|
43
|
+
it. A page with no footer.status still works — it just reserves nothing.
|
|
44
|
+
-->
|
|
45
|
+
|
|
46
|
+
<!-- ─────────────── <head> ─────────────── -->
|
|
47
|
+
<!-- INLINE and FIRST. A module at the end of <body> runs after first paint, so a
|
|
48
|
+
reader who chose "green" or hid the rail would watch the default paint and then
|
|
49
|
+
jump, on every single page load. Both reads are wrapped: a locked-down browser
|
|
50
|
+
throws on localStorage, and a page that cannot remember is still a working page —
|
|
51
|
+
it just starts from the default, which is the right answer when in doubt. -->
|
|
52
|
+
<script>
|
|
53
|
+
(() => {
|
|
54
|
+
try {
|
|
55
|
+
const themes = ["warm", "green", "mono", "paper"];
|
|
56
|
+
const stored = localStorage.getItem("theme");
|
|
57
|
+
if (themes.includes(stored)) document.documentElement.dataset.theme = stored;
|
|
58
|
+
} catch {}
|
|
59
|
+
try {
|
|
60
|
+
if (localStorage.getItem("ls-nav") === "off") document.documentElement.dataset.lsNav = "off";
|
|
61
|
+
} catch {}
|
|
62
|
+
})();
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<!-- ─────────────── header ─────────────── -->
|
|
66
|
+
<header class="bar">
|
|
67
|
+
<a href="/" class="brand"
|
|
68
|
+
><span class="glow">danieldeusing-SURFACE</span><span class="cursor-block" aria-hidden="true"></span
|
|
69
|
+
></a>
|
|
70
|
+
|
|
71
|
+
<button type="button" class="nav-burger" data-nav-toggle aria-label="menu" aria-controls="site-nav" aria-expanded="false">
|
|
72
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M3 12h18"/><path d="M3 18h18"/></svg>
|
|
73
|
+
</button>
|
|
74
|
+
|
|
75
|
+
<nav aria-label="site" id="site-nav" class="site-nav">
|
|
76
|
+
<!-- The head lives in the BAR, the rail hangs below it. Keeping `ls -l` at one
|
|
77
|
+
fixed spot is the point: the toggle is in the same place open or closed. -->
|
|
78
|
+
<div class="ls-nav-head">
|
|
79
|
+
<span class="ls-nav-title prompt">ls -l</span>
|
|
80
|
+
<!-- The guillemet is GENERATED by chrome.css (» open, « closed) — do not type a
|
|
81
|
+
character in here, or it will disagree with the state on the next release. -->
|
|
82
|
+
<button type="button" class="ls-nav-toggle" data-ls-nav-toggle aria-controls="nav"
|
|
83
|
+
aria-expanded="true" aria-label="show or hide navigation" title="show or hide navigation"></button>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="ls-nav" id="nav">
|
|
87
|
+
<ul class="ls-panel" role="list">
|
|
88
|
+
<!-- One <li> per entry. `ls-row--dir` marks a directory (it takes the accent
|
|
89
|
+
and the weight); `ls-row--sub` / `ls-row--sub2` draw the nesting. The
|
|
90
|
+
permission string is decoration that carries meaning: drwxr-xr-x has
|
|
91
|
+
children, -rw-r--r-- does not. -->
|
|
92
|
+
<li><span class="ls-group"># group</span></li>
|
|
93
|
+
<li class="ls-row"><span class="ls-perm">-rw-r--r--</span><a class="ls-name" href="/page">page</a></li>
|
|
94
|
+
<li class="ls-row ls-row--dir"><span class="ls-perm">drwxr-xr-x</span><a class="ls-name" href="/section/">section/</a></li>
|
|
95
|
+
<li class="ls-row ls-row--sub"><span class="ls-perm">-rw-r--r--</span><a class="ls-name" href="/section/child">child</a></li>
|
|
96
|
+
</ul>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<!-- Below 64rem the rail hides and the burger opens this instead. -->
|
|
100
|
+
<ul class="mobile-nav" role="list"></ul>
|
|
101
|
+
</nav>
|
|
102
|
+
</header>
|
|
103
|
+
|
|
104
|
+
<!-- ─────────────── content ─────────────── -->
|
|
105
|
+
<!-- .wrap is the shared column: --content-w wide, --content-pad from the edges. Set
|
|
106
|
+
padding-BLOCK here for the page's own vertical rhythm — never the `padding`
|
|
107
|
+
shorthand, which resets padding-inline and silently drops the shared margin. -->
|
|
108
|
+
<main class="wrap" style="padding-block: 1.1rem 6rem">
|
|
109
|
+
<!-- page content -->
|
|
110
|
+
</main>
|
|
111
|
+
|
|
112
|
+
<!-- ─────────────── footer ─────────────── -->
|
|
113
|
+
<!-- Fixed and full width. It is not "the bottom of the page", it is the control
|
|
114
|
+
surface, so it stays on screen and the rail stops above it. -->
|
|
115
|
+
<footer class="status">
|
|
116
|
+
<span class="status-left"><span class="glow">[surface]</span> what this page is</span>
|
|
117
|
+
|
|
118
|
+
<nav class="status-right">
|
|
119
|
+
<a class="doc-link" href="https://danieldeusing.de">danieldeusing.de</a>
|
|
120
|
+
<span class="sep" aria-hidden="true"></span>
|
|
121
|
+
|
|
122
|
+
<details class="dropdown">
|
|
123
|
+
<summary>
|
|
124
|
+
<span class="visually-hidden">theme </span>
|
|
125
|
+
<svg width="11" height="11" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.5" fill="currentColor"></circle></svg>
|
|
126
|
+
<span data-theme-label>warm</span>
|
|
127
|
+
<span aria-hidden="true">▾</span>
|
|
128
|
+
</summary>
|
|
129
|
+
<ul class="dropdown-panel" role="list">
|
|
130
|
+
<li><button type="button" class="dropdown-item" data-theme-value="warm">warm</button></li>
|
|
131
|
+
<li><button type="button" class="dropdown-item" data-theme-value="green">green</button></li>
|
|
132
|
+
<li><button type="button" class="dropdown-item" data-theme-value="mono">mono</button></li>
|
|
133
|
+
<li><button type="button" class="dropdown-item" data-theme-value="paper">paper</button></li>
|
|
134
|
+
</ul>
|
|
135
|
+
</details>
|
|
136
|
+
|
|
137
|
+
<span class="sep" aria-hidden="true"></span>
|
|
138
|
+
<button type="button" class="anim-toggle" data-anim-toggle aria-pressed="true">[x] anim</button>
|
|
139
|
+
</nav>
|
|
140
|
+
</footer>
|
package/tokens/tokens.json
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
"description": "danieldeusing terminal design tokens, by theme. Generated from src/tokens.css — do not edit by hand.",
|
|
4
4
|
"themes": {
|
|
5
5
|
"warm": {
|
|
6
|
+
"background": "#f5efe2",
|
|
7
|
+
"foreground": "#43352a",
|
|
8
|
+
"card": "#efe7d4",
|
|
9
|
+
"card-foreground": "#43352a",
|
|
10
|
+
"popover": "#efe7d4",
|
|
11
|
+
"popover-foreground": "#43352a",
|
|
12
|
+
"primary": "#8a4516",
|
|
13
|
+
"primary-foreground": "#f8f3e8",
|
|
14
|
+
"secondary": "#ece3cf",
|
|
15
|
+
"secondary-foreground": "#43352a",
|
|
16
|
+
"muted": "#ece3cf",
|
|
17
|
+
"muted-foreground": "#71614e",
|
|
18
|
+
"accent": "#8a4516",
|
|
19
|
+
"accent-foreground": "#f8f3e8",
|
|
20
|
+
"destructive": "#a02c2c",
|
|
21
|
+
"success": "#1a6b2e",
|
|
22
|
+
"warning": "#845600",
|
|
23
|
+
"info": "#1c5f9e",
|
|
24
|
+
"pending": "#5f3dc4",
|
|
25
|
+
"border": "#d9cdb6",
|
|
26
|
+
"input": "#d9cdb6",
|
|
27
|
+
"ring": "#8a4516",
|
|
28
|
+
"glow": "rgba(160, 82, 45, 0.1)",
|
|
29
|
+
"glow-soft": "rgba(160, 82, 45, 0.05)",
|
|
30
|
+
"scanline-opacity": "0.15",
|
|
31
|
+
"radius": "0rem",
|
|
32
|
+
"font-mono": "\"JetBrains Mono Variable\", \"JetBrains Mono\", \"Menlo\", monospace",
|
|
6
33
|
"content-w": "78rem",
|
|
7
34
|
"content-pad": "1.5rem",
|
|
8
35
|
"fs-xs": "0.625rem",
|
|
@@ -33,6 +60,8 @@
|
|
|
33
60
|
"destructive": "#ff5c5c",
|
|
34
61
|
"success": "#4ade80",
|
|
35
62
|
"warning": "#f5b32b",
|
|
63
|
+
"info": "#4dabf7",
|
|
64
|
+
"pending": "#b197fc",
|
|
36
65
|
"border": "#1c4a2c",
|
|
37
66
|
"input": "#1c4a2c",
|
|
38
67
|
"ring": "#33ff66",
|
|
@@ -58,6 +87,8 @@
|
|
|
58
87
|
"destructive": "#ff5c5c",
|
|
59
88
|
"success": "#4ade80",
|
|
60
89
|
"warning": "#f5b32b",
|
|
90
|
+
"info": "#4dabf7",
|
|
91
|
+
"pending": "#b197fc",
|
|
61
92
|
"border": "#333333",
|
|
62
93
|
"input": "#333333",
|
|
63
94
|
"ring": "#ffffff",
|
|
@@ -83,6 +114,8 @@
|
|
|
83
114
|
"destructive": "#b3261e",
|
|
84
115
|
"success": "#1a7031",
|
|
85
116
|
"warning": "#8f5d00",
|
|
117
|
+
"info": "#1c5f9e",
|
|
118
|
+
"pending": "#5f3dc4",
|
|
86
119
|
"border": "#d4d4d4",
|
|
87
120
|
"input": "#d4d4d4",
|
|
88
121
|
"ring": "#000000",
|