Files
SealShare/resources/css/app.css
T
Andreas Reinhold / reiniandClaude Opus 5 5658ac148c Drop the Tailwind framing from a stale comment in app.css
The recovery-codes pulse comment still explained itself against
Tailwind's animate-pulse, which left the stack in 2.0.0. The reason
stands on its own: the package keeps no keyframe utility for a pulse
loop, so the loading state animates on the effects spring instead.

config/livewire.php:237 stays on Livewire's own "tailwind" default:
SealShare still installs livewire-material ^2.0 from Gitea, whose
vendor copy has no `pagination::material` view yet, so pointing
pagination_theme at it now would break pagination. The package takes
the theme over itself once 2.2.0 is tagged and pulled.
DesignLanguageTest carried no Tailwind wording to update.

Full suite (322) and Pint green, unchanged — run against the old
vendor copy, so the guard's new undeclared-class check is not
exercised here yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 21:23:47 +02:00

316 lines
13 KiB
CSS

@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@import '../../vendor/nonameweb/livewire-material/resources/css/foundation.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/grid.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/pane.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/row.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/stack.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/surface.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/account-menu.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/alert.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/badge.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/button.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/card.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/checkbox.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/divider.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/empty-state.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/file.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/form.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/group.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/icon.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/input.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/list-item.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/list.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/loading.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/menu-item.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/modal.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/pagination.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/password.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/progress.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/scheme-picker.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/section-nav.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/select.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/shape.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/stat.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/textarea.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/theme-toggle.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toast.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toggle.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toolbar.css';
@import './material-scheme.css';
/*
* SealShare's own rules, unlayered so they outrank every package rule: one section per view, in
* the order a visitor meets them — the layout and the page template, the share flow (upload,
* share created, download), the settings pages in their navigation's order, then admin.
*/
/*
* resources/views/layouts/app.blade.php: every page's main region.
*
* `<x-pane as="main">` gives the region its horizontal M3 margin (16px below `medium`, 24px from
* it); the page inside (components/page.blade.php) sets its own width and centres itself. The
* vertical rhythm is the app's own. The bottom padding clears the floating toolbar in
* partials/toolbar.blade.php by what the toolbar publishes as `--material-bottom-toolbar` (its top
* edge's distance from the window's bottom, safe area included), plus 16px. Never set
* `--material-bottom-bar` here: the toolbar reads it to place itself.
*/
.app-main {
padding-block-start: var(--md-sys-measurement-space400);
padding-block-end: calc(var(--material-bottom-toolbar, 0px) + var(--md-sys-measurement-space200));
}
@media (width >= 600px) {
.app-main {
padding-block-start: var(--md-sys-measurement-space600);
}
}
/* resources/views/components/page.blade.php: the site's own logo above the title on a `brand` page, at 1.x's 5rem-tall size, its width following the image. */
.page-logo {
block-size: 5rem;
}
/*
* resources/views/livewire/file-uploader.blade.php: the drop zone's dashed outline and its
* primary tint while dragging. `data-dragging` is Alpine's, not the package's, since no
* component tracks a native drag over an arbitrary drop target; disabled where uploads cannot run
* (no secure context) blocks pointer events and dims to M3's disabled-content opacity, as a code dims elsewhere while
* busy (.settings-recovery-code--loading).
*/
.upload-drop-zone {
padding: var(--md-sys-measurement-space400);
border: 2px dashed var(--md-sys-color-outline-variant);
border-radius: var(--md-sys-shape-corner-xl);
transition: border-color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default), background-color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
}
.upload-drop-zone[data-dragging='true'] {
border-color: var(--md-sys-color-primary);
background-color: color-mix(in srgb, var(--md-sys-color-primary-container) 40%, transparent);
}
.upload-drop-zone[aria-disabled='true'] {
pointer-events: none;
opacity: var(--md-sys-state-disabled-content-opacity);
}
/*
* resources/views/livewire/file-uploader.blade.php: the drop zone's shape morphs into a burst
* while files are dragged over it — SealShare's signature, kept from 1.x (docs/reference/m3/styles.md
* § Shape: "Shape morph should respond to user interaction"). Two `<x-shape>`s sit
* stacked (`inset: 0` on an absolutely positioned element sizes it to the box, no width/height
* class needed) and cross-fade/scale on the spatial-slow spring the shape's size warrants
* (docs/reference/m3/styles.md § Motion: "larger elements may use slow"); opacity rides the
* effects-slow spring beside it, since a colour or fade must never overshoot. Reduced motion needs
* no local override: the tokens themselves zero out under it (tokens/motion.css).
*/
.upload-drop-shapes {
position: relative;
display: grid;
place-items: center;
inline-size: 7rem;
block-size: 7rem;
}
.upload-drop-shape {
position: absolute;
inset: 0;
transition: scale var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow), rotate var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow), opacity var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow);
}
.upload-drop-shape--idle {
scale: 1;
rotate: 0deg;
opacity: 1;
color: var(--md-sys-color-secondary-container);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-shape--idle {
scale: 0.5;
rotate: 45deg;
opacity: 0;
}
.upload-drop-shape--burst {
scale: 0.5;
rotate: -45deg;
opacity: 0;
color: var(--md-sys-color-primary-container);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-shape--burst {
scale: 1.1;
rotate: 0deg;
opacity: 1;
}
.upload-drop-icon {
position: relative;
color: var(--md-sys-color-on-secondary-container);
transition: color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-icon {
color: var(--md-sys-color-on-primary-container);
}
/* resources/views/livewire/file-uploader.blade.php: the selected-files list scrolls on its own past 1.x's cap instead of pushing the options and the submit button down the page. */
.upload-file-list {
max-block-size: 18rem;
overflow-y: auto;
}
/*
* resources/views/livewire/share-created.blade.php: the check that settles onto its Expressive
* shape once the link is ready (the `share-ready`/`share-ready-fade` keyframes after it). The shape
* sits at the box's edges (`inset: 0` on an absolutely positioned element sizes it, no width/height
* class needed); both colours are container roles `md-ink-*` has no class for, so they are the
* application's own CSS rather than a component prop.
*/
.share-check {
position: relative;
display: grid;
place-items: center;
inline-size: 6rem;
block-size: 6rem;
animation:
share-ready var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow) both,
share-ready-fade var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow) both;
}
.share-check-shape {
position: absolute;
inset: 0;
color: var(--md-sys-color-primary-container);
}
.share-check-icon {
/* Without this the icon, though later in the DOM, is a non-positioned in-flow child: it paints
before the absolutely positioned shape beside it (CSS's stacking order for z-index:auto) and
sits hidden underneath it, as .upload-drop-icon's own position: relative is there to avoid. */
position: relative;
color: var(--md-sys-color-on-primary-container);
}
/*
* resources/views/livewire/share-created.blade.php: the check settling onto its shape, run by
* .share-check — rotate and scale on the spatial spring (shape motion), opacity on effects beside
* it, since M3 never lets a colour or fade overshoot; reduced motion needs no local override, the
* duration tokens themselves zero out under it.
*/
@keyframes share-ready {
from {
rotate: -90deg;
scale: 0.4;
}
to {
rotate: 0deg;
scale: 1;
}
}
@keyframes share-ready-fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
* resources/views/livewire/share-created.blade.php: the QR code dialog. `App\Services\QrCodeService`
* already draws its SVG black on white with a four-module quiet zone, so the container adds no
* colour of its own — no colour class or literal colour could give it one that also holds in dark
* mode. The corner only rounds the container that clips it, exactly as .settings-two-factor-qr's does.
*/
.share-qr {
display: grid;
place-items: center;
inline-size: 100%;
max-inline-size: 20rem;
aspect-ratio: 1;
margin-inline: auto;
overflow: hidden;
border-radius: var(--md-sys-shape-corner-lg);
}
.share-qr svg {
inline-size: 100%;
block-size: 100%;
}
/*
* resources/views/pages/settings/two-factor.blade.php: the setup QR code. Fortify's own
* twoFactorQrCodeSvg() draws no quiet zone, so the SVG comes from App\Services\QrCodeService
* against the same otpauth URL instead, which bakes in its own white field and four-module quiet
* zone — the only way to guarantee one in dark mode, since no colour class or literal colour can
* paint it onto 2.0.0's foundation. Sized at 1.x's 16rem square, corners rounded and clipped to
* match the settings surfaces around it.
*/
.settings-two-factor-qr {
display: grid;
place-items: center;
inline-size: 16rem;
aspect-ratio: 1;
overflow: hidden;
border-radius: var(--md-sys-shape-corner-lg);
}
.settings-two-factor-qr svg {
inline-size: 100%;
block-size: 100%;
}
/*
* resources/views/pages/settings/two-factor/recovery-codes.blade.php: a code dims to M3's disabled
* content opacity while regenerateRecoveryCodes() is in flight, and back, on the effects spring
* rather than a keyframe pulse loop — 2.0.0 keeps no keyframe utility for one. The
* transition sits on the code itself so the way back eases too; under reduced motion the token's
* duration is 0ms.
*/
.settings-recovery-code {
transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
}
.settings-recovery-code--loading {
opacity: var(--md-sys-state-disabled-content-opacity);
}
/*
* resources/views/pages/settings/appearance.blade.php: the theme picker stays a comfortable
* width instead of stretching across the settings card. No `<x-group>` width prop caps it, and
* 24rem matches no `<x-pane>` preset.
*/
.settings-appearance-picker {
max-inline-size: 24rem;
}
/*
* resources/views/livewire/admin/admin-dashboard.blade.php: a share's details are two lines of
* their own (its files, size and downloads; its expiry), and they wrap rather than clip. The
* package clamps a list item's description at two lines with an ellipsis, which on a phone hid
* the expiry with no way to read it.
*/
.admin-shares [data-md-list-item-description] {
display: block;
overflow: visible;
}
.admin-share-detail {
display: block;
}
/*
* resources/views/livewire/admin/admin-settings.blade.php: the current and previewed site logo,
* at 1.x's 4rem height with its width following the image's own ratio. M3 keeps no size scale for
* a plain <img>.
*/
.admin-settings-logo {
block-size: 4rem;
border-radius: var(--md-sys-shape-corner-sm);
}