Compare commits

...

14 Commits

Author SHA1 Message Date
cea94c56db fix(glossaire): expose relations heading to reading follow
All checks were successful
SMOKE / smoke (push) Successful in 4s
CI / build-and-anchors (push) Successful in 41s
CI / build-and-anchors (pull_request) Successful in 43s
2026-03-26 20:42:01 +01:00
c1e24736e3 Merge pull request 'feat(glossaire): deduplicate entry aside relation groups' (#302) from feat/glossaire-entry-aside-dedup into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 21s
CI / build-and-anchors (push) Successful in 49s
SMOKE / smoke (push) Successful in 4s
Deploy staging+live (annotations) / deploy (push) Successful in 9m41s
Reviewed-on: #302
2026-03-26 20:27:31 +01:00
24bbfbc17f feat(glossaire): deduplicate entry aside relation groups
All checks were successful
SMOKE / smoke (push) Successful in 6s
CI / build-and-anchors (push) Successful in 47s
CI / build-and-anchors (pull_request) Successful in 46s
2026-03-26 20:24:49 +01:00
a11e2f1d18 Merge pull request 'fix(glossaire): compact sticky entry hero on glossary pages' (#301) from fix/glossaire-entry-sticky-hero-collapse into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 32s
CI / build-and-anchors (push) Successful in 45s
SMOKE / smoke (push) Successful in 8s
Deploy staging+live (annotations) / deploy (push) Successful in 9m18s
Reviewed-on: #301
2026-03-26 18:32:19 +01:00
630b146d02 fix(glossaire): compact sticky entry hero on glossary pages
All checks were successful
SMOKE / smoke (push) Successful in 5s
CI / build-and-anchors (push) Successful in 50s
CI / build-and-anchors (pull_request) Successful in 46s
2026-03-26 18:30:34 +01:00
551360db83 Merge pull request 'fix(ci): use local pagefind binary instead of npx wrapper' (#300) from fix/ci-pagefind-local-bin into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 26s
CI / build-and-anchors (push) Successful in 44s
SMOKE / smoke (push) Successful in 8s
Deploy staging+live (annotations) / deploy (push) Successful in 9m45s
Reviewed-on: #300
2026-03-26 14:45:29 +01:00
a96c282780 fix(ci): use local pagefind binary instead of npx wrapper
All checks were successful
SMOKE / smoke (push) Successful in 5s
CI / build-and-anchors (push) Successful in 45s
CI / build-and-anchors (pull_request) Successful in 46s
2026-03-26 14:41:02 +01:00
d2e0f147c2 Merge pull request 'audit(glossaire): tighten portal exposure and cross-page coherence' (#299) from audit/glossaire-transverse-coherence-fix into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 33s
SMOKE / smoke (push) Successful in 10s
Deploy staging+live (annotations) / deploy (push) Successful in 10m22s
CI / build-and-anchors (push) Successful in 45s
Reviewed-on: #299
2026-03-26 14:20:37 +01:00
ad95364021 audit(glossaire): tighten portal exposure and cross-page coherence
All checks were successful
SMOKE / smoke (push) Successful in 5s
CI / build-and-anchors (push) Successful in 1m11s
CI / build-and-anchors (pull_request) Successful in 1m17s
2026-03-26 14:16:05 +01:00
e48e322363 Merge pull request 'feat(glossaire): harmonize portal pages and sticky reading ux' (#298) from feat/glossaire-portal-polish-final into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 27s
Deploy staging+live (annotations) / deploy (push) Successful in 10m51s
SMOKE / smoke (push) Successful in 7s
CI / build-and-anchors (push) Successful in 43s
Reviewed-on: #298
2026-03-26 13:01:46 +01:00
a9f2a5bbd4 feat(glossaire): harmonize portal pages and sticky reading ux
All checks were successful
SMOKE / smoke (push) Successful in 5s
CI / build-and-anchors (push) Successful in 54s
CI / build-and-anchors (pull_request) Successful in 43s
2026-03-26 12:58:17 +01:00
0cba8f868e Merge pull request 'feat(glossaire): harmonize portal pages with shared components' (#297) from feat/glossaire-portals-harmonization into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 28s
CI / build-and-anchors (push) Successful in 43s
SMOKE / smoke (push) Successful in 7s
Deploy staging+live (annotations) / deploy (push) Successful in 10m36s
Reviewed-on: #297
2026-03-25 23:52:36 +01:00
f8e3ee4cca 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
2026-03-25 23:49:00 +01:00
92e0ad01c6 Merge pull request 'refactor(glossaire): componentize glossary entry page' (#296) from refactor/glossaire-entry-componentization into main
All checks were successful
Proposer Apply (Queue) / apply-proposer (push) Successful in 22s
CI / build-and-anchors (push) Successful in 48s
SMOKE / smoke (push) Successful in 6s
Deploy staging+live (annotations) / deploy (push) Successful in 9m57s
Reviewed-on: #296
2026-03-25 19:28:10 +01:00
22 changed files with 2804 additions and 6020 deletions

View File

@@ -10,7 +10,8 @@
"clean": "rm -rf dist",
"build": "astro build",
"build:clean": "npm run clean && npm run build",
"postbuild": "node scripts/inject-anchor-aliases.mjs && node scripts/dedupe-ids-dist.mjs && node scripts/build-para-index.mjs && node scripts/build-annotations-index.mjs && node scripts/purge-dist-dev-whoami.mjs && npx pagefind --site dist",
"build:search": "pagefind --site dist",
"postbuild": "node scripts/inject-anchor-aliases.mjs && node scripts/dedupe-ids-dist.mjs && node scripts/build-para-index.mjs && node scripts/build-annotations-index.mjs && node scripts/purge-dist-dev-whoami.mjs && npm run build:search",
"import": "node scripts/import-docx.mjs",
"apply:ticket": "node scripts/apply-ticket.mjs",
"audit:dist": "node scripts/audit-dist.mjs",

View File

@@ -91,31 +91,44 @@ const hasScholarlyMeta =
}
.glossary-entry-head__title{
padding: 18px 18px 16px;
padding:
var(--entry-hero-pad-top, 18px)
var(--entry-hero-pad-x, 18px)
calc(var(--entry-hero-pad-top, 18px) - 2px);
transition: padding 180ms ease;
}
.glossary-entry-head h1{
margin: 0;
font-size: clamp(2.2rem, 4vw, 3.15rem);
font-size: var(--entry-hero-h1-size, clamp(2.2rem, 4vw, 3.15rem));
line-height: 1.02;
letter-spacing: -.04em;
font-weight: 850;
transition: font-size 180ms ease;
}
.glossary-entry-summary{
display: grid;
gap: 14px;
padding: 16px 18px 18px;
gap: var(--entry-hero-gap, 14px);
padding:
calc(var(--entry-hero-pad-bottom, 18px) - 2px)
var(--entry-hero-pad-x, 18px)
var(--entry-hero-pad-bottom, 18px);
border-top: 1px solid rgba(127,127,127,0.14);
background: rgba(255,255,255,0.02);
transition: gap 180ms ease, padding 180ms ease;
}
.glossary-entry-dek{
margin: 0;
max-width: 76ch;
font-size: 1.04rem;
line-height: 1.55;
max-width: var(--entry-hero-dek-maxw, 76ch);
font-size: var(--entry-hero-dek-size, 1.04rem);
line-height: var(--entry-hero-dek-lh, 1.55);
opacity: .94;
transition:
max-width 180ms ease,
font-size 180ms ease,
line-height 180ms ease;
}
.glossary-entry-signals{
@@ -123,6 +136,7 @@ const hasScholarlyMeta =
flex-wrap: wrap;
gap: 8px;
margin: 0;
transition: gap 180ms ease;
}
.glossary-pill{
@@ -135,6 +149,11 @@ const hasScholarlyMeta =
background: rgba(127,127,127,0.05);
font-size: 13px;
line-height: 1.35;
transition:
padding 180ms ease,
font-size 180ms ease,
background 120ms ease,
border-color 120ms ease;
}
.glossary-pill--family{
@@ -148,6 +167,14 @@ const hasScholarlyMeta =
border: 1px solid rgba(127,127,127,0.18);
border-radius: 12px;
background: rgba(127,127,127,0.04);
max-height: var(--entry-hero-meta-max-h, 12rem);
opacity: var(--entry-hero-meta-opacity, 1);
overflow: hidden;
transition:
max-height 180ms ease,
opacity 140ms ease,
padding 180ms ease,
border-color 180ms ease;
}
.glossary-entry-meta p{

View File

@@ -114,6 +114,10 @@
z-index: 10;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-signals){
gap: 6px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-head){
margin-bottom: 0;
border-bottom-left-radius: 0;
@@ -126,12 +130,21 @@
padding-bottom: 10px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-signals){
gap: 6px;
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-dek){
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-pill){
padding: 4px 8px;
font-size: 12px;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on .glossary-entry-meta){
padding: 8px 10px;
padding: 0;
border-color: transparent;
}
:global(body.is-glossary-entry-page.glossary-entry-follow-on #reading-follow){

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,87 @@
---
export interface Props {
href: string;
label: string;
icon?: string;
className?: string;
}
const {
href,
label,
icon = "↗",
className,
} = Astro.props;
---
<a class:list={["glossary-portal-cta", className]} href={href}>
<span>{label}</span>
<span aria-hidden="true">{icon}</span>
</a>
<style>
.glossary-portal-cta{
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 40px;
padding: 0 14px;
border: 1px solid rgba(0,217,255,0.24);
border-radius: 999px;
background:
linear-gradient(180deg, rgba(0,217,255,0.10), rgba(0,217,255,0.04)),
rgba(127,127,127,0.06);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.05),
0 0 0 1px rgba(0,217,255,0.04);
text-decoration: none;
font-size: 12px;
font-weight: 800;
letter-spacing: .01em;
white-space: nowrap;
transition:
transform 120ms ease,
background 120ms ease,
border-color 120ms ease,
box-shadow 120ms ease;
}
.glossary-portal-cta:hover{
transform: translateY(-1px);
border-color: rgba(0,217,255,0.34);
background:
linear-gradient(180deg, rgba(0,217,255,0.14), rgba(0,217,255,0.06)),
rgba(127,127,127,0.08);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
0 0 0 1px rgba(0,217,255,0.08),
0 10px 28px rgba(0,0,0,0.18);
text-decoration: none;
}
.glossary-portal-cta:focus-visible{
outline: 2px solid rgba(0,217,255,0.28);
outline-offset: 4px;
}
@media (max-width: 720px){
.glossary-portal-cta{
width: 100%;
}
}
@media (prefers-color-scheme: dark){
.glossary-portal-cta{
background:
linear-gradient(180deg, rgba(0,217,255,0.12), rgba(0,217,255,0.05)),
rgba(255,255,255,0.04);
}
.glossary-portal-cta:hover{
background:
linear-gradient(180deg, rgba(0,217,255,0.16), rgba(0,217,255,0.07)),
rgba(255,255,255,0.06);
}
}
</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,96 @@
---
export interface Props {
id?: string;
title: string;
count?: string;
intro?: string;
surface?: boolean;
className?: string;
}
const {
id,
title,
count,
intro,
surface = false,
className,
} = Astro.props;
---
<div
class:list={[
"glossary-portal-panel",
surface && "glossary-portal-panel--surface",
className,
]}
>
<div class="glossary-portal-panel__head">
<h3 id={id}>{title}</h3>
{count && <span class="glossary-portal-panel__count">{count}</span>}
</div>
{intro && <p class="glossary-portal-panel__intro">{intro}</p>}
<slot />
</div>
<style>
.glossary-portal-panel{
display: grid;
gap: 12px;
}
.glossary-portal-panel--surface{
padding: 18px 18px 16px;
border: 1px solid var(--glossary-border, rgba(127,127,127,0.18));
border-radius: 18px;
background:
linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)),
var(--glossary-bg-soft, rgba(127,127,127,0.035));
}
.glossary-portal-panel__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
}
.glossary-portal-panel__head h3{
margin: 0;
font-size: 15px;
line-height: 1.3;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 36px);
}
.glossary-portal-panel__count{
display: inline-flex;
align-items: center;
min-height: 24px;
padding: 0 10px;
border: 1px solid rgba(127,127,127,0.22);
border-radius: 999px;
font-size: 12px;
line-height: 1.2;
opacity: .78;
white-space: nowrap;
}
.glossary-portal-panel__intro{
max-width: 78ch;
margin: 0;
font-size: 14px;
line-height: 1.5;
opacity: .9;
}
@media (prefers-color-scheme: dark){
.glossary-portal-panel--surface{
background:
linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)),
rgba(255,255,255,0.04);
}
}
</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

@@ -7,12 +7,15 @@ interface Props {
}
const { relationBlocks = [] } = Astro.props;
const relationsHeadingId = "relations-conceptuelles";
---
{relationBlocks.length > 0 && (
<section class="glossary-relations" aria-label="Relations conceptuelles">
<h2>Relations conceptuelles</h2>
<section
class="glossary-relations"
aria-labelledby={relationsHeadingId}
>
<h2 id={relationsHeadingId}>Relations conceptuelles</h2>
<div class="glossary-relations-grid">
{relationBlocks.map((block) => (
<section class={`glossary-relations-card ${block.className}`}>

View File

@@ -26,6 +26,38 @@ const {
</EditionLayout>
<style is:global>
body[data-edition-key="glossaire"][data-sticky-mode="glossary-entry"]{
--entry-hero-pad-top: 18px;
--entry-hero-pad-x: 18px;
--entry-hero-pad-bottom: 18px;
--entry-hero-gap: 14px;
--entry-hero-h1-size: clamp(2.2rem, 4vw, 3.15rem);
--entry-hero-dek-size: 1.04rem;
--entry-hero-dek-lh: 1.55;
--entry-hero-dek-maxw: 76ch;
--entry-hero-meta-max-h: 12rem;
--entry-hero-meta-opacity: 1;
}
body[data-edition-key="glossaire"][data-sticky-mode="glossary-entry"].glossary-entry-follow-on{
--entry-hero-pad-top: 8px;
--entry-hero-pad-x: 14px;
--entry-hero-pad-bottom: 6px;
--entry-hero-gap: 6px;
--entry-hero-h1-size: clamp(1.45rem, 2.4vw, 1.9rem);
--entry-hero-dek-size: .90rem;
--entry-hero-dek-lh: 1.32;
--entry-hero-dek-maxw: 56ch;
--entry-hero-meta-max-h: 0px;
--entry-hero-meta-opacity: 0;
}
body[data-edition-key="glossaire"][data-sticky-mode="glossary-portal"]{
--portal-hero-pad-top: 18px;
--portal-hero-pad-x: 18px;

View File

@@ -201,6 +201,36 @@ export function uniqueGlossaryEntries(
return out;
}
export function slugsOfGlossaryEntries(
entries: GlossaryEntry[] = [],
): Set<string> {
const slugs = new Set<string>();
for (const entry of entries) {
const slug = slugOfGlossaryEntry(entry);
if (!slug) continue;
slugs.add(slug);
}
return slugs;
}
export function excludeGlossaryEntries(
entries: GlossaryEntry[] = [],
excluded: Iterable<string> = [],
): GlossaryEntry[] {
const excludedSlugs = new Set(
Array.from(excluded)
.map((value) => normalizeGlossarySlug(value))
.filter(Boolean),
);
return entries.filter((entry) => {
const slug = slugOfGlossaryEntry(entry);
return Boolean(slug) && !excludedSlugs.has(slug);
});
}
export function resolveGlossaryEntriesInSourceOrder(
slugs: string[] = [],
allEntries: GlossaryEntry[] = [],
@@ -504,11 +534,27 @@ export function getGlossaryEntryAsideData(
allEntries: GlossaryEntry[] = [],
): GlossaryEntryAsideData {
const currentFamily = familyOf(currentEntry);
const currentSlug = slugOfGlossaryEntry(currentEntry);
const fondamentaux = getFondamentaux(allEntries);
const sameFamilyEntries = getEntriesOfSameFamily(currentEntry, allEntries);
const sameFamilyTitle = getSameFamilyTitle(currentEntry);
const relationSections = getRelationSections(currentEntry, allEntries);
const contextualTheory = getContextualTheory(currentEntry, allEntries);
const relationEntries = uniqueGlossaryEntries(
relationSections.flatMap((section) => section.items),
);
const relationSlugs = slugsOfGlossaryEntries(relationEntries);
const contextualTheory = excludeGlossaryEntries(
getContextualTheory(currentEntry, allEntries),
new Set([currentSlug, ...relationSlugs]),
).slice(0, 6);
const contextualTheorySlugs = slugsOfGlossaryEntries(contextualTheory);
const sameFamilyEntries = excludeGlossaryEntries(
getEntriesOfSameFamily(currentEntry, allEntries),
new Set([currentSlug, ...relationSlugs, ...contextualTheorySlugs]),
).slice(0, 8);
const showNoyau =
currentFamily !== "concept-fondamental" &&

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,49 @@ 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/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é" },
];
const prolongerLinks = [
{
href: "/glossaire/concepts-fondamentaux/",
title: "Concepts fondamentaux",
text:
"Revenir au noyau minimal : arcalité, cratialité, tension, archicration, co-viabilité et archicratie.",
},
{
href: "/glossaire/paradigmes/",
title: "Paradigmes et doctrines",
text:
"Situer les archicrations dans le paysage théorique au sein duquel larchicratie se compare et se distingue.",
},
{
href: "/glossaire/tensions-irreductibles/",
title: "Tensions irréductibles",
text:
"Revenir aux foyers structuraux de conflictualité que les archicrations stabilisent sans les abolir.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver lensemble des entrées du glossaire dans une navigation alphabétique intégrale.",
},
];
---
<GlossaryLayout
@@ -82,99 +131,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 +181,29 @@ 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="prolonger-la-lecture"
title="Prolonger la lecture"
intro="Cette cartographie des archicrations peut ensuite être replacée dans le noyau conceptuel, dans le paysage théorique général et dans lindex complet du glossaire."
>
<div class="archi-cards">
{prolongerLinks.map((item) => (
<a class="archi-card" href={item.href}>
<strong>{item.title}</strong>
<span>{item.text}</span>
</a>
))}
</div>
</GlossaryPortalSection>
<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 +212,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 +226,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 +269,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-la-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

View File

@@ -39,6 +39,9 @@ const tension = bySlug.get("tension");
const sceneDepreuve = bySlug.get("scene-depreuve");
const archicration = bySlug.get("archicration");
const conceptsPageHref = "/glossaire/concepts-fondamentaux/";
const scenesPageHref = "/glossaire/scenes-archicratiques/";
const dynamiquesPageHref = "/glossaire/dynamiques-archicratiques/";
const paradigmeArchicratiquePageHref = "/glossaire/paradigme-archicratique/";
const metaRegimesPageHref = "/glossaire/archicrations/";
const tensionsPageHref = "/glossaire/tensions-irreductibles/";
@@ -215,6 +218,8 @@ const approfondirPortalItems = [
title="Concepts fondamentaux"
followSection="Concepts fondamentaux"
intro="Ces notions forment la grammaire minimale de larchicratie. Elles donnent accès à la structure générale du système."
ctaHref={conceptsPageHref}
ctaLabel="Ouvrir le portail"
>
<GlossaryCardGrid entries={fondamentaux} />
</GlossaryHomeSection>
@@ -237,6 +242,8 @@ const approfondirPortalItems = [
title="Scènes archicratiques"
followSection="Scènes archicratiques"
intro="Les scènes archicratiques rendent possible la comparution des architectures de régulation. Elles sont le lieu où lordre peut être exposé, discuté et révisé."
ctaHref={scenesPageHref}
ctaLabel="Ouvrir le portail"
>
<GlossaryCardGrid entries={scenes} wide={true} />
</GlossaryHomeSection>
@@ -248,6 +255,8 @@ const approfondirPortalItems = [
title="Dynamiques archicratiques"
followSection="Dynamiques archicratiques"
intro="Cette famille rassemble les processus de déplacement, les dérives et les formes de pathologisation de la régulation archicratique."
ctaHref={dynamiquesPageHref}
ctaLabel="Ouvrir le portail"
>
<GlossaryCardGrid entries={dynamiques} />
</GlossaryHomeSection>
@@ -274,6 +283,7 @@ const approfondirPortalItems = [
>
<GlossaryPortalGrid items={approfondirPortalItems} secondary={true} />
</GlossaryHomeSection>
</section>
<script is:inline>
(() => {

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);
}

View File

@@ -1,14 +1,27 @@
---
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 GlossaryPortalPanel from "../../components/GlossaryPortalPanel.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 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;
const slugOf = (entry) => String(entry.id).replace(/\.(md|mdx)$/i, "");
function sortByTerm(list = []) {
return [...list].sort((a, b) => collator.compare(a.data.term, b.data.term));
@@ -23,12 +36,14 @@ function resolveEntries(slugs = []) {
function uniqueBySlug(list = []) {
const seen = new Set();
const out = [];
for (const entry of list) {
const slug = slugOf(entry);
if (seen.has(slug)) continue;
seen.add(slug);
out.push(entry);
}
return out;
}
@@ -61,7 +76,56 @@ const otherEntries = sortByTerm(
const mobilizedAuthors = sceneDepreuve?.data?.mobilizedAuthors ?? [];
const comparisonTraditions = sceneDepreuve?.data?.comparisonTraditions ?? [];
const structuralCount = structuralEntries.length;
const constellationCount = relatedEntries.length;
const otherCount = otherEntries.length;
const paradigmCount = paradigmEntries.length;
const pageItems = [
{ href: "#coeur-de-notion", label: "Cœur de notion" },
...(structuralEntries.length > 0
? [{ href: "#articulations-essentielles", label: "Articulations essentielles" }]
: []),
...(relatedEntries.length > 0
? [{ href: "#constellation-theorique", label: "Constellation théorique" }]
: []),
{ href: "#prolonger-la-lecture", label: "Prolonger la lecture" },
];
const usefulLinks = [
{ href: "/glossaire/tension/", label: "Tension" },
{ href: "/glossaire/archicration/", label: "Archicration" },
{ href: "/glossaire/archicratie/", label: "Archicratie" },
{ href: "/glossaire/concepts-fondamentaux/", label: "Concepts fondamentaux" },
{ href: "/glossaire/paradigmes/", label: "Paradigmes et doctrines" },
];
const prolongerLinks = [
{
href: "/glossaire/",
title: "Accueil du glossaire",
text: "Revenir à la cartographie générale du système archicratique.",
},
{
href: "/glossaire/concepts-fondamentaux/",
title: "Concepts fondamentaux",
text:
"Repartir du noyau conceptuel minimal : arcalité, cratialité, tension, archicration, co-viabilité, archicratie.",
},
{
href: "/glossaire/paradigmes/",
title: "Paradigmes et doctrines",
text:
"Situer la scène archicratique dans son paysage de comparaison théorique.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver toutes les entrées du glossaire dans lordre alphabétique.",
},
];
---
<GlossaryLayout
@@ -70,93 +134,34 @@ const constellationCount = relatedEntries.length;
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="scene-aside" aria-label="Navigation des scènes archicratiques">
<div class="scene-aside__block">
<a class="scene-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="scene-aside__title">Scènes archicratiques</div>
<div class="scene-aside__meta">
{sceneDepreuve ? "1 notion-pivot" : "Portail en cours de constitution"}
</div>
</div>
<div class="scene-aside__block">
<h2 class="scene-aside__heading">Dans cette page</h2>
<ul class="scene-aside__list">
<li><a href="#coeur-de-notion">Cœur de notion</a></li>
{structuralEntries.length > 0 && (
<li><a href="#articulations-essentielles">Articulations essentielles</a></li>
)}
{relatedEntries.length > 0 && (
<li><a href="#constellation-theorique">Constellation théorique</a></li>
)}
<li><a href="#prolonger-la-lecture">Prolonger la lecture</a></li>
</ul>
</div>
<div class="scene-aside__block">
<h2 class="scene-aside__heading">Renvois utiles</h2>
<ul class="scene-aside__list">
<li><a href="/glossaire/tension/">Tension</a></li>
<li><a href="/glossaire/archicration/">Archicration</a></li>
<li><a href="/glossaire/archicratie/">Archicratie</a></li>
<li><a href="/glossaire/concepts-fondamentaux/">Concepts fondamentaux</a></li>
<li><a href="/glossaire/paradigmes/">Paradigmes et doctrines</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des scènes archicratiques"
title="Scènes archicratiques"
meta={sceneDepreuve ? "1 notion-pivot" : "Portail en cours de constitution"}
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="scene-page" data-scene-page>
<div class="scene-hero glossary-page-hero" data-scene-hero>
<p class="scene-kicker">Parcours du glossaire</p>
<h1>Scènes archicratiques</h1>
<p class="scene-intro">
Les scènes archicratiques désignent les espaces de comparution,
dexposition, de contestation et de révision par lesquels une
architecture régulatrice cesse dêtre purement opaque pour devenir
visible, discutable et transformable.
</p>
<div class="scene-hero-collapsible">
<div
class="scene-hero-more"
id="scene-hero-more"
data-scene-more
aria-hidden="false"
>
<p class="scene-intro">
Dans léconomie générale du paradigme, elles sont ce qui empêche la
régulation de se refermer sur elle-même. Elles ouvrent un espace où les
tensions peuvent apparaître, être qualifiées, disputées et réorganisées.
</p>
</div>
<button
class="scene-hero-toggle"
id="scene-hero-toggle"
data-scene-more-toggle
type="button"
aria-controls="scene-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
<section class="scene-section">
<div class="scene-section__head">
<h2 id="coeur-de-notion">Cœur de notion</h2>
</div>
<p class="scene-section__intro">
Cette page prend pour pivot la <strong>scène dépreuve</strong>, notion
centrale pour penser lexposition publique, la mise en discussion et la
révisabilité des architectures de régulation.
</p>
<section class="scene-page">
<GlossaryPortalHero
prefix="scene"
kicker="Parcours du glossaire"
title="Scènes archicratiques"
intro="Les scènes archicratiques désignent les espaces de comparution, dexposition, de contestation et de révision par lesquels une architecture régulatrice cesse dêtre purement opaque pour devenir visible, discutable et transformable."
moreParagraphs={[
"Dans léconomie générale du paradigme, elles sont ce qui empêche la régulation de se refermer sur elle-même. Elles ouvrent un espace où les tensions peuvent apparaître, être qualifiées, disputées et réorganisées.",
]}
introMaxWidth="76ch"
followIntroMaxWidth="72ch"
moreMaxHeight="18rem"
/>
<GlossaryPortalSection
id="coeur-de-notion"
title="Cœur de notion"
intro="Cette page prend pour pivot la scène dépreuve, notion centrale pour penser lexposition publique, la mise en discussion et la révisabilité des architectures de régulation."
>
{sceneDepreuve ? (
<article class="scene-focus-card">
<div class="scene-focus-card__eyebrow">Entrée principale</div>
@@ -172,6 +177,7 @@ const constellationCount = relatedEntries.length;
<strong>Auteurs mobilisés :</strong> {mobilizedAuthors.join(" / ")}
</p>
)}
{comparisonTraditions.length > 0 && (
<p>
<strong>Traditions de comparaison :</strong> {comparisonTraditions.join(" / ")}
@@ -185,29 +191,22 @@ const constellationCount = relatedEntries.length;
La fiche principale nest pas encore disponible dans la collection.
</p>
)}
</section>
</GlossaryPortalSection>
{structuralEntries.length > 0 && (
<section class="scene-section">
<div class="scene-section__head">
<h2 id="articulations-essentielles">Articulations essentielles</h2>
<span class="scene-section__count">
{structuralEntries.length} notion{structuralEntries.length > 1 ? "s" : ""}
</span>
</div>
<p class="scene-section__intro">
La scène nest pas une notion isolée. Elle sarticule au phénomène de
tension, à lopérateur darchicration et au méta-régime darchicratie.
</p>
<GlossaryPortalSection
id="articulations-essentielles"
title="Articulations essentielles"
count={`${structuralCount} notion${structuralCount > 1 ? "s" : ""}`}
intro="La scène nest pas une notion isolée. Elle sarticule au phénomène de tension, à lopérateur darchicration et au méta-régime darchicratie."
>
<div class="scene-cards">
{structuralEntries.map((entry) => (
<a class="scene-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>
@@ -215,34 +214,32 @@ const constellationCount = relatedEntries.length;
</a>
))}
</div>
</section>
</GlossaryPortalSection>
)}
{relatedEntries.length > 0 && (
<section class="scene-section">
<div class="scene-section__head">
<h2 id="constellation-theorique">Constellation théorique</h2>
<span class="scene-section__count">
{constellationCount} entrée{constellationCount > 1 ? "s" : ""}
</span>
</div>
<p class="scene-section__intro">
Cette notion dialogue avec plusieurs diagnostics et paradigmes qui
permettent den préciser la portée politique, symbolique et
régulatrice.
</p>
<GlossaryPortalSection
id="constellation-theorique"
title="Constellation théorique"
count={`${constellationCount} entrée${constellationCount > 1 ? "s" : ""}`}
intro="Cette notion dialogue avec plusieurs diagnostics et paradigmes qui permettent den préciser la portée politique, symbolique et régulatrice."
>
{otherEntries.length > 0 && (
<div class="scene-block">
<h3>Notions et diagnostics liés</h3>
<GlossaryPortalPanel
id="notions-et-diagnostics-lies"
title="Notions et diagnostics liés"
count={`${otherCount} entrée${otherCount > 1 ? "s" : ""}`}
intro="Ces entrées prolongent la scène dépreuve vers des questions dinstituabilité, de fermeture, dempêchement ou de visibilité de la régulation."
surface={true}
className="scene-block"
>
<div class="scene-cards">
{otherEntries.map((entry) => (
<a class="scene-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>
@@ -250,19 +247,25 @@ const constellationCount = relatedEntries.length;
</a>
))}
</div>
</div>
</GlossaryPortalPanel>
)}
{paradigmEntries.length > 0 && (
<div class="scene-block">
<h3>Paradigmes mobilisés</h3>
<GlossaryPortalPanel
id="paradigmes-mobilises"
title="Paradigmes mobilisés"
count={`${paradigmCount} paradigme${paradigmCount > 1 ? "s" : ""}`}
intro="Ces paradigmes servent de points dappui comparatifs pour mieux comprendre ce qui, dans la scène archicratique, relève de la conflictualité, de lapparition publique ou de la mise en litige de la régulation."
surface={true}
className="scene-block"
>
<div class="scene-cards">
{paradigmEntries.map((entry) => (
<a class="scene-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>
@@ -270,57 +273,31 @@ const constellationCount = relatedEntries.length;
</a>
))}
</div>
</div>
</GlossaryPortalPanel>
)}
</section>
</GlossaryPortalSection>
)}
<section class="scene-section">
<div class="scene-section__head">
<h2 id="prolonger-la-lecture">Prolonger la lecture</h2>
</div>
<p class="scene-section__intro">
Cette page a vocation à devenir un portail intermédiaire entre laccueil
du glossaire et les fiches détaillées. Elle prolonge la lecture vers les
autres parcours déjà stabilisés du système archicratique.
</p>
<GlossaryPortalSection
id="prolonger-la-lecture"
title="Prolonger la lecture"
intro="Cette page a vocation à devenir un portail intermédiaire entre laccueil du glossaire et les fiches détaillées. Elle prolonge la lecture vers les autres parcours déjà stabilisés du système archicratique."
>
<div class="scene-cards">
<a class="scene-card" href="/glossaire/">
<strong>Accueil du glossaire</strong>
<span>
Revenir à la cartographie générale du système archicratique.
</span>
</a>
<a class="scene-card" href="/glossaire/concepts-fondamentaux/">
<strong>Concepts fondamentaux</strong>
<span>
Repartir du noyau conceptuel minimal : arcalité, cratialité, tension,
archicration, co-viabilité, archicratie.
</span>
</a>
<a class="scene-card" href="/glossaire/paradigmes/">
<strong>Paradigmes et doctrines</strong>
<span>
Situer la scène archicratique dans son paysage de comparaison
théorique.
</span>
</a>
<a class="scene-card" href="/glossaire/index-complet/">
<strong>Index complet</strong>
<span>
Retrouver toutes les entrées du glossaire dans lordre alphabétique.
</span>
</a>
{prolongerLinks.map((item) => (
<a class="scene-card" href={item.href}>
<strong>{item.title}</strong>
<span>{item.text}</span>
</a>
))}
</div>
</section>
</GlossaryPortalSection>
<section class="scene-section scene-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Les scènes archicratiques rappellent que la régulation ne vaut jamais
seulement par son efficacité interne. Elle doit aussi pouvoir paraître,
@@ -330,232 +307,13 @@ const constellationCount = relatedEntries.length;
dêtre pure opération pour devenir enjeu politique, symbolique et
collectif.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-scene-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("scene-hero-more");
const heroToggle = document.getElementById("scene-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-scenes-archicratiques-page";
const FOLLOW_ON_CLASS = "scene-follow-on";
const EXPANDED_CLASS = "scene-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(".scene-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="scene-hero-more"
heroToggleId="scene-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -563,138 +321,6 @@ const constellationCount = relatedEntries.length;
padding: 8px 0 24px;
}
.scene-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;
}
.scene-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.scene-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;
}
.scene-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;
}
.scene-hero-collapsible{
display: grid;
row-gap: 6px;
}
.scene-hero-more{
display: grid;
row-gap: 14px;
max-height: 28rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.scene-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;
}
.scene-hero-toggle:hover{
opacity: .84;
}
.scene-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.scene-hero-toggle[hidden]{
display: none !important;
}
.scene-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.scene-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.scene-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.scene-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.scene-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.scene-focus-card{
margin-top: 14px;
padding: 18px 20px;
@@ -746,14 +372,8 @@ const constellationCount = relatedEntries.length;
margin-top: 6px;
}
.scene-block + .scene-block{
margin-top: 22px;
}
.scene-block h3{
margin: 0 0 12px;
font-size: 15px;
line-height: 1.3;
.scene-block{
margin-top: 18px;
}
.scene-cards{
@@ -772,7 +392,10 @@ const constellationCount = relatedEntries.length;
border-radius: 16px;
background: rgba(127,127,127,0.05);
text-decoration: none;
transition: transform 120ms ease, background 120ms ease, border-color 120ms ease;
transition:
transform 120ms ease,
background 120ms ease,
border-color 120ms ease;
}
.scene-card:hover{
@@ -805,142 +428,9 @@ const constellationCount = relatedEntries.length;
opacity: .82;
}
.scene-section--final{
margin-top: 42px;
}
.scene-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.scene-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.scene-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.scene-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.scene-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.scene-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.scene-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.scene-aside__list li{
margin: 6px 0;
}
.scene-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-scenes-archicratiques-page.scene-follow-on .scene-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-scenes-archicratiques-page.scene-follow-on .scene-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-scenes-archicratiques-page.scene-follow-on .scene-intro){
max-width: 72ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-scenes-archicratiques-page.scene-follow-on:not(.scene-hero-expanded) .scene-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-scenes-archicratiques-page.scene-follow-on:not(.scene-hero-expanded) .scene-hero-toggle){
display: inline-flex;
}
:global(body.is-scenes-archicratiques-page.scene-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-scenes-archicratiques-page #reading-follow){
z-index: 10;
}
:global(body.is-scenes-archicratiques-page .scene-section__head.is-sticky),
:global(body.is-scenes-archicratiques-page .scene-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){
.scene-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
row-gap: 12px;
}
.scene-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.scene-hero-toggle{
display: none !important;
}
}
@media (prefers-color-scheme: dark){
.scene-focus-card,
.scene-card,
.scene-aside__block{
.scene-card{
background: rgba(255,255,255,0.04);
}

View File

@@ -1,14 +1,25 @@
---
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 GlossaryPortalPanel from "../../components/GlossaryPortalPanel.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 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 sortByTerm(list = []) {
return [...list].sort((a, b) => collator.compare(a.data.term, b.data.term));
@@ -112,6 +123,53 @@ const irreducibleTensions = [
}));
const tensionsCount = irreducibleTensions.length;
const pageItems = [
{ href: "#orientation", label: "Orientation" },
{ href: "#dix-tensions", label: "Les dix tensions" },
...(foundationEntries.length > 0
? [{ href: "#articulations-fondamentales", label: "Articulations fondamentales" }]
: []),
...(resonanceEntries.length > 0
? [{ href: "#resonances-theoriques", label: "Résonances théoriques" }]
: []),
{ href: "#prolonger-la-lecture", label: "Prolonger la lecture" },
];
const usefulLinks = [
{ href: "/glossaire/tension/", label: "Tension" },
{ href: "/glossaire/scene-depreuve/", label: "Scène dépreuve" },
{ href: "/glossaire/archicration/", label: "Archicration" },
{ href: "/glossaire/co-viabilite/", label: "Co-viabilité" },
{ href: "/glossaire/dynamiques-archicratiques/", label: "Dynamiques archicratiques" },
];
const prolongerLinks = [
{
href: "/glossaire/dynamiques-archicratiques/",
title: "Dynamiques archicratiques",
text:
"Revenir aux processus de fermeture, doblitération et de dérive de la régulation.",
},
{
href: "/glossaire/archicrations/",
title: "Méta-régimes archicratiques",
text:
"Parcourir les grandes formes de co-viabilité qui stabilisent les tensions sans les abolir.",
},
{
href: "/glossaire/paradigmes/",
title: "Paradigmes et doctrines",
text:
"Situer ces tensions dans un paysage théorique plus large.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver lensemble des entrées du glossaire dans une navigation alphabétique intégrale.",
},
];
---
<GlossaryLayout
@@ -120,96 +178,34 @@ const tensionsCount = irreducibleTensions.length;
stickyMode="glossary-portal"
>
<Fragment slot="aside">
<nav class="tir-aside" aria-label="Navigation des tensions irréductibles">
<div class="tir-aside__block">
<a class="tir-aside__back" href="/glossaire/">← Retour au glossaire</a>
<div class="tir-aside__title">Tensions irréductibles</div>
<div class="tir-aside__meta">
{tensionsCount} tension{tensionsCount > 1 ? "s" : ""} structurale{tensionsCount > 1 ? "s" : ""}
</div>
</div>
<div class="tir-aside__block">
<h2 class="tir-aside__heading">Dans cette page</h2>
<ul class="tir-aside__list">
<li><a href="#orientation">Orientation</a></li>
<li><a href="#dix-tensions">Les dix tensions</a></li>
{foundationEntries.length > 0 && (
<li><a href="#articulations-fondamentales">Articulations fondamentales</a></li>
)}
{resonanceEntries.length > 0 && (
<li><a href="#resonances-theoriques">Résonances théoriques</a></li>
)}
<li><a href="#prolonger-la-lecture">Prolonger la lecture</a></li>
</ul>
</div>
<div class="tir-aside__block">
<h2 class="tir-aside__heading">Renvois utiles</h2>
<ul class="tir-aside__list">
<li><a href="/glossaire/tension/">Tension</a></li>
<li><a href="/glossaire/scene-depreuve/">Scène dépreuve</a></li>
<li><a href="/glossaire/archicration/">Archicration</a></li>
<li><a href="/glossaire/co-viabilite/">Co-viabilité</a></li>
<li><a href="/glossaire/dynamiques-archicratiques/">Dynamiques archicratiques</a></li>
</ul>
</div>
</nav>
<GlossaryPortalAside
ariaLabel="Navigation des tensions irréductibles"
title="Tensions irréductibles"
meta={`${tensionsCount} tension${tensionsCount > 1 ? "s" : ""} structurale${tensionsCount > 1 ? "s" : ""}`}
pageItems={pageItems}
usefulLinks={usefulLinks}
/>
</Fragment>
<section class="tir-page" data-tir-page>
<div class="tir-hero glossary-page-hero" data-tir-hero>
<p class="tir-kicker">Parcours du glossaire</p>
<h1>Tensions irréductibles</h1>
<p class="tir-intro">
Cette page rassemble les dix tensions que le chapitre 5 présente comme
<strong> ontologiquement irréductibles</strong> et politiquement fondatrices.
Elles ne se confondent pas avec des tensions simplement sectorielles :
elles désignent des lignes de conflictualité plus profondes, à partir
desquelles une scène archicratique doit organiser la co-viabilité.
</p>
<div class="tir-hero-collapsible">
<div
class="tir-hero-more"
id="tir-hero-more"
data-tir-more
aria-hidden="false"
>
<p class="tir-intro">
Le point décisif nest donc pas de dresser un inventaire conjoncturel
des crises, mais didentifier des foyers structuraux suffisamment
fondamentaux pour traverser durablement les régulations collectives.
</p>
</div>
<button
class="tir-hero-toggle"
id="tir-hero-toggle"
data-tir-more-toggle
type="button"
aria-controls="tir-hero-more"
aria-expanded="false"
hidden
>
lire la suite
</button>
</div>
</div>
<section class="tir-section">
<div class="tir-section__head">
<h2 id="orientation">Orientation</h2>
</div>
<p class="tir-section__intro">
Dans cette perspective, une archicration ne supprime pas les tensions :
elle les met en scène, les distribue, les hiérarchise, les arbitre ou
les rend révisables. Les tensions irréductibles désignent ainsi le plan
à partir duquel devient pensable lexigence même de régulation.
</p>
<section class="tir-page">
<GlossaryPortalHero
prefix="tir"
kicker="Parcours du glossaire"
title="Tensions irréductibles"
intro="Cette page rassemble les dix tensions que le chapitre 5 présente comme ontologiquement irréductibles et politiquement fondatrices. Elles ne se confondent pas avec des tensions simplement sectorielles : elles désignent des lignes de conflictualité plus profondes, à partir desquelles une scène archicratique doit organiser la co-viabilité."
moreParagraphs={[
"Le point décisif nest donc pas de dresser un inventaire conjoncturel des crises, mais didentifier des foyers structuraux suffisamment fondamentaux pour traverser durablement les régulations collectives.",
]}
introMaxWidth="72ch"
followIntroMaxWidth="68ch"
moreMaxHeight="18rem"
/>
<GlossaryPortalSection
id="orientation"
title="Orientation"
intro="Dans cette perspective, une archicration ne supprime pas les tensions : elle les met en scène, les distribue, les hiérarchise, les arbitre ou les rend révisables. Les tensions irréductibles désignent ainsi le plan à partir duquel devient pensable lexigence même de régulation."
>
<div class="tir-note-card">
<strong>Point de méthode</strong>
<p>
@@ -219,23 +215,16 @@ const tensionsCount = irreducibleTensions.length;
culturels — sans se réduire à aucun dentre eux pris isolément.
</p>
</div>
</section>
<section class="tir-section">
<div class="tir-section__head">
<h2 id="dix-tensions">Les dix tensions irréductibles</h2>
<span class="tir-section__count">
{tensionsCount} tension{tensionsCount > 1 ? "s" : ""}
</span>
</div>
<p class="tir-section__intro">
Le chapitre 5 les présente comme les foyers majeurs de conflictualité
auxquels une pensée archicratique doit se confronter.
</p>
</GlossaryPortalSection>
<GlossaryPortalSection
id="dix-tensions"
title="Les dix tensions irréductibles"
count={`${tensionsCount} tension${tensionsCount > 1 ? "s" : ""}`}
intro="Le chapitre 5 les présente comme les foyers majeurs de conflictualité auxquels une pensée archicratique doit se confronter."
>
<div class="tir-cards">
{irreducibleTensions.map((item) => (
{irreducibleTensions.map((item) =>
item.entry ? (
<a class="tir-card tir-card--link" href={hrefOf(item.entry)}>
<div class="tir-card__index">{item.index}</div>
@@ -249,122 +238,94 @@ const tensionsCount = irreducibleTensions.length;
<p>{item.text}</p>
</article>
)
))}
)}
</div>
</section>
</GlossaryPortalSection>
{foundationEntries.length > 0 && (
<section class="tir-section">
<div class="tir-section__head">
<h2 id="articulations-fondamentales">Articulations fondamentales</h2>
<span class="tir-section__count">
{foundationEntries.length} notion{foundationEntries.length > 1 ? "s" : ""}
</span>
</div>
<GlossaryPortalSection
id="articulations-fondamentales"
title="Articulations fondamentales"
count={`${foundationEntries.length} notion${foundationEntries.length > 1 ? "s" : ""}`}
intro="Ces tensions ne prennent sens, dans le glossaire, quen relation avec quelques notions cardinales : la tension elle-même, la scène dépreuve, larchicration, la co-viabilité et larchicratie."
>
<GlossaryPortalPanel
id="notions-cardinales"
title="Notions cardinales"
count={`${foundationEntries.length} repère${foundationEntries.length > 1 ? "s" : ""}`}
surface={true}
className="tir-block"
>
<div class="tir-link-cards">
{foundationEntries.map((entry) => (
<a class="tir-link-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
<p class="tir-section__intro">
Ces tensions ne prennent sens, dans le glossaire, quen relation avec
quelques notions cardinales : la tension elle-même, la scène
dépreuve, larchicration, la co-viabilité et larchicratie.
</p>
<div class="tir-link-cards">
{foundationEntries.map((entry) => (
<a class="tir-link-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
{entry.data.comparisonTraditions?.length > 0 && (
<small>
Traditions de comparaison : {entry.data.comparisonTraditions.join(" / ")}
</small>
)}
</a>
))}
</div>
</section>
{(entry.data.comparisonTraditions?.length ?? 0) > 0 && (
<small>
Traditions de comparaison : {entry.data.comparisonTraditions.join(" / ")}
</small>
)}
</a>
))}
</div>
</GlossaryPortalPanel>
</GlossaryPortalSection>
)}
{resonanceEntries.length > 0 && (
<section class="tir-section">
<div class="tir-section__head">
<h2 id="resonances-theoriques">Résonances théoriques</h2>
<span class="tir-section__count">
{resonanceEntries.length} entrée{resonanceEntries.length > 1 ? "s" : ""}
</span>
</div>
<GlossaryPortalSection
id="resonances-theoriques"
title="Résonances théoriques"
count={`${resonanceEntries.length} entrée${resonanceEntries.length > 1 ? "s" : ""}`}
intro="Plusieurs paradigmes déjà présents dans le glossaire permettent déclairer certains versants de ces tensions : gouvernementalité algorithmique, préemption, cosmopolitique, technodiversité, pharmacologie technique ou légitimation démocratique."
>
<GlossaryPortalPanel
id="paradigmes-et-resonances"
title="Paradigmes et résonances"
count={`${resonanceEntries.length} entrée${resonanceEntries.length > 1 ? "s" : ""}`}
surface={true}
className="tir-block"
>
<div class="tir-link-cards">
{resonanceEntries.map((entry) => (
<a class="tir-link-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
<p class="tir-section__intro">
Plusieurs paradigmes déjà présents dans le glossaire permettent
déclairer certains versants de ces tensions : gouvernementalité
algorithmique, préemption, cosmopolitique, technodiversité,
pharmacologie technique ou légitimation démocratique.
</p>
<div class="tir-link-cards">
{resonanceEntries.map((entry) => (
<a class="tir-link-card" href={hrefOf(entry)}>
<strong>{entry.data.term}</strong>
<span>{entry.data.definitionShort}</span>
{entry.data.mobilizedAuthors?.length > 0 && (
<small>
Auteurs mobilisés : {entry.data.mobilizedAuthors.join(" / ")}
</small>
)}
</a>
))}
</div>
</section>
{(entry.data.mobilizedAuthors?.length ?? 0) > 0 && (
<small>
Auteurs mobilisés : {entry.data.mobilizedAuthors.join(" / ")}
</small>
)}
</a>
))}
</div>
</GlossaryPortalPanel>
</GlossaryPortalSection>
)}
<section class="tir-section">
<div class="tir-section__head">
<h2 id="prolonger-la-lecture">Prolonger la lecture</h2>
</div>
<p class="tir-section__intro">
Cette page fixe le socle conceptuel des tensions irréductibles. Elle
pourra ensuite servir de base à un approfondissement plus détaillé, sans
alourdir laccueil général du glossaire.
</p>
<GlossaryPortalSection
id="prolonger-la-lecture"
title="Prolonger la lecture"
intro="Cette page fixe le socle conceptuel des tensions irréductibles. Elle pourra ensuite servir de base à un approfondissement plus détaillé, sans alourdir laccueil général du glossaire."
>
<div class="tir-link-cards">
<a class="tir-link-card" href="/glossaire/dynamiques-archicratiques/">
<strong>Dynamiques archicratiques</strong>
<span>
Revenir aux processus de fermeture, doblitération et de dérive de
la régulation.
</span>
</a>
<a class="tir-link-card" href="/glossaire/archicrations/">
<strong>Méta-régimes archicratiques</strong>
<span>
Parcourir les grandes formes de co-viabilité qui stabilisent les
tensions sans les abolir.
</span>
</a>
<a class="tir-link-card" href="/glossaire/paradigmes/">
<strong>Paradigmes et doctrines</strong>
<span>
Situer ces tensions dans un paysage théorique plus large.
</span>
</a>
<a class="tir-link-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="tir-link-card" href={item.href}>
<strong>{item.title}</strong>
<span>{item.text}</span>
</a>
))}
</div>
</section>
</GlossaryPortalSection>
<section class="tir-section tir-section--final">
<h2>Portée densemble</h2>
<GlossaryPortalSection
id="portee-densemble"
title="Portée densemble"
final={true}
>
<p>
Les tensions irréductibles ne décrivent pas des accidents secondaires de
la vie collective, mais les lignes de fracture à partir desquelles toute
@@ -373,232 +334,13 @@ const tensionsCount = irreducibleTensions.length;
archicration digne de ce nom doit toujours affronter, mettre en forme et
rouvrir ce qui ne peut être définitivement résorbé.
</p>
</section>
</GlossaryPortalSection>
</section>
<script is:inline>
(() => {
const boot = () => {
const body = document.body;
const root = document.documentElement;
const hero = document.querySelector("[data-tir-hero]");
const follow = document.getElementById("reading-follow");
const heroMore = document.getElementById("tir-hero-more");
const heroToggle = document.getElementById("tir-hero-toggle");
if (!body || !root || !hero || !follow) return;
const BODY_CLASS = "is-tensions-irreductibles-page";
const FOLLOW_ON_CLASS = "tir-follow-on";
const EXPANDED_CLASS = "tir-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(".tir-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="tir-hero-more"
heroToggleId="tir-hero-toggle"
/>
</GlossaryLayout>
<style>
@@ -606,139 +348,6 @@ const tensionsCount = irreducibleTensions.length;
padding: 8px 0 24px;
}
.tir-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;
}
.tir-kicker{
margin: 0;
font-size: 12px;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .72;
}
.tir-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;
}
.tir-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;
}
.tir-hero-collapsible{
display: grid;
row-gap: 6px;
}
.tir-hero-more{
display: grid;
row-gap: 14px;
max-height: 18rem;
overflow: hidden;
opacity: 1;
transition:
max-height 220ms ease,
opacity 180ms ease;
}
.tir-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;
}
.tir-hero-toggle:hover{
opacity: .84;
}
.tir-hero-toggle:focus-visible{
outline: 2px solid rgba(0,217,255,0.24);
outline-offset: 4px;
border-radius: 4px;
}
.tir-hero-toggle[hidden]{
display: none !important;
}
.tir-section{
margin-top: 34px;
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.tir-section h2{
scroll-margin-top: calc(var(--sticky-offset-px, 96px) + 28px);
}
.tir-section__head{
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
position: static;
}
.tir-section__count{
font-size: 13px;
opacity: .72;
white-space: nowrap;
}
.tir-section__intro{
max-width: 78ch;
margin: 0;
opacity: .92;
}
.tir-note-card{
margin-top: 14px;
padding: 16px 18px;
@@ -761,6 +370,10 @@ const tensionsCount = irreducibleTensions.length;
opacity: .92;
}
.tir-block{
margin-top: 18px;
}
.tir-cards{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
@@ -854,155 +467,10 @@ const tensionsCount = irreducibleTensions.length;
opacity: .72;
}
.tir-section--final{
margin-top: 42px;
}
.tir-aside{
display: flex;
flex-direction: column;
gap: 14px;
}
.tir-aside__block{
border: 1px solid rgba(127,127,127,0.22);
border-radius: 16px;
padding: 12px;
background: rgba(127,127,127,0.05);
}
.tir-aside__back{
display: inline-block;
margin-bottom: 8px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
}
.tir-aside__title{
font-size: 14px;
font-weight: 800;
letter-spacing: .2px;
line-height: 1.25;
}
.tir-aside__meta{
margin-top: 8px;
font-size: 12px;
line-height: 1.35;
opacity: .78;
}
.tir-aside__heading{
margin: 0 0 10px;
font-size: 13px;
font-weight: 800;
opacity: .9;
}
.tir-aside__list{
list-style: none;
margin: 0;
padding: 0;
}
.tir-aside__list li{
margin: 6px 0;
}
.tir-aside__list a{
text-decoration: none;
font-size: 13px;
line-height: 1.3;
}
:global(body.is-tensions-irreductibles-page #reading-follow){
z-index: 10;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on .tir-hero){
margin-bottom: 0;
padding: 12px 16px 14px;
row-gap: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on .tir-hero h1){
font-size: clamp(1.9rem, 3.2vw, 2.55rem);
}
:global(body.is-tensions-irreductibles-page.tir-follow-on .tir-intro){
max-width: 68ch;
font-size: .98rem;
line-height: 1.48;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on:not(.tir-hero-expanded) .tir-hero-more){
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on:not(.tir-hero-expanded) .tir-hero-toggle){
display: inline-flex;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on #reading-follow .reading-follow__inner){
border-top-left-radius: 0;
border-top-right-radius: 0;
}
:global(body.is-tensions-irreductibles-page .tir-section__head.is-sticky),
:global(body.is-tensions-irreductibles-page .tir-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){
.tir-hero{
position: static;
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
.tir-intro{
max-width: none;
}
.tir-hero-more{
max-height: none;
opacity: 1;
overflow: visible;
}
.tir-hero-toggle{
display: none !important;
}
:global(body.is-tensions-irreductibles-page.tir-follow-on .tir-hero){
border-radius: 22px;
margin-bottom: 20px;
padding: 14px 14px 16px;
row-gap: 12px;
}
}
@media (prefers-color-scheme: dark){
.tir-note-card,
.tir-card,
.tir-link-card,
.tir-aside__block{
.tir-link-card{
background: rgba(255,255,255,0.04);
}

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/scenes-archicratiques/",
title: "Scènes archicratiques",
text:
"Revenir aux formes de comparution, dépreuve, dempêchement et de réouverture de la régulation.",
},
{
href: "/glossaire/dynamiques-archicratiques/",
title: "Dynamiques archicratiques",
text:
"Explorer les processus de fermeture, doblitération ou de dérive auxquels les verbes de la scène donnent une texture plus fine.",
},
{
href: "/glossaire/paradigme-archicratique/",
title: "Paradigme archicratique",
text:
"Replacer ce mini-glossaire opératoire dans larchitecture générale du système archicratique.",
},
{
href: "/glossaire/index-complet/",
title: "Index complet",
text:
"Retrouver toutes les 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,30 @@ 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="Ce mini-glossaire opératoire complète les portails conceptuels du site. Il permet de décrire plus finement les opérations concrètes qui affectent une scène de régulation."
>
<div class="verbs-cards">
{prolongerLinks.map((item) => (
<a class="verbs-card verbs-card--link" href={item.href}>
<div class="verbs-card__index">↗</div>
<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 +321,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 +335,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));
@@ -688,6 +353,11 @@ const totalCount = sections.reduce((sum, section) => sum + section.items.length,
transition: background 120ms ease, border-color 120ms ease, transform 120ms ease;
}
.verbs-card--link{
text-decoration: none;
color: inherit;
}
.verbs-card:hover{
transform: translateY(-1px);
background: rgba(127,127,127,0.08);
@@ -716,153 +386,8 @@ 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);
}