Skip to content

feat(ui): edge-to-edge glass header with progressive-blur scrolling - #570

Merged
BigSimmo merged 2 commits into
mainfrom
claude/phone-blackout-fix-nuxnt3
Jul 13, 2026
Merged

feat(ui): edge-to-edge glass header with progressive-blur scrolling#570
BigSimmo merged 2 commits into
mainfrom
claude/phone-blackout-fix-nuxnt3

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Brings the top header up to the bottom composer dock's standard: a translucent glass bar with a top progressive-blur scrim, reaching edge-to-edge under the notch/status bar, that content scrolls beneath and frosts against — mirroring the dock's masked 2px/8px/22px three-pass blur (.answer-footer-search-backdrop) but inverted so the blur is strongest at the physical top edge.
  • Glass bar (src/app/globals.css): .edge-glass-header / .universal-header backgrounds become color-mix(in srgb, var(--surface) 72%, transparent), which activates the header's previously-inert backdrop-blur-xl (it was a no-op over the old opaque surface). The hard border-bottom and the old below-header ::after mini-gradient are superseded by the new .edge-glass-header-backdrop scrim, rendered as the first child of <header> so it slides away with the bar. The mode pill and icon controls keep their opaque inline surfaces and stay legible.
  • Answer view overlays the header at every breakpoint (ClinicalDashboard.tsx, master-search-header.tsx): the header goes absolute inside the now-relative content column, and <main> reserves the bar's exact measured height (72px borderless bar → calc(4rem + max(0.5rem, env(safe-area-inset-top)))) as top padding — padding scrolls with content, which is what lets it slide up and frost beneath the glass. The reserve is constant (it sits at scroll-start and is already off-screen whenever the header hides, so reclaiming it would only jump content). scroll-padding-top keeps scrollIntoView targets clear of the bar.
  • Slide-away / return at all widths: new opt-in allBreakpoints overlay path (useScrollHideReporter, MasterSearchHeader.hideOnScroll) — the header translates up on scroll-down and returns on any deliberate scroll-up, mirroring the phone bottom dock; activation offset raised 56 → 72 to match the bar height. The existing open-menu/focus guards are reused unchanged (menus pin the bar; keyboard focus reveals it).
  • Non-answer modes are intentionally structural no-ops: they keep the in-flow header + phone-only collapse (their sm+ composer renders in-flow beneath the header, which an absolute bar would bury) while still gaining the glass + scrim visuals. Bottom dock behavior is untouched.
  • Accessibility fallbacks mirror the dock: @supports not (backdrop-filter) and prefers-reduced-transparency: reduce force an opaque bar + stronger scrim tint; forced-colors: active paints solid Canvas with no blur/mask; motion-reduce disables the slide transition.

Verification

  • npm run verify:pr-local — not run; ran the equivalent gates below.
  • npm run verify:cheapexit 0 (runtime, Actions pin, sitemap, brand, type-scale, icon-scale, full lint, typecheck, 1,929 unit tests incl. the merge-artifact guards).
  • Chromium UI (in lieu of the stock verify:ui invocation, which in this sandbox needs PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH pointed at the pre-installed browser): full tests/ui-smoke.spec.ts70 passed; the only 4 failures are the pre-existing, unrelated /privacy heading test that fails identically on clean main (local-env quirk; untouched by this diff).
    • Rewritten/new coverage: phone overlay hide/reveal + a reserve == rendered-bar-height invariant, desktop hide/reveal, non-answer phone collapse retention — all green, alongside the existing phone answer-layout phantom-scroll guards (which prove the reserve math is 1:1).
    • Manual Playwright sweep at 390/768/1280, light + dark: content frosts under the bar mid-scroll and is fully clear at rest; hide/reveal at every width with no top band or reveal jump; answer home stays centred; documents mode keeps its in-flow header/composer; mode-menu-open and header-focus guards pin the bar.
  • Retrieval/answer-eval and readiness checks: N/A — presentation-layer only.

Clinical Governance Preflight

N/A — pure presentation/layout change (header chrome, scrim CSS, scroll-hide wiring). No ingestion, answer generation, search/ranking, source rendering logic, document access, privacy, production env, or clinical output behavior is affected.

Notes

  • Per the approved design, the desktop/tablet header now hides on scroll-down in the answer view (the bottom composer stays put on desktop). If that feels off in review, flipping allBreakpoints: false in ClinicalDashboard.tsx makes desktop a pinned glass bar while phones keep hiding — one-line toggle.
  • manifest.tstheme_color stays #ffffff (a static manifest can't be per-scheme; the per-scheme viewport.themeColor already tints browser chrome for both themes — installed-PWA splash is the only surface affected).

Generated by Claude Code

Bring the top header up to the bottom composer dock's standard: a
translucent glass bar with a top progressive-blur scrim, edge-to-edge
under the notch/status bar, that content scrolls beneath and frosts
against — mirroring the dock's masked 2px/8px/22px three-pass blur but
inverted so it is strongest at the physical top edge.
- Glass bar: .edge-glass-header/.universal-header backgrounds become
color-mix(var(--surface) 72%, transparent), activating the header's
previously inert backdrop-blur; the hard border-bottom and the old
below-header ::after gradient are superseded by the new
.edge-glass-header-backdrop scrim (rendered inside <header> so it
slides away with it). Mode pill and icon controls keep their opaque
inline surfaces and stay legible.
- Answer view overlays the header at every breakpoint: the header goes
absolute inside the (now relative) content column and <main> reserves
the bar's exact measured height (72px + safe-area-top) as top padding,
so scrolled content passes beneath the glass; the reserve is constant
(it sits at scroll-start and is already off-screen whenever the header
hides). scroll-padding-top keeps scrollIntoView targets clear of the
bar. The header slides away on scroll-down and returns on scroll-up at
all widths (new allBreakpoints overlay in useScrollHideReporter /
MasterSearchHeader; activation offset raised to the bar height).
- Non-answer modes keep the in-flow header + phone-only collapse (their
sm+ composer renders beneath the header, which an absolute bar would
bury) while still gaining the glass + scrim visuals.
- Accessibility fallbacks mirror the dock: no-backdrop-filter and
prefers-reduced-transparency force an opaque bar + stronger scrim
tint; forced-colors paints solid Canvas; motion-reduce disables the
slide transition.
- Tests: the header-hide smoke test is rewritten for the overlay
mechanism (absolute header, data-scroll-hidden on <header>, reserve ==
bar height), plus new desktop hide/reveal and non-answer collapse
coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1ekcXQZVFVKKzdoVpjyVQ
@supabase

supabaseBot commented Jul 13, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitaiBot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Answer-mode headers now overlay content consistently across phone and desktop layouts.
    • Headers automatically hide while scrolling down and reappear when scrolling up.
    • Answer views reserve space for the header to keep content aligned.
  • Bug Fixes

    • Improved header readability and visual layering with translucent glass effects.
    • Added fallbacks for reduced transparency, unavailable blur support, and high-contrast display modes.
    • Prevented private-scope alerts from being clipped or causing layout shifts.

Walkthrough

The change adds translucent glass header styling, progressive backdrop scrims, all-breakpoint scroll hiding for answer mode, reserved main-content spacing, alert relocation, and mobile/desktop UI coverage.

Changes

Glass header overlay

Layer / File(s)Summary
Glass header chrome and fallbacks
src/app/globals.css
Header surfaces use translucent glass styling, progressive blur scrims, and no-blur, reduced-transparency, and forced-colors fallbacks.
All-breakpoint scroll overlay behavior
src/components/clinical-dashboard/use-hide-on-scroll.ts, src/components/clinical-dashboard/master-search-header.tsx
Scroll hiding supports all breakpoints, and overlay headers use absolute positioning, updated translation behavior, and a backdrop element.
Answer-mode layout integration and validation
src/components/ClinicalDashboard.tsx, tests/ui-smoke.spec.ts
Answer mode enables the overlay header and reserves matching main-content spacing; tests cover phone, desktop, and document-mode behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
participant User
participant ClinicalDashboard
participant useScrollHideReporter
participant MasterSearchHeader
participant Main
User->>ClinicalDashboard: Open answer mode
ClinicalDashboard->>useScrollHideReporter: Enable all-breakpoint reporting
ClinicalDashboard->>MasterSearchHeader: Configure overlay header
ClinicalDashboard->>Main: Reserve header height and scroll padding
User->>Main: Scroll content
Main->>useScrollHideReporter: Report scroll position
useScrollHideReporter->>MasterSearchHeader: Update hidden state
MasterSearchHeader->>Main: Overlay and hide or reveal header
Loading

Possibly related PRs


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check nameStatusExplanationResolution
Verification Claims❌ ErrorThe description still has vague verification claims (“successful cheap checks”, “70 passing Chromium UI tests”) without exact command/result wording.Rewrite those notes as explicit entries, e.g. “Ran npm run verify:cheap: passed” and “Ran tests/ui-smoke.spec.ts: 70 passed”; avoid broad pass claims.
Docstring Coverage⚠️ WarningDocstring coverage is 33.33% which is insufficient. The required threshold is 70.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (9 passed)
Check nameStatusExplanation
Title check✅ PassedThe title is concise and accurately captures the main UI change: an edge-to-edge glass header with progressive-blur scrolling.
Description check✅ PassedThe description matches the template well, with Summary, Verification, Clinical Governance Preflight, and Notes filled in appropriately.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Generated And Sensitive Files✅ PassedPR changes only source/test files; diff scan found no secrets, tokens, logs, caches, build outputs, node_modules, or other generated artifacts.
Risky Git Or Deployment Actions✅ PassedThe PR is UI/CSS and scroll-behavior only; the touched files contain no force-push, hard-reset, branch-deletion, or destructive deploy instructions.
Supabase Project And Schema Safety✅ PassedOnly CSS changed; no Supabase refs, schema/migration, RLS, policy, or env updates were present.
Runtime And Package Manager Integrity✅ PassedNo package.json/lockfile/.npmrc/Node version changes; repo still pins npm@11.17.0, Node 24.x, and engine-strict=true.
Api Route Failure Handling✅ PassedOnly UI/header CSS, scroll hook, and smoke tests changed; no API/server/provider integration paths were modified.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/phone-blackout-fix-nuxnt3
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/phone-blackout-fix-nuxnt3

Comment @coderabbitai help to get the list of available commands.

CI format:check flagged the new .edge-glass-header-backdrop::before
mask-image line; pure line wrapping, no value change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1ekcXQZVFVKKzdoVpjyVQ
@BigSimmo
BigSimmo marked this pull request as ready for review July 13, 2026 09:49
@BigSimmo
BigSimmo merged commit cc6bfc1 into mainJul 13, 2026
13 of 15 checks passed

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:551b07b44e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

: "max-sm:transition-transform max-sm:duration-200 max-sm:ease-out motion-reduce:transition-none"),
hideStrategy === "overlay" &&
headerChromeHidden &&
(overlayAllBreakpoints ? "-translate-y-full" : "max-sm:-translate-y-full"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Translate the full scrim offscreen

In answer mode after scrolling down, this -translate-y-full only moves the header by its own rendered height (~72px), but the newly added .edge-glass-header-backdrop is taller (max(6.5rem, safe-area + 5.5rem)) and is not clipped by the header. That leaves roughly 1.5–2rem of the blurred/tinted scrim still visible at the top after the header is marked hidden, so content never gets the fully clear viewport the hide-on-scroll behavior is meant to provide; the current bounding-rect test misses it because the overflowing backdrop does not affect the header rect.

Useful? React with 👍 / 👎.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/app/globals.css (1)

659-723: 🚀 Performance & Scalability | 🔵 Trivial

Stacked backdrop-filter layers now run at every breakpoint in answer mode.

The header itself carries backdrop-blur-xl backdrop-saturate-150 (Tailwind, on the <header> element) plus this new .edge-glass-header-backdrop element layers three more backdrop-filter passes (blur(2px), ::before blur(8px), ::after blur(22px)) to build the progressive frost. Previously this cost was scoped to phone widths only for answer mode's hide/show cycling; with the all-breakpoints overlay, these compositing-heavy layers now recompute continuously while scrolling on desktop too. Worth a quick perf check (Chromium profiling / npm run verify:ui) on lower-end hardware, since multiple stacked backdrop-filters are one of the pricier paint operations in the platform.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/globals.css` around lines 659 - 723, Restrict the stacked
backdrop-filter treatment in .edge-glass-header-backdrop and its
::before/::after layers to the narrow answer-mode breakpoint where hide/show
cycling requires it, while preserving the existing header glass styling and
desktop behavior. Verify the all-breakpoints overlay no longer applies the three
compositing-heavy blur passes during desktop scrolling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/clinical-dashboard/master-search-header.tsx`:
- Around line 246-256: Update the internal scroll fallback used by hideOnScroll
so overlay mode with allBreakpoints enabled also computes hide/reveal state on
non-phone breakpoints when scrollHidden is not supplied. Thread
hideOnScroll.allBreakpoints into the scroll hook or fallback configuration,
while preserving parent-provided scrollHidden behavior and existing phone-only
behavior otherwise.
In `@src/components/clinical-dashboard/use-hide-on-scroll.ts`:
- Around line 55-58: Thread allowAllBreakpoints through UseHideOnScrollOptions
and the useHideOnScroll implementation, forwarding it to both helper calls
including usePhoneScrollHideActive. Ensure the internal fallback in
master-search-header.tsx passes hideOnScroll.allBreakpoints so overlay mode can
operate beyond phone breakpoints.
---
Nitpick comments:
In `@src/app/globals.css`:
- Around line 659-723: Restrict the stacked backdrop-filter treatment in
.edge-glass-header-backdrop and its ::before/::after layers to the narrow
answer-mode breakpoint where hide/show cycling requires it, while preserving the
existing header glass styling and desktop behavior. Verify the all-breakpoints
overlay no longer applies the three compositing-heavy blur passes during desktop
scrolling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f79396cb-8cdf-4a6e-aca3-5cd959f9045f

📥 Commits

Reviewing files that changed from the base of the PR and between 5e2e90f and 551b07b.

📒 Files selected for processing (5)
  • src/app/globals.css
  • src/components/ClinicalDashboard.tsx
  • src/components/clinical-dashboard/master-search-header.tsx
  • src/components/clinical-dashboard/use-hide-on-scroll.ts
  • tests/ui-smoke.spec.ts

Comment on lines 246 to 256
hideOnScroll?: {
strategy: "overlay" | "collapse";
/**
* Overlay-only: apply the hide/reveal (and the out-of-flow absolute header)
* at every breakpoint instead of phones only. The host must reserve
* matching top padding on its scroll container.
*/
allBreakpoints?: boolean;
/** Parent-owned hidden state for hosts that report scroll via React `onScroll`. */
scrollHidden?: boolean;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash# Description: Confirm every current caller that sets allBreakpoints also sets scrollHidden.
rg -n -B3 -A3 'allBreakpoints' src/components

Repository: BigSimmo/Database

Length of output: 2463


🏁 Script executed:

#!/bin/bashset -euo pipefail
# Inspect the component logic around hideOnScroll and the hook implementation.
rg -n -A8 -B8 'internalScrollHidden|overlayAllBreakpoints|hideOnScroll\.scrollHidden|useHideOnScroll|strategy: "overlay"|allBreakpoints' src/components/clinical-dashboard/master-search-header.tsx src/components/ClinicalDashboard.tsx src/components -g '!**/*.map'# Show the relevant section of the header component with line numbers.
sed -n '1360,1465p' src/components/clinical-dashboard/master-search-header.tsx
# Show the hook implementation if present.
fd -a 'use-hide-on-scroll.ts' src

Repository: BigSimmo/Database

Length of output: 38165


🏁 Script executed:

#!/bin/bashset -euo pipefail
sed -n '1,220p' src/components/clinical-dashboard/use-hide-on-scroll.ts

Repository: BigSimmo/Database

Length of output: 6591


Thread all-breakpoints into the scroll fallback. The overlay + allBreakpoints path still depends on scrollHidden, but the internal fallback stays phone-only. If a caller sets hideOnScroll={{ strategy: "overlay", allBreakpoints: true }} without also passing scrollHidden, the header will become absolute on desktop but never hide/reveal there. Either require scrollHidden for that mode or pass the all-breakpoints flag into the scroll hook.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/clinical-dashboard/master-search-header.tsx` around lines 246
- 256, Update the internal scroll fallback used by hideOnScroll so overlay mode
with allBreakpoints enabled also computes hide/reveal state on non-phone
breakpoints when scrollHidden is not supplied. Thread
hideOnScroll.allBreakpoints into the scroll hook or fallback configuration,
while preserving parent-provided scrollHidden behavior and existing phone-only
behavior otherwise.

Source: Path instructions

Comment on lines +55 to 58
function usePhoneScrollHideActive(disabled = false, allowAllBreakpoints = false) {
const isPhone = useSyncExternalStore(subscribeToPhoneMedia, readPhoneMedia, readPhoneMediaServer);
return isPhone && !disabled;
return (allowAllBreakpoints || isPhone) && !disabled;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash# Description: Find other consumers of useHideOnScroll to confirm no caller currently# needs allBreakpoints through this path.
rg -n -B2 -A6 '\buseHideOnScroll\s*\(' src

Repository: BigSimmo/Database

Length of output: 3050


🏁 Script executed:

#!/bin/bashset -euo pipefail
sed -n '1,220p' src/components/clinical-dashboard/use-hide-on-scroll.ts | cat -n

Repository: BigSimmo/Database

Length of output: 7907


🏁 Script executed:

#!/bin/bashset -euo pipefail
rg -n "allowAllBreakpoints|useScrollHideReporter|usePhoneScrollHideActive|useHideOnScroll" src/components/clinical-dashboard src/components/DocumentViewer.tsx

Repository: BigSimmo/Database

Length of output: 2095


🏁 Script executed:

#!/bin/bashset -euo pipefail
sed -n '220,340p' src/components/clinical-dashboard/master-search-header.tsx | cat -n

Repository: BigSimmo/Database

Length of output: 7872


useHideOnScroll should forward allowAllBreakpoints.master-search-header.tsx already exposes hideOnScroll.allBreakpoints, but the internal fallback still calls useHideOnScroll({ disabled: !hideOnScroll || hideOnScroll.scrollHidden !== undefined }), so overlay mode stays phone-only instead of widening past the breakpoint. Thread the option through UseHideOnScrollOptions and both helper calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/clinical-dashboard/use-hide-on-scroll.ts` around lines 55 -
58, Thread allowAllBreakpoints through UseHideOnScrollOptions and the
useHideOnScroll implementation, forwarding it to both helper calls including
usePhoneScrollHideActive. Ensure the internal fallback in
master-search-header.tsx passes hideOnScroll.allBreakpoints so overlay mode can
operate beyond phone breakpoints.

BigSimmo pushed a commit that referenced this pull request Jul 13, 2026
Post-merge review of the glass header (#570) surfaced that the CSS build
pipeline was silently dropping EVERY hand-authored backdrop-filter
declaration: the manual -webkit-backdrop-filter duplicates in
globals.css confused Lightning CSS's property merging, so the header
scrim, the bottom dock's three-pass progressive blur, and the composer
pill had been tint-only in every engine all along — the only real blur
came from Tailwind utilities. Removing the manual -webkit- duplicates
(the pipeline handles prefixing) restores genuine blur to all of them,
verified via computed styles and visual probes.
With real blur available, the review's remaining findings are fixed:
- The header element no longer carries backdrop-blur utilities (an
element with backdrop-filter forms a backdrop root that starves the
nested scrim of the page behind it — redundant in Chromium, inert in
WebKit). The retuned scrim (14/20/26px, top-biased masks) is now the
single source of the bar's frost and samples the real page in every
engine, cutting the always-active blur layers on the answer view.
- Every scrim mask now fades to true zero before content rests, so no
faint veil sits on the first line at rest, and the hidden-state
residual is bounded by a new test assertion.
- The private-scope recovery alert is sticky inside <main> so its
actions stay reachable while scrolling in every mode (it previously
scrolled away in non-answer modes); covered by a new test.
- The scroll-hide reporter resets its direction state when the
breakpoint gate changes, avoiding a stale hide/reveal blip on phone
mode switches.
- The no-blur / reduced-transparency fallback bar backgrounds are now
layered so call-site utilities keep winning per the header-chrome
layering contract; the forced-colors override stays unlayered on
purpose.
Review recorded in docs/branch-review-ledger.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1ekcXQZVFVKKzdoVpjyVQ
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BigSimmo@claude