/* ==========================================================================
   6ty.Plus — Site
   Hierarchy: space → light → image → typography → content → interface
   ========================================================================== */

/* ── Base ──────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--paper);
  color: var(--ink-body);
  transition: background-color var(--dur-atmos) var(--ease-atmos);
}

body {
  margin: 0;
  font-family: var(--font-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
  color: var(--ink-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* paper grain — the tactile layer; composited once, never animated */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  background-image: var(--grain);
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }

/* [hidden] must win over any component's display rule — otherwise a control
   marked hidden (e.g. a sound invite in a silent atmosphere) stays on screen */
[hidden] { display: none !important; }
ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }
img, svg { display: block; max-width: 100%; }
button { font: inherit; color: inherit; }

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.38em;
  text-decoration-color: color-mix(in oklab, currentColor 32%, transparent);
  transition: text-decoration-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
a:hover { text-decoration-color: currentColor; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: var(--radius-subtle);
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  inset-block-start: 0.75rem;
  inset-inline-start: 0.75rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-meta);
  font-size: var(--fs-nav);
  border-radius: var(--radius-medium);
  transform: translateY(-160%);
}
.skip-link:focus { transform: none; }

/* ── Quiet type roles ──────────────────────────────────────────────────── */

/* Latin room / atmosphere names — the house vocabulary */
.label {
  font-family: var(--font-meta);
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  line-height: var(--lh-meta);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.label a { text-decoration: none; }
.label a:hover { color: var(--ink); }

/* small Thai text — never letterspaced */
.meta {
  font-family: var(--font-meta);
  font-size: 0.9375rem;
  font-weight: var(--fw-regular);
  line-height: 1.75;
  color: var(--ink-muted);
}

.sep { margin-inline: 0.55em; opacity: 0.6; }

/* ── Header · quiet navigation ─────────────────────────────────────────── */

.site-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: 1.1rem var(--space-page);
  transition:
    background-color var(--dur-gentle) var(--ease-out),
    box-shadow var(--dur-gentle) var(--ease-out),
    transform var(--dur-gentle) var(--ease-out);
  view-transition-name: site-header;
}
/* no bar behind the header, ever — the logo floats on the page with its own glow (owner, Sep 2026) */

.wordmark {
  font-family: var(--font-text);
  font-size: 1.125rem;
  font-weight: var(--fw-medium);
  letter-spacing: 0.02em;
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
  padding-block: 0.6rem;
}
.wordmark span { font-weight: var(--fw-light); color: var(--ink-muted); }
.wordmark { display: inline-flex; align-items: center; gap: 0.7rem; }
/* the open mark keeps its edge over photographs. Light pages: a dark shadow (owner, 27 Sep 2026 — the pale halo let the
   green vanish into light photographs); a tight one for the edge, a soft one for depth. Dark pages keep the paper halo. */
.wordmark__logo {
  width: 2.75rem; height: 2.75rem; flex: none;
  filter: drop-shadow(0 1px 1px rgb(20 14 8 / 0.55)) drop-shadow(0 0.15rem 0.6rem rgb(20 14 8 / 0.4));
}
:root[data-theme="dark"] .wordmark__logo { filter: drop-shadow(0 0 0.5rem color-mix(in oklab, var(--paper) 60%, transparent)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .wordmark__logo { filter: drop-shadow(0 0 0.5rem color-mix(in oklab, var(--paper) 60%, transparent)); }
}

/* ==========================================================================
   Scene — the image layer, drawn in light.
   Placeholder for real photography (see DESIGN_DECISIONS.md → Image direction).
   Every scene shares the same markup:
     <div class="scene" data-scene="…"><span class="scene__light"><i>×6</i></span><span class="scene__detail"></span></div>
   ========================================================================== */

.scene {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(120% 90% at 72% 18%, color-mix(in oklab, var(--light) 28%, transparent), transparent 62%),
    linear-gradient(180deg, var(--wall) 0%, var(--wall) 58%, var(--wall-shade) 100%);
  border-radius: var(--radius-subtle);
}

/* grain on the image itself, a touch stronger than on paper */
.scene::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background-image: var(--grain);
  opacity: calc(var(--grain-opacity) * 1.6);
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* the patch of light a window throws onto the wall */
.scene__light {
  position: absolute;
  /* --win-scale enlarges the window on narrow screens and pulls it toward the left */
  left: calc(var(--win-x) * (2 - var(--win-scale, 1)) + 4% * (var(--win-scale, 1) - 1));
  top: var(--win-y);
  width: calc(var(--win-w) * var(--win-scale, 1));
  aspect-ratio: 3 / 4.2;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, 1fr);
  gap: clamp(9px, 1.4vw, 20px);
  transform: skewX(var(--light-skew)) rotate(var(--light-rotate));
  filter: blur(var(--light-blur));
  opacity: var(--light-strength);
  transition: opacity 4s var(--ease-atmos);
  animation: light-drift var(--dur-ambient) var(--ease-in-out) infinite alternate;
  will-change: transform;
}
/* brighter where the sun is, softer toward the far edge */
.scene__light i {
  background: linear-gradient(165deg, var(--light) 20%, color-mix(in oklab, var(--light) 55%, transparent));
  border-radius: 2px;
}

.scene__detail { position: absolute; pointer-events: none; }

/* while listening, the room warms very slightly */
:root[data-listening] .scene:not([data-scene="night"]) .scene__light { opacity: min(1, calc(var(--light-strength) + 0.14)); }

@keyframes light-drift {
  from { translate: 0 0;      rotate: 0deg; }
  to   { translate: -1.6% 1.2%; rotate: 0.8deg; }
}

/* ── window · leaves moving in the light ── */
[data-scene="window"] .scene__detail {
  left: calc(var(--win-x) - 6%);
  top: calc(var(--win-y) + 4%);
  width: calc(var(--win-w) + 16%);
  aspect-ratio: 1;
  background:
    radial-gradient(28% 14% at 22% 30%, var(--shadow-tone), transparent 70%),
    radial-gradient(18% 10% at 40% 22%, var(--shadow-tone), transparent 70%),
    radial-gradient(22% 12% at 64% 48%, var(--shadow-tone), transparent 70%),
    radial-gradient(14% 9% at 30% 62%, var(--shadow-tone), transparent 70%),
    radial-gradient(20% 11% at 76% 28%, var(--shadow-tone), transparent 70%);
  filter: blur(5px);
  mix-blend-mode: multiply;
  opacity: 0.7;
  animation: leaves-sway 17s var(--ease-in-out) infinite alternate;
  transform-origin: 20% 0%;
}
@keyframes leaves-sway {
  from { transform: rotate(-1.2deg) translate(0, 0); }
  to   { transform: rotate(1deg) translate(1.2%, 0.6%); }
}

/* ── table · light falling across a surface, a trace of something out of frame ── */
[data-scene="table"] {
  --table-far:  color-mix(in oklab, var(--accent) 22%, var(--wall));
  --table-near: color-mix(in oklab, var(--accent) 42%, var(--wall-shade));
  background:
    linear-gradient(180deg, transparent 0 44%, rgb(0 0 0 / 0.08) 44%, transparent 47%),
    linear-gradient(180deg, var(--wall) 0%, var(--wall) 44%, var(--table-far) 44%, var(--table-near) 100%);
}
[data-scene="table"] .scene__light {
  top: 50%;
  left: 20%;
  width: 46%;
  aspect-ratio: 3 / 2.6;
  transform: perspective(700px) rotateX(58deg) skewX(-26deg);
  animation-duration: 90s;
}
[data-scene="table"] .scene__detail {
  left: 36%;
  top: 60%;
  width: 34%;
  height: 7%;
  background: var(--shadow-tone);
  border-radius: 50%;
  filter: blur(7px);
  transform: rotate(-17deg) skewX(-30deg);
  opacity: 0.9;
}

/* ── night · one lamp in the room; almost still ──
   Also used by the arrival when the house is in its night light. */
[data-scene="night"],
:root[data-light="night"] .arrival .scene {
  --wall: #2A2520;
  --wall-shade: #141210;
  --lamp: #F2C688;
  background:
    radial-gradient(60% 70% at 18% 82%, color-mix(in oklab, var(--lamp) 42%, transparent), transparent 62%),
    radial-gradient(26% 30% at 18% 88%, color-mix(in oklab, var(--lamp) 60%, transparent), transparent 70%),
    linear-gradient(180deg, var(--wall) 0%, var(--wall-shade) 100%);
}
[data-scene="night"] .scene__light,
:root[data-light="night"] .arrival .scene .scene__light {
  --light: #B9C7D6;
  left: 58%; top: 8%; width: 22%;
  transform: skewX(-8deg);
  opacity: 0.12;
  filter: blur(20px);
  animation: none;
}
:root[data-listening][data-light="night"] .arrival .scene .scene__light { opacity: 0.18; }
[data-scene="night"] .scene__detail,
:root[data-light="night"] .arrival .scene .scene__detail {
  inset: auto;
  left: 12%; bottom: 0; width: 22%; height: 26%;
  aspect-ratio: auto;
  background: radial-gradient(50% 30% at 50% 100%, rgb(0 0 0 / 0.35), transparent 70%);
  filter: none;
  mix-blend-mode: normal;
  animation: none;
}

/* ── rain · soft, repetitive; light diffused through a wet window ── */
/* note: a custom property can't reference itself (--light: mix(var(--light)) is a cycle),
   so the rain tones are mixed directly where they're painted */
[data-scene="rain"] {
  background:
    radial-gradient(90% 70% at 60% 20%, color-mix(in oklab, var(--light) 30%, transparent), transparent 65%),
    linear-gradient(180deg,
      color-mix(in oklab, var(--wall) 74%, #A9B5BA) 0%,
      color-mix(in oklab, var(--wall-shade) 70%, #8E9BA0) 100%);
}
[data-scene="rain"] .scene__light { filter: blur(22px); opacity: calc(var(--light-strength) * 0.85); }
[data-scene="rain"] .scene__light i { background: color-mix(in oklab, var(--light) 55%, #E6EEF1); }
[data-scene="rain"] .scene__detail {
  inset: -100% 0 0 0;
  background:
    repeating-linear-gradient(98deg, transparent 0 17px, rgb(255 255 255 / 0.07) 17px 18px),
    repeating-linear-gradient(94deg, transparent 0 29px, rgb(255 255 255 / 0.05) 29px 30px);
  filter: blur(0.6px);
  animation: rain-fall 38s linear infinite;
}
@keyframes rain-fall { to { transform: translateY(50%); } }

/* ── horizon · wide distance; road, sky, haze ── */
[data-scene="horizon"] {
  background:
    linear-gradient(180deg, color-mix(in oklab, var(--light) 30%, var(--wall)) 0%, var(--wall) 60%, transparent 60%),
    linear-gradient(180deg, transparent 60%, color-mix(in oklab, var(--wall-shade) 70%, var(--ink) 8%) 60%, var(--wall-shade) 100%);
}
[data-scene="horizon"] .scene__light {
  left: -10%; top: 46%; width: 120%;
  aspect-ratio: 12 / 1;
  display: block;
  background: var(--light);
  border-radius: 50%;
  transform: none;
  filter: blur(28px);
  animation-duration: 80s;
}
[data-scene="horizon"] .scene__light i { display: none; }
[data-scene="horizon"] .scene__detail {
  left: 48%; top: 60%; width: 4%; height: 40%;
  background: linear-gradient(180deg, transparent, color-mix(in oklab, var(--light) 50%, transparent));
  clip-path: polygon(48% 0, 52% 0, 100% 100%, 0 100%);
  opacity: 0.55;
}

/* ==========================================================================
   Photo — a real photograph resting on top of its light study.
   If the file is missing or slow, the light underneath is what the reader sees;
   nothing ever collapses into an empty box (WEB_IMPLEMENTATION §38).
   ========================================================================== */

.photo { position: relative; overflow: hidden; isolation: isolate; }
.photo .scene { position: absolute; inset: 0; height: 100%; border-radius: inherit; }
.photo img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focus, 50% 50%);
}
/* art direction for narrow screens: --focus-sm moves the crop, no second file */
@media (max-width: 40rem) {
  .photo img { object-position: var(--focus-sm, var(--focus, 50% 50%)); }
}
.photo img.is-loading { opacity: 0; }
.photo img.is-loaded { animation: settle var(--dur-atmos) var(--ease-atmos) both; }

/* keeps typography readable where it sits over a photograph, and lets the
   image settle into the paper instead of ending on a hard edge */
.photo--scrim::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(to bottom, color-mix(in oklab, var(--paper) 62%, transparent), transparent 13%),
    linear-gradient(to right, color-mix(in oklab, var(--paper) 72%, transparent), transparent 48%),
    linear-gradient(to top, var(--paper) 2%, color-mix(in oklab, var(--paper) 45%, transparent) 22%, transparent 52%);
}

/* scenes rest when off-screen — battery matters (MOTION_SYSTEM §24) */
.scene.is-resting *,
.scene.is-resting::before { animation-play-state: paused; }

/* ==========================================================================
   Motion · entrances and reveals
   ========================================================================== */

@keyframes arrive {
  from { opacity: 0; transform: translateY(var(--move-small)); }
  to   { opacity: 1; transform: none; }
}
@keyframes settle {
  from { opacity: 0; transform: scale(1.025); }
  to   { opacity: 1; transform: none; }
}

/* JS adds .can-reveal only when it can also reveal; content never depends on it */
.can-reveal .reveal:not(.is-visible) {
  opacity: 0;
  transform: translateY(var(--move-medium));
}
.can-reveal .reveal {
  transition: opacity var(--dur-atmos) var(--ease-atmos), transform var(--dur-atmos) var(--ease-atmos);
}

/* ==========================================================================
   Home · the entrance
   ========================================================================== */

.arrival {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  isolation: isolate;
}
.arrival > .photo,
.arrival > .scene {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 0;
  mask-image: linear-gradient(180deg, #000 76%, transparent);
}

.arrival__inner {
  align-self: end;
  padding-inline: max(var(--space-page), 9vw) var(--space-page);
  padding-block: 8rem clamp(2.5rem, 9vh, 6rem);
}

.arrival__line {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  font-weight: var(--fw-light);
  color: var(--ink);
}
.arrival__line .l {
  display: block;
  animation: arrive var(--dur-atmos) var(--ease-atmos) both;
}
.arrival__line .l + .l      { animation-delay: 0.6s; padding-inline-start: 0.9em; }
.arrival__line .l + .l + .l { animation-delay: 1.2s; padding-inline-start: 1.8em; }

/* mobile: intimate, not compressed — the window comes closer, the lines stay whole */
@media (max-width: 40rem) {
  .arrival > .scene { --win-scale: 1.8; }
  .arrival__inner { padding-inline: var(--space-page); }
  .arrival__line .l + .l      { padding-inline-start: 0.6em; }
  .arrival__line .l + .l + .l { padding-inline-start: 1.2em; }
}

.arrival__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem var(--space-md);
  padding: 0 var(--space-page) var(--space-md);
  animation: arrive var(--dur-atmos) var(--ease-atmos) 2s both;
}
/* the home page has no player until the reader presses play (owner): the invitation stays in the entrance */
.arrival__story { color: inherit; text-decoration: none; transition: color var(--dur-gentle) var(--ease-out); }
.arrival__story:hover, .arrival__story:focus-visible { color: var(--ink); }
.arrival__story::after { content: " →"; opacity: 0.6; }


/* The breathing ring — like a person actually breathing at rest (owner), centred on the wordmark.
   Not a metronome: site.js draws each breath a little different — a quicker inhale that slows at the top,
   a passive exhale that falls then settles, a short pause, and now and then a deeper sigh.
   It rests when the entrance is out of view, and stands still for readers who ask for less motion. */
.breathe {
  position: fixed;   /* stays with the logo all the way down, on every page (owner) */
  inset: 0;
  z-index: 49;   /* just beneath the logo; faint 1px lines, so words passing under them still read */
  overflow: hidden;   /* the ring runs off the screen edge, never widens the page */
  pointer-events: none;
  --cx: calc(var(--space-page) + 1.375rem);
  --cy: 3.075rem;
  view-transition-name: breathe;   /* stays with the logo from page to page, not cross-faded with the page */
}
/* site.js measures the logo into --cx / --cy and breathes --breath from 0 (out) to about 1 (in) */
/* Before site.js measures, the rings already sit on the logo: its centre worked out from the header's own spacing
   (padding 1.1rem + the mark's 0.6rem + half of its 2.75rem). Without this they sat mid-screen for the first frames of
   every page — and for the whole 900ms cross-fade between pages (owner). */
.breathe svg {
  position: absolute;
  left: var(--cx, 50%);
  top: var(--cy, 50%);
  translate: -50% -50%;
  width: min(62vmin, 34rem);
  aspect-ratio: 1;
  overflow: visible;
  overflow: visible;
  will-change: transform;
}
/* three rings, one behind the other, each a moment later — a breath moving through, not one line pulsing (owner) */
.breathe circle {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1px;
  transform-origin: center;
  transform: scale(var(--s, 1));
  opacity: calc((0.3 + 0.28 * var(--o, 0.4)) * var(--fade, 1));
}
.breathe circle[data-ring="1"] { --fade: 0.66; }
.breathe circle[data-ring="2"] { --fade: 0.42; }
@media (max-width: 40rem) {
  .breathe svg { width: 78vw; }
}

/* ── Scroll cue: there is more below (owner) ──────────────────────────────
   Pages that open on a whole photograph (home, story, about) give no sign that they go on. A hairline at the foot
   of the screen, light running slowly down it — never a bounce or a blink (MOTION_SYSTEM). It waits until the
   photograph has been seen (2.5s), and leaves for good at the first scroll. Still, for readers who ask for less motion. */
.scroll-cue { display: none; }
.page-home .scroll-cue,
.page-article .scroll-cue,
.page-about .scroll-cue,
.page-colour .scroll-cue,
.page-room .scroll-cue {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  position: fixed;
  left: 50%;
  bottom: 0.9rem;
  z-index: 45;
  translate: -50% 0;
  pointer-events: none;
  opacity: 0;
  animation: cue-in 1.6s var(--ease-atmos) 2.5s forwards;
  transition: opacity 0.6s var(--ease-out);
}
/* the line: 2px and a little brighter than first tried, so it is found (owner: A) */
.scroll-cue i {
  position: relative;
  width: 2px;
  height: 2.5rem;
  overflow: hidden;
  border-radius: 1px;
  background: color-mix(in oklab, var(--ink) 35%, transparent);
}
.scroll-cue i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, transparent, var(--ink) 50%, transparent);
  translate: 0 -100%;
  animation: cue-run 2.8s var(--ease-atmos) 2.5s infinite;
}
/* the words, first visit only (owner: "เมื่อพร้อม ค่อยไปต่อ"): small and quiet, with the same soft halo the other words on photographs have */
.scroll-cue span {
  font-family: var(--font-meta);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  white-space: nowrap;   /* "เมื่อพร้อม ค่อยไปต่อ" (owner) on one line */
  color: var(--ink-body);
  text-shadow: 0 0 0.5em var(--paper), 0 0 1.2em color-mix(in oklab, var(--paper) 85%, transparent);
}
:root[data-scrolled] .scroll-cue { opacity: 0 !important; animation: none; }
:root[data-cue-known] .scroll-cue span { display: none; }   /* after the first visit: the line alone (owner) */
/* phones: the title sits at the foot of the first screen — a shorter line keeps the cue clear of it */
@media (max-width: 40rem) {
  .page-home .scroll-cue, .page-article .scroll-cue, .page-about .scroll-cue { bottom: 0.6rem; gap: 0.25rem; }
  .scroll-cue i { height: 1.25rem; }
}
@keyframes cue-in { to { opacity: 1; } }
@keyframes cue-run { 0% { translate: 0 -100%; } 70%, 100% { translate: 0 100%; } }
@media (prefers-reduced-motion: reduce) {
  .scroll-cue i::after { animation: none; translate: 0 0; opacity: 0.6; }
}

[data-for-light] { display: none; }
:root[data-light="morning"]   [data-for-light="morning"],
:root[data-light="afternoon"] [data-for-light="afternoon"],
:root[data-light="evening"]   [data-for-light="evening"],
:root[data-light="night"]     [data-for-light="night"] { display: inline; }

/* tinted sections — another room's light, fading in and out of the house paper */
.tint {
  background: linear-gradient(180deg, var(--house-paper), var(--paper) 16%, var(--paper) 84%, var(--house-paper));
}

.feeling { padding-block: var(--space-section); }
.feeling__intro {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  margin-block-end: var(--space-xl);
}
.feeling__intro > * { max-width: 34rem; }
.feeling__line {
  margin-block-start: 0.9rem;
  font-size: var(--fs-subtitle);
  line-height: 1.75;
  font-weight: var(--fw-light);
  color: var(--ink);
}

/* ── piece · an article entry, like an object placed in a room ── */

.piece { position: relative; }
.piece__image { overflow: hidden; border-radius: var(--radius-subtle); }
.piece__image .scene { height: 100%; transition: filter var(--dur-gentle) var(--ease-out); }
.piece:hover .piece__image .scene { filter: brightness(1.035); }

.piece__place { margin-block-end: 0.35rem; }
.piece__title {
  font-size: clamp(1.4375rem, 1.2rem + 0.9vw, 1.875rem);
  line-height: 1.55;
  font-weight: var(--fw-regular);
  color: var(--ink);
  text-wrap: balance;
}
.piece__title a { text-decoration-color: transparent; }
.piece__title a:hover { text-decoration-color: currentColor; }
/* whole piece is clickable, but only the title is the link's name */
.piece__title a::after { content: ""; position: absolute; inset: 0; z-index: 4; }
.piece__title a:focus-visible { outline: none; }
.piece:has(.piece__title a:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 8px;
  border-radius: var(--radius-subtle);
}
/* a piece that has not been written yet — present in the room, not yet a door */
.piece__title.is-unwritten { color: var(--ink-muted); }
.piece__excerpt {
  margin-block-start: 0.6rem;
  font-size: 1.0625rem;
  line-height: 1.9;
  color: var(--ink-muted);
}
.piece__more {
  display: inline-block;
  margin-block-start: 1rem;
  font-family: var(--font-meta);
  font-size: var(--fs-nav);
  color: var(--accent);
}

.piece--feature {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-md);
  align-items: end;
}
.piece--feature .piece__image { grid-column: 1 / span 8; aspect-ratio: 4 / 3; }
.piece--feature .piece__text  { grid-column: 9 / -1; padding-block-end: var(--space-sm); }

@media (max-width: 52rem) {
  .piece--feature { display: block; }
  .piece--feature .piece__image { aspect-ratio: 5 / 4; margin-block-end: var(--space-md); }
  .piece--feature .piece__text { max-width: 30rem; }
}

/* ── pause · a thread of space ── */
.pause {
  display: grid;
  place-items: center;
  height: clamp(7rem, 18vh, 12rem);
}
.pause span { width: 1px; height: 55%; background: var(--line); }

/* ── the entrance stays; the six rooms fade in over it, one at a time (owner) ──
   Nothing rises: the rooms section is a scroll track laid over the pinned entrance (pulled up by one screen);
   its stage is pinned too, so scrolling only turns up the veil and then each door, in order (site.js sets
   --veil, --head-in and each door's --in from 0 to 1). After the sixth door the track ends and the page moves on. */
.page-home .arrival { position: sticky; top: 0; z-index: 0; }
.page-home main > :not(.arrival) { position: relative; z-index: 1; background-color: var(--paper); }
/* The Music Room waits in the same place, pinned top and bottom, invisible until the doors let go; it then
   comes up where they were and, once the scene ends, scrolls on with the footer like any section */
.page-home main > .place {
  position: sticky;
  top: 0;
  bottom: 0;
  height: 100svh;
  opacity: var(--music-in, 0);
}
.page-home main > .place:not([data-shown]) { visibility: hidden; }
.page-home .place__inner { opacity: calc(var(--music-in, 0) * 1.4 - 0.4); }   /* its words a moment after the picture */
@media (prefers-reduced-motion: reduce) {
  .page-home main > .place { position: relative; height: auto; min-height: 100svh; opacity: 1; visibility: visible; }
  .page-home .place__inner { opacity: 1; }
  .page-home main > .rooms { height: auto; }
}
.page-home .place > .photo { mask-image: linear-gradient(180deg, transparent, #000 14%); }   /* runs to the bottom, under the footer */
/* where the footer lies on the photograph, the paper deepens to ≥90% so its small grey text keeps ≥5:1 */
.page-home .place .photo--scrim::after {
  background:
    linear-gradient(to top, color-mix(in oklab, var(--paper) 92%, transparent) calc(var(--footer-h, 6rem) * 0.8), transparent calc(var(--footer-h, 6rem) + 8rem)),
    linear-gradient(to right, color-mix(in oklab, var(--paper) 88%, transparent) 8%, transparent 58%),
    linear-gradient(to top, var(--paper) 2%, color-mix(in oklab, var(--paper) 40%, transparent) 26%, transparent 60%);
}
.page-home main > .rooms {
  background: none;
  height: calc(100svh + 270svh);   /* the whole scene: entrance dims, six colours (quicker than the rooms were — owner), a hold, then the Music Room (site.js) */
  margin-block-start: -100svh;
  padding: 0;
  pointer-events: none;   /* it lies over the entrance from the start: clicks pass through to the first screen (owner: the corner link could not be pressed) */
}
.page-home .rooms__inner {
  position: sticky;
  top: 0;
  width: auto;
  height: 100svh;
  display: grid;
  align-content: center;
  padding-inline: max(var(--space-page), calc((100% - var(--measure-wide)) / 2));
}
.page-home .room-entry { pointer-events: auto; }   /* only the colours take them, and only once shown (visibility hides the rest) */
/* the veil: page colour over the entrance, 92% at most so the room is still faintly there */
.page-home .rooms__inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--paper);
  opacity: calc(0.92 * var(--veil, 0));
  transition: background-color var(--dur-atmos) var(--ease-atmos);
}
.page-home .rooms__head { opacity: var(--head-in, 0); }
.page-home .rooms__list { border-top-color: color-mix(in oklab, var(--ink) calc(14% * var(--head-in, 0)), transparent); }
.page-home .room-entry { opacity: var(--in, 0); }
.page-home .room-entry:not([data-shown]) { visibility: hidden; }   /* an unseen door cannot be clicked or tabbed to */
/* the entrance keeps its picture but lets go of its words first, so they never sit under the doors */
.page-home .arrival__inner,
.page-home .arrival__foot > .meta { opacity: calc(1 - var(--veil, 0)); }
@media (prefers-reduced-motion: reduce) {
  .page-home main > .rooms { height: auto; margin-block-start: 0; }
  .page-home .rooms__inner { position: static; height: auto; padding-block: var(--space-section); }
  .page-home .rooms__inner::before { opacity: 1; }
  .page-home .rooms__head, .page-home .room-entry { opacity: 1; visibility: visible; }
  .page-home .arrival { position: relative; }
}

/* ── the breath question: six colours in a ring around the question (owner) ──
   Colour alone never carries the choice: every colour has its name (colour-blind readers, owner). */
.breath__ring {
  position: relative;
  width: min(84vmin, 42rem);
  aspect-ratio: 1;
  margin-inline: auto;
  --r: calc(min(84vmin, 42rem) / 2 - 4.5rem);   /* ring radius, leaving room for the names */
}
.breath__head {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 0 22%;
  text-align: center;
}
/* the question and, under it, the quiet line to breathe instead (owner, 27 Sep 2026) */
.breath__head { align-content: center; gap: 0.6rem; }
.breath__alone {
  background: none;
  border: 0;
  padding: 0.35rem 0.5rem;
  font-family: var(--font-meta);
  font-size: 0.9375rem;
  color: var(--ink-muted);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
}
.breath__alone:hover { color: var(--ink); }
/* phones: the ring is small — one line, a size smaller, so it never wraps into the colours */
@media (max-width: 40rem) {
  .breath__head { gap: 0.2rem; }
  .breath__alone { font-size: 0.8125rem; white-space: nowrap; padding: 0.5rem 0.25rem; }
}
.breath__alone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
/* pressable only once the question has come up (site.js marks it); before that it is not there to press */
.page-home .rooms__inner:not([data-head-shown]) .breath__alone { visibility: hidden; }
.page-home .rooms__inner[data-head-shown] .breath__alone { pointer-events: auto; }   /* the scene itself lets touches through */
.breath__question {
  font-family: var(--font-text);
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  line-height: 1.5;
  font-weight: var(--fw-regular);
  color: var(--ink);
  text-wrap: balance;
}
.page-home .breath__list { border: 0; }

/* เรื่องที่เคยแวะมา — under the colours, only on a device that has read something (flow.js). It comes in after the
   sixth colour like one more door (site.js) and grows upward when opened, so it never pushes the ring. */
.page-home .revisit {
  position: absolute;
  inset-inline: 0;
  bottom: max(1.5rem, env(safe-area-inset-bottom));
  display: grid;
  justify-items: center;
  gap: 0.75rem;
  padding-inline: var(--space-page);
  text-align: center;
  pointer-events: auto;
  opacity: var(--in, 0);
}
.page-home .revisit[hidden] { display: none; }
/* the bottom-right corner on every screen (owner) — empty once the first screen's words have faded, and across from
   the listen line at the bottom left */
.page-home .revisit { inset-inline: auto 0; justify-items: end; text-align: end; }
/* open: the pieces float up out of the corner, above the line, which stays where it was (owner); the colours fall back
   to a trace — still there, not in the way — and come back when it closes (press again, or Esc) */
.revisit__list { order: -1; }
.revisit__list:not([hidden]) { animation: revisit-rise var(--dur-gentle) var(--ease-out) both; }
@keyframes revisit-rise { from { opacity: 0; transform: translateY(0.75rem); } }
.page-home .breath__ring { transition: opacity var(--dur-gentle) var(--ease-out); }
.page-home .rooms__inner:has(.revisit[data-open]) .breath__ring { opacity: 0.12; }
.page-home .rooms__inner:has(.revisit[data-open]) .room-entry { pointer-events: none; }
.page-home .revisit:not([data-shown]) { visibility: hidden; }
.revisit__toggle {
  background: none;
  border: 0;
  padding: 0.5rem 0.25rem;
  min-height: 44px;
  font: inherit;
  color: var(--ink-muted);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: color-mix(in oklab, currentColor 35%, transparent);
  text-underline-offset: 0.3em;
}
.revisit__toggle:hover, .revisit__toggle:focus-visible { color: var(--ink); }
.revisit__list {
  display: grid;
  gap: 0.875rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.revisit__list[hidden] { display: none; }
.revisit__list li { display: grid; gap: 0.15rem; }
.revisit__list .label { text-decoration: none; }
.revisit__title { color: var(--ink); text-decoration: none; }
.revisit__title:hover, .revisit__title:focus-visible { color: var(--accent); }
@media (prefers-reduced-motion: reduce) {
  .page-home .revisit { position: static; margin-block-start: var(--space-section, 3rem); opacity: 1; visibility: visible; }
  .revisit__list:not([hidden]) { animation: none; }
}
/* phones: the ring was too tight — the question sat on the colours (owner's screenshot). The ring takes the full width,
   the dots and the question shrink a step: radius ≈125px on a 375px phone, the question fits in the empty middle */
@media (max-width: 40rem) {
  .breath__ring { width: min(100vw - 2rem, 26rem); --r: calc(min(100vw - 2rem, 26rem) / 2 - 2.6rem); }
  .breath__head { padding: 0 24%; }
  .breath__question { font-size: 1.125rem; line-height: 1.6; }
  .breath__ring .breath__dot { width: 2.75rem; }
  .breath__ring .breath__name { font-size: 0.875rem; }
  li.breath__choice a { gap: 0.4rem; }
}
/* the narrowest phones (≤360px, e.g. iPhone SE 320px): the dots one step smaller again, so the question keeps its air */
@media (max-width: 22.5rem) {
  .breath__ring { --r: calc(min(100vw - 2rem, 26rem) / 2 - 2.3rem); }
  .breath__ring .breath__dot { width: 2.25rem; }
  .breath__ring .breath__name { font-size: 0.8125rem; }
  .breath__question { font-size: 1rem; }
}
/* larger text on a phone (ก ก ก): the ring cannot grow past the screen, so the colours step out of it —
   the question on top, the six colours in two columns under it, every name still beside its colour */
@media (max-width: 40rem) {
  :root:is([data-text="1.25"], [data-text="1.5"]) .breath__ring { width: auto; aspect-ratio: auto; }
  :root:is([data-text="1.25"], [data-text="1.5"]) .breath__head { position: static; padding: 0 0 var(--space-md); }
  :root:is([data-text="1.25"], [data-text="1.5"]) .breath__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-sm) var(--space-xs); padding: 0; margin: 0; }
  :root:is([data-text="1.25"], [data-text="1.5"]) .breath__choice { position: static; transform: none; }
  :root:is([data-text="1.25"], [data-text="1.5"]) li.breath__choice a { flex-direction: row; justify-content: flex-start; gap: 0.6rem; }
  :root:is([data-text="1.25"], [data-text="1.5"]) .breath__ring .breath__dot { width: 2rem; flex: none; }   /* a colour name never breaks in two */
  :root:is([data-text="1.25"], [data-text="1.5"]) .arrival__line { font-size: min(1.625rem, 6.4vw); }
}
.breath__choice {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: rotate(var(--a)) translate(var(--r)) rotate(calc(-1 * var(--a))) translate(-50%, -50%);
}
li.breath__choice a,
.flow-colours li a {   /* these are not doors in a hallway: no rule line, no two columns */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem;
  border: 0;
  text-decoration: none;
  color: var(--ink-muted);
}
.breath__dot {
  width: clamp(3.25rem, 2.6rem + 2vw, 4.5rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--breath);
  /* a 1px edge in the muted ink (owner: must pass on the home page) — the swatch keeps its exact colour, the edge gives
     every colour its shape on either page: ≥4.4:1 light, ≥5.3:1 dark, where ครามตีสาม alone was 1.7:1 and ผ้าลินิน 1.3:1 */
  box-shadow: 0 0 0 1px var(--ink-muted);
  transition: transform var(--dur-gentle) var(--ease-out);
}
.breath__name { font-family: var(--font-meta); font-size: 0.9375rem; white-space: nowrap;
  /* a touch darker than muted (owner: pass in full) — worst case under the 92% veil: 5.3:1 light · 6.3:1 dark, was 4.4 */
  color: color-mix(in oklab, var(--ink-muted) 80%, var(--ink)); transition: color var(--dur-gentle) var(--ease-out); }
.breath__choice a:hover .breath__dot,
.breath__choice a:focus-visible .breath__dot,
.flow-colours a:hover .breath__dot,
.flow-colours a:focus-visible .breath__dot { transform: scale(1.08); }
.breath__choice a:hover .breath__name,
.flow-colours a:hover .breath__name { color: var(--ink); }

/* after a second piece: the colours not yet walked today, in the reading column */
.flow-colours { margin-block-start: var(--space-md); animation: arrive var(--dur-atmos) var(--ease-atmos) both; }
.flow-colours[hidden] { display: none; }
.flow-colours__ask { font-family: var(--font-title); font-size: 1.25rem; color: var(--ink); }   /* a question, like the home page's (Sarabun) */
/* the colour the reader is in, just before the question (owner): a small swatch and its name — not a choice */
.flow-colours__now { display: flex; justify-content: center; align-items: center; gap: 0.6rem; margin: 0 0 0.5rem; }   /* centred like the question on phones */
.flow-colours__now[hidden] { display: none; }
.flow-colours .flow-colours__now .breath__dot { width: 1.25rem; }
@media (min-width: 64rem) { .flow-colours__now { justify-content: flex-start; } }   /* wide screens: the question sits left, so does its colour */
/* the five colours still to walk: five columns in one row (owner), in the same place */
.flow-colours__list { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--space-sm) 0.5rem; margin: var(--space-sm) 0 0; padding: 0; list-style: none; }
.flow-colours__list li { display: flex; justify-content: center; }
/* phones: five across in ~64px each — the dots and names a step smaller so every name stays on one line */
@media (max-width: 40rem) {
  .flow-colours__list { column-gap: 0.25rem; }
  .flow-colours__list .breath__dot { width: 2.25rem; }
  .flow-colours__list .breath__name { font-size: 0.75rem; }
  .flow-colours__list li a { padding-inline: 0; }
}
.flow-colours__list li[hidden] { display: none; }
.flow-colours .breath__dot { width: 2.75rem; }
.nearby__choice[hidden] { display: none; }   /* "read on" gives way to the colours; rest with music stays (owner: rest is always there) */
.flow-enough { margin-block-start: var(--space-md); font-family: var(--font-text); font-size: 1.25rem; color: var(--ink); }
.flow-enough[hidden] { display: none; }
.flow-breathe { margin-block-start: var(--space-sm); }
.flow-breathe[hidden] { display: none; }

/* ── Breathing together · 4-7-8 (site.js guidedBreath) ── the page draws back behind paper, one ring leads.
   Above the header and player (z 65): nothing else asks for attention while breathing. */
.guided {
  position: fixed;
  inset: 0;
  z-index: 65;
  display: grid;
  place-items: center;
  grid-template-rows: 1fr auto auto auto auto 1fr;   /* ring · words · what the numbers are · เริ่ม · (space) · stop */
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-page);
  background: color-mix(in oklab, var(--paper) 94%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 1.2s var(--ease-atmos);
}
.guided.is-open { opacity: 1; }
.guided__ring,
.guided__count { grid-row: 2; grid-column: 1; }
/* the band: thicker than the ring, the same green, running clockwise from the top through each phase */
.guided__ring .guided__band {
  fill: none;
  stroke: var(--brand-green);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 100 100;
  stroke-dashoffset: 100;
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}
.guided__ring {
  width: min(62vmin, 22rem);
  aspect-ratio: 1;
}
.guided__ring svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* three soft discs in the logo's green (owner, 27 Sep 2026 — after the "Breath Diagram" reference): no outlines,
   lighter toward the edge. The inner two follow the ring's swell a beat late and swell a little further, so the
   layers open like a breath. */
.guided__disc {
  stroke: none;
  transform-origin: 50% 50%;
  scale: var(--to, 0.8);
  /* a breath eases in and out; each disc at its own pace (owner): outer the whole phase, middle 80%, inner 60% */
  transition: scale calc(var(--dur, 4s) * var(--pace, 1)) cubic-bezier(0.45, 0.05, 0.35, 0.95);
}
.guided__disc--1 { --pace: 1; }
.guided__disc--2 { --pace: 0.8; }
.guided__disc--3 { --pace: 0.6; }
/* holding for 7 (owner, 27 Sep 2026): the middle disc moves in and out a little — two slow waves of 3.5s that end
   exactly as the hold ends, so nothing jumps. transform, which adds to the scale above rather than replacing it. */
.guided__ring[data-hold] .guided__disc--2 { animation: hold-sway 3.5s cubic-bezier(0.45, 0.05, 0.35, 0.95) 2; }
@keyframes hold-sway {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.045); }
}
.guided__disc--1 { fill: color-mix(in oklab, var(--brand-green) 10%, var(--paper)); }
.guided__disc--2 { fill: color-mix(in oklab, var(--brand-green) 17%, var(--paper)); }
.guided__disc--3 { fill: color-mix(in oklab, var(--brand-green) 26%, var(--paper)); }
.guided__band { vector-effect: non-scaling-stroke; display: none; }   /* set aside (owner: "ง่าย ๆ น่าจะพอ") — the discs and the count lead; remove display:none to bring the band back */
.guided__count {
  position: relative;
  z-index: 1;   /* above the discs, which paint on their own layer while they scale */
  place-self: center;
  font-family: var(--font-title);   /* Sarabun Light (owner, 27 Sep 2026) — already loaded at 300 */
  font-size: clamp(2.5rem, 2rem + 3vw, 4rem);
  font-weight: var(--fw-light);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--brand-green-text);   /* 4.8:1 on light paper, the logo's green on dark */
}
.guided__word {
  grid-row: 3;
  margin: 0;
  min-height: 1.6em;
  font-family: var(--font-text);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  color: var(--ink);
  text-align: center;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.guided__word.is-on { opacity: 1; }
.guided__hint {
  grid-row: 4;
  margin: 0;
  font-family: var(--font-meta);
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-muted);
  text-align: center;
  transition: opacity 0.6s ease;
}
.guided__hint.is-gone { opacity: 0; visibility: hidden; transition: opacity 0.6s ease, visibility 0s 0.6s; }   /* keeps its room */
.guided__start { grid-row: 5; }
.guided__start[hidden] { visibility: hidden; display: inline-flex; }   /* keeps its room, so the ring and words stay put */
.guided__stop {
  grid-row: 6;
  align-self: end;
  background: none;
  border: 0;
  padding: 0.6rem 1rem;
  font: inherit;
  font-size: 0.9375rem;
  color: var(--ink-muted);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in oklab, currentColor 45%, transparent);
}
.guided__stop:hover { color: var(--ink); }
.guided__stop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
:root[data-guided] { overflow: hidden; }

/* ── rooms · doors along a hallway, not a grid of cards ── */
.rooms {
  padding-block: var(--space-section);
  background: var(--paper);
  transition: background-color var(--dur-atmos) var(--ease-atmos);
}
.rooms__inner { width: min(100% - 2 * var(--space-page), var(--measure-wide)); margin-inline: auto; }
.rooms__head { margin-block-end: var(--space-lg); }
.rooms__list { border-top: 1px solid var(--line); }

.room-entry a {
  display: grid;
  grid-template-columns: minmax(9rem, 15rem) 1fr;
  gap: 0.25rem var(--space-md);
  align-items: baseline;
  padding-block: clamp(1.2rem, 0.9rem + 1vw, 1.9rem);
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}
.room-entry .label { transition: color var(--dur-gentle) var(--ease-out); }
.room-entry__line {
  font-size: clamp(1.25rem, 1.08rem + 0.8vw, 1.75rem);
  line-height: 1.6;
  font-weight: var(--fw-light);
  color: var(--ink);
  transition: color var(--dur-gentle) var(--ease-out), transform var(--dur-gentle) var(--ease-out);
}
.room-entry a:hover .room-entry__line,
.room-entry a:focus-visible .room-entry__line { color: var(--accent); transform: translateX(var(--move-small)); }
.room-entry a:hover .label { color: var(--accent); }

@media (max-width: 36rem) {
  .room-entry a { grid-template-columns: 1fr; }
}

/* ── place · one full-bleed atmosphere, used once ── */
.place {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;   /* a full screen, like the entrance (owner) */
  display: grid;
  align-items: end;
  isolation: isolate;
}
.place > .photo,
.place > .scene {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 0;
  mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent);
}
/* the sound moment carries text over a busy photograph — it needs more paper */
.place .photo--scrim::after {
  background:
    linear-gradient(to right, color-mix(in oklab, var(--paper) 88%, transparent) 8%, transparent 58%),
    linear-gradient(to top, var(--paper) 2%, color-mix(in oklab, var(--paper) 40%, transparent) 26%, transparent 60%);
}

.place__inner {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  padding-block: var(--space-xl) calc(var(--space-xl) + 4vh);
}
.place__line {
  max-width: 30rem;
  margin-block: 0.9rem 1.5rem;
  font-size: var(--fs-subtitle);
  line-height: 1.75;
  font-weight: var(--fw-light);
  color: var(--ink);
}

/* ── continue · a few more doors, quietly ── */
.continue {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  padding-block: var(--space-section) 0;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-md);
}
.continue > .meta { grid-column: 1 / span 4; }
.quiet-list { grid-column: 5 / -1; border-top: 1px solid var(--line); }
.quiet-list a {
  display: block;
  padding-block: 1.25rem;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}
.quiet-list__title {
  display: block;
  font-size: 1.375rem;
  line-height: 1.6;
  color: var(--ink);
  transition: color var(--dur-gentle) var(--ease-out);
}
.quiet-list a:hover .quiet-list__title { color: var(--accent); }

@media (max-width: 52rem) {
  .continue { display: block; }
  .continue > .meta { margin-block-end: var(--space-md); }
}

/* ── about · who is on the other side of the writing ───────────────────── */

.about {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  padding-block: var(--space-section) 0;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-md);
  align-items: center;
}
.about__image { grid-column: 1 / span 6; aspect-ratio: 16 / 10; border-radius: var(--radius-subtle); }
.about__text { grid-column: 8 / -1; }
.about__line {
  margin-block: 0.8rem 1rem;
  font-size: var(--fs-subtitle);
  line-height: 1.8;
  font-weight: var(--fw-light);
  color: var(--ink);
}
.about__note { font-size: 1.0625rem; line-height: 1.95; color: var(--ink-muted); }
.about__note p { margin-block: 0 1em; }
/* on its own page (owner): one screen, the photograph and the words side by side, centred in the height */
/* the About page reads like a story (.entry), mirrored on wide screens — see "About · mirrored" below.
   Its sections keep quiet headings in the title face, and its links look like links. */
.about__body h2 {
  margin-block: 2.6em 0.7em;
  font-family: var(--font-title);
  font-size: var(--fs-subtitle);
  font-weight: var(--fw-regular);
  line-height: 1.5;
  color: var(--ink);
}
.about__body a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
.about__body strong { font-weight: var(--fw-medium); color: var(--ink); }
/* the belief line opens every story (owner, 25 Sep 2026) — in the logo's green, the one vivid colour */
.about__body a.believe { color: var(--brand-green-text); text-decoration-color: color-mix(in oklab, var(--brand-green) 45%, transparent); }
.about__body a.believe strong { color: inherit; }
.about__body a.believe:hover { text-decoration-color: currentColor; }

/* ── library · every story, titles only (owner, 25 Sep 2026) — calm at 60 pieces: six named colours, no images ── */
.library {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  padding-block-start: clamp(7.5rem, 17vh, 11rem);
  /* room between the last titles and the footer, which slides up over the page's end (owner) — this page's body
     class zeroes .ending-space like an article's */
  padding-block-end: clamp(4.5rem, 12vh, 8rem);
}
.library__head { margin-block-end: 2.5rem; }   /* the groups sit close under the title (owner) */
/* phones: six named colours at the top jump to their group (owner, 25 Sep 2026) — at 60 pieces the list runs ~5 screens */
.library__jump { display: none; }
.library__colour { scroll-margin-block-start: 8.5rem; }   /* clear of the logo and its rings */
@media (max-width: 52rem) {
  .library__head { margin-block-end: var(--space-md); }
  .library__jump { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin-block-end: var(--space-lg); padding: 0; list-style: none; }
  .library__jump a { display: inline-flex; align-items: center; gap: 0.5em; min-height: 44px; font-family: var(--font-meta); font-size: 0.9375rem; color: var(--ink-body); text-decoration: none; }
  .library__jump i { width: 0.75em; height: 0.75em; border-radius: 50%; background: var(--dot); flex: none; box-shadow: 0 0 0 1px color-mix(in oklab, var(--ink) 18%, transparent); }
}
.library__heading { margin-block-start: 0.75rem; font-family: var(--font-title); font-size: var(--fs-display); line-height: var(--lh-display); font-weight: var(--fw-light); color: var(--ink); }
.library__note { margin-block-start: 1rem; max-width: 30rem; font-size: 1.0625rem; line-height: 1.9; color: var(--ink-muted); }
.library__groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
  gap: var(--space-xl) var(--space-lg);
  align-items: start;
}
.library__colour { display: flex; align-items: center; gap: 0.6em; margin-block-end: 0.5rem; color: var(--ink); }
.library__colour i { width: 0.75em; height: 0.75em; border-radius: 50%; background: var(--dot); flex: none; box-shadow: 0 0 0 1px color-mix(in oklab, var(--ink) 18%, transparent); }
.library__count { margin-inline-start: auto; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.library__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.library__list a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.8rem;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}
.library__title { font-size: 1.125rem; line-height: 1.6; color: var(--ink); transition: color var(--dur-gentle) var(--ease-out); }
.library__list a:hover .library__title,
.library__list a:focus-visible .library__title { color: var(--accent); }
.library__draft { margin-inline-start: 0.5em; vertical-align: 0.15em; }
.library__read { flex: none; font-family: var(--font-meta); font-size: 0.8125rem; color: var(--ink-muted); }
.library__list li:not([data-read]) .library__read { display: none; }

@media (max-width: 52rem) {
  .about { display: block; }
  .about__image { aspect-ratio: 4 / 3; margin-block-end: var(--space-md); }
}

/* ==========================================================================
   Sound invite · a control, not an instruction
   ========================================================================== */

.sound-invite {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  min-height: 44px;
  padding: 0.25rem 0;
  background: none;
  border: 0;
  font-family: var(--font-meta);
  font-size: var(--fs-nav);
  line-height: 1.5;
  color: var(--ink-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
}
.sound-invite:hover { color: var(--ink); }
.sound-invite__mark {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  flex: none;
  border: 1px solid currentColor;
  border-radius: 50%;
  transition: background-color var(--dur-gentle) var(--ease-out), color var(--dur-gentle) var(--ease-out);
}
.sound-invite__mark svg { width: 0.7rem; height: 0.7rem; }
.sound-invite__state { display: none; }
.sound-invite[aria-pressed="true"] { color: var(--ink); }
.sound-invite[aria-pressed="true"] .sound-invite__mark { background: var(--ink); border-color: var(--ink); }
.sound-invite[aria-pressed="true"] .sound-invite__mark svg { color: var(--paper); }
.sound-invite[aria-pressed="true"] .sound-invite__state { display: inline; }

/* play / pause glyphs, shared by every toggle */
[data-player-toggle] .i-pause { display: none; }
[data-player-toggle][aria-pressed="true"] .i-play { display: none; }
[data-player-toggle][aria-pressed="true"] .i-pause { display: block; }

/* ==========================================================================
   Room · one template, many kinds of light
   ========================================================================== */

.room__arrival {
  width: min(100% - 2 * var(--space-page), 78rem);
  margin-inline: auto;
  padding-block-start: clamp(7.5rem, 18vh, 12rem);
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-md);
  align-items: end;
}
.room__intro { grid-column: 1 / span 7; padding-block-end: var(--space-md); }
.room__line {
  margin-block: 1rem 1.5rem;
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  font-weight: var(--fw-light);
  color: var(--ink);
  white-space: pre-line;
  animation: arrive var(--dur-atmos) var(--ease-atmos) 0.15s both;
}
.room__note { max-width: 26rem; font-size: 1.0625rem; line-height: 1.95; color: var(--ink-muted); }
/* a feeling's line carries the + of the cover, large, in the feeling's own colour (owner) — --accent is the feeling's
   colour, lightened on dark pages so it holds over the photograph; drawn, never read aloud */
.arrival--feeling .arrival__line .l:first-child::before,
.arrival--colour .arrival__line .l:first-child::before {
  content: "";
  display: inline-block;   /* on the first line (owner), raised by half the line's height, as on the cover */
  width: 1.1em;
  height: 1.1em;
  margin-inline-end: 0.2em;
  vertical-align: 0.5em;
  background:
    linear-gradient(var(--plus, var(--accent)), var(--plus, var(--accent))) center / 100% 0.28em no-repeat,
    linear-gradient(var(--plus, var(--accent)), var(--plus, var(--accent))) center / 0.28em 100% no-repeat;
}
/* the + takes 1.3em at the start of the first line, so the steps of lines two and three move by the same,
   and still step from where the words begin */
.arrival--feeling .arrival__line .l + .l      { padding-inline-start: calc(0.9em + 1.3em); }
.arrival--feeling .arrival__line .l + .l + .l { padding-inline-start: calc(1.8em + 1.3em); }
@media (max-width: 40rem) {
  .arrival--feeling .arrival__line .l + .l      { padding-inline-start: calc(0.6em + 1.3em); }
  .arrival--feeling .arrival__line .l + .l + .l { padding-inline-start: calc(1.2em + 1.3em); }
}
/* wide screens (owner, trial): the + hangs out into the left margin, so the words begin where the home page's do and
   the three lines keep the home page's steps. Phones and tablets keep it on the line — their margin is too narrow. */
@media (min-width: 64rem) {
  .arrival--feeling .arrival__line .l:first-child::before,
  .arrival--colour .arrival__line .l:first-child::before { margin-inline-start: -1.3em; }
  .arrival--feeling .arrival__line .l + .l      { padding-inline-start: 0.9em; }
  .arrival--feeling .arrival__line .l + .l + .l { padding-inline-start: 1.8em; }
}

.room__image {
  grid-column: 9 / -1;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius-subtle);
  animation: settle 2.4s var(--ease-atmos) both;
}
.room__image .scene { height: 100%; }

@media (max-width: 52rem) {
  .room__arrival { display: block; }
  .room__image { aspect-ratio: 4 / 3; margin-block-start: var(--space-lg); }
}

.pieces {
  width: min(100% - 2 * var(--space-page), 72rem);
  margin: var(--space-section) auto 0;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-xl) var(--space-md);
}
/* A five-step rhythm, not three: with nine pieces on a page a three-step loop
   becomes a visible pattern. Widths, offsets and image shapes all change. */
.pieces > li:nth-child(5n + 1) { grid-column: 1 / span 7; }
.pieces > li:nth-child(5n + 2) { grid-column: 9 / -1; align-self: center; }
.pieces > li:nth-child(5n + 3) { grid-column: 3 / span 5; }
.pieces > li:nth-child(5n + 4) { grid-column: 9 / -1; align-self: end; }
.pieces > li:nth-child(5n + 5) { grid-column: 5 / span 8; }

.pieces .piece__image { aspect-ratio: 3 / 2; margin-block-end: var(--space-md); }
.pieces > li:nth-child(5n + 3) .piece__image { aspect-ratio: 4 / 5; }
.pieces > li:nth-child(5n + 5) .piece__image { aspect-ratio: 16 / 9; }

@media (max-width: 52rem) {
  .pieces { display: block; }
  .pieces > li + li { margin-block-start: var(--space-xl); }
}

.room__places,
.room__next {
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
}
.room__places { margin-block-start: var(--space-section); }
.room__places p:last-child {
  margin-block-start: 0.75rem;
  font-size: var(--fs-subtitle);
  font-weight: var(--fw-light);
  line-height: 1.8;
  color: var(--ink);
}
.room__next {
  margin-block-start: var(--space-section);
  padding-block-start: var(--space-lg);
  border-top: 1px solid var(--line);
}
.room__next a { display: block; margin-block-start: 0.75rem; text-decoration: none; }
.room__next-line {
  display: block;
  font-size: var(--fs-subtitle);
  line-height: 1.7;
  font-weight: var(--fw-light);
  color: var(--ink);
  transition: color var(--dur-gentle) var(--ease-out);
}
.room__next a:hover .room__next-line { color: var(--accent); }

/* ==========================================================================
   Article · sacred reading space
   ========================================================================== */

.entry { padding-block-start: clamp(7.5rem, 17vh, 11rem); }

.entry__head,
.entry__body,
.nearby {
  width: min(100% - 2 * var(--space-page), var(--measure));
  margin-inline: auto;
}

.entry__title {
  margin-block: 0.8rem 1.25rem;
  font-size: var(--fs-title);
  line-height: var(--lh-title);
  font-weight: var(--fw-regular);
  color: var(--ink);
  text-wrap: balance;
  animation: arrive var(--dur-atmos) var(--ease-atmos) 0.1s both;
}
/* Titles and headlines in Sarabun (owner, from the early 6ty+ Music cover) — the reading text stays in Noto Serif Thai */
.entry__title, .arrival__line, .feeling__line, .breath__question, .place__line, .about__line, .room__line { font-family: var(--font-title); }

/* A story's title carries the + of the cover (owner): a mark, not a letter — drawn, and never read aloud; it sits
   raised before the first word as it does on the cover. Its colour is the story's own colour, the very swatch the
   reader picked on the home page, so they know they came through the right colour (owner). Green only if none. */
.page-article .entry__title::before {
  content: "";
  display: inline-block;
  width: 0.8em;
  height: 0.8em;
  margin-inline-end: 0.14em;
  vertical-align: 0.26em;
  background:
    linear-gradient(var(--breath, var(--brand-green)), var(--breath, var(--brand-green))) center / 100% 0.24em no-repeat,
    linear-gradient(var(--breath, var(--brand-green)), var(--breath, var(--brand-green))) center / 0.24em 100% no-repeat;
  /* no edge (owner): the + is seen by its size, large and heavy as on the cover */
}
/* phones: a touch smaller, so on a two-line title it does not pull the eye from the first word (owner) */
@media (max-width: 40rem) {
  .page-article .entry__title::before { width: 0.64em; height: 0.64em; margin-inline-end: 0.12em; vertical-align: 0.3em; background-size: 100% 0.2em, 0.2em 100%; }
}
.entry__sound { display: flex; flex-wrap: wrap; align-items: center; gap: 0 1rem; }

.entry__image {
  width: min(100% - 2 * var(--space-page), 60rem);
  margin: var(--space-xl) auto;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius-subtle);
  animation: settle 2.4s var(--ease-atmos) 0.3s both;
}
.entry__image .scene { height: 100%; }
/* the photograph first, then the room, place and title (owner): the head arrives once the picture has settled in,
   and holds while the picture is still loading */
.entry:has(> .entry__image) > .entry__head {
  animation: arrive var(--dur-atmos) var(--ease-atmos) 1.4s both;
}
.entry:has(> .entry__image) > .entry__head .entry__title { animation: none; }
.entry:has(> .entry__image img.is-loading) > .entry__head { animation-play-state: paused; }

@media (max-width: 63.99rem) {
  /* phones and tablets held upright (below the wide layout): closer, more intimate */
  .entry__image { width: 100%; aspect-ratio: 4 / 5; border-radius: 0; }
}

.entry__body p {
  margin-block-end: var(--paragraph-gap);
  color: var(--ink-body);
  text-wrap: pretty;
  hyphens: none;
}
.entry__body p:last-child { margin-block-end: 0; }

/* ── The image stays while the words move (DESIGN_DECISIONS · Article) ──
   Wide screens: the photograph holds the left column at full height; the
   reading column scrolls beside it and lets go when the article ends.
   Phones: a thin strip of the photograph stays at the top for the whole
   article; the words pass above it and fade out in its lowest tenth.        */

@media (min-width: 64rem) {
  .entry {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, calc(var(--measure) + 2 * var(--space-page)));
    padding-block-start: 0;
  }
  .entry > .entry__image {
    grid-column: 1 / -1;   /* the photograph lies under the whole page; the words sit on a layer above it */
    grid-row: 1 / -1;   /* every row, so it stays pinned behind the words and the choices after them (owner) */
    position: sticky;
    inset-block-start: 0;
    align-self: start;
    width: 100%;
    height: 100vh;
    height: 100svh;
    margin: 0;
    aspect-ratio: auto;
    border-radius: 0;
  }
  /* First view: the photograph is shown almost whole, the title waits low at the right.
     As the reader scrolls, the page colour washes in behind the words (--wash 0 → 1, site.js). */
  .entry > .entry__image::before,
  .entry > .entry__image::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
  }
  /* always there: just enough shade under the title, and a soft lower edge */
  .entry > .entry__image::before {
    background:
      linear-gradient(to bottom, color-mix(in oklab, var(--paper) 72%, transparent), transparent 12%),   /* the menu stays readable on bright ceilings */
      /* the shade sits under the title wherever the reading column falls — centred on the column, not on a fixed 88%,
         which missed the title on narrower wide screens (a 1024px tablet on its side: the place line was unreadable) */
      radial-gradient(ellipse 55% 45% at calc(100% - var(--measure) / 2 - var(--space-page)) 84%, color-mix(in oklab, var(--paper) 82%, transparent), transparent 80%),
      linear-gradient(to top, var(--paper), color-mix(in oklab, var(--paper) 35%, transparent) 14%, transparent 34%);
  }
  /* arrives with scrolling: the reading side of the page */
  .entry > .entry__image::after {
    opacity: var(--wash, 0);
    /* darker where it helps reading (owner): 84% across the whole column of words, anchored to where the column
       begins at any width. Measured over all twelve photographs, both schemes: body text ≥7.3:1 (AAA) */
    --col: calc(100% - var(--measure) - 2 * var(--space-page));
    background: linear-gradient(to right,
      transparent calc(var(--col) - 33%),
      color-mix(in oklab, var(--paper) 42%, transparent) calc(var(--col) - 13%),
      color-mix(in oklab, var(--paper) 84%, transparent) calc(var(--col) - 2%),
      color-mix(in oklab, var(--paper) 84%, transparent));
  }
  .entry > .entry__head,
  .entry > .entry__body {
    position: relative;
    z-index: 1;
    grid-column: 2;
    width: min(100%, var(--measure));
    margin-inline: var(--space-page);
  }
  /* the header and menu also sit on the photograph here */
  .page-article .site-header { text-shadow: 0 0 0.5em var(--paper), 0 0 1.2em color-mix(in oklab, var(--paper) 85%, transparent); }
  /* readable on any photograph, bright or dark: a soft halo of page colour right behind the letters */
  .entry > .entry__head { text-shadow: 0 0 0.6em var(--paper), 0 0 1.4em color-mix(in oklab, var(--paper) 80%, transparent); }
  /* the small place line sits on the photograph too: body ink rather than muted, so it holds on bright cloth (tablet on its side) */
  .entry > .entry__head .label { color: var(--ink-body); }
  /* the invitation moves to the waiting player at the left (site.js) */
  .entry > .entry__head .entry__sound { display: none; }
  /* the waiting player fades in as the page opens (owner, 25 Sep 2026: so the music can start from the beginning —
     it used to wait for the second paragraph); a short pause first, so the photograph is still seen first */
  .page-article .player[data-state="idle"] { animation: arrive var(--dur-atmos) var(--ease-out) 0.6s both; }

  /* the title sits at the foot of the first screen, so the photograph is seen first */
  .entry > .entry__head {
    grid-row: 1;   /* explicit rows: the full-width photograph would otherwise push the words below it */
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 100vh;
    min-height: 100svh;
    padding-block-end: var(--space-xl);
    margin-block-end: var(--space-lg);
  }
  .entry > .entry__body { grid-row: 2; }
  /* the choices come straight after the words, over the same pinned photograph (owner) */
  .entry > .nearby {
    grid-row: 3;
    grid-column: 2;   /* the reading column, like the words (owner) */
    width: min(100%, var(--measure));
    margin-inline: var(--space-page);
    position: relative;
    z-index: 3;
  }
  /* the ground is no longer solid: a soft halo keeps the small labels readable over a bright photograph */
  .entry > .nearby li { text-shadow: 0 0 0.5em var(--paper), 0 0 1.2em color-mix(in oklab, var(--paper) 85%, transparent); }
  /* no ground under the footer: the photograph stays whole to the bottom of the page (owner) */
}

/* ── About · mirrored (owner): the same held photograph, the words on the left this time ── */
@media (min-width: 64rem) {
  .entry--mirror { grid-template-columns: minmax(0, calc(var(--measure) + 2 * var(--space-page))) minmax(0, 1fr); }
  .entry--mirror > .entry__head,
  .entry--mirror > .entry__body { grid-column: 1; }
  /* the shade under the title and the wash behind the words follow the words to the left */
  .entry--mirror > .entry__image::before {
    background:
      linear-gradient(to bottom, color-mix(in oklab, var(--paper) 72%, transparent), transparent 12%),
      radial-gradient(ellipse 55% 45% at calc(var(--measure) / 2 + var(--space-page)) 84%, color-mix(in oklab, var(--paper) 82%, transparent), transparent 80%),
      linear-gradient(to top, var(--paper), color-mix(in oklab, var(--paper) 35%, transparent) 14%, transparent 34%);
  }
  .entry--mirror > .entry__image::after {
    background: linear-gradient(to left,
      transparent calc(var(--col) - 33%),
      color-mix(in oklab, var(--paper) 42%, transparent) calc(var(--col) - 13%),
      color-mix(in oklab, var(--paper) 84%, transparent) calc(var(--col) - 2%),
      color-mix(in oklab, var(--paper) 84%, transparent));
  }
  .page-about .site-header { text-shadow: 0 0 0.5em var(--paper), 0 0 1.2em color-mix(in oklab, var(--paper) 85%, transparent); }
  /* the words scroll up under the logo's corner (owner): instead of a band of colour, the words themselves fade out
     before they reach it — the same kind of fade as the phones' strip (site.js keeps --top-cut at 150px from the top, owner) */
  .entry--mirror > .entry__head,
  .entry--mirror > .entry__body {
    -webkit-mask-image: linear-gradient(to bottom, transparent var(--top-cut, -100vh), #000 calc(var(--top-cut, -100vh) + 3.5rem));
    mask-image: linear-gradient(to bottom, transparent var(--top-cut, -100vh), #000 calc(var(--top-cut, -100vh) + 3.5rem));
  }
}

/* phones and tablets held upright (owner: check tablets) — everything narrower than the wide two-column layout reads
   this way; before, tablets fell between the two and got the old stacked page: title, small photo, words */
@media (max-width: 63.99rem) {
  /* the first screen is the photograph with the title at its foot (site.js sets --open to what the title leaves);
     scrolling slides it up until a 25svh strip stays pinned, and the picture inside always fills what is still in view */
  .entry > .entry__image {
    position: sticky;
    inset-block-start: calc(25svh - var(--open, 70svh));
    z-index: 2;
    height: var(--open, 70svh);
    aspect-ratio: auto;
    margin: 0;
  }
  .entry > .entry__image img {
    position: absolute;
    inset: auto 0 0;
    height: var(--view, 100%);
    object-position: var(--focus-sm, var(--focus, 50% 50%));
  }
  /* room at the foot of the first screen for the scroll cue (line + เลื่อนลง), so it never touches the title —
     and, since the player is there from the start (owner, 25 Sep 2026), for the player below them both:
     the title sits above the cue, the cue just above the player (~6.25rem tall with its status line + its 1rem margin) */
  .entry > .entry__head { padding-block: var(--space-md) calc(var(--space-lg) + 1.75rem); }
  /* only while the player is actually there (owner, 27 Sep: a story whose player never showed kept 7.5rem of empty
     room under the title, which shrank the photograph and pushed the words away) */
  :root[data-player-open] .page-article .entry > .entry__head { padding-block-end: calc(var(--space-lg) + 1.75rem + 7.5rem); }
  :root[data-player-open] .page-article .scroll-cue { bottom: 7.6rem; }
  /* the label on one line: the atmosphere alone (owner, 27 Sep 2026) */
  .page-article .entry > .entry__head .label__feeling { display: none; }
  /* the invitation waits in the player, which arrives with the words */
  .entry > .entry__head .entry__sound { display: none; }
  .page-article .player[data-state="idle"] { animation: arrive var(--dur-atmos) var(--ease-out) 0.6s both; }   /* as the page opens (owner) */
  /* the words ride above the strip and fade out inside its lowest tenth,
     so the photograph is never written over (site.js keeps --cut at the strip's lower edge) */
  /* the photograph opens the page; the room, place and title follow, then the words */
  .entry { display: flex; flex-direction: column; padding-block-start: 0; }
  .entry > .entry__image { order: -1; }
  .entry > .entry__head,
  .entry > .entry__body,
  .entry > .nearby {
    position: relative;
    z-index: 3;
    --band: 2.5svh;   /* 10% of the 25svh strip */
    -webkit-mask-image: linear-gradient(to bottom, transparent calc(var(--cut) - var(--band)), #000 var(--cut));
    mask-image: linear-gradient(to bottom, transparent calc(var(--cut) - var(--band)), #000 var(--cut));
  }
  /* the strip's lower edge melts into the page instead of ending on a hard line */
  .entry > .entry__image::after {
    content: "";
    position: absolute;
    inset: auto 0 0;
    height: 25svh;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(to top, var(--paper), color-mix(in oklab, var(--paper) 40%, transparent) 30%, transparent 60%);
  }
}

/* the ending breathes before anything else appears */
.ending-space { height: clamp(10rem, 34vh, 22rem); }
/* articles already breathe: the sixth paragraph rises to mid-screen, then the question (owner) */
.page-article .ending-space { height: 0; }

/* after the last paragraph, about half a paragraph before the choices (owner, 27 Sep 2026; --after-words, site.js) */
.entry > .entry__body { padding-block-end: var(--after-words, 6rem); }
.nearby { padding-block-end: var(--space-lg); }   /* lower (owner) — site.js adds the footer's height on top */
/* that added room runs under the footer, and the choices sit above it (z-index 3 over the photograph) — let taps
   through the empty room so the footer's links work (owner: เกี่ยวกับ could not be pressed on a story) */
.entry > .nearby { pointer-events: none; }
.entry > .nearby > * { pointer-events: auto; }

/* after the last paragraph, one quiet question: rest, or read on (owner) */
/* the two buttons fade in as they come into view — watched on their own, because they sit at the very
   bottom of the page where the general reveal (which ignores the lowest 12% of the screen) never fires */
.nearby__ask { text-align: center; }
.can-reveal .nearby__ask { opacity: 0; transition: opacity var(--dur-atmos) var(--ease-atmos); }
.can-reveal .nearby__ask.is-visible { opacity: 1; }
.nearby__choice .nearby__on,
.nearby__choice[aria-pressed="true"] .nearby__off { display: none; }
.nearby__choice[aria-pressed="true"] .nearby__on { display: inline; }
.nearby__choice[hidden] { display: none; }
/* the music choice is the quiet call to action: a soft wash of the room's accent, never a loud button (owner) */
.nearby__choice[data-player-toggle] {
  color: var(--ink);
  background: color-mix(in oklab, var(--accent) 16%, var(--paper));
  border-color: color-mix(in oklab, var(--accent) 80%, var(--paper));   /* edge ≥3.3:1 in every room, light and dark */
}
.nearby__choice[data-player-toggle]:hover,
.nearby__choice[data-player-toggle]:focus-visible {
  background: color-mix(in oklab, var(--accent) 24%, var(--paper));
  border-color: var(--accent);
}
.nearby__choices { display: flex; justify-content: center; gap: var(--space-md); }
/* today's three steps under the choices (owner): thin, as wide as the reading column, not something to press.
   A step read is a thick bar in that piece's own colour; a step to come is a hairline — thickness tells, not an edge. */
.flow-steps { margin-block-start: var(--space-md); }
.flow-steps[hidden] { display: none; }
.flow-steps__bars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
.flow-steps__bars { align-items: center; }
.flow-steps__bars i { display: block; height: 1px; background: var(--ink-muted); opacity: 0.45; }
.flow-steps__bars i[data-done] { height: 4px; margin-block: 0; background: var(--c, var(--ink)); opacity: 1; }   /* read = thick (owner), no edge */
/* phones: room after the last paragraph, and the two choices stacked full width so neither wraps */
@media (max-width: 40rem) {
  .nearby__choices { flex-direction: column; align-items: stretch; gap: 0.75rem; }
  .nearby__choice { white-space: nowrap; }
}
.nearby__choice {
  min-height: 2.75rem;
  padding: 0.5rem 1.4rem;
  font: inherit;
  color: var(--ink-muted);
  background: none;
  border: 1px solid color-mix(in oklab, var(--ink-muted) 80%, transparent);   /* ≥3:1 so the button edge can be seen (WCAG 1.4.11) */
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--dur-gentle) var(--ease-out), border-color var(--dur-gentle) var(--ease-out);
}
.nearby__choice:hover,
.nearby__choice:focus-visible { color: var(--ink); border-color: var(--ink-muted); }

.nearby__more { animation: arrive var(--dur-atmos) var(--ease-atmos) both; }

/* ── A colour's page (/category/…) — the colour, not the category (owner, 18 Sep 2026) ──
   First screen: the swatch, its name, one invitation into the reading loop. Below, quietly, the pieces of this colour. */
/* ── A colour's page, layout A (owner, 18 Sep 2026) ──
   1 the colour's photograph held, washed with the colour · a large + in the colour's own swatch · its name · one invitation
   2 the newest two or three pieces rise over the held photograph
   3 the photograph fades into the page colour
   4 the rest, six at a time, with the story's-end bars as a navigator */
/* the photograph held while the sequence plays — a colour's page and a feeling's page alike (owner) */
.page-colour .arrival, .page-room .arrival { position: sticky; top: 0; z-index: 0; }
.page-colour main > :not(.arrival), .page-room main > :not(.arrival) { position: relative; z-index: 1; }
.arrival--colour { --plus: var(--breath); }   /* the very swatch the reader picked, as on a story's title */
.arrival--colour .arrival__inner,
.arrival--feeling .arrival__inner,
.arrival--feeling .arrival__foot > * { opacity: calc(1 - var(--veil, 0)); }   /* the foot's own arrival animation holds its opacity — its children step back instead */   /* the words step back as the pieces come (site.js) */
.arrival--colour .arrival__inner .colour__start { visibility: visible; }

/* the colour lies over the whole photograph, quietly, so the page reads as this colour even before the words */
.arrival--colour::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--breath);
  mix-blend-mode: soft-light;
  opacity: 0.6;
  pointer-events: none;
  mask-image: linear-gradient(180deg, #000 76%, transparent);
}
.arrival--colour .colour__start { margin-block-start: 1.5rem; background: color-mix(in oklab, var(--paper) 55%, transparent); color: var(--ink); }
/* the newest pieces — the home page as the guide (owner): the stage lies over the held photograph from the first screen,
   a curtain of page colour rises to 92% as the first words step back (--veil), then the newest come one at a time in the
   middle — each fades in, then out as the next fades in. The page does not move under them. */
.seq__newest { height: 200svh; margin-block-start: -100svh; pointer-events: none; }   /* clicks pass through to the first screen; only what is shown takes them */
.seq__newest[data-has-list] { height: 330svh; }   /* curtain · the newest two · they leave · the rest come up · the footer comes */
.seq__newest:not([data-has-list]) { height: 240svh; }   /* no list: the newest stay a while before the footer comes */
.seq__newest:not([data-has-list]) .seq__latest { margin-block-end: var(--footer-h, 0px); }   /* the footer arrives under them, nothing moves */
.seq__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  pointer-events: none;   /* the first screen's invitation stays pressable beneath it */
}
.seq__stage::before {   /* the curtain, as behind the home page's colour question */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--paper);
  opacity: calc(var(--veil, 0) * 0.92);
}
/* the two newest together (owner): side by side on a wide screen, one above the other on a phone */
.seq__stage > .seq__latest,
.seq__stage > .seq__list { grid-area: 1 / 1; }   /* one place: the rest come up where the newest were (owner — as the home page's Music Room) */
.seq__latest { opacity: var(--a, 0); width: min(100% - 2 * var(--space-page), var(--measure-wide)); }   /* a set width, or the two columns collapse into one */
.seq__list { opacity: var(--b, 0); width: min(100% - 2 * var(--space-page), var(--measure)); pointer-events: auto; margin-block-end: var(--footer-h, 0px); }   /* sits in the room above where the footer will come, so it never moves (owner) */
.seq__latest ul { width: 100%; margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(12, 1fr); column-gap: var(--space-md); align-items: start; }
/* the newest two as the first room pages laid them out (owner): one upright (4:5), one wide (3:2), set off the same line;
   each fades in after the one before (--in, site.js) */
.seq__item { opacity: var(--in, 0); }
.seq__item--upright { grid-column: 1 / span 5; }
.seq__item--wide { grid-column: 7 / -1; margin-block-start: clamp(3rem, 12svh, 9rem); }
@media (min-width: 40.01rem) { .seq__item--upright:only-child { grid-column: 4 / span 6; } }   /* one piece alone stands in the middle, not left with an empty half */
.seq__item .piece__image { margin-block-end: var(--space-sm); max-height: 50svh; }
.seq__item--upright .piece__image { aspect-ratio: 4 / 5; }
.seq__item--wide .piece__image { aspect-ratio: 3 / 2; }
.seq__item .piece__image img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 40rem) {
  /* phones: one above the other, both wide and lower, titles only — so both fit on the screen */
  .seq__latest ul { grid-template-columns: 1fr; row-gap: var(--space-md); }
  .seq__item--upright, .seq__item--wide { grid-column: 1; margin-block-start: 0; }
  /* smaller, set off each other like the wide-screen pair (owner: full-width was too big) —
     first right, away from the logo in the top-left corner (owner), second left */
  .seq__item .piece__image, .seq__item--upright .piece__image { aspect-ratio: 3 / 2; max-height: 22svh; width: 64%; }
  .seq__item--upright .piece__image { margin-inline-start: auto; }
  .seq__item--upright > a { text-align: end; }
  .seq__item .seq__excerpt { display: none; }
}
.seq__latest li a { display: block; pointer-events: auto; text-decoration: none; }
@media (prefers-reduced-motion: reduce) { .seq__latest, .seq__item { opacity: 1; } .seq__newest[data-has-list] .seq__latest { opacity: 0; } .seq__list { opacity: 1; } }
.seq__latest .label { display: block; margin-block-end: 0.6rem; }
.seq__latest .seq__piece { display: block; font-family: var(--font-title); font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.625rem); line-height: 1.5; color: var(--ink); }
.seq__latest li a:hover .seq__piece { color: var(--accent); }
.seq__excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-block-start: 0.75rem;
  font-size: 1.0625rem;
  line-height: 1.85;
  color: var(--ink-body);
}
/* then the photograph fades into the page colour */
/* then the photograph fades into the page colour — and the page colour then holds a full screen at least (with the
   rest of the pieces, or on its own), so by the end nothing of the photograph is left */
/* the navigator: the story's-end bars, one per page of six, the current page thick in the colour (owner) */
.seq__list ul { margin: var(--space-sm) 0 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.seq__list li a { display: block; padding-block: 0.8rem; border-bottom: 1px solid var(--line); text-decoration: none; }
.seq__list .label { display: block; margin-block-end: 0.15rem; }
.seq__list .seq__piece { font-family: var(--font-title); font-size: 1.125rem; color: var(--ink-body); }
.seq__list li a:hover .seq__piece { color: var(--ink); }
.js .seq__list li[data-hidden] { display: none; }
/* phones and upright tablets: the list starts near the logo's corner — its heading moves to the right (owner) */
@media (max-width: 63.99rem) { .seq__list > .meta { text-align: end; } }
/* phones: titles only, so six pieces, their bars and the footer all fit beneath the logo (owner) */
@media (max-width: 40rem) { .seq__list .label { display: none; } .seq__list li a { padding-block: 0.7rem; } }
.seq__pager { margin-block-start: var(--space-md); grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 1fr; }
.seq__pager[hidden] { display: none; }
.seq__pager button { padding: 0.9rem 0; background: none; border: 0; cursor: pointer; }
.seq__pager button i { display: block; height: 1px; background: var(--ink-muted); opacity: 0.45; transition: height var(--dur-gentle) var(--ease-out); }
.seq__pager button[aria-current] i { height: 4px; background: var(--breath, var(--accent)); opacity: 1; }   /* a feeling has no breath colour: its own colour */
.seq__pager button:hover i { opacity: 0.8; }
/* a feeling's page, after the sequence: its note, where it is found, and the feeling beside it — on the page colour */
.colour__start {   /* the end-of-piece buttons' look: a quiet outline, never a loud fill */
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0.5rem 1.4rem;
  color: var(--ink-muted);
  text-decoration: none;
  border: 1px solid color-mix(in oklab, var(--ink-muted) 80%, transparent);
  border-radius: 999px;
  transition: color var(--dur-gentle) var(--ease-out), border-color var(--dur-gentle) var(--ease-out);
}
.colour__start:hover,
.colour__start:focus-visible { color: var(--ink); border-color: var(--ink-muted); }
.nearby__heading { outline: none; }
/* the nearby list only — the colour question lives in the same aside and must not take its rules and lines */
.nearby__more ul { border-top: 1px solid var(--line); }
.nearby__more li > a { display: block; padding-block: 1.3rem; border-bottom: 1px solid var(--line); text-decoration: none; }
.nearby__why { display: block; }
.nearby__title {
  display: block;
  margin-block-start: 0.2rem;
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--ink);
  transition: color var(--dur-gentle) var(--ease-out);
}
.nearby a:hover .nearby__title { color: var(--accent); }

/* wide screens: the choices and, after "อ่านต่อ", the three stories appear in the reading column on the right,
   in place of the buttons — like a panel on the page, not a pop-up (owner). They sit on the same veil as the words,
   so nothing else has to cover the photograph. */
@media (min-width: 64rem) {
  .nearby__ask { text-align: start; }
  .nearby__choices { justify-content: flex-start; }
}

/* ==========================================================================
   Footer · leaving the house
   ========================================================================== */

/* On every page the footer lies over the foot of the last section (owner): pulled up by its own height
   (--footer-h, site.js), no ground of its own. site.js adds the same height to the last section's bottom padding,
   so its words stay clear while its picture or colour runs on underneath. */
.site-footer {
  position: relative;
  z-index: 2;
  margin-block-start: calc(-1 * var(--footer-h, 0px));
  text-shadow: 0 0 0.5em var(--paper), 0 0 1.2em color-mix(in oklab, var(--paper) 85%, transparent);   /* readable on any ground */
  width: min(100% - 2 * var(--space-page), var(--measure-wide));
  margin-inline: auto;
  /* below the footer text: the same space as between the line and the text (owner) */
  padding-block: 0 var(--space-sm);   /* low (owner): the section above keeps its own room */
  transition: padding-block-start var(--dur-atmos) var(--ease-atmos);
}
/* articles: the footer comes close under the two buttons, and makes room once the stories are opened (owner) */
.footer__line {
  font-size: var(--fs-subtitle);
  line-height: 1.8;
  font-weight: var(--fw-light);
  color: var(--ink);
}
.footer__meta { margin-block-start: 0; }
/* two rows, the line between them (owner): the name and เกี่ยวกับ above, the rights and the channels below —
   the same space above the line as below it */
.footer__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem var(--space-md);
}
.footer__row p { margin: 0; }
/* the English brand line as in the clips (owner, 25 Sep 2026): tracked capitals — the Thai no-letterspacing rule does not apply */
.tagline { font-weight: var(--fw-medium); letter-spacing: 0.28em; text-transform: uppercase; }   /* footer, About and library labels */
.footer__row .tagline { font-size: 0.85em; }   /* capitals look larger than the name beside them */
.footer__row--top { padding-block-end: var(--space-sm); }
.footer__row--bottom { padding-block-start: var(--space-sm); border-top: 1px solid var(--line); }
.footer__meta a { text-decoration: none; }
.footer__meta a:hover,
.footer__meta a[aria-current="page"] { color: var(--ink); }
.footer__social { display: flex; justify-content: flex-end; align-items: center; gap: 3rem; height: 1lh; }   /* one text line tall, marks centred on it; the wide gap parts the two groups (owner, 27 Sep 2026) */
.footer__tools,
.footer__channels { display: flex; align-items: center; gap: 1.25rem; }
/* wide article pages: the tools line up with the story's words (site.js initFooterAlign sets their margin) */
.footer__social.is-aligned { flex: 1; justify-content: space-between; }
.footer__icon { display: inline-flex; padding: 0.25rem; margin: -0.25rem; }   /* 24px to tap, 16px to see */
.footer__icon svg { display: block; }
/* the lamp: a plain button dressed as the channel marks; lit when the page is light */
.footer__lamp { background: none; border: 0; color: inherit; cursor: pointer; font: inherit; }
.footer__lamp:hover { color: var(--ink); }
.footer__lamp:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.footer__lamp[aria-pressed="true"] .lamp__glass { fill: currentColor; fill-opacity: 0.28; }
.lamp__rays { opacity: 0; transition: opacity var(--dur-fast) ease; }
.footer__lamp[aria-pressed="true"] .lamp__rays { opacity: 1; }   /* lit: short strokes of light around the bulb (owner) */
/* text size ก ก ก — three plain letters at three sizes; the one in use is underlined, not only coloured */
.footer__text { display: inline-flex; align-items: baseline; gap: 0.15rem; }
.footer__size { background: none; border: 0; color: inherit; cursor: pointer; font-family: var(--font-meta); font-size: 0.8125rem; line-height: 1; padding: 0.3rem 0.3rem; min-width: 1.5rem; min-height: 1.5rem; }
.footer__size--2 { font-size: 1rem; }
.footer__size--3 { font-size: 1.1875rem; }
.footer__size:hover { color: var(--ink); }
.footer__size[aria-pressed="true"] { color: var(--ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.3em; }
.footer__size:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 2px; }
/* phones (owner, 27 Sep 2026): ก ก ก + lamp at the left edge, the two channels at the right, and the copyright
   shrinks to one line — sized by the screen width, so it stays one line at any text size (ก ก ก) */
@media (max-width: 40rem) {
  .footer__social { flex: 1 0 100%; justify-content: space-between; }
  .footer__rights { font-size: min(0.8125rem, (100vw - 2 * var(--space-page)) / 20); white-space: nowrap; }   /* the line is ~19 font-sizes long */
}
/* a link inside a sentence keeps a quiet underline, or nobody knows it is one */
.footer__rights a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.2em; text-decoration-color: color-mix(in oklab, currentColor 45%, transparent); }

/* ==========================================================================
   Player · a small object resting in the room
   ========================================================================== */

.player {
  position: fixed;
  inset-inline-start: 1rem;
  inset-block-end: 1rem;
  z-index: 60;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  column-gap: 0.75rem;
  width: min(19rem, calc(100% - 2rem));
  padding: 0.65rem 0.5rem 0.2rem 0.65rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-large);
  /* a shadow that lifts it off the page (owner) — --shadow-tone is warm brown on light pages, deep black on dark ones
     (the old soft shadow was tuned for light pages and vanished on dark): close edge · middle lift · far soft fall */
  box-shadow:
    0 1px 2px var(--shadow-tone),
    0 8px 20px -6px var(--shadow-tone),
    0 24px 48px -16px var(--shadow-tone);
  font-family: var(--font-meta);
  animation: arrive var(--dur-gentle) var(--ease-out) both;
  view-transition-name: player;
}
.player[hidden] { display: none; }

.player__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), opacity var(--dur-fast);
}
.player__btn:hover { background: var(--paper-deep); }
.player__btn svg { width: 0.8rem; height: 0.8rem; }
.player__mute { color: var(--ink-muted); }   /* the same ring as play — it stands where the hide mark was (owner) */
.player__mute .i-muted { display: none; }
.player__mute[aria-pressed="true"] .i-sound { display: none; }
.player__mute[aria-pressed="true"] .i-muted { display: block; }

.player[data-state="loading"] [data-player-toggle] { opacity: 0.55; }

.player__info { min-width: 0; line-height: 1.45; }
.player__status {
  font-size: 0.75rem;
  color: var(--ink-muted);
}
/* only the Latin "Now playing" is tracked — Thai states stay unspaced */
.player[data-state="playing"] .player__status {
  font-size: 0.6875rem;
  font-weight: var(--fw-medium);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.player__title {
  overflow: hidden;
  font-size: 0.9375rem;
  color: var(--ink);
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* the title links to the source clip — attribution without an extra control */
.player__title a { text-decoration-color: transparent; }
.player__title a:hover { text-decoration-color: currentColor; }
.player__channel { font-size: 0.8125rem; color: var(--ink-muted); }

.player__seek {
  --p: 0%;
  grid-column: 1 / -1;
  width: 100%;
  height: 22px;
  margin: 0.25rem 0 0;
  background: transparent;
  appearance: none;
  cursor: pointer;
}
.player__seek::-webkit-slider-runnable-track {
  height: 2px;
  background: linear-gradient(90deg, var(--accent) var(--p), var(--line) var(--p));
  border-radius: 2px;
}
.player__seek::-webkit-slider-thumb {
  appearance: none;
  width: 11px; height: 11px;
  margin-top: -4.5px;
  background: var(--accent);
  border-radius: 50%;
  opacity: 0;
  transition: opacity var(--dur-fast);
}
.player__seek::-moz-range-track { height: 2px; background: var(--line); border-radius: 2px; }
.player__seek::-moz-range-progress { height: 2px; background: var(--accent); }
.player__seek::-moz-range-thumb { width: 11px; height: 11px; background: var(--accent); border: 0; border-radius: 50%; opacity: 0; }
.player:hover .player__seek::-webkit-slider-thumb,
.player__seek:focus-visible::-webkit-slider-thumb { opacity: 1; }
.player:hover .player__seek::-moz-range-thumb,
.player__seek:focus-visible::-moz-range-thumb { opacity: 1; }
.player__seek:focus-visible { outline-offset: 0; }

/* the channel's own player — YouTube: visible, at least 200×200px, nothing laid over it */
.player__video {
  grid-column: 1 / -1;
  height: 200px;   /* YouTube's minimum — width follows the player */
  margin: -0.15rem 0.15rem 0.55rem 0;
  overflow: hidden;
  background: var(--ink);
  border-radius: calc(var(--radius-large) - 6px);
}
.player__video[hidden] { display: none; }
.player__video { position: relative; }
.player__video iframe { display: block; width: 100%; height: 100%; border: 0; }
/* the article's photograph as the clip's cover — while loading and paused only; a playing video is never covered */
.player__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  transition: opacity var(--dur-gentle) ease;
}
.player__poster[hidden] { display: none; }
.player[data-state="playing"] .player__poster { opacity: 0; visibility: hidden; }
.player:has(.player__video:not([hidden])) { width: min(22.5rem, calc(100% - 2rem)); }

/* leave room so the player never hides the last line */
:root[data-player-open] body { padding-block-end: 6.5rem; }
:root[data-player-open] body:has(.player__video:not([hidden])) { padding-block-end: 20rem; }
/* wide screens: the small player sits to the left of the footer instead of pushing the page longer;
   the footer text only steps right if the player would otherwise cover it (player: 1rem + 19rem + 1rem gap) */
@media (min-width: 64rem) {
  :root[data-player-open] body:not(:has(.player__video:not([hidden]))) { padding-block-end: 0; }
  :root[data-player-open] .footer__meta {
    padding-inline-start: max(0px, calc(21rem - (100vw - min(100vw - 2 * var(--space-page), var(--measure-wide))) / 2));
  }
}

@media (max-width: 40rem) {
  /* phones show the status too (owner, 25 Sep 2026: the invitation "ลองเปิดฟังไปพร้อมกับการอ่าน" should be seen) —
     one line, so the player keeps its height */
  .player__status { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  /* phones: the player spans the screen with the same margin both sides, centred (owner) */
  .player,
  .player:has(.player__video:not([hidden])) { inset-inline: 1rem; width: auto; margin-inline: auto; }
}

/* ==========================================================================
   Walking from one room into another — cross-document view transitions
   ========================================================================== */

@view-transition { navigation: auto; }

/* the chosen colour follows the reader in (owner, 27 Sep 2026; site.js colourWash): a circle of the colour opens from
   the pressed dot to the farthest corner, beneath the logo and its rings (z 49–50), then the crossfade dissolves it
   into the story. Mixed a little with the page's paper so the darker colours arrive as a tint, not a blackout. */
.colour-wash {
  position: fixed;
  z-index: 48;
  left: calc(var(--x) - var(--r));
  top: calc(var(--y) - var(--r));
  width: calc(2 * var(--r));
  height: calc(2 * var(--r));
  border-radius: 50%;
  background: color-mix(in oklab, var(--wash) 78%, var(--paper));
  pointer-events: none;
  scale: 0;
  transition: scale 750ms cubic-bezier(0.45, 0.05, 0.35, 0.95);
}
.colour-wash.is-open { scale: 1; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 900ms;
  animation-timing-function: cubic-bezier(0.33, 0, 0.2, 1);
}

/* ==========================================================================
   Reduced motion — a complete, still experience
   ========================================================================== */

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

  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .scene__light, .scene__detail { animation: none !important; }
  .room-entry a:hover .room-entry__line { transform: none; }
}

/* ==========================================================================
   Press kit · /presskit/ (owner, 26 Sep 2026) — Day One → features, for people the work is shown to.
   The house's own paper, type and quiet; one column, wider only where a grid helps.
   ========================================================================== */

.press { padding-block: calc(var(--space-xl) + 2rem) var(--space-section); }
.press > * { max-width: calc(var(--measure) + 2 * var(--space-page)); margin-inline: auto; padding-inline: var(--space-page); }
.press > .press__image,
.press > .press__section--wide { max-width: calc(var(--measure-wide) + 2 * var(--space-page)); }

.press__hero { padding-block-end: var(--space-lg); }
.press__hero .label,
.press__section > .label { color: var(--ink-muted); margin: 0 0 var(--space-xs); }
.press__title { font-family: var(--font-title); font-size: var(--fs-display); font-weight: var(--fw-medium); line-height: 1.15; color: var(--ink); margin: 0; }
.press__tagline { font-family: var(--font-meta); font-size: var(--fs-meta); color: var(--brand-green-text); margin: var(--space-xs) 0 var(--space-md); }
.press__lede { font-family: var(--font-text); font-size: var(--fs-subtitle); line-height: 1.7; color: var(--ink-body); margin: 0; }

.press > .press__image { padding-inline: var(--space-page); }
.press__image { aspect-ratio: 16 / 9; border-radius: var(--radius-medium); }
.press__image img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-medium); }

.press__section { padding-block-start: var(--space-section); }
.press__section h2 { font-family: var(--font-title); font-size: var(--fs-title); font-weight: var(--fw-medium); line-height: 1.25; color: var(--ink); margin: 0 0 var(--space-md); }
.press__section p { font-family: var(--font-text); font-size: var(--fs-body); line-height: 1.95; color: var(--ink-body); margin: 0 0 var(--space-sm); }
.press__quote { margin: var(--space-lg) 0; padding: 0 0 0 var(--space-md); border-left: 2px solid var(--brand-green-text); }
.press__quote p { font-size: var(--fs-subtitle); line-height: 1.75; color: var(--ink); }

/* the road — a thin line with a mark at each day; Day One carries the green */
.press__path { list-style: none; margin: 0; padding: 0; border-left: 1px solid var(--line); }
.press__step { position: relative; padding: 0 0 var(--space-lg) var(--space-md); }
.press__step::before { content: ""; position: absolute; left: -4px; top: 0.55em; width: 7px; height: 7px; border-radius: 50%; background: var(--ink-muted); }
.press__step--one::before { background: var(--brand-green-text); width: 9px; height: 9px; left: -5px; }
.press__date { margin: 0; color: var(--ink-muted); }
.press__step-title { font-family: var(--font-title); font-size: var(--fs-subtitle); font-weight: var(--fw-medium); color: var(--ink); margin: 0.2rem 0 0.4rem; }
.press__step p:last-child { font-size: 1rem; line-height: 1.85; margin: 0; }

/* features — one column on a phone, three across when there is room */
.press__features { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-lg) var(--space-md); grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr)); }
.press__feature { border-top: 1px solid var(--line); padding-top: var(--space-sm); }
.press__feature .label { color: var(--ink-muted); margin: 0 0 var(--space-xs); }
.press__feature h3 { font-family: var(--font-title); font-size: var(--fs-subtitle); font-weight: var(--fw-medium); color: var(--ink); margin: 0 0 var(--space-xs); }
.press__feature p:last-of-type { font-size: 1rem; line-height: 1.85; margin: 0; }
.press__swatches { list-style: none; margin: var(--space-sm) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; font-family: var(--font-meta); font-size: var(--fs-meta); color: var(--ink-body); }
.press__swatches li { display: inline-flex; align-items: center; gap: 0.4rem; }
.press__swatch { width: 0.85rem; height: 0.85rem; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12); }

.press__numbers { margin: 0; display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr)); }
.press__numbers div { display: flex; flex-direction: column-reverse; border-top: 1px solid var(--line); padding-top: var(--space-sm); }
.press__numbers dd { margin: 0; font-family: var(--font-title); font-size: var(--fs-display); font-weight: var(--fw-medium); line-height: 1.1; color: var(--ink); }
.press__numbers dt { font-family: var(--font-meta); font-size: var(--fs-meta); color: var(--ink-muted); margin-top: 0.3rem; }

.press__assets { list-style: none; margin: 0 0 var(--space-lg); padding: 0; font-family: var(--font-meta); font-size: 1rem; line-height: 1.6; color: var(--ink-body); }
.press__assets li { padding: 0.6rem 0; border-bottom: 1px solid var(--line); }
.press__assets a { color: var(--ink); text-decoration-thickness: 1px; text-underline-offset: 0.2em; text-decoration-color: color-mix(in oklab, currentColor 40%, transparent); }
.press__assets a:hover { text-decoration-color: currentColor; }
.press__cta { display: inline-block; font-family: var(--font-meta); font-size: 1rem; color: var(--ink); text-decoration: none; padding: 0.7rem 1.4rem; border: 1px solid var(--line); border-radius: 999px; }
.press__cta:hover { border-color: var(--ink-muted); }
.press a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

/* press kit · real screens above the features */
.press__screens { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm); margin: 0 0 var(--space-lg); }
.press__screen { margin: 0; }
.press__screen--wide { grid-column: 1 / -1; }
.press__screen img { width: 100%; height: auto; display: block; border-radius: var(--radius-medium); box-shadow: 0 0 0 1px var(--line); }
.press__screen figcaption { color: var(--ink-muted); margin-top: 0.4rem; }
@media (max-width: 40rem) { .press__screens { grid-template-columns: 1fr; } }

/* ── AFK · resting with the music (owner) ─────────────────────────────────────────────────────────
   site.js sets [data-afk] after 20s of stillness while the music plays at a photograph: a story's opening, or on the
   home page the entrance and the Music Room. filter: opacity() rather than opacity, because the arrive/settle
   animations hold opacity with fill-mode both and would win. Slow to leave (4s), quick to come back (0.6s).
   [data-waking] keeps the first touch after resting from pressing a button nobody could see. */
:is(.page-article, .page-home) :is(.site-header, .scroll-cue, .player, .site-footer),
.page-article .entry > :is(.entry__head, .entry__body, .nearby),
.page-home :is(.arrival__inner, .arrival__foot, .rooms__inner, .place__inner) {
  transition: filter 0.6s var(--ease-out);
}
:root[data-afk] :is(.site-header, .scroll-cue, .player, .site-footer),
:root[data-afk] .entry > :is(.entry__head, .entry__body, .nearby),
:root[data-afk] :is(.arrival__inner, .arrival__foot, .rooms__inner, .place__inner) {
  filter: opacity(0);
  transition-duration: 4s;
  transition-timing-function: var(--ease-atmos);
}
:root:is([data-afk], [data-waking]) :is(.site-header, .player, .site-footer, .entry, main) { pointer-events: none; }
/* the music plays through YouTube, and a playing embed must stay in sight: the player with its video thins to 60%
   instead of leaving (owner, 27 Sep) — still plainly visible, just quieter beside the photograph */
:root[data-afk] .player:has(.player__video:not([hidden])) { filter: opacity(0.6); }
/* home: the paper laid over the photographs is there for the words — with the words gone, the photograph comes clear */
.page-home :is(.arrival, .place) .photo--scrim::after { transition: opacity 0.6s var(--ease-out); }
:root[data-afk] .page-home :is(.arrival, .place) .photo--scrim::after { opacity: 0; transition: opacity 4s var(--ease-atmos); }
/* the picture drifts in, about 5% over a minute and a half, and eases back when the reader returns */
.page-article .entry > .entry__image img,
.page-home :is(.arrival, .place) > .photo img { transition: scale 2.4s var(--ease-atmos); }
:root[data-afk] .page-article .entry > .entry__image img,
:root[data-afk] .page-home :is(.arrival, .place) > .photo img { scale: 1.05; transition: scale 90s linear; }
@media (prefers-reduced-motion: reduce) {
  :root[data-afk] :is(.entry__image, .photo) img { scale: none; }
}

/* ── /breathe · a link to share (owner, 27 Sep 2026) ──────────────────────────────────────────────
   The breathing opens by itself; this is what stays behind it: the home photograph and two quiet ways on, on a
   soft pool of paper so the words read over any part of the picture. */
.breathe-page .arrival { grid-template-rows: 1fr; place-items: center; }
.breathe-page__inner {
  display: grid;
  justify-items: center;
  gap: var(--space-sm);
  padding: var(--space-xl) calc(var(--space-page) + var(--space-lg));
  text-align: center;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--paper) 94%, transparent) 55%, color-mix(in oklab, var(--paper) 80%, transparent) 78%, transparent);
  text-shadow: 0 0 0.6em var(--paper);
}
.breathe-page__title { margin: 0; font-family: var(--font-title); font-weight: var(--fw-regular); font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem); color: var(--ink); }
.breathe-page__how { margin: 0 0 var(--space-sm); font-family: var(--font-meta); font-size: 0.9375rem; color: var(--ink-body); }
.breathe-page__home {
  font-family: var(--font-meta);
  font-size: 0.9375rem;
  color: var(--ink-body);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
}
.breathe-page__home:hover { color: var(--ink); }

/* ── 404 · a quiet page, not an error screen (27 Sep 2026) ── */
.lost {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: calc(var(--space-xl) + 3rem) var(--space-page) var(--space-xl);
  text-align: center;
}
.lost__inner { display: grid; justify-items: center; gap: var(--space-sm); max-width: 32rem; }
.lost__title { margin: 0; font-family: var(--font-title); font-weight: var(--fw-regular); font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem); color: var(--ink); }
.lost__line { margin: 0 0 var(--space-sm); color: var(--ink-body); text-wrap: balance; }
.lost__ways { margin: 0; }
.lost__more { margin: var(--space-xs, 0.5rem) 0 0; display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 0.25rem 0.75rem; font-family: var(--font-meta); font-size: 0.9375rem; color: var(--ink-muted); }
.lost__link {
  background: none; border: 0; padding: 0.35rem 0.25rem; font: inherit; color: var(--ink-body); cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
}
.lost__link:hover { color: var(--ink); }
.lost__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* ── Consent for Google Analytics (27 Sep 2026) — one quiet line at the foot, the footer's type and colours;
   it rises in after the first screen has settled and leaves for good once answered ── */
.consent {
  position: fixed;
  z-index: 70;   /* above the player while it asks, below the breathing layer */
  inset-inline: 1rem;
  inset-block-end: 1rem;
  margin-inline: auto;
  max-width: 40rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.25rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-large);
  box-shadow: var(--shadow-atmos);
  font-family: var(--font-meta);
  font-size: 0.875rem;
  color: var(--ink-body);
  opacity: 0;
  translate: 0 0.5rem;
  transition: opacity 0.6s var(--ease-out), translate 0.6s var(--ease-out);
}
.consent.is-shown { opacity: 1; translate: 0 0; }
.consent__line { margin: 0; flex: 1 1 18rem; }
.consent__choices { margin: 0; display: flex; gap: 0.5rem; }
.consent button {
  font: inherit; cursor: pointer; padding: 0.45rem 0.9rem; border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--ink) 30%, transparent); background: none; color: var(--ink);
}
.consent .consent__yes { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.consent button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
:root[data-afk] .consent { opacity: 0; }
