Files
Momoko-Ayase a230c37281 web: stack file-row status below the name on narrow screens
On phone-width viewports the right-aligned status column shared a flex
line with a long file name and wrapped one word per line. Below 560px
the row now wraps: name and action icons keep the first line and the
status takes a full-width line underneath.
2026-09-10 09:29:23 +08:00

390 lines
7.8 KiB
CSS

:root {
color-scheme: dark;
--bg: #14161a;
--panel: #1d2026;
--black: #0c0e11;
--border: #2e323b;
--text: #e4e7ec;
--dim: #9aa3b0;
--accent: #e8b64c;
--blue: #3b82f6;
--blue-deep: #1d4ed8;
--ok: #1e6b34;
--ok-bright: #6fcf7c;
--err: #7a2828;
--err-bright: #e06c6c;
--warn: #e8b64c;
}
* { box-sizing: border-box; }
/* display rules below (inline-flex etc.) would otherwise beat the hidden
attribute's UA display:none — the badge/download icons must stay hidden. */
[hidden] { display: none !important; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font: 16px/1.55 system-ui, "Segoe UI", sans-serif;
}
main {
max-width: 720px;
margin: 0 auto;
padding: 2.5rem 1.25rem 3rem;
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
}
h1 { margin-bottom: 0.25rem; }
.tag {
font-size: 0.45em;
vertical-align: super;
color: var(--accent);
letter-spacing: 0.08em;
}
.github-link {
color: var(--dim);
transition: color 0.2s, transform 0.2s;
}
.github-link:hover {
color: var(--text);
transform: scale(1.12);
}
.lede { color: var(--dim); }
.lede strong { color: var(--text); }
/* --- legal modal --- */
#legal-overlay {
position: fixed;
inset: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
padding: 1.25rem;
background: rgba(10, 11, 13, 0.82);
backdrop-filter: blur(3px);
animation: fadeIn 0.25s ease-out;
}
.legal-box {
max-width: 560px;
max-height: 85vh;
overflow-y: auto;
padding: 1.75rem 2rem;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 12px;
animation: popIn 0.3s cubic-bezier(0.2, 1.4, 0.4, 1);
}
.legal-box h2 { margin-top: 0; }
.legal-box p { color: var(--dim); font-size: 0.95rem; }
.legal-box strong { color: var(--text); }
button {
font: inherit;
padding: 0.55rem 1.2rem;
border: 1px solid var(--accent);
border-radius: 8px;
background: var(--accent);
color: #14161a;
font-weight: 600;
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
}
button:not(:disabled):hover {
transform: translateY(-1px);
box-shadow: 0 3px 12px rgba(232, 182, 76, 0.25);
}
button:not(:disabled):active { transform: translateY(0); }
button:disabled {
opacity: 0.45;
cursor: default;
}
button.secondary {
background: transparent;
color: var(--dim);
border-color: var(--border);
}
button.secondary:not(:disabled):hover {
box-shadow: none;
color: var(--text);
}
#legal-accept { width: 100%; margin-top: 0.5rem; }
/* --- dropzone --- */
#dropzone {
margin: 1.5rem 0;
padding: 2.25rem 1.5rem;
text-align: center;
background: var(--panel);
border: 2px dashed var(--border);
border-radius: 12px;
cursor: pointer;
transition: border-color 0.2s, background 0.2s, transform 0.2s;
}
#dropzone:hover, #dropzone:focus-visible {
border-color: var(--accent);
outline: none;
}
#dropzone.over {
border-color: var(--accent);
background: #232730;
transform: scale(1.01);
animation: pulse 1s ease-in-out infinite;
}
#dropzone p { margin: 0.25rem 0; }
.hint { color: var(--dim); font-size: 0.9rem; }
code {
background: var(--bg);
padding: 0.1em 0.35em;
border-radius: 4px;
font-size: 0.9em;
}
/* --- file list --- */
#files {
list-style: none;
margin: 0 0 0.75rem;
padding: 0;
}
.file {
position: relative;
margin-bottom: 0.45rem;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
background: var(--black); /* staged */
transition: background-color 0.5s ease;
animation: slideIn 0.25s ease-out;
}
.file.leaving {
opacity: 0;
transform: translateX(12px);
margin-bottom: 0;
border-width: 0;
transition:
opacity 0.13s ease-in,
transform 0.13s ease-in,
max-height 0.17s ease-in 0.03s,
margin-bottom 0.17s ease-in 0.03s,
border-width 0.17s ease-in 0.03s;
}
.file .bar {
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 0.3s;
}
.file.working { background: var(--black); }
/* The gradient's left and right edge colors match, so the 200%-sized image
tiles seamlessly and the position loop has no visible restart. */
.file.working .bar {
opacity: 1;
background: linear-gradient(
100deg,
var(--blue-deep) 0%,
var(--blue) 25%,
#7fb3ff 50%,
var(--blue) 75%,
var(--blue-deep) 100%
);
background-size: 200% 100%;
animation: shimmer 1.6s linear infinite;
}
.file.ok { background: var(--ok); }
.file.ok.suspect { background: #6b5a1e; }
.file.err { background: var(--err); }
.file .row {
position: relative;
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.55rem 0.85rem;
}
.file .name {
overflow-wrap: anywhere;
font-weight: 600;
}
.file.working .name { color: #fff; }
.file.ok .name, .file.err .name { color: #fff; }
.badge.companion {
flex: none;
display: inline-flex;
align-items: center;
padding: 0.15rem 0.35rem;
border-radius: 5px;
background: rgba(59, 130, 246, 0.18);
color: #7fb3ff;
}
.file.ok .badge.companion,
.file.err .badge.companion,
.file.working .badge.companion {
background: rgba(255, 255, 255, 0.15);
color: #fff;
}
.file .status {
flex: 1;
text-align: right;
font-size: 0.85rem;
color: var(--dim);
overflow-wrap: anywhere;
}
.file.ok .status { color: #cfe9d5; }
.file.ok.suspect .status { color: #f0e3b2; }
.file.err .status { color: #f0c8c8; }
.file.working .status { color: #dbe7ff; }
.file .dl {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.9rem;
height: 1.9rem;
border-radius: 6px;
background: rgba(255, 255, 255, 0.16);
color: #fff;
transition: background 0.15s, transform 0.15s;
animation: popIn 0.3s cubic-bezier(0.2, 1.4, 0.4, 1);
}
.file .dl:hover {
background: rgba(255, 255, 255, 0.32);
transform: scale(1.1);
}
.file .remove {
flex: none;
padding: 0.1rem 0.55rem;
background: transparent;
border: 1px solid var(--border);
border-radius: 6px;
color: var(--dim);
font-weight: 400;
}
.file .remove:hover {
color: var(--err-bright);
border-color: var(--err-bright);
box-shadow: none;
transform: none;
}
.file.ok .remove,
.file.err .remove,
.file.working .remove {
border-color: rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.75);
}
.file.ok .remove:hover,
.file.err .remove:hover {
color: #fff;
border-color: #fff;
}
.actions {
display: flex;
gap: 0.6rem;
animation: fadeIn 0.25s ease-out;
}
footer {
margin-top: 2rem;
color: var(--dim);
font-size: 0.85rem;
}
footer a { color: var(--dim); }
/* --- narrow screens --- */
/* On a narrow viewport the status column (flex: 1, right-aligned) is
squeezed by a long file name into a one-word-per-line vertical strip.
Stack the row instead: name + icons on the first line, the status on its
own full-width line below, left-aligned. */
@media (max-width: 560px) {
main { padding: 1.5rem 0.9rem 2.5rem; }
#dropzone { padding: 1.75rem 1rem; }
.file .row { flex-wrap: wrap; }
.file .name { flex: 1; min-width: 0; }
.file .status {
order: 6; /* after the download/remove icons */
flex-basis: 100%;
text-align: left;
}
}
/* --- animations --- */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes popIn {
from { opacity: 0; transform: scale(0.85); }
to { opacity: 1; transform: scale(1); }
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes shimmer {
from { background-position: 0 0; }
to { background-position: -200% 0; }
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(232, 182, 76, 0.25); }
50% { box-shadow: 0 0 0 6px rgba(232, 182, 76, 0); }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}