oficina / estilo Public
Shared save status
Status: revision 2 approved by Claude Fable 5.1 (claude-fable-5-1), 2026-09-07. Implementation and consumer adoption require branch review. Full initial and revised verdicts are recorded in Amadan Estilo discussion 1. User instruction: extract reusable components and maintain consistent suite UI/UX through Estilo during the overnight implementation run.
Concrete consumers
Docs at 499d200 has a polite live region in views/show.html with two localized messages (retrying, failed), styled as a fixed notice. Its editor sets data-state; successful routine saves deliberately have no visible message.
Slides slice-2-editor at a863fb6 has a status line in templates/editor.html and editor.css. editor-entry.js updates its text and data-state. It displays saved, saving, offline and error messages from the app's catalog. Existing session owns unfinished editor work; adoption will use an isolated branch after its current revision and be coordinated before merging.
Primitive
Build the first shared component in Estilo, consumed by Docs first; Slides is the second adoption that validates/corrects the interface (AGENTS.md).
Package savestatus exports an embedded html/template definition plus CSS. Data is a struct with localized text for Saved, Saving, Retrying, Failed and an optional localized accessible label. Missing text means that state stays visually silent. No English default or authored product copy lives here. The initial state is validated to a closed set, including idle. Unknown states are silent and never represented as saved.
Markup uses estilo-save-status and estilo-save-message attributes, role=status, aria-live=polite, aria-atomic=true. Messages are ordinary template-escaped strings. The component is non-interactive. State changes are reflected by a small shared JavaScript function updating textContent in the already-present live region; it never injects HTML. Without script, the initial status text is visible.
Slides maps saved/saving directly. Its offline state maps to retrying and retains the existing localized offline text. Its sticky dropped-batch case continues showing that same offline text, never saved; no new failed message is invented. Slide-load errors remain an app-owned element separate from save status, using the existing localized error text. The adopter must not claim a successful save clears a load error, or a successful load clears a dropped batch.
Two placements are needed by the existing consumers: inline and floating. CSS inherits rastrillo tokens, wraps long text, respects 320px reflow and uses words plus weight for failure emphasis; it changes no theme value. App code continues to own save lifecycle, sticky failure, retry and recovery semantics. The floating failure retains Docs' negative background/foreground tone tokens. Inline placement retains Slides' minimum inline size of 8ch to avoid jitter. Both variants disappear for print via the component's own print rule.
Silent status is an empty rendered live region: never display:none, visibility: hidden, hidden, or aria-hidden. Empty floating state has no padding/background/ shadow, but the element remains present before a subsequent text mutation. This keeps the region in the accessibility tree before its first failure announcement.
Do not ship a new all-green appearance for Docs routine saves, and do not change failure/retry wording. Do not infer save state from HTTP activity alone.
Integration
Both app adopters import the same Estilo package revision and serve its CSS/JS through their existing embedded asset route. Their templates use the shared markup. Remove the replaced app-local status styling and DOM-writing functions. Retain an app-specific selector only where needed during the same migration; remove duplicate status DOM. No dynamic CDN imports, new framework, or bundler.
Delivery is one same-origin ES module URL exposed in the editor's data attribute. The bundle loads it with dynamic import of that URL (kept external to bundling) and calls its exported mount function. The element holds template-escaped data-text-saved/saving/retrying/failed values; the module reads those once. Both apps' existing static routes serve the embedded module and CSS. Module-load failure must leave existing error/retry indication operational through a minimal app fallback or a pre-editor failure state; it must never silently run an editor whose persistence failure cannot be shown. The implementation review must verify this delivery/failure path in the actual bundle, not only the helper's unit test.
Verification
Test HTML escaping, invalid state handling, missing labels/messages, role/live region and scriptless initial state. Exercise state transitions on a real DOM and prove failure wording is not replaced by stale save completion through app tests. Run Estilo theme/token-prefix tests unchanged and each consumer's gates. Verify both variants at 320px and keyboard/screen-reader semantics. Review full library and consumer diffs with Fable before CI/merge/deploy. Exercise repeated saving/offline/failed transitions; the live region remains in the DOM/accessibility tree while silent. Check Slides' sticky failure never returns to saved after a dropped batch; check load-error independence. Measure 320px using Docs' longest existing failed text and widest available locale.
No extraction is called complete until two apps consume it and their old duplicate implementation is removed. Until then it is an in-progress primitive.
Fable review 1: claude-fable-5-1, /tmp/oficina-overnight-review/estilo.json. All seven findings accepted above: exact Slides mapping, persistent live region, explicit JS delivery, print, inline width, negative tone, pinned Slides revision.
Implementation evidence
The floating notice uses pointer-events:none so it cannot block the editor. The full local make test gate passes. Mutation checks reject treating an unknown state as saved and replacing textContent with innerHTML.
Private module transport
Estilo remains private. Use module path amadan.net/oficina/estilo.git, GOPRIVATE=amadan.net and authenticated Git transport. Go documents the VCS suffix as the supported way to resolve a private repository without public go-import metadata. A fresh direct download of5f712c7 via that path resolved the exact repository and commit. No public visibility change or local replace is part of the shipping dependency. Both first consumers adopt the qualified module path; no existing consumer pin was found.