Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon
Auth (app-modus):
- Roller admin/standard. Admin oppretter/sletter kontoer, resetter passord,
endrer roller (konto-modal). Eksisterende brukere → admin ved migrering;
bootstrap-bruker via proxy-bypass → admin. Siste admin vernet.
- Tilbakekalling via per-bruker epoke i tokenet: passordbytte, admin-reset,
«Logg ut alle enheter» og sletting dreper alle aktive sesjoner. Token-format
endret (3- → 4-delt) — alle logges ut én gang ved oppgradering.
Dagsplan: søkbar/velgbar planliste («📋 Planer») avledet fra planIndex —
finn plan på navn/dato/person uten å gjette dato.
GUI: login-neon trukket inn i hovedappen (header/knapper/KPI-kanter), og
login-siden fikk mer tech (HUD-hjørner, glitch-tittel, scanlines).
40 integrasjonstester (6 nye), alle grønne. README + CLAUDE.md oppdatert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
f6268440d9
commit
3f69cd4248
9 changed files with 518 additions and 36 deletions
|
|
@ -47,21 +47,54 @@
|
|||
.card {
|
||||
position: relative; z-index: 2; width: 100%; max-width: 420px;
|
||||
background: rgba(10,14,22,0.72); backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(79,230,255,0.25); border-radius: 14px; padding: 34px 30px 28px;
|
||||
box-shadow: 0 0 0 1px rgba(255,92,244,0.08), 0 24px 70px rgba(0,0,0,0.6), 0 0 60px rgba(79,230,255,0.12);
|
||||
border: 1px solid rgba(79,230,255,0.35); border-radius: 14px; padding: 34px 30px 28px;
|
||||
box-shadow: 0 0 0 1px rgba(255,92,244,0.1), 0 24px 70px rgba(0,0,0,0.6), 0 0 60px rgba(79,230,255,0.12);
|
||||
animation: borderpulse 3.6s ease-in-out infinite;
|
||||
}
|
||||
.prompt { font-family: var(--mono); font-size: 12px; color: var(--cyan); letter-spacing: 1px; margin-bottom: 8px; opacity: 0.85; }
|
||||
@keyframes borderpulse {
|
||||
0%,100% { border-color: rgba(79,230,255,0.35); box-shadow: 0 0 0 1px rgba(255,92,244,0.1), 0 24px 70px rgba(0,0,0,0.6), 0 0 50px rgba(79,230,255,0.12); }
|
||||
50% { border-color: rgba(79,230,255,0.6); box-shadow: 0 0 0 1px rgba(255,92,244,0.18), 0 24px 70px rgba(0,0,0,0.6), 0 0 80px rgba(79,230,255,0.28); }
|
||||
}
|
||||
/* Tynn scanline over kortet + svak CRT-støy */
|
||||
.card::before {
|
||||
content: ""; position: absolute; inset: 0; border-radius: 14px; pointer-events: none;
|
||||
background: repeating-linear-gradient(0deg, transparent 0, transparent 2px, rgba(79,230,255,0.025) 3px, transparent 4px);
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
/* HUD-hjørner */
|
||||
.corner { position: absolute; width: 18px; height: 18px; border: 2px solid var(--cyan);
|
||||
filter: drop-shadow(0 0 4px var(--cyan)); pointer-events: none; }
|
||||
.corner.tl { top: -1px; left: -1px; border-right: 0; border-bottom: 0; border-top-left-radius: 14px; }
|
||||
.corner.tr { top: -1px; right: -1px; border-left: 0; border-bottom: 0; border-top-right-radius: 14px; border-color: var(--magenta); filter: drop-shadow(0 0 4px var(--magenta)); }
|
||||
.corner.bl { bottom: -1px; left: -1px; border-right: 0; border-top: 0; border-bottom-left-radius: 14px; border-color: var(--magenta); filter: drop-shadow(0 0 4px var(--magenta)); }
|
||||
.corner.br { bottom: -1px; right: -1px; border-left: 0; border-top: 0; border-bottom-right-radius: 14px; }
|
||||
|
||||
.hud { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||
.prompt { font-family: var(--mono); font-size: 12px; color: var(--cyan); letter-spacing: 1px; opacity: 0.85; }
|
||||
.prompt::before { content: "› "; }
|
||||
.lock { font-family: var(--mono); font-size: 10px; letter-spacing: 1.5px; color: var(--magenta);
|
||||
border: 1px solid rgba(255,92,244,0.4); border-radius: 4px; padding: 3px 7px;
|
||||
text-shadow: 0 0 8px rgba(255,92,244,0.7); animation: lockblink 2.4s steps(1) infinite; }
|
||||
@keyframes lockblink { 0%,70%,100% { opacity: 1; } 78%,88% { opacity: 0.3; } }
|
||||
h1 {
|
||||
font-size: 40px; font-weight: 800; letter-spacing: 1px; line-height: 1;
|
||||
color: #eafcff; text-shadow: 0 0 8px var(--cyan), 0 0 22px rgba(79,230,255,0.7), 0 0 40px rgba(79,230,255,0.4);
|
||||
animation: flicker 4.5s infinite;
|
||||
font-size: 42px; font-weight: 800; letter-spacing: 1px; line-height: 1; position: relative;
|
||||
color: #eafcff;
|
||||
text-shadow: -1.5px 0 rgba(255,92,244,0.55), 1.5px 0 rgba(79,230,255,0.55),
|
||||
0 0 8px var(--cyan), 0 0 22px rgba(79,230,255,0.75), 0 0 44px rgba(79,230,255,0.45);
|
||||
animation: flicker 4.5s infinite, glitch 7s steps(1) infinite;
|
||||
}
|
||||
h1 .x { color: var(--magenta); text-shadow: 0 0 8px var(--magenta), 0 0 22px rgba(255,92,244,0.7), 0 0 40px rgba(255,92,244,0.4); }
|
||||
h1 .x { color: var(--magenta); text-shadow: 0 0 8px var(--magenta), 0 0 22px rgba(255,92,244,0.75), 0 0 44px rgba(255,92,244,0.45); }
|
||||
@keyframes flicker {
|
||||
0%,18%,22%,25%,53%,57%,100% { opacity: 1; }
|
||||
20%,24%,55% { opacity: 0.72; }
|
||||
}
|
||||
/* Sporadisk kromatisk «glitch»-forskyvning */
|
||||
@keyframes glitch {
|
||||
0%,90%,100% { transform: translate(0,0); text-shadow: -1.5px 0 rgba(255,92,244,0.55), 1.5px 0 rgba(79,230,255,0.55), 0 0 8px var(--cyan), 0 0 22px rgba(79,230,255,0.75); }
|
||||
91% { transform: translate(2px,-1px); text-shadow: -3px 0 var(--magenta), 3px 0 var(--cyan), 0 0 26px rgba(79,230,255,0.9); }
|
||||
93% { transform: translate(-2px,1px); text-shadow: 3px 0 var(--magenta), -3px 0 var(--cyan), 0 0 26px rgba(79,230,255,0.9); }
|
||||
95% { transform: translate(1px,0); }
|
||||
}
|
||||
.teaser { color: var(--dim); font-size: 13.5px; line-height: 1.6; margin: 14px 0 22px; }
|
||||
.teaser b { color: var(--text); font-weight: 600; }
|
||||
.ticker { font-family: var(--mono); font-size: 11px; color: var(--green);
|
||||
|
|
@ -87,7 +120,8 @@
|
|||
background: linear-gradient(90deg, var(--cyan), #7fe9ff);
|
||||
box-shadow: 0 0 22px rgba(79,230,255,0.5); transition: all 0.18s;
|
||||
}
|
||||
button:hover { box-shadow: 0 0 34px rgba(79,230,255,0.85); transform: translateY(-1px); }
|
||||
button:hover { box-shadow: 0 0 40px rgba(79,230,255,1); transform: translateY(-1px); letter-spacing: 1.5px; }
|
||||
button::after { content: ""; }
|
||||
button:disabled { opacity: 0.6; cursor: wait; }
|
||||
.msg { min-height: 1.2em; font-size: 13px; color: var(--magenta); font-family: var(--mono);
|
||||
text-shadow: 0 0 10px rgba(255,92,244,0.5); text-align: center; }
|
||||
|
|
@ -105,7 +139,12 @@
|
|||
<div class="scan"></div>
|
||||
|
||||
<div class="card">
|
||||
<div class="prompt">network-engineer@nms:~$ ssh netops</div>
|
||||
<span class="corner tl"></span><span class="corner tr"></span>
|
||||
<span class="corner bl"></span><span class="corner br"></span>
|
||||
<div class="hud">
|
||||
<div class="prompt">network-engineer@nms:~$ ssh netops</div>
|
||||
<span class="lock">● LOCKED</span>
|
||||
</div>
|
||||
<h1>NetOps<span class="x">//</span></h1>
|
||||
<p class="teaser">
|
||||
Bak denne porten <b>puster nettet</b>. Pakker flyr, rutene konvergerer,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue