Files
boc/html-patches/company-onboarding.html
T

1200 lines
46 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="sv">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bolagsonboarding — AAMOS</title>
<style>
/* ── iOS 26 Native Design System ── */
:root {
--ios-bg: #F2F2F7;
--ios-surface: #FFFFFF;
--ios-surface-2: #F2F2F7;
--ios-grouped: rgba(255,255,255,0.72);
--ios-label: #000000;
--ios-label-2: rgba(60,60,67,0.60);
--ios-label-3: rgba(60,60,67,0.30);
--ios-label-4: rgba(60,60,67,0.18);
--ios-separator: rgba(60,60,67,0.29);
--ios-fill: rgba(120,120,128,0.12);
--ios-fill-2: rgba(120,120,128,0.16);
--ios-blue: #007AFF;
--ios-blue-dark: #0056CC;
--ios-green: #34C759;
--ios-orange: #FF9500;
--ios-red: #FF3B30;
--ios-purple: #AF52DE;
--ios-teal: #5AC8FA;
--ios-indigo: #5856D6;
--ios-gray-6: #F2F2F7;
--ios-corner-large: 16px;
--ios-corner-med: 12px;
--ios-corner-small: 8px;
--ios-shadow: 0 2px 20px rgba(0,0,0,0.08);
--ios-shadow-lg: 0 8px 40px rgba(0,0,0,0.12);
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--ios-bg);
color: var(--ios-label);
min-height: 100vh;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* ── Navigation Bar ── */
.nav-bar {
position: sticky; top: 0; z-index: 100;
background: rgba(242,242,247,0.88);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border-bottom: 0.5px solid var(--ios-separator);
padding: 0 20px;
height: 56px;
display: flex; align-items: center; justify-content: space-between;
}
.nav-title {
font-size: 17px; font-weight: 600;
letter-spacing: -0.4px;
}
.nav-logo {
font-size: 15px; font-weight: 500; color: var(--ios-blue);
text-decoration: none;
}
.nav-badge {
background: var(--ios-blue); color: #fff;
font-size: 11px; font-weight: 600;
padding: 2px 8px; border-radius: 10px;
}
/* ── Hero ── */
.hero {
background: linear-gradient(145deg, #007AFF 0%, #5856D6 60%, #AF52DE 100%);
padding: 56px 24px 48px;
text-align: center;
color: #fff;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute; inset: 0;
background: radial-gradient(ellipse at 30% 60%, rgba(255,255,255,0.15) 0%, transparent 60%);
}
.hero-eyebrow {
font-size: 13px; font-weight: 600;
letter-spacing: 0.8px; text-transform: uppercase;
opacity: 0.8; margin-bottom: 12px;
}
.hero-title {
font-size: 34px; font-weight: 700;
letter-spacing: -1.2px; line-height: 1.1;
margin-bottom: 12px;
}
.hero-sub {
font-size: 17px; opacity: 0.85;
font-weight: 400; line-height: 1.5;
max-width: 340px; margin: 0 auto 24px;
}
.hero-badge {
display: inline-flex; align-items: center; gap: 6px;
background: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.3);
border-radius: 100px;
padding: 6px 16px;
font-size: 14px; font-weight: 600;
}
/* ── Container ── */
.container {
max-width: 520px; margin: 0 auto;
padding: 0 16px 80px;
}
/* ── Step Indicator ── */
.steps-bar {
display: flex; align-items: center; justify-content: center;
gap: 0; margin: 24px 0;
}
.step-dot {
width: 28px; height: 28px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 700;
background: var(--ios-fill);
color: var(--ios-label-2);
transition: all 0.3s ease;
position: relative; z-index: 1;
}
.step-dot.active {
background: var(--ios-blue); color: #fff;
box-shadow: 0 4px 12px rgba(0,122,255,0.35);
}
.step-dot.done {
background: var(--ios-green); color: #fff;
}
.step-line {
flex: 1; height: 2px; max-width: 48px;
background: var(--ios-fill);
transition: background 0.3s;
}
.step-line.done { background: var(--ios-green); }
/* ── Card ── */
.card {
background: var(--ios-surface);
border-radius: var(--ios-corner-large);
box-shadow: var(--ios-shadow);
overflow: hidden;
margin-bottom: 16px;
}
.card-header {
padding: 16px 20px 12px;
border-bottom: 0.5px solid var(--ios-separator);
display: flex; align-items: center; gap: 12px;
}
.card-icon {
width: 36px; height: 36px; border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.card-icon.blue { background: rgba(0,122,255,0.12); }
.card-icon.green { background: rgba(52,199,89,0.12); }
.card-icon.purple { background: rgba(175,82,222,0.12); }
.card-title { font-size: 17px; font-weight: 600; letter-spacing: -0.4px; }
.card-sub { font-size: 13px; color: var(--ios-label-2); margin-top: 2px; }
.card-body { padding: 16px 20px; }
/* ── Form fields ── */
.field-group { margin-bottom: 16px; }
.field-label {
font-size: 13px; font-weight: 500;
color: var(--ios-label-2);
margin-bottom: 6px;
letter-spacing: -0.1px;
display: flex; align-items: center; gap: 6px;
}
.field-required { color: var(--ios-red); }
.field-input {
width: 100%;
background: var(--ios-fill);
border: none; outline: none;
border-radius: var(--ios-corner-med);
padding: 13px 16px;
font-size: 17px; font-weight: 400;
color: var(--ios-label);
font-family: inherit;
transition: all 0.2s;
-webkit-appearance: none;
}
.field-input:focus {
background: var(--ios-surface);
box-shadow: 0 0 0 2px var(--ios-blue), var(--ios-shadow);
}
.field-input.valid { box-shadow: 0 0 0 2px var(--ios-green); }
.field-input.error { box-shadow: 0 0 0 2px var(--ios-red); }
.field-hint {
font-size: 12px; color: var(--ios-label-3);
margin-top: 6px;
}
/* ── Company preview card ── */
.company-preview {
background: linear-gradient(135deg, rgba(52,199,89,0.08) 0%, rgba(0,122,255,0.06) 100%);
border: 1px solid rgba(52,199,89,0.3);
border-radius: var(--ios-corner-med);
padding: 14px 16px;
margin-top: 12px;
display: none;
}
.company-preview.show { display: block; animation: fadeIn 0.3s ease; }
.company-preview-name {
font-size: 17px; font-weight: 600; letter-spacing: -0.5px;
color: var(--ios-label);
}
.company-preview-row {
font-size: 13px; color: var(--ios-label-2);
margin-top: 4px; display: flex; align-items: center; gap: 6px;
}
.company-preview-badge {
display: inline-flex; align-items: center;
background: rgba(52,199,89,0.15); color: #1a7a30;
border-radius: 100px; padding: 2px 8px;
font-size: 11px; font-weight: 600; letter-spacing: 0.2px;
}
/* ── Plan selector ── */
.plans-grid {
display: grid; grid-template-columns: 1fr 1fr 1fr;
gap: 10px; margin-bottom: 4px;
}
.plan-card {
border: 1.5px solid var(--ios-fill-2);
border-radius: var(--ios-corner-med);
padding: 12px 10px;
cursor: pointer; text-align: center;
transition: all 0.2s;
background: var(--ios-surface);
position: relative;
}
.plan-card:hover { border-color: var(--ios-blue); background: rgba(0,122,255,0.04); }
.plan-card.selected {
border-color: var(--ios-blue);
background: rgba(0,122,255,0.08);
box-shadow: 0 4px 16px rgba(0,122,255,0.15);
}
.plan-name { font-size: 14px; font-weight: 600; margin-top: 4px; }
.plan-price { font-size: 12px; color: var(--ios-label-2); margin-top: 2px; }
.plan-emoji { font-size: 20px; }
.plan-check {
position: absolute; top: 6px; right: 6px;
width: 16px; height: 16px; border-radius: 50%;
background: var(--ios-blue); color: #fff;
font-size: 10px;
display: none; align-items: center; justify-content: center;
}
.plan-card.selected .plan-check { display: flex; }
/* ── CTA Button ── */
.btn-primary {
width: 100%;
background: var(--ios-blue);
color: #fff;
border: none; outline: none;
border-radius: var(--ios-corner-large);
padding: 16px;
font-size: 17px; font-weight: 600;
font-family: inherit;
cursor: pointer;
letter-spacing: -0.4px;
transition: all 0.15s;
box-shadow: 0 4px 16px rgba(0,122,255,0.35);
-webkit-tap-highlight-color: transparent;
}
.btn-primary:hover { background: var(--ios-blue-dark); box-shadow: 0 6px 24px rgba(0,122,255,0.4); }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled { background: var(--ios-label-3); box-shadow: none; cursor: not-allowed; }
.btn-secondary {
background: var(--ios-fill);
color: var(--ios-blue);
border: none; outline: none;
border-radius: var(--ios-corner-large);
padding: 14px 24px;
font-size: 15px; font-weight: 600;
font-family: inherit;
cursor: pointer;
transition: all 0.15s;
-webkit-tap-highlight-color: transparent;
}
.btn-secondary:hover { background: var(--ios-fill-2); }
/* ── Progress bar ── */
.progress-wrap {
background: var(--ios-fill);
border-radius: 100px; height: 6px;
overflow: hidden; margin: 12px 0;
}
.progress-bar {
height: 100%; border-radius: 100px;
background: linear-gradient(90deg, var(--ios-blue) 0%, var(--ios-indigo) 100%);
transition: width 0.5s ease;
box-shadow: 0 2px 8px rgba(0,122,255,0.35);
}
/* ── Step items ── */
.step-items { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; }
.step-item {
display: flex; align-items: center; gap: 12px;
padding: 10px 0;
border-bottom: 0.5px solid var(--ios-separator);
animation: fadeIn 0.4s ease;
}
.step-item:last-child { border-bottom: none; }
.step-status-icon {
width: 28px; height: 28px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0; font-size: 14px;
}
.step-status-icon.pending { background: var(--ios-fill); color: var(--ios-label-3); }
.step-status-icon.running { background: rgba(0,122,255,0.12); color: var(--ios-blue); }
.step-status-icon.done { background: rgba(52,199,89,0.12); color: var(--ios-green); }
.step-status-icon.error { background: rgba(255,59,48,0.12); color: var(--ios-red); }
.step-item-text { flex: 1; }
.step-item-label { font-size: 15px; font-weight: 500; }
.step-item-sub { font-size: 12px; color: var(--ios-label-2); margin-top: 2px; }
.spinner { animation: spin 1s linear infinite; display: inline-block; }
/* ── Checklist ── */
.checklist-category { margin-bottom: 20px; }
.checklist-cat-header {
display: flex; align-items: center; gap: 8px;
font-size: 13px; font-weight: 600;
color: var(--ios-label-2); text-transform: uppercase;
letter-spacing: 0.5px; margin-bottom: 8px;
}
.checklist-item {
display: flex; align-items: flex-start; gap: 12px;
padding: 10px 0;
border-bottom: 0.5px solid var(--ios-separator);
cursor: pointer;
transition: opacity 0.2s;
}
.checklist-item:last-child { border-bottom: none; }
.checklist-item.completed { opacity: 0.5; }
.checklist-item.completed .checklist-title { text-decoration: line-through; }
.checklist-checkbox {
width: 22px; height: 22px; border-radius: 50%;
border: 2px solid var(--ios-separator);
display: flex; align-items: center; justify-content: center;
flex-shrink: 0; margin-top: 1px;
transition: all 0.2s;
}
.checklist-item.completed .checklist-checkbox {
background: var(--ios-green); border-color: var(--ios-green);
}
.checklist-item.auto .checklist-checkbox {
background: var(--ios-blue); border-color: var(--ios-blue);
}
.checklist-title { font-size: 15px; font-weight: 500; }
.checklist-meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.checklist-time { font-size: 12px; color: var(--ios-label-2); }
.priority-badge {
font-size: 10px; font-weight: 600; letter-spacing: 0.3px;
padding: 2px 6px; border-radius: 4px;
text-transform: uppercase;
}
.priority-high { background: rgba(255,59,48,0.1); color: var(--ios-red); }
.priority-medium { background: rgba(255,149,0,0.1); color: var(--ios-orange); }
.priority-low { background: rgba(120,120,128,0.1); color: var(--ios-label-2); }
/* ── Success state ── */
.success-hero {
text-align: center; padding: 32px 20px 24px;
}
.success-icon {
width: 80px; height: 80px; border-radius: 50%;
background: linear-gradient(135deg, var(--ios-green), #28a745);
margin: 0 auto 20px;
display: flex; align-items: center; justify-content: center;
font-size: 36px;
box-shadow: 0 8px 32px rgba(52,199,89,0.35);
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.success-title {
font-size: 28px; font-weight: 700; letter-spacing: -0.8px;
margin-bottom: 8px;
}
.success-sub {
font-size: 15px; color: var(--ios-label-2); line-height: 1.5;
}
/* ── Stats row ── */
.stats-row {
display: grid; grid-template-columns: 1fr 1fr 1fr;
gap: 12px; margin-bottom: 16px;
}
.stat-card {
background: var(--ios-surface);
border-radius: var(--ios-corner-med);
padding: 14px;
text-align: center;
box-shadow: var(--ios-shadow);
}
.stat-value { font-size: 24px; font-weight: 700; letter-spacing: -0.5px; }
.stat-label { font-size: 11px; color: var(--ios-label-2); font-weight: 500; margin-top: 2px; }
/* ── Hidden states ── */
.step-view { display: none; }
.step-view.active { display: block; }
/* ── Animations ── */
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes popIn { from { transform: scale(0.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
.fade-in { animation: fadeIn 0.4s ease forwards; }
/* ── Utility ── */
.text-center { text-align: center; }
.mt-8 { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.gap-8 { gap: 8px; }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.w-full { width: 100%; }
.section-header {
font-size: 22px; font-weight: 700;
letter-spacing: -0.6px; margin-bottom: 4px;
}
.section-sub {
font-size: 14px; color: var(--ios-label-2); margin-bottom: 16px; line-height: 1.5;
}
.tag {
display: inline-flex; align-items: center;
font-size: 12px; font-weight: 600;
padding: 3px 10px; border-radius: 100px;
}
.tag-blue { background: rgba(0,122,255,0.12); color: var(--ios-blue); }
.tag-green { background: rgba(52,199,89,0.12); color: #1a7a30; }
.tag-orange { background: rgba(255,149,0,0.12); color: #cc7700; }
/* Divider */
.divider { height: 0.5px; background: var(--ios-separator); margin: 12px 0; }
</style>
<link rel="stylesheet" href="/_design-system/apple-native/tokens.css">
<link rel="stylesheet" href="/_design-system/apple-native/universal-fix.css">
<link rel="stylesheet" href="/_design-system/apple-native/typography.css">
<link rel="stylesheet" href="/_design-system/apple-native/components.css">
<style>
/* ── Ouroboros OS Layout Inject ── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
--bg:#F2F2F7;--bg2:#FFFFFF;--bg3:#E5E5EA;
--accent:#007AFF;--accent2:#0051D4;
--text:#000000;--text2:rgba(60,60,67,.8);--text3:rgba(60,60,67,.6);
--card:#FFFFFF;--border:rgba(60,60,67,.13);
--green:#34C759;--red:#FF3B30;--orange:#FF9500;
--blue:#007AFF;--purple:#AF52DE;--teal:#30B0C7;--gold:#C8763A;
--shadow:0 1px 3px rgba(0,0,0,.08),0 4px 16px rgba(0,0,0,.04);
}
@media(prefers-color-scheme:dark){:root{
--bg:#000;--bg2:#1C1C1E;--bg3:#2C2C2E;
--text:#fff;--text2:rgba(235,235,245,.8);--text3:rgba(235,235,245,.5);
--card:#1C1C1E;--border:rgba(255,255,255,.12);
--green:#30D158;--red:#FF453A;--orange:#FF9F0A;
--blue:#0A84FF;--purple:#BF5AF2;--shadow:0 2px 12px rgba(0,0,0,.4);
}}
html,body{height:100%;overflow:hidden}
body{font-family:-apple-system,'SF Pro Text',system-ui,sans-serif;-webkit-font-smoothing:antialiased;background:var(--bg);color:var(--text)}
/* ── Layout ── */
.os-layout{display:flex;height:100vh;overflow:hidden}
/* ── Sidebar ── */
.os-sidebar{width:240px;background:var(--bg2);border-right:.5px solid var(--border);display:flex;flex-direction:column;flex-shrink:0;overflow-y:auto;transition:transform .3s}
.os-sidebar-logo{padding:18px 18px 14px;border-bottom:.5px solid var(--border)}
.os-logo-brand{font-size:10px;font-weight:700;letter-spacing:.12em;color:var(--gold);text-transform:uppercase;margin-bottom:4px}
.os-logo-name{font-size:17px;font-weight:800;color:var(--text);letter-spacing:-.02em}
.os-logo-sub{font-size:11px;color:var(--text3);margin-top:2px}
.os-sidebar-back{padding:8px 14px;border-bottom:.5px solid var(--border)}
.os-sidebar-back a{color:var(--blue);font-size:13px;text-decoration:none;display:flex;align-items:center;gap:4px}
.os-sidebar-back a:hover{opacity:.7}
.os-sidebar-section{padding:12px 10px 4px}
.os-sidebar-label{font-size:10px;font-weight:700;letter-spacing:.1em;color:var(--text3);text-transform:uppercase;padding:0 8px;margin-bottom:6px}
.os-nav-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:10px;cursor:pointer;color:var(--text2);font-size:13px;font-weight:500;transition:all .15s;border:none;background:none;width:100%;text-align:left;text-decoration:none}
.os-nav-item:hover{background:var(--bg3);color:var(--text)}
.os-nav-item.active{background:var(--blue);color:#fff}
.os-nav-icon{font-size:15px;width:20px;text-align:center}
.os-sidebar-footer{margin-top:auto;padding:14px;border-top:.5px solid var(--border);font-size:11px;color:var(--text3)}
/* ── Main + Topbar ── */
.os-main{flex:1;display:flex;flex-direction:column;overflow:hidden}
.os-topbar{background:rgba(242,242,247,.85);backdrop-filter:saturate(180%) blur(20px);-webkit-backdrop-filter:saturate(180%) blur(20px);border-bottom:.5px solid var(--border);padding:0 20px;height:52px;display:flex;align-items:center;justify-content:space-between;position:relative;z-index:100;flex-shrink:0}
@media(prefers-color-scheme:dark){.os-topbar{background:rgba(28,28,30,.85)}}
.os-topbar-title{font-size:15px;font-weight:700;color:var(--text)}
.os-topbar-breadcrumb{font-size:12px;color:var(--text3);display:flex;align-items:center;gap:6px}
.os-topbar-actions{display:flex;gap:8px;align-items:center}
.os-topbar-org{font-size:12px;color:var(--text3);background:var(--bg3);padding:3px 9px;border-radius:8px;font-weight:600}
.os-topbar-live{display:inline-flex;align-items:center;gap:5px;background:rgba(52,199,89,.12);border:.5px solid rgba(52,199,89,.3);border-radius:20px;padding:3px 10px;font-size:11px;font-weight:700;color:var(--green)}
.os-live-dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:osPulse 1.5s infinite}
@keyframes osPulse{0%,100%{opacity:1}50%{opacity:.3}}
/* ── Content area ── */
.os-content{flex:1;overflow-y:auto;min-height:0}
/* ── Mobile ── */
@media(max-width:768px){.os-sidebar{display:none}.os-layout{flex-direction:column}}
</style>
<style>
/* iOS Perfection Fix — hides duplicate nav, fixes stats, improves typography */
.nav-bar{display:none!important}
.large-title{font-size:28px!important;font-weight:700!important;letter-spacing:-.5px!important;margin-bottom:3px!important}
.large-subtitle{font-size:14px!important;color:rgba(60,60,67,.55)!important;font-weight:400!important}
.large-title-area,.large-title-section{padding:4px 20px 8px!important}
.mini-stat{background:#fff!important;border-radius:14px!important;padding:14px 12px!important;border:none!important;box-shadow:0 1px 3px rgba(0,0,0,.05),0 2px 8px rgba(0,0,0,.04)!important}
.mini-stat-value{font-size:26px!important;font-weight:800!important;letter-spacing:-.03em!important;color:#007AFF!important;display:block!important;margin-bottom:5px!important}
.mini-stat-label{font-size:11px!important;font-weight:500!important;color:rgba(60,60,67,.55)!important;display:block!important}
.stats-row{gap:10px!important;padding:8px 16px 12px!important}
.search-area{padding:4px 16px 8px!important}
.search-wrap{height:38px!important;border-radius:11px!important;background:rgba(120,120,128,.11)!important}
.section-title-text,.section-title{font-size:20px!important;font-weight:700!important;letter-spacing:-.3px!important}
.kpi-card{background:#fff!important;border-radius:16px!important;border:none!important;box-shadow:0 1px 3px rgba(0,0,0,.05),0 2px 8px rgba(0,0,0,.04)!important}
.kpi-value{font-weight:800!important;letter-spacing:-.03em!important}
@media(prefers-color-scheme:dark){
.mini-stat,.kpi-card{background:#1C1C1E!important}
.mini-stat-value{color:#0A84FF!important}
.large-title{color:#fff!important}
.large-subtitle{color:rgba(235,235,245,.55)!important}
}
</style>
<style id="ouroboros-apple-system">
/* OUROBOROS GLOBAL SYSTEM CSS — Apple iOS 18 baseline */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
/* System font stack — SF Pro on Apple, Inter elsewhere */
body, input, select, textarea, button {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display',
'Helvetica Neue', Arial, system-ui, sans-serif;
}
/* Fix any broken button appearances */
button { -webkit-appearance: none; appearance: none; cursor: pointer; }
select { -webkit-appearance: none; appearance: none; }
input[type="number"] { -moz-appearance: textfield; }
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; }
/* Remove blue outline on focus (replace with subtle ring) */
:focus-visible {
outline: 2.5px solid rgba(0, 122, 255, 0.6);
outline-offset: 2px;
border-radius: 6px;
}
/* Language buttons must ALWAYS look like pills */
.lang-btn {
padding: 6px 12px !important;
border: 1.5px solid rgba(60,60,67,.15) !important;
border-radius: 20px !important;
background: #fff !important;
color: rgba(60,60,67,.6) !important;
font-size: 12px !important;
font-weight: 700 !important;
-webkit-appearance: none !important;
box-shadow: 0 1px 2px rgba(0,0,0,.06) !important;
}
.lang-btn.active {
background: #007AFF !important;
border-color: #007AFF !important;
color: #fff !important;
}
/* Tap targets minimum 44×44pt (iOS HIG requirement) */
@media (pointer: coarse) {
button, .btn-primary, .btn-ghost, .option-card, .lang-btn {
min-height: 44px;
}
}
</style>
<style id="wcag-contrast-enforcement">
/* AAMOS GLOBAL CONTRAST ENFORCEMENT — WCAG AA (4.5:1 minimum) */
/* Regel: Ingen text under 70% opacity. Aldrig. */
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
/* Fix common low-contrast patterns */
[style*="rgba(60,60,67,0.4)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(60,60,67,0.3)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(255,255,255,0.4)"] { color: rgba(255,255,255,0.72) !important; }
[style*="rgba(255,255,255,0.3)"] { color: rgba(255,255,255,0.72) !important; }
[style*="opacity: 0.4"] { opacity: 0.72 !important; }
[style*="opacity: 0.3"] { opacity: 0.72 !important; }
</style>
</head>
<body>
<div class="os-layout">
<!-- ── Sidebar ── -->
<nav class="os-sidebar">
<div class="os-sidebar-logo">
<div class="os-logo-brand">AAMOS · Ouroboros</div>
<div class="os-logo-name">Bolagsonboarding</div>
<div class="os-logo-sub">AAMOS Ouroboros</div>
</div>
<div class="os-sidebar-back">
<a href="/ouroboros/">← Ouroboros Hub</a>
</div>
<div class="os-sidebar-section">
<div class="os-sidebar-label">Navigation</div>
<a class="os-nav-item active" href="#">
<span class="os-nav-icon">🏛️</span> Bolagsonboarding
</a>
<a class="os-nav-item" href="/ouroboros/cockpit.html">
<span class="os-nav-icon">🚀</span> Cockpit
</a>
<a class="os-nav-item" href="/ouroboros/finance-hub.html">
<span class="os-nav-icon">💰</span> Finance Hub
</a>
<a class="os-nav-item" href="/ouroboros/compliance-hub.html">
<span class="os-nav-icon">⚖️</span> Compliance Hub
</a>
<a class="os-nav-item" href="/ouroboros/analytics-hub.html">
<span class="os-nav-icon">📊</span> Analytics Hub
</a>
</div>
<div class="os-sidebar-footer">
<div>AAMOS Ouroboros OS</div>
<div style="margin-top:4px;opacity:.6">wavult-group</div>
</div>
</nav>
<!-- ── Main ── -->
<div class="os-main">
<div class="os-topbar">
<div class="os-topbar-breadcrumb">
<a href="/ouroboros/" style="color:var(--blue);text-decoration:none">Ouroboros</a>
<span></span>
<span class="os-topbar-title">Bolagsonboarding</span>
</div>
<div class="os-topbar-actions">
<span class="os-topbar-live"><span class="os-live-dot"></span>LIVE</span>
<span class="os-topbar-org">wavult-group</span>
</div>
</div>
<div class="os-content">
<!-- Navigation -->
<nav class="nav-bar">
<a href="/ouroboros" class="nav-logo">← AAMOS</a>
<span class="nav-title">Bolagsonboarding</span>
<span class="nav-badge">BETA</span>
</nav>
<!-- Hero -->
<div class="hero">
<div class="hero-eyebrow">AAMOS · OUROBOROS</div>
<h1 class="hero-title">Starta ett bolag<br>på 15 minuter.</h1>
<p class="hero-sub">Automatisk provisioning, bankintegration, skatteregistrering och checklista — på direkten.</p>
<div class="hero-badge">⚡ Powered by AI · Bolagsverket · GECL</div>
</div>
<!-- Main content -->
<div class="container">
<!-- Step indicator -->
<div class="steps-bar">
<div class="step-dot active" id="dot1">1</div>
<div class="step-line" id="line1"></div>
<div class="step-dot" id="dot2">2</div>
<div class="step-line" id="line2"></div>
<div class="step-dot" id="dot3">3</div>
<div class="step-line" id="line3"></div>
<div class="step-dot" id="dot4">4</div>
</div>
<!-- ── STEP 1: Org-nummer ── -->
<div class="step-view active" id="step1">
<div class="section-header">Vilket bolag gäller det?</div>
<p class="section-sub">Ange organisationsnummer — vi hämtar resten från Bolagsverket automatiskt.</p>
<div class="card fade-in">
<div class="card-header">
<div class="card-icon blue">🏢</div>
<div>
<div class="card-title">Organisationsnummer</div>
<div class="card-sub">10 siffror, format XXXXXX-XXXX</div>
</div>
</div>
<div class="card-body">
<div class="field-group">
<div class="field-label">
Org-nummer <span class="field-required">*</span>
</div>
<input
type="text"
id="orgNrInput"
class="field-input"
placeholder="556000-0000"
maxlength="11"
autocomplete="off"
autocorrect="off"
spellcheck="false"
>
<div class="field-hint" id="orgNrHint">Ange bolagets registrerade organisationsnummer</div>
</div>
<!-- Company preview -->
<div class="company-preview" id="companyPreview">
<div class="flex items-center justify-between">
<div class="company-preview-name" id="previewName"></div>
<div class="company-preview-badge" id="previewStatus">✓ FOUND</div>
</div>
<div class="company-preview-row" id="previewAddress"></div>
<div class="company-preview-row">
<span id="previewLegalForm"></span>
&nbsp;·&nbsp;
<span id="previewSni"></span>
</div>
</div>
<div class="mt-16">
<button class="btn-primary" id="step1Next" disabled onclick="goStep2()">
Fortsätt →
</button>
</div>
</div>
</div>
</div>
<!-- ── STEP 2: Välj plan & kontakt ── -->
<div class="step-view" id="step2">
<div class="section-header">Välj plan</div>
<p class="section-sub">Alla planer inkluderar automatisk skatteregistrering och bankintegration.</p>
<div class="card fade-in">
<div class="card-header">
<div class="card-icon purple"></div>
<div>
<div class="card-title">Abonnemangsplan</div>
<div class="card-sub">Kan ändras när som helst</div>
</div>
</div>
<div class="card-body">
<div class="plans-grid">
<div class="plan-card" onclick="selectPlan('starter', this)" data-plan="starter">
<div class="plan-check"></div>
<div class="plan-emoji">🌱</div>
<div class="plan-name">Starter</div>
<div class="plan-price">990 kr/mån</div>
</div>
<div class="plan-card selected" onclick="selectPlan('professional', this)" data-plan="professional">
<div class="plan-check"></div>
<div class="plan-emoji">🚀</div>
<div class="plan-name">Professional</div>
<div class="plan-price">2 990 kr/mån</div>
</div>
<div class="plan-card" onclick="selectPlan('enterprise', this)" data-plan="enterprise">
<div class="plan-check"></div>
<div class="plan-emoji">🏛️</div>
<div class="plan-name">Enterprise</div>
<div class="plan-price">9 900 kr/mån</div>
</div>
</div>
<div class="divider mt-12"></div>
<div class="field-group mt-12">
<div class="field-label">Admin-namn <span class="field-required">*</span></div>
<input type="text" id="adminName" class="field-input" placeholder="Anna Andersson" autocomplete="name">
</div>
<div class="field-group">
<div class="field-label">E-postadress <span class="field-required">*</span></div>
<input type="email" id="adminEmail" class="field-input" placeholder="anna@bolaget.se" autocomplete="email">
<div class="field-hint">Välkomstmail och dashboard-länk skickas hit</div>
</div>
<div class="field-group">
<div class="field-label">Lösenord <span class="field-required">*</span></div>
<input type="password" id="adminPassword" class="field-input" placeholder="Minst 8 tecken" autocomplete="new-password" minlength="8">
<div class="field-hint">Minst 8 tecken — används för att logga in i dashboard</div>
</div>
<div class="flex gap-8 mt-16">
<button class="btn-secondary" onclick="goStep1()" style="flex:1">← Tillbaka</button>
<button class="btn-primary" onclick="goStep3()" style="flex:2">Starta provisioning →</button>
</div>
</div>
</div>
</div>
<!-- ── STEP 3: Provisioning progress ── -->
<div class="step-view" id="step3">
<div class="section-header">Sätter upp bolaget…</div>
<p class="section-sub" id="step3Sub">AAMOS konfigurerar allt automatiskt — brukar ta under 15 sekunder.</p>
<div class="card fade-in">
<div class="card-header">
<div class="card-icon blue">⚙️</div>
<div>
<div class="card-title">Automatisk provisioning</div>
<div class="card-sub" id="progressLabel">Initierar…</div>
</div>
</div>
<div class="card-body">
<div class="progress-wrap">
<div class="progress-bar" id="progressBar" style="width:0%"></div>
</div>
<div class="field-hint text-center" id="progressPct">0% klart</div>
<div class="step-items mt-12" id="provSteps">
<!-- Injected by JS -->
</div>
</div>
</div>
</div>
<!-- ── STEP 4: Klar! Dashboard + Checklista ── -->
<div class="step-view" id="step4">
<div class="card fade-in">
<div class="success-hero">
<div class="success-icon"></div>
<div class="success-title" id="successTitle">Klart!</div>
<div class="success-sub" id="successSub">Bolaget är nu konfigurerat i AAMOS.<br>Välkomstmail skickat.</div>
</div>
</div>
<!-- Stats -->
<div class="stats-row fade-in">
<div class="stat-card">
<div class="stat-value" id="statSecs"></div>
<div class="stat-label">Sekunder</div>
</div>
<div class="stat-card">
<div class="stat-value" id="statModules"></div>
<div class="stat-label">Moduler</div>
</div>
<div class="stat-card">
<div class="stat-value" id="statItems"></div>
<div class="stat-label">Åtgärdspunkter</div>
</div>
</div>
<!-- Onboarding checklist -->
<div class="card fade-in" id="checklistCard">
<div class="card-header">
<div class="card-icon green">📋</div>
<div>
<div class="card-title">Onboarding-checklista</div>
<div class="card-sub" id="checklistMeta">Laddar…</div>
</div>
</div>
<div class="card-body" id="checklistBody">
<!-- Injected by JS -->
</div>
</div>
<!-- Dashboard link -->
<div class="card fade-in mt-16">
<div class="card-body text-center">
<div style="font-size:32px; margin-bottom:12px;">🔐</div>
<div style="font-size:17px; font-weight:600; margin-bottom:6px;">Klart att köra!</div>
<div style="font-size:14px; color: var(--ios-label-2); margin-bottom:12px;">
Ditt AAMOS-konto är aktiverat med alla moduler konfigurerade.
</div>
<div id="credentialBox" style="background:var(--ios-fill);border-radius:var(--ios-corner-med);padding:14px 16px;margin-bottom:16px;text-align:left;font-size:14px;line-height:1.7;"></div>
<a id="dashboardBtn" href="/ouroboros/app/login.html" class="btn-primary" style="display:inline-block; text-decoration:none; padding: 14px 24px;">
Klart! Logga in här →
</a>
</div>
</div>
<!-- Restart -->
<div class="text-center mt-16">
<button class="btn-secondary" onclick="restart()">Onboarda ett till bolag</button>
</div>
</div>
</div><!-- /container -->
<script>
// ── State ────────────────────────────────────────────────────────────────────
let state = {
orgNr: null,
companyData: null,
plan: 'professional',
adminEmail: null,
adminName: null,
adminPassword: null,
jobId: null,
jobData: null,
};
const PROV_STEPS = [
{ label: 'Hämtar bolagsdata från Bolagsverket', icon: '🏛️' },
{ label: 'Skapar organisation i Stammregister', icon: '📋' },
{ label: 'Konfigurerar standardroller', icon: '👥' },
{ label: 'Tillämpar SNI-baserat regelset', icon: '⚖️' },
{ label: 'Aktiverar moduler', icon: '🔧' },
{ label: 'Genererar onboarding-checklista', icon: '✅' },
{ label: 'Skickar välkomstmail', icon: '📧' },
{ label: 'GECL-signerar provisioning-record', icon: '🔐' },
];
// ── DOM helpers ──────────────────────────────────────────────────────────────
const $ = id => document.getElementById(id);
const setActive = (n) => {
[1,2,3,4].forEach(i => {
$(`step${i}`).classList.toggle('active', i === n);
const dot = $(`dot${i}`);
dot.classList.toggle('active', i === n);
dot.classList.toggle('done', i < n);
if (i < 4) $(`line${i}`).classList.toggle('done', i < n);
});
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// ── Org-nr input handling ────────────────────────────────────────────────────
let lookupTimeout;
$('orgNrInput').addEventListener('input', function() {
clearTimeout(lookupTimeout);
let v = this.value.replace(/[^\d-]/g, '');
// Auto-format
const digits = v.replace(/-/g, '');
if (digits.length > 6 && !v.includes('-')) {
v = digits.slice(0,6) + '-' + digits.slice(6,10);
}
this.value = v;
$('step1Next').disabled = true;
$('companyPreview').classList.remove('show');
const clean = v.replace(/[-\s]/g, '');
if (clean.length === 10) {
this.classList.remove('valid', 'error');
$('orgNrHint').textContent = 'Slår upp bolag…';
lookupTimeout = setTimeout(() => lookupOrgNr(clean), 500);
} else {
$('orgNrHint').textContent = 'Ange 10 siffror (XXXXXX-XXXX)';
}
});
async function lookupOrgNr(orgNr) {
try {
const r = await fetch(`/api/company/lookup/${orgNr}`);
const d = await r.json();
state.orgNr = orgNr;
state.companyData = d;
if (d.status === 'FOUND' || d.status === 'PARTIAL') {
$('orgNrInput').classList.add('valid');
$('orgNrHint').textContent = d.status === 'FOUND'
? '✅ Bolag verifierat via Bolagsverket'
: '⚠️ Delvis data — ange resterande uppgifter manuellt';
$('previewName').textContent = d.name || `Org.nr ${d.org_nr_formatted}`;
$('previewStatus').textContent = d.status === 'FOUND' ? '✓ VERIFIERAD' : '~ PARTIAL';
$('previewStatus').style.background = d.status === 'FOUND' ? 'rgba(52,199,89,0.15)' : 'rgba(255,149,0,0.15)';
$('previewAddress').textContent = [d.address?.street, d.address?.city].filter(Boolean).join(', ') || 'Adress saknas';
$('previewLegalForm').textContent = d.legal_form || 'Aktiebolag';
$('previewSni').textContent = d.sni_category || 'Okänd bransch';
$('companyPreview').classList.add('show');
$('step1Next').disabled = false;
} else {
$('orgNrInput').classList.add('error');
$('orgNrHint').textContent = `${d.error || 'Bolaget hittades inte'}`;
}
} catch (err) {
$('orgNrHint').textContent = '⚠️ Kunde inte nå Bolagsverket — fortsätt ändå';
$('step1Next').disabled = false;
state.orgNr = orgNr;
}
}
// ── Plan selector ────────────────────────────────────────────────────────────
function selectPlan(plan, el) {
state.plan = plan;
document.querySelectorAll('.plan-card').forEach(c => c.classList.remove('selected'));
el.classList.add('selected');
}
// ── Navigation ───────────────────────────────────────────────────────────────
function goStep1() { setActive(1); }
function goStep2() { setActive(2); }
function goStep3() {
const name = $('adminName').value.trim();
const email = $('adminEmail').value.trim();
const password = $('adminPassword').value;
if (!name || !email) {
alert('Ange namn och e-postadress.');
return;
}
if (!password || password.length < 8) {
alert('Lösenordet måste vara minst 8 tecken.');
return;
}
state.adminName = name;
state.adminEmail = email;
state.adminPassword = password;
setActive(3);
startProvisioning();
}
// ── Provisioning ─────────────────────────────────────────────────────────────
function renderProvSteps(doneCount) {
const container = $('provSteps');
container.innerHTML = PROV_STEPS.map((s, i) => {
const isDone = i < doneCount;
const isRunning = i === doneCount;
let iconClass = 'pending', iconContent = '○';
if (isDone) { iconClass = 'done'; iconContent = '✓'; }
if (isRunning) { iconClass = 'running'; iconContent = '<span class="spinner">⟳</span>'; }
return `
<div class="step-item">
<div class="step-status-icon ${iconClass}">${iconContent}</div>
<div class="step-item-text">
<div class="step-item-label">${s.label}</div>
${isRunning ? '<div class="step-item-sub">Pågår…</div>' :
isDone ? '<div class="step-item-sub" style="color:var(--ios-green)">Klart</div>' : ''}
</div>
<div style="font-size:18px">${s.icon}</div>
</div>`;
}).join('');
}
async function startProvisioning() {
renderProvSteps(0);
updateProgress(0);
try {
const resp = await fetch('/api/company/provision', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
org_nr: state.orgNr,
plan: state.plan,
admin_email: state.adminEmail,
admin_name: state.adminName,
admin_password: state.adminPassword,
}),
});
const job = await resp.json();
state.jobId = job.job_id;
pollJob(state.jobId);
} catch (err) {
$('step3Sub').textContent = `Fel: ${err.message}`;
}
}
function updateProgress(pct) {
$('progressBar').style.width = pct + '%';
$('progressPct').textContent = pct + '% klart';
$('progressLabel').textContent = pct < 100 ? `${pct}% — pågår…` : 'Klart!';
}
let pollInterval;
function pollJob(jobId) {
let attempts = 0;
pollInterval = setInterval(async () => {
attempts++;
if (attempts > 120) { clearInterval(pollInterval); return; } // 2 min timeout
try {
const r = await fetch(`/api/company/provisioning-status/${jobId}`);
const d = await r.json();
if (d.status === 'running') {
const pct = d.progress_pct || 0;
updateProgress(pct);
renderProvSteps(d.steps_done || 0);
} else if (d.status === 'completed') {
clearInterval(pollInterval);
state.jobData = d;
updateProgress(100);
renderProvSteps(8);
setTimeout(() => goStep4(d), 800);
} else if (d.status === 'failed') {
clearInterval(pollInterval);
$('step3Sub').textContent = `Fel: ${d.error || 'Okänt fel'}`;
}
} catch (_) {}
}, 1000);
}
// ── Step 4: Result ────────────────────────────────────────────────────────────
function goStep4(data) {
setActive(4);
$('successTitle').textContent = `${data.company_name || 'Bolaget'} är redo! 🎉`;
$('successSub').innerHTML = `Konfigurerat på <strong>${data.elapsed_seconds}s</strong>. Välkomstmail skickat till ${data.welcome_email?.to || state.adminEmail}.`;
$('statSecs').textContent = data.elapsed_seconds + 's';
$('statModules').textContent = Object.keys(data.module_status || {}).length || '—';
$('statItems').textContent = data.checklist?.total_items || '—';
// Visa inloggningsuppgifter
const orgId = data.org_id || '—';
const maskPwd = state.adminPassword
? '•'.repeat(Math.min(state.adminPassword.length, 12))
: '••••••••';
$('credentialBox').innerHTML = [
'<div style="margin-bottom:8px;font-weight:700;font-size:12px;color:var(--ios-label-2);text-transform:uppercase;letter-spacing:.5px">Inloggningsuppgifter</div>',
`<div>🏢 Org-ID: <strong style="font-family:monospace;font-size:13px">${orgId}</strong></div>`,
`<div>📧 E-post: <strong>${state.adminEmail}</strong></div>`,
`<div>🔑 Lösenord: <strong>${maskPwd}</strong> (ditt valda lösenord)</div>`,
].join('');
// Sätt login-URL
$('dashboardBtn').href = data.dashboard_url || '/ouroboros/app/login.html';
if (data.checklist) {
renderChecklist(data.checklist);
}
}
function renderChecklist(cl) {
$('checklistMeta').textContent = `${cl.total_items} åtgärder · Beräknad tid ~${cl.estimated_hours}h`;
const body = $('checklistBody');
body.innerHTML = cl.categories.map(cat => `
<div class="checklist-category">
<div class="checklist-cat-header">
<span>${cat.icon}</span> ${cat.category}
<span class="priority-badge priority-${cat.priority}">${cat.priority}</span>
</div>
${cat.items.map(item => `
<div class="checklist-item ${item.status === 'auto' ? 'auto' : ''}" onclick="toggleCheck(this)">
<div class="checklist-checkbox">${item.status === 'auto' ? '<span style="color:#fff;font-size:11px;">✓</span>' : ''}</div>
<div style="flex:1">
<div class="checklist-title">${item.title}</div>
<div class="checklist-meta">
<span class="checklist-time">⏱ ${item.estimated_min} min</span>
${item.note ? `<span class="tag tag-blue">${item.note}</span>` : ''}
</div>
</div>
</div>
`).join('')}
</div>
`).join('<div class="divider"></div>');
}
function toggleCheck(el) {
if (el.classList.contains('auto')) return;
el.classList.toggle('completed');
const cb = el.querySelector('.checklist-checkbox');
cb.innerHTML = el.classList.contains('completed')
? '<span style="color:#fff;font-size:11px;">✓</span>'
: '';
}
function restart() {
clearInterval(pollInterval);
state = { orgNr: null, companyData: null, plan: 'professional', adminEmail: null, adminName: null, adminPassword: null, jobId: null, jobData: null };
$('orgNrInput').value = '';
$('orgNrInput').className = 'field-input';
$('companyPreview').classList.remove('show');
$('orgNrHint').textContent = 'Ange bolagets registrerade organisationsnummer';
$('step1Next').disabled = true;
$('adminName').value = '';
$('adminEmail').value = '';
setActive(1);
}
// Init: pre-select professional plan
document.querySelector('[data-plan="professional"]').classList.add('selected');
// Handle ?org= querystring
const params = new URLSearchParams(location.search);
if (params.get('org')) {
// Already provisioned — show success hint
const orgHint = document.createElement('div');
orgHint.style.cssText = 'background:rgba(52,199,89,0.1);border:1px solid rgba(52,199,89,0.3);border-radius:12px;padding:16px;margin:16px 0;text-align:center;font-size:14px;color:#1a7a30;font-weight:500;';
orgHint.innerHTML = `✅ Org <code style="font-family:monospace">${params.get('org')}</code> är redan provisionerat i AMOS.`;
document.querySelector('.container').prepend(orgHint);
}
</script>
</div><!-- /os-content -->
</div><!-- /os-main -->
</div><!-- /os-layout -->
</body>
</html>