Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/landing-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@
# privacy page at a range of widths and fails on horizontal overflow.
#
# Kept out of android-build.yml so it does not tangle with the required "build"
# check and only runs when the docs actually change.
# check and only runs when the docs actually change. The stylesheets are in that
# set too: layout lives in the CSS, so a markup-only filter would let exactly the
# change most able to overflow a page through untested.
name: Landing check

on:
push:
branches: [main]
paths:
- 'docs/**.html'
- 'docs/**.css'
- 'scripts/check-landing-overflow.mjs'
- '.github/workflows/landing-check.yml'
pull_request:
paths:
- 'docs/**.html'
- 'docs/**.css'
- 'scripts/check-landing-overflow.mjs'
- '.github/workflows/landing-check.yml'
workflow_dispatch:
Expand Down
8 changes: 8 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2026-07-27 - Landing stylesheets made direction-aware (#146)

- Trigger: looking back at #146 — the Persian reader whose right-to-left note content laid out left-to-right, fixed in v2.28.0 — the same question one level up: the app handles RTL, the site around it never had to. The work started as a Persian README plus landing page; the maintainer cut that mid-flight, leaving only the part that has to exist before any RTL page can.
- Analysis: both stylesheets were written in physical directions — `left` on the skip link and the file-receipt card, `border-left` on the trust-ledger dividers, `padding-left` on the feature-point bullets and their `::before` dash, `margin-left` in the file-browser bar, `text-align: right` on the channel-row status, `padding-left` on the privacy page's lists. Each is a no-op to swap under LTR and a visible break under RTL. Three things do not follow from direction at all: the font stacks name Latin/CJK faces only, the display tracking is negative (which closes up a joined script), and `translateX` on the channel-row hover has no logical form.
- Contract/scope: physical offsets become logical (`inset-inline-start`, `padding-inline-start`, `border-inline-start`, `text-align: start/end`); the three exceptions get `[dir="rtl"]` rules — an Arabic-script *system* stack (no webfont, the pages fetch nothing), `letter-spacing: normal`, and a mirrored hover nudge with its `:active` reset. No new page and no content change: the six landing pages, six privacy pages and six READMEs are untouched.
- Verification: geometry diff of every element on 14 pages x 4 widths, old CSS vs new. The twelve real pages come out box-identical; the only computed-style change anywhere is `text-align` reporting `start` instead of `left` on three `.channel-row em`. Two throwaway `dir="rtl"` copies of `index.html` and `privacy.html` moved 20 elements and picked up the new stack, and screenshots confirm the mirror by eye — the file-receipt card and its accent border swap to the inline-start edge. `check-landing-overflow.mjs` passes 14 pages x 6 widths with both probes included. Pixel diffing was tried first and abandoned: the animated tablet GIFs and the `loading="lazy"` webps make the *same* tree screenshot differently twice, which read as four to nine phantom regressions per run.
- Gate: `landing-check` only fired on `docs/**.html`, so a stylesheet change — the one most able to overflow a page — reached `main` untested. `docs/**.css` added to both path filters, which is what makes this change itself gated.

## 2026-07-25 - Notes grid, first-line titles, and v2.32.0 (#279, #280)

- Trigger: two feature requests filed the same afternoon by one external reporter — a grid view for the notes list (#279), and a title field for each note (#280), the second reported as "what is set as the title is not necessarily the first line".
Expand Down
59 changes: 46 additions & 13 deletions docs/landing.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,29 @@ li {
word-break: keep-all;
}

/* Right-to-left pages. The layout itself mirrors on its own — every offset in
this file is a logical property — but typography does not follow from
direction. Arabic-script text needs a face the Latin/CJK stack above does not
carry; no webfont is fetched, so this is a system stack. Groundwork from
#146, where a Persian reader ran into the app's own right-to-left handling. */
[dir="rtl"] {
--font-display: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif;
--font-body: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif;
}

/* Tight negative tracking is a Latin display trick; in a joined script it pulls
letters into each other. */
[dir="rtl"] :is(h1, h2, h3) {
letter-spacing: normal;
}

/* Mono + wide tracking + uppercase reads as a Latin small-label device, and
Arabic script has no equivalent — keep the scale, drop the Latin styling. */
[dir="rtl"] :is(.kicker, .story-step, .channel-status, .release-line) {
font-family: var(--font-body);
letter-spacing: normal;
}

:focus-visible {
outline: 0.1875rem solid var(--color-focus);
outline-offset: var(--space-1);
Expand All @@ -157,7 +180,7 @@ li {
background: var(--color-primary-ink);
color: var(--color-surface);
font-weight: 700;
left: var(--space-4);
inset-inline-start: var(--space-4);
padding: var(--space-3) var(--space-4);
position: fixed;
text-decoration: none;
Expand Down Expand Up @@ -417,12 +440,12 @@ li {

.file-receipt {
background: var(--color-surface);
border-left: var(--space-1) solid var(--color-primary);
border-inline-start: var(--space-1) solid var(--color-primary);
bottom: 0;
box-shadow: 0 var(--space-2) var(--space-6) var(--color-shadow-soft);
display: grid;
gap: var(--space-1);
left: calc(-1 * var(--space-6));
inset-inline-start: calc(-1 * var(--space-6));
max-width: 18rem;
padding: var(--space-4) var(--space-6);
position: absolute;
Expand All @@ -448,7 +471,7 @@ li {
}

.hero-product > figcaption {
padding-left: var(--space-4);
padding-inline-start: var(--space-4);
}

.trust-ledger {
Expand All @@ -466,7 +489,7 @@ li {
}

.proof-item + .proof-item {
border-left: 0.0625rem solid var(--color-white-line);
border-inline-start: 0.0625rem solid var(--color-white-line);
}

.proof-item p {
Expand Down Expand Up @@ -546,15 +569,15 @@ li {

.feature-points li {
color: var(--color-ink);
padding-left: var(--space-6);
padding-inline-start: var(--space-6);
position: relative;
}

.feature-points li::before {
color: var(--color-primary);
content: "—";
font-weight: 800;
left: 0;
inset-inline-start: 0;
position: absolute;
}

Expand Down Expand Up @@ -606,7 +629,7 @@ li {

.file-browser-bar strong {
font-size: var(--text-caption);
margin-left: var(--space-2);
margin-inline-start: var(--space-2);
}

.ownership-demo pre {
Expand Down Expand Up @@ -808,6 +831,16 @@ li {
transform: translateX(0);
}

/* The nudge should follow the reading direction; translateX has no logical
form, so right-to-left gets its own pair (order matters — :active resets). */
[dir="rtl"] .channel-row:hover {
transform: translateX(calc(-1 * var(--space-1)));
}

[dir="rtl"] .channel-row:active {
transform: translateX(0);
}

.channel-row strong,
.channel-row small {
display: block;
Expand All @@ -828,7 +861,7 @@ li {
font-size: var(--text-caption);
font-style: normal;
font-weight: 750;
text-align: right;
text-align: end;
}

.channel-paused em {
Expand Down Expand Up @@ -943,7 +976,7 @@ li {
}

.file-receipt {
left: var(--space-4);
inset-inline-start: var(--space-4);
}

.trust-grid {
Expand All @@ -955,7 +988,7 @@ li {
}

.proof-item + .proof-item {
border-left: 0;
border-inline-start: 0;
border-top: 0.0625rem solid var(--color-white-line);
}

Expand Down Expand Up @@ -1028,7 +1061,7 @@ li {

.file-receipt {
bottom: var(--space-2);
left: var(--space-3);
inset-inline-start: var(--space-3);
max-width: calc(100% - var(--space-6));
padding: var(--space-3) var(--space-4);
}
Expand All @@ -1054,7 +1087,7 @@ li {
}

.channel-row em {
text-align: left;
text-align: start;
}
}

Expand Down
8 changes: 7 additions & 1 deletion docs/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ body {
line-height: 1.65;
}

/* Arabic-script text has no face in the stack above; a right-to-left page needs
one. No webfont is fetched — see the same note in landing.css. */
[dir="rtl"] body {
font-family: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif;
}

a {
color: inherit;
}
Expand Down Expand Up @@ -336,7 +342,7 @@ footer a {
}

.content ul {
padding-left: 1.3rem;
padding-inline-start: 1.3rem;
}

.content pre {
Expand Down
Loading