/* Home, Photos and Books are one place, not three: moving between them fades
   rather than cuts. Progressive enhancement in the strictest sense, a browser
   that does not know this rule shows exactly what it shows today. */
@view-transition { navigation: auto; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

:root {
  --ink: #1a1a1a;
  --ink-soft: #444444;
  --muted: #6b6b6b;
  --muted-soft: #a3a3a3;

  --accent-soft: #d1e3b9;      /* light green wash; --accent is shadowed inside .badge */
  --accent: var(--accent-soft);
  --accent-strong: #7aa84f;
  --accent-text: #4d6b2c;
  --ok: #2faf5a;
  --status: #7bd13f;

  --status-rgb: 123 209 63;
  --accent-strong-rgb: 122 168 79;

  --portrait-bg: #e2c2c2;
  --bg: #f1f2f6;
  --card: #ffffff;
  --frame-bg: #d6d8de;
  --border-soft: rgba(0, 0, 0, .18);

  /* japandi light-wood tones (book shelves) */
  --shelf-wood: #e3d6c0;          /* base tone */
  --shelf-wood-top: #f2ebdd;      /* top surface, catching the light */
  --shelf-wood-face: #dccdb3;     /* vertical front face */
  --shelf-wood-lip: #c5b291;      /* bottom lip, in shade */
  --shelf-edge: rgba(150, 122, 84, .34);

  --shadow-sm: 1px 1px 6px rgba(0, 0, 0, .1);
  --shadow-md: 0 8px 20px rgba(0, 0, 0, .12);

  --font-sans: "Inter", system-ui, -apple-system, sans-serif;
  --font-serif: "Crimson Text", Georgia, serif;
  --font-mono: "Inconsolata", ui-monospace, monospace;
  --font-pixel: "Micro 5", monospace;
  --font-grotesk: "Space Grotesk", system-ui, sans-serif;

  --ink-invert: #ffffff;

  --radius-sm: 6px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-pill: 999px;

  --text-2xs: 11px;
  --text-xs: 12px;
  --text-sm: 13px;
  --text-md: 15px;
  --text-lg: 16px;
  --text-xl: 19px;
  --text-2xl: 22px;
  --text-display: clamp(27px, 3.6vw, 38px);
  --text-hero: clamp(34px, 6vw, 56px);

  /* Inconsolata reads smaller than the sans at the same size, so anything set
     in it runs a pixel up. Its own scale, so the shared one stays untouched
     and the mono can be tuned in one place. */
  --mono-2xs: 12px;
  --mono-xs: 13px;
  --mono-sm: 14px;
  --mono-md: 16px;
  --mono-lg: 17px;

  --leading-none: 1;
  --leading-display: 1.15;
  --leading-tight: 1.25;
  --leading-snug: 1.4;
  --leading-normal: 1.6;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 32px;
  --space-9: 36px;
  --space-10: 40px;
  --space-11: 44px;
  --space-12: 48px;
  --space-13: 52px;
  --space-14: 56px;
  --space-16: 64px;
  --space-18: 72px;
  --space-20: 80px;
  --space-22: 88px;
  --space-24: 96px;

  --dur-press: .16s;
  --dur-fast: .15s;
  --dur: .2s;
  --dur-slow: .7s;
  /* Built-in easings are too soft to read as deliberate: the two curves below
     carry anything that moves, and --ease is left to colour and background,
     where there is no trajectory to shape. */
  --ease: ease;
  --ease-out: cubic-bezier(.23, 1, .32, 1);       /* enters, exits, answers a click */
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);   /* already on screen, moving from A to B */

  --maxw: 1100px;
  --heading-gap: var(--space-13);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* The hidden attribute must win over any display rule set on a component */
[hidden] { display: none !important; }

/* Readable by screen readers, invisible on screen (icon-only controls) */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

html.lenis, html.lenis body { height: auto; }

.lenis.lenis-smooth { scroll-behavior: auto !important; }

.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }

.lenis.lenis-stopped { overflow: hidden; }

.lenis.lenis-smooth iframe { pointer-events: none; }

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
}

.page {
  position: relative;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgb(var(--pulse-rgb) / .6); }
  70%  { box-shadow: 0 0 0 8px rgb(var(--pulse-rgb) / 0); }
  100% { box-shadow: 0 0 0 0 rgb(var(--pulse-rgb) / 0); }
}

/* The same halo, grown on a layer of its own rather than out of a box-shadow.
   Reach for this one wherever the pulse never stops: a shadow that changes size
   repaints its element on every frame, a scaled layer does not. --pulse-scale is
   the ring's final diameter over the dot's own. */
@keyframes pulseRing {
  0%   { transform: scale(1); opacity: 1; }
  70%  { transform: scale(var(--pulse-scale, 2.8)); opacity: 0; }
  100% { transform: scale(var(--pulse-scale, 2.8)); opacity: 0; }
}

/* ---- Infobulle ----
   Un hote en position relative, une bulle au-dessus de l'element. Elle
   n'intercepte jamais le pointeur, sans quoi elle se placerait entre la
   souris et le lien et clignoterait. */
.tip-host {
  position: relative;
  display: inline-flex;
}

.tip {
  /* Le placement passe par ces deux variables : chaque variante n'a plus qu'a
     les redefinir, et le transform reste ecrit une seule fois. */
  --tip-x: -50%;
  --tip-y: 4px;
  position: absolute;
  bottom: calc(100% + var(--space-2));
  left: 50%;
  z-index: 10;
  transform: translate(var(--tip-x), var(--tip-y));
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--mono-xs);
  line-height: 1.3;
  white-space: nowrap;
  text-transform: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}

/* La petite pointe qui rattache la bulle a son element. */
.tip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  border: 5px solid transparent;
  border-top-color: var(--ink);
  transform: translateX(-50%);
}

.tip-host:hover .tip,
.tip-host:focus-within .tip {
  --tip-y: 0px;
  opacity: 1;
}

/* Pour un element colle au bord droit : la bulle s'aligne sur lui plutot que
   de se centrer et de sortir de l'ecran. */
.tip--end { --tip-x: 0; left: auto; right: 0; }
.tip--end::after { left: auto; right: var(--space-3); transform: none; }

/* Pour un element en haut de page : la bulle s'ouvre vers le bas, sinon elle
   sort par le haut de l'ecran. La pointe passe de l'autre cote avec elle. */
.tip--below {
  --tip-y: -4px;
  top: calc(100% + var(--space-2));
  bottom: auto;
}

.tip--below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: var(--ink);
}

/* Une bulle qui ne porte qu'un emoji : plus de fond ni de pointe, l'emoji est
   la bulle. Il lui faut sa propre taille, celle du texte le rendrait minuscule. */
.tip--emoji {
  padding: 0;
  background: none;
  font-size: 30px;
  line-height: 1;
}

.tip--emoji::after { content: none; }

/* La main salue depuis son poignet : le pivot est en bas, sinon l'emoji
   tourne autour de son centre et glisse au lieu de saluer. L'animation est
   portee par une couche interieure, la bulle gardant son transform pour son
   propre placement. Elle ne tourne que pendant le survol, et repart donc du
   debut a chaque fois. */
.tip__wave {
  display: inline-block;
  transform-origin: 60% 90%;
}

.tip-host:hover .tip__wave,
.tip-host:focus-within .tip__wave {
  animation: wave 1.1s var(--ease-in-out) infinite;
}

@keyframes wave {
  0%, 60%, 100% { transform: rotate(0deg); }
  15% { transform: rotate(16deg); }
  30% { transform: rotate(-10deg); }
  45% { transform: rotate(14deg); }
}

@media (prefers-reduced-motion: reduce) {
  .tip-host:hover .tip__wave,
  .tip-host:focus-within .tip__wave { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .tip { transition: none; }
}

/* Deux boutons cote a cote tant que la ligne les accepte ; des qu'elle est
   trop courte, le second passe dessous plutot que de deborder. */
.cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: var(--space-6) 0 var(--space-5);
}

/* ---- Pressable ----
   Everything clickable answers on the way down rather than on release: the
   press is the moment the interface says it heard you. A hover lifts and a
   press sinks, and neither overwrites the other, because each state sets only
   its own variable and the transform composes the two. An element that already
   carries a transform of its own (.back-top here, .shelf__book on the books
   page) repeats the composition with its own base instead of joining the list.
   The list is the one place to edit when a new control appears. */
.btn,
.mail-field,
.copy,
.lang-toggle,
.carousel__arrow,
.view-switch__btn,
.lightbox__btn,
.gallery__item {
  --lift: 0px;
  --press: 1;
  transform: translateY(var(--lift)) scale(var(--press));
}

.btn:active,
.mail-field:active,
.copy:active,
.lang-toggle:active,
.carousel__arrow:active,
.view-switch__btn:active,
.lightbox__btn:active,
.gallery__item:active,
.shelf__book:active,
.back-top:active { --press: .97; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 44px;
  padding: 0 var(--space-5);
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: var(--text-lg);
  text-decoration: none;
  color: var(--ink);
  transition: transform var(--dur-press) var(--ease-out), box-shadow var(--dur-fast) var(--ease);
}

.btn--solid {
  background: var(--card);
  box-shadow: var(--shadow-sm);
}

/* Lifting on hover is motion, and a tap on a touch screen fires hover: gate it,
   or the button rises under the finger and stays there. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { --lift: -2px; box-shadow: var(--shadow-md); }
}

.btn--avatar { padding-left: 8px; }

.btn__avatar {
  position: relative;
  display: block;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--portrait-bg);
  overflow: hidden;
}

.btn__avatar img {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: 23px;
  display: block;
}

/* Understated second half of the "Call me maybe" wink */
.btn__maybe {
  color: var(--muted);
  font-size: .68em;
  font-weight: 500;
}

.btn__icon { flex-shrink: 0; transition: transform var(--dur) var(--ease-out); }

.btn__icon--diag { --icon-nudge: translate(2px, -2px); }

@media (hover: hover) and (pointer: fine) {
  .btn:hover .btn__icon { transform: var(--icon-nudge, translateY(2px)); }
}

@media (prefers-reduced-motion: reduce) {
  .btn__icon { transition: none; }
  .btn:hover .btn__icon { transform: none; }
}

/* The bar in the top corner of every page: page links, outside links and the
   language toggle. Inner pages carry the toggle alone. The face is set once on
   the bar and inherited by what it holds. */
.page-nav {
  position: absolute;
  top: 20px;
  right: 24px;
  z-index: 20;
  display: flex;
  /* Les entrees portent deja leur propre retrait horizontal : l'ecart visible
     entre deux mots vaut cet espace plus le leur. */
  gap: var(--space-2);
  font-family: var(--font-grotesk);
}

/* ---- Menu deroulant ----
   Le declencheur et les entrees portent .nav-link : le menu est la barre qui
   se prolonge vers le bas, meme face et meme survol. Il s'ouvre au survol et
   au clavier, sans JS : rien a synchroniser, rien a fermer. */
.menu { position: relative; }

.menu__trigger {
  border: 0;
  background: none;
  cursor: pointer;
  gap: var(--space-1);
  font: inherit;
}

.menu__caret { transition: transform var(--dur) var(--ease-out); }

.menu__panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 116px;
  /* Le retrait du haut est un pont : le pointeur traverse le vide entre le
     declencheur et le panneau sans jamais quitter le menu. */
  margin-top: var(--space-2);
  padding: var(--space-1);
  border: 1px solid rgba(255, 255, 255, .45);
  /* Le rayon exterieur vaut celui des entrees plus le retrait qui les entoure :
     les deux arrondis restent alors concentriques. */
  border-radius: calc(var(--radius-sm) + var(--space-1));
  /* Meme verre que .live et .back-top : fond opaque par defaut, translucide
     seulement la ou le flou existe (plus bas). */
  background: rgba(255, 255, 255, .72);
  box-shadow: 0 2px 12px rgba(20, 20, 30, .12), inset 0 1px 0 rgba(255, 255, 255, .6);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out),
              visibility var(--dur) var(--ease-out);
}

.menu__panel::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: var(--space-2);
}

.menu:hover .menu__panel,
.menu:focus-within .menu__panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.menu:hover .menu__caret,
.menu:focus-within .menu__caret { transform: rotate(180deg); }

/* Verre depoli la ou le navigateur sait flouter ce qui passe derriere. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .menu__panel {
    background: rgba(255, 255, 255, .38);
    -webkit-backdrop-filter: blur(12px) saturate(170%);
    backdrop-filter: blur(12px) saturate(170%);
  }
}

/* Dans le panneau, les entrees s'empilent et occupent toute la largeur : le
   survol couvre la ligne entiere plutot que le seul mot. */
.menu__item {
  justify-content: flex-start;
  width: 100%;
  height: auto;
  padding: var(--space-2);
}

/* ---- Bandeau vivant ----
   Lu comme un cadran d'instrument : des champs separes par des filets, poses a
   meme la page. Les chiffres sont tabulaires, sinon la ligne respire a chaque
   seconde qui passe. */
.live {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  color: var(--muted);
  font-family: var(--font-grotesk);
  font-size: var(--text-2xs);
  letter-spacing: .5px;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.live__field {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* Le filet appartient au champ qui le suit : ainsi le premier n'en porte pas
   et aucun separateur ne pend en bout de ligne. */
.live__field + .live__field::before,
.live__field--place + .live__field::before {
  content: "";
  width: 1px;
  height: 11px;
  margin-right: var(--space-2);
  background: var(--border-soft);
}

.live__icon { display: inline-flex; opacity: .75; }

/* Le bouton de langue se comporte comme une entree de la barre : meme retrait,
   meme arrondi, meme fond au survol. */
.lang-toggle {
  height: 28px;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  /* A button does not inherit the bar's face on its own */
  font-family: inherit;
  font-size: var(--mono-xs);
  font-weight: 600;
  letter-spacing: .5px;
  cursor: pointer;
  transition: color var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out),
              transform var(--dur-press) var(--ease-out);
}

/* Colour on its own is not motion: it can stay on touch, where it reads as
   the tap being acknowledged. Only what moves is gated. */
.lang-toggle:hover {
  color: var(--ink);
  background-color: var(--accent-soft);
}

/* Un carre plutot qu'un rectangle : le globe n'a pas la largeur d'un mot. */
.lang-toggle__icon { display: block; }

.nav-link {
  display: inline-flex;
  align-items: center;
  height: 28px;
  color: var(--muted);
  font-size: var(--mono-xs);
  font-weight: 600;
  letter-spacing: .5px;
  text-decoration: none;
  /* Le padding est reserve des le repos : le fond du survol a ainsi de la
     place sans decaler la barre au passage de la souris. */
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  transition: color var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out);
}

.nav-link:hover {
  color: var(--ink);
  background-color: var(--accent-soft);
}

.section { padding: var(--space-18) 0; }

.section__label {
  display: block;
  width: fit-content;
  margin: 0 auto;
  color: var(--accent-text);
  font-family: var(--font-mono);
  font-size: var(--mono-sm);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .5px;
}

.section__head {
  max-width: 760px;
  margin: 0 auto var(--heading-gap);
  text-align: center;
}

.section__title {
  margin: var(--space-4) 0 0;
  font-size: var(--text-display);
  font-weight: 800;
  line-height: var(--leading-display);
  letter-spacing: -1px;
}

.pill-list {
  --pill-gap: var(--space-2);
  --pill-padding: var(--space-2) var(--space-4);
  --pill-size: 12px;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--pill-gap);
  margin: 0;
  padding: 0;
}

.pill-list li {
  padding: var(--pill-padding);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-pill);
  font-size: var(--pill-size);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .4px;
}

@media (prefers-reduced-motion: no-preference) {
  /* The transition belongs to the revealed state, never to the hidden one:
     .reveal is set by script.js on a page the visitor is already looking at,
     and an element in view has to be hidden on the spot rather than be seen
     fading out. Coming back in is the only move that animates. */
  .reveal {
      opacity: 0;
      transform: translateY(24px);
    }
  .reveal.is-in {
      opacity: 1;
      transform: none;
      transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
    }
}

.cta--center { justify-content: center; }

.mail-field {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  height: 44px;
  padding: 0 var(--space-4) 0 var(--space-5);
  background: var(--card);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-lg);
  font-weight: 400;
  transition: transform var(--dur-press) var(--ease-out), box-shadow var(--dur-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .mail-field:hover { --lift: -2px; box-shadow: var(--shadow-md); }
}

.mail-field a {
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
}

.copy {
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink); display: grid; place-items: center; padding: var(--space-1);
  border-radius: var(--radius-sm);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease-out);
}

.copy:hover { background: rgba(0, 0, 0, .06); }

.copy.copied { color: var(--ok); }

/* Copying is a thing that either happened or did not, and it happens once in a
   visit: the tick is worth the beat it takes to arrive. Both icons share the
   one grid cell, so one takes over from the other in place. */
.copy__icon {
  grid-area: 1 / 1;
  transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}

.copy__icon--done { opacity: 0; transform: scale(.8); }

.copy.copied .copy__icon:not(.copy__icon--done) { opacity: 0; transform: scale(.8); }

.copy.copied .copy__icon--done { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .copy__icon { transition: opacity var(--dur) var(--ease); transform: none; }
  .copy.copied .copy__icon:not(.copy__icon--done) { transform: none; }
}

/* Progressive blur. One masked strip always shows the line where its blur
   begins; four of them, each blurred a little more than the last and masked to
   its own band, hand over to one another instead, so the page slides out of
   focus rather than crossing an edge. */
.bottom-blur {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 40;
  height: 200px;
  pointer-events: none;
  transition: opacity var(--dur-slow) var(--ease);
}

/* Once the footer is in view the page has been read to the end: there is
   nothing left running under the edge to soften (see script.js). */
.bottom-blur.is-out { opacity: 0; }

/* Each layer only differs by how much it blurs and by the band it is masked to,
   so those are the only two things a layer states. */
.bottom-blur__layer {
  position: absolute;
  inset: 0;
  -webkit-backdrop-filter: blur(var(--depth));
  backdrop-filter: blur(var(--depth));
  -webkit-mask-image: var(--band);
  mask-image: var(--band);
}

.bottom-blur__layer:nth-child(1) {
  --depth: .1px;
  --band: linear-gradient(to bottom, transparent 0%, #000 25%, #000 50%, transparent 75%);
}

.bottom-blur__layer:nth-child(2) {
  --depth: .5px;
  --band: linear-gradient(to bottom, transparent 25%, #000 50%, #000 75%, transparent 100%);
}

.bottom-blur__layer:nth-child(3) {
  --depth: 1.5px;
  --band: linear-gradient(to bottom, transparent 50%, #000 75%, #000 100%);
}

.bottom-blur__layer:nth-child(4) {
  --depth: 5px;
  --band: linear-gradient(to bottom, transparent 75%, #000 100%);
}

.footer {
  position: relative;
  margin-top: var(--space-10);
  padding: var(--space-14) 0 var(--space-10);
  text-align: center;
}

/* The credit closes the page, on the centre line. */
.footer__credit {
  max-width: var(--maxw);
  margin: var(--space-4) auto 0;
  padding: 0 var(--space-6);
  color: var(--muted);
  font-size: var(--text-sm);
  text-align: center;
}

@media (max-width: 860px) {
  .cta { justify-content: center; }
  /* Le hero s'empile : la barre prend toute la largeur pour l'accompagner.
     Les deux pages a gauche, le reste pousse contre le bord droit. */
  .page-nav--home {
    left: 24px;
    right: 24px;
  }
  .page-nav--home .menu { margin-left: auto; }
}

@media (max-width: 560px) {
  .page-nav--home {
      left: 16px;
      right: 16px;
    }
  .page { padding: 0 var(--space-4); }
  .footer__credit { padding: 0 var(--space-4); }
}

.home-link {
  position: absolute;
  top: 20px;
  left: 24px;
  z-index: 20;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--mono-sm);
  font-weight: 600;
  letter-spacing: .5px;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}

.home-link:hover { color: var(--ink); }

/* Floating glass pill: stays visible wherever the reader is on the page */
.back-top {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: 50;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px var(--space-3);
  border-radius: var(--radius-pill);
  border: 1px solid rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .72); /* opaque fallback where backdrop-filter is unsupported */
  box-shadow: 0 2px 12px rgba(20, 20, 30, .08), inset 0 1px 0 rgba(255, 255, 255, .6);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--mono-2xs);
  font-weight: 500;
  letter-spacing: .4px;
  text-transform: uppercase;
  text-decoration: none;
  /* Hidden until the reader has scrolled away from the top (see script.js).
     Composed like the other pressables: the pill's own travel and the press
     each own a variable, so arriving and being clicked never fight. */
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  --lift: 8px;
  --press: 1;
  transform: translateY(var(--lift)) scale(var(--press));
  transition: color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
              transform var(--dur) var(--ease-out), background var(--dur-fast) var(--ease),
              opacity var(--dur) var(--ease), visibility var(--dur) var(--ease);
}

.back-top.is-visible {
  opacity: .72;
  visibility: visible;
  pointer-events: auto;
  --lift: 0px;
}

/* Frosted glass where the browser can blur what sits behind the pill */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .back-top {
    background: rgba(255, 255, 255, .38);
    -webkit-backdrop-filter: blur(12px) saturate(170%);
    backdrop-filter: blur(12px) saturate(170%);
  }
}

/* Comes forward only on intent */
.back-top.is-visible:hover {
  opacity: 1;
  color: var(--ink);
  background: rgba(255, 255, 255, .6);
  box-shadow: 0 6px 22px rgba(20, 20, 30, .14), inset 0 1px 0 rgba(255, 255, 255, .75);
  transform: translateY(-2px);
}

/* The link is fixed, so the wrapper only holds end-of-page breathing room */
.back-top__wrap { padding: var(--space-6) 0 var(--space-2); }

@media (max-width: 560px) {
  .back-top {
    right: var(--space-4);
    bottom: var(--space-4);
    padding: var(--space-2) var(--space-3);
  }
}
