oficina / home Public

Move rastrillo to amadan.net/rastrillo/rastrillo (v0.23.0 -> 29e4491)

Every import of github.com/carlosframework/rastrillo in the root module
now names amadan.net/rastrillo/rastrillo, pinned at 29e4491 (v0.26.0+8),
the version connect, handoff and roster already required. connect,
handoff and roster imported only the new path already, so their go.mod
files are untouched and no app needs a home/connect bump. The old path
stops at v0.23.0, so Home had received no rastrillo fix since 2026-08-31,
iOS's zoom-on-tap fix included. The old module stays in go.mod only as
estilo's indirect requirement (chrome's SafeReturn).

At this pin sessions, csrf, passkey, webauthn, db and migrate differ from
v0.23.0 only in the import path; mail gains context-aware sending and a
Date header. An old database boots and migrates, its sessions still
authenticate on both roles, and a magic link minted by the old build
still signs in (checked on the production-shaped local stack).

- tokens.css re-copied by `go tool rastrillo doctor --fix`: the touch
  rule (16px text controls under a coarse pointer, touch-action:
  manipulation), button sizes, --rst-fs-lg, primary inputs, the stat
  band, native meter/progress, date picker styles. The four scripts
  doctor also writes are deleted: Home serves estilo's busy.js, and the
  shim at this pin carries rastrillo's old busy rule.
  TestNoRastrilloShimBesideBusy fails if one is left on disk or served.
- internal/guardstest: TestNoPreMoveRastrillo forbids the old path in
  every module.
- The CLI is a go.mod tool (`go tool rastrillo`).
- make release (and the placeholder's README) stamps
  amadan.net/rastrillo/rastrillo.BuildVersion. The old symbol would have
  left /api/version answering "dev".
- make credits: the new db package brings gormlite's licence.
- AGENTS.md: the path, the doctor step, and the stale "no vendored
  static/" paragraph corrected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev pushed by paul@keymail.dev b2f937b54b73c790a800d113104ff5b5880d83cb parent e75460d
49 files changed, +460 −83
  • AGENTS.md +23 −10
  • Makefile +1 −1
  • cmd/home-placeholder/README.md +2 −2
  • cmd/home-placeholder/main.go +1 −1
  • cmd/home/main.go +3 −3
  • go.mod +4 −1
  • go.sum +2 −0
  • internal/guardstest/premove_test.go +29 −0
  • internal/home/app.go +4 −4
  • internal/home/compatibility_linux.go +1 −1
  • internal/home/compatibility_linux_test.go +1 −1
  • internal/home/credits/notices.json +4 −0
  • internal/home/directory.go +3 −3
  • internal/home/directorydata/operator_schema.go +1 −1
  • internal/home/directorydata/roster.go +1 −1
  • internal/home/directorydata/roster_test.go +1 −1
  • internal/home/directorydata/store.go +1 −1
  • internal/home/directorydata/store_test.go +2 −2
  • internal/home/docs_chooser.go +2 −2
  • internal/home/docs_chooser_test.go +2 −2
  • internal/home/exchange.go +1 −1
  • internal/home/exchange_test.go +2 −2
  • internal/home/keys.go +1 −1
  • internal/home/legacy_schema_diagnostic.go +1 −1
  • internal/home/legacy_schema_diagnostic_test.go +2 −2
  • internal/home/links.go +1 −1
  • internal/home/models.go +3 −3
  • internal/home/noscript_test.go +30 −2
  • internal/home/operator_command_linux_test.go +2 −2
  • internal/home/operator_person_test.go +2 −2
  • internal/home/operator_schema_linux_test.go +1 −1
  • internal/home/passkey.go +2 −2
  • internal/home/passkey_test.go +1 −1
  • internal/home/render.go +1 −1
  • internal/home/roster_integration_test.go +1 −1
  • internal/home/roster_pending_integration_test.go +1 −1
  • internal/home/roster_runtime_test.go +1 −1
  • internal/home/runtime.go +3 −3
  • internal/home/schema_commitment_linux_test.go +1 −1
  • internal/home/schema_inventory.go +1 −1
  • internal/home/security_test.go +1 −1
  • internal/home/signin.go +1 −1
  • internal/home/signin_return_factor_test.go +1 −1
  • internal/home/signout.go +1 −1
  • internal/home/static/tokens.css +303 −6
  • internal/home/testapp_test.go +2 −2
  • internal/operator/engine.go +1 −1
  • internal/operator/engine_test.go +2 −2
  • internal/operator/ledger.go +2 −1

CI passed — run details

CI log
amadan: .amadan/timeout: this job's budget is 15m0s (this runner allows up to 30m0s)
=== vet ===
CGO_ENABLED=0 go vet ./...
CGO_ENABLED=0 go vet -tags browser ./internal/home/
cd handoff && CGO_ENABLED=0 go vet ./...
cd roster && CGO_ENABLED=0 go vet ./...
cd connect && CGO_ENABLED=0 go vet ./...
=== fmt ===
=== build ===
CGO_ENABLED=0 go build ./...
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ./cmd/home ./cmd/oficina ./internal/operatorlaunch
cd handoff && CGO_ENABLED=0 go build ./...
cd roster && CGO_ENABLED=0 go build ./...
cd connect && CGO_ENABLED=0 go build ./...
=== go-test ===
CGO_ENABLED=0 go test -count=1 ./...
?   	amadan.net/oficina/home/cmd/home	[no test files]
ok  	amadan.net/oficina/home/cmd/home-placeholder	0.652s
?   	amadan.net/oficina/home/cmd/oficina	[no test files]
ok  	amadan.net/oficina/home/internal/guardstest	0.045s
ok  	amadan.net/oficina/home/internal/home	9.179s
ok  	amadan.net/oficina/home/internal/home/directorydata	0.980s
ok  	amadan.net/oficina/home/internal/home/logtest	0.005s
ok  	amadan.net/oficina/home/internal/home/seal	0.003s
ok  	amadan.net/oficina/home/internal/home/sealtest	0.004s
ok  	amadan.net/oficina/home/internal/operator	5.071s
ok  	amadan.net/oficina/home/internal/operatorlaunch	4.114s
ok  	amadan.net/oficina/home/internal/provisioner	46.003s
cd handoff && CGO_ENABLED=0 go test -count=1 ./...
ok  	amadan.net/oficina/home/handoff	0.313s
ok  	amadan.net/oficina/home/handoff/seal	0.002s
cd roster && CGO_ENABLED=0 go test -count=1 ./...
ok  	amadan.net/oficina/home/roster	5.085s
cd connect && CGO_ENABLED=0 go test -count=1 ./...
ok  	amadan.net/oficina/home/connect	0.112s
ok  	amadan.net/oficina/home/connect/linkstore	0.323s
=== race ===
go test -race -count=1 ./internal/home/ ./internal/operator/ ./internal/operatorlaunch/ ./internal/provisioner/ ./internal/home/directorydata/
ok  	amadan.net/oficina/home/internal/home	101.970s
ok  	amadan.net/oficina/home/internal/operator	64.719s
ok  	amadan.net/oficina/home/internal/operatorlaunch	22.348s
ok  	amadan.net/oficina/home/internal/provisioner	295.160s
ok  	amadan.net/oficina/home/internal/home/directorydata	15.475s
cd handoff && CGO_ENABLED=1 go test -race -count=1 ./...
ok  	amadan.net/oficina/home/handoff	11.230s
ok  	amadan.net/oficina/home/handoff/seal	1.035s
cd roster && CGO_ENABLED=1 go test -race -count=1 ./...
ok  	amadan.net/oficina/home/roster	6.624s
cd connect && CGO_ENABLED=1 go test -race -count=1 ./...
ok  	amadan.net/oficina/home/connect	1.616s
ok  	amadan.net/oficina/home/connect/linkstore	3.711s
diff --git a/AGENTS.md b/AGENTS.md
index 293cab7..94d0e57 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -298,16 +298,29 @@ quietly ignored).
both `ui/tokens.css` and `ui/partials/`** — checking one and not the
other is how the second reason survived a pass that was looking for
exactly this.
-- **`rastrillo doctor` has landed** — in v0.21.0, the first version this
- repo pinned. "Adopt it the day it lands" was a trigger that had already
- fired when it was written. When this app vendors `static/`, run
- `rastrillo doctor --fix` on each upgrade rather than re-copying by hand,
- and add the `TestVendoredAssetsMatchTheLibrary` that `rastrillo new`
- scaffolds as the standing gate — "add", not "keep": this repo was
- hand-written, not scaffolded, so it has no `internal/hometest/` and no
- copy of that test. There is no vendored `static/` in the
- tree today — `internal/home/page.go` links no stylesheet, deliberately —
- so this is an instruction with no object until the first asset arrives.
+- **rastrillo is `amadan.net/rastrillo/rastrillo`** (moved 2026-10-01,
+ pinned at 29e4491, v0.26.0+8 — the version `connect`, `handoff` and
+ `roster` already required). The old path,
+ `github.com/carlosframework/rastrillo`, stops at v0.23.0: code importing
+ it gets no fix, and its own checks cannot tell — Home's sign-in field
+ zoomed iOS on every tap for a month that way (`TestNoZoomOnTap`,
+ `make test-browser`). `internal/guardstest`'s `TestNoPreMoveRastrillo`
+ forbids it in every module here; it stays in go.mod only as estilo's
+ indirect requirement. Re-checked at this pin: `ui/partials/` still has
+ the same 6 utility `class=` occurrences, and nothing in the
+ class-versus-attribute reasoning above moved. The CLI is a go.mod
+ `tool`: run it as `go tool rastrillo …`, never a `rastrillo` from PATH.
+ `make release` stamps `amadan.net/rastrillo/rastrillo.BuildVersion`; the
+ old symbol would leave `/api/version` answering "dev".
+- **`rastrillo doctor`.** `internal/home/static/tokens.css` is vendored,
+ and `TestVendoredAssetsMatchTheLibrary` (noscript_test.go) is the
+ standing gate: run `go tool rastrillo doctor --fix` on every rastrillo
+ upgrade rather than re-copying by hand. **Then delete the scripts it
+ adds** (`static/rastrillo.js`, `select.js`, `datetime.js`,
+ `calendar.js`). Home serves none of them, and the shim doctor adds at
+ this pin still carries rastrillo's old busy rule, which fights estilo's
+ `busy.js` over every submit. `TestNoRastrilloShimBesideBusy` fails if
+ one is left on disk or served.
- **No script by default; script only to enhance, and always prefer
none** (Paul, 2026-09-29, replacing rulings 21/24's closed list of
screens). Every screen works with scripts off — magic-link sign-in,
diff --git a/Makefile b/Makefile
index bcfe109..b3c941b 100644
--- a/Makefile
+++ b/Makefile
@@ -48,7 +48,7 @@ release:
{ echo "make release: no version to stamp; commit, or name it: make release VERSION=v0.1.0"; exit 1; }
@mkdir -p releases
CGO_ENABLED=0 GOOS=$(RELEASE_GOOS) GOARCH=$(RELEASE_GOARCH) go build -trimpath \
- -ldflags "-s -w -X github.com/carlosframework/rastrillo.BuildVersion=$(VERSION)" \
+ -ldflags "-s -w -X amadan.net/rastrillo/rastrillo.BuildVersion=$(VERSION)" \
-o $(RELEASE_BIN) ./cmd/$(APP)
@echo "built $(RELEASE_BIN) reporting version $(VERSION)"
@echo "publish it with:"
diff --git a/cmd/home-placeholder/README.md b/cmd/home-placeholder/README.md
index 7a41754..305e6c1 100644
--- a/cmd/home-placeholder/README.md
+++ b/cmd/home-placeholder/README.md
@@ -11,11 +11,11 @@ identity/domain migration have been planned and accepted. The old skeleton's
Litestream-only database cannot be adopted by the current identity migrations.
Stamp the release with the source commit in
-`github.com/carlosframework/rastrillo.BuildVersion`, as for the main Home binary.
+`amadan.net/rastrillo/rastrillo.BuildVersion`, as for the main Home binary.
```sh
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath \
- -ldflags "-s -w -X github.com/carlosframework/rastrillo.BuildVersion=$(git rev-parse --short HEAD)" \
+ -ldflags "-s -w -X amadan.net/rastrillo/rastrillo.BuildVersion=$(git rev-parse --short HEAD)" \
-o /tmp/home-placeholder ./cmd/home-placeholder
```
diff --git a/cmd/home-placeholder/main.go b/cmd/home-placeholder/main.go
index 570421e..07a60e2 100644
--- a/cmd/home-placeholder/main.go
+++ b/cmd/home-placeholder/main.go
@@ -9,7 +9,7 @@ import (
"os"
"amadan.net/oficina/home/internal/home"
- "github.com/carlosframework/rastrillo"
+ "amadan.net/rastrillo/rastrillo"
)
func main() {
diff --git a/cmd/home/main.go b/cmd/home/main.go
index e74c411..ed7948e 100644
--- a/cmd/home/main.go
+++ b/cmd/home/main.go
@@ -42,9 +42,9 @@ import (
"net/http"
"os"
- "github.com/carlosframework/rastrillo"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/home/internal/home"
)
diff --git a/go.mod b/go.mod
index 68b8066..dab5a0a 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,6 @@ require (
amadan.net/oficina/home/roster v0.0.0-20260908123429-74dda570e0cf
amadan.net/rastrillo/rastrillo v0.26.1-0.20260908075707-29e4491631bd
filippo.io/age v1.3.2
- github.com/carlosframework/rastrillo v0.23.0
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327
github.com/chromedp/chromedp v0.14.2
github.com/go-chi/chi/v5 v5.3.2
@@ -24,6 +23,8 @@ require (
)
require (
+ github.com/BurntSushi/toml v1.6.0 // indirect
+ github.com/carlosframework/rastrillo v0.23.0 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
@@ -47,3 +48,5 @@ require (
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
+
+tool amadan.net/rastrillo/rastrillo/cmd/rastrillo
diff --git a/go.sum b/go.sum
index d6d482a..253b264 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ filippo.io/age v1.3.2 h1:r6RSZLFSMm6rzKepZ7ZAYkKCu14f3/Me8c7uKYh7C8c=
filippo.io/age v1.3.2/go.mod h1:TH/Yr2sSRhCKbaH4XPxpUV0Us8Gv6txYUpiZQWz8Evk=
filippo.io/hpke v0.4.0 h1:p575VVQ6ted4pL+it6M00V/f2qTZITO0zgmdKCkd5+A=
filippo.io/hpke v0.4.0/go.mod h1:EmAN849/P3qdeK+PCMkDpDm83vRHM5cDipBJ8xbQLVY=
+github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
+github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/carlosframework/rastrillo v0.23.0 h1:tKAAlwPt4Pg/rkqk7o6jvV12bbZ0r34oEVpuOlKfX7w=
github.com/carlosframework/rastrillo v0.23.0/go.mod h1:pZlrE5F5OhspvZFzef0DrfjHAjA8FXycb9J5/8vc8Tw=
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 h1:UQ4AU+BGti3Sy/aLU8KVseYKNALcX9UXY6DfpwQ6J8E=
diff --git a/internal/guardstest/premove_test.go b/internal/guardstest/premove_test.go
new file mode 100644
index 0000000..12a9ea0
--- /dev/null
+++ b/internal/guardstest/premove_test.go
@@ -0,0 +1,29 @@
+package guards
+
+import (
+ "strings"
+ "testing"
+)
+
+// preMoveRastrillo is rastrillo's module path before it moved to
+// amadan.net/rastrillo/rastrillo (2026-08-31). Nothing after v0.23.0 was
+// released under it, so code importing it gets no rastrillo fix — which
+// is how Home's sign-in field kept zooming iOS on every tap for a month
+// after rastrillo fixed it (polish audit r3, item 1).
+//
+// estilo still imports it (chrome's SafeReturn), so it stays in go.mod as
+// an indirect requirement until estilo moves. Home's own code never may.
+const preMoveRastrillo = "github.com/carlosframework/rastrillo"
+
+// TestNoPreMoveRastrillo fails on any import of rastrillo's old module
+// path, in any of Home's modules.
+func TestNoPreMoveRastrillo(t *testing.T) {
+ root := repoRoot(t)
+ for _, path := range goFiles(t, root) {
+ for _, imp := range fileImports(t, path) {
+ if imp == preMoveRastrillo || strings.HasPrefix(imp, preMoveRastrillo+"/") {
+ t.Errorf("%s: imports %q, rastrillo's frozen pre-move path; use amadan.net/rastrillo/rastrillo", relPath(t, root, path), imp)
+ }
+ }
+ }
+}
diff --git a/internal/home/app.go b/internal/home/app.go
index bd36888..3d8c01f 100644
--- a/internal/home/app.go
+++ b/internal/home/app.go
@@ -24,10 +24,10 @@ import (
"amadan.net/oficina/estilo.git/theme"
"amadan.net/oficina/home/handoff"
- "github.com/carlosframework/rastrillo/csrf"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/passkey"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/passkey"
+ "amadan.net/rastrillo/rastrillo/sessions"
"github.com/go-chi/chi/v5"
"github.com/keymaildev/signin"
)
diff --git a/internal/home/compatibility_linux.go b/internal/home/compatibility_linux.go
index 956c96f..4a2892d 100644
--- a/internal/home/compatibility_linux.go
+++ b/internal/home/compatibility_linux.go
@@ -19,7 +19,7 @@ import (
"amadan.net/oficina/home/internal/home/directorydata"
"amadan.net/oficina/home/internal/home/seal"
"amadan.net/oficina/home/internal/operator"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
// This component has no command or serving entry point. Only the future verified
diff --git a/internal/home/compatibility_linux_test.go b/internal/home/compatibility_linux_test.go
index 51b011a..084163c 100644
--- a/internal/home/compatibility_linux_test.go
+++ b/internal/home/compatibility_linux_test.go
@@ -19,7 +19,7 @@ import (
"amadan.net/oficina/home/internal/home/seal"
"amadan.net/oficina/home/internal/operator"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
"golang.org/x/sys/unix"
)
diff --git a/internal/home/credits/notices.json b/internal/home/credits/notices.json
index eefb54c..f86edb6 100644
--- a/internal/home/credits/notices.json
+++ b/internal/home/credits/notices.json
@@ -52,6 +52,10 @@
{
"Name": "LICENSE",
"Text": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n means each individual or legal entity that creates, contributes to\n the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n means the combination of the Contributions of others (if any) used\n by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n means Source Code Form to which the initial Contributor has attached\n the notice in Exhibit A, the Executable Form of such Source Code\n Form, and Modifications of such Source Code Form, in each case\n including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n means\n\n (a) that the initial Contributor has attached the notice described\n in Exhibit B to the Covered Software; or\n\n (b) that the Covered Software was made available under the terms of\n version 1.1 or earlier of the License, but not also under the\n terms of a Secondary License.\n\n1.6. \"Executable Form\"\n means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n means a work that combines Covered Software with other material, in\n a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n means this document.\n\n1.9. \"Licensable\"\n means having the right to grant, to the maximum extent possible,\n whether at the time of the initial grant or subsequently, any and\n all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n means any of the following:\n\n (a) any file in Source Code Form that results from an addition to,\n deletion from, or modification of the contents of Covered\n Software; or\n\n (b) any new file in Source Code Form that contains any Covered\n Software.\n\n1.11. \"Patent Claims\" of a Contributor\n means any patent claim(s), including without limitation, method,\n process, and apparatus claims, in any patent Licensable by such\n Contributor that would be infringed, but for the grant of the\n License, by the making, using, selling, offering for sale, having\n made, import, or transfer of either its Contributions or its\n Contributor Version.\n\n1.12. \"Secondary License\"\n means either the GNU General Public License, Version 2.0, the GNU\n Lesser General Public License, Version 2.1, the GNU Affero General\n Public License, Version 3.0, or any later versions of those\n licenses.\n\n1.13. \"Source Code Form\"\n means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n means an individual or a legal entity exercising rights under this\n License. For legal entities, \"You\" includes any entity that\n controls, is controlled by, or is under common control with You. For\n purposes of this definition, \"control\" means (a) the power, direct\n or indirect, to cause the direction or management of such entity,\n whether by contract or otherwise, or (b) ownership of more than\n fifty percent (50%) of the outstanding shares or beneficial\n ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or\n as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n for sale, have made, import, and otherwise transfer either its\n Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n or\n\n(b) for infringements caused by: (i) Your and any other third party's\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n Form, as described in Section 3.1, and You must inform recipients of\n the Executable Form how they can obtain a copy of such Source Code\n Form by reasonable means in a timely manner, at a charge no more\n than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n License, or sublicense it under different terms, provided that the\n license for the Executable Form does not attempt to limit or alter\n the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n* *\n* 6. Disclaimer of Warranty *\n* ------------------------- *\n* *\n* Covered Software is provided under this License on an \"as is\" *\n* basis, without warranty of any kind, either expressed, implied, or *\n* statutory, including, without limitation, warranties that the *\n* Covered Software is free of defects, merchantable, fit for a *\n* particular purpose or non-infringing. The entire risk as to the *\n* quality and performance of the Covered Software is with You. *\n* Should any Covered Software prove defective in any respect, You *\n* (not any Contributor) assume the cost of any necessary servicing, *\n* repair, or correction. This disclaimer of warranty constitutes an *\n* essential part of this License. No use of any Covered Software is *\n* authorized under this License except under this disclaimer. *\n* *\n************************************************************************\n\n************************************************************************\n* *\n* 7. Limitation of Liability *\n* -------------------------- *\n* *\n* Under no circumstances and under no legal theory, whether tort *\n* (including negligence), contract, or otherwise, shall any *\n* Contributor, or anyone who distributes Covered Software as *\n* permitted above, be liable to You for any direct, indirect, *\n* special, incidental, or consequential damages of any character *\n* including, without limitation, damages for lost profits, loss of *\n* goodwill, work stoppage, computer failure or malfunction, or any *\n* and all other commercial damages or losses, even if such party *\n* shall have been informed of the possibility of such damages. This *\n* limitation of liability shall not apply to liability for death or *\n* personal injury resulting from such party's negligence to the *\n* extent applicable law prohibits such limitation. Some *\n* jurisdictions do not allow the exclusion or limitation of *\n* incidental or consequential damages, so this exclusion and *\n* limitation may not apply to You. *\n* *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n This Source Code Form is subject to the terms of the Mozilla Public\n License, v. 2.0. If a copy of the MPL was not distributed with this\n file, You can obtain one at https://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n This Source Code Form is \"Incompatible With Secondary Licenses\", as\n defined by the Mozilla Public License, v. 2.0.\n"
+ },
+ {
+ "Name": "gormlite/LICENSE",
+ "Text": "The MIT License (MIT)\n\nCopyright (c) 2013-NOW Jinzhu \u003cwosmvp@gmail.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
}
]
},
diff --git a/internal/home/directory.go b/internal/home/directory.go
index c2c5a0d..fad60da 100644
--- a/internal/home/directory.go
+++ b/internal/home/directory.go
@@ -10,9 +10,9 @@ import (
"amadan.net/oficina/estilo.git/theme"
"amadan.net/oficina/home/handoff"
"amadan.net/rastrillo/rastrillo/assertion"
- "github.com/carlosframework/rastrillo/csrf"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/sessions"
"github.com/go-chi/chi/v5"
)
diff --git a/internal/home/directorydata/operator_schema.go b/internal/home/directorydata/operator_schema.go
index 357ecae..b7e6b14 100644
--- a/internal/home/directorydata/operator_schema.go
+++ b/internal/home/directorydata/operator_schema.go
@@ -4,7 +4,7 @@ import (
"embed"
"io/fs"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
//go:embed operator_migrations
diff --git a/internal/home/directorydata/roster.go b/internal/home/directorydata/roster.go
index 70af8dd..ec86b9f 100644
--- a/internal/home/directorydata/roster.go
+++ b/internal/home/directorydata/roster.go
@@ -11,7 +11,7 @@ import (
"time"
"amadan.net/oficina/home/roster"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
"github.com/go-json-experiment/json"
)
diff --git a/internal/home/directorydata/roster_test.go b/internal/home/directorydata/roster_test.go
index 51e8074..fb36b37 100644
--- a/internal/home/directorydata/roster_test.go
+++ b/internal/home/directorydata/roster_test.go
@@ -14,7 +14,7 @@ import (
"time"
"amadan.net/oficina/home/internal/home/sealtest"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
"github.com/go-json-experiment/json"
)
diff --git a/internal/home/directorydata/store.go b/internal/home/directorydata/store.go
index e32af2d..f36b86c 100644
--- a/internal/home/directorydata/store.go
+++ b/internal/home/directorydata/store.go
@@ -13,7 +13,7 @@ import (
"unicode"
"unicode/utf8"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
//go:embed migrations/*.sql
diff --git a/internal/home/directorydata/store_test.go b/internal/home/directorydata/store_test.go
index c84b7bb..74ebdca 100644
--- a/internal/home/directorydata/store_test.go
+++ b/internal/home/directorydata/store_test.go
@@ -11,8 +11,8 @@ import (
"amadan.net/oficina/home/internal/home/seal"
"amadan.net/oficina/home/internal/home/sealtest"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
const personA = "pr_aaaaaaaaaaaaaaaaaaaaaaaaaa"
diff --git a/internal/home/docs_chooser.go b/internal/home/docs_chooser.go
index 06672bd..828baa7 100644
--- a/internal/home/docs_chooser.go
+++ b/internal/home/docs_chooser.go
@@ -10,8 +10,8 @@ import (
"amadan.net/oficina/home/handoff"
"amadan.net/oficina/home/internal/home/directorydata"
- "github.com/carlosframework/rastrillo/csrf"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
const docsEntryPath = "/apps/docs"
diff --git a/internal/home/docs_chooser_test.go b/internal/home/docs_chooser_test.go
index b1509bf..1882167 100644
--- a/internal/home/docs_chooser_test.go
+++ b/internal/home/docs_chooser_test.go
@@ -11,8 +11,8 @@ import (
"amadan.net/oficina/home/handoff"
"amadan.net/oficina/home/internal/home/directorydata"
- "github.com/carlosframework/rastrillo/migrate"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
const chooserPerson = "pr_aaaaaaaaaaaaaaaaaaaaaaaaaa"
diff --git a/internal/home/exchange.go b/internal/home/exchange.go
index 6b950e9..8de9f78 100644
--- a/internal/home/exchange.go
+++ b/internal/home/exchange.go
@@ -8,7 +8,7 @@ import (
"amadan.net/oficina/home/handoff"
"amadan.net/rastrillo/rastrillo/assertion"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
json "github.com/go-json-experiment/json"
)
diff --git a/internal/home/exchange_test.go b/internal/home/exchange_test.go
index f20cf79..2cfe33f 100644
--- a/internal/home/exchange_test.go
+++ b/internal/home/exchange_test.go
@@ -23,8 +23,8 @@ import (
"amadan.net/oficina/home/internal/home/sealtest"
"amadan.net/rastrillo/rastrillo/assertion"
assertioncrypto "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
type exchangePair struct {
diff --git a/internal/home/keys.go b/internal/home/keys.go
index e810963..927b0e1 100644
--- a/internal/home/keys.go
+++ b/internal/home/keys.go
@@ -9,7 +9,7 @@ import (
"os"
"strings"
- "github.com/carlosframework/rastrillo/mail"
+ "amadan.net/rastrillo/rastrillo/mail"
"amadan.net/oficina/home/internal/home/seal"
)
diff --git a/internal/home/legacy_schema_diagnostic.go b/internal/home/legacy_schema_diagnostic.go
index 31ebc49..08ad742 100644
--- a/internal/home/legacy_schema_diagnostic.go
+++ b/internal/home/legacy_schema_diagnostic.go
@@ -8,7 +8,7 @@ import (
"encoding/json"
"log/slog"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
const (
diff --git a/internal/home/legacy_schema_diagnostic_test.go b/internal/home/legacy_schema_diagnostic_test.go
index f0e27a7..4e61072 100644
--- a/internal/home/legacy_schema_diagnostic_test.go
+++ b/internal/home/legacy_schema_diagnostic_test.go
@@ -20,8 +20,8 @@ import (
"amadan.net/oficina/home/internal/home/sealtest"
"amadan.net/oficina/home/internal/operator"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func legacyDiagnosticFixture(t *testing.T, historical, replication bool) *db.DB {
diff --git a/internal/home/links.go b/internal/home/links.go
index 48d300e..62c48ba 100644
--- a/internal/home/links.go
+++ b/internal/home/links.go
@@ -11,7 +11,7 @@ import (
"strings"
"time"
- "github.com/carlosframework/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/db"
"amadan.net/oficina/home/internal/home/seal"
)
diff --git a/internal/home/models.go b/internal/home/models.go
index cd6f085..803e86b 100644
--- a/internal/home/models.go
+++ b/internal/home/models.go
@@ -3,9 +3,9 @@ package home
import (
"embed"
- "github.com/carlosframework/rastrillo/migrate"
- "github.com/carlosframework/rastrillo/passkey"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/passkey"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
//go:embed migrations/*.sql
diff --git a/internal/home/noscript_test.go b/internal/home/noscript_test.go
index e6b3e80..932ec12 100644
--- a/internal/home/noscript_test.go
+++ b/internal/home/noscript_test.go
@@ -15,8 +15,8 @@ import (
"testing"
"amadan.net/oficina/estilo.git/theme"
- "github.com/carlosframework/rastrillo"
- "github.com/carlosframework/rastrillo/ui"
+ "amadan.net/rastrillo/rastrillo"
+ "amadan.net/rastrillo/rastrillo/ui"
"github.com/go-chi/chi/v5"
)
@@ -420,6 +420,34 @@ func TestVendoredAssetsMatchTheLibrary(t *testing.T) {
}
}
+// rastrilloScripts are the scripts `rastrillo doctor --fix` writes into
+// static/ beside tokens.css. Home uses none of them. rastrillo.js at this
+// pin is the combined shim with rastrillo's old busy rule inside, and
+// Home serves estilo's busy.js; the two rules on one page fight over the
+// same submit (each holds it, then re-submits). So after a doctor run they
+// are deleted, and this fails if one is left on disk or served.
+var rastrilloScripts = []string{"rastrillo.js", "select.js", "datetime.js", "calendar.js"}
+
+func TestNoRastrilloShimBesideBusy(t *testing.T) {
+ for _, name := range rastrilloScripts {
+ if _, err := os.Stat(filepath.Join("static", name)); err == nil {
+ t.Errorf("static/%s is on disk: `rastrillo doctor --fix` adds it, and Home serves estilo's busy.js instead; delete it", name)
+ }
+ }
+ app := newTestApp(t)
+ for _, host := range []string{directoryHost, credentialHost} {
+ for _, name := range rastrilloScripts {
+ req := httptest.NewRequest(http.MethodGet, "/static/"+name, nil)
+ req.Host = host
+ rec := httptest.NewRecorder()
+ app.Router().ServeHTTP(rec, req)
+ if rec.Code != http.StatusNotFound {
+ t.Errorf("%s /static/%s: %d, want 404 (Home serves no rastrillo script)", host, name, rec.Code)
+ }
+ }
+ }
+}
+
// No handler in this package may set its own Content-Security-Policy.
//
// rastrillo's securityHeaders sets the default on every response, and a
diff --git a/internal/home/operator_command_linux_test.go b/internal/home/operator_command_linux_test.go
index b1f527e..7e61e95 100644
--- a/internal/home/operator_command_linux_test.go
+++ b/internal/home/operator_command_linux_test.go
@@ -22,8 +22,8 @@ import (
"amadan.net/carlos/platform.git/launchctx"
"amadan.net/oficina/home/internal/operator"
family "amadan.net/rastrillo/rastrillo/crypto"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"golang.org/x/sys/unix"
)
diff --git a/internal/home/operator_person_test.go b/internal/home/operator_person_test.go
index e97d63a..61e1780 100644
--- a/internal/home/operator_person_test.go
+++ b/internal/home/operator_person_test.go
@@ -17,8 +17,8 @@ import (
"amadan.net/oficina/home/internal/operator"
"amadan.net/oficina/home/roster"
family "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"github.com/go-json-experiment/json"
)
diff --git a/internal/home/operator_schema_linux_test.go b/internal/home/operator_schema_linux_test.go
index 3a3520b..a9a39a7 100644
--- a/internal/home/operator_schema_linux_test.go
+++ b/internal/home/operator_schema_linux_test.go
@@ -4,7 +4,7 @@ package home
import (
"amadan.net/oficina/home/internal/operator"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
"testing"
)
diff --git a/internal/home/passkey.go b/internal/home/passkey.go
index b351c1b..1a026ad 100644
--- a/internal/home/passkey.go
+++ b/internal/home/passkey.go
@@ -6,8 +6,8 @@ import (
"net/http"
"time"
- "github.com/carlosframework/rastrillo/passkey"
- "github.com/carlosframework/rastrillo/webauthn"
+ "amadan.net/rastrillo/rastrillo/passkey"
+ "amadan.net/rastrillo/rastrillo/webauthn"
)
//go:embed static/passkey.js static/tokens.css static/assertion.js
diff --git a/internal/home/passkey_test.go b/internal/home/passkey_test.go
index 7bc24a7..eaf6edf 100644
--- a/internal/home/passkey_test.go
+++ b/internal/home/passkey_test.go
@@ -10,7 +10,7 @@ import (
"testing"
"time"
- "github.com/carlosframework/rastrillo/webauthn/authtest"
+ "amadan.net/rastrillo/rastrillo/webauthn/authtest"
)
// signInFully takes a person all the way to a full session and returns
diff --git a/internal/home/render.go b/internal/home/render.go
index 6083f10..0a6fac2 100644
--- a/internal/home/render.go
+++ b/internal/home/render.go
@@ -11,7 +11,7 @@ import (
"amadan.net/oficina/estilo.git/credits"
"amadan.net/oficina/estilo.git/sky"
- "github.com/carlosframework/rastrillo/ui"
+ "amadan.net/rastrillo/rastrillo/ui"
)
//go:embed templates/*.html
diff --git a/internal/home/roster_integration_test.go b/internal/home/roster_integration_test.go
index e4711d2..2d737fa 100644
--- a/internal/home/roster_integration_test.go
+++ b/internal/home/roster_integration_test.go
@@ -20,8 +20,8 @@ import (
"amadan.net/oficina/home/internal/home/sealtest"
"amadan.net/oficina/home/roster"
+ "amadan.net/rastrillo/rastrillo"
family "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo"
"github.com/go-json-experiment/json"
)
diff --git a/internal/home/roster_pending_integration_test.go b/internal/home/roster_pending_integration_test.go
index dcbccdd..576077c 100644
--- a/internal/home/roster_pending_integration_test.go
+++ b/internal/home/roster_pending_integration_test.go
@@ -9,7 +9,7 @@ import (
"amadan.net/oficina/home/internal/home/directorydata"
"amadan.net/oficina/home/internal/home/sealtest"
"amadan.net/oficina/home/roster"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func TestPendingRosterActualSignedHTTPAndLeaseCeiling(t *testing.T) {
diff --git a/internal/home/roster_runtime_test.go b/internal/home/roster_runtime_test.go
index 682d20a..086fe80 100644
--- a/internal/home/roster_runtime_test.go
+++ b/internal/home/roster_runtime_test.go
@@ -9,7 +9,7 @@ import (
"testing"
family "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func rosterPrivate(t *testing.T) (*family.Keypair, string) {
diff --git a/internal/home/runtime.go b/internal/home/runtime.go
index 503709a..7c0d792 100644
--- a/internal/home/runtime.go
+++ b/internal/home/runtime.go
@@ -14,9 +14,9 @@ import (
"amadan.net/oficina/home/internal/operator"
"amadan.net/rastrillo/rastrillo/assertion"
assertioncrypto "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/sessions"
json "github.com/go-json-experiment/json"
)
diff --git a/internal/home/schema_commitment_linux_test.go b/internal/home/schema_commitment_linux_test.go
index a726249..56064b2 100644
--- a/internal/home/schema_commitment_linux_test.go
+++ b/internal/home/schema_commitment_linux_test.go
@@ -19,7 +19,7 @@ import (
"strings"
"testing"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func TestSchemaCommitmentFrozenCatalog(t *testing.T) {
diff --git a/internal/home/schema_inventory.go b/internal/home/schema_inventory.go
index 941513e..8d0dada 100644
--- a/internal/home/schema_inventory.go
+++ b/internal/home/schema_inventory.go
@@ -7,7 +7,7 @@ import (
"sort"
"time"
- "github.com/carlosframework/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/db"
)
// LogSchemaInventory reports only compiled migration names and counts. Unknown
diff --git a/internal/home/security_test.go b/internal/home/security_test.go
index e166f32..db96f98 100644
--- a/internal/home/security_test.go
+++ b/internal/home/security_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/carlosframework/rastrillo"
+ "amadan.net/rastrillo/rastrillo"
)
func TestSecurityPolicyPreservesFrameworkDefaults(t *testing.T) {
diff --git a/internal/home/signin.go b/internal/home/signin.go
index 1888483..806797f 100644
--- a/internal/home/signin.go
+++ b/internal/home/signin.go
@@ -8,7 +8,7 @@ import (
"time"
"amadan.net/oficina/estilo.git/chrome"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
"github.com/keymaildev/signin"
)
diff --git a/internal/home/signin_return_factor_test.go b/internal/home/signin_return_factor_test.go
index c0f44ff..cf3ba27 100644
--- a/internal/home/signin_return_factor_test.go
+++ b/internal/home/signin_return_factor_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/carlosframework/rastrillo/webauthn/authtest"
+ "amadan.net/rastrillo/rastrillo/webauthn/authtest"
)
// Mutation-checked 2026-09-07: bypassing Gate or passing the original
diff --git a/internal/home/signout.go b/internal/home/signout.go
index 63bf16c..246e22f 100644
--- a/internal/home/signout.go
+++ b/internal/home/signout.go
@@ -5,7 +5,7 @@ import (
"net/url"
"strings"
- "github.com/carlosframework/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/csrf"
)
// signoutPath is the same path on the credential origin, the directory
diff --git a/internal/home/static/tokens.css b/internal/home/static/tokens.css
index 16a8809..10f6da5 100644
--- a/internal/home/static/tokens.css
+++ b/internal/home/static/tokens.css
@@ -62,8 +62,10 @@
Padding values are load-bearing for SC 2.5.8 Target Size (AA, new in
WCAG 2.2): pagination chips measure about 30px, row action pills
- about 27px and buttons about 34px on their smaller axis, all clear of
- the 24px minimum. Do not shrink them without re-measuring.
+ about 27px, and the button sizes about 28px (sm), 34px (default) and
+ 44px (lg) on their smaller axis, all clear of the 24px minimum. Do
+ not shrink them without re-measuring; the button block shows the
+ arithmetic.
Type sizes are rem, not px, so the whole scale tracks a reader who has
raised their browser's default font size. Spacing is rem for the same
@@ -73,6 +75,7 @@
/* ── Scale: type and spacing. Theme-independent. Radius is not here —
it is part of the theme's shape axis; see themes/. ────────────── */
:root {
+ --rst-fs-lg: 1.0625rem; /* 17px — the one step above base */
--rst-fs-base: 0.875rem; /* 14px at the browser default */
--rst-fs-sm: 0.78125rem; /* 12.5px */
--rst-fs-xs: 0.71875rem; /* 11.5px */
@@ -244,6 +247,56 @@ body {
filter: brightness(0.9);
}
+/* ── Button sizes ─────────────────────────────────────────────────────
+ Three steps, and they are a size scale rather than a set of variants:
+ size composes with primary/ghost/danger, so `rst-btn="primary lg"` is
+ the ordinary spelling of a form's submit.
+
+ The default step is the one the page-header action and the row pill
+ want — small, dense, a control beside other controls. It was the ONLY
+ step for a long time, and that is how a form's submit ended up
+ wearing it: a 34px, 12.5px-labelled button stretched across a 44rem
+ column, which reads as a skinny bar rather than the thing the whole
+ screen is asking you to press. A CTA is not a toolbar button; give it
+ `lg`.
+
+ Measured on the smaller axis, against SC 2.5.8's 24px floor — padding
+ both sides, plus the label's line box, plus the 1px border top and
+ bottom (the border is why the default step is 34px and not 32px). The
+ header comment carries these too; keep the two in step:
+ sm 0.3rem × 2 + 11.5px × 1.4 + 2 = 9.6 + 16.1 + 2 ≈ 28px
+ default 0.45rem × 2 + 12.5px × 1.4 + 2 = 14.4 + 17.5 + 2 ≈ 34px
+ lg 0.7rem × 2 + 14px × 1.4 + 2 = 22.4 + 19.6 + 2 ≈ 44px
+ sm is the tightest thing in the file that is still a button. It is
+ for a dense row of them, not for making an ordinary button smaller,
+ and there is deliberately nothing below it. */
+.rst-btn--sm, [rst-btn~="sm"] {
+ font-size: var(--rst-fs-xs);
+ padding: 0.3rem 0.55rem;
+}
+.rst-btn--lg, [rst-btn~="lg"] {
+ font-size: var(--rst-fs-base);
+ padding: 0.7rem 1.15rem;
+}
+
+/* block — a button that fills its container, for the one-action form
+ (sign in, sign up, a confirm page) where the submit IS the screen.
+ It centres its own label: .rst-btn sets no justify-content, so a
+ stretched button's text sits at the row's flex-start and reads as a
+ mistake rather than a choice.
+
+ Pair it with lg. A block button at the default size is precisely the
+ skinny bar described above — the width comes from the container and
+ the height does not follow, so the ratio goes wrong in proportion to
+ how wide the column is. Nothing here enforces that pairing, because a
+ narrow container is a legitimate place for a block button at the
+ default size; the wide ones are where it fails. */
+.rst-btn--block, [rst-btn~="block"] {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+}
+
/* busy — the loading state rastrillo.js gives every submit button on
its way out, and the one state of a button that is not a variant:
any .rst-btn can wear it. The spinner is a real child element
@@ -656,7 +709,7 @@ body {
document outline, not a paragraph dressed up as one. */
.rst-empty__title, [rst-empty-title] {
color: var(--rst-text);
- font-size: 1.0625rem;
+ font-size: var(--rst-fs-lg);
font-weight: 600;
margin: 0 0 var(--rst-sp-2);
}
@@ -733,12 +786,132 @@ body {
.rst-badge--negative, [rst-badge~="negative"] { background: var(--rst-tone-negative-bg); border-color: var(--rst-tone-negative-fg); color: var(--rst-tone-negative-fg); }
.rst-badge--neutral, [rst-badge~="neutral"] { background: var(--rst-tone-neutral-bg); border-color: var(--rst-tone-neutral-fg); color: var(--rst-tone-neutral-fg); }
-/* meter — 4px capacity bar; the number rides beside it as text. */
+/* meter — 4px capacity bar; the number rides beside it as text.
+
+ The bar is a native <meter> (spec §6-v2.4), and styling one is the
+ one place in this file where the same declaration has to be written
+ three times: once on the element, once for the WebKit/Blink
+ pseudo-elements, once for the Firefox one. They cannot share a rule.
+ A selector list containing a pseudo-element an engine does not know
+ is invalid AS A WHOLE in that engine, so ::-webkit-meter-bar and
+ ::-moz-meter-bar in one comma-separated rule would style nothing
+ anywhere. That is why the repetition below is not tidied up.
+
+ The two engines also disagree about which pseudo-element is which.
+ In WebKit/Blink ::-webkit-meter-bar is the TRACK and
+ ::-webkit-meter-optimum-value is the FILL; in Firefox the element
+ itself is the track and ::-moz-meter-bar is the FILL. Read the three
+ blocks with that in mind or they look contradictory.
+
+ HONESTLY FLAGGED: the -moz- rule is unverified. This project's
+ browser drive is Chromium, so the WebKit/Blink path below is measured
+ and the Firefox path is written from the spec and reasoned about. It
+ was shipped that way knowingly (Paul's call). If a Firefox drive ever
+ lands, this is the first rule to point it at.
+
+ The old markup was a <span> with an <i> in it sized by
+ --rst-meter-fill. That custom property is gone; an app that set it is
+ setting nothing now, which is why it is called out in the changelog
+ rather than only here. */
.rst-meter, [rst-meter] { align-items: center; color: var(--rst-text-muted); display: inline-flex; font-size: var(--rst-fs-xs); gap: var(--rst-sp-2); }
-.rst-meter__bar, [rst-meter-bar] { background: var(--rst-accent-soft); border-radius: 2px; flex: 1; height: 4px; min-width: 34px; overflow: hidden; }
-.rst-meter__bar i, [rst-meter-bar] i { background: var(--rst-accent); border-radius: 2px; display: block; height: 100%; width: var(--rst-meter-fill, 0%); }
+.rst-meter__bar, [rst-meter-bar] { appearance: none; background: var(--rst-accent-soft); block-size: 4px; border: 0; border-radius: 2px; flex: 1; min-inline-size: 34px; }
+.rst-meter__bar::-webkit-meter-inner-element, [rst-meter-bar]::-webkit-meter-inner-element { block-size: 100%; }
+.rst-meter__bar::-webkit-meter-bar, [rst-meter-bar]::-webkit-meter-bar { background: var(--rst-accent-soft); block-size: 100%; border: 0; border-radius: 2px; }
+.rst-meter__bar::-webkit-meter-optimum-value, [rst-meter-bar]::-webkit-meter-optimum-value { background: var(--rst-accent); border-radius: 2px; }
+.rst-meter__bar::-moz-meter-bar, [rst-meter-bar]::-moz-meter-bar { background: var(--rst-accent); border-radius: 2px; }
.rst-meter__num, [rst-meter-num] { font-variant-numeric: tabular-nums; white-space: nowrap; }
+/* stats — the instrument strip a dashboard or a report opens with: a
+ lead reading at headline size, companion readings beside it, divided
+ by hairlines inside one card.
+
+ One band, one cell, one lead variant. The headline stat and the
+ counts next to it are the same component at two sizes (spec
+ §6-v2.4), so there is no second kind to keep in step with this one.
+
+ flex-wrap and a flex-basis rather than a grid with a column count.
+ Any number of cells has to work — three on one dashboard, five on
+ the next — and a grid would need the caller to say how many. The
+ basis is what decides when the strip becomes two rows, and the lead
+ cell's is larger so it keeps the line to itself when the others
+ wrap under it.
+
+ The hairline is border-inline-start on every cell but the first,
+ which is what makes the strip read as ONE instrument rather than as
+ a row of cards. Logical, so it lands on the right in Arabic. A
+ wrapped cell keeps its line, and that is the one visual compromise
+ here: at two rows the first cell of the second row draws a leading
+ hairline against the card's edge. It is a hairline, and the
+ alternative — :nth-child arithmetic against a column count nobody
+ declared — is the grid this deliberately is not. */
+.rst-stats, [rst-stats] {
+ background: var(--rst-surface);
+ border: 1px solid var(--rst-line);
+ border-radius: var(--rst-radius);
+ display: flex;
+ flex-wrap: wrap;
+}
+.rst-stat, [rst-stat] {
+ border-inline-start: 1px solid var(--rst-line);
+ display: flex;
+ flex: 1 1 9rem;
+ flex-direction: column;
+ gap: 0.15rem;
+ min-inline-size: 0;
+ padding: var(--rst-sp-4);
+}
+.rst-stat:first-child, [rst-stat]:first-child {
+ border-inline-start: 0;
+}
+.rst-stat--lead, [rst-stat~="lead"] {
+ flex-basis: 14rem;
+}
+/* The eyebrow. Uppercase and tracked, the same grammar every label in
+ this system uses above a value, so a band of cells reads as one row
+ of labels rather than as four headings. */
+.rst-stat__label, [rst-stat-label] {
+ color: var(--rst-text-muted);
+ font-size: var(--rst-fs-xs);
+ font-weight: 650;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+}
+/* tabular-nums so a column of readings lines up on its digits, and so
+ a number that changes on a poll does not jitter its neighbours. */
+.rst-stat__num, [rst-stat-num] {
+ font-size: 1.5rem;
+ font-variant-numeric: tabular-nums;
+ font-weight: 650;
+ line-height: 1.1;
+}
+.rst-stat--lead .rst-stat__num, [rst-stat~="lead"] [rst-stat-num] {
+ font-size: 2.1rem;
+}
+/* The delta is TEXT in a colour, not a colour. Its sign is written by
+ the caller and is the signal a reader who cannot tell the two hues
+ apart is reading; the colour is the second one (WCAG 2.2 AA 1.4.1).
+ Both hues are held at 4.5:1 against this card by the contrast gate
+ in the same commit that added them — they are text, so the floor
+ applies whether or not the colour carries meaning of its own. */
+.rst-stat__delta, [rst-stat-delta] {
+ font-size: var(--rst-fs-sm);
+ font-variant-numeric: tabular-nums;
+ font-weight: 600;
+}
+.rst-stat__delta[data-tone="positive"], [rst-stat-delta][rst-tone~="positive"] {
+ color: var(--rst-tone-positive-fg);
+}
+.rst-stat__delta[data-tone="negative"], [rst-stat-delta][rst-tone~="negative"] {
+ color: var(--rst-tone-negative-fg);
+}
+.rst-stat__delta[data-tone="neutral"], [rst-stat-delta][rst-tone~="neutral"] {
+ color: var(--rst-text-muted);
+}
+.rst-stat__note, [rst-stat-note] {
+ color: var(--rst-text-faint);
+ font-size: var(--rst-fs-xs);
+}
+
/* person — avatar + name + email; avatar is decoration, text is identity. */
.rst-person, [rst-person] { align-items: center; color: inherit; display: inline-flex; gap: 0.7rem; min-width: 0; text-decoration: none; }
.rst-person__av, [rst-person-av] { align-items: center; background: var(--rst-accent); border-radius: 50%; color: var(--rst-on-accent); display: flex; flex: none; font-size: 0.6875rem; font-weight: 600; height: 28px; justify-content: center; width: 28px; }
@@ -1039,6 +1212,17 @@ details[open] > summary > .rst-caret, details[open] > summary > [rst-caret] { tr
and it is wide enough for the postcodes and codes it is for. The
max keeps it from overflowing a column narrower than itself. */
.rst-input--short, [rst-input~="short"] { inline-size: 8rem; max-inline-size: 100%; }
+/* primary is the form's headline field — the title or name the record is
+ known by — and the size is the whole signal, because the label above it
+ stays the same quiet line every other field gets. font-size has to be
+ restated rather than inherited: .rst-input sets `font: inherit`, so the
+ shorthand would otherwise reset it back to the body's 14px. 550 is the
+ weight .rst-nm and .rst-person__name already give a name; 600 reads as a
+ heading, which this is not. The padding grows with the type so the box
+ keeps its proportions instead of looking like a squeezed plain input.
+ 17px is also where iOS Safari stops zooming a focused input, which the
+ 14px base does not clear — a real bonus, not the reason. */
+.rst-input--primary, [rst-input~="primary"] { font-size: var(--rst-fs-lg); font-weight: 550; padding: 0.6rem 0.7rem; }
textarea.rst-input, textarea[rst-input] { min-height: 5rem; resize: vertical; }
/* field-text/field-textarea (the interim pair the manifest generator
emits) mark a required label with * and put the textarea on its own
@@ -1288,6 +1472,19 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
animation: rst-spin 0.8s linear infinite;
}
@keyframes rst-spin { to { transform: rotate(1turn); } }
+
+/* A running job's determinate bar: a native <progress>, styled the same
+ way and for the same reasons as [rst-meter-bar] — see that block for
+ why the three engines need three rules that cannot be merged, and for
+ the same honest flag about the -moz- one being unverified here.
+ <progress>'s pseudo-elements are its own: ::-webkit-progress-bar is
+ the track, ::-webkit-progress-value the fill, ::-moz-progress-bar the
+ fill. It is a block on its own line under the sentence, because it
+ measures the job the sentence is about. */
+.rst-job__bar, [rst-job-bar] { appearance: none; background: var(--rst-accent-soft); block-size: 4px; border: 0; border-radius: 2px; display: block; inline-size: 100%; margin-block-start: var(--rst-sp-2); }
+.rst-job__bar::-webkit-progress-bar, [rst-job-bar]::-webkit-progress-bar { background: var(--rst-accent-soft); border-radius: 2px; }
+.rst-job__bar::-webkit-progress-value, [rst-job-bar]::-webkit-progress-value { background: var(--rst-accent); border-radius: 2px; }
+.rst-job__bar::-moz-progress-bar, [rst-job-bar]::-moz-progress-bar { background: var(--rst-accent); border-radius: 2px; }
@media (prefers-reduced-motion: reduce) {
.rst-spin, [rst-spin] { animation: none; opacity: 0.5; }
}
@@ -1343,6 +1540,72 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
.rst-dtp__set, [rst-dtp-set] { flex: none; font-size: var(--rst-fs-xs); color: var(--rst-muted); }
.rst-dtp__hint, [rst-dtp-hint] { color: var(--rst-muted); font-size: var(--rst-fs-xs); padding: 0.35rem 0.65rem 0.15rem; }
+/* The popup opens above the field where there is no room below it —
+ datetime.js measures and sets .is-above, because a panel hanging off
+ the bottom of the window is a panel whose last week nobody can click.
+ One rule for both popups: only ever one of them is open. */
+.rst-dtp.is-above .rst-dtp__list, [rst-dtp].is-above [rst-dtp-list], .rst-dtp.is-above .rst-cal, [rst-dtp].is-above [rst-cal] { inset-block-end: 100%; margin-block-end: 4px; margin-block-start: 0; top: auto; }
+/* A completion offered rather than chosen — the other months a
+ half-typed word could still have meant. Lighter than the reading
+ above it, because it is a second-best by construction. */
+.rst-dtp__row--alt .rst-dtp__label, [rst-dtp-row~="alt"] [rst-dtp-label] { color: var(--rst-text-muted); }
+
+/* ── The calendar overlay (ui/calendar.js): the month grid a date
+ field's button opens. A real <table> with real column headers,
+ because that is what a calendar is, with role="grid" over the top
+ and a roving tabindex so exactly one day sits in the tab order.
+
+ Sized in rem so the grid keeps its shape when a page is zoomed:
+ seven columns of text, not seven columns of pixels. A fixed inline
+ size rather than the field's, because a calendar is a calendar
+ whatever it hangs under — a month stretched across a wide input is
+ a grid nobody can aim at.
+
+ Everything here is logical (inline/block, never left/right), so a
+ right-to-left page mirrors the panel and the grid together. The
+ chevrons are the one thing that needs saying twice, below.
+ ───────────────────────────────────────────────────────────────── */
+.rst-cal, [rst-cal] { background: var(--rst-surface); border: 1px solid var(--rst-line); border-radius: 9px; box-shadow: var(--rst-shadow-pop); inline-size: 18rem; inset-inline-start: 0; margin-block-start: 4px; padding: var(--rst-sp-2); position: absolute; top: 100%; z-index: 40; }
+.rst-cal__head, [rst-cal-head] { align-items: center; display: flex; gap: var(--rst-sp-1); justify-content: space-between; padding-block-end: var(--rst-sp-2); }
+.rst-cal__title, [rst-cal-title] { flex: 1; font-size: var(--rst-fs-sm); font-weight: 600; text-align: center; }
+.rst-cal__nav, [rst-cal-nav] { align-items: center; background: none; block-size: 1.75rem; border: 0; border-radius: var(--rst-radius-sm); color: var(--rst-muted); cursor: pointer; display: flex; inline-size: 1.75rem; justify-content: center; padding: 0; }
+.rst-cal__nav:hover:not(:disabled), [rst-cal-nav]:hover:not(:disabled) { background: var(--rst-accent-soft); color: var(--rst-text); }
+/* A month with nothing pickable in it — past the field's min, or past
+ its max. Dimmed and inert rather than removed, so the header keeps
+ its shape and the title stays where the eye left it. */
+.rst-cal__nav:disabled, [rst-cal-nav]:disabled { cursor: default; opacity: 0.35; }
+.rst-cal__nav svg, [rst-cal-nav] svg { block-size: 1.1rem; inline-size: 1.1rem; }
+/* One chevron, drawn once and turned round for the other direction, so
+ "back" always points at the start of the line — which is the other
+ end of the box in a right-to-left page, and handled there by the
+ panel's own direction rather than a second rule. */
+[rst-cal-nav~="next"] svg, .rst-cal__nav--next svg { transform: scaleX(-1); }
+.rst-cal__grid, [rst-cal-grid] { border-collapse: collapse; inline-size: 100%; table-layout: fixed; }
+.rst-cal__grid th, [rst-cal-grid] th { color: var(--rst-muted); font-size: var(--rst-fs-xs); font-weight: 500; padding-block: var(--rst-sp-1); text-align: center; }
+.rst-cal__day, [rst-cal-day] { border-radius: var(--rst-radius-sm); cursor: pointer; font-size: var(--rst-fs-sm); font-variant-numeric: tabular-nums; line-height: 2.15; text-align: center; }
+.rst-cal__day:hover, [rst-cal-day]:hover { background: var(--rst-accent-soft); }
+/* The days either side of the month. Still pickable — reaching for the
+ 1st from the row above it is how people use a calendar — but plainly
+ not part of the month on screen. */
+.rst-cal__day.is-outside, [rst-cal-day].is-outside { color: var(--rst-text-faint); }
+/* Today is a ring rather than a fill, so it can still be read when the
+ selection is sitting on top of it. */
+.rst-cal__day.is-today, [rst-cal-day].is-today { box-shadow: inset 0 0 0 1px var(--rst-line-strong); font-weight: 600; }
+/* What the text in the box currently reads as: an outline that follows
+ the words as they are typed. Deliberately quieter than the selection
+ — it is a preview, and nothing has been chosen yet. */
+.rst-cal__day.is-preview, [rst-cal-day].is-preview { box-shadow: inset 0 0 0 2px var(--rst-accent); }
+/* The committed value. aria-selected says so in the accessibility tree;
+ this is the matching visual, never the only signal. */
+.rst-cal__day.is-selected, [rst-cal-day].is-selected { background: var(--rst-accent); color: var(--rst-on-accent); font-weight: 600; }
+.rst-cal__day.is-selected.is-outside, [rst-cal-day].is-selected.is-outside { color: var(--rst-on-accent); }
+/* Outside the field's own min/max. aria-disabled carries it to a screen
+ reader and calendar.js refuses the pick; this says the same to the
+ eye. */
+.rst-cal__day.is-disabled, [rst-cal-day].is-disabled { color: var(--rst-text-faint); cursor: default; text-decoration: line-through; }
+.rst-cal__day.is-disabled:hover, [rst-cal-day].is-disabled:hover { background: none; }
+.rst-cal__day:focus-visible, [rst-cal-day]:focus-visible { outline: 2px solid var(--rst-accent); outline-offset: -2px; }
+
/* ── Shells: the page frames an app's layout template wraps .rst-page
in — topbar and sidebar. Written in logical properties throughout,
so a right-to-left locale gets a mirrored shell for free: the rail
@@ -1618,6 +1881,40 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
.rst-error__cta, [rst-error-cta] { display: flex; flex-wrap: wrap; gap: var(--rst-sp-2); justify-content: center; margin-block: var(--rst-sp-5) 0; }
.rst-error__ref, [rst-error-ref] { color: var(--rst-text-faint); margin-block: 2rem 0; }
+/* ---------------------------------------------------------------------
+ Touch: the two zooms nobody asked for.
+
+ Mobile Safari zooms the whole page when it focuses a form control
+ whose text is under 16px, and this file's base type is 14px on
+ purpose. So every text-entry control comes back up to 16px where the
+ pointer is coarse, and stays 14px under a mouse. max() rather than a
+ flat 1rem, so a control deliberately set larger keeps its size; rem
+ rather than px, so a reader who raised the browser default keeps the
+ increase. This is the fix. The other one — user-scalable=no in the
+ viewport tag — buys the same quiet by taking pinch-zoom away from
+ everyone, which is a WCAG 1.4.4 failure and not on offer here.
+
+ Double-tap is the second zoom: tap a button or a row twice in quick
+ succession and the second tap lands as a zoom gesture rather than a
+ click. touch-action: manipulation drops that gesture on interactive
+ elements only, so panning and pinch-zoom are untouched, and so is
+ double-tapping prose or an image, which is a real way to read a
+ narrow column. :where() weighs nothing, so any rule can override it.
+ --------------------------------------------------------------------- */
+
+@media (pointer: coarse) {
+ input, select, textarea,
+ .rst-input, [rst-input],
+ .rst-textarea, [rst-textarea],
+ .rst-search input[type="search"], [rst-search] input[type="search"] {
+ font-size: max(1rem, 1em);
+ }
+}
+
+:where(a[href], button, input, select, textarea, label, summary, [role="button"], [role="tab"], [role="option"]) {
+ touch-action: manipulation;
+}
+
/* ---------------------------------------------------------------------
Utilities, last on purpose.
diff --git a/internal/home/testapp_test.go b/internal/home/testapp_test.go
index a36a848..386f114 100644
--- a/internal/home/testapp_test.go
+++ b/internal/home/testapp_test.go
@@ -10,8 +10,8 @@ import (
"sync"
"testing"
- "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/home/internal/home/seal"
)
diff --git a/internal/operator/engine.go b/internal/operator/engine.go
index 20986f4..ba38305 100644
--- a/internal/operator/engine.go
+++ b/internal/operator/engine.go
@@ -12,7 +12,7 @@ import (
"math"
"time"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
//go:embed migrations
diff --git a/internal/operator/engine_test.go b/internal/operator/engine_test.go
index cb09c53..6ee5aa4 100644
--- a/internal/operator/engine_test.go
+++ b/internal/operator/engine_test.go
@@ -15,8 +15,8 @@ import (
sharedseal "amadan.net/oficina/home/handoff/seal"
"amadan.net/oficina/home/internal/home/directorydata"
family "amadan.net/rastrillo/rastrillo/crypto"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
_ "modernc.org/sqlite"
)
diff --git a/internal/operator/ledger.go b/internal/operator/ledger.go
index 57deba5..070ab59 100644
--- a/internal/operator/ledger.go
+++ b/internal/operator/ledger.go
@@ -3,7 +3,8 @@ package operator
import (
"context"
"database/sql"
- "github.com/carlosframework/rastrillo/migrate"
+
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func VerifyLedger(ctx context.Context, c *sql.Conn, set *migrate.Set) error {