Files
LockScreenWallpaper/src/styles.css
T
Christoph 7c15f51355
Android Release / Build signed release APK (push) Canceled after 40m19s
feat(android): add Android release workflow and shuffle UI improvements
Adds a new Android release workflow to sign and publish APKs when tags are pushed. Also enhances wallpaper shuffle by tracking seen IDs to reduce repeats. UI changes in App.tsx introduce lazy loading for the gallery and improved navigation/history handling.

- Add Android signing workflow with keystore secrets
- Track shuffle seen IDs to avoid image repeats
- Enable gallery lazy loading via sentinel and observer
2026-08-25 23:22:36 +02:00

197 lines
20 KiB
CSS

:root { font-family: Inter, Roboto, "Noto Sans", system-ui, sans-serif; color: #18201b; background: #edf1ed; font-synthesis: none; --green: #145d32; --sage: #e6eee4; --line: #dce3dc; }
* { box-sizing: border-box; }
body { margin: 0; min-width: 320px; min-height: 100vh; }
button { font: inherit; }
.app-shell { width: min(100%, 480px); min-height: 100dvh; margin: 0 auto; background: #f8faf7; position: relative; padding-bottom: calc(94px + env(safe-area-inset-bottom)); box-shadow: 0 0 50px rgba(32, 50, 37, .12); overflow-anchor: none; }
header { padding: max(24px, env(safe-area-inset-top)) 24px 18px; display: flex; align-items: center; justify-content: space-between; }
h1 { font-size: 34px; letter-spacing: -1.7px; line-height: 1.05; margin: 0 0 6px; font-weight: 800; }
header p { margin: 0; font-size: 13px; color: #657068; font-weight: 500; }
.icon-button { width: 44px; height: 44px; border: 0; border-radius: 50%; background: #edf2eb; color: #31523b; display: grid; place-items: center; }
.icon-button svg { width: 21px; }
.icon-button:disabled { opacity: .55; }
.app-header { gap: 12px; overflow: hidden; }
.brand { min-width: 0; flex: 1; display: flex; align-items: center; gap: 11px; }
.brand-logo { width: 46px; height: 46px; flex: 0 0 auto; border-radius: 13px; box-shadow: 0 5px 15px rgba(20,93,50,.18); }
.brand-copy { min-width: 0; }
.brand-copy h1 { margin-bottom: 3px; overflow: hidden; font-size: clamp(24px, 7vw, 30px); letter-spacing: -1.2px; text-overflow: ellipsis; white-space: nowrap; }
.brand-copy p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-shortcut { flex: 0 0 46px; width: 46px; height: 46px; color: white; background: var(--green); box-shadow: 0 7px 18px rgba(20,93,50,.24); }
.settings-shortcut.selected { color: var(--green); background: #dcebdd; box-shadow: inset 0 0 0 2px rgba(20,93,50,.12); }
.settings-shortcut:active { transform: scale(.94); }
.gallery-header { gap: 14px; }
.gallery-header > div { flex: 1; }
.gallery-header h1 { font-size: 25px; letter-spacing: -.9px; margin-bottom: 3px; }
@media (max-width: 360px) {
header { padding-left: 16px; padding-right: 16px; }
.brand { gap: 8px; }
.brand-logo { width: 40px; height: 40px; border-radius: 11px; }
.brand-copy h1 { font-size: 23px; }
.brand-copy p { font-size: 11px; }
.settings-shortcut { flex-basis: 42px; width: 42px; height: 42px; }
}
.content { padding: 0 20px; }
.hero { position: relative; height: 294px; margin: 0 0 15px; border-radius: 26px; isolation: isolate; }
.hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; z-index: 1; }
.photo-stack { position: absolute; inset: -7px 10px 8px; background: #dce5d9; transform: rotate(1.2deg); border-radius: 26px; }
.hero-shade { position: absolute; inset: 45% 0 0; z-index: 2; border-radius: 0 0 26px 26px; background: linear-gradient(transparent, rgba(3, 17, 9, .64)); }
.hero-meta { position: absolute; z-index: 3; left: 18px; right: 16px; bottom: 17px; display: flex; align-items: center; justify-content: space-between; color: white; }
.hero-meta > span { display: flex; gap: 7px; align-items: center; font-size: 12px; font-weight: 700; }
.hero-meta button { border: 0; background: white; color: var(--green); border-radius: 999px; padding: 11px 14px 11px 16px; font-size: 13px; font-weight: 700; display: flex; align-items: center; gap: 4px; }
.setting-row { min-height: 66px; display: flex; align-items: center; gap: 13px; font-size: 15px; font-weight: 650; border-bottom: 1px solid var(--line); }
.setting-icon { width: 39px; height: 39px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 50%; background: var(--sage); color: var(--green); }
.setting-icon svg { width: 19px; }
.setting-row > span { flex: 1; line-height: 1.3; }
.interval-row select { min-width: 118px; max-width: 145px; height: 38px; padding: 0 30px 0 11px; border: 1px solid #cbd7cc; border-radius: 11px; color: var(--green); background: white; font-size: 12px; font-weight: 750; }
.switch { width: 48px; height: 28px; padding: 3px; border-radius: 30px; border: 0; background: #c7cec8; transition: .2s ease; }
.switch span { display: block; width: 22px; height: 22px; background: white; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.22); transition: transform .2s ease; }
.switch.on { background: var(--green); }
.switch.on span { transform: translateX(20px); }
.primary { border: 0; width: 100%; height: 56px; margin: 18px 0 24px; border-radius: 17px; background: var(--green); color: white; font-size: 16px; font-weight: 750; display: flex; align-items: center; justify-content: center; gap: 10px; box-shadow: 0 9px 24px rgba(20, 93, 50, .18); }
.primary svg { width: 21px; }
.primary:disabled, .hero-meta button:disabled { opacity: .65; }
.section-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
h2 { margin: 0; font-size: 21px; letter-spacing: -.6px; }
.section-heading button { border: 0; padding: 4px 0; color: var(--green); background: transparent; font-size: 13px; font-weight: 750; display: flex; align-items: center; }
.section-heading svg { width: 17px; }
.photo-rail { display: flex; gap: 10px; overflow-x: auto; padding: 2px 2px 4px; scrollbar-width: none; }
.photo-rail::-webkit-scrollbar { display: none; }
.photo-rail button { position: relative; width: 80px; height: 102px; padding: 0; border-radius: 13px; border: 2px solid transparent; background: #ddd; flex: 0 0 auto; overflow: hidden; }
.photo-rail button.selected { border-color: #73a17c; box-shadow: 0 0 0 2px #f8faf7 inset; }
.photo-rail img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-rail span { position: absolute; left: 7px; top: 7px; width: 23px; height: 23px; background: var(--green); color: white; border-radius: 50%; display: grid; place-items: center; }
.photo-rail span svg { width: 14px; }
.empty-collection { width: 100%; min-height: 84px; border: 1px dashed #b8c6ba; border-radius: 15px; background: #f1f5ef; color: #667069; display: flex; align-items: center; justify-content: center; gap: 9px; font-size: 13px; font-weight: 650; }
.empty-collection svg { width: 20px; color: var(--green); }
.hint { margin: 8px 0 12px; text-align: center; font-size: 11px; color: #7a837d; }
.settings-list { border-top: 1px solid var(--line); }
.settings-page > p { color: #667069; margin: 8px 0 24px; font-size: 14px; }
.language-setting { min-height: 68px; margin-bottom: 8px; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--line); }
.language-setting > div:nth-child(2) { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.language-setting strong { font-size: 15px; }
.language-setting span { color: #768078; font-size: 11px; }
.locale-select { min-width: 128px; max-width: 155px; height: 38px; padding: 0 28px 0 10px; border: 1px solid #cbd7cc; border-radius: 11px; color: var(--green); background: white; font-size: 12px; font-weight: 750; }
.language-toggle { padding: 3px; display: flex; border-radius: 12px; background: #e8eee7; }
.language-toggle button { width: 39px; height: 31px; padding: 0; border: 0; border-radius: 9px; color: #657068; background: transparent; font-size: 12px; font-weight: 800; }
.language-toggle button.active { color: white; background: var(--green); box-shadow: 0 2px 7px rgba(20,93,50,.2); }
.settings-page .settings-list { margin-top: 8px; }
.info { margin-top: 28px; padding: 20px; background: #eaf2e8; border-radius: 20px; }
.info h3 { color: var(--green); margin: 0 0 6px; font-size: 16px; }
.info p { margin: 0; font-size: 13px; line-height: 1.55; color: #526158; }
.immich-settings { margin-top: 24px; padding: 18px; border: 1px solid #d5dfd5; border-radius: 20px; background: white; box-shadow: 0 8px 24px rgba(24,56,35,.06); }
.immich-title { display: flex; gap: 12px; align-items: center; margin-bottom: 16px; }
.immich-title > span { width: 42px; height: 42px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 13px; color: white; background: var(--green); }
.immich-title svg { width: 22px; }
.immich-title h3 { margin: 0 0 3px; font-size: 18px; }
.immich-title p { margin: 0; color: #69736c; font-size: 12px; line-height: 1.4; }
.immich-field { display: block; margin-top: 13px; }
.immich-field > span { display: block; margin-bottom: 6px; color: #526158; font-size: 11px; font-weight: 750; }
.immich-field > div { position: relative; }
.immich-field svg { position: absolute; left: 12px; top: 50%; width: 17px; color: #63806b; transform: translateY(-50%); }
.immich-field input { width: 100%; height: 46px; padding: 0 12px; border: 1px solid #c7d4c9; border-radius: 12px; color: #18201b; background: #fbfcfa; font-size: 13px; }
.immich-field div input { padding-left: 38px; }
.immich-field input:focus { outline: 2px solid rgba(20,93,50,.18); border-color: var(--green); }
.immich-help, .immich-warning { margin: 7px 2px 0; color: #748078; font-size: 10px; line-height: 1.4; }
.immich-warning { padding: 8px 10px; border-radius: 9px; color: #795518; background: #fff4d7; }
.immich-connect, .immich-open { width: 100%; height: 48px; margin-top: 15px; border: 0; border-radius: 13px; display: flex; align-items: center; justify-content: center; gap: 8px; color: white; background: var(--green); font-size: 13px; font-weight: 800; }
.immich-connect:disabled, .immich-open:disabled, .immich-disconnect:disabled { opacity: .55; }
.immich-connect svg, .immich-open svg, .immich-disconnect svg { width: 18px; }
.immich-open svg:last-child { margin-left: auto; }
.immich-open { padding: 0 14px; }
.immich-connected { padding: 12px; border-radius: 12px; background: var(--sage); display: flex; flex-direction: column; gap: 3px; }
.immich-connected strong { color: var(--green); font-size: 12px; }
.immich-connected span { overflow: hidden; color: #647069; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.immich-disconnect { width: 100%; height: 40px; margin-top: 8px; border: 0; border-radius: 11px; color: #7a3434; background: #f5eaea; display: flex; align-items: center; justify-content: center; gap: 7px; font-size: 11px; font-weight: 750; }
.immich-header .import-selection { color: white; background: var(--green); }
.immich-browser { padding-bottom: max(24px, env(safe-area-inset-bottom)); }
.immich-album-filter { display: block; margin-bottom: 10px; }
.immich-album-filter > span { display: block; margin: 0 0 6px 2px; color: #6a756d; font-size: 10px; font-weight: 750; text-transform: uppercase; letter-spacing: .8px; }
.immich-album-filter select { width: 100%; height: 45px; padding: 0 38px 0 12px; border: 1px solid #c8d5ca; border-radius: 13px; color: var(--green); background: white; font-size: 13px; font-weight: 750; }
.immich-grid article { aspect-ratio: 1; }
.immich-placeholder { width: 100%; height: 100%; display: grid; place-items: center; color: #78907d; background: var(--sage); }
.immich-placeholder svg { width: 28px; }
.immich-import { position: sticky; z-index: 4; bottom: max(16px, env(safe-area-inset-bottom)); margin-bottom: 0; box-shadow: 0 10px 30px rgba(20,93,50,.3); }
.immich-import-progress { position: sticky; z-index: 4; bottom: max(16px, env(safe-area-inset-bottom)); margin-top: 18px; padding: 13px 15px; border-radius: 17px; color: white; background: var(--green); box-shadow: 0 10px 30px rgba(20,93,50,.3); }
.immich-import-progress > div { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 12px; font-weight: 750; }
.immich-import-progress progress { width: 100%; height: 7px; margin-top: 9px; border: 0; border-radius: 99px; overflow: hidden; background: rgba(255,255,255,.28); accent-color: white; }
.immich-import-progress progress::-webkit-progress-bar { background: rgba(255,255,255,.28); }
.immich-import-progress progress::-webkit-progress-value { border-radius: 99px; background: white; }
.immich-import-progress progress::-moz-progress-bar { border-radius: 99px; background: white; }
nav { position: fixed; z-index: 10; bottom: 0; left: 50%; transform: translateX(-50%); width: min(100%, 480px); height: calc(76px + env(safe-area-inset-bottom)); padding: 8px 34px env(safe-area-inset-bottom); background: rgba(248,250,247,.96); backdrop-filter: blur(16px); border-top: 1px solid var(--line); display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
nav button { border: 0; color: #657068; background: transparent; border-radius: 18px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 3px; font-size: 11px; font-weight: 650; }
nav button.active { color: var(--green); background: var(--sage); }
nav svg { width: 21px; }
.snackbar { position: fixed; z-index: 20; left: 50%; transform: translateX(-50%); bottom: calc(92px + env(safe-area-inset-bottom)); max-width: calc(100% - 40px); background: #26312a; color: white; border: 0; border-radius: 12px; padding: 13px 18px; font-size: 12px; box-shadow: 0 8px 26px rgba(0,0,0,.22); }
.gallery-page { padding-bottom: max(24px, env(safe-area-inset-bottom)); }
.selection-toolbar { min-height: 44px; margin: 0 0 11px; padding: 0 4px; display: flex; align-items: center; justify-content: space-between; gap: 12px; color: #6c766e; font-size: 12px; }
.selection-toolbar button { min-height: 36px; padding: 0 12px; border: 0; border-radius: 11px; color: var(--green); background: var(--sage); font-size: 12px; font-weight: 800; }
.selection-toolbar button:disabled { opacity: .55; }
.delete-selection { color: #fff; background: #8e2929; }
.gallery-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.gallery-grid article { position: relative; aspect-ratio: 3 / 4; overflow: hidden; border-radius: 14px; background: #e3e9e2; border: 2px solid transparent; }
.gallery-grid article.current { border-color: #73a17c; }
.gallery-grid article.chosen { border-color: var(--green); box-shadow: 0 0 0 2px rgba(20,93,50,.14); }
.gallery-image-button { width: 100%; height: 100%; padding: 0; border: 0; background: transparent; display: block; }
.gallery-image-button img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-grid article.chosen .gallery-image-button img { filter: brightness(.78); }
.selection-check { position: absolute; z-index: 2; top: 7px; right: 7px; width: 27px; height: 27px; display: grid; place-items: center; border: 2px solid rgba(255,255,255,.94); border-radius: 50%; color: transparent; background: rgba(28,38,31,.28); pointer-events: none; }
.selection-check svg { width: 15px; }
.gallery-grid article.chosen .selection-check { color: white; border-color: var(--green); background: var(--green); }
.delete-button { position: absolute; top: 7px; right: 7px; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%; display: grid; place-items: center; color: white; background: rgba(94, 20, 20, .86); box-shadow: 0 3px 12px rgba(0,0,0,.24); }
.delete-button svg { width: 16px; }
.delete-button:disabled { opacity: .5; }
.edit-button { position: absolute; z-index: 2; right: 7px; bottom: 7px; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%; display: grid; place-items: center; color: var(--green); background: rgba(255,255,255,.92); box-shadow: 0 3px 12px rgba(0,0,0,.2); }
.edit-button svg { width: 16px; }
.current-badge { position: absolute; left: 6px; bottom: 6px; display: flex; align-items: center; gap: 3px; padding: 5px 7px; border-radius: 99px; background: rgba(20, 93, 50, .9); color: white; font-size: 9px; font-weight: 750; }
.current-badge svg { width: 11px; height: 11px; }
.gallery-empty { min-height: 58vh; padding: 40px 18px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; color: #68736b; }
.gallery-empty > svg { width: 48px; height: 48px; padding: 11px; border-radius: 50%; color: var(--green); background: var(--sage); }
.gallery-empty h2 { margin-top: 16px; color: #26312a; }
.gallery-empty p { max-width: 290px; margin: 8px 0 2px; font-size: 13px; line-height: 1.5; }
.gallery-empty .primary { max-width: 260px; }
.gallery-status { padding: 28px 0; text-align: center; color: #6d776f; font-size: 13px; }
.gallery-load-sentinel { height: 1px; }
.load-more { width: 100%; height: 48px; margin-top: 18px; border: 1px solid #b9c8bb; border-radius: 15px; color: var(--green); background: white; font-weight: 750; }
.save-crop { background: var(--green); color: white; }
.crop-editor { padding-bottom: max(28px, env(safe-area-inset-bottom)); }
.phone-preview { position: relative; width: min(72vw, 270px); aspect-ratio: 9 / 19.5; margin: 0 auto 22px; overflow: hidden; border: 7px solid #202621; border-radius: 34px; background: #090b09; box-shadow: 0 18px 38px rgba(20,35,24,.22); }
.preview-image-frame { position: absolute; inset: 0; transform-origin: center; transition: transform .16s ease; }
.preview-image-frame.quarter-turn { inset: 26.923% -58.333%; }
.preview-image-frame > img { width: 100%; height: 100%; display: block; transition: object-position .16s ease; }
.phone-preview.interactive { touch-action: none; user-select: none; cursor: grab; }
.phone-preview.interactive:active { cursor: grabbing; }
.phone-preview.interactive .preview-image-frame, .phone-preview.interactive img { pointer-events: none; user-select: none; transition: none; }
.crop-grid { position: absolute; z-index: 2; inset: 0; pointer-events: none; opacity: .48; }
.crop-grid i { position: absolute; display: block; background: rgba(255,255,255,.72); box-shadow: 0 0 2px rgba(0,0,0,.38); }
.crop-grid i:nth-child(1), .crop-grid i:nth-child(2) { top: 0; bottom: 0; width: 1px; }
.crop-grid i:nth-child(1) { left: 33.333%; }
.crop-grid i:nth-child(2) { left: 66.666%; }
.crop-grid i:nth-child(3), .crop-grid i:nth-child(4) { left: 0; right: 0; height: 1px; }
.crop-grid i:nth-child(3) { top: 33.333%; }
.crop-grid i:nth-child(4) { top: 66.666%; }
.preview-clock { position: absolute; z-index: 2; top: 55px; left: 0; right: 0; color: white; text-align: center; font-size: 42px; line-height: 1; font-weight: 300; text-shadow: 0 2px 10px rgba(0,0,0,.45); pointer-events: none; }
.preview-clock span { display: block; margin-top: 7px; font-size: 10px; font-weight: 600; }
.crop-controls { padding: 17px; border: 1px solid var(--line); border-radius: 20px; background: white; }
.fit-toggle { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px; margin-bottom: 17px; border-radius: 13px; background: #edf2eb; }
.fit-toggle button { height: 38px; border: 0; border-radius: 10px; color: #68736b; background: transparent; font-size: 13px; font-weight: 750; }
.fit-toggle button.active { color: white; background: var(--green); box-shadow: 0 3px 9px rgba(20,93,50,.18); }
.rotate-image { width: 100%; height: 42px; margin-bottom: 15px; padding: 0 13px; border: 0; border-radius: 12px; color: var(--green); background: var(--sage); display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 750; }
.rotate-image svg { width: 17px; }
.rotate-image strong { margin-left: auto; }
.crop-controls label { display: block; margin-top: 13px; color: #58635b; font-size: 12px; font-weight: 700; }
.crop-controls label span { display: flex; justify-content: space-between; }
.crop-controls label strong { color: var(--green); }
.crop-controls input[type="range"] { width: 100%; margin: 8px 0 0; accent-color: var(--green); }
.direct-crop-heading { display: flex; align-items: center; justify-content: space-between; color: #526158; font-size: 13px; font-weight: 750; }
.direct-crop-heading span { display: flex; align-items: center; gap: 7px; }
.direct-crop-heading svg { width: 17px; }
.direct-crop-heading strong { color: var(--green); }
.direct-crop-help { margin: 5px 0 11px; color: #7a837d; font-size: 10px; line-height: 1.4; }
.zoom-control { display: grid !important; grid-template-columns: 40px 1fr; align-items: center; gap: 10px; margin: 13px 0 0 !important; }
.zoom-control > span { color: #526158; font-size: 12px; font-weight: 750; }
.zoom-control input { margin: 0 !important; }
.reset-crop { width: 100%; height: 42px; margin-top: 16px; border: 0; border-radius: 12px; color: #526158; background: #edf2eb; display: flex; justify-content: center; align-items: center; gap: 7px; font-size: 12px; font-weight: 750; }
.reset-crop svg { width: 16px; }
@media (min-width: 700px) { .app-shell { margin-top: 20px; min-height: calc(100vh - 40px); border-radius: 32px; overflow: hidden; } nav { bottom: 20px; border-radius: 0 0 32px 32px; } }
@media (max-height: 740px) { .hero { height: 235px; } }
@media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto !important; transition: none !important; } }