feat(glossaire): harmonize portal pages with shared components
All checks were successful
SMOKE / smoke (push) Successful in 5s
CI / build-and-anchors (push) Successful in 47s
CI / build-and-anchors (pull_request) Successful in 46s

This commit is contained in:
2026-03-25 23:49:00 +01:00
parent 92e0ad01c6
commit f8e3ee4cca
13 changed files with 2508 additions and 5989 deletions

View File

@@ -0,0 +1,122 @@
---
interface LinkItem {
href: string;
label: string;
}
interface Props {
ariaLabel: string;
title: string;
meta?: string;
backHref?: string;
backLabel?: string;
pageItems?: LinkItem[];
usefulLinks?: LinkItem[];
}
const {
ariaLabel,
title,
meta,
backHref = "/glossaire/",
backLabel = "← Retour au glossaire",
pageItems = [],
usefulLinks = [],
} = Astro.props;
---
<nav class="glossary-portal-aside" aria-label={ariaLabel}>
<div class="glossary-portal-aside__block">
<a class="glossary-portal-aside__back" href={backHref}>{backLabel}</a>
<div class="glossary-portal-aside__title">{title}</div>
{meta && <div class="glossary-portal-aside__meta">{meta}</div>}
</div>
{pageItems.length > 0 && (
<div class="glossary-portal-aside__block">
<h2 class="glossary-portal-aside__heading">Dans cette page</h2>
<ul class="glossary-portal-aside__list">
{pageItems.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</div>
)}
{usefulLinks.length > 0 && (
<div class="glossary-portal-aside__block">
<h2 class="glossary-portal-aside__heading">Renvois utiles</h2>
<ul class="glossary-portal-aside__list">
{usefulLinks.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</div>
)}
</nav>
<style>
.glossary-portal-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.glossary-portal-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.glossary-portal-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.glossary-portal-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.glossary-portal-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.glossary-portal-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.glossary-portal-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.glossary-portal-aside__list li{
margin: 6px 0;
}
.glossary-portal-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
@media (prefers-color-scheme: dark){
.glossary-portal-aside__block{
background: rgba(255,255,255,0.04);
}
}
</style>

View File

@@ -0,0 +1,190 @@
---
interface Props {
prefix: string;
kicker: string;
title: string;
intro: string;
moreParagraphs?: string[];
introMaxWidth?: string;
followIntroMaxWidth?: string;
moreMaxHeight?: string;
}
const {
prefix,
kicker,
title,
intro,
moreParagraphs = [],
introMaxWidth = "72ch",
followIntroMaxWidth = "68ch",
moreMaxHeight = "18rem",
} = Astro.props;
---
<div
class="glossary-portal-hero glossary-page-hero"
data-glossary-portal-hero
style={`--portal-hero-intro-max-w:${introMaxWidth}; --portal-hero-follow-intro-max-w:${followIntroMaxWidth}; --portal-hero-more-max-h:${moreMaxHeight};`}
>
<p class="glossary-portal-hero__kicker">{kicker}</p>
<h1>{title}</h1>
<p class="glossary-portal-hero__intro">
{intro}
</p>
{moreParagraphs.length > 0 && (
<div class="glossary-portal-hero__collapsible">
<div
class="glossary-portal-hero__more"
id={`${prefix}-hero-more`}
data-glossary-portal-more
aria-hidden="false"
>
{moreParagraphs.map((paragraph) => (
<p class="glossary-portal-hero__intro">{paragraph}</p>
))}
</div>
<button
class="glossary-portal-hero__toggle"
id={`${prefix}-hero-toggle`}
data-glossary-portal-toggle
type="button"
aria-controls={`${prefix}-hero-more`}
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
)}
</div>
<style>
.glossary-portal-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.glossary-portal-hero__kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.glossary-portal-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.glossary-portal-hero__intro{
margin: 0;
max-width: var(--portal-hero-intro-max-w);
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.glossary-portal-hero__collapsible{
display: grid;
row-gap: 6px;
}
.glossary-portal-hero__more{
display: grid;
row-gap: 14px;
max-height: var(--portal-hero-more-max-h);
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.glossary-portal-hero__toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.glossary-portal-hero__toggle:hover{
opacity: .84;
}
.glossary-portal-hero__toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.glossary-portal-hero__toggle[hidden]{
display: none !important;
}
@media (max-width: 860px){
.glossary-portal-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.glossary-portal-hero__intro{
max-width: none;
}
.glossary-portal-hero__more{
max-height: none;
opacity: 1;
overflow: visible;
}
.glossary-portal-hero__toggle{
display: none !important;
}
}
</style>

View File

@@ -0,0 +1,67 @@
---
interface Props {
id: string;
title: string;
count?: string;
intro?: string;
final?: boolean;
className?: string;
}
const {
id,
title,
count,
intro,
final = false,
className,
} = Astro.props;
---
<section class:list={["glossary-portal-section", final && "glossary-portal-section--final", className]}>
<div class="glossary-portal-section__head">
<h2 id={id}>{title}</h2>
{count && <span class="glossary-portal-section__count">{count}</span>}
</div>
{intro && <p class="glossary-portal-section__intro">{intro}</p>}
<slot />
</section>
<style>
.glossary-portal-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.glossary-portal-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.glossary-portal-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.glossary-portal-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.glossary-portal-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.glossary-portal-section--final{
margin-top: 42px;
}
</style>

View File

@@ -0,0 +1,294 @@
---
interface Props {
heroMoreId: string;
heroToggleId: string;
sectionHeadSelector?: string;
mobileBreakpoint?: number;
autoCollapseDelta?: number;
}
const {
heroMoreId,
heroToggleId,
sectionHeadSelector = ".glossary-portal-section__head",
mobileBreakpoint = 860,
autoCollapseDelta = 160,
} = Astro.props;
---
<script
is:inline
define:vars={{ heroMoreId, heroToggleId, sectionHeadSelector, mobileBreakpoint, autoCollapseDelta }}
>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-glossary-portal-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById(heroMoreId);
const heroToggle = document.getElementById(heroToggleId);
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-glossary-portal-page";
const FOLLOW_ON_CLASS = "glossary-portal-follow-on";
const EXPANDED_CLASS = "glossary-portal-hero-expanded";
const mqMobile = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`);
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
let raf = 0;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const stripLocalSticky = () => {
document.querySelectorAll(sectionHeadSelector).forEach((el) => {
el.classList.remove("is-sticky");
el.removeAttribute("data-sticky-active");
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
} else {
root.style.setProperty("--glossary-local-sticky-h", `${h}px`);
}
};
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= autoCollapseDelta) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
});
};
heroToggle?.addEventListener("click", expandHero);
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
});
const heroResizeObserver =
typeof ResizeObserver !== "undefined"
? new ResizeObserver(schedule)
: null;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
if (document.fonts?.ready) {
document.fonts.ready.then(schedule).catch(() => {});
}
if (mqMobile.addEventListener) {
mqMobile.addEventListener("change", schedule);
} else if (mqMobile.addListener) {
mqMobile.addListener(schedule);
}
schedule();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
} else {
boot();
}
})();
</script>
<style>
:global(body.is-glossary-portal-page #reading-follow){
z-index: 10;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on .glossary-portal-hero__intro){
max-width: var(--portal-hero-follow-intro-max-w, 68ch);
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on:not(.glossary-portal-hero-expanded) .glossary-portal-hero__more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on:not(.glossary-portal-hero-expanded) .glossary-portal-hero__toggle){
display: inline-flex;
}
:global(body.is-glossary-portal-page.glossary-portal-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-glossary-portal-page .glossary-portal-section__head.is-sticky),
:global(body.is-glossary-portal-page .glossary-portal-section__head[data-sticky-active="true"]){
position: static !important;
top: auto !important;
z-index: auto !important;
padding: 0 !important;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
</style>

View File

@@ -1,14 +1,20 @@
---
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
import GlossaryPortalAside from "../../components/GlossaryPortalAside.astro";
import GlossaryPortalHero from "../../components/GlossaryPortalHero.astro";
import GlossaryPortalSection from "../../components/GlossaryPortalSection.astro";
import GlossaryPortalStickySync from "../../components/GlossaryPortalStickySync.astro";
import { getCollection } from "astro:content";
import {
buildGlossaryBySlug,
hrefOfGlossaryEntry,
} from "../../lib/glossary";
const entries = await getCollection("glossaire");
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
const hrefOf = (entry) => `/glossaire/${slugOf(entry)}/`;
const collator = new Intl.Collator("fr", { sensitivity: "base", numeric: true });
const bySlug = new Map(entries.map((entry) => [slugOf(entry), entry]));
const bySlug = buildGlossaryBySlug(entries);
const hrefOf = hrefOfGlossaryEntry;
function resolve(slugs = []) {
return slugs
@@ -74,6 +80,19 @@ const sections = [
];
const totalCount = sections.reduce((sum, section) => sum + section.items.length, 0);
const pageItems = sections.map((section) => ({
href: `#${section.id}`,
label: section.title,
}));
const usefulLinks = [
{ href: "/glossaire/archicration/", label: "Archicration" },
{ href: "/glossaire/archicratie/", label: "Archicratie" },
{ href: "/glossaire/arcalite/", label: "Arcalité" },
{ href: "/glossaire/cratialite/", label: "Cratialité" },
{ href: "/glossaire/co-viabilite/", label: "Co-viabilité" },
];
---
<GlossaryLayout
@@ -82,99 +101,49 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="archi-aside" aria-label="Navigation des archicrations">
<div class="archi-aside__block">
<a class="archi-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="archi-aside__title">Archicrations</div>
<div class="archi-aside__meta">{totalCount} types cartographiés</div>
</div>
<div class="archi-aside__block">
<h2 class="archi-aside__heading">Dans cette page</h2>
<ul class="archi-aside__list">
{sections.map((section) => (
<li><a href={`#${section.id}`}>{section.title}</a></li>
))}
</ul>
</div>
<div class="archi-aside__block">
<h2 class="archi-aside__heading">Renvois utiles</h2>
<ul class="archi-aside__list">
<li><a href="/glossaire/archicration/">Archicration</a></li>
<li><a href="/glossaire/archicratie/">Archicratie</a></li>
<li><a href="/glossaire/arcalite/">Arcalité</a></li>
<li><a href="/glossaire/cratialite/">Cratialité</a></li>
<li><a href="/glossaire/co-viabilite/">Co-viabilité</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des archicrations"
title="Archicrations"
meta={`${totalCount} type${totalCount > 1 ? "s" : ""} cartographié${totalCount > 1 ? "s" : ""}`}
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="archi-page" data-archi-page>
<div class="archi-hero glossary-page-hero" data-archi-hero>
<p class="archi-kicker">Topologie archicratique</p>
<h1>Archicrations</h1>
<p class="archi-intro">
Cette page rassemble les principales formes darchicration distinguées
dans le glossaire. Elle propose une vue densemble des grands régimes de
co-viabilité à partir desquels un collectif se stabilise, se transmet,
se transforme ou se recompose.
</p>
<div class="archi-hero-collapsible">
<div
class="archi-hero-more"
id="archi-hero-more"
data-archi-more
aria-hidden="false"
>
<p class="archi-intro">
Les catégories proposées ci-dessous ne valent pas comme cases closes,
mais comme repères de lecture permettant de situer les différentes
topologies de régulation et leurs articulations.
</p>
</div>
<button
class="archi-hero-toggle"
id="archi-hero-toggle"
data-archi-more-toggle
type="button"
aria-controls="archi-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
<section class="archi-page">
<GlossaryPortalHero
prefix="archi"
kicker="Topologie archicratique"
title="Archicrations"
intro="Cette page rassemble les principales formes darchicration distinguées dans le glossaire. Elle propose une vue densemble des grands régimes de co-viabilité à partir desquels un collectif se stabilise, se transmet, se transforme ou se recompose."
moreParagraphs={[
"Les catégories proposées ci-dessous ne valent pas comme cases closes, mais comme repères de lecture permettant de situer les différentes topologies de régulation et leurs articulations.",
]}
introMaxWidth="72ch"
followIntroMaxWidth="68ch"
moreMaxHeight="18rem"
/>
{sections.map((section) => (
<section class="archi-section">
<div class="archi-section__head">
<h2 id={section.id}>{section.title}</h2>
<span class="archi-section__count">
{section.items.length} fiche{section.items.length > 1 ? "s" : ""}
</span>
</div>
<p class="archi-section__intro">{section.intro}</p>
<GlossaryPortalSection
id={section.id}
title={section.title}
count={`${section.items.length} fiche${section.items.length > 1 ? "s" : ""}`}
intro={section.intro}
>
<div class="archi-cards">
{section.items.map((entry) => (
<a class="archi-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
{entry.data.comparisonTraditions && (
{(entry.data.comparisonTraditions?.length ?? 0) > 0 && (
<small>
Traditions de comparaison : {entry.data.comparisonTraditions.join(" / ")}
</small>
)}
{entry.data.mobilizedAuthors?.length > 0 && (
{(entry.data.mobilizedAuthors?.length ?? 0) > 0 && (
<small>
Auteurs mobilisés : {entry.data.mobilizedAuthors.join(" / ")}
</small>
@@ -182,11 +151,14 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
</a>
))}
</div>
</section>
</GlossaryPortalSection>
))}
<section class="archi-section archi-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Cette cartographie permet de lire les archicrations non comme des formes
isolées, mais comme des topologies de régulation susceptibles de se
@@ -195,232 +167,13 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
<a href="/glossaire/archicratie/">archicratie</a> peut être pensée comme
intelligibilité densemble des formes de co-viabilité.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-archi-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("archi-hero-more");
const heroToggle = document.getElementById("archi-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-archicrations-page";
const FOLLOW_ON_CLASS = "archi-follow-on";
const EXPANDED_CLASS = "archi-hero-expanded";
const mqMobile = window.matchMedia("(max-width: 860px)");
const AUTO_COLLAPSE_DELTA = 160;
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const stripLocalSticky = () => {
document.querySelectorAll(".archi-section__head").forEach((el) => {
el.classList.remove("is-sticky");
el.removeAttribute("data-sticky-active");
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
} else {
root.style.setProperty("--glossary-local-sticky-h", `${h}px`);
}
};
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= AUTO_COLLAPSE_DELTA) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
let raf = 0;
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
});
};
heroToggle?.addEventListener("click", () => {
expandHero();
});
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
});
const heroResizeObserver =
typeof ResizeObserver !== "undefined"
? new ResizeObserver(schedule)
: null;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
if (document.fonts?.ready) {
document.fonts.ready.then(schedule).catch(() => {});
}
if (mqMobile.addEventListener) {
mqMobile.addEventListener("change", schedule);
} else if (mqMobile.addListener) {
mqMobile.addListener(schedule);
}
schedule();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
} else {
boot();
}
})();
</script>
<GlossaryPortalStickySync
heroMoreId="archi-hero-more"
heroToggleId="archi-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -428,139 +181,6 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
padding: 8px 0 24px;
}
.archi-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.archi-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.archi-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.archi-intro{
margin: 0;
max-width: 72ch;
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.archi-hero-collapsible{
display: grid;
row-gap: 6px;
}
.archi-hero-more{
display: grid;
row-gap: 14px;
max-height: 18rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.archi-hero-toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
text-transform: none;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.archi-hero-toggle:hover{
opacity: .84;
}
.archi-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.archi-hero-toggle[hidden]{
display: none !important;
}
.archi-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.archi-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.archi-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.archi-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.archi-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.archi-cards{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
@@ -604,153 +224,8 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
opacity: .72;
}
.archi-section--final{
margin-top: 42px;
}
.archi-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.archi-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.archi-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.archi-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.archi-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.archi-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.archi-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.archi-aside__list li{
margin: 6px 0;
}
.archi-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-archicrations-page #reading-follow){
z-index: 10;
}
:global(body.is-archicrations-page.archi-follow-on .archi-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-archicrations-page.archi-follow-on .archi-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-archicrations-page.archi-follow-on .archi-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-archicrations-page.archi-follow-on:not(.archi-hero-expanded) .archi-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-archicrations-page.archi-follow-on:not(.archi-hero-expanded) .archi-hero-toggle){
display: inline-flex;
}
:global(body.is-archicrations-page.archi-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-archicrations-page .archi-section__head.is-sticky),
:global(body.is-archicrations-page .archi-section__head[data-sticky-active="true"]){
position: static !important;
top: auto !important;
z-index: auto !important;
padding: 0 !important;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
@media (max-width: 860px){
.archi-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.archi-intro{
max-width: none;
}
.archi-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.archi-hero-toggle{
display: none !important;
}
:global(body.is-archicrations-page.archi-follow-on .archi-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
}
@media (prefers-color-scheme: dark){
.archi-card,
.archi-aside__block{
.archi-card{
background: rgba(255,255,255,0.04);
}

View File

@@ -1,13 +1,19 @@
---
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
import GlossaryPortalAside from "../../components/GlossaryPortalAside.astro";
import GlossaryPortalHero from "../../components/GlossaryPortalHero.astro";
import GlossaryPortalSection from "../../components/GlossaryPortalSection.astro";
import GlossaryPortalStickySync from "../../components/GlossaryPortalStickySync.astro";
import { getCollection } from "astro:content";
import {
buildGlossaryBySlug,
hrefOfGlossaryEntry,
} from "../../lib/glossary";
const entries = await getCollection("glossaire");
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
const hrefOf = (entry) => `/glossaire/${slugOf(entry)}/`;
const bySlug = new Map(entries.map((entry) => [slugOf(entry), entry]));
const bySlug = buildGlossaryBySlug(entries);
const hrefOf = hrefOfGlossaryEntry;
const orderedSlugs = [
"arcalite",
@@ -79,6 +85,55 @@ const readingSteps = [
"Larchicratie nomme alors le régime général dans lequel cette composition devient lisible comme structure de régulation.",
},
];
const pageItems = [
{ href: "#grammaire-minimale", label: "Grammaire minimale du système" },
{ href: "#six-concepts", label: "Les six concepts cardinaux" },
{ href: "#distinctions-decisives", label: "Distinctions décisives" },
{ href: "#ordre-lecture", label: "Ordre conseillé de lecture" },
{ href: "#prolonger-lecture", label: "Prolonger la lecture" },
];
const usefulLinks = [
{ href: "/glossaire/scenes-archicratiques/", label: "Scènes archicratiques" },
{ href: "/glossaire/dynamiques-archicratiques/", label: "Dynamiques archicratiques" },
{ href: "/glossaire/archicrations/", label: "Méta-régimes archicratiques" },
{ href: "/glossaire/paradigmes/", label: "Paradigmes et doctrines" },
{ href: "/glossaire/index-complet/", label: "Index complet" },
];
const prolongerLinks = [
{
href: "/glossaire/scenes-archicratiques/",
title: "Scènes archicratiques",
text:
"Comprendre où les tensions deviennent visibles, discutables et révisables.",
},
{
href: "/glossaire/dynamiques-archicratiques/",
title: "Dynamiques archicratiques",
text:
"Explorer les processus de déplacement, doblitération et de pathologisation de la régulation.",
},
{
href: "/glossaire/archicrations/",
title: "Méta-régimes archicratiques",
text:
"Parcourir les grandes formes de co-viabilité et leurs modulations historiques.",
},
{
href: "/glossaire/paradigmes/",
title: "Paradigmes et doctrines",
text:
"Situer larchicratie dans le paysage théorique avec lequel elle dialogue.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver lensemble des entrées du glossaire dans une navigation alphabétique intégrale.",
},
];
---
<GlossaryLayout
@@ -87,93 +142,34 @@ const readingSteps = [
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="cf-aside" aria-label="Navigation des concepts fondamentaux">
<div class="cf-aside__block">
<a class="cf-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="cf-aside__title">Concepts fondamentaux</div>
<div class="cf-aside__meta">
{concepts.length} notion{concepts.length > 1 ? "s" : ""} cardinale{concepts.length > 1 ? "s" : ""}
</div>
</div>
<div class="cf-aside__block">
<h2 class="cf-aside__heading">Dans cette page</h2>
<ul class="cf-aside__list">
<li><a href="#grammaire-minimale">Grammaire minimale du système</a></li>
<li><a href="#six-concepts">Les six concepts cardinaux</a></li>
<li><a href="#distinctions-decisives">Distinctions décisives</a></li>
<li><a href="#ordre-lecture">Ordre conseillé de lecture</a></li>
<li><a href="#prolonger-lecture">Prolonger la lecture</a></li>
</ul>
</div>
<div class="cf-aside__block">
<h2 class="cf-aside__heading">Renvois utiles</h2>
<ul class="cf-aside__list">
<li><a href="/glossaire/scenes-archicratiques/">Scènes archicratiques</a></li>
<li><a href="/glossaire/dynamiques-archicratiques/">Dynamiques archicratiques</a></li>
<li><a href="/glossaire/archicrations/">Méta-régimes archicratiques</a></li>
<li><a href="/glossaire/paradigmes/">Paradigmes et doctrines</a></li>
<li><a href="/glossaire/index-complet/">Index complet</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des concepts fondamentaux"
title="Concepts fondamentaux"
meta={`${concepts.length} notion${concepts.length > 1 ? "s" : ""} cardinale${concepts.length > 1 ? "s" : ""}`}
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="cf-page" data-cf-page>
<div class="cf-hero glossary-page-hero" data-cf-hero>
<p class="cf-kicker">Portail du glossaire</p>
<h1>Concepts fondamentaux</h1>
<p class="cf-intro">
Cette page rassemble la grammaire minimale de larchicratie. Elle ne
remplace pas les fiches détaillées, mais elle en organise la lecture en
montrant comment les six notions cardinales se répondent, se distinguent
et composent ensemble un même système.
</p>
<div class="cf-hero-collapsible">
<div
class="cf-hero-more"
id="cf-hero-more"
data-cf-more
aria-hidden="false"
>
<p class="cf-intro">
Ces concepts ne valent pas comme unités isolées. Ils forment un noyau de
lecture à partir duquel peuvent ensuite se comprendre les scènes
archicratiques, les dynamiques, les tensions et les méta-régimes de
co-viabilité.
</p>
</div>
<button
class="cf-hero-toggle"
id="cf-hero-toggle"
data-cf-more-toggle
type="button"
aria-controls="cf-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
<section class="cf-section">
<div class="cf-section__head">
<h2 id="grammaire-minimale">Grammaire minimale du système</h2>
</div>
<p class="cf-section__intro">
La lecture la plus ramassée du paradigme archicratique peut se formuler
comme une chaîne de composition : deux vecteurs premiers entrent en
tension, cette tension appelle un opérateur régulateur, cet opérateur
vise une co-viabilité, et cette composition prend la forme générale
dune archicratie.
</p>
<section class="cf-page">
<GlossaryPortalHero
prefix="cf"
kicker="Portail du glossaire"
title="Concepts fondamentaux"
intro="Cette page rassemble la grammaire minimale de larchicratie. Elle ne remplace pas les fiches détaillées, mais elle en organise la lecture en montrant comment les six notions cardinales se répondent, se distinguent et composent ensemble un même système."
moreParagraphs={[
"Ces concepts ne valent pas comme unités isolées. Ils forment un noyau de lecture à partir duquel peuvent ensuite se comprendre les scènes archicratiques, les dynamiques, les tensions et les méta-régimes de co-viabilité.",
]}
introMaxWidth="76ch"
followIntroMaxWidth="68ch"
moreMaxHeight="12rem"
/>
<GlossaryPortalSection
id="grammaire-minimale"
title="Grammaire minimale du système"
intro="La lecture la plus ramassée du paradigme archicratique peut se formuler comme une chaîne de composition : deux vecteurs premiers entrent en tension, cette tension appelle un opérateur régulateur, cet opérateur vise une co-viabilité, et cette composition prend la forme générale dune archicratie."
>
<div class="cf-map" aria-label="Carte des concepts fondamentaux">
<div class="cf-map__stage">
<div class="cf-map__title">Vecteurs premiers</div>
@@ -242,21 +238,14 @@ const readingSteps = [
)}
</div>
</div>
</section>
<section class="cf-section">
<div class="cf-section__head">
<h2 id="six-concepts">Les six concepts cardinaux</h2>
<span class="cf-section__count">
{concepts.length} fiche{concepts.length > 1 ? "s" : ""}
</span>
</div>
<p class="cf-section__intro">
Chaque fiche peut se lire séparément, mais leur intelligibilité augmente
lorsquon les aborde comme un ensemble structuré.
</p>
</GlossaryPortalSection>
<GlossaryPortalSection
id="six-concepts"
title="Les six concepts cardinaux"
count={`${concepts.length} fiche${concepts.length > 1 ? "s" : ""}`}
intro="Chaque fiche peut se lire séparément, mais leur intelligibilité augmente lorsquon les aborde comme un ensemble structuré."
>
<div class="cf-cards">
{concepts.map((entry) => (
<a class="cf-card" href={hrefOf(entry)}>
@@ -265,21 +254,14 @@ const readingSteps = [
</a>
))}
</div>
</section>
<section class="cf-section">
<div class="cf-section__head">
<h2 id="distinctions-decisives">Distinctions décisives</h2>
<span class="cf-section__count">
{comparisonCards.length} distinction{comparisonCards.length > 1 ? "s" : ""}
</span>
</div>
<p class="cf-section__intro">
Ce portail ne sert pas seulement à regrouper des définitions : il doit
aussi empêcher les confusions qui brouilleraient la lecture du système.
</p>
</GlossaryPortalSection>
<GlossaryPortalSection
id="distinctions-decisives"
title="Distinctions décisives"
count={`${comparisonCards.length} distinction${comparisonCards.length > 1 ? "s" : ""}`}
intro="Ce portail ne sert pas seulement à regrouper des définitions : il doit aussi empêcher les confusions qui brouilleraient la lecture du système."
>
<div class="cf-comparisons">
{comparisonCards.map((item) => (
<section class="cf-card cf-card--text">
@@ -288,21 +270,14 @@ const readingSteps = [
</section>
))}
</div>
</section>
<section class="cf-section">
<div class="cf-section__head">
<h2 id="ordre-lecture">Ordre conseillé de lecture</h2>
<span class="cf-section__count">
{readingSteps.length} étape{readingSteps.length > 1 ? "s" : ""}
</span>
</div>
<p class="cf-section__intro">
Pour un lecteur qui découvre larchitecture conceptuelle, cet ordre
offre le chemin le plus clair.
</p>
</GlossaryPortalSection>
<GlossaryPortalSection
id="ordre-lecture"
title="Ordre conseillé de lecture"
count={`${readingSteps.length} étape${readingSteps.length > 1 ? "s" : ""}`}
intro="Pour un lecteur qui découvre larchitecture conceptuelle, cet ordre offre le chemin le plus clair."
>
<div class="cf-steps">
{readingSteps.map((step) => (
<section class="cf-step">
@@ -314,64 +289,28 @@ const readingSteps = [
</section>
))}
</div>
</section>
<section class="cf-section">
<div class="cf-section__head">
<h2 id="prolonger-lecture">Prolonger la lecture</h2>
</div>
<p class="cf-section__intro">
Une fois cette grammaire minimale stabilisée, la lecture peut sélargir
vers les familles de méta-régimes, les paradigmes de comparaison, les
dynamiques archicratiques et lindex complet.
</p>
</GlossaryPortalSection>
<GlossaryPortalSection
id="prolonger-lecture"
title="Prolonger la lecture"
intro="Une fois cette grammaire minimale stabilisée, la lecture peut sélargir vers les familles de méta-régimes, les paradigmes de comparaison, les dynamiques archicratiques et lindex complet."
>
<div class="cf-cards">
<a class="cf-card" href="/glossaire/scenes-archicratiques/">
<strong>Scènes archicratiques</strong>
<span>
Comprendre où les tensions deviennent visibles, discutables et
révisables.
</span>
</a>
<a class="cf-card" href="/glossaire/dynamiques-archicratiques/">
<strong>Dynamiques archicratiques</strong>
<span>
Explorer les processus de déplacement, doblitération et de
pathologisation de la régulation.
</span>
</a>
<a class="cf-card" href="/glossaire/archicrations/">
<strong>Méta-régimes archicratiques</strong>
<span>
Parcourir les grandes formes de co-viabilité et leurs modulations
historiques.
</span>
</a>
<a class="cf-card" href="/glossaire/paradigmes/">
<strong>Paradigmes et doctrines</strong>
<span>
Situer larchicratie dans le paysage théorique avec lequel elle
dialogue.
</span>
</a>
<a class="cf-card" href="/glossaire/index-complet/">
<strong>Index complet</strong>
<span>
Retrouver lensemble des entrées du glossaire dans une navigation
alphabétique intégrale.
</span>
</a>
{prolongerLinks.map((item) => (
<a class="cf-card" href={item.href}>
<strong>{item.title}</strong>
<span>{item.text}</span>
</a>
))}
</div>
</section>
</GlossaryPortalSection>
<section class="cf-section cf-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Lire ces concepts ensemble permet de comprendre que l
<a href="/glossaire/archicratie/">archicratie</a> nest pas une notion
@@ -383,232 +322,13 @@ const readingSteps = [
<a href="/glossaire/co-viabilite/">co-viabilité</a> et, plus largement,
les différentes formes historiques de co-viabilité.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-cf-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("cf-hero-more");
const heroToggle = document.getElementById("cf-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-concepts-fondamentaux-page";
const FOLLOW_ON_CLASS = "cf-follow-on";
const EXPANDED_CLASS = "cf-hero-expanded";
const mqMobile = window.matchMedia("(max-width: 860px)");
const AUTO_COLLAPSE_DELTA = 160;
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const stripLocalSticky = () => {
document.querySelectorAll(".cf-section__head").forEach((el) => {
el.classList.remove("is-sticky");
el.removeAttribute("data-sticky-active");
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
} else {
root.style.setProperty("--glossary-local-sticky-h", `${h}px`);
}
};
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= AUTO_COLLAPSE_DELTA) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
let raf = 0;
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
});
};
heroToggle?.addEventListener("click", () => {
expandHero();
});
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
});
const heroResizeObserver =
typeof ResizeObserver !== "undefined"
? new ResizeObserver(schedule)
: null;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
if (document.fonts?.ready) {
document.fonts.ready.then(schedule).catch(() => {});
}
if (mqMobile.addEventListener) {
mqMobile.addEventListener("change", schedule);
} else if (mqMobile.addListener) {
mqMobile.addListener(schedule);
}
schedule();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
} else {
boot();
}
})();
</script>
<GlossaryPortalStickySync
heroMoreId="cf-hero-more"
heroToggleId="cf-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -616,139 +336,6 @@ const readingSteps = [
padding: 8px 0 24px;
}
.cf-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.cf-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.cf-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.cf-intro{
max-width: 76ch;
margin: 0;
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.cf-hero-collapsible{
display: grid;
row-gap: 6px;
}
.cf-hero-more{
display: grid;
row-gap: 14px;
max-height: 12rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.cf-hero-toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
text-transform: none;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.cf-hero-toggle:hover{
opacity: .84;
}
.cf-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.cf-hero-toggle[hidden]{
display: none !important;
}
.cf-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.cf-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.cf-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.cf-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.cf-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.cf-map{
display: grid;
justify-items: center;
@@ -913,119 +500,6 @@ const readingSteps = [
opacity: .92;
}
.cf-section--final{
margin-top: 42px;
}
.cf-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.cf-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.cf-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.cf-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.cf-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.cf-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.cf-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.cf-aside__list li{
margin: 6px 0;
}
.cf-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-concepts-fondamentaux-page #reading-follow){
z-index: 10;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on .cf-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on .cf-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on .cf-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on:not(.cf-hero-expanded) .cf-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on:not(.cf-hero-expanded) .cf-hero-toggle){
display: inline-flex;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-concepts-fondamentaux-page .cf-section__head.is-sticky),
:global(body.is-concepts-fondamentaux-page .cf-section__head[data-sticky-active="true"]){
position: static !important;
top: auto !important;
z-index: auto !important;
padding: 0 !important;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
@media (max-width: 720px){
.cf-map__roots{
grid-template-columns: 1fr;
@@ -1041,43 +515,11 @@ const readingSteps = [
}
}
@media (max-width: 860px){
.cf-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.cf-intro{
max-width: none;
}
.cf-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.cf-hero-toggle{
display: none !important;
}
:global(body.is-concepts-fondamentaux-page.cf-follow-on .cf-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
}
@media (prefers-color-scheme: dark){
.cf-map,
.cf-node,
.cf-card,
.cf-step,
.cf-aside__block{
.cf-step{
background: rgba(255,255,255,0.04);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,16 @@
---
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
import GlossaryPortalAside from "../../components/GlossaryPortalAside.astro";
import GlossaryPortalHero from "../../components/GlossaryPortalHero.astro";
import GlossaryPortalSection from "../../components/GlossaryPortalSection.astro";
import GlossaryPortalStickySync from "../../components/GlossaryPortalStickySync.astro";
import { getCollection } from "astro:content";
import { hrefOfGlossaryEntry } from "../../lib/glossary";
const entries = await getCollection("glossaire");
const collator = new Intl.Collator("fr", { sensitivity: "base", numeric: true });
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
const hrefOf = (entry) => `/glossaire/${slugOf(entry)}/`;
const hrefOf = hrefOfGlossaryEntry;
function sortByTerm(list = []) {
return [...list].sort((a, b) => collator.compare(a.data.term, b.data.term));
@@ -22,6 +26,51 @@ const doctrines = sortByTerm(
const doctrinesCount = doctrines.length;
const paradigmesCount = paradigmes.length;
const pageItems = [
...(doctrines.length > 0
? [{ href: "#doctrines", label: "Doctrines fondatrices" }]
: []),
...(paradigmes.length > 0
? [{ href: "#paradigmes", label: "Paradigmes régulateurs" }]
: []),
{ href: "#prolonger-la-lecture", label: "Prolonger la lecture" },
];
const usefulLinks = [
{ href: "/glossaire/concepts-fondamentaux/", label: "Concepts fondamentaux" },
{ href: "/glossaire/scenes-archicratiques/", label: "Scènes archicratiques" },
{ href: "/glossaire/archicrations/", label: "Méta-régimes archicratiques" },
{ href: "/glossaire/dynamiques-archicratiques/", label: "Dynamiques archicratiques" },
{ href: "/glossaire/index-complet/", label: "Index complet" },
];
const prolongerLinks = [
{
href: "/glossaire/concepts-fondamentaux/",
title: "Concepts fondamentaux",
text:
"Revenir au noyau minimal : arcalité, cratialité, tension, archicration, co-viabilité, archicratie.",
},
{
href: "/glossaire/scenes-archicratiques/",
title: "Scènes archicratiques",
text:
"Comprendre où les architectures de régulation deviennent visibles, disputables et révisables.",
},
{
href: "/glossaire/archicrations/",
title: "Méta-régimes archicratiques",
text:
"Parcourir les grandes formes de co-viabilité et leurs modulations historiques.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver lensemble des entrées du glossaire dans une navigation alphabétique intégrale.",
},
];
---
<GlossaryLayout
@@ -30,111 +79,64 @@ const paradigmesCount = paradigmes.length;
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="theo-aside" aria-label="Navigation des paradigmes et doctrines">
<div class="theo-aside__block">
<a class="theo-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="theo-aside__title">Paradigmes et doctrines</div>
<div class="theo-aside__meta">
doctrines fondatrices · paradigmes régulateurs
</div>
</div>
<div class="theo-aside__block">
<h2 class="theo-aside__heading">Dans cette page</h2>
<ul class="theo-aside__list">
{doctrines.length > 0 && (
<li><a href="#doctrines">Doctrines fondatrices</a></li>
)}
{paradigmes.length > 0 && (
<li><a href="#paradigmes">Paradigmes régulateurs</a></li>
)}
<li><a href="#prolonger-la-lecture">Prolonger la lecture</a></li>
</ul>
</div>
<div class="theo-aside__block">
<h2 class="theo-aside__heading">Renvois utiles</h2>
<ul class="theo-aside__list">
<li><a href="/glossaire/concepts-fondamentaux/">Concepts fondamentaux</a></li>
<li><a href="/glossaire/scenes-archicratiques/">Scènes archicratiques</a></li>
<li><a href="/glossaire/archicrations/">Méta-régimes archicratiques</a></li>
<li><a href="/glossaire/dynamiques-archicratiques/">Dynamiques archicratiques</a></li>
<li><a href="/glossaire/index-complet/">Index complet</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des paradigmes et doctrines"
title="Paradigmes et doctrines"
meta="doctrines fondatrices · paradigmes régulateurs"
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="theo-page" data-theo-page>
<div class="theo-hero glossary-page-hero" data-theo-hero>
<p class="theo-kicker">Cartographie théorique</p>
<h1>Paradigmes et doctrines</h1>
<section class="theo-page">
<GlossaryPortalHero
prefix="theo"
kicker="Cartographie théorique"
title="Paradigmes et doctrines"
intro="Larchicratie ne se déploie pas dans le vide. Elle sinscrit dans un paysage intellectuel plus large où se croisent des doctrines fondatrices de lordre et des paradigmes de régulation des collectifs."
moreParagraphs={[
"On appellera ici doctrines fondatrices les formulations qui posent un principe premier de légitimité, de souveraineté ou dordre politique. On appellera paradigmes régulateurs les cadres théoriques qui décrivent des modes de tenue, de conflictualité, dadministration, de reproduction ou de transformation des sociétés.",
]}
introMaxWidth="72ch"
followIntroMaxWidth="68ch"
moreMaxHeight="18rem"
/>
<p class="theo-intro">
Larchicratie ne se déploie pas dans le vide. Elle sinscrit dans un
paysage intellectuel plus large où se croisent des doctrines
fondatrices de lordre et des paradigmes de régulation des collectifs.
</p>
<div class="theo-hero-collapsible">
<div
class="theo-hero-more"
id="theo-hero-more"
data-theo-more
aria-hidden="false"
>
<p class="theo-intro">
On appellera ici <strong>doctrines fondatrices</strong> les formulations
qui posent un principe premier de légitimité, de souveraineté ou dordre
politique. On appellera <strong>paradigmes régulateurs</strong> les
cadres théoriques qui décrivent des modes de tenue, de conflictualité,
dadministration, de reproduction ou de transformation des sociétés.
</p>
</div>
<button
class="theo-hero-toggle"
id="theo-hero-toggle"
data-theo-more-toggle
type="button"
aria-controls="theo-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
<div class="theo-overview" aria-label="Repères de lecture théorique">
<article class="theo-overview__item">
<strong>Doctrines fondatrices</strong>
<span>Principes premiers de légitimité, de souveraineté et de fondation de lordre.</span>
</article>
<article class="theo-overview__item">
<strong>Paradigmes régulateurs</strong>
<span>Cadres décrivant la tenue, le conflit, ladministration ou la transformation des collectifs.</span>
</article>
<article class="theo-overview__item">
<strong>Portée comparative</strong>
<span>Le paysage dans lequel larchicratie situe ses proximités, ses écarts et sa singularité.</span>
</article>
</div>
{doctrines.length > 0 && (
<section class="theo-section">
<div class="theo-section__head">
<h2 id="doctrines">Doctrines fondatrices</h2>
<span class="theo-section__count">
{doctrinesCount} entrée{doctrinesCount > 1 ? "s" : ""}
</span>
</div>
<p class="theo-section__intro">
Ces doctrines posent un principe premier dautorité, de légitimité ou
dordre collectif. Elles servent de points de comparaison pour penser
ce qui, dans une régulation, relève de la fondation, de la souveraineté
ou du principe architectonique initial.
</p>
<GlossaryPortalSection
id="doctrines"
title="Doctrines fondatrices"
count={`${doctrinesCount} entrée${doctrinesCount > 1 ? "s" : ""}`}
intro="Ces doctrines posent un principe premier dautorité, de légitimité ou dordre collectif. Elles servent de points de comparaison pour penser ce qui, dans une régulation, relève de la fondation, de la souveraineté ou du principe architectonique initial."
>
<div class="theo-cards">
{doctrines.map((entry) => (
<a class="theo-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
{entry.data.mobilizedAuthors?.length > 0 && (
{(entry.data.mobilizedAuthors?.length ?? 0) > 0 && (
<small>
Auteurs mobilisés : {entry.data.mobilizedAuthors.join(" / ")}
</small>
)}
{entry.data.comparisonTraditions?.length > 0 && (
{(entry.data.comparisonTraditions?.length ?? 0) > 0 && (
<small>
Traditions de comparaison : {entry.data.comparisonTraditions.join(" / ")}
</small>
@@ -142,38 +144,29 @@ const paradigmesCount = paradigmes.length;
</a>
))}
</div>
</section>
</GlossaryPortalSection>
)}
{paradigmes.length > 0 && (
<section class="theo-section">
<div class="theo-section__head">
<h2 id="paradigmes">Paradigmes régulateurs</h2>
<span class="theo-section__count">
{paradigmesCount} entrée{paradigmesCount > 1 ? "s" : ""}
</span>
</div>
<p class="theo-section__intro">
Ces paradigmes décrivent des formes de conflictualité, de gouvernement,
de régulation, de reproduction ou de transformation des collectifs.
Ils constituent le champ théorique au sein duquel larchicratie entre
en discussion, se compare et précise sa singularité.
</p>
<GlossaryPortalSection
id="paradigmes"
title="Paradigmes régulateurs"
count={`${paradigmesCount} entrée${paradigmesCount > 1 ? "s" : ""}`}
intro="Ces paradigmes décrivent des formes de conflictualité, de gouvernement, de régulation, de reproduction ou de transformation des collectifs. Ils constituent le champ théorique au sein duquel larchicratie entre en discussion, se compare et précise sa singularité."
>
<div class="theo-cards">
{paradigmes.map((entry) => (
<a class="theo-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
{entry.data.mobilizedAuthors?.length > 0 && (
{(entry.data.mobilizedAuthors?.length ?? 0) > 0 && (
<small>
Auteurs mobilisés : {entry.data.mobilizedAuthors.join(" / ")}
</small>
)}
{entry.data.comparisonTraditions?.length > 0 && (
{(entry.data.comparisonTraditions?.length ?? 0) > 0 && (
<small>
Traditions de comparaison : {entry.data.comparisonTraditions.join(" / ")}
</small>
@@ -181,58 +174,29 @@ const paradigmesCount = paradigmes.length;
</a>
))}
</div>
</section>
</GlossaryPortalSection>
)}
<section class="theo-section">
<div class="theo-section__head">
<h2 id="prolonger-la-lecture">Prolonger la lecture</h2>
</div>
<p class="theo-section__intro">
Cette page sert de portail entre la cartographie théorique générale et
les autres ensembles du glossaire. Elle permet de relier les doctrines
et paradigmes aux scènes, aux dynamiques, aux méta-régimes et au noyau
conceptuel archicratique.
</p>
<GlossaryPortalSection
id="prolonger-la-lecture"
title="Prolonger la lecture"
intro="Cette page sert de portail entre la cartographie théorique générale et les autres ensembles du glossaire. Elle permet de relier les doctrines et paradigmes aux scènes, aux dynamiques, aux méta-régimes et au noyau conceptuel archicratique."
>
<div class="theo-cards">
<a class="theo-card" href="/glossaire/concepts-fondamentaux/">
<strong>Concepts fondamentaux</strong>
<span>
Revenir au noyau minimal : arcalité, cratialité, tension,
archicration, co-viabilité, archicratie.
</span>
</a>
<a class="theo-card" href="/glossaire/scenes-archicratiques/">
<strong>Scènes archicratiques</strong>
<span>
Comprendre où les architectures de régulation deviennent visibles,
disputables et révisables.
</span>
</a>
<a class="theo-card" href="/glossaire/archicrations/">
<strong>Méta-régimes archicratiques</strong>
<span>
Parcourir les grandes formes de co-viabilité et leurs modulations
historiques.
</span>
</a>
<a class="theo-card" href="/glossaire/index-complet/">
<strong>Index complet</strong>
<span>
Retrouver lensemble des entrées du glossaire dans une navigation
alphabétique intégrale.
</span>
</a>
{prolongerLinks.map((item) => (
<a class="theo-card" href={item.href}>
<strong>{item.title}</strong>
<span>{item.text}</span>
</a>
))}
</div>
</section>
</GlossaryPortalSection>
<section class="theo-section theo-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Lire doctrines et paradigmes ensemble permet de situer larchicratie
dans un espace comparatif plus vaste. Les doctrines éclairent les formes
@@ -241,232 +205,13 @@ const paradigmesCount = paradigmes.length;
alors non comme un isolat conceptuel, mais comme une intelligibilité
régulatrice située dans un paysage théorique dense et disputé.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-theo-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("theo-hero-more");
const heroToggle = document.getElementById("theo-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-paradigmes-page";
const FOLLOW_ON_CLASS = "theo-follow-on";
const EXPANDED_CLASS = "theo-hero-expanded";
const mqMobile = window.matchMedia("(max-width: 860px)");
const AUTO_COLLAPSE_DELTA = 160;
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const stripLocalSticky = () => {
document.querySelectorAll(".theo-section__head").forEach((el) => {
el.classList.remove("is-sticky");
el.removeAttribute("data-sticky-active");
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
} else {
root.style.setProperty("--glossary-local-sticky-h", `${h}px`);
}
};
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= AUTO_COLLAPSE_DELTA) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
let raf = 0;
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
});
};
heroToggle?.addEventListener("click", () => {
expandHero();
});
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
});
const heroResizeObserver =
typeof ResizeObserver !== "undefined"
? new ResizeObserver(schedule)
: null;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
if (document.fonts?.ready) {
document.fonts.ready.then(schedule).catch(() => {});
}
if (mqMobile.addEventListener) {
mqMobile.addEventListener("change", schedule);
} else if (mqMobile.addListener) {
mqMobile.addListener(schedule);
}
schedule();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
} else {
boot();
}
})();
</script>
<GlossaryPortalStickySync
heroMoreId="theo-hero-more"
heroToggleId="theo-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -474,137 +219,31 @@ const paradigmesCount = paradigmes.length;
padding: 8px 0 24px;
}
.theo-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
.theo-overview{
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.theo-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.theo-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.theo-intro{
margin: 0;
max-width: 72ch;
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.theo-hero-collapsible{
display: grid;
row-gap: 6px;
}
.theo-hero-more{
display: grid;
row-gap: 14px;
max-height: 18rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.theo-hero-toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
text-transform: none;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.theo-hero-toggle:hover{
opacity: .84;
}
.theo-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.theo-hero-toggle[hidden]{
display: none !important;
}
.theo-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.theo-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.theo-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
margin: 18px 0 8px;
}
.theo-section__count{
.theo-overview__item{
display: grid;
gap: 6px;
padding: 14px 16px;
border: 1px solid rgba(127,127,127,0.20);
border-radius: 16px;
background: rgba(127,127,127,0.04);
}
.theo-overview__item strong{
font-size: 14px;
line-height: 1.3;
}
.theo-overview__item span{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.theo-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
line-height: 1.45;
opacity: .86;
}
.theo-cards{
@@ -650,153 +289,15 @@ const paradigmesCount = paradigmes.length;
opacity: .72;
}
.theo-section--final{
margin-top: 42px;
}
.theo-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.theo-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.theo-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.theo-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.theo-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.theo-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.theo-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.theo-aside__list li{
margin: 6px 0;
}
.theo-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-paradigmes-page #reading-follow){
z-index: 10;
}
:global(body.is-paradigmes-page.theo-follow-on .theo-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-paradigmes-page.theo-follow-on .theo-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-paradigmes-page.theo-follow-on .theo-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-paradigmes-page.theo-follow-on:not(.theo-hero-expanded) .theo-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-paradigmes-page.theo-follow-on:not(.theo-hero-expanded) .theo-hero-toggle){
display: inline-flex;
}
:global(body.is-paradigmes-page.theo-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-paradigmes-page .theo-section__head.is-sticky),
:global(body.is-paradigmes-page .theo-section__head[data-sticky-active="true"]){
position: static !important;
top: auto !important;
z-index: auto !important;
padding: 0 !important;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
@media (max-width: 860px){
.theo-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.theo-intro{
max-width: none;
}
.theo-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.theo-hero-toggle{
display: none !important;
}
:global(body.is-paradigmes-page.theo-follow-on .theo-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
@media (max-width: 920px){
.theo-overview{
grid-template-columns: 1fr;
}
}
@media (prefers-color-scheme: dark){
.theo-card,
.theo-aside__block{
.theo-overview__item,
.theo-card{
background: rgba(255,255,255,0.04);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,9 @@
---
import GlossaryLayout from "../../layouts/GlossaryLayout.astro";
import GlossaryPortalAside from "../../components/GlossaryPortalAside.astro";
import GlossaryPortalHero from "../../components/GlossaryPortalHero.astro";
import GlossaryPortalSection from "../../components/GlossaryPortalSection.astro";
import GlossaryPortalStickySync from "../../components/GlossaryPortalStickySync.astro";
const sections = [
{
@@ -189,6 +193,52 @@ const sections = [
];
const totalCount = sections.reduce((sum, section) => sum + section.items.length, 0);
const pageItems = [
...sections.map((section) => ({
href: `#${section.id}`,
label: section.title,
})),
{ href: "#prolonger-la-lecture", label: "Prolonger la lecture" },
];
const usefulLinks = [
{ href: "/glossaire/scene-depreuve/", label: "Scène dépreuve" },
{ href: "/glossaire/archicration/", label: "Archicration" },
{ href: "/glossaire/obliteration-archicratique/", label: "Oblitération archicratique" },
{ href: "/glossaire/archicration-obliteree/", label: "Archicration oblitérée" },
{ href: "/glossaire/synchrotopie/", label: "Synchrotopie" },
{ href: "/glossaire/hypotopie/", label: "Hypotopie" },
{ href: "/glossaire/hypertopie/", label: "Hypertopie" },
{ href: "/glossaire/atopie/", label: "Atopie" },
];
const prolongerLinks = [
{
href: "/glossaire/scene-depreuve/",
title: "Scène dépreuve",
text:
"Revenir à la notion-pivot de comparution, dexposition et de mise en discussion régulatrice.",
},
{
href: "/glossaire/scenes-archicratiques/",
title: "Scènes archicratiques",
text:
"Retrouver le portail synthétique des scènes, topologies et formats de comparution.",
},
{
href: "/glossaire/dynamiques-archicratiques/",
title: "Dynamiques archicratiques",
text:
"Explorer les processus de fermeture, de capture, doblitération et de dérive des scènes.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver lensemble des entrées du glossaire dans une navigation alphabétique intégrale.",
},
];
---
<GlossaryLayout
@@ -197,88 +247,36 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="verbs-aside" aria-label="Navigation des verbes de la scène">
<div class="verbs-aside__block">
<a class="verbs-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="verbs-aside__title">Verbes de la scène</div>
<div class="verbs-aside__meta">{totalCount} verbes cartographiés</div>
</div>
<div class="verbs-aside__block">
<h2 class="verbs-aside__heading">Dans cette page</h2>
<ul class="verbs-aside__list">
{sections.map((section) => (
<li><a href={`#${section.id}`}>{section.title}</a></li>
))}
</ul>
</div>
<div class="verbs-aside__block">
<h2 class="verbs-aside__heading">Renvois utiles</h2>
<ul class="verbs-aside__list">
<li><a href="/glossaire/scene-depreuve/">Scène dépreuve</a></li>
<li><a href="/glossaire/archicration/">Archicration</a></li>
<li><a href="/glossaire/obliteration-archicratique/">Oblitération archicratique</a></li>
<li><a href="/glossaire/archicration-obliteree/">Archicration oblitérée</a></li>
<li><a href="/glossaire/synchrotopie/">Synchrotopie</a></li>
<li><a href="/glossaire/hypotopie/">Hypotopie</a></li>
<li><a href="/glossaire/hypertopie/">Hypertopie</a></li>
<li><a href="/glossaire/atopie/">Atopie</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des verbes de la scène"
title="Verbes de la scène"
meta={`${totalCount} verbe${totalCount > 1 ? "s" : ""} cartographié${totalCount > 1 ? "s" : ""}`}
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="verbs-page" data-verbs-page>
<div class="verbs-hero glossary-page-hero" data-verbs-hero>
<p class="verbs-kicker">Mini-glossaire systémique</p>
<h1>Verbes de la scène archicratique</h1>
<p class="verbs-intro">
Cette page ne rassemble pas des notions de régime, de topologie ou de processus,
mais des verbes danalyse. Elle sert à qualifier ce qui arrive à une scène :
comment elle souvre, comment elle séloigne, comment elle se ferme,
comment elle est capturée, et comment un archicrate peut encore y répondre.
</p>
<div class="verbs-hero-collapsible">
<div
class="verbs-hero-more"
id="verbs-hero-more"
data-verbs-more
aria-hidden="false"
>
<p class="verbs-intro">
Elle constitue ainsi un outil de description fin, complémentaire des fiches
consacrées aux scènes, aux topologies et aux dynamiques archicratiques.
</p>
</div>
<button
class="verbs-hero-toggle"
id="verbs-hero-toggle"
data-verbs-more-toggle
type="button"
aria-controls="verbs-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
<section class="verbs-page">
<GlossaryPortalHero
prefix="verbs"
kicker="Mini-glossaire systémique"
title="Verbes de la scène archicratique"
intro="Cette page ne rassemble pas des notions de régime, de topologie ou de processus, mais des verbes danalyse. Elle sert à qualifier ce qui arrive à une scène : comment elle souvre, comment elle séloigne, comment elle se ferme, comment elle est capturée, et comment un archicrate peut encore y répondre."
moreParagraphs={[
"Elle constitue ainsi un outil de description fin, complémentaire des fiches consacrées aux scènes, aux topologies et aux dynamiques archicratiques.",
]}
introMaxWidth="76ch"
followIntroMaxWidth="68ch"
moreMaxHeight="12rem"
/>
{sections.map((section) => (
<section class="verbs-section">
<div class="verbs-section__head">
<h2 id={section.id}>{section.title}</h2>
<span class="verbs-section__count">
{section.items.length} verbe{section.items.length > 1 ? "s" : ""}
</span>
</div>
<p class="verbs-section__intro">{section.intro}</p>
<GlossaryPortalSection
id={section.id}
title={section.title}
count={`${section.items.length} verbe${section.items.length > 1 ? "s" : ""}`}
intro={section.intro}
>
<div class="verbs-cards">
{section.items.map((item) => (
<article class="verbs-card">
@@ -291,11 +289,29 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
</article>
))}
</div>
</section>
</GlossaryPortalSection>
))}
<section class="verbs-section verbs-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="prolonger-la-lecture"
title="Prolonger la lecture"
intro="Cette page forme un mini-glossaire daction. Elle permet de mieux qualifier ce qui arrive concrètement aux scènes archicratiques et prolonge la lecture vers les pages de concepts, de topologies et de dynamiques."
>
<div class="verbs-cards">
{prolongerLinks.map((item) => (
<a class="verbs-card verbs-card--link" href={item.href}>
<h3>{item.title}</h3>
<p class="verbs-card__definition">{item.text}</p>
</a>
))}
</div>
</GlossaryPortalSection>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Ces verbes permettent de distinguer plus finement les niveaux du paradigme :
une <a href="/glossaire/scene-depreuve/">scène</a> dit où quelque chose peut comparaître,
@@ -304,232 +320,13 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
un processus comme la <a href="/glossaire/desarchicration/">désarchicration</a>
dit ce qui se transforme, et ces verbes disent ce quon fait concrètement à la scène.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-verbs-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("verbs-hero-more");
const heroToggle = document.getElementById("verbs-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-verbes-de-la-scene-page";
const FOLLOW_ON_CLASS = "verbs-follow-on";
const EXPANDED_CLASS = "verbs-hero-expanded";
const mqMobile = window.matchMedia("(max-width: 860px)");
const AUTO_COLLAPSE_DELTA = 160;
let expandedAtY = null;
let lastScrollY = window.scrollY || 0;
body.classList.add(BODY_CLASS);
const heroHeight = () =>
Math.max(0, Math.round(hero.getBoundingClientRect().height || 0));
const stripLocalSticky = () => {
document.querySelectorAll(".verbs-section__head").forEach((el) => {
el.classList.remove("is-sticky");
el.removeAttribute("data-sticky-active");
});
};
const computeFollowOn = () =>
!mqMobile.matches &&
follow.classList.contains("is-on") &&
follow.style.display !== "none" &&
follow.getAttribute("aria-hidden") !== "true";
const applyLocalStickyHeight = () => {
const h = mqMobile.matches ? 0 : heroHeight();
if (typeof window.__archiSetLocalStickyHeight === "function") {
window.__archiSetLocalStickyHeight(h);
} else {
root.style.setProperty("--glossary-local-sticky-h", `${h}px`);
}
};
const syncFollowState = () => {
const on = computeFollowOn();
body.classList.toggle(FOLLOW_ON_CLASS, on);
return on;
};
const collapseHero = () => {
if (!body.classList.contains(EXPANDED_CLASS)) return;
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "true");
}
if (heroToggle) {
heroToggle.hidden = false;
heroToggle.setAttribute("aria-expanded", "false");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const expandHero = () => {
body.classList.add(EXPANDED_CLASS);
expandedAtY = window.scrollY || 0;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "true");
}
try {
window.__archiUpdateFollow?.();
} catch {}
schedule();
};
const syncHeroState = () => {
const followOn = computeFollowOn();
const expanded = body.classList.contains(EXPANDED_CLASS);
const collapsed = followOn && !expanded;
if (!followOn || mqMobile.matches) {
body.classList.remove(EXPANDED_CLASS);
expandedAtY = null;
if (heroMore) {
heroMore.setAttribute("aria-hidden", "false");
}
if (heroToggle) {
heroToggle.hidden = true;
heroToggle.setAttribute("aria-expanded", "false");
}
return;
}
if (heroMore) {
heroMore.setAttribute("aria-hidden", collapsed ? "true" : "false");
}
if (heroToggle) {
heroToggle.hidden = !collapsed;
heroToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
}
};
const maybeAutoCollapseOnScroll = () => {
if (mqMobile.matches) {
lastScrollY = window.scrollY || 0;
return;
}
if (!computeFollowOn()) {
lastScrollY = window.scrollY || 0;
return;
}
if (!body.classList.contains(EXPANDED_CLASS)) {
lastScrollY = window.scrollY || 0;
return;
}
if (expandedAtY == null) {
lastScrollY = window.scrollY || 0;
return;
}
const currentY = window.scrollY || 0;
const scrollingDown = currentY > lastScrollY;
const delta = currentY - expandedAtY;
if (scrollingDown && delta >= AUTO_COLLAPSE_DELTA) {
collapseHero();
}
lastScrollY = currentY;
};
const syncAll = () => {
stripLocalSticky();
syncFollowState();
syncHeroState();
applyLocalStickyHeight();
};
let raf = 0;
const schedule = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
requestAnimationFrame(syncAll);
});
};
heroToggle?.addEventListener("click", () => {
expandHero();
});
const onScroll = () => {
maybeAutoCollapseOnScroll();
schedule();
};
const followObserver = new MutationObserver(schedule);
followObserver.observe(follow, {
attributes: true,
attributeFilter: ["class", "style", "aria-hidden"],
subtree: false,
});
const heroResizeObserver =
typeof ResizeObserver !== "undefined"
? new ResizeObserver(schedule)
: null;
heroResizeObserver?.observe(hero);
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", schedule);
window.addEventListener("pageshow", schedule);
if (document.fonts?.ready) {
document.fonts.ready.then(schedule).catch(() => {});
}
if (mqMobile.addEventListener) {
mqMobile.addEventListener("change", schedule);
} else if (mqMobile.addListener) {
mqMobile.addListener(schedule);
}
schedule();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
} else {
boot();
}
})();
</script>
<GlossaryPortalStickySync
heroMoreId="verbs-hero-more"
heroToggleId="verbs-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -537,139 +334,6 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
padding: 8px 0 24px;
}
.verbs-hero{
position: sticky;
top: calc(var(--sticky-header-h, 0px) + var(--page-gap, 12px));
z-index: 11;
margin: 0 0 24px;
padding: 18px 18px 20px;
border: 1px solid rgba(127,127,127,0.18);
border-radius: 28px;
background:
linear-gradient(180deg, rgba(0,0,0,0.60), rgba(0,0,0,0.92)),
radial-gradient(900px 240px at 20% 0%, rgba(0,217,255,0.08), transparent 60%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: grid;
row-gap: 14px;
transition:
margin-bottom 180ms ease,
border-radius 180ms ease,
padding 180ms ease,
row-gap 180ms ease;
}
.verbs-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.verbs-hero h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.verbs-intro{
max-width: 76ch;
margin: 0;
font-size: 1.04rem;
line-height: 1.55;
opacity: .94;
transition:
font-size 180ms ease,
line-height 180ms ease,
max-width 180ms ease;
}
.verbs-hero-collapsible{
display: grid;
row-gap: 6px;
}
.verbs-hero-more{
display: grid;
row-gap: 14px;
max-height: 12rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.verbs-hero-toggle{
display: none;
align-self: flex-start;
width: fit-content;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 11px;
line-height: 1.2;
letter-spacing: .01em;
text-transform: none;
opacity: .56;
cursor: pointer;
text-decoration: underline;
text-underline-offset: .12em;
text-decoration-thickness: 1px;
}
.verbs-hero-toggle:hover{
opacity: .84;
}
.verbs-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.verbs-hero-toggle[hidden]{
display: none !important;
}
.verbs-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.verbs-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.verbs-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.verbs-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.verbs-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.verbs-cards{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
@@ -685,10 +349,19 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
background: rgba(127,127,127,0.05);
transition: background 120ms ease, border-color 120ms ease, transform 120ms ease;
transition:
background 120ms ease,
border-color 120ms ease,
transform 120ms ease;
}
.verbs-card:hover{
.verbs-card--link{
text-decoration: none;
color: inherit;
}
.verbs-card:hover,
.verbs-card--link:hover{
transform: translateY(-1px);
background: rgba(127,127,127,0.08);
border-color: rgba(0,217,255,0.16);
@@ -716,157 +389,13 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
opacity: .92;
}
.verbs-section--final{
margin-top: 42px;
}
.verbs-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.verbs-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.verbs-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.verbs-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.verbs-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.verbs-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.verbs-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.verbs-aside__list li{
margin: 6px 0;
}
.verbs-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-verbes-de-la-scene-page #reading-follow){
z-index: 10;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on .verbs-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on .verbs-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on .verbs-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on:not(.verbs-hero-expanded) .verbs-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on:not(.verbs-hero-expanded) .verbs-hero-toggle){
display: inline-flex;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-verbes-de-la-scene-page .verbs-section__head.is-sticky),
:global(body.is-verbes-de-la-scene-page .verbs-section__head[data-sticky-active="true"]){
position: static !important;
top: auto !important;
z-index: auto !important;
padding: 0 !important;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
@media (max-width: 860px){
.verbs-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.verbs-intro{
max-width: none;
}
.verbs-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.verbs-hero-toggle{
display: none !important;
}
:global(body.is-verbes-de-la-scene-page.verbs-follow-on .verbs-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
}
@media (prefers-color-scheme: dark){
.verbs-card,
.verbs-aside__block{
.verbs-card{
background: rgba(255,255,255,0.04);
}
.verbs-card:hover{
.verbs-card:hover,
.verbs-card--link:hover{
background: rgba(255,255,255,0.07);
}
}