643 lines
13 KiB
CSS
Executable File
643 lines
13 KiB
CSS
Executable File
/* app.css - Design System Premium untuk SpeedTest */
|
|
|
|
/* Impor font Roboto asli proyek */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
font-display: swap;
|
|
src: url("../fonts/roboto-v30-latin-regular.eot");
|
|
src: local(""),
|
|
url("../fonts/roboto-v30-latin-regular.eot?#iefix") format("embedded-opentype"),
|
|
url("../fonts/roboto-v30-latin-regular.woff2") format("woff2"),
|
|
url("../fonts/roboto-v30-latin-regular.woff") format("woff"),
|
|
url("../fonts/roboto-v30-latin-regular.ttf") format("truetype"),
|
|
url("../fonts/roboto-v30-latin-regular.svg#Roboto") format("svg");
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
font-display: swap;
|
|
src: url("assets/fonts/roboto-v30-latin-500.eot");
|
|
src: local(""),
|
|
url("assets/fonts/roboto-v30-latin-500.eot?#iefix") format("embedded-opentype"),
|
|
url("assets/fonts/roboto-v30-latin-500.woff2") format("woff2"),
|
|
url("assets/fonts/roboto-v30-latin-500.woff") format("woff"),
|
|
url("assets/fonts/roboto-v30-latin-500.ttf") format("truetype"),
|
|
url("assets/fonts/roboto-v30-latin-500.svg#Roboto") format("svg");
|
|
}
|
|
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
background: radial-gradient(circle at 50% 50%, #F8FAFC 0%, #E2E8F0 100%);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
transition: background 0.4s ease;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
html {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
|
|
/* Container Utama */
|
|
.app-layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
max-width: 960px;
|
|
padding: 24px;
|
|
box-sizing: border-box;
|
|
gap: 24px;
|
|
}
|
|
|
|
/* Header Dashboard */
|
|
.app-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
animation: fadeInDown 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
}
|
|
|
|
.header-logo-img {
|
|
width: 40px;
|
|
height: 40px;
|
|
object-fit: contain;
|
|
filter: drop-shadow(0 4px 12px rgba(79, 172, 254, 0.3));
|
|
}
|
|
|
|
.header-text {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.header-text h1 {
|
|
margin: 0;
|
|
font-family: 'Outfit', sans-serif;
|
|
font-size: 24px;
|
|
font-weight: 800;
|
|
letter-spacing: -0.02em;
|
|
color: #0F172A;
|
|
}
|
|
|
|
.header-badge {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
color: #2563EB;
|
|
background: rgba(37, 99, 235, 0.08);
|
|
padding: 4px 10px;
|
|
border-radius: 12px;
|
|
border: 1px solid rgba(37, 99, 235, 0.15);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.client-ip-container {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: calc(50% - 150px);
|
|
transform: translateX(-50%);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: #64748B;
|
|
z-index: 20;
|
|
pointer-events: none;
|
|
white-space: nowrap;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
@media only screen and (orientation: portrait) {
|
|
.client-ip-container {
|
|
left: 50%;
|
|
top: 12px;
|
|
}
|
|
}
|
|
|
|
.client-ip-container span#client-ip-text {
|
|
color: #0EA5E9;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* Card Wrapper Speed Test */
|
|
.app-card {
|
|
position: relative;
|
|
width: 100%;
|
|
background: rgba(255, 255, 255, 0.7);
|
|
backdrop-filter: blur(24px) saturate(180%);
|
|
-webkit-backdrop-filter: blur(24px) saturate(180%);
|
|
border: 1px solid rgba(255, 255, 255, 0.4);
|
|
border-radius: 32px;
|
|
box-shadow:
|
|
0 20px 40px -15px rgba(15, 23, 42, 0.05),
|
|
0 0 80px rgba(15, 23, 42, 0.02),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.6);
|
|
padding: 40px;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
animation: scaleIn 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
}
|
|
|
|
.app-card:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow:
|
|
0 30px 60px -20px rgba(15, 23, 42, 0.08),
|
|
0 0 100px rgba(15, 23, 42, 0.03),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.8);
|
|
border-color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
/* SVG App Sizing */
|
|
.openSpeedtestApp {
|
|
width: 100%;
|
|
max-width: 600px;
|
|
height: auto;
|
|
aspect-ratio: 586 / 346;
|
|
display: none;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Spinner Loader */
|
|
.spinner {
|
|
position: absolute;
|
|
display: flex;
|
|
gap: 8px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 99;
|
|
}
|
|
|
|
.spinner>div {
|
|
width: 12px;
|
|
height: 12px;
|
|
background: linear-gradient(135deg, #00F2FE 0%, #4FACFE 100%);
|
|
border-radius: 50%;
|
|
animation: bounceDelay 1.4s infinite ease-in-out both;
|
|
}
|
|
|
|
.spinner .bounce1 {
|
|
animation-delay: -0.32s;
|
|
}
|
|
|
|
.spinner .bounce2 {
|
|
animation-delay: -0.16s;
|
|
}
|
|
|
|
/* ==========================================
|
|
KONTROL TAMPILAN ELEMENT (PENTING!)
|
|
Menyembunyikan komponen SVG secara default
|
|
agar tidak bertumpuk.
|
|
========================================== */
|
|
#UI-Desk {
|
|
display: none;
|
|
}
|
|
|
|
#UI-Mob {
|
|
display: none;
|
|
}
|
|
|
|
#ipMob {
|
|
display: none;
|
|
}
|
|
|
|
#ipDesk {
|
|
display: none;
|
|
}
|
|
|
|
#upSymbolDesk {
|
|
display: none;
|
|
}
|
|
|
|
#downSymbolDesk {
|
|
display: none;
|
|
}
|
|
|
|
#upSymbolMob {
|
|
display: none;
|
|
}
|
|
|
|
#downSymbolMob {
|
|
display: none;
|
|
}
|
|
|
|
.ConnectError {
|
|
display: none;
|
|
}
|
|
|
|
/* ==========================================
|
|
TYPOGRAPHY DI DALAM SVG (ASLI ROBOTO)
|
|
Menggunakan font-family dan ukuran asli
|
|
agar layout & koordinat SVG tidak berantakan
|
|
========================================== */
|
|
.oDoLive-Speed {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 20px !important;
|
|
font-weight: 500 !important;
|
|
fill: #500516 !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
.oDoLive-Status {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 10px !important;
|
|
font-weight: 500 !important;
|
|
fill: #94A3B8 !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
.rtextnum {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 23px !important;
|
|
font-weight: 500 !important;
|
|
fill: #0F172A !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
.rtext {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 10px !important;
|
|
font-weight: 400 !important;
|
|
fill: #64748B !important;
|
|
}
|
|
|
|
.rtextmbms {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 12px !important;
|
|
font-weight: 500 !important;
|
|
fill: #94A3B8 !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
.oDo-Meter {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 16.63px !important;
|
|
font-weight: 500 !important;
|
|
fill: #94A3B8 !important;
|
|
}
|
|
|
|
.oDoTop-Speed {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 16.96px !important;
|
|
font-weight: 500 !important;
|
|
fill: #94A3B8 !important;
|
|
text-anchor: end !important;
|
|
}
|
|
|
|
.jitter-Mob {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 9px !important;
|
|
font-weight: 500 !important;
|
|
fill: #64748B !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
.buttonTxt {
|
|
font-family: 'Roboto', sans-serif !important;
|
|
font-size: 40px !important;
|
|
font-weight: 500 !important;
|
|
fill: #ffffff !important;
|
|
text-anchor: middle !important;
|
|
}
|
|
|
|
/* ==========================================
|
|
ESTETIKA DAN DESAIN ELEMEN SVG
|
|
========================================== */
|
|
.Cards {
|
|
fill: rgba(248, 250, 252, 0.8) !important;
|
|
stroke: rgba(226, 232, 240, 0.8) !important;
|
|
stroke-width: 1.5px !important;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.uiBg {
|
|
fill: #94A3B8 !important;
|
|
}
|
|
|
|
.Symbol {
|
|
fill: url(#gradient) !important;
|
|
}
|
|
|
|
.progressbg {
|
|
stroke: #E2E8F0 !important;
|
|
stroke-width: 8px !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-dasharray: 400 !important;
|
|
stroke-dashoffset: 0;
|
|
}
|
|
|
|
.intro-Progress {
|
|
stroke: #4FACFE !important;
|
|
stroke-width: 8px !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-dasharray: 400 !important;
|
|
stroke-dashoffset: 0;
|
|
}
|
|
|
|
.progressElmstart {
|
|
stroke: #4FACFE !important;
|
|
stroke-width: 8px !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-dasharray: 400 !important;
|
|
stroke-dashoffset: 0;
|
|
display: block !important;
|
|
}
|
|
|
|
.main-Gaugebg {
|
|
fill: none !important;
|
|
stroke: #E2E8F0 !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-width: 22px !important;
|
|
stroke-dasharray: 681 !important;
|
|
}
|
|
|
|
.main-GaugeBlue {
|
|
fill: none !important;
|
|
stroke: url(#gradient) !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-width: 22px !important;
|
|
stroke-dasharray: 681 !important;
|
|
stroke-opacity: 0;
|
|
}
|
|
|
|
.main-GaugeWhite {
|
|
fill: none !important;
|
|
stroke: rgb(255, 255, 255) !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-width: 15px !important;
|
|
stroke-dasharray: 0, 681 !important;
|
|
stroke-dashoffset: 1;
|
|
stroke-opacity: 0;
|
|
}
|
|
|
|
.deskStart {
|
|
fill: none !important;
|
|
stroke: url(#gradient) !important;
|
|
stroke-linecap: round !important;
|
|
stroke-linejoin: round !important;
|
|
stroke-dasharray: 681 !important;
|
|
}
|
|
|
|
/* Button & Interactive elements */
|
|
.startButton {
|
|
fill: url(#gradient) !important;
|
|
cursor: pointer;
|
|
filter: drop-shadow(0 8px 20px rgba(0, 242, 254, 0.25));
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
}
|
|
|
|
.startButton:hover {
|
|
filter: drop-shadow(0 12px 28px rgba(0, 242, 254, 0.45));
|
|
opacity: 0.95;
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
.startButton:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
.Startsettings {
|
|
cursor: pointer;
|
|
opacity: 0.3;
|
|
transition: all 0.3s ease;
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
}
|
|
|
|
.Startsettings:hover {
|
|
opacity: 0.9;
|
|
transform: rotate(30deg);
|
|
}
|
|
|
|
/* Restyle logo di SVG menggunakan CSS */
|
|
svg [style*="fill: #3da6ff"] {
|
|
fill: #2563EB !important;
|
|
/* Modern Royal Blue */
|
|
}
|
|
|
|
svg [style*="fill: #4d4d4d"] {
|
|
fill: #0F172A !important;
|
|
/* Slate 900 */
|
|
}
|
|
|
|
/* Dark mode toggle */
|
|
.darkmode {
|
|
fill: #94A3B8 !important;
|
|
transition: all 0.3s ease;
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
}
|
|
|
|
.darkmode:hover {
|
|
fill: #2563EB !important;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
#daymode {
|
|
margin-right: 40px;
|
|
}
|
|
|
|
/* Footer & Credits */
|
|
.Credits {
|
|
margin-top: 10px;
|
|
text-align: center;
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 13px;
|
|
color: #64748B;
|
|
animation: fadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
animation-delay: 0.2s;
|
|
}
|
|
|
|
.Credits p {
|
|
margin: 4px 0;
|
|
}
|
|
|
|
.Credits a {
|
|
text-decoration: none;
|
|
color: #2563EB;
|
|
font-weight: 600;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.Credits a:hover {
|
|
color: #1d4ed8;
|
|
}
|
|
|
|
.copyright {
|
|
font-size: 11px;
|
|
color: #94A3B8;
|
|
}
|
|
|
|
/* Media Queries Responsif */
|
|
.Mobile,
|
|
.Desktop {
|
|
visibility: hidden;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
|
|
@media only screen and (orientation: landscape) {
|
|
.Mobile {
|
|
visibility: hidden;
|
|
display: none;
|
|
}
|
|
|
|
.Desktop {
|
|
visibility: visible;
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
@media only screen and (orientation: portrait) {
|
|
.app-card {
|
|
padding: 24px;
|
|
border-radius: 24px;
|
|
}
|
|
|
|
.openSpeedtestApp {
|
|
width: 100%;
|
|
max-width: 320px;
|
|
aspect-ratio: 295.9 / 363.3;
|
|
}
|
|
|
|
.Mobile {
|
|
visibility: visible;
|
|
display: block;
|
|
}
|
|
|
|
.Desktop {
|
|
visibility: hidden;
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
@media only screen and (max-width: 360px) {
|
|
.Credits {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Animasi */
|
|
@keyframes bounceDelay {
|
|
|
|
0%,
|
|
80%,
|
|
100% {
|
|
transform: scale(0);
|
|
opacity: 0.3;
|
|
}
|
|
|
|
40% {
|
|
transform: scale(1.0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInDown {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-20px);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
/* Tombol Refresh / Uji Lagi */
|
|
.refresh-btn {
|
|
display: none;
|
|
/* Disembunyikan secara default */
|
|
background: linear-gradient(135deg, #00F2FE 0%, #4FACFE 100%);
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 28px;
|
|
font-family: 'Outfit', 'Inter', sans-serif;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
border-radius: 50px;
|
|
cursor: pointer;
|
|
box-shadow: 0 8px 20px rgba(0, 242, 254, 0.25);
|
|
align-items: center;
|
|
gap: 10px;
|
|
z-index: 10;
|
|
margin-top: 10px;
|
|
margin-bottom: -6px;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
}
|
|
|
|
.refresh-btn:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 12px 28px rgba(0, 242, 254, 0.45);
|
|
filter: brightness(1.05);
|
|
}
|
|
|
|
.refresh-btn:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.refresh-btn svg {
|
|
transition: transform 0.4s ease;
|
|
}
|
|
|
|
.refresh-btn:hover svg {
|
|
transform: rotate(180deg);
|
|
} |