diff --git a/src/app/notes/header/tag-rail/tag-rail.component.scss b/src/app/notes/header/tag-rail/tag-rail.component.scss
index 62469cd..972fc0c 100644
--- a/src/app/notes/header/tag-rail/tag-rail.component.scss
+++ b/src/app/notes/header/tag-rail/tag-rail.component.scss
@@ -5,7 +5,21 @@
padding: 10px 24px;
border-bottom: 1px solid var(--line-soft);
flex-shrink: 0;
+}
+
+// ⚠️ Only the pills scroll. With the Manage button inside the scrolling row, its
+// `margin-left: auto` had no free space left to claim once the tags overflowed, and it
+// followed them out of the viewport.
+.tag-rail-scroll {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ flex: 1;
+ // Or the row pushes the button out again instead of scrolling.
+ min-width: 0;
overflow-x: auto;
+ // Falls on empty space while everything fits, so it only shows when there is more.
+ mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
.tag-rail-label {
@@ -18,7 +32,6 @@
.tag-rail-manage {
all: unset;
box-sizing: border-box;
- margin-left: auto;
flex-shrink: 0;
padding: 3px 9px;
border: 1px solid var(--line-soft);
diff --git a/src/app/notes/header/tag-rail/tag-rail.component.spec.ts b/src/app/notes/header/tag-rail/tag-rail.component.spec.ts
index a9bad30..358af39 100644
--- a/src/app/notes/header/tag-rail/tag-rail.component.spec.ts
+++ b/src/app/notes/header/tag-rail/tag-rail.component.spec.ts
@@ -42,6 +42,22 @@ describe('TagRailComponent', () => {
expect(rail.getAttribute('aria-label')).toBe('Filtrer par tag');
});
+ /**
+ * ⚠️ Structural, because jsdom lays nothing out. Inside the scrolling row the Manage
+ * button's `margin-left: auto` had no free space to claim once the tags overflowed, so
+ * it followed them out of the viewport — at forty tags it sat at x=2710 in a rail 1920
+ * wide. What keeps it reachable is being outside that row.
+ */
+ it('keeps the Manage button out of the row that scrolls', async () => {
+ fixture.componentRef.setInput('tags', ['alpha', 'beta']);
+ await fixture.whenStable();
+
+ const scroll = fixture.nativeElement.querySelector('.tag-rail-scroll');
+ expect(scroll.querySelectorAll('app-tag-pill')).toHaveLength(2);
+ expect(scroll.querySelector('.tag-rail-manage')).toBeNull();
+ expect(fixture.nativeElement.querySelector('.tag-rail > .tag-rail-manage')).not.toBeNull();
+ });
+
it('forwards the toggled event from a tag pill as tagToggled', async () => {
fixture.componentRef.setInput('tags', ['alpha']);
await fixture.whenStable();