Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions demos/textspoiler.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
demo: textspoiler
Kanonisk källa för både live-demot och kodvalvet i index.html.
Bygg: npm run build · Kontroll: npm run build:check
Grupp C: live-markupen och kodvalvet är nu samma markup. Kommentaren nedan
är medvetet filens ANDRA kommentar: den första är den här dokumentationen,
och bara den strippas av bygget. Varningen följer därför med både till
kortet och till den kopierade koden — kodvalvet är det enda stället en
kopierande läsare möter den.
-->
<!-- Suddigheten är bara presentation, texten finns kvar i HTML-källan. Använd aldrig mönstret för hemligheter. -->
<p class="demo-yta" style="font-size:.94rem; color:var(--dim);">Filmslutet: <span class="spoiler" tabindex="0" aria-label="Spoiler, fokusera eller hovra för att avslöja"><span>hunden överlever</span></span></p>
<style>
.spoiler {
display: inline-block; padding: .05em .4em; border-radius: 4px; background: var(--ink); color: transparent;
cursor: pointer; user-select: none; overflow: hidden;
}
.spoiler span { display: inline-block; filter: blur(6px); transition: filter .25s ease; }
.spoiler:hover, .spoiler:focus-visible { background: var(--acc-soft); color: var(--ink); }
.spoiler:hover span, .spoiler:focus-visible span { filter: blur(0); }
</style>
111 changes: 111 additions & 0 deletions docs/demo-kalla.md
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,117 @@ kort för kort:
lättare, att underhålla. Alternativ: låt live-versionen bli den förenklade
(det är oftast `media-*`-proven som har extra scenografi).

#### Utredningen (2026-09-26) och beslutet

*Status: piloten avgjord. **En** av de sju är migrerad — `textspoiler`. De
övriga sex är medvetet kvar och skälen nedan är mätta, inte gissade.*

Varje demo undersöktes maskinellt och i webbläsare **innan** något ändrades:

1. jämfördes kodvalvets HTML-del med live-markupen rad för rad,
2. jämfördes kodvalvets CSS med stilbladet regel för regel (normaliserat),
3. räknades vilka klasser som finns i *live*-markupen och vilka som bara finns
i stilbladet eller bara i valvet — `.nd-*` är ett valv-namnrum, så lika
selektorer bevisar ingenting om lika innehåll,
4. mättes vilka CSS-regler fler än ett kort använder, eftersom en delad regel
inte kan flyttas in i en källa utan att dupliceras i stilbladet (och
`scripts/build.test.mjs` §3 faller på exakt det).

Resultatet delar de sju i två grupper.

**A. Valvet är en egen, påhittad variant (`.nd-*`), och dess CSS finns bara i
valvet.** Fyra demos: `media-color-gamut` (`.nd-gamut`), `round-mod`
(`.nd-math`), `media-scripting` (`.nd-script`) och `media-hover-pointer`
(`.nd-pek`). Klassen förekommer **noll** gånger i live-markupen — reglerna
renderas alltså ingenstans på sidan. Det pedagogiska innehållet är samtidigt
svagare än live-kortets: valvet visar en enda statisk rad där kortet visar
frågans alla svar med den aktuella enhetens svar markerat (`.prov-rad` +
"ditt läge"). För `round-mod` är skillnaden större än så: live-kortet har ett
reglage (`.labb-steg` med `--lv`) och en auto-kryssruta, valvet två statiska
staplar — två olika implementationer, inte två varianter av samma.

**B. Valvet återanvänder live-klasser.** Tre demos: `textspoiler`
(`.spoiler`), `prefers-reduced-motion` och `hover-hover` (båda `.media-list`).

| Demo | Live-markup | Valvets markup | Vad som skiljer | Varför den blev kvar |
| ---- | ----------- | -------------- | --------------- | -------------------- |
| `textspoiler` | `.spoiler` i en `<p class="demo-yta">` | **samma markup** | bara varningskommentaren, som bara stod i valvet | — (migrerad, se nedan) |
| `prefers-reduced-motion` | `.prov.prov-rm` (två rader) + `.rm-prov`/`.rm-snurra` med `@keyframes rm-rot` | `.media-list`-enradare | hela implementationen | Live-kortets poäng är att *hela sidan* lyder flaggan; enradaren tappar snurran. `.media-list` används dessutom av `prefers-color-scheme` och `min-width-640px` (se §6b) — flyttas den hit dupliceras den i stilbladet |
| `hover-hover` | `.prov.prov-hover` + `.hover-prov` (en yta man känner på) | `.media-list`-enradare | hela implementationen | Samma skäl; `.prov-hover`-raderna används också av `media-hover-pointer` |
| `media-color-gamut` | `.prov.prov-gamut`, två `.prov-rad` | `.nd-gamut`, två `<span>` | både markup och CSS | Live-varianten är bättre men `.prov`/`.prov-rad` (6 regler) delas av fem kort → ägarlöst delat block, se nedan |
| `media-scripting` | `.prov.prov-script`, två `.prov-rad` | `.nd-script`, två `<span>` | både markup och CSS | Samma: `.prov`-familjen plus två aktiveringsregler som bara gäller detta kort |
| `media-hover-pointer` | `.prov.prov-pekare` (tre rader) + `.prov.prov-hover` | `.nd-pek`, två `<span>` | både markup och CSS | Samma blockerare; dessutom två frågor i ett kort |

**Blockeraren för grupp A är inte källformatet utan en ägarfråga.**
`.prov`-familjen (stilbladets rad 545–579: sju basregler — `.prov`,
`.prov-rad`, `.prov-rad::before`, `.prov-rad.pa`, `.prov-rad.pa::before`,
`.prov-rad b`, `.prov-rad.pa b` — och elva `@media`-block med tre regler var,
ett per svar på frågorna korten ställer) används av fem kort. Att migrera till exempel
`media-color-gamut` kräver att antingen familjen flyttas in i källan — då står
samma regler två gånger i stilbladet och byggtestet fäller — eller att den
ligger kvar som sidscenografi i `<style data-live>`, men då får den kopierade
koden ingen stil alls och slutar vara ett fungerande exempel. Det är samma
beslut som redan är noterat för `radioflikar` i §6b ("delat labb-block, ingen
ägare"), nu med mätt konsumentlista. Nästa steg för de demos är alltså ett
beslut om `.prov`-familjen (sannolikt `<style data-include="prov">`, precis
som Grupp B gjorde med `swatch`), inte en ändring av källformatet.

**Beslut: PATH A — formatet räcker, och exakt en demo migreras.**
`textspoiler` var den enda av de sju där live-markupen och valvets markup var
identisk; den enda skillnaden var en varningskommentar som bara fanns i valvet.
Källformatet kan uttrycka den utan utbyggnad: `parseSource` strippar bara
**första** ledande kommentaren, så dokumentationshuvudet försvinner medan en
kommentar som står efter det följer med i både live-markupen och kopian.
Kodvalvet har därför blivit ett komplett, fristående exempel vars enda skillnad
mot förut är att CSS:en står precis som i stilbladet i stället för
ihopkomprimerad — och varningen står kvar.

Migreringen (filerna: `demos/textspoiler.html`, `scripts/demo-spec.mjs`,
`tests/demo-scenarios.mjs`, `tests/demo-source.mjs`,
`scripts/check.test.mjs`, `tests/baseline/demos.json`, `index.html`):

- **Live-ytan är pixelidentisk.** Skärmbilder av `#textspoiler .demo-yta` i
vila och i avslöjat läge är **byte-identiska** före och efter
(`sha256 be689d98…` respektive `687e101d…`).
- **Pariteten är exakt.** 534 värden jämförda mot baslinjen, 0 strukturella
avvikelser, **0 px** geometriavvikelse. Baslinjeposten fångades med
`--capture --merge --demo textspoiler` **före** migreringen ur dokumentet med
sha256 `2d2e2a5e…` (Chromium `153.0.8010.0`, samma som baslinjens); de 30
historiska posterna och hela `mergeLog` är orörda (diffen är 617 tillagda
rader, 0 borttagna).
- **Inga nya toleranser.** Antalet textmetrikvarningar varierar mellan
körningar även för ett och samma dokument (7 i den inledande kontrollkörningen
av orörd `main`, 19 i körningarna nedan), så jämförelsen gjordes mellan
före- och efterdokumentet i samma körning: **avvikelselistorna är
identiska** — samma 19 värden, samma demos, samma tal (störst 21,74 px i
`target`). Ingen post lades till i `INTENTIONAL_DIFFS`, ingen tolerans
ändrades.
- **Regressionsskydd.** `textspoiler` har fått ett scenario
(`tests/demo-scenarios.mjs`) och 21 påståenden i `tests/demo-source.mjs` som
prövar både sidan och den fristående kopian: suddigheten, den genomskinliga
texten, `tabindex`/`aria-label`, hover som avslöjar, `:focus-visible` via
riktigt tangentbordsfokus, fokusringen, att kopian bär exakt demots fyra
regler, att alla `var()` löses upp mot Grundpaketet, att kopians enda
tab-stopp är partiet, och att varningskommentaren följer med i kopian.
`scripts/check.test.mjs` negativtest för obalanserade klammerblock pekade på
valvets gamla ihopkomprimerade text och pekar nu på den nya (samma mutation,
samma förväntade fel).

**Varför inte fler.** `prefers-reduced-motion` och `hover-hover` har två
genuint olika implementationer (interaktiv snurra/yta mot en enradare), och
deras valv använder `.media-list`, som i live-markupen tillhör två andra,
omigrerade kort (`prefers-color-scheme`, `min-width-640px`) — de hör till
gruppmigreringen i §6b, inte hit. `round-mod` har samma sak plus ett reglage. De tre kvarvarande
`.prov`-korten är pedagogiskt bättre live men blockerade av `.prov`-familjens
ägarlöshet. Att tvinga in någon av dem nu hade antingen duplicerat delade
regler i stilbladet eller tömt ett fungerande exempel på innehåll — båda
sämre än att låta dem stå.

**Medvetet inte gjort.** Ingen utbyggnad av källformatet (ingen andra
markup-variant, inget nytt attribut). Den översta statusraden i det här
dokumentet och räknarna i §7 är historiska och står kvar oförändrade; det
aktuella antalet är **31 av 133** migrerade demos.

### Grupp D — stora, sammansatta demos (≈20: `property-sin-cos` (49 regler), `view-timeline` (39), `tre-i-rad-tic-tac-toe`, `css-arkad`, `4-bitars-binaradderare`, `flerstegs-formular-wizard`, `fore-efter-jamforare`, `dialog-commandfor`, `3d-card-tilt` …)

Formeln gäller, men källfilerna blir 100–400 rader och CSS:en ligger ofta i
Expand Down
19 changes: 13 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2223,13 +2223,15 @@
}
@keyframes skimra { to { --shimmer-x: 150%; } }

/* demo:textspoiler:css */
.spoiler {
display: inline-block; padding: .05em .4em; border-radius: 4px; background: var(--ink); color: transparent;
cursor: pointer; user-select: none; overflow: hidden;
}
.spoiler span { display: inline-block; filter: blur(6px); transition: filter .25s ease; }
.spoiler:hover, .spoiler:focus-visible { background: var(--acc-soft); color: var(--ink); }
.spoiler:hover span, .spoiler:focus-visible span { filter: blur(0); }
/* /demo:textspoiler:css */

.roll-link { display: inline-flex; perspective: 500px; font-family: var(--disp); font-weight: 700; font-size: 1.6rem; cursor: default; }
.roll-char { position: relative; display: inline-block; transform-style: preserve-3d; transition: transform .3s cubic-bezier(.2,.8,.2,1); transition-delay: calc(var(--i, 0) * 35ms); }
Expand Down Expand Up @@ -9647,20 +9649,25 @@ <h3 class="demo-titel">Textspoiler <span class="stod">— filter: blur() + fokus
<line x1="60" y1="15" x2="100" y2="15" class="strk" marker-end="url(#pil)" />
<text x="130" y="20" text-anchor="middle" font-family="var(--mono)" font-size="9" class="acc">spoiler!</text></svg>
<p class="fig-cap">filter: blur(6px) → blur(0) vid :hover/:focus-visible.</p></div>
<!-- demo:textspoiler:markup -->
<!-- Suddigheten är bara presentation, texten finns kvar i HTML-källan. Använd aldrig mönstret för hemligheter. -->
<p class="demo-yta" style="font-size:.94rem; color:var(--dim);">Filmslutet: <span class="spoiler" tabindex="0" aria-label="Spoiler, fokusera eller hovra för att avslöja"><span>hunden överlever</span></span></p>
<!-- /demo:textspoiler:markup -->
<p class="labb-hint">Suddigheten är bara presentation — texten finns fortfarande i HTML-källan. CSS är <b>inte</b> åtkomstkontroll, så använd aldrig mönstret för hemligheter.</p>
<details class="kod-valv"><summary><span class="kod-hint">klicka i rutan → ⌘C / Ctrl+C</span></summary><textarea class="kod" readonly spellcheck="false" rows="11" aria-label="Kod för Textspoiler — filter: blur() + fokus">&lt;!-- HTML --&gt;
<details class="kod-valv"><summary><span class="kod-hint">klicka i rutan → ⌘C / Ctrl+C</span></summary><textarea class="kod" readonly spellcheck="false" rows="14" aria-label="Kod för Textspoiler — filter: blur() + fokus">&lt;!-- HTML --&gt;
&lt;!-- Suddigheten är bara presentation, texten finns kvar i HTML-källan. Använd aldrig mönstret för hemligheter. --&gt;
&lt;p class="demo-yta" style="font-size:.94rem; color:var(--dim);"&gt;Filmslutet: &lt;span class="spoiler" tabindex="0" aria-label="Spoiler, fokusera eller hovra för att avslöja"&gt;&lt;span&gt;hunden överlever&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

/* CSS */

.demo-yta {position: relative; border-radius: 4px;}
.spoiler {display: inline-block; padding: .05em .4em; border-radius: 4px; background: var(--ink); color: transparent;
cursor: pointer; user-select: none; overflow: hidden;}
.spoiler span {display: inline-block; filter: blur(6px); transition: filter .25s ease;}
.spoiler:hover, .spoiler:focus-visible {background: var(--acc-soft); color: var(--ink);}
.spoiler:hover span, .spoiler:focus-visible span {filter: blur(0);}</textarea></details>
.spoiler {
display: inline-block; padding: .05em .4em; border-radius: 4px; background: var(--ink); color: transparent;
cursor: pointer; user-select: none; overflow: hidden;
}
.spoiler span { display: inline-block; filter: blur(6px); transition: filter .25s ease; }
.spoiler:hover, .spoiler:focus-visible { background: var(--acc-soft); color: var(--ink); }
.spoiler:hover span, .spoiler:focus-visible span { filter: blur(0); }</textarea></details>
<!-- demo-ctx:textspoiler --><p class="demo-ctx"><a class="ctx-kap" href="#typografi">Kapitel 07 · Typografi</a><span class="ctx-sep" aria-hidden="true">·</span><a class="ctx-reg" href="#reg-t">I registret: T</a></p><!-- /demo-ctx:textspoiler -->
</article>

Expand Down
8 changes: 5 additions & 3 deletions scripts/check.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,12 @@ expectCaught(

expectCaught(
'obalanserade CSS-klammerblock i snippet upptäcks',
// </textarea>-suffixet gör att mutationen träffar kodvalvet, inte live-CSS:en
// </textarea>-suffixet gör att mutationen träffar kodvalvet, inte live-CSS:en.
// Strängen är kodvalvet för textspoiler, som sedan Grupp C-piloten är
// ordagrant samma CSS som stilbladet (därav mellanslagen i klammerparen).
(h) => h.replace(
'.spoiler:hover span, .spoiler:focus-visible span {filter: blur(0);}</textarea>',
'.spoiler:hover span, .spoiler:focus-visible span filter: blur(0);}</textarea>',
'.spoiler:hover span, .spoiler:focus-visible span { filter: blur(0); }</textarea>',
'.spoiler:hover span, .spoiler:focus-visible span filter: blur(0); }</textarea>',
1,
),
checkSnippets,
Expand Down
10 changes: 8 additions & 2 deletions scripts/demo-spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
*
* Fält:
* id demots id i index.html (och filnamnet i demos/)
* type 'pilot' (första tre), 'batch-1' (Grupp A), 'batch-2' (Grupp B-pilot)
* eller 'batch-3'/'batch-4' (fortsättning av Grupp B)
* type 'pilot' (första tre), 'batch-1' (Grupp A), 'batch-2' (Grupp B-pilot),
* 'batch-3'…'batch-5' (fortsättning av Grupp B) eller 'grupp-c'
* (Grupp C-piloten; valvet skiljde sig från live-markupen)
* anchors id:n i demots markup som interna länkar pekar på (dokumenteras
* för läsbarhet; byggtestet härleder dem ur källfilen)
* liveCss true om källfilen har <style data-live> (sidans scenografi som
Expand Down Expand Up @@ -233,6 +234,11 @@ export const DEMO_SPEC = [
shared: ['swatch', 'swatch-solo', 'filter-motiv'],
note: 'Grupp B: motivet delas; .f-drop är bara sin egen filter-deklaration (drop-shadow + brightness), labbets --lv-skala är live-only',
},
{
id: 'textspoiler', type: 'grupp-c', anchors: [], liveCss: false,
shared: [],
note: 'Grupp C: live-markupen och kodvalvet var samma markup; bara demots varningskommentar skiljde. Den ligger i källans markup (filens andra kommentar) och följer därför med till både kortet och kopian. .spoiler-reglerna ägs av demot och används av exakt ett kort',
},
];

/** Alla migrerade id:n, i manifestets ordning. */
Expand Down
Loading
Loading