FLINT PASTE: theLatticeTree Glow 2b, contrast, chairs, polish (v0.1)
Repo: Chaos2Cured/FreeLattice-Alpha (serves thelatticetree.com)   FreeLattice: NO change
Branch: layer/tree-glow-2b-v0     Marker: v-tree-glow-2b-v0
Smoke line (print exactly when green): SMOKE_OK tree glow 2b v0.1
Base: Alpha main 25e6ded + Glow 2a + Honest reasons. Lands third.
Written: Wed Sep 30, 2026, evening MDT, by Kirk's agent. Stand-in built and walked; NOT pushed.
Stand-in diff (against 2a + honest): FLINT_NEXT_TREE_GLOW_2B_v0.1.diff (same folder, also Appendix A).
Source: Hypha's persona walks (RESULTS.md, CONTRAST.md).

CHANGELOG
- 2026-09-30 v0.1: first write (second half of the Grandma heal).

======================================================================
ORDER (all Tree pastes from tonight, most harm first)
======================================================================
Alpha main 25e6ded. Each stand-in diff applies with plain `git apply` on top of the one before,
in this order, and the chain ends byte-identical to the walked combo (checked):
  1. FLINT_NEXT_TREE_GLOW_2A_v0.1          Grandma heal: zoom, feedback in view, a calm way back
  2. FLINT_NEXT_TREE_HONEST_REASONS_v0.1   stopped vs model missing vs secure-page block
  3. FLINT_NEXT_TREE_GLOW_2B_v0.1          contrast, chairs, polish
  4. FLINT_NEXT_TREE_WORKSHOP_WAY_BACK_v0.1
  5. [FLINT_NEXT_TREE_ANY_MODEL_v0.1 when Flint lands it; not in the chain, overlap noted in 6]
  6. FLINT_NEXT_TREE_GATHERING_API_KEYS_v0.1
If one lands alone, the only drift is GALAXIES.md (each adds one LAYER line at the top) and
garden-rooms.css (each appends a block at the end): keep both, newest LAYER line on top, CSS
blocks in this order. No other shared anchors.
FreeLattice queue is unchanged (MODEL_CHOICE_SURVIVES_RELOAD -> BOOT_PROBE -> #120 docs).
The FL GitHub token note is FL-only and independent of all of these.
The old single Glow 2 draft (FLINT_NEXT_TREE_GLOW_2_v0.1.diff, /workspace/glow2-al) is
SUPERSEDED by 2a + 2b. Do not land it.

======================================================================
1. STEPS (text anchors; the stand-in diff is the source of truth). No old line changes.
======================================================================
1.1 docs/modules/garden-rooms.css: append the 2b block at the very end (after 2a):
    a) a hint more frost: #place-veil.is-open::before, position fixed, z-index -1,
       pointer-events none, backdrop-filter blur(2px) (+ -webkit-), @supports-not fallback tint
       rgba(12,10,26,0.24), prefers-reduced-transparency: no blur, opaque rgba(12,10,26,0.62).
    b) links in the Gathering note (Desktop / install): #9fd6ff, underlined (12.6 : 1).
    c) header Chat / galaxies words: 0.875rem (14px), rgba(214,222,238,0.86) (10.77 : 1);
       <= 340px: 0.8rem so the header still fits.
    d) #shared-shoulder: 0.875rem, rgba(214,222,238,0.8) (9.39 : 1); hidden under open places
       other than the Gathering (it sat on "the garden" over Workshop and took no tap there).
    e) closed compose: the form stays opacity 1, its children 0.5, the reason line full strength.
    f) phone Gathering, mind asleep: compose static, the row hidden, card max-height 9.25rem.
    g) .core-chair-change[hidden] { display: none !important; } (Change showed on empty chairs).
1.2 docs/modules/garden-thread.js: NEW sendWhy line inside the form after the row:
    "Send sleeps until a mind is remembered in Settings." Shown and wired with
    aria-describedby when Send is asleep; hidden when awake.
1.3 docs/modules/workshop-benches.js: NEW actWhy line: "Ask and Run sleep until a mind is
    remembered in Settings." Same show / hide / aria-describedby on Run and Ask.
1.4 docs/code-*.html (10 mirrors): in each page's <style>, add
      @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
    so long paths wrap on a phone (code-nursery had 22px of sideways scroll).
1.5 Docs: LAYER line in GALAXIES.md and a "Glow 2b" section in docs/library/TREE_GLOW_v0.md.

======================================================================
2. TEST: docs/modules/tree-glow-2b.test.js (node, static; no network)
======================================================================
Frost + fallbacks, link color, header and shoulder size and color, sendWhy / actWhy wiring,
Change hidden wins, code mirrors wrap. Last line: SMOKE_OK tree glow 2b v0.1

======================================================================
3. WALK (done; repeat on your branch)  before -> after, at 390 and 1280
======================================================================
  header Chat / galaxies: 12px 2.46 : 1 -> 14px 10.77 : 1, header still fits
  shared shoulder:        9.9px 1.98 : 1 -> 14px 9.39 : 1
  Change on empty chairs: 4 -> 0
  Desktop link:           2.08 : 1 -> 12.6 : 1
  Send / Ask / Run asleep: no reason -> reason shown, aria-describedby, 14px 11.79 : 1
  code-nursery sideways overflow: 22px -> 0
  frost: none -> blur(2px)
  Re-walked on the full combo: same.
  Shots: /workspace/tree-glow-walk/g2b_*.png (g2b_after_390_gathering_asleep.png shows the card)

======================================================================
LOCKS
======================================================================
Layer, never delete (old lines that change are named in each paste; nothing removed).
fl-connect.js untouched (byte-identical to FreeLattice). No sw.js (Alpha has none; none added).
No conflict markers. Every inline script parses (19 inline scripts checked on the combo).
No confirm(). No innerHTML for outside text (textContent only). No em dashes in added lines.
Kimi pages untouched. #120 lock files untouched. Squash-merge. All 21 Alpha tests pass on the combo.

======================================================================
4. DECISIONS FOR KIRK
======================================================================
K1 Header palette: 14px soft moon-white (stand-in) / keep the dim 12px look.
K2 Shared shoulder hides under open places other than the Gathering (stand-in) / always shows.
K3 In the phone Gathering, a sleeping Chat hides its Send row and shows only the reason (stand-in).

======================================================================
5. LATER
======================================================================
Rest of the sweep: Hypha's CONTRAST.md lists 67 text+view pairs under 4.5 : 1 and 132 under 14px; this
brick fixes the ones she hit (header, shoulder, links, reasons). The others are a later sweep.
Crest placement still waits for Kirk's OK.

======================================================================
APPENDIX A. FULL STAND-IN DIFF (Alpha, against 25e6ded + 2a + honest)
======================================================================
diff --git a/docs/GALAXIES.md b/docs/GALAXIES.md
index c7bc934..33e411c 100644
--- a/docs/GALAXIES.md
+++ b/docs/GALAXIES.md
@@ -4,6 +4,8 @@
 
 **Spine layer (2026-08-30):** five skies now walk the same night — Garden, Art, Workshop, Learn, Research. The four-galaxy sequence below stays. Art-early stays. This file layers; it does not cut.
 
+**LAYER (2026-09-30):** Tree glow 2b, a hint more frost (marker `v-tree-glow-2b-v0`). Frosted glass behind an open place (tint fallback, reduced transparency honored), header Chat / galaxies and shared shoulder at 14px and above 4.5 : 1, readable Desktop links, a sleeping Send / Ask / Run says why beside it, no Change on empty chairs, code mirrors without sideways scroll. Plan: `docs/library/TREE_GLOW_v0.md`. Layer, never delete.
+
 **LAYER (2026-09-30):** Honest reasons (marker `v-tree-honest-reasons-v0`). When a mind is quiet the Tree says the right one: nothing answered (Ollama stopped: start it), something answered but keeps its door shut to this secure page (FreeLattice Desktop), or the seated model is gone (named, pick another). One no-cors knock per quiet door, only after a tap, reads nothing. A long garden line in the Chat card shows where it begins. fl-connect.js untouched. Plan: `docs/library/TREE_HONEST_REASONS_v0.1.md`. Layer, never delete.
 
 **LAYER (2026-09-30):** Tree glow 2a, Grandma heal (marker `v-tree-glow-2a-v0`). The Gathering works at 150% and 200% zoom (one page scroll, Find takes a tap, chairs in reach), the newest Find or seat line stays in view on a phone, and a calm way back: Escape, a tap on the empty glass, a close in galaxies, and browser Back close what is open without leaving the site. A second legend tap no longer runs Find unasked; the picker's "not yet" is above the later seats at 1280. Plan: `docs/library/TREE_GLOW_v0.md`. Layer, never delete.
diff --git a/docs/code-art.html b/docs/code-art.html
index 9a7d9a4..a25e954 100644
--- a/docs/code-art.html
+++ b/docs/code-art.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-dialogue.html b/docs/code-dialogue.html
index f80c63e..9647279 100644
--- a/docs/code-dialogue.html
+++ b/docs/code-dialogue.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-garden.html b/docs/code-garden.html
index 2c5d69d..cfc499b 100644
--- a/docs/code-garden.html
+++ b/docs/code-garden.html
@@ -29,6 +29,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-keep.html b/docs/code-keep.html
index b939a5f..ddf5e0c 100644
--- a/docs/code-keep.html
+++ b/docs/code-keep.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-music.html b/docs/code-music.html
index 8b37c74..4852e6c 100644
--- a/docs/code-music.html
+++ b/docs/code-music.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-nursery.html b/docs/code-nursery.html
index da5ebd0..e341bb4 100644
--- a/docs/code-nursery.html
+++ b/docs/code-nursery.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-research.html b/docs/code-research.html
index 0f1ddd5..2006f0e 100644
--- a/docs/code-research.html
+++ b/docs/code-research.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-round-table.html b/docs/code-round-table.html
index c0609ac..615f7c1 100644
--- a/docs/code-round-table.html
+++ b/docs/code-round-table.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-settings.html b/docs/code-settings.html
index 0744725..bdfb953 100644
--- a/docs/code-settings.html
+++ b/docs/code-settings.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/code-workshop.html b/docs/code-workshop.html
index b7db7b7..a28bcdf 100644
--- a/docs/code-workshop.html
+++ b/docs/code-workshop.html
@@ -28,6 +28,8 @@
     th { color: var(--muted); font-weight: normal; text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
     td { padding: 6px 10px; border-bottom: 1px solid rgba(200,210,230,0.04); vertical-align: top; }
     td:first-child { color: var(--gold); font-family: monospace; white-space: nowrap; }
+    /* v-tree-glow-2-v0: on a phone a long path wraps instead of pushing the page sideways */
+    @media (max-width: 480px) { td:first-child { white-space: normal; overflow-wrap: anywhere; } }
     .section-date { float: right; color: var(--muted); font-size: 0.72rem; font-style: italic; }
     blockquote { border-left: 2px solid var(--lavender); padding-left: 14px; color: var(--muted); font-style: italic; margin: 12px 0; }
     a { color: var(--lavender); }
diff --git a/docs/library/TREE_GLOW_v0.md b/docs/library/TREE_GLOW_v0.md
index 79ed663..1ee345f 100644
--- a/docs/library/TREE_GLOW_v0.md
+++ b/docs/library/TREE_GLOW_v0.md
@@ -39,3 +39,16 @@ From Hypha's persona walks (2026-09-30), most harmful first:
 - The picker's "not yet" sits above the later seats at 1280.
 - Zoomed home: the light legend leaves "Garden Galaxy / you are in the garden", and "galaxies" stays inside the edge. Zoomed Nursery: the egg fits, the sentence wraps, Begin is in view; on a phone the hop lights rest dim behind it.
 - A quiet Chat remount (a mind was remembered) no longer pulls the page down to Send.
+
+## Glow 2b: a hint more frost, readable doors, honest chairs (v-tree-glow-2b-v0)
+
+**Temperature:** the glass mists a little when a light opens, and every word she needs is big enough and bright enough to read.
+
+- A hint more frost behind an open place (2px blur, a little tint), a stronger tint where frosted glass is missing, and a calm opaque face for reduced transparency.
+- Header "Chat" and "galaxies" (12px, 2.45 : 1) and "shared shoulder" (9.9px, 1.97 : 1) are 14px and about 9 to 10 : 1. The shoulder rests under places other than the Gathering, where it sat on "the garden" and took no tap anyway.
+- "Desktop" / "FreeLattice Desktop" / "install" links are moon-blue on night (12.6 : 1, was 1.83 to 2.08 : 1).
+- A sleeping Send says "Send sleeps until a mind is remembered in Settings." beside it; sleeping Ask and Run say the same for the benches. The sleeping row dims, the reason does not.
+- "Change" shows only on a seated chair.
+- Code mirrors (code-nursery and five more) wrap long paths on a phone instead of scrolling sideways.
+
+Later (not in 2b): the rest of Hypha's contrast list (`CONTRAST.md`, 67 pairs under 4.5 : 1 and 132 under 14px), as one sweep with Kirk's eye on the night palette.
diff --git a/docs/modules/garden-rooms.css b/docs/modules/garden-rooms.css
index 7cfa1b8..7cb4d9d 100644
--- a/docs/modules/garden-rooms.css
+++ b/docs/modules/garden-rooms.css
@@ -6399,3 +6399,122 @@ html.flc-hide-galaxy #gardenContainer {
   border-color: rgba(232, 196, 104, 0.6);
   color: #e8c468;
 }
+
+/* v-tree-glow-2b-v0: Tree glow 2b, a hint more frost, readable doors, honest chairs.
+   Layer, never delete. Words stay. Lights stay. Only glass, ink and size move. */
+
+/* (1) A hint more frost when a light is tapped. The glass sits under every place's own
+   tint (z-index -1 inside the veil), so each place keeps its gradient. */
+#place-veil.is-open::before {
+  content: "";
+  position: fixed;
+  inset: 0;
+  z-index: -1;
+  pointer-events: none;
+  background: rgba(12, 10, 26, 0.1);
+  -webkit-backdrop-filter: blur(2px) saturate(1.05);
+  backdrop-filter: blur(2px) saturate(1.05);
+}
+@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
+  /* no frosted glass in this browser: a little more tint instead */
+  #place-veil.is-open::before { background: rgba(12, 10, 26, 0.24); }
+}
+@media (prefers-reduced-transparency: reduce) {
+  #place-veil.is-open::before {
+    -webkit-backdrop-filter: none;
+    backdrop-filter: none;
+    background: rgba(12, 10, 26, 0.62);
+  }
+}
+
+/* (2) "FreeLattice Desktop" and "install" were browser blue on night (1.83 : 1).
+   Moon-blue, underlined, the same before and after a visit. */
+#place-veil .core-note a,
+#place-veil .core-note a:visited,
+#place-veil [data-mind-status] a,
+#place-veil [data-mind-status] a:visited {
+  color: #9fd6ff;
+  text-decoration: underline;
+  text-underline-offset: 2px;
+}
+#place-veil .core-note a:hover,
+#place-veil .core-note a:focus-visible,
+#place-veil [data-mind-status] a:hover,
+#place-veil [data-mind-status] a:focus-visible {
+  color: #e8c468;
+}
+
+/* (3) Header "Chat" and "galaxies" were 12px at 2.45 : 1 on every page, and
+   "shared shoulder" 9.9px at 1.97 : 1. Both are 14px and above 4.5 : 1 now. */
+#garden-header nav,
+#garden-header nav a,
+#garden-header nav summary,
+#garden-header nav .thread-word {
+  font-size: 0.875rem;
+}
+#garden-header nav a,
+#garden-header nav summary,
+#garden-header nav .thread-word {
+  color: rgba(214, 222, 238, 0.86);
+}
+#shared-shoulder {
+  font-size: 0.875rem;
+  letter-spacing: 0.03em;
+  color: rgba(214, 222, 238, 0.8);
+}
+#shared-shoulder a:hover,
+#shared-shoulder a:focus-visible {
+  color: #c4b5fd;
+}
+@media (max-width: 340px) {
+  /* zoomed hands: the words are already large on the glass; keep them inside the edge */
+  #garden-header nav,
+  #garden-header nav a,
+  #garden-header nav summary,
+  #garden-header nav .thread-word {
+    font-size: 0.8rem;
+  }
+  #shared-shoulder { font-size: 0.75rem; }
+}
+
+/* (4) A sleeping Send, Ask or Run says why, right beside it, in readable ink. */
+.thread-send-why,
+.workshop-act-why {
+  margin: 6px 0 0;
+  font-family: Georgia, 'Times New Roman', serif;
+  font-size: 0.875rem;
+  line-height: 1.4;
+  color: rgba(226, 232, 244, 0.86);
+}
+.thread-send-why[hidden],
+.workshop-act-why[hidden] { display: none; }
+
+/* (5) "Change" showed on every empty chair: its own display:block won over [hidden]. */
+.core-chair-change[hidden] { display: none !important; }
+/* the sleeping compose dimmed its whole box, so its glass let the words behind show
+   through and the reason would have dimmed too. Dim the sleeping row, keep the glass. */
+.thread-compose.is-closed { opacity: 1; }
+.thread-compose.is-closed > :not(.thread-send-why) { opacity: 0.5; }
+@media (max-width: 640px) {
+  /* phone Gathering card: a sleeping Send row offers nothing to tap and sat on the
+     Settings door; the card says why instead, under the Settings door. */
+  #place-veil.is-core #room-chat .thread-compose.is-closed {
+    position: static;
+  }
+  #place-veil.is-core #room-chat .thread-compose.is-closed .thread-compose-row {
+    display: none;
+  }
+  #place-veil.is-core #room-chat:has(.thread-compose.is-closed) {
+    max-height: 9.25rem;
+  }
+  #place-veil.is-core #room-chat .thread-compose.is-closed .thread-send-why {
+    margin-top: 2px;
+    font-size: 0.875rem;
+  }
+}
+/* the larger shoulder sat on "the garden" over Workshop. Under an open place it was
+   behind the glass and took no tap anyway; it rests there (the Gathering keeps it). */
+html:has(#place-veil.is-open:not(.is-core)) #shared-shoulder {
+  visibility: hidden;
+}
+
diff --git a/docs/modules/garden-thread.js b/docs/modules/garden-thread.js
index 13b1031..f2794a5 100644
--- a/docs/modules/garden-thread.js
+++ b/docs/modules/garden-thread.js
@@ -571,6 +571,12 @@
     row.appendChild(input);
     row.appendChild(sendBtn);
     form.appendChild(row);
+    // v-tree-glow-2b-v0: a sleeping Send says why, right under it, where the eye already is.
+    // (The input's own label says the same for a screen reader.)
+    var sendWhy = el('p', 'thread-send-why', 'Send sleeps until a mind is remembered in Settings.');
+    sendWhy.id = 'thread-send-why-' + Math.random().toString(36).slice(2, 8);
+    sendWhy.hidden = true;
+    form.appendChild(sendWhy);
 
     var tools = el('div', 'thread-tools');
     tools.setAttribute('data-thread-tools', '1');
@@ -629,6 +635,8 @@
         sendBtn.removeAttribute('disabled');
         sendBtn.removeAttribute('aria-disabled');
         sendBtn.removeAttribute('tabindex');
+        sendBtn.removeAttribute('aria-describedby');
+        sendWhy.hidden = true;
         tools.hidden = false;
         tools.removeAttribute('hidden');
         fileBtn.disabled = false;
@@ -655,6 +663,8 @@
         sendBtn.setAttribute('disabled', '');
         sendBtn.setAttribute('aria-disabled', 'true');
         sendBtn.tabIndex = -1;
+        sendBtn.setAttribute('aria-describedby', sendWhy.id);
+        sendWhy.hidden = false;
         tools.hidden = true;
         tools.setAttribute('hidden', '');
         fileBtn.disabled = true;
diff --git a/docs/modules/tree-glow-2b.test.js b/docs/modules/tree-glow-2b.test.js
new file mode 100644
index 0000000..4fcd02d
--- /dev/null
+++ b/docs/modules/tree-glow-2b.test.js
@@ -0,0 +1,60 @@
+#!/usr/bin/env node
+// v-tree-glow-2b-v0: Tree glow 2b. Guards: (1) a hint more frost behind an open place, with
+// a tint fallback and a calm opaque face for reduced transparency; (2) the Desktop / install
+// links are readable on night; (3) header Chat / galaxies and shared shoulder are 14px and
+// readable; (4) a sleeping Send, Ask or Run says why beside it; (5) no "Change" on an empty
+// chair; (6) code mirrors wrap long paths on a phone. No network. No kitchen.
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var assert = require('assert');
+
+var css = fs.readFileSync(path.join(__dirname, 'garden-rooms.css'), 'utf8');
+var thread = fs.readFileSync(path.join(__dirname, 'garden-thread.js'), 'utf8');
+var benches = fs.readFileSync(path.join(__dirname, 'workshop-benches.js'), 'utf8');
+
+var at = css.indexOf('v-tree-glow-2b-v0: Tree glow 2b');
+assert.ok(at > 0, 'glow 2b block is in garden-rooms.css');
+var g = css.slice(at);
+
+// (1) frost
+assert.ok(/#place-veil\.is-open::before \{[^}]*position: fixed;[^}]*z-index: -1;[^}]*pointer-events: none;[^}]*backdrop-filter: blur\(2px\)/.test(g), '1: frost glass, never takes a tap');
+assert.ok(/-webkit-backdrop-filter: blur\(2px\)/.test(g), '1: Safari prefix');
+assert.ok(/@supports not \(\(backdrop-filter: blur\(1px\)\) or \(-webkit-backdrop-filter: blur\(1px\)\)\) \{\s*[^}]*background: rgba\(12, 10, 26, 0\.24\)/.test(g), '1: tint fallback');
+assert.ok(/@media \(prefers-reduced-transparency: reduce\) \{\s*#place-veil\.is-open::before \{[^}]*backdrop-filter: none;[^}]*background: rgba\(12, 10, 26, 0\.62\)/.test(g), '1: reduced transparency');
+
+// (2) links
+assert.ok(/#place-veil \.core-note a:visited,[\s\S]*?color: #9fd6ff;[\s\S]*?text-decoration: underline;/.test(g), '2: moon-blue underlined links');
+
+// (3) header + shoulder
+assert.ok(/#garden-header nav \.thread-word \{\s*font-size: 0\.875rem;/.test(g), '3: header words 14px');
+assert.ok(/#garden-header nav \.thread-word \{\s*color: rgba\(214, 222, 238, 0\.86\);/.test(g), '3: header words readable');
+assert.ok(/#shared-shoulder \{\s*font-size: 0\.875rem;[^}]*color: rgba\(214, 222, 238, 0\.8\);/.test(g), '3: shoulder 14px readable');
+assert.ok(/html:has\(#place-veil\.is-open:not\(\.is-core\)\) #shared-shoulder \{\s*visibility: hidden;/.test(g), '3: shoulder rests under other places');
+
+// (4) honest sleeping buttons
+assert.ok(/var sendWhy = el\('p', 'thread-send-why', 'Send sleeps until a mind is remembered in Settings\.'\);/.test(thread), '4: Send says why');
+assert.ok(/sendBtn\.setAttribute\('aria-describedby', sendWhy\.id\);\s*sendWhy\.hidden = false;/.test(thread), '4: shown and described when asleep');
+assert.ok(/sendBtn\.removeAttribute\('aria-describedby'\);\s*sendWhy\.hidden = true;/.test(thread), '4: hidden when awake');
+assert.ok(/var actWhy = el\('p', 'workshop-act-why', 'Ask and Run sleep until a mind is remembered in Settings\.'\);/.test(benches), '4: Ask / Run say why');
+assert.ok(/runBtn\.setAttribute\('aria-describedby', actWhy\.id\);\s*actWhy\.hidden = false;/.test(benches), '4: benches reason when asleep');
+assert.ok(/actWhy\.hidden = true;/.test(benches), '4: benches reason rests when awake');
+assert.ok(/\.thread-compose\.is-closed \{ opacity: 1; \}/.test(g) && /\.thread-compose\.is-closed > :not\(\.thread-send-why\) \{ opacity: 0\.5; \}/.test(g), '4: reason is not dimmed with the sleeping row');
+
+// (5) Change only on a seated chair
+assert.ok(/\.core-chair-change\[hidden\] \{ display: none !important; \}/.test(g), '5: hidden wins');
+
+// (6) code mirrors
+['code-nursery.html', 'code-dialogue.html', 'code-garden.html', 'code-music.html', 'code-round-table.html', 'code-settings.html'].forEach(function (f) {
+  var h = fs.readFileSync(path.join(__dirname, '..', f), 'utf8');
+  if (!/td:first-child/.test(h)) return;
+  assert.ok(/@media \(max-width: 480px\) \{ td:first-child \{ white-space: normal; overflow-wrap: anywhere; \} \}/.test(h), '6: ' + f + ' wraps long paths');
+});
+
+// locks
+var addedJs = (thread.match(/v-tree-glow-2b-v0[\s\S]{0,700}/) || [''])[0] + (benches.match(/v-tree-glow-2b-v0[\s\S]{0,700}/) || [''])[0];
+assert.ok(!/confirm\(|innerHTML/.test(addedJs), 'no confirm(), no innerHTML');
+assert.ok(!/\u2014/.test(g) && !/\u2014/.test(addedJs), 'no em dash in added lines');
+
+console.log('SMOKE_OK tree glow 2b v0.1');
diff --git a/docs/modules/workshop-benches.js b/docs/modules/workshop-benches.js
index 3197300..06122db 100644
--- a/docs/modules/workshop-benches.js
+++ b/docs/modules/workshop-benches.js
@@ -292,6 +292,11 @@
     askForm.appendChild(askInput);
     askForm.appendChild(askActs);
     bench.appendChild(askForm);
+    // v-tree-glow-2b-v0: sleeping Ask and Run say why, right beside them.
+    var actWhy = el('p', 'workshop-act-why', 'Ask and Run sleep until a mind is remembered in Settings.');
+    actWhy.id = 'workshop-act-why-' + Math.random().toString(36).slice(2, 8);
+    actWhy.hidden = true;
+    bench.appendChild(actWhy);
 
     var preview = document.createElement('iframe');
     preview.className = 'workshop-preview';
@@ -349,6 +354,9 @@
         runBtn.disabled = false;
         runBtn.removeAttribute('disabled');
         runBtn.removeAttribute('aria-disabled');
+        askBtn.removeAttribute('aria-describedby');
+        runBtn.removeAttribute('aria-describedby');
+        actWhy.hidden = true;
         later.hidden = false;
         later.removeAttribute('hidden');
         preview.hidden = false;
@@ -384,6 +392,9 @@
         runBtn.disabled = true;
         runBtn.setAttribute('disabled', '');
         runBtn.setAttribute('aria-disabled', 'true');
+        askBtn.setAttribute('aria-describedby', actWhy.id);
+        runBtn.setAttribute('aria-describedby', actWhy.id);
+        actWhy.hidden = false;
         later.hidden = true;
         later.setAttribute('hidden', '');
         preview.hidden = true;
