internal/web/assets/style.css
191 Zeilen · 8.0 KB · CSS
| 1 | /* TV-Wall Webinterface - bewusst ohne externe Abhaengigkeiten, da der Pi als |
| 2 | Access Point keine Internetverbindung hat. */ |
| 3 | |
| 4 | :root { |
| 5 | --bg: #0d1117; |
| 6 | --bg-card: #161c26; |
| 7 | --bg-soft: #1e2632; |
| 8 | --line: #2a3442; |
| 9 | --fg: #e7edf5; |
| 10 | --fg-dim: #94a3b8; |
| 11 | --accent: #52b6ff; |
| 12 | --accent-dark: #1d84cc; |
| 13 | --danger: #ff6b6b; |
| 14 | --ok: #4ade80; |
| 15 | --radius: 14px; |
| 16 | } |
| 17 | |
| 18 | * { box-sizing: border-box; } |
| 19 | |
| 20 | html { -webkit-text-size-adjust: 100%; } |
| 21 | |
| 22 | body { |
| 23 | margin: 0; |
| 24 | padding: 0 0 3rem; |
| 25 | background: var(--bg); |
| 26 | color: var(--fg); |
| 27 | font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; |
| 28 | } |
| 29 | |
| 30 | h1, h2 { margin: 0; font-weight: 650; } |
| 31 | h1 { font-size: 1.15rem; letter-spacing: .02em; } |
| 32 | h2 { font-size: .95rem; text-transform: uppercase; letter-spacing: .08em; color: var(--fg-dim); } |
| 33 | |
| 34 | /* ---------- Kopfzeile ---------- */ |
| 35 | .top { |
| 36 | position: sticky; top: 0; z-index: 20; |
| 37 | display: flex; flex-wrap: wrap; gap: .75rem; |
| 38 | align-items: center; justify-content: space-between; |
| 39 | padding: .85rem 1rem; |
| 40 | padding-top: max(.85rem, env(safe-area-inset-top)); |
| 41 | background: rgba(13, 17, 23, .92); |
| 42 | backdrop-filter: blur(8px); |
| 43 | border-bottom: 1px solid var(--line); |
| 44 | } |
| 45 | .brand { display: flex; align-items: center; gap: .7rem; } |
| 46 | .logo { |
| 47 | width: 34px; height: 34px; border-radius: 9px; flex: none; |
| 48 | background: linear-gradient(150deg, var(--accent), var(--accent-dark)); |
| 49 | box-shadow: 0 0 0 1px rgba(255,255,255,.08) inset; |
| 50 | } |
| 51 | .sub { margin: 0; font-size: .78rem; color: var(--fg-dim); } |
| 52 | .now { |
| 53 | display: flex; align-items: center; gap: .5rem; |
| 54 | font-size: .82rem; color: var(--fg-dim); |
| 55 | max-width: 100%; overflow: hidden; |
| 56 | } |
| 57 | .now span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| 58 | .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--fg-dim); flex: none; } |
| 59 | .dot.on { background: var(--ok); box-shadow: 0 0 8px rgba(74,222,128,.7); } |
| 60 | .dot.err { background: var(--danger); } |
| 61 | |
| 62 | /* ---------- Layout ---------- */ |
| 63 | main { max-width: 780px; margin: 0 auto; padding: 1rem; display: grid; gap: 1rem; } |
| 64 | .card { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem; } |
| 65 | .card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; } |
| 66 | .counter { font-size: .8rem; color: var(--fg-dim); } |
| 67 | .hint { margin: .5rem 0 .9rem; font-size: .8rem; color: var(--fg-dim); } |
| 68 | |
| 69 | /* ---------- Upload ---------- */ |
| 70 | /* Nicht display:none - sonst laesst sich das Feld auf manchen Browsern nicht |
| 71 | ueber das Label ansprechen. */ |
| 72 | .visually-hidden { |
| 73 | position: absolute; width: 1px; height: 1px; |
| 74 | padding: 0; margin: -1px; overflow: hidden; |
| 75 | clip-path: inset(50%); white-space: nowrap; border: 0; |
| 76 | } |
| 77 | |
| 78 | .drop { |
| 79 | margin-top: .8rem; |
| 80 | display: flex; flex-direction: column; align-items: center; justify-content: center; |
| 81 | gap: .4rem; text-align: center; |
| 82 | min-height: 140px; padding: 1.2rem; |
| 83 | border: 2px dashed var(--line); border-radius: var(--radius); |
| 84 | background: var(--bg-soft); cursor: pointer; |
| 85 | transition: border-color .15s, background .15s; |
| 86 | } |
| 87 | .drop:active, .drop.over { border-color: var(--accent); background: #1b2939; } |
| 88 | .drop-icon { font-size: 1.8rem; color: var(--accent); line-height: 1; } |
| 89 | .drop-text { font-size: .92rem; color: var(--fg-dim); } |
| 90 | .drop-text b { color: var(--fg); font-weight: 600; } |
| 91 | .drop-hint { font-size: .74rem; color: var(--fg-dim); opacity: .75; } |
| 92 | |
| 93 | .progress { display: flex; align-items: center; gap: .7rem; margin-top: .8rem; } |
| 94 | .bar { flex: 1; height: 8px; border-radius: 99px; background: var(--bg-soft); overflow: hidden; } |
| 95 | .fill { height: 100%; width: 0; background: linear-gradient(90deg, var(--accent-dark), var(--accent)); transition: width .2s; } |
| 96 | .progress-label { font-size: .78rem; color: var(--fg-dim); min-width: 3.2rem; text-align: right; } |
| 97 | |
| 98 | /* ---------- Buttons ---------- */ |
| 99 | .controls { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .8rem; } |
| 100 | .btn { |
| 101 | flex: 1 1 auto; min-width: 6.5rem; min-height: 44px; |
| 102 | padding: .55rem .9rem; |
| 103 | border: 1px solid var(--line); border-radius: 10px; |
| 104 | background: var(--bg-soft); color: var(--fg); |
| 105 | font-size: .9rem; font-weight: 550; cursor: pointer; |
| 106 | transition: background .12s, border-color .12s; |
| 107 | } |
| 108 | .btn:hover { border-color: var(--accent); } |
| 109 | .btn:active { background: #253242; } |
| 110 | .btn.ghost { background: transparent; color: var(--fg-dim); } |
| 111 | .btn.small { flex: 0 0 auto; min-width: auto; min-height: 38px; font-size: .82rem; } |
| 112 | .btn[disabled] { opacity: .45; cursor: default; } |
| 113 | |
| 114 | /* ---------- Einstellungen ---------- */ |
| 115 | .settings { display: flex; flex-wrap: wrap; align-items: center; gap: .9rem; margin-top: 1rem; |
| 116 | padding-top: 1rem; border-top: 1px solid var(--line); } |
| 117 | .field { display: flex; flex-direction: column; gap: .3rem; font-size: .82rem; color: var(--fg-dim); } |
| 118 | .input-unit { display: flex; align-items: center; gap: .4rem; } |
| 119 | .input-unit span { font-size: .8rem; } |
| 120 | input[type="number"] { |
| 121 | width: 5.5rem; min-height: 40px; padding: .35rem .6rem; |
| 122 | border: 1px solid var(--line); border-radius: 9px; |
| 123 | background: var(--bg-soft); color: var(--fg); font-size: .95rem; |
| 124 | } |
| 125 | .switch { display: flex; align-items: center; gap: .5rem; font-size: .82rem; color: var(--fg-dim); cursor: pointer; } |
| 126 | .switch input { width: 20px; height: 20px; accent-color: var(--accent); } |
| 127 | |
| 128 | /* ---------- Playliste ---------- */ |
| 129 | .list { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; } |
| 130 | .item { |
| 131 | display: grid; |
| 132 | grid-template-columns: auto auto 84px 1fr auto; |
| 133 | align-items: center; gap: .7rem; |
| 134 | padding: .5rem; border: 1px solid var(--line); border-radius: 12px; |
| 135 | background: var(--bg-soft); |
| 136 | } |
| 137 | .item.playing { border-color: var(--accent); box-shadow: 0 0 0 1px rgba(82,182,255,.25); } |
| 138 | .item.dragging { opacity: .4; } |
| 139 | .item.drop-target { border-color: var(--accent); border-style: dashed; } |
| 140 | .grip { cursor: grab; padding: .4rem .2rem; color: var(--fg-dim); font-size: 1.1rem; line-height: 1; touch-action: none; user-select: none; } |
| 141 | .grip:active { cursor: grabbing; } |
| 142 | |
| 143 | /* Haken: bestimmt, ob der Eintrag auf der Wand erscheint */ |
| 144 | .toggle { display: grid; place-items: center; padding: .2rem; cursor: pointer; } |
| 145 | .toggle input { width: 22px; height: 22px; accent-color: var(--accent); cursor: pointer; } |
| 146 | .item.off { opacity: .55; } |
| 147 | .item.off .thumb { filter: grayscale(1); } |
| 148 | .badge.off { background: #3a2a1e; color: #e0b088; } |
| 149 | .thumb { |
| 150 | width: 84px; height: 56px; border-radius: 8px; object-fit: cover; |
| 151 | background: #0b1220; display: block; |
| 152 | } |
| 153 | .meta { min-width: 0; } |
| 154 | .name { font-size: .88rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| 155 | .tags { display: flex; gap: .4rem; align-items: center; margin-top: .2rem; font-size: .72rem; color: var(--fg-dim); } |
| 156 | .badge { padding: .1rem .4rem; border-radius: 5px; background: #223247; color: #9dc7ee; font-size: .68rem; letter-spacing: .03em; } |
| 157 | .badge.video { background: #33244a; color: #c6a8f0; } |
| 158 | .actions { display: flex; gap: .25rem; } |
| 159 | .icon-btn { |
| 160 | width: 38px; height: 38px; display: grid; place-items: center; |
| 161 | border: 1px solid transparent; border-radius: 9px; |
| 162 | background: transparent; color: var(--fg-dim); |
| 163 | font-size: 1rem; cursor: pointer; |
| 164 | } |
| 165 | .icon-btn:hover { background: #22303f; color: var(--fg); } |
| 166 | .icon-btn.del:hover { color: var(--danger); } |
| 167 | .empty { color: var(--fg-dim); font-size: .85rem; text-align: center; padding: 1.2rem 0; } |
| 168 | |
| 169 | .foot { text-align: center; font-size: .74rem; color: var(--fg-dim); opacity: .8; } |
| 170 | |
| 171 | /* ---------- Meldungen ---------- */ |
| 172 | .toasts { |
| 173 | position: fixed; left: 50%; transform: translateX(-50%); |
| 174 | bottom: max(1rem, env(safe-area-inset-bottom)); z-index: 50; |
| 175 | display: grid; gap: .4rem; width: min(90vw, 460px); |
| 176 | } |
| 177 | .toast { |
| 178 | padding: .6rem .9rem; border-radius: 10px; |
| 179 | background: #223142; border: 1px solid var(--line); |
| 180 | color: var(--fg); font-size: .85rem; |
| 181 | box-shadow: 0 8px 24px rgba(0,0,0,.45); |
| 182 | animation: pop .2s ease-out; |
| 183 | } |
| 184 | .toast.err { background: #3a2028; border-color: #6b2b36; } |
| 185 | .toast.ok { background: #1c3527; border-color: #2f6b47; } |
| 186 | @keyframes pop { from { opacity: 0; transform: translateY(8px); } } |
| 187 | |
| 188 | @media (max-width: 420px) { |
| 189 | .item { grid-template-columns: auto auto 64px 1fr auto; } |
| 190 | .thumb { width: 64px; height: 44px; } |
| 191 | } |