forked from yvv/decision
Fusion de chantier/acte-certification dans lot/s-seed (lot H : l'accueil sous la voûte)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,49 @@ fusionnés (B2, F, D), puis `4d4adcc` (mineurs de la relecture de F) ; boucle ve
|
||||
- **F1.2, N1, N1.1, O1** réécrits (amendement de seed sur une proposition ouverte) ;
|
||||
- **licence** AGPL-3.0 (`76b8e9f`).
|
||||
|
||||
**Revue d'Yvv du 02/11 (ergonomie, Propositions seed, tampon des votes, accueil)**, armée d'avance par
|
||||
« Et pousse. Déploie. ». Décisions d'Yvv du 02/11, de 06 h 26 à 07 h 05 (registre) :
|
||||
- Propositions seed au **cran 2** ;
|
||||
- **C devient un quorum** de votants par cran : 12 · 12 · 50 · 50 · 50 en Monnaie libre, 1 à
|
||||
l'essai. Au-delà, la proportion suit la courbe des cinq crans. L'auteur initial change le quorum
|
||||
de son article avant le premier vote ;
|
||||
- l'écran dit, sans prendre de place, combien de « oui » font passer et combien de « non »
|
||||
bloquent ;
|
||||
- un vote simulé compte, puis s'efface à l'ouverture de la chaîne (acte « supprime ») ;
|
||||
- la publication est suspendue jusqu'au premier texte en vigueur.
|
||||
|
||||
**Relève d'orch le 03/11 à 03 h 38**, sur ordre d'orch racine (dev-63). La session d'avant était
|
||||
bloquée par le quota depuis le 02/11 à 09 h 51, puis coupée par le redémarrage du poste à 02 h 56.
|
||||
Les quatre agents sont morts, leurs copies sont intactes, `/tmp` est vidé (captures et bases de
|
||||
test perdues). Budget : finir S, U, V et H, sans nouveau lot, **un sous-agent à la fois** (compte
|
||||
partagé avec HCO, qui passe en premier). **Pas de mandat** : M6 attend le « déploie » d'Yvv tapé
|
||||
dans cette session (le « Pousse. Déploie. » du 02/11 a été dit à une autre session).
|
||||
|
||||
Ordre de reprise : H, puis S, puis V, puis U. Chaque lot fusionne d'abord le chantier, qui contient
|
||||
déjà les lots finis. Le contrat du quorum vient de S et sert V et U.
|
||||
|
||||
Lots en cours, en copies de travail (`.claude/worktrees/agent-<id>`) :
|
||||
- **H** (`a6b179c…`, `lot/h-accueil`) : l'accueil. **Fini et fusionné** le 03/11 à 04 h 03
|
||||
(`a3c0a76`). Boucle verte dans sa copie : 237 tests Rust, 55 vitest, e2e 35 / 35. À faire voir
|
||||
à Yvv : le titre anglais devient « Making it possible / to decide together » ; les trois points
|
||||
font 12 px à 360 de large.
|
||||
- **S** (`a0b2510…`, `lot/s-seed`) : I1, E1 et E2 deviennent des « Propositions seed », pas en
|
||||
vigueur, au cran 2 ; la publication suspendue (ADR 0011, migration 0009). WIP `6228d39` + 14
|
||||
fichiers (tests en reprise). Phase 2 : le quorum, ADR 0013, migration 0011,
|
||||
`PUT /units/{id}/quorum`, champs `quorum`, `yesNeeded` et `noNeeded`. Phase 3 : la licence
|
||||
`AGPL-3.0-or-later`. **Relancé le 03/11 à 04 h 05.**
|
||||
- **V** (`a78bacc…`, `lot/v-tampon`) : le tampon entre la base des votes et les indexeurs ; « je
|
||||
vois ce que j'ai fait sans attendre » ; contrôle a posteriori (unique, le dernier qui vaut) ; vote
|
||||
simulé partout tant que la chaîne est fermée, qui compte, puis s'efface par un acte « supprime ».
|
||||
ADR 0012 et moteur commités (`e7dda2f`, `ee37c3b`) ; serveur, migration 0010 et tests non
|
||||
commités (16 fichiers). En attente de S.
|
||||
- **U** (`adddf06…`, `lot/u-lecteur`) : le lecteur. Page courte ; ordonnancement par poignées en
|
||||
fin de section ; trois natures de modules ; consoles sans doublon ; déplier ou panneau, une règle ;
|
||||
la ligne oui / non et le réglage du quorum. Note `UX-lecteur.md` commitée (`d4531da`), 4 fichiers
|
||||
commencés. En attente de V.
|
||||
|
||||
Puis : boucle sur le chantier, relecture indépendante, répétition, dossier d'acte M6, PRÊT.
|
||||
|
||||
Yvv relit les quatre textes en ligne. Au prochain tour, avec ses retours :
|
||||
- N1.1 : G se calcule sur p̃ rapporté à W ;
|
||||
- étendre la garde de l'amendement à un texte déjà amendé.
|
||||
@@ -51,7 +94,9 @@ Ce qu'Yvv doit fournir :
|
||||
| L12 | Objections « redit » et « contredit » : la plus récente des deux propositions n'est pas votable tant que son auteur n'a pas répondu (redit : modifier l'article visé ; contredit : reformuler) ; un message à l'auteur de l'objection dans trustinWallet : lever ou réitérer ; sans réponse sous 3 jours, l'objection est levée. | F | M4 |
|
||||
| L13 | Coquilles : celle d'un autre que l'auteur attend sa validation (message), puis passe seule après 3 jours ; l'auteur garde la main tant que le texte n'est pas en vigueur ; sur un texte en vigueur, seule une coquille validée le corrige. | F | M4 |
|
||||
|
||||
**Liste d'attente** (hors livraison, sauf mot d'Yvv) : l'inscription de chaque vote sur la
|
||||
**Liste d'attente** (hors livraison, sauf mot d'Yvv) : au bureau, le bas du menu latéral (pastilles
|
||||
d'ambiance, « Se connecter ») est rogné au bord droit ; sur téléphone avec session, le sceau fixe
|
||||
chevauche la flèche d'une carte de groupe (vus par le lot H le 03/11, pas comparés à `5cf30e0`) ; l'inscription de chaque vote sur la
|
||||
chaîne (question stratégique, `docs/recherche/vote-g1-chaine.md`) ; l'affichage dans Ğecko.
|
||||
|
||||
## Lots
|
||||
@@ -78,6 +123,8 @@ chaîne (question stratégique, `docs/recherche/vote-g1-chaine.md`) ; l'affichag
|
||||
| Q6 | Ğ1Companion ne signe pas encore une transaction construite par une page : quelle extension pour le geste unique ? | **tranché** (01/11) : duniter-connect maintenant ; Ğ1Companion et trustinWallet sur la même interface ; Ğecko par lien et QR |
|
||||
| Q7 | Le compte qui reçoit les 0,1 Ğ1 : à qui, et que deviennent les sommes ? | **tranché** (01/11) : un compte « libreDecision » créé par Yvv dans Ğecko, les sommes au collectif ; attend son adresse publique |
|
||||
| Q8 | Le secret du vote tombe par recoupement : la chaîne montre qui vient de voter, et les totaux bougent aussitôt (relecture de `74f96be`) | **tranché** (01/11) : on ne dit rien ; totaux et son propre vote en direct, inchangés |
|
||||
| Q9 | Sous le quorum, les votants qui manquent comptent-ils comme des « non » ? (Sinon, un « non » peut faire passer un texte en complétant le quorum.) | **tranché** (03/11, formulaire d'orch racine vers 03 h 45) : « Ils comptent comme non » ; au cran 2, quorum 12, 9 oui passent avec 3 non au plus |
|
||||
| Q10 | Licence : AGPL-3.0 seulement, ou « ou toute version ultérieure » ? | **tranché** (03/11, même formulaire) : « Ou version ultérieure » → `AGPL-3.0-or-later` dans les manifestes (`Cargo.toml`, `web/package.json` et son verrou) et le README ; `LICENSE` inchangé ; confié au lot S |
|
||||
|
||||
Défauts posés par orch, sans question (Yvv peut les corriger) :
|
||||
- Décisions : « modules restant à voter » = les modules du doc pas encore adoptés par un vote
|
||||
@@ -106,15 +153,5 @@ Liste d'attente (relecture de `033b331+4d4adcc`, après M4) :
|
||||
- `place_at_end` coupe toujours le même intervalle : au 52e ajout dans une section, les positions se confondent ;
|
||||
- `publish.rs` : articles sur `tally`, modules sur `shown_tally` (identiques aujourd'hui).
|
||||
|
||||
À dire à Yvv : dans le groupe d'essai (C = 1), dès 16 membres une voix seule fait passer un texte,
|
||||
la garde B^W passant sous la précision du calcul (ADR 0007). Monnaie libre (C = 50) n'est pas
|
||||
concernée. Pour deux voix dans l'essai quel que soit W : C = 2.
|
||||
|
||||
À demander à Yvv (relecture de `cd7e683`) : sur une version retenue par une objection, ni retirer
|
||||
son vote ni passer à « contre » ; à la levée, l'adoption tourne aussitôt. Le garder, ou permettre de
|
||||
retirer son vote et de voter « contre » sur une version retenue ? Défaut : tel quel (ADR 0010).
|
||||
|
||||
Ensuite : Chaque mise en ligne (M1 à M4) attend « déploie » d'Yvv et une relecture
|
||||
indépendante inscrite. La migration « Raison d'être » touche la base de production : elle ne
|
||||
remplace le Préambule que s'il est intact (texte de départ, 0 vote, aucune correction), et le
|
||||
dossier d'acte de M1 le dit.
|
||||
Chaque mise en ligne attend « déploie » d'Yvv, ou le mandat d'orch, et une relecture indépendante
|
||||
inscrite.
|
||||
|
||||
+72
-1
@@ -1,4 +1,4 @@
|
||||
import type { Browser, Page } from '@playwright/test';
|
||||
import { expect, type Browser, type Page } from '@playwright/test';
|
||||
|
||||
export const DOC = '/g/monnaie-libre/docs/acte-engagement-certification';
|
||||
export const TEST_DOC = '/g/essai/docs/acte-engagement-certification';
|
||||
@@ -138,3 +138,74 @@ export async function chain(page: Page, docPath = DOC) {
|
||||
(await page.request.post(`${base}/control/${what}`)).json(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The welcome (Yvv, 2026-11-02), in French: the keystone arch shelters the three points, the
|
||||
* toolbox first, each centred under the keystone in the opening; then the title, centred, on
|
||||
* two lines broken after « possible ». Nothing tilted, nothing past the edges of the screen.
|
||||
* Measured once the arch has settled (its entrance done).
|
||||
*/
|
||||
export async function expectWelcome(page: Page) {
|
||||
await expect(page.locator('.vault .leitmotiv li')).toHaveText(['boîte à outils', 'contexte et cadrage', 'processus et modalités']);
|
||||
const h1 = page.getByRole('heading', { level: 1 });
|
||||
await expect(h1).toHaveText('Rendre possible la décision collective');
|
||||
await expect(h1.locator('.line')).toHaveText(['Rendre possible', 'la décision collective']);
|
||||
const m = await page.evaluate(async () => {
|
||||
const intro = document.querySelector('.intro')!;
|
||||
await Promise.all(intro.getAnimations({ subtree: true }).map((a) => a.finished));
|
||||
const text = (el: Element) => {
|
||||
const r = document.createRange();
|
||||
r.selectNodeContents(el);
|
||||
return { box: r.getBoundingClientRect(), rects: r.getClientRects().length };
|
||||
};
|
||||
const v = document.querySelector('.vault')!.getBoundingClientRect();
|
||||
// The arch in its own units: 92 wide (x from −46), the top of the keystone at y = −40.
|
||||
const u = v.width / 92;
|
||||
const at = (x: number, y: number) => ({ x: v.left + (x + 46) * u, y: v.top + (y + 40) * u });
|
||||
const points = [...document.querySelectorAll('.leitmotiv li')].map((li) => {
|
||||
const { box, rects } = text(li);
|
||||
// Back into the arch's units, from its axis and its springing line (y = 0).
|
||||
return { rects, left: (box.left - at(0, 0).x) / u, right: (box.right - at(0, 0).x) / u, top: (box.top - at(0, 0).y) / u, bottom: (box.bottom - at(0, 0).y) / u };
|
||||
});
|
||||
const h = document.querySelector('h1')!.getBoundingClientRect();
|
||||
const lines = [...document.querySelectorAll('h1 .line')].map((l) => ({ ...text(l), block: l.getBoundingClientRect() }));
|
||||
const tilted = [document.querySelector('.vault svg')!, ...document.querySelectorAll('.vault svg path')]
|
||||
.flatMap((n) => {
|
||||
const out: string[] = [];
|
||||
for (let e: Element | null = n; e && e !== document.body; e = e.parentElement) {
|
||||
const cs = getComputedStyle(e);
|
||||
const flat = cs.transform === 'none' || /^matrix\(1, 0, 0, 1, /.test(cs.transform);
|
||||
if (!flat || (cs.rotate && cs.rotate !== 'none')) out.push(`${e.tagName} ${cs.transform} ${cs.rotate}`);
|
||||
}
|
||||
return out;
|
||||
});
|
||||
return {
|
||||
overflow: document.documentElement.scrollWidth - innerWidth,
|
||||
axis: v.left + v.width / 2,
|
||||
vaultBottom: v.bottom,
|
||||
points,
|
||||
title: { top: h.top, axis: h.left + h.width / 2 },
|
||||
lines: lines.map(({ box, rects, block }) => ({ rects, top: block.top, bottom: block.bottom, axis: box.left + box.width / 2 })),
|
||||
tilted,
|
||||
};
|
||||
});
|
||||
expect(m.overflow, 'nothing past the edge of the screen').toBeLessThanOrEqual(0);
|
||||
expect(m.tilted, 'the arch is never tilted').toEqual([]);
|
||||
// The three points: one line each, top to bottom, centred on the axis, under the keystone (its
|
||||
// foot at y = −19), between the imposts (x = ±19) and above the slab (y = 15.6); a line that
|
||||
// rises above the springing line stays clear of the voussoirs, closer in there (x = ±17).
|
||||
for (const [i, p] of m.points.entries()) {
|
||||
expect(p.rects, `point ${i}: one line`).toBe(1);
|
||||
expect(Math.abs((p.left + p.right) / 2), `point ${i}: centred`).toBeLessThan(0.3);
|
||||
expect(p.top, `point ${i}: under the keystone`).toBeGreaterThan(-19);
|
||||
expect(p.bottom, `point ${i}: above the slab`).toBeLessThan(15.6);
|
||||
expect(p.right, `point ${i}: in the opening`).toBeLessThan(p.top < 0 ? 17 : 19);
|
||||
if (i > 0) expect(p.top, `point ${i}: under the one before`).toBeGreaterThan(m.points[i - 1]!.top);
|
||||
}
|
||||
// The title: under the arch, centred on its axis, two lines of one line each.
|
||||
expect(m.title.top).toBeGreaterThanOrEqual(m.vaultBottom);
|
||||
expect(Math.abs(m.title.axis - m.axis)).toBeLessThan(1);
|
||||
expect(m.lines.map((l) => l.rects)).toEqual([1, 1]);
|
||||
expect(m.lines[1]!.top).toBeGreaterThanOrEqual(m.lines[0]!.bottom - 1);
|
||||
for (const l of m.lines) expect(Math.abs(l.axis - m.axis)).toBeLessThan(1);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { expect, test, type Locator } from '@playwright/test';
|
||||
import { DOC, shot, signIn } from './helpers';
|
||||
import { DOC, expectWelcome, shot, signIn } from './helpers';
|
||||
|
||||
/** WCAG contrast ratio of two CSS colours `rgb(r, g, b)`. */
|
||||
function contrast(a: string, b: string): number {
|
||||
@@ -25,13 +25,19 @@ async function backdrop(el: Locator): Promise<string> {
|
||||
});
|
||||
}
|
||||
|
||||
test('M1 — mobile : logo dans la barre, menu en tiroir, vote déplié, panier, réglages lisibles, pastilles au clavier', async ({ page }) => {
|
||||
test('M1 — mobile : logo dans la barre, l’accueil sous la voûte, menu en tiroir, vote déplié, panier, réglages lisibles, pastilles au clavier', async ({ page }) => {
|
||||
await signIn(page, 'Chiara');
|
||||
await page.goto('/');
|
||||
const brand = page.locator('header.topbar a.brand');
|
||||
await expect(brand).toHaveAccessibleName('libreDecision');
|
||||
await expect(brand.locator('svg')).toBeVisible();
|
||||
await expect(page.locator('a.root')).toContainText('Monnaie libre');
|
||||
// The welcome on this phone, then on a narrow one (360): the arch still shelters the three points.
|
||||
await expectWelcome(page);
|
||||
const size = page.viewportSize();
|
||||
await page.setViewportSize({ width: 360, height: 780 });
|
||||
await expectWelcome(page);
|
||||
if (size) await page.setViewportSize(size);
|
||||
await page.goto(DOC);
|
||||
await page.getByRole('button', { name: 'Menu' }).click();
|
||||
const drawer = page.getByRole('dialog', { name: 'Boîte à outils' });
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { BOB, DOC, person, signIn, TEST_DOC, wallet } from './helpers';
|
||||
import { BOB, DOC, expectWelcome, person, signIn, TEST_DOC, wallet } from './helpers';
|
||||
|
||||
test('C1 — l’accueil sans session : le titre, le leitmotiv en trois lignes, la connexion, le menu complet', async ({ page }) => {
|
||||
test('C1 — l’accueil sans session : la voûte abrite les trois points, le titre centré en deux lignes, la connexion, le menu complet', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Rendre possible la décision collective');
|
||||
await expect(page.locator('.leitmotiv li')).toHaveText(['contexte et cadrage', 'processus et modalités', 'boîte à outils']);
|
||||
await expectWelcome(page);
|
||||
const nav = page.getByRole('navigation', { name: 'Boîte à outils' });
|
||||
for (const item of ['Décisions', 'Docs de référence', 'Mandats', 'Protocoles']) {
|
||||
await expect(nav.locator('.tool', { hasText: item })).toBeVisible();
|
||||
|
||||
@@ -30,7 +30,8 @@ export const en: Messages = {
|
||||
'nav.menu': 'Menu',
|
||||
'nav.close': 'Close',
|
||||
|
||||
'home.title': 'Making collective decisions possible',
|
||||
'home.title.line1': 'Making it possible',
|
||||
'home.title.line2': 'to decide together',
|
||||
'home.leitmotiv.context': 'context and framing',
|
||||
'home.leitmotiv.process': 'processes and methods',
|
||||
'home.leitmotiv.tools': 'a toolbox',
|
||||
|
||||
@@ -30,7 +30,8 @@ export const es: Messages = {
|
||||
'nav.menu': 'Menú',
|
||||
'nav.close': 'Cerrar',
|
||||
|
||||
'home.title': 'Hacer posible la decisión colectiva',
|
||||
'home.title.line1': 'Hacer posible',
|
||||
'home.title.line2': 'la decisión colectiva',
|
||||
'home.leitmotiv.context': 'contexto y encuadre',
|
||||
'home.leitmotiv.process': 'procesos y modalidades',
|
||||
'home.leitmotiv.tools': 'caja de herramientas',
|
||||
|
||||
@@ -33,7 +33,9 @@ export const fr = {
|
||||
'nav.menu': 'Menu',
|
||||
'nav.close': 'Fermer',
|
||||
|
||||
'home.title': 'Rendre possible la décision collective',
|
||||
// The title on two lines, the break after « possible » (Yvv, 2026-11-02): one key per line.
|
||||
'home.title.line1': 'Rendre possible',
|
||||
'home.title.line2': 'la décision collective',
|
||||
'home.leitmotiv.context': 'contexte et cadrage',
|
||||
'home.leitmotiv.process': 'processus et modalités',
|
||||
'home.leitmotiv.tools': 'boîte à outils',
|
||||
|
||||
+121
-39
@@ -1,17 +1,28 @@
|
||||
<script lang="ts">
|
||||
// The welcome (Yvv, 2026-11-02): the keystone arch, large enough to shelter the three points of
|
||||
// the leitmotiv, the toolbox first; then the title, centred, broken after « possible ».
|
||||
import sign from '$lib/assets/cle-de-voute.svg?raw';
|
||||
import GroupChoice from '$lib/components/GroupChoice.svelte';
|
||||
import { t } from '$lib/i18n/index.svelte';
|
||||
import { session } from '$lib/session.svelte';
|
||||
|
||||
const LEITMOTIV = ['home.leitmotiv.tools', 'home.leitmotiv.context', 'home.leitmotiv.process'] as const;
|
||||
</script>
|
||||
|
||||
<div class="home">
|
||||
<header class="intro">
|
||||
<h1>{t('home.title')}</h1>
|
||||
<ul class="leitmotiv">
|
||||
<li>{t('home.leitmotiv.context')}</li>
|
||||
<li>{t('home.leitmotiv.process')}</li>
|
||||
<li>{t('home.leitmotiv.tools')}</li>
|
||||
</ul>
|
||||
<div class="vault">
|
||||
<span class="sign" aria-hidden="true">{@html sign}</span>
|
||||
<ul class="leitmotiv">
|
||||
{#each LEITMOTIV as key, i (key)}
|
||||
<li style:--i={i}>{t(key)}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<h1>
|
||||
<span class="line">{t('home.title.line1')}</span>
|
||||
<span class="line">{t('home.title.line2')}</span>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
{#if session.me}
|
||||
@@ -28,56 +39,127 @@
|
||||
.home {
|
||||
max-width: 44rem;
|
||||
margin: 0 auto;
|
||||
padding: clamp(3rem, 10vh, 6.5rem) clamp(1.2rem, 5vw, 3.5rem) 5rem;
|
||||
padding: clamp(2rem, 7vh, 4.5rem) clamp(1.2rem, 5vw, 3.5rem) 5rem;
|
||||
display: grid;
|
||||
gap: clamp(2.4rem, 6vh, 3.6rem);
|
||||
}
|
||||
.intro h1 {
|
||||
font-family: var(--font-text);
|
||||
font-weight: 500;
|
||||
font-size: clamp(2.1rem, 1.4rem + 3vw, 3.4rem);
|
||||
letter-spacing: -0.015em;
|
||||
line-height: 1.08;
|
||||
font-variation-settings: 'opsz' 72;
|
||||
max-width: 15ch;
|
||||
text-wrap: balance;
|
||||
|
||||
/* The arch, drawn by the sign of the logo (stones in the ink of the mood, the keystone in
|
||||
`--cle`), never tilted. Its box is the stone itself: 92 units wide (the base slab, x from
|
||||
−46 to 46) and 59 high (y from −40, the top of the keystone, to 19, under the slab); the SVG's
|
||||
own 3-unit margin spills out above and below (clipped on the sides, where it is empty). On a
|
||||
phone the arch reaches into the side padding, 0.75rem short of the screen's edges, so that the
|
||||
opening keeps as much room as it can. */
|
||||
.vault {
|
||||
--w: min(34rem, 100vw - 1.5rem);
|
||||
container-type: inline-size;
|
||||
position: relative;
|
||||
width: var(--w);
|
||||
margin-inline: calc(50% - var(--w) / 2);
|
||||
aspect-ratio: 92 / 59;
|
||||
overflow-x: clip;
|
||||
color: var(--ink);
|
||||
}
|
||||
/* The leitmotiv: three lines, each set on a small stone of the keystone's colour. */
|
||||
.sign {
|
||||
position: absolute;
|
||||
inset: calc(-300% / 59) calc(-300% / 92);
|
||||
}
|
||||
.sign :global(svg) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
/* The light under the vault: the opening (x from −18.5 to 18.5, from the keystone down to the
|
||||
slab), its top a half circle, washed with the keystone's colour. */
|
||||
.vault::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: calc(2150% / 59) calc(2750% / 92) calc(340% / 59);
|
||||
border-radius: 50% 50% 0 0 / 54.25% 54.25% 0 0;
|
||||
background: radial-gradient(
|
||||
ellipse 75% 62% at 50% 60%,
|
||||
color-mix(in srgb, var(--cle) 12%, transparent),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
/* The three points, sheltered: centred in the opening (x from −19 to 19; a band from y = −19,
|
||||
under the keystone, to 19, centred on the springing line y = 0), one line each. The type
|
||||
follows the arch (cqi): the longest line of the three languages, 10.5 em (es), holds in the
|
||||
38 units of the opening with room to spare. On a phone the italic is small (12px at 360):
|
||||
its advances are kept exact, not rounded to the pixel, or the letters drift apart
|
||||
(« pr ocessus ») and the word spaces close up. */
|
||||
.leitmotiv {
|
||||
list-style: none;
|
||||
margin: 1.4rem 0 0;
|
||||
position: absolute;
|
||||
inset: calc(2100% / 59) calc(2700% / 92) 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: grid;
|
||||
gap: 0.2rem;
|
||||
align-content: center;
|
||||
justify-items: center;
|
||||
gap: 0.2em;
|
||||
font-family: var(--font-text);
|
||||
font-style: italic;
|
||||
font-size: clamp(1.12rem, 1rem + 0.55vw, 1.4rem);
|
||||
line-height: 1.45;
|
||||
font-size: 3.55cqi;
|
||||
line-height: 1.3;
|
||||
color: var(--ink-soft);
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
text-rendering: geometricPrecision;
|
||||
}
|
||||
.leitmotiv li {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.7rem;
|
||||
|
||||
.intro h1 {
|
||||
margin-top: clamp(1.4rem, 4vh, 2.4rem);
|
||||
font-family: var(--font-text);
|
||||
font-weight: 500;
|
||||
font-size: min(3.3rem, 8.6vw);
|
||||
letter-spacing: -0.015em;
|
||||
line-height: 1.1;
|
||||
font-variation-settings: 'opsz' 72;
|
||||
text-align: center;
|
||||
}
|
||||
.leitmotiv li::before {
|
||||
content: '';
|
||||
flex: none;
|
||||
width: 0.62em;
|
||||
height: 0.34em;
|
||||
border-radius: 0.1em;
|
||||
background: var(--cle);
|
||||
opacity: 0.75;
|
||||
translate: 0 -0.12em;
|
||||
.line {
|
||||
display: block;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.enter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.6rem 1.2rem;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
gap: 0.8rem;
|
||||
text-align: center;
|
||||
}
|
||||
.enter .btn {
|
||||
min-height: 2.75rem;
|
||||
padding-inline: 1.4rem;
|
||||
}
|
||||
.enter p {
|
||||
font-size: 0.9rem;
|
||||
max-width: 34ch;
|
||||
}
|
||||
|
||||
/* The keystone sets the arch, then the three points come under it. */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.sign :global(path[fill^='var(--cle']) {
|
||||
transform-box: fill-box;
|
||||
animation: settle 0.7s var(--ease) 0.1s backwards;
|
||||
}
|
||||
.leitmotiv li {
|
||||
animation: appear 0.6s var(--ease) backwards;
|
||||
animation-delay: calc(0.55s + var(--i) * 0.12s);
|
||||
}
|
||||
}
|
||||
@keyframes settle {
|
||||
from {
|
||||
transform: translateY(-40%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes appear {
|
||||
from {
|
||||
transform: translateY(0.4em);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user