Push Tracker
ria-ran--sim-drop/portal/css/style.css
A ashkan@beigi.net 8672b0de6b Add Phase-1 eSIM provisioning implementation
Full working closed-loop eSIM provisioning stack (spec in claude.md / plan/):
Flask API, SQLite subscriber store, credential/profile generator, Open5GS
and free5gc core adapters, captive portal, operational scripts, systemd
units, network configs, and a 44-test suite.

Profile generation currently returns a mock JSON profile; real SGP.22
generation via pySim is the planned Phase-2 upgrade.

Fixes two bugs found while getting the suite green:
- generate_imsi hardcoded a 10-digit MSIN, producing 16-digit IMSIs for a
  3-digit MNC; MSIN length is now 15 - len(mcc) - len(mnc).
- check_rate_limit compared timestamps as strings across mismatched formats
  (SQLite CURRENT_TIMESTAMP vs Python isoformat); both sides now normalized
  via SQLite datetime() so the window check is chronologically correct.

Add .gitignore for venv, caches, runtime config.yaml, and databases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 05:56:31 +00:00

168 lines
2.5 KiB
CSS

*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, sans-serif;
background: #1a1a2e;
color: #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1rem;
}
.card {
background: #16213e;
border-radius: 16px;
padding: 2.5rem 2rem;
max-width: 420px;
width: 100%;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.logo {
font-size: 3.5rem;
margin-bottom: 0.5rem;
}
h1 {
font-size: 1.5rem;
font-weight: 700;
color: #ffffff;
margin-bottom: 0.5rem;
}
.subtitle {
font-size: 0.95rem;
color: #9ca3af;
margin-bottom: 2rem;
line-height: 1.5;
}
/* ---- Buttons ---- */
.btn-primary,
.btn-secondary {
display: block;
width: 100%;
padding: 1rem;
border-radius: 10px;
font-size: 1.1rem;
font-weight: 600;
border: none;
cursor: pointer;
margin: 1rem 0;
text-decoration: none;
transition: background 0.2s, transform 0.1s;
}
.btn-primary {
background: #0f3460;
color: #ffffff;
}
.btn-primary:hover {
background: #e94560;
transform: translateY(-1px);
}
.btn-primary:active {
transform: translateY(0);
}
.btn-secondary {
background: transparent;
color: #9ca3af;
border: 1px solid #374151;
}
.btn-secondary:hover {
background: #374151;
color: #ffffff;
}
.hint {
font-size: 0.8rem;
color: #6b7280;
margin-top: -0.5rem;
}
/* ---- Spinner ---- */
.spinner {
width: 48px;
height: 48px;
border: 4px solid #374151;
border-top-color: #e94560;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 1rem auto;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* ---- Status icons ---- */
.icon-success {
font-size: 4rem;
color: #22c55e;
margin: 0.5rem 0;
}
.icon-error {
font-size: 4rem;
color: #ef4444;
margin: 0.5rem 0;
}
h2 {
font-size: 1.3rem;
color: #ffffff;
margin: 0.5rem 0;
}
/* ---- Instructions ---- */
.instructions {
text-align: left;
background: #0f3460;
border-radius: 10px;
padding: 1.25rem 1.5rem;
margin-top: 1.5rem;
}
.instructions h3 {
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #9ca3af;
margin-bottom: 0.75rem;
}
.instructions ol {
padding-left: 1.25rem;
}
.instructions li {
font-size: 0.9rem;
line-height: 1.6;
color: #d1d5db;
}
.instructions li + li {
margin-top: 0.4rem;
}
#error-message {
color: #fca5a5;
margin: 0.5rem 0 1rem;
font-size: 0.95rem;
}