  :root {
    /* base ink / paper */
    --ink-void: #0B0B0D;
    --ink-deep: #14141A;
    --ink-soft: #1F2026;
    --paper: #EDE8DF;
    --paper-dim: #9A968C;
    --paper-faint: #7D796C;  /* recessive but readable: ≥4.5:1 on the void (WCAG AA) */

    /* seasonal (overridden per data-season) */
    --bg: #0E0B0D;
    --accent: #E6A9C4;
    --glow: #F3D7E2;
    --text: #F2E9EC;

    --ease-breath: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-ink: cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* haru / spring: soft warm dawn, blush pink */
  [data-season="haru"] { --bg:#170E14; --accent:#E89DBE; --glow:#F7D4E3; --text:#F4ECEE; }
  /* natsu / summer: deep cool green-black with a warm inner glow */
  [data-season="natsu"]{ --bg:#06110D; --accent:#A8DC95; --glow:#F2F4C2; --text:#E7F0E6; }
  /* aki / autumn: low amber ember, enclosed warmth */
  [data-season="aki"]  { --bg:#160C06; --accent:#DC9046; --glow:#F0BC6C; --text:#F3E7D6; }
  /* fuyu / winter: cold pale blue, high-key and airy */
  [data-season="fuyu"] { --bg:#0C1116; --accent:#A7C2D6; --glow:#EEF6FB; --text:#EAF1F6; }

  /* GROUND · AMOLED variant: the surround goes pure black so the seasonal
     light-pools (kept via --bg) read as illumination against true black.
     Surfaces (tiles/panels) deepen too. Default (no attr) stays the slate grey
     above. Toggled live via the ground control; persisted in localStorage. */
  [data-ground="amoled"] {
    --ink-void: #000000;
    --ink-deep: #070709;
    --ink-soft: #15151A;
    --paper-faint: #827E71;
  }
  /* on AMOLED, ease the grain so the true-black surround stays clean
     (html-qualified so it outweighs the per-season #grain rules below) */
  html[data-ground="amoled"] #grain { opacity: 0.03; }

  /* ===================================================================
     ===== per-season atmospheres =====
     Each season gets its own #bg light-source position, gradient colours
     and vignette weight so the four moods read distinctly:
       haru:  soft warm dawn, light high-right, gentle blush, open
       natsu: overhead noon light over deep green-black, lush, enclosed
       aki:   low warm ember from below-right, amber, most enclosed
       fuyu:  cold diffuse high-key light from above, airy, most negative space
     The base #bg keeps its `transition: background 2.2s` so switching
     seasons still cross-dissolves smoothly. We also vary #grain opacity
     and the brand/season-word glow per season.
     =================================================================== */

  /* haru: dawn light high-right, a low warm horizon, soft vignette */
  [data-season="haru"] #bg {
    background:
      radial-gradient(95% 75% at 78% 6%, var(--bg), transparent 58%),
      radial-gradient(120% 80% at 30% 112%, rgba(232,157,190,0.10), transparent 60%),
      radial-gradient(150% 130% at 20% 102%, rgba(0,0,0,0.45), transparent 58%),
      var(--ink-void);
  }
  [data-season="haru"] #grain { opacity: 0.04; }

  /* natsu: light overhead/centre-top, deep cool body, denser vignette */
  [data-season="natsu"] #bg {
    background:
      radial-gradient(80% 70% at 50% -4%, var(--bg), transparent 55%),
      radial-gradient(70% 60% at 50% 36%, rgba(242,244,194,0.07), transparent 62%),
      radial-gradient(160% 130% at 50% 118%, rgba(0,0,0,0.62), transparent 56%),
      var(--ink-void);
  }
  [data-season="natsu"] #grain { opacity: 0.05; }

  /* aki: low warm ember from below-right, heavy enclosing vignette */
  [data-season="aki"] #bg {
    background:
      radial-gradient(110% 90% at 70% 116%, var(--bg), transparent 60%),
      radial-gradient(90% 70% at 76% 100%, rgba(220,144,70,0.14), transparent 55%),
      radial-gradient(170% 150% at 14% 0%, rgba(0,0,0,0.70), transparent 52%),
      var(--ink-void);
  }
  [data-season="aki"] #grain { opacity: 0.065; }

  /* fuyu: cold diffuse light from above, high-key, lightest vignette (most ma) */
  [data-season="fuyu"] #bg {
    background:
      radial-gradient(130% 95% at 50% -10%, var(--bg), transparent 64%),
      radial-gradient(120% 90% at 50% 8%, rgba(238,246,251,0.06), transparent 60%),
      radial-gradient(150% 140% at 20% 108%, rgba(0,0,0,0.34), transparent 60%),
      var(--ink-void);
  }
  [data-season="fuyu"] #grain { opacity: 0.055; }

  /* per-season glow on the brand glyph + season-word (subtle, uses --glow) */
  [data-season="haru"] .brand .glyph,
  [data-season="haru"] .season-word { text-shadow: 0 0 14px rgba(247,212,227,0.30); }
  [data-season="natsu"] .brand .glyph,
  [data-season="natsu"] .season-word { text-shadow: 0 0 12px rgba(242,244,194,0.22); }
  [data-season="aki"] .brand .glyph,
  [data-season="aki"] .season-word { text-shadow: 0 0 16px rgba(240,188,108,0.34); }
  [data-season="fuyu"] .brand .glyph,
  [data-season="fuyu"] .season-word { text-shadow: 0 0 18px rgba(238,246,251,0.40); }

  /* very gentle ambient drift of the light source, calm, slow, optional.
     Drifts via transform (composited on the GPU) rather than
     background-position, which repainted the full-viewport gradient stack
     every frame for the life of the page. scale(1.06) keeps the oversized
     layer covering the viewport while it wanders.
     Gated behind no-preference; disabled in the reduced-motion block below. */
  @media (prefers-reduced-motion: no-preference) {
    #bg {
      will-change: transform;
      animation: ambient-drift 46s ease-in-out infinite alternate;
    }
    @keyframes ambient-drift {
      from { transform: translate3d(0, 0, 0) scale(1.06); }
      to   { transform: translate3d(-1.6%, 1.4%, 0) scale(1.06); }
    }
  }

  * { margin: 0; padding: 0; box-sizing: border-box; }

  /* text selection stays inside the palette (the browser default blue
     shatters the mood the instant a reader copies a verse) */
  ::selection {
    background: color-mix(in srgb, var(--accent) 28%, transparent);
    color: var(--paper);
  }

  /* quiet, thin scrollbars on the pages that scroll (poems, faq): recessive
     but perceivable on both grounds (ink-soft vanished on true black) */
  html { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--paper-dim) 35%, transparent) transparent; }
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--paper-dim) 35%, transparent); border-radius: 5px;
    border: 2px solid transparent; background-clip: padding-box;
  }

  html, body { height: 100%; overflow: hidden; background: var(--ink-void); }
  body {
    color: var(--paper);
    font-family: 'EB Garamond', serif;
    -webkit-font-smoothing: antialiased;
    transition: background 2.2s var(--ease-breath);
  }

  #bg {
    position: fixed; inset: 0; z-index: 0;
    transition: background 2.2s var(--ease-breath);
    background:
      radial-gradient(120% 90% at 72% 8%, var(--bg), transparent 60%),
      radial-gradient(150% 120% at 18% 105%, rgba(0,0,0,0.55), transparent 55%),
      var(--ink-void);
  }
  #grain {
    position: fixed; inset: 0; z-index: 1; pointer-events: none;
    opacity: 0.045; mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  }
  canvas#particles { position: fixed; inset: 0; z-index: 2; pointer-events: none; }

  /* chrome that obeys cursor-hush */
  .chrome { transition: opacity 1.2s var(--ease-breath); }
  body.hushed .chrome { opacity: 0; pointer-events: none; }
  /* boot: the room lights up — chrome and the ground kanji breathe in
     together once the first poem is ready (class managed by app.js; if JS
     never runs, nothing is ever hidden) */
  body.preboot .chrome { opacity: 0; }
  body.preboot .glyph-bg { opacity: 0; }

  /* ---- brand ---- */
  .brand {
    position: fixed; top: 26px; left: 38px; z-index: 12;
    display: flex; align-items: baseline; gap: 15px; line-height: 1;
    text-decoration: none; cursor: pointer;
  }
  .brand .glyph {
    font-family: 'Shippori Mincho', serif; font-size: 42px; line-height: 1; color: var(--accent);
    transition: color 2.2s var(--ease-breath), text-shadow 0.6s var(--ease-breath), transform 0.6s var(--ease-breath);
  }
  .brand .name {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 15px; letter-spacing: 0.52em;
    text-transform: uppercase; color: var(--paper-dim);
    transition: color 0.6s var(--ease-breath);
  }
  /* it now leads to "learn" — give it a quiet link affordance on hover/focus */
  .brand:hover .glyph { transform: translateY(-1px); }
  .brand:hover .name { color: var(--paper); }
  .brand:focus-visible { outline: none; }
  .brand:focus-visible .name { color: var(--accent); }
  .brand:focus-visible .glyph { text-shadow: 0 0 16px color-mix(in srgb, var(--accent) 60%, transparent); }

  /* back-to-gallery: appears top-centre only while reading a poem opened from the gallery */
  .back-gallery {
    position: fixed; top: 30px; left: 50%; transform: translateX(-50%); z-index: 13;
    background: none; border: 1px solid var(--ink-soft); border-radius: 40px;
    color: var(--paper-dim); cursor: pointer;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 10px;
    letter-spacing: 0.28em; text-transform: uppercase; padding: 9px 18px;
    transition: color 0.5s var(--ease-breath), border-color 0.5s var(--ease-breath), transform 0.5s var(--ease-breath);
  }
  .back-gallery:hover { color: var(--paper); border-color: var(--accent); transform: translateX(-50%) translateY(1px); }
  .back-gallery[hidden] { display: none; }

  /* ---- ground toggle (amoled ⇄ slate) · discreet, bottom-left ---- */
  .ground-toggle {
    position: fixed; bottom: 30px; left: 38px; z-index: 12;
    display: flex; align-items: center; gap: 10px;
    background: none; border: none; cursor: pointer; padding: 4px 2px;
    color: var(--paper-dim);
    transition: color 0.6s var(--ease-breath), opacity 1.2s var(--ease-breath);
  }
  .ground-toggle:hover { color: var(--paper); }
  .ground-toggle:focus-visible {
    outline: none; color: var(--accent); border-radius: 40px;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
  }
  .ground-toggle .gt-dot {
    width: 13px; height: 13px; border-radius: 50%; flex: none;
    border: 1px solid currentColor;
    /* half-lit disc: the "illuminated" half hints at the ground tone */
    background: linear-gradient(90deg, #000 0 50%, var(--paper-dim) 50% 100%);
    transition: background 0.6s var(--ease-breath);
  }
  .ground-toggle.amoled .gt-dot { background: linear-gradient(90deg, #000 0 50%, var(--accent) 50% 100%); }
  .ground-toggle .gt-label {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 10px;
    letter-spacing: 0.32em; text-transform: uppercase;
  }

  /* ---- ambient sound toggle ---- */
  /* More present than the other chrome: it reads as a real control (faint pill
     + border) and, while OFF, breathes gently to invite a first tap. Still
     recessive — never louder than the poem. */
  .sound-toggle {
    position: fixed; top: 90px; left: 38px; z-index: 12;
    display: flex; align-items: center; gap: 12px;
    cursor: pointer; padding: 9px 16px 9px 13px;
    color: var(--paper);
    background: color-mix(in srgb, var(--accent) 7%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--ink-soft));
    border-radius: 40px;
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    transition: color 0.6s var(--ease-breath), border-color 0.6s var(--ease-breath),
                background 0.6s var(--ease-breath), opacity 1.2s var(--ease-breath),
                transform 0.6s var(--ease-breath);
  }
  .sound-toggle[hidden] { display: none; }
  .sound-toggle:hover {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 55%, transparent);
    background: color-mix(in srgb, var(--accent) 13%, transparent);
  }
  .sound-toggle:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
  }
  .sound-toggle .sound-label {
    font-family: 'Inter', sans-serif; font-weight: 400; font-size: 11px;
    letter-spacing: 0.32em; text-transform: uppercase;
    transition: color 0.6s var(--ease-breath);
  }
  /* three little wave bars, the "speaker / wave" glyph */
  .sound-glyph {
    display: inline-flex; align-items: center; gap: 3px; height: 16px;
  }
  .sound-glyph .wave {
    width: 2.5px; border-radius: 2px; background: currentColor;
    opacity: 0.7; transition: height 0.5s var(--ease-breath), opacity 0.5s var(--ease-breath), background 0.6s var(--ease-breath);
  }
  .sound-glyph .w1 { height: 6px; }
  .sound-glyph .w2 { height: 13px; }
  .sound-glyph .w3 { height: 8px; }
  /* OFF (idle) invitation: the whole control breathes slowly until first use */
  @media (prefers-reduced-motion: no-preference) {
    .sound-toggle:not(.on) { animation: sndInvite 4.4s var(--ease-breath) infinite; }
    .sound-toggle:not(.on):hover { animation: none; }
    /* the invitation rests while the page is hushed (it is invisible anyway) */
    body.hushed .sound-toggle:not(.on) { animation: none; }
  }
  @keyframes sndInvite {
    0%, 100% { border-color: color-mix(in srgb, var(--accent) 24%, var(--ink-soft)); }
    50%      { border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
  }
  /* ON state: accent-tinted + a gentle breathing pulse on the bars */
  .sound-toggle.on {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 50%, transparent);
    background: color-mix(in srgb, var(--accent) 12%, transparent);
  }
  .sound-toggle.on .sound-glyph .wave { opacity: 1; background: var(--accent); }
  @media (prefers-reduced-motion: no-preference) {
    .sound-toggle.on .sound-glyph .w1 { animation: sndWave 2.6s var(--ease-breath) infinite; }
    .sound-toggle.on .sound-glyph .w2 { animation: sndWave 2.6s var(--ease-breath) 0.3s infinite; }
    .sound-toggle.on .sound-glyph .w3 { animation: sndWave 2.6s var(--ease-breath) 0.6s infinite; }
  }
  @keyframes sndWave {
    0%, 100% { transform: scaleY(0.55); }
    50%      { transform: scaleY(1); }
  }
  .sound-glyph .wave { transform-origin: center; }

  /* ---- season nav (read + gallery) ---- */
  .seasons {
    position: fixed; right: 40px; top: 50%; transform: translateY(-50%); z-index: 12;
    display: flex; flex-direction: column; gap: 24px; align-items: center;
  }
  .seasons button {
    background: none; border: none; cursor: pointer;
    font-family: 'Shippori Mincho', serif; font-size: 21px;
    color: var(--paper-dim); opacity: 0.55;
    writing-mode: vertical-rl; letter-spacing: 0.1em; padding: 3px;
    transition: color 0.7s var(--ease-breath), opacity 0.7s var(--ease-breath), transform 0.7s var(--ease-breath);
  }
  .seasons button:hover { opacity: 0.95; }
  .seasons button.active {
    color: var(--accent); opacity: 1; transform: scale(1.16);
    text-shadow: 0 0 14px color-mix(in srgb, var(--glow) 35%, transparent);
  }

  /* ---- mode panels (cross-dissolve) ---- */
  .panel {
    position: fixed; inset: 0; z-index: 5;
    opacity: 0; pointer-events: none;
    /* visibility keeps the two inactive panels' controls (compose inputs,
       gallery tiles) out of the tab order; it flips after the dissolve */
    visibility: hidden;
    transition: opacity 1s var(--ease-breath), visibility 0s linear 1s;
  }
  .panel.active {
    opacity: 1; pointer-events: auto; visibility: visible;
    transition: opacity 1s var(--ease-breath);
  }

  /* ============ READ ============ */
  #read { display: flex; }
  /* the share card's signature carried home: an enormous, breath-faint
     season kanji resting behind the poem. it must stay quieter than the
     light pool — presence, not decoration. */
  .glyph-bg {
    position: absolute; inset: 0; z-index: -1; pointer-events: none;
    display: flex; align-items: center; justify-content: center;
    font-family: 'Shippori Mincho', serif; font-weight: 500;
    font-size: clamp(240px, 48vmin, 540px); line-height: 1;
    color: var(--accent); opacity: 0.035;
    transform: translateY(-6vh);
    transition: color 2.2s var(--ease-breath), opacity 2.2s var(--ease-breath);
  }
  /* the kanji itself breathes, slower than anything else on the page */
  @media (prefers-reduced-motion: no-preference) {
    .glyph-bg::before { animation: glyphBreath 16s ease-in-out infinite alternate; }
    @keyframes glyphBreath {
      from { opacity: 1; }
      to   { opacity: 0.65; }
    }
  }
  [data-season="haru"] .glyph-bg::before { content: "春"; }
  [data-season="natsu"] .glyph-bg::before { content: "夏"; }
  [data-season="aki"]   .glyph-bg::before { content: "秋"; }
  [data-season="fuyu"]  .glyph-bg::before { content: "冬"; }
  /* a faint pool of light gathers behind the poem column so the verse reads
     as the one lit thing; tuned low and tied to --glow, recedes with chrome */
  #read::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: radial-gradient(46% 38% at 50% 34%, color-mix(in srgb, var(--glow) 5%, transparent), transparent 70%);
    opacity: 0; transition: opacity 2.2s var(--ease-breath);
  }
  #read.active::before { opacity: 1; }
  .stage {
    height: 100%; width: 100%;
    display: flex; flex-direction: column; align-items: center;
    justify-content: flex-start; text-align: center;
    padding: 22vh 8vw 150px;
    overflow-y: auto; scrollbar-width: none;
  }
  .stage::-webkit-scrollbar { width: 0; }
  .season-word {
    position: relative;
    font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 300;
    text-transform: uppercase; letter-spacing: 0.52em; color: var(--accent);
    opacity: 0; margin-bottom: 52px; padding-bottom: 18px;
    transition: opacity 1.2s var(--ease-breath);
  }
  .season-word.show { opacity: 0.72; }
  /* a slender breath-paced rule grows under the season word as it settles */
  .season-word::after {
    content: ""; position: absolute; left: 50%; bottom: 0;
    width: 0; height: 1px; transform: translateX(-50%);
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 60%, transparent), transparent);
    transition: width 1.8s var(--ease-ink) 0.3s;
  }
  .season-word.show::after { width: 64px; }
  .poem { max-width: 92vw; }
  .poem .line {
    font-size: clamp(1.7rem, 3.6vw, 2.7rem); font-weight: 400; line-height: 1.95;
    color: var(--text);
    white-space: nowrap;            /* each verse stays on one line (large screens) */
    opacity: 0; filter: blur(6px); letter-spacing: 0.18em;
    transition: opacity 1.4s var(--ease-ink), filter 1.4s var(--ease-ink), letter-spacing 1.4s var(--ease-ink);
  }
  /* on narrow screens allow wrapping so long verses never overflow */
  @media (max-width: 820px) {
    .poem { max-width: 34ch; }
    .poem .line { white-space: normal; }
  }
  /* shared/community poems can carry long lines; .wrap (set by renderRead)
     lets them fold on any width instead of clipping past the viewport */
  .poem.wrap { max-width: min(44ch, 92vw); }
  .poem.wrap .line { white-space: normal; }
  .poem .line.show {
    opacity: 1; filter: blur(0); letter-spacing: 0.01em;
    text-shadow: 0 0 26px color-mix(in srgb, var(--glow) 12%, transparent);
  }
  /* exit breath: on navigation the standing verse dissolves out quickly
     (~0.35s) before the next one's slow reveal — placed after .show so it
     wins the cascade while the swap is in flight */
  .poem.leaving .line {
    opacity: 0; filter: blur(5px); letter-spacing: 0.06em;
    transition: opacity 0.35s var(--ease-ink), filter 0.35s var(--ease-ink),
                letter-spacing 0.35s var(--ease-ink);
  }
  .meta { margin-top: 56px; opacity: 0; transition: opacity 1.2s var(--ease-breath) 0.2s; }
  .meta.show { opacity: 1; }
  .meta .author { font-style: italic; font-size: 18px; color: var(--paper-dim); letter-spacing: 0.03em; }
  /* a faint kanji-ish dot rests above the author, a quiet seal under the verse */
  .meta::before {
    content: "·"; display: block; color: var(--accent); opacity: 0.4;
    font-size: 20px; line-height: 1; margin-bottom: 18px;
    transition: opacity 1.2s var(--ease-breath);
  }
  /* romaji + source now live in the readings panel; kept in markup but hidden here */
  .meta .romaji, .meta .source { display: none; }

  /* ---- center poem set as vertical Japanese ---- */
  .poem.jp {
    display: flex; flex-direction: row-reverse; align-items: flex-start;
    justify-content: center; gap: clamp(20px, 4vw, 52px);
    max-width: none; margin: 4px auto 0;
  }
  .poem.jp .line {
    font-family: 'Shippori Mincho', serif;
    writing-mode: vertical-rl; text-orientation: upright;
    white-space: nowrap; line-height: 1.18;
    font-size: clamp(2.2rem, 5.2vw, 3.6rem);
    letter-spacing: 0.16em; color: var(--text);
    text-shadow: 0 0 22px color-mix(in srgb, var(--glow) 22%, transparent);
  }
  .poem.jp .line.show { letter-spacing: 0.1em; }

  .read-controls {
    position: fixed; bottom: 84px; left: 50%; transform: translateX(-50%); z-index: 13;
    display: flex; align-items: center; gap: 26px; flex-wrap: wrap; justify-content: center;
  }
  .dots { display: flex; gap: 14px; }
  /* dots are real buttons; the ::after pad grows each tap/click target to
     20px without changing the 6px visual (gap keeps neighbours from
     overlapping, so a tap between two dots is never mis-assigned) */
  .dot {
    width: 6px; height: 6px; border-radius: 50%; background: var(--paper-dim);
    border: none; padding: 0; position: relative;
    opacity: 0.35; cursor: pointer; transition: all 0.5s var(--ease-breath);
  }
  .dot::after { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
  .dot.active { background: var(--accent); opacity: 1; transform: scale(1.5); box-shadow: 0 0 10px var(--accent); }
  .dot:focus-visible {
    outline: none; opacity: 1;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent);
  }
  .arrows button {
    background: none; border: none; cursor: pointer; color: var(--paper-dim);
    font-size: 24px; line-height: 1; padding: 4px 6px;
    transition: color 0.4s, transform 0.4s var(--ease-breath);
  }
  .arrows button:hover { color: var(--accent); transform: scale(1.2); }

  /* ============ COMPOSE ============ */
  #compose .wrap {
    height: 100%; display: flex; flex-direction: column;
    align-items: center; justify-content: center; padding: 0 6vw;
  }
  #compose h2 {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 12px;
    letter-spacing: 0.46em; text-transform: uppercase; color: var(--accent);
    opacity: 0.85; margin-bottom: 46px;
  }
  .composer { width: min(640px, 88vw); }
  .composer .row {
    display: flex; align-items: center; gap: 22px;
    position: relative;
    border-bottom: 1px solid var(--ink-soft); padding: 8px 0;
    transition: border-color 0.7s var(--ease-breath);
  }
  .composer .row.ok { border-color: var(--accent); }
  /* while a line is being written, a breath-paced accent rule grows from the
     centre beneath it (the same gesture as the season-word hairline) */
  .composer .row::after {
    content: ""; position: absolute; left: 50%; bottom: -1px;
    width: 0; height: 1px; transform: translateX(-50%);
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 65%, transparent), transparent);
    transition: width 1.4s var(--ease-ink);
  }
  .composer .row:focus-within::after { width: 100%; }
  .composer input {
    flex: 1; background: none; border: none; outline: none; color: var(--text);
    font-family: 'EB Garamond', serif; font-size: clamp(1.4rem, 3vw, 2rem);
    font-weight: 400; padding: 12px 0; letter-spacing: 0.01em;
  }
  .composer input::placeholder { color: var(--paper-faint); font-style: italic; opacity: 0.7; }
  .composer .count {
    font-family: 'Inter', sans-serif; font-size: 12px; font-weight: 300;
    letter-spacing: 0.1em; min-width: 56px; text-align: right;
    color: var(--paper-faint); transition: color 0.5s var(--ease-breath);
  }
  .composer .count.ok { color: var(--accent); }
  .composer .count b { font-weight: 400; color: var(--paper); }

  .compose-actions {
    margin-top: 40px; display: flex; flex-direction: column; align-items: center; gap: 22px;
    min-height: 70px;
  }
  .settle-msg {
    font-style: italic; font-size: 17px; color: var(--paper-dim); height: 22px;
    transition: color 0.6s var(--ease-breath); text-align: center;
  }
  .settle-msg.done { color: var(--accent); }
  .action-row { display: flex; gap: 14px; opacity: 0; transform: translateY(8px); pointer-events: none; transition: all 0.8s var(--ease-breath); }
  .action-row.show { opacity: 1; transform: none; pointer-events: auto; }

  /* season picker in compose */
  .season-pick { display: flex; gap: 18px; margin-bottom: 40px; }
  .season-pick button {
    background: none; border: none; cursor: pointer; font-family: 'Shippori Mincho', serif;
    font-size: 20px; color: var(--paper-dim); opacity: 0.5; padding: 4px 8px;
    transition: all 0.5s var(--ease-breath);
  }
  .season-pick button.active { color: var(--accent); opacity: 1; transform: scale(1.15); }

  /* ============ GALLERY ============ */
  #gallery .gwrap { height: 100%; overflow-y: auto; padding: 14vh 6vw max(12vh, 120px); }
  #gallery .gwrap::-webkit-scrollbar { width: 0; }
  .gallery-head { text-align: center; margin-bottom: 8vh; }
  .gallery-head .gtitle { font-family: 'Inter', sans-serif; font-weight: 300; font-size: 12px; letter-spacing: 0.46em; text-transform: uppercase; color: var(--accent); opacity: 0.85; }
  .gallery-head .gsub { margin-top: 14px; font-style: italic; color: var(--paper-dim); font-size: 16px; }

  /* ---- collection tabs (masters / other hands) ---- */
  .gtabs {
    display: inline-flex; gap: 6px; margin-bottom: 26px;
    border: 1px solid var(--ink-soft); border-radius: 40px; padding: 4px;
  }
  .gtab {
    background: none; border: none; cursor: pointer;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 10px;
    letter-spacing: 0.28em; text-transform: uppercase; color: var(--paper-dim);
    padding: 9px 20px; border-radius: 40px;
    transition: color 0.5s var(--ease-breath), background 0.5s var(--ease-breath);
  }
  .gtab:hover { color: var(--paper); }
  .gtab.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }

  /* ---- subtle sort control (community only) ---- */
  .gsort {
    margin-top: 22px; display: flex; flex-wrap: wrap; gap: 4px 14px;
    align-items: center; justify-content: center;
  }
  .gsort[hidden] { display: none; }
  .gsort-label {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.3em; text-transform: uppercase; color: var(--paper-faint);
  }
  .gsort-opt {
    background: none; border: none; cursor: pointer;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.2em; text-transform: uppercase; color: var(--paper-dim);
    opacity: 0.6; padding: 4px 2px;
    transition: color 0.5s var(--ease-breath), opacity 0.5s var(--ease-breath);
  }
  .gsort-opt:hover { opacity: 1; color: var(--paper); }
  .gsort-opt.active { color: var(--accent); opacity: 1; }
  .grid {
    columns: 3 260px; column-gap: clamp(24px, 4vw, 56px); max-width: 1100px; margin: 0 auto;
  }
  /* per-season tile colour (--tile-c); falls back to neutral ink */
  .tile { --tile-c: var(--paper-dim); }
  .tile[data-season="haru"]  { --tile-c: #E89DBE; }
  .tile[data-season="natsu"] { --tile-c: #A8DC95; }
  .tile[data-season="aki"]   { --tile-c: #DC9046; }
  .tile[data-season="fuyu"]  { --tile-c: #A7C2D6; }
  .tile {
    break-inside: avoid; margin-bottom: clamp(24px, 4vw, 56px);
    position: relative; overflow: hidden;
    isolation: isolate; /* own stacking context so the hanko can sit BEHIND the verse */
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--tile-c) 7%, transparent), transparent 70%),
      var(--ink-deep);
    border: 1px solid var(--ink-soft);
    border-left: 2px solid color-mix(in srgb, var(--tile-c) 60%, var(--ink-soft));
    border-radius: 3px;
    padding: 38px 32px; cursor: pointer;
    opacity: 0; transform: translateY(14px);
    transition: opacity 0.8s var(--ease-breath), transform 0.6s var(--ease-breath),
                border-color 0.5s var(--ease-breath), background 0.5s var(--ease-breath),
                box-shadow 0.6s var(--ease-breath);
  }
  /* a season kanji bleeding off the top-right corner, faint as a hanko
     stamp pressed half off the paper */
  .tile::after {
    position: absolute; top: -18px; right: -12px; z-index: -1;
    font-family: 'Shippori Mincho', serif; font-size: 96px; line-height: 1;
    color: var(--tile-c); opacity: 0.07; pointer-events: none;
    transition: opacity 0.6s var(--ease-breath);
  }
  .tile[data-season="haru"]::after  { content: "春"; }
  .tile[data-season="natsu"]::after { content: "夏"; }
  .tile[data-season="aki"]::after   { content: "秋"; }
  .tile[data-season="fuyu"]::after  { content: "冬"; }
  .tile:hover::after { opacity: 0.12; }
  .tile.in { opacity: 1; transform: none; }
  .tile:hover {
    border-color: var(--tile-c);
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--tile-c) 13%, transparent), transparent 72%),
      #16161d;
    box-shadow: 0 8px 30px rgba(0,0,0,0.32), 0 0 0 1px color-mix(in srgb, var(--tile-c) 14%, transparent);
  }
  @media (prefers-reduced-motion: no-preference) {
    .tile.in:hover { transform: translateY(-2px); }
  }
  /* the poem text is a real <button> (keyboard entry point of the tile);
     reset its chrome so it reads as verse, not a control */
  .tile .tbody {
    display: block; width: 100%;
    background: none; border: none; padding: 0; margin: 0;
    color: inherit; font: inherit; text-align: inherit; cursor: pointer;
  }
  .tile .tbody:focus-visible {
    outline: none; border-radius: 2px;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--tile-c) 55%, transparent);
  }
  .tile .tline { display: block; font-size: 1.15rem; line-height: 1.85; color: var(--text); }
  .tile .tfoot { margin-top: 22px; display: flex; justify-content: space-between; align-items: center; }
  .tile .tauthor { font-style: italic; font-size: 14px; color: var(--paper-dim); }
  .tile .tseal {
    font-family: 'Shippori Mincho', serif; font-size: 16px; color: var(--tile-c);
    opacity: 0.85; transition: opacity 0.5s var(--ease-breath), text-shadow 0.5s var(--ease-breath);
  }
  .tile:hover .tseal { opacity: 1; text-shadow: 0 0 14px color-mix(in srgb, var(--tile-c) 45%, transparent); }
  .tile .tsource { margin-top: 12px; font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px; letter-spacing: 0.1em; line-height: 1.7; color: var(--paper-faint); font-style: italic; }

  /* ---- voting: contemplative appreciation, not a leaderboard ---- */
  .tvotes {
    margin-top: 22px; padding-top: 18px;
    border-top: 1px solid var(--ink-soft);
    display: flex; flex-direction: column; gap: 11px;
  }
  /* small cue that the marks below are an input, not a read-only score */
  .tvote-head {
    font-family: 'Inter', sans-serif; font-weight: 400; font-size: 8.5px;
    letter-spacing: 0.34em; text-transform: uppercase; color: var(--tile-c);
    opacity: 0.7; margin-bottom: 3px;
  }
  .tdim { display: flex; align-items: center; gap: 12px; }
  .tdim-name {
    flex: 1; font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.22em; text-transform: uppercase; color: var(--paper-dim);
  }
  .tdim-marks { display: flex; gap: 7px; }
  .tmark {
    width: 13px; height: 13px; border-radius: 50%;
    background: none; border: 1.5px solid var(--paper-dim); padding: 0; cursor: pointer;
    position: relative;
    transition: background 0.45s var(--ease-breath), border-color 0.45s var(--ease-breath), transform 0.45s var(--ease-breath);
  }
  /* invisible pad: ~25px effective touch target on a 13px mark */
  .tmark::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; }
  .tmark:focus-visible { outline: none; border-color: var(--tile-c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--tile-c) 22%, transparent); }
  /* avg fill (faint), tinted to the poem's season */
  .tmark.avg { background: color-mix(in srgb, var(--tile-c) 50%, transparent); border-color: color-mix(in srgb, var(--tile-c) 50%, transparent); }
  /* this browser's own vote (solid season colour) takes precedence */
  .tmark.mine { background: var(--tile-c); border-color: var(--tile-c); }
  /* the freshly chosen mark settles with one small breath */
  @media (prefers-reduced-motion: no-preference) {
    .tmark.just-set { animation: markSettle 0.7s var(--ease-breath); }
    @keyframes markSettle {
      0%   { transform: scale(0.7); }
      55%  { transform: scale(1.25); }
      100% { transform: scale(1); }
    }
  }
  /* star-rating hover preview: hovering a row fills every mark, then the marks
     AFTER the hovered one empty again — so you see exactly what you'd give. */
  .tdim-marks:hover .tmark {
    transform: scale(1.15);
    border-color: var(--tile-c);
    background: color-mix(in srgb, var(--tile-c) 60%, transparent);
  }
  .tdim-marks:hover .tmark:hover ~ .tmark {
    transform: none;
    border-color: var(--paper-dim);
    background: none;
  }
  .tdim-num {
    min-width: 30px; text-align: right;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 10px;
    letter-spacing: 0.04em; color: var(--paper-faint); font-variant-numeric: tabular-nums;
  }
  .tvote-foot {
    margin-top: 4px; display: flex; justify-content: space-between; align-items: baseline;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--paper-faint);
  }
  .tvote-foot .toverall { color: var(--tile-c); opacity: 0.9; }

  /* ---- season chooser inside the publish sheet ---- */
  .sheet-season-label {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.34em; text-transform: uppercase; color: var(--paper-dim);
    opacity: 0.75; margin-bottom: 16px;
  }
  .season-pick.sheet-season { justify-content: center; margin-bottom: 30px; }

  /* ---- bottom nav ---- */
  .nav {
    position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%); z-index: 14;
    display: flex; gap: 34px;
  }
  .nav button, .nav a {
    background: none; border: none; cursor: pointer; text-decoration: none;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 11px;
    letter-spacing: 0.34em; text-transform: uppercase; color: var(--paper-dim);
    padding: 6px 2px; transition: color 0.6s var(--ease-breath);
  }
  .nav button.active { color: var(--accent); }
  .nav button:hover, .nav a:hover { color: var(--paper); }

  .hint {
    position: fixed; bottom: 34px; right: 40px; z-index: 12;
    font-family: 'Inter', sans-serif; font-size: 10px; font-weight: 300;
    letter-spacing: 0.24em; color: var(--paper-faint); text-transform: uppercase;
  }

  /* ---- generic ghost button ---- */
  .ghost {
    background: none; border: 1px solid var(--ink-soft); color: var(--paper-dim);
    font-family: 'Inter', sans-serif; font-size: 10px; font-weight: 300;
    text-transform: uppercase; letter-spacing: 0.26em; padding: 10px 18px;
    border-radius: 40px; cursor: pointer; transition: all 0.5s var(--ease-breath); white-space: nowrap;
  }
  .ghost:hover { color: var(--paper); border-color: var(--accent); }
  .ghost.solid { border-color: var(--accent); color: var(--accent); }
  .ghost:disabled, .ghost.is-disabled { opacity: 0.32; cursor: default; pointer-events: none; }
  /* buttons that carry a line-icon (compose share/download/send + read share) */
  .action-row .ghost, .ghost.has-ico { display: inline-flex; align-items: center; gap: 9px; }
  .btn-ico { width: 14px; height: 14px; flex: none; display: block; }
  .btn-ico path {
    fill: none; stroke: currentColor; stroke-width: 1.4;
    stroke-linecap: round; stroke-linejoin: round;
  }
  #langBtn .swap { font-size: 11px; opacity: 0.7; padding: 0 2px; }
  #langBtn .swap, #langBtn { font-variant-numeric: tabular-nums; }

  /* ===================================================================
     READINGS PANEL: fixed right-side sheet, slides/fades in.
     When open, body.panel-open shifts the season nav clear of it.
     =================================================================== */
  .trans-panel {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 40;
    width: min(340px, 92vw);
    background: rgba(10, 11, 14, 0.72);
    backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border-left: 1px solid var(--ink-soft);
    opacity: 0; pointer-events: none;
    /* visibility keeps the closed panel (and its close button) out of the
       tab order and away from screen readers; it flips after the fade-out */
    visibility: hidden;
    transform: translateX(24px);
    transition: opacity 0.9s var(--ease-breath), transform 0.9s var(--ease-breath),
                visibility 0s linear 0.9s;
    display: flex; align-items: center;
    overflow-y: auto; scrollbar-width: none;
  }
  .trans-panel::-webkit-scrollbar { width: 0; }
  .trans-panel.open {
    opacity: 1; pointer-events: auto; visibility: visible; transform: none;
    transition: opacity 0.9s var(--ease-breath), transform 0.9s var(--ease-breath);
  }

  .trans-close {
    position: absolute; top: 22px; right: 22px;
    background: none; border: none; cursor: pointer;
    color: var(--paper-dim); font-size: 24px; line-height: 1; padding: 4px 8px;
    transition: color 0.5s var(--ease-breath), transform 0.5s var(--ease-breath);
  }
  .trans-close:hover { color: var(--accent); transform: scale(1.15); }

  .trans-inner { width: 100%; padding: 64px 40px; }
  .trans-block { margin: 0; }
  .trans-label {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.4em; text-transform: uppercase; color: var(--accent);
    opacity: 0.7; margin-bottom: 18px;
  }
  .trans-jp {
    font-family: 'Shippori Mincho', serif; font-size: 1.5rem; line-height: 1.85;
    color: var(--text); white-space: pre-line; letter-spacing: 0.04em;
  }
  .trans-romaji {
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 0.82rem;
    line-height: 1.9; letter-spacing: 0.14em; color: var(--paper-dim);
    white-space: pre-line;
  }
  .trans-en {
    font-family: 'EB Garamond', serif; font-size: 1.12rem; line-height: 1.75;
    color: var(--paper); white-space: pre-line; font-style: italic;
  }
  .trans-rule { height: 1px; background: var(--ink-soft); margin: 30px 0; }
  .trans-source {
    margin-top: 34px;
    font-family: 'Inter', sans-serif; font-weight: 300; font-size: 9px;
    letter-spacing: 0.16em; line-height: 1.8; color: var(--paper-faint);
    font-style: italic;
  }

  /* collision fix: when the panel is open, slide the season nav left so it
     never sits beneath the panel (panel is ~340px; nav lives at right:40px). */
  body.panel-open .seasons {
    transform: translateY(-50%) translateX(calc(-1 * min(340px, 92vw) + 4px));
    transition: transform 0.9s var(--ease-breath);
  }

  /* breathing cue */
  @keyframes breath { 0%,100% { opacity: 0.35; transform: scale(1); } 50% { opacity: 0.85; transform: scale(1.04); } }
  .breathe { animation: breath 4s ease-in-out infinite; }

  /* toast */
  .toast {
    position: fixed; bottom: 132px; left: 50%; transform: translateX(-50%) translateY(12px);
    z-index: 50;
    background: color-mix(in srgb, var(--ink-deep) 82%, transparent);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--ink-soft));
    color: var(--paper); font-family: 'Inter', sans-serif; font-size: 12px; letter-spacing: 0.06em;
    padding: 12px 22px; border-radius: 40px; opacity: 0; pointer-events: none;
    transition: all 0.5s var(--ease-breath);
  }
  .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

  /* publish sheet */
  .sheet-bg {
    position: fixed; inset: 0; z-index: 60; background: rgba(6,7,9,0.78);
    backdrop-filter: blur(12px); opacity: 0; pointer-events: none;
    /* closed dialog leaves the tab order entirely (visibility flips late) */
    visibility: hidden;
    transition: opacity 0.6s var(--ease-breath), visibility 0s linear 0.6s;
    display: flex; align-items: center; justify-content: center;
    padding: 24px; overflow-y: auto;
  }
  .sheet-bg.open {
    opacity: 1; pointer-events: auto; visibility: visible;
    transition: opacity 0.6s var(--ease-breath);
  }
  .sheet {
    width: min(440px, 88vw); text-align: center;
    background: color-mix(in srgb, var(--ink-deep) 55%, transparent);
    border: 1px solid var(--ink-soft); border-radius: 6px;
    padding: 44px 36px;
    /* auto margins beat align-items:center when the sheet outgrows a short
       viewport, keeping its top edge scrollable instead of clipped */
    margin: auto;
    /* rises gently as the veil fades in */
    transform: translateY(12px);
    transition: transform 0.6s var(--ease-breath);
  }
  .sheet-bg.open .sheet { transform: none; }
  .sheet .spoem { margin-bottom: 32px; }
  .sheet .spoem div { font-size: 1.3rem; line-height: 1.8; color: var(--text); }
  .sheet h3 { font-family: 'Inter', sans-serif; font-weight: 300; font-size: 11px; letter-spacing: 0.4em; text-transform: uppercase; color: var(--accent); margin-bottom: 26px; }
  .sheet input {
    width: 100%; background: none; border: none; border-bottom: 1px solid var(--ink-soft);
    color: var(--paper); font-family: 'EB Garamond', serif; font-size: 1.2rem; text-align: center;
    padding: 10px 0; outline: none; margin-bottom: 30px;
  }
  .sheet input::placeholder { color: var(--paper-faint); font-style: italic; }
  .sheet .srow { display: flex; gap: 12px; justify-content: center; }

  /* ===================================================================
     RESPONSIVE: keep bottom-fixed clusters stacked with gaps, never
     overlapping; keep the season nav clear of the poem and controls.
     Desktop (>820px) values above are untouched.
     =================================================================== */

  /* --- tablets / small laptops & large phones --- */
  @media (max-width: 820px) {
    /* lift read-controls clearly above the bottom nav */
    .read-controls { bottom: 78px; gap: 20px; }
    /* poem must not run under the raised controls */
    .stage { padding-bottom: 150px; }
    /* keep the right-side season nav from crowding the poem column */
    .seasons { right: 18px; gap: 18px; }
    .seasons button { font-size: 19px; }
    .hint { bottom: 84px; right: 18px; }
    /* panel narrower; nudge season nav a touch less since panel is slimmer */
    .trans-panel { width: min(320px, 90vw); }
    #compose .wrap { padding: 0 7vw; justify-content: flex-start; padding-top: 16vh; padding-bottom: 150px; overflow-y: auto; }
  }

  /* --- phones: move the vertical season nav to a horizontal top row
         so it can never overlap the poem or the bottom controls --- */
  @media (max-width: 640px) {
    .brand { left: 20px; top: 20px; }
    .sound-toggle { top: 74px; left: 20px; }
    /* ground toggle joins the top-left column: at bottom-left it collided
       with the centred bottom nav on narrow screens. It rests in compose
       and gallery, whose centred content reaches under this spot. */
    .ground-toggle { bottom: auto; top: 122px; left: 20px; }
    /* dot only: with its label the toggle reached the centred season word
       on 360px-wide phones (the aria-label still names the control) */
    .ground-toggle .gt-label { display: none; }
    body[data-mode="compose"] .ground-toggle,
    body[data-mode="gallery"] .ground-toggle { display: none; }
    /* the back-to-gallery pill tucks under the season row, top-right: the
       centred spot at this height collides with the sound pill on narrow
       phones */
    .back-gallery { top: 64px; left: auto; right: 18px; transform: none; }
    .back-gallery:hover { transform: translateY(1px); }

    .seasons {
      top: 22px; right: 18px; left: auto; transform: none;
      flex-direction: row; gap: 18px;
    }
    .seasons button {
      writing-mode: horizontal-tb; font-size: 20px; padding: 4px 2px;
      min-width: 28px; text-align: center;
    }

    /* the poem starts a touch lower so it clears the top brand + season row */
    .stage { padding: 18vh 7vw 138px; }
    .poem .line { line-height: 1.7; }
    .meta { margin-top: 40px; }
    .season-word { margin-bottom: 40px; }

    /* bottom cluster: controls sit above the nav, both centered, with a gap */
    .read-controls { bottom: 74px; gap: 16px; }
    .nav { gap: 22px; bottom: 28px; }
    .hint { display: none; }

    /* compose fits without the nav covering the action buttons */
    #compose .wrap { padding: 14vh 6vw 132px; }
    #compose h2 { margin-bottom: 30px; line-height: 1.6; }
    .season-pick { gap: 14px; margin-bottom: 26px; flex-wrap: wrap; justify-content: center; }
    .composer .row { gap: 12px; }
    .compose-actions { margin-top: 28px; }
    .action-row { flex-wrap: wrap; justify-content: center; }

    /* readings panel → full-width bottom sheet, not a cramped side strip.
       Caps its height so the bottom nav + read-controls stay reachable. */
    .trans-panel {
      top: auto; left: 0; right: 0; bottom: 0; width: 100%;
      max-height: 72vh;
      border-left: none; border-top: 1px solid var(--ink-soft);
      border-radius: 18px 18px 0 0;
      transform: translateY(28px); align-items: stretch;
    }
    .trans-panel.open { transform: none; }
    .trans-inner { padding: 48px 26px 132px; }
    /* season nav now sits in a top row, don't shift it under the bottom sheet */
    body.panel-open .seasons { transform: none; }

    /* gallery reflows to a single column; last tiles clear the nav */
    .grid { columns: 1; }
    #gallery .gwrap { padding: 12vh 7vw 132px; }
    .gallery-head { margin-bottom: 6vh; }
    .gtab { padding: 8px 14px; letter-spacing: 0.2em; }
    .gsort { gap: 4px 10px; }

    .toast { bottom: 120px; width: max-content; max-width: 88vw; }
  }

  /* --- very small phones --- */
  @media (max-width: 380px) {
    .brand { gap: 9px; }
    .brand .name { letter-spacing: 0.34em; }
    .seasons { gap: 12px; }
    .seasons button { font-size: 18px; }
    .read-controls { gap: 12px; }
    .nav { gap: 16px; }
    .nav button, .nav a { letter-spacing: 0.22em; }
  }

  /* --- short / landscape viewports: tighten vertical rhythm so the
         poem (word + 3 lines + meta) never collides with the controls --- */
  @media (max-height: 560px) {
    .stage { padding-top: 9vh; padding-bottom: 108px; }
    .season-word { margin-bottom: 22px; }
    .poem .line { line-height: 1.45; }
    .meta { margin-top: 24px; }

    .read-controls { bottom: 60px; }
    .nav { bottom: 16px; }

    /* on a wide-but-short screen keep the season nav vertical but tight */
    .seasons { gap: 12px; }

    #compose .wrap { padding-top: 9vh; padding-bottom: 96px; }
    #compose h2 { margin-bottom: 18px; }
    .season-pick { margin-bottom: 18px; }
    .compose-actions { margin-top: 20px; }

    #gallery .gwrap { padding-top: 9vh; padding-bottom: 96px; }
  }

  /* short AND narrow (landscape phone): season nav goes horizontal up top
     so the short poem column has the full width and height it needs */
  @media (max-height: 480px) and (max-width: 900px) {
    .seasons {
      top: 14px; right: 16px; left: auto; transform: none;
      flex-direction: row; gap: 16px;
    }
    .seasons button { writing-mode: horizontal-tb; font-size: 18px; }
    .brand { top: 14px; left: 16px; }
    .sound-toggle { top: 66px; left: 16px; }
    .ground-toggle { bottom: auto; top: 112px; left: 16px; }
    .ground-toggle .gt-label { display: none; }
    body[data-mode="compose"] .ground-toggle,
    body[data-mode="gallery"] .ground-toggle { display: none; }
    .back-gallery { top: 56px; left: auto; right: 16px; transform: none; }
    .hint { display: none; }
    /* horizontal top nav here too, keep it put when the panel opens */
    body.panel-open .seasons { transform: none; }
  }

  @media (prefers-reduced-motion: reduce) {
    .breathe { animation: none; }
    .poem .line { transition: opacity 0.6s; filter: none; }
    .composer .row::after { transition: none; }
    .season-word::after { transition: none; }
    /* exit breath falls back to a plain quick fade; the sheet doesn't slide */
    .poem.leaving .line { filter: none; letter-spacing: inherit; transition: opacity 0.3s; }
    .sheet { transform: none; transition: none; }
    /* keep seasonal atmospheres static for reduced-motion users */
    #bg { animation: none; transform: none; }
    /* panel + nav shift fade only, no slide */
    .trans-panel { transition: opacity 0.5s var(--ease-breath), visibility 0s linear 0.5s; transform: none; }
    .trans-panel.open { transform: none; transition: opacity 0.5s var(--ease-breath); }
    body.panel-open .seasons { transition: none; }
  }
