Elite Outsiders ← Tools menu → Open the page

LF & Cross Platform Content Process Doc, 29/07/2026 update

Documentation source-of-truth · last updated 2026-07-29 · for AL and Claude

What this page is for. Fully documents how /backdata/lf-cross-platform-content works. Architecture, data model, behavior of the 3 views, synchronization rules, files involved, endpoints. Read by Claude at the start of any session that touches this page. AL refers to it to understand how it works / decide on new features.

Table of contents

  1. A — Architecture (single root)
  2. B — Data model
  3. C — View 1 (Edit)
  4. D — View 2 (Run)
  5. E — View 3 (Gantt)
  6. F — Inter-view synchronization
  7. G — Color code
  8. H — Context menus (right-click)
  9. I — Tracked runs (videos in production)
  10. J — Files, endpoints, D1 stores
  11. K — Deployment workflow
  12. L — Recent changelog

A — Architecture (single root)· non-negotiable principle

BOARD is the single root. Everything shown in the 3 views derives from BOARD (in JS memory, persisted to D1). No duplication.

                       ┌──────────────────────────┐
                       │   BOARD (in-memory)      │
                       │   phases[] · steps[]     │
                       │   (steps → subActions[]) │
                       └──────────┬───────────────┘
                                  │ derives
              ┌───────────────────┼───────────────────┐
              ▼                   ▼                   ▼
        ┌───────────┐       ┌───────────┐       ┌───────────┐
        │  View 1   │       │  View 2   │       │  View 3   │
        │  Edit     │       │  Run      │       │  Gantt    │
        └───────────┘       └───────────┘       └───────────┘
        struct editing      check in            visual chain
        (who/what)          parallel            + typed arrows

D1 persistence — 2 separate stores under intranet_state:

On display, BOARD merges the 2 stores in memory (origin tagged via step.originBoard). On save, we split on output and PUT separately. The old pages /backdata/long-process and /backdata/cross-platform-content still run on the same stores → everything stays consistent.

User-only overlays that are NOT in BOARD:

Golden sync rule. Every data change goes through BOARD (or a documented user-only store). No view stores a duplicated state. Any action in one view is reflected in the other 2 because they re-render from the same source.

B — Data model· JSON schema

B.1 BOARD (in-memory)

{
  version: 8,
  phases: [
    {
      id: 'p_script',
      label: 'Script',
      originBoard: 'long',          // 'long' or 'cross'
      originLabel: 'LF',            // editable badge (LF / CROSS / custom)
      color: '#a855f7',             // canonical phase color (PHASE_PALETTE)
      criticalPath: [],             // step IDs marked critical
      wave: 1,                      // WAVE 1|2|3 Edit-view grouping, 4 = SBY parking. Lives on the PHASE.
                                    // Run + Gantt ignore 1-3 and fully exclude 4 (SBY).
      textColor: undefined          // 'red' | 'yellow' | 'green' | 'wave1' (legacy yellow marker rows)
    },
    …
  ],
  steps: [
    {
      id: 's_l1',
      phaseId: 'p_script',
      label: 'Script + prompt template (9-bullet skeleton)',
      shortLabel: 'Script + prompt',// summary for the right SVG bar
      shortLabelManual: false,      // true = user edited shortLabel by hand
      subActions: [
        {
          label: 'fill BANK',
          owners: [], tools: [],
          execModes: [],            // ['auto', 'manual'] in the chosen order
          linksTo: [],              // sub-action → sub-action (cross-task within the phase)
          textColor: undefined      // 'red' | 'yellow' | undefined (= white)
          // subs also carry: execModes, execManual, prompt, url, finder, overlay, strike
        }, …
      ],
      owners: ['AL'],               // labels (references TAGS.owners[].label)
      tools: ['ClaudeCode', 'ClaudeLLM'],
      color: '#a855f7',             // = phase.color (option A chosen, overwritten on load)
      parallelTo: null,             // or step.id = parallel to this anchor
      execModes: ['auto'],          // derived from owners, displayed as AUTO / MANUAL / SEMI
      execManual: false,            // true = AL cycled the badge by hand, freezes the derivation
      prompt: { enabled, title, url, target },   // red PROMPT button
      url:    { enabled, title, url, target },   // purple URL button
      finder: { enabled, title, url, target },   // gold FINDER button, config separate from URL since 28/07
      overlay:{ enabled, title, url, target },   // cyan OVERLAY safe-zone marker
      strike: true,                 // optional strikethrough flag (absent = false)
      originBoard: 'long',
      weekOffset: 0,                // 0 for LF, 3 for Cross (Run view)
      textColor: undefined,         // 'red' | 'yellow' | undefined
      linksTo: []                   // task → task (manual via right-click)
    },
    …
  ]
}

B.2 Run (D1 table video_runs)

{
  id: 'r_xxxxx',
  label: 'Trauma Map LF',
  week_ref: '2026-W20',
  created_at: 'ISO',
  completed_at: 'ISO' | null,
  duration_seconds: number | null,
  archived: false,
  step_completions: {
    's_l1': { checked_at: ISO, started_at: ISO|null },
    …
  },
  sub_completions: {
    's_l1:0': { checked_at: ISO, started_at: ISO|null },
    …
  }
}

v2 format stored in the JSON column. The legacy v1 (flat {stepId: ISO}) is migrated in memory on read. started_at = timestamp of the last check BEFORE this one in the run (computed server-side on PATCH).

B.3 V3 custom chain (D1 key gantt_v3_triggers)

{
  version: 1,
  firstCell: 'phase:p_script',       // entry point of the V3 Gantt
  chain: {
    'phase:p_script': ['step:s_l1'],
    'step:s_l1': ['step:s_l2'],
    …
  }
}

cellId format:

This store holds only the custom arrows the user added on top of the default chain (which is derived on the fly from BOARD at each render).

B.4 Authoring conventions (28-29/07)

Schedules live ONLY in content-system. Posting times and days are stored exclusively in /backdata/content-system. The board never stores a schedule, and neither do the grammars or prompts. Any step that posts content points to content-system for its timing.

C — View 1 (Edit)· source of structural changes

Purpose. Edit the production method: tasks, sub-actions, phases, owners, apps, parallelTo, colors, prompts. This is WHERE you change the structure.

C.1 Layout

C.2 Sub-actions (narrow left column)

Vertical order stacked in .chip-sub-stack:

  1. ⋮⋮ drag handle
  2. 1A number (phase idx + letter within the step)
  3. run dot (visible only if a run is selected)

The sub-action text takes all remaining width (inline editing).

Execution badge, big on the Edit view (28-29/07). Every task and sub-action shows a large MANUAL / AUTO / SEMI badge (execModesHtml(modes, big)) on its own line: under the task name row for tasks, under the text for sub-actions. AUTO = robot alone, MANUAL = AL alone, SEMI = both (Claude runs it, AL steps in for validation, choice or manual finish). Derived from owners; clicking the badge cycles derive, MANUAL, AUTO, SEMI and sets a manual override (execManual) that freezes the derivation until the cycle returns to derive.

C.3 Editor modal (Edit ▼ button)

On each task, opens a modal that exposes:

Same in a sub-action's modal: Previous actions and Next actions sections.

C.4 Config buttons: PROMPT / URL / FINDER / OVERLAY

D — View 2 (Run)· execution batch

Purpose. See at a glance what launches in parallel and check items off as you go.

D.1 Layout

D.2 Cards

D.3 Run header

Run label + week_ref + done count + global % (computed over BOARD's total steps, SBY excluded).

Validation and run duration (29/07): checking the last pending step opens the "Validate & close run" modal (notes field, 5000 chars). It now shows the run duration, computed client-side from run.created_at (completed_at does not exist yet at that point; the server sets it on the PATCH that follows). Cancel = the step is not checked. Per-step duration badges are intentionally disabled per AL: durations are still tracked in D1 (every check records checked_at + started_at) but never displayed in any view.

E — View 3 (Gantt)· MS Project-style cell chain

Purpose. Visualize the sequencing of all cells (phases, tasks, sub-actions) in a single Gantt with arrows.

E.1 Cells

E.2 Layout (per-swimlane)

  1. Each phase = a horizontal swimlane (band tinted with the phase color). Top→bottom order = BOARD.phases[] order.
  2. X axis per swimlane (independent column space):
    • Phase cell at column 0
    • Steps at column 1 by default (= all parallel within the swimlane)
    • Intra-phase parallelTo + intra-phase V3 custom arrows can push a step to col 2, 3, …
  3. Default chain derived from BOARD: only phase → its steps (intra-swimlane visual grouping). No auto cross-phase arrow.
  4. User chain (V3_CHAIN.chain):
    • Intra-phase = pushes target by 1 column within its swimlane
    • Cross-phase = semantic trigger, does not move the target on X

E.3 Arrows

Orthogonal path (right angles, MS Project style). Style determined by the TARGET'S TYPE:

TargetStyleColor
phasethick 3px solid #e8d5b0
stepthin 1.8px solid #f2f2f5
subthin 1.5px dashed (6/4) #9a9aa4

E.4 Right-click + arrow drag (V3)

Right-click on a cell → unified Previous / Next modal: ⬅ previous actions (trigger this cell) · ➡ next actions (triggered by this cell). × pills to remove + a + button to add a custom arrow via a tree (phases > steps > subs).

Drag from a cell handle → pulls an arrow to another cell. The hovered cell is highlighted during the drag. On release: if a cell is under the cursor, the arrow is created; otherwise the drag is cancelled cleanly.

If the target is in another phase (cross-phase) → a mini-modal asks for the trigger kind:
☐ Full phase complete (= wait for all actions of the source phase to finish)
☐ Specific step [dropdown of the source phase's steps]
☐ Specific sub-action [dropdown of the source phase's subs]
→ stored in V3_CHAIN.triggers[srcCellId], V2 gates the start of the target wave.

On an internal sub-action (mini-list) → mini-menu: text color (green/red/yellow/white), ∥ set parallel, ⚙ configure prompt, duplicate, link to another sub.

E.5 Phase brackets (MS Project style)

Above each phase, a thin horizontal SVG line spanning from the phase's first step to its last step, with the phase label above the line. Color = phase.color. Opacity 0.55 so it doesn't clutter visually.

E.6 PROMPT button (top-right of cell)

On each step or sub cell whose prompt is enabled: a PROMPT button in absolute top-right. Empty style (dashed) if no URL, solid if URL. Left-click opens the URL, right-click opens the config modal.

F — Inter-view synchronization· reference contract (full matrix)

Non-negotiable principle. BOARD + V3_CHAIN + run completions = 3 stores. The 3 views read these stores and compute nothing on their own. V3 is the visual source-of-truth for column (X) positioning; V2 derives its waves directly from the V3 columns.

F.1 Storage — where each piece of data lives

DataStoreKey / fieldNote
Phase / step / sub labelBOARDphases[].label · steps[].label · steps[].subActions[].labelEditable from V1, V2, or V3
step shortLabelBOARDsteps[].shortLabelAuto-derived from label unless shortLabelManual=true
Phase colorBOARDphases[].colorInherited by all steps of the phase + tints the V3 swimlane
Text color (red/yellow/green/white)BOARDsteps[].textColor · steps[].subActions[].textColorApplied across the 3 views
Owners + apps + execModesBOARDsteps[].owners[] .tools[] .execModes[] (same for subs)Tags shared via gantt_shared_tags
Prompt configBOARDsteps[].prompt = { enabled, title, url, target } · same for subtarget = 'task' or sub index. Red #c45c5c.
URL configBOARDsteps[].url = { enabled, title, url, target } · same for subExact mirror of Prompt. Purple #a855f7. Visible if enabled.
FINDER configBOARDsteps[].finder = { enabled, title, url, target } · same for subSeparate from URL since 28/07. Gold button, opens Finder via eofinder://.
OVERLAY configBOARDsteps[].overlay = { enabled, title, url, target } · same for subCyan safe-zone marker. URL defaults to content-system Safe Zones.
Run notesvideo_runs (D1)notes TEXT columnEntered via the "Validate & close run" modal on the last pending step.
parallelTo (intra-phase pairing)BOARDsteps[].parallelToPushes 2 steps into the same V3 column
Phase / step ordering BOARDBOARDOrder of the phases[] and steps[] arraysDetermines V3 swimlane order (top→bottom)
Custom arrows (X positioning)V3_CHAINV3_CHAIN.chain[srcCellId] = [tgtCellId, …]Intra-phase = pushes target by 1 col. Cross-phase = no push, visual only.
Trigger kind of a cross-phase arrowV3_CHAINV3_CHAIN.triggers[srcCellId] = { kind: 'phase'|'step'|'sub', refId }Semantic: what must be complete to start the target phase. To be implemented.
V3 firstCellV3_CHAINV3_CHAIN.firstCellGold frame + BFS anchor (residual, dispensable since per-swimlane depth)
Run completions (steps + subs)video_runs (D1)completions = { steps: {id: {checked_at}}, subs: {…} }Per run, not per BOARD
Run history listvideo_runs (D1)Entire tableShown in the "Tracked runs" widget

F.2 Visibility — where each piece of data appears

DataV1 (Edit)V2 (Run)V3 (Gantt)
Phase labelPhase header (editable)Mention in card metaPhase cell + left lane head
Step labelLeft row + right SVG bar (editable)Card name (editable)Step cell name (editable)
Sub-action labelChip-sub (editable)Sub-card name (editable)Mini-row in step cell (editable)
Phase colorPhase border + chipsCard border + dotCell border + swimlane tint + lane head
Text colorOn the name (row + bar)On the card + sub-card nameOn the cell name + sub mini-row
Owners + apps + execModesStep-line chips + chips in chip-subChips in card + sub-cardChips in cell
Prompt buttonButton in row (task or sub)Button in card / sub-cardTop-right button of cell
parallelToBilateral orange ∥ chipCards aligned on the same wave + gold dotCells stacked in the same intra-swimlane column
V3 custom arrowNEW: Edit step modal → "Previous actions" + "Next actions" section (read-only, × to remove)Implicit via wave shift (= consequence of the column push)Drawn arrow (orthogonal path)
Trigger kind (cross-phase)Edit step modal → "triggers phase X" mention with kindThe target phase's wave appears only once the trigger is satisfied (checking = advances the wave)Modal on draw + mini chip on the cross-phase arrow (phase / step / sub icon)
Run completions step⊙ check on card⊙ check on cell
Run completions sub⊙ check on chip-sub⊙ check on sub-card⊙ check on mini-row

F.3 Action → Cross-view consequences

ActionDone inConsequence in the other views
Rename (label) a cellV1 · V2 · V3BOARD.label mutated → all views re-render with the new name
Check / uncheck a stepV2 · V3video_runs mutated → V2 + V3 ⊙ check sync (V1 does not show the run)
Check / uncheck a subV1 · V2 · V3video_runs mutated → V1 ⊙ + V2 sub-card check + V3 mini-row check sync
Change text color (green/red/yellow/white)V1 · V3 (right-click)BOARD.textColor mutated → 3 views re-render with color
Set parallelTo (right-click ∥)V1 · V3BOARD.parallelTo mutated → V1 bilateral ∥ chip + V2 cards same wave + V3 cells same intra-swimlane column
Drag-drop a step in V2 from one wave to anotherV2NEW: writes an intra-phase custom arrow in V3_CHAIN.chain that pushes the step by N columns → V3 shows the cell at the new column + V2 recomputes its waves from V3
Draw a custom arrow in V3 (intra-phase)V3V3_CHAIN.chain mutated → V3 target cell pushed by 1 col + V2 adds a wave + V1 Edit step modal shows it in Previous/Next actions
Draw a custom arrow in V3 (cross-phase)V3Modal opens: "Trigger by: ☐ Full phase complete ☐ Specific step ☐ Specific sub". Choice → V3_CHAIN.triggers + visible arrow. V2 gates the start of the target phase's wave on the trigger being satisfied.
Add / remove a phase / step / subV1 (toolbar or modal)BOARD mutated + V3_CHAIN cleaned of orphaned refs → 3 views re-render
Set first cell V3V3 toolbarV3_CHAIN.firstCell mutated → V3 gold frame (V1 and V2 unchanged)
Reorder phases / steps in BOARDV1 drag-dropBOARD order mutated → V3 swimlane order (top→bottom) + BOARD-list order in V2

F.4 Positioning model (the core)

  1. Y axis: V3 swimlane order = BOARD.phases[] order. One phase = one swimlane = one horizontal band.
  2. Intra-swimlane X axis: phase cell at col 0, steps at col 1 by default. Intra-phase parallelTo + intra-phase V3 custom arrows can push a step to col 2+.
  3. Cross-phase: no auto arrow. Cross-phase V3 custom arrows do NOT move the target on X (each swimlane stays independent). They only add a semantic trigger.
  4. V2 waves: derived strictly from the V3 columns, merged cross-swimlane. Wave N = all steps of all phases whose V3 column equals N, AND whose phase trigger is satisfied (or phase already in progress).
  5. V1 Edit step modal: the "Previous actions" section lists the cells pointing to this step (read from the inverse of V3_CHAIN.chain). The "Next actions" section lists the cells this step points to.

F.5 Save guard: atomic 409 + 3-way merge + undo barrier

F.6 Per-view position memory (localStorage)

G — Color code· phase + text + execMode

G.1 Phase palette (PHASE_PALETTE)

IndexColorHex
0 purple#a855f7
1 gold#e8d5b0
2 cyan#06b6d4
3 green#22c55e
4 pink#ec4899
5 orange#f59e0b
6 blue#3b82f6
7 light green#84cc16

Option A: all steps of a phase automatically take phase.color on load (per-step custom colors are overwritten). Sub-actions visually inherit their parent phase's color with a subtle variation (lighten 35%).

G.2 Text color (per task/sub override)

ValueHexPreview
'red'#e08585Red text
'yellow'#e8d265Yellow text
undefined (= white)#ffffffWhite text
'green' (phase label only)#5ed191Green text
'wave1' (phase label only, legacy)#e8d265Yellow pill

Editable via right-click (V1 on task or sub, V3 on an internal sub-action). Synchronized across the 3 views. Since 2026-07-24 the yellow pill identity ('wave1') is carried by the WAVE dropdown headers themselves; the value stays accepted for legacy rows.

G.3 ExecModes (AUTO / MANUAL / SEMI)

H — Context menus (right-click)· full V1/V3 parity

H.1 On a sub-action (V1 .chip-sub-text · V3 mini-row)

  1. Set text green
  2. Set text red
  3. Set text yellow
  4. Set text white
  5. ⌐ Toggle strikethrough
  6. ∥ Set parallel to… (another sub-action in the same task, orange)
  7. ⚙ Configure prompt… (red)
  8. ⚙ Configure URL… (purple)
  9. ⚙ Configure FINDER link… (gold)
  10. ⚙ Configure OVERLAY… (cyan)
  11. ⎘ Duplicate sub-action
  12. ↪ Link to another sub-action…
  13. ◪ Move to SBY (yellow)

H.2 On a main task (V1 .task-row-name)

  1. Set text green
  2. Set text red
  3. Set text yellow
  4. Set text white
  5. ⌐ Toggle strikethrough
  6. ∥ Set parallel to… (another task in the SAME phase, ergonomic equivalent of the V2 drag-drop)
  7. ⚙ Configure prompt… (red)
  8. ⚙ Configure URL… (purple)
  9. ⚙ Configure FINDER link… (gold)
  10. ⚙ Configure OVERLAY… (cyan)
  11. ⎘ Duplicate task
  12. ↪ Link to another task… (cross-phase)
  13. ⇄ Move to another phase…
  14. ◪ Move to SBY (yellow)

H.3 On a V3 cell (outside an internal sub-action)

  1. Tree modal to add a custom arrow to another cell.
  2. List of existing triggers at the top, remove via × cell.

I — Tracked runs (videos in production)· shared widget

1 run = 1 video that goes through the 2 boards (LF then Cross ~3 weeks later).

I.1 "Active runs" widget

I.2 Toggling a step / sub

Click the dot → PATCH /api/admin/video-runs/:id with {step, done, total_steps} or {sub, done}. The server computes started_at = max(checked_at) among the checks already done. checked_at = ISO now. When done count ≥ total_steps → automatic completed_at.

I.3 Cross-tab sync

BroadcastChannel('video_runs_updated') notifies the other open tabs. The page listens and re-renders.

J — Files, endpoints, D1 stores· where to look

J.1 Source files

PathRole
public/backdata/lf-cross-platform-content.htmlMain page (~6500 lines as of 29/07). Inline HTML + CSS + JS.
public/backdata/_video-runs.jsShared tracked-runs widget. Active runs section, decorateBoard with checkboxes.
public/backdata/_board-ui.jsShared behaviors: collapse, step drag-drop, context menu (sub + task).
public/backdata/_tune.jsLive layout tuner ?tune=1 (dev-only).
public/backdata/long-process.htmlLegacy LF page (still active, writes the same D1 store).
public/backdata/cross-platform-content.htmlLegacy Cross page (still active, writes the same D1 store).

J.2 API endpoints

PathMethodsRole
/api/admin/state/[key]GET / PUTRead/write a JSON blob in intranet_state. Used for gantt_long_v2, cross_platform_content_process_v2, gantt_shared_tags, gantt_v3_triggers, lfx_change_log. Conditional write: GET returns the updated_at token, the client echoes it via X-If-Updated-At, and a mismatch answers 409 (see F.5). Board keys are versioned in intranet_state_history on every save.
/api/admin/video-runsGET (list) / POST (create)Lists runs filtered by status, creates a new run.
/api/admin/video-runs/[id]GET / PATCH / DELETERun detail, toggle step/sub, rename label, archive.

J.3 D1 stores

Key / TableSchemaCanonical source
gantt_long_v2 (intranet_state)BOARD LF (phases + steps Script · Film · Edit · Post)BOARD (split on save)
cross_platform_content_process_v2 (intranet_state)BOARD CrossBOARD (split on save)
gantt_shared_tags (intranet_state)Owners + Apps + Arrows tagsTAGS (shared across the 3 pages)
gantt_v3_triggers (intranet_state){firstCell, chain}V3_CHAIN (additive only, not in BOARD)
video_runs (dedicated table)1 row per runAPI /api/admin/video-runs
lfx_change_log (intranet_state){entries[]} readable diff lines, last 400Written on every save (diffBoards), read via the "≡ Change log" toolbar button
intranet_state_history (dedicated table)1 row per save per board key (cap 200/key)Server-side versioning, includes direct D1 patches done by Claude

K — Deployment workflow· non-negotiable

No GitHub auto-deploy. On this repo (eliteoutsiders-tools), git push ALONE deploys nothing. The prod page stays frozen on the last npm run deploy:prod.

Claude (and AL) workflow after any edit:

cd ~/Projects/eliteoutsiders-tools
# 1. Inline JS syntax validation (anti page-stuck-at-loading)
node -e "const fs=require('fs');const html=fs.readFileSync('public/backdata/lf-cross-platform-content.html','utf8');const scripts=[...html.matchAll(/<script>([\s\S]*?)<\/script>/g)];scripts.forEach((m,i)=>{try{new Function(m[1]);console.log('script',i,'OK')}catch(e){console.log('ERR:',e.message)}})"

# 2. Commit
git add -A
git commit -m "..."

# 3. DEPLOY (= wrangler pages deploy + smoke tests)
npm run deploy:prod

The deploy:prod script chains: inject-meta.js (canonical + robots) → wrangler pages deploy public --project-name=eliteoutsidersintranet --commit-dirty=truesmoke-test.sh (51 URLs) → auto-commit-after-deploy.sh (creates the commit deploy: prod ship YYYY-MM-DD HH:MM).

L — Recent changelog· updated at each iteration

2026-08-02 update (Run view phase-follows-steps + links + Cmd+B + Gantt zoom/fullscreen)

2026-07-29 update (FINDER split + exec badges + undo barrier + phase strip + position memory + content resync 28-29/07)

2026-07-28 (atomic save guard + newsletter wiring + shorts resync + sub-tags rows)

2026-07-26 (FINDER one-click + mapping pass + overwrite guard + sync cron)

2026-07-24 late (SBY parking + menu colors + config defaults + wave data migration)

2026-07-24 (WAVE dropdowns + Batch rename + Finder tag)

2026-05-19 (D+7 — global phase order persistence)

2026-05-19 (D+6 — V3 dynamic channel widening)

2026-05-19 (D+5 — V3 task numbering T01/T02)

2026-05-19 (D+4 — fix phase title overlap + Wave view 1 option)

2026-05-19 (D+3 — kill page-jump on textColor + strike toggle)

2026-05-19 (D+2 — color picker page-jump diagnosis)

2026-05-19 (D+1 — fix ownerToMode for renamed tags)

2026-05-19 (late night 6 — Execution auto-derived from Owner)

2026-05-19 (late night 5 — CF Access session guard T+23h59)

2026-05-19 (late night 4 — Add step moved + short label newlines)

2026-05-19 (late night 3 — strikethrough toggle right-click)

2026-05-19 (late night 2 — undo glow ping + doc target_blank)

2026-05-19 (late night — fix DnD + phase nums + URL/PROMPT lock)

2026-05-19 (cont. — end of day)

2026-05-19