2026-07-05 06:41:32 +00:00
<!DOCTYPE html>
< html lang = "sv" data-theme = "light" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0, viewport-fit=cover" >
< meta name = "apple-native-compliance" content = "full" >
< meta name = "module" content = "dac7-reporting" >
< title > DAC7 Rapportering · quiXzoom< / title >
< link rel = "stylesheet" >
< link rel = "stylesheet" >
< script defer > < / script >
< style >
* , * :: before , * :: after { box-sizing : border-box ; margin : 0 ; padding : 0 ; }
: root {
--ios-blue : #007AFF ;
--ios-green : #34C759 ;
--ios-red : #FF3B30 ;
--ios-orange : #FF9500 ;
--ios-yellow : #FFCC00 ;
--ios-purple : #AF52DE ;
--ios-gray : #8E8E93 ;
--ios-gray2 : #AEAEB2 ;
--ios-gray3 : #C7C7CC ;
--ios-gray4 : #D1D1D6 ;
--ios-gray5 : #E5E5EA ;
--ios-gray6 : #F2F2F7 ;
--label-primary : rgba ( 0 , 0 , 0 , 1 ) ;
--label-secondary : rgba ( 60 , 60 , 67 , .6 ) ;
--label-tertiary : rgba ( 60 , 60 , 67 , .3 ) ;
--background-primary : #FFFFFF ;
--background-secondary : #F2F2F7 ;
--grouped-bg : #F2F2F7 ;
--grouped-bg2 : #FFFFFF ;
--separator : rgba ( 60 , 60 , 67 , .29 ) ;
--tint : var ( - - ios - blue ) ;
--glass-bg : rgba ( 255 , 255 , 255 , .72 ) ;
--glass-blur : blur ( 40 px ) saturate ( 180 % ) ;
--safe-top : env ( safe - area - inset - top , 0 px ) ;
--safe-bottom : env ( safe - area - inset - bottom , 0 px ) ;
}
body {
font-family : - apple-system , "SF Pro Text" , "Helvetica Neue" , sans-serif ;
background : var ( - - grouped - bg ) ;
color : var ( - - label - primary ) ;
min-height : 100 vh ;
-webkit- font-smoothing : antialiased ;
padding-top : calc ( var ( - - safe - top ) + 52 px ) ;
padding-bottom : calc ( var ( - - safe - bottom ) + 20 px ) ;
}
2026-07-07 07:11:50 +00:00
/* Navigation Bar */
2026-07-05 06:41:32 +00:00
. navbar {
position : fixed ;
top : 0 ; left : 0 ; right : 0 ;
height : calc ( var ( - - safe - top ) + 52 px ) ;
padding-top : var ( - - safe - top ) ;
background : var ( - - glass - bg ) ;
backdrop-filter : var ( - - glass - blur ) ;
-webkit- backdrop-filter : var ( - - glass - blur ) ;
border-bottom : 0.5 px solid var ( - - separator ) ;
display : flex ;
align-items : flex-end ;
padding-bottom : 8 px ;
padding-left : 16 px ;
padding-right : 16 px ;
z-index : 1000 ;
gap : 12 px ;
}
. navbar-icon {
width : 30 px ; height : 30 px ;
background : linear-gradient ( 135 deg , #007AFF , #5856D6 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
display : flex ; align-items : center ; justify-content : center ;
font-size : 16 px ;
flex-shrink : 0 ;
}
. navbar-title {
font-size : 17 px ;
font-weight : 600 ;
letter-spacing : -0.41 px ;
color : var ( - - label - primary ) ;
flex : 1 ;
}
. navbar-badge {
font-size : 11 px ;
font-weight : 600 ;
color : var ( - - ios - blue ) ;
background : rgba ( 0 , 122 , 255 , .1 ) ;
padding : 3 px 8 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - xl ) ;
2026-07-05 06:41:32 +00:00
}
2026-07-07 07:11:50 +00:00
/* Content */
2026-07-05 06:41:32 +00:00
. content { padding : 0 16 px ; }
2026-07-07 07:11:50 +00:00
/* Alert Banner */
2026-07-05 06:41:32 +00:00
. deadline-alert {
margin : 20 px 0 0 ;
background : linear-gradient ( 135 deg , rgba ( 255 , 59 , 48 , .08 ) , rgba ( 255 , 149 , 0 , .08 ) ) ;
border : 1 px solid rgba ( 255 , 59 , 48 , .2 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
padding : 16 px ;
display : flex ;
align-items : flex-start ;
gap : 12 px ;
}
. alert-icon {
width : 36 px ; height : 36 px ;
background : rgba ( 255 , 59 , 48 , .12 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
display : flex ; align-items : center ; justify-content : center ;
font-size : 18 px ;
flex-shrink : 0 ;
}
. alert-body { flex : 1 ; }
. alert-title {
font-size : 15 px ;
font-weight : 600 ;
color : var ( - - ios - red ) ;
letter-spacing : -0.23 px ;
margin-bottom : 3 px ;
}
. alert-desc {
font-size : 13 px ;
color : var ( - - label - secondary ) ;
line-height : 1.4 ;
}
. days-left {
font-size : 22 px ;
font-weight : 700 ;
color : var ( - - ios - red ) ;
text-align : center ;
}
. days-label {
font-size : 10 px ;
font-weight : 500 ;
color : var ( - - label - tertiary ) ;
text-align : center ;
text-transform : uppercase ;
letter-spacing : 0.5 px ;
}
2026-07-07 07:11:50 +00:00
/* Section Header */
2026-07-05 06:41:32 +00:00
. section-header {
font-size : 13 px ;
font-weight : 600 ;
color : var ( - - label - secondary ) ;
text-transform : uppercase ;
letter-spacing : 0.5 px ;
padding : 24 px 4 px 8 px ;
}
2026-07-07 07:11:50 +00:00
/* Cards */
2026-07-05 06:41:32 +00:00
. card {
background : var ( - - grouped - bg2 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
overflow : hidden ;
margin-bottom : 12 px ;
}
. card-header {
padding : 14 px 16 px 0 ;
}
. card-title {
font-size : 15 px ;
font-weight : 600 ;
letter-spacing : -0.23 px ;
margin-bottom : 2 px ;
}
. card-subtitle {
font-size : 13 px ;
color : var ( - - label - secondary ) ;
line-height : 1.4 ;
}
2026-07-07 07:11:50 +00:00
/* Info Row */
2026-07-05 06:41:32 +00:00
. info-row {
display : flex ;
align-items : center ;
padding : 12 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
gap : 12 px ;
}
. info-row : last-child { border-bottom : none ; }
. info-icon {
width : 32 px ; height : 32 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
display : flex ; align-items : center ; justify-content : center ;
font-size : 15 px ;
flex-shrink : 0 ;
}
. info-content { flex : 1 ; min-width : 0 ; }
. info-label { font-size : 15 px ; letter-spacing : -0.23 px ; }
. info-value {
font-size : 13 px ;
color : var ( - - label - secondary ) ;
margin-top : 1 px ;
}
. info-right {
font-size : 15 px ;
font-weight : 600 ;
color : var ( - - label - primary ) ;
text-align : right ;
}
2026-07-07 07:11:50 +00:00
/* Stats Row */
2026-07-05 06:41:32 +00:00
. stats-grid {
display : grid ;
grid-template-columns : 1 fr 1 fr 1 fr ;
gap : 1 px ;
background : var ( - - separator ) ;
border-radius : 0 0 16 px 16 px ;
overflow : hidden ;
}
. stat-cell {
background : var ( - - grouped - bg2 ) ;
padding : 14 px 12 px ;
text-align : center ;
}
. stat-value {
font-size : 20 px ;
font-weight : 700 ;
letter-spacing : -0.5 px ;
color : var ( - - label - primary ) ;
}
. stat-label {
font-size : 11 px ;
color : var ( - - label - tertiary ) ;
margin-top : 2 px ;
text-transform : uppercase ;
letter-spacing : 0.3 px ;
}
2026-07-07 07:11:50 +00:00
/* Zoomer Table */
2026-07-05 06:41:32 +00:00
. zoomer-row {
display : flex ;
align-items : center ;
padding : 14 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
gap : 12 px ;
cursor : pointer ;
transition : background 0.15 s ;
}
. zoomer-row : last-child { border-bottom : none ; }
. zoomer-row : active { background : var ( - - ios - gray6 ) ; }
. zoomer-avatar {
width : 40 px ; height : 40 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - full ) ;
2026-07-05 06:41:32 +00:00
display : flex ; align-items : center ; justify-content : center ;
font-size : 16 px ;
font-weight : 700 ;
color : white ;
flex-shrink : 0 ;
}
. zoomer-info { flex : 1 ; min-width : 0 ; }
. zoomer-name { font-size : 15 px ; letter-spacing : -0.23 px ; font-weight : 500 ; }
. zoomer-tin {
font-size : 12 px ;
color : var ( - - label - tertiary ) ;
font-family : "SF Mono" , Menlo , monospace ;
margin-top : 2 px ;
}
. zoomer-right { text-align : right ; }
. zoomer-amount {
font-size : 15 px ;
font-weight : 600 ;
letter-spacing : -0.23 px ;
color : var ( - - label - primary ) ;
}
. status-badge {
display : inline-flex ;
align-items : center ;
gap : 4 px ;
font-size : 11 px ;
font-weight : 600 ;
padding : 3 px 8 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - xl ) ;
2026-07-05 06:41:32 +00:00
margin-top : 4 px ;
}
. status-verified {
background : rgba ( 52 , 199 , 89 , .12 ) ;
color : var ( - - ios - green ) ;
}
. status-missing {
background : rgba ( 255 , 59 , 48 , .1 ) ;
color : var ( - - ios - red ) ;
}
. status-pending {
background : rgba ( 255 , 149 , 0 , .12 ) ;
color : var ( - - ios - orange ) ;
}
2026-07-07 07:11:50 +00:00
/* Info Section */
2026-07-05 06:41:32 +00:00
. info-card {
background : var ( - - grouped - bg2 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
padding : 16 px ;
margin-bottom : 12 px ;
}
. info-card-title {
font-size : 15 px ;
font-weight : 600 ;
letter-spacing : -0.23 px ;
margin-bottom : 10 px ;
display : flex ;
align-items : center ;
gap : 8 px ;
}
. info-card-text {
font-size : 14 px ;
color : var ( - - label - secondary ) ;
line-height : 1.55 ;
}
. info-card-text strong {
color : var ( - - label - primary ) ;
font-weight : 600 ;
}
2026-07-07 07:11:50 +00:00
/* Export Button */
2026-07-05 06:41:32 +00:00
. export-section {
margin : 8 px 0 24 px ;
}
. btn-primary {
display : flex ;
align-items : center ;
justify-content : center ;
gap : 8 px ;
width : 100 % ;
padding : 16 px ;
background : var ( - - ios - blue ) ;
color : white ;
border : none ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
font-size : 17 px ;
font-weight : 600 ;
letter-spacing : -0.41 px ;
cursor : pointer ;
transition : opacity 0.15 s ;
-webkit- tap-highlight-color : transparent ;
}
. btn-primary : active { opacity : 0.8 ; }
. btn-secondary {
display : flex ;
align-items : center ;
justify-content : center ;
gap : 8 px ;
width : 100 % ;
padding : 14 px ;
background : var ( - - ios - gray6 ) ;
color : var ( - - ios - blue ) ;
border : none ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
font-size : 15 px ;
font-weight : 600 ;
letter-spacing : -0.23 px ;
cursor : pointer ;
margin-top : 10 px ;
transition : opacity 0.15 s ;
}
. btn-secondary : active { opacity : 0.7 ; }
2026-07-07 07:11:50 +00:00
/* Period Card */
2026-07-05 06:41:32 +00:00
. period-row {
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 14 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
}
. period-row : last-child { border-bottom : none ; }
. period-label { font-size : 15 px ; letter-spacing : -0.23 px ; }
. period-value { font-size : 15 px ; font-weight : 500 ; color : var ( - - label - secondary ) ; }
2026-07-07 07:11:50 +00:00
/* Divider Text */
2026-07-05 06:41:32 +00:00
. divider-text {
text-align : center ;
font-size : 12 px ;
color : var ( - - label - tertiary ) ;
padding : 8 px 0 16 px ;
line-height : 1.4 ;
}
2026-07-07 07:11:50 +00:00
/* Toast */
2026-07-05 06:41:32 +00:00
. toast {
position : fixed ;
bottom : calc ( var ( - - safe - bottom ) + 24 px ) ;
left : 50 % ; transform : translateX ( -50 % ) ;
background : rgba ( 242 , 242 , 247 , .85 ) ;
color : white ;
font-size : 14 px ;
font-weight : 500 ;
padding : 12 px 20 px ;
border-radius : 100 px ;
white-space : nowrap ;
opacity : 0 ;
transition : opacity 0.25 s ;
pointer-events : none ;
z-index : 9999 ;
display : flex ;
align-items : center ;
gap : 8 px ;
}
. toast . show { opacity : 1 ; }
2026-07-07 07:11:50 +00:00
/* Progress Bar */
2026-07-05 06:41:32 +00:00
. progress-track {
height : 4 px ;
background : var ( - - ios - gray5 ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - sm ) ;
2026-07-05 06:41:32 +00:00
margin : 12 px 16 px 14 px ;
overflow : hidden ;
}
. progress-fill {
height : 100 % ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - sm ) ;
2026-07-05 06:41:32 +00:00
background : var ( - - ios - blue ) ;
transition : width 0.5 s ease ;
}
@ media ( max-width : 640px ) {
. hero h1 { font-size : 2 rem !important ; }
. hero p { font-size : 1 rem !important ; }
. card { padding : 1.5 rem !important ; }
. grid { grid-template-columns : 1 fr !important ; }
. btn { padding : 0.75 rem 1.5 rem !important ; font-size : 1 rem !important ; }
}
2026-07-14 15:27:33 +00:00
/* QUIXZOOM STANDARD — Dark Theme */
: root {
--qz-bg : #0a0a0a ;
--qz-surface : #111111 ;
--qz-surface-2 : #1a1a1a ;
--qz-border : rgba ( 255 , 255 , 255 , 0.08 ) ;
--qz-text : #e8e8e8 ;
--qz-text-dim : #a0a0a0 ;
--qz-text-muted : #6b6b6b ;
--qz-blue : #007AFF ;
--qz-blue-dark : #0056CC ;
--qz-radius : 10 px ;
}
* { margin : 0 ; padding : 0 ; box-sizing : border-box ; }
body {
font-family : - apple-system , BlinkMacSystemFont , 'Inter' , sans-serif ;
background : var ( - - qz - bg ) ;
color : var ( - - qz - text ) ;
line-height : 1.6 ;
-webkit- font-smoothing : antialiased ;
}
/* Navigation */
. qz-nav {
position : fixed ; top : 0 ; left : 0 ; right : 0 ; z-index : 100 ;
display : flex ; align-items : center ; justify-content : space-between ;
padding : 0 24 px ; height : 56 px ;
background : rgba ( 255 , 255 , 255 , 0.92 ) ;
backdrop-filter : blur ( 16 px ) ;
border-bottom : 1 px solid var ( - - qz - border ) ;
}
. qz-nav-logo { font-size : 18 px ; font-weight : 700 ; color : #fff ; text-decoration : none ; }
. qz-nav-links { display : flex ; gap : 24 px ; list-style : none ; }
. qz-nav-links a { font-size : 14 px ; color : var ( - - qz - text - dim ) ; text-decoration : none ; transition : color 0.2 s ; }
. qz-nav-links a : hover { color : #fff ; }
/* Buttons */
. qz-btn {
display : inline-flex ; align-items : center ; gap : 6 px ;
padding : 12 px 24 px ; border-radius : var ( - - qz - radius ) ;
font-size : 15 px ; font-weight : 600 ; text-decoration : none ;
transition : all 0.2 s ; cursor : pointer ; border : none ;
}
. qz-btn-primary {
background : var ( - - qz - blue ) ; color : #fff ;
}
. qz-btn-primary : hover {
background : var ( - - qz - blue - dark ) ; transform : translateY ( -1 px ) ;
}
. qz-btn-ghost {
background : transparent ; color : var ( - - qz - text ) ;
border : 1 px solid var ( - - qz - border ) ;
}
. qz-btn-ghost : hover {
border-color : var ( - - qz - blue ) ; color : var ( - - qz - blue ) ;
}
/* Cards */
. qz-card {
background : var ( - - qz - surface ) ;
border : 1 px solid var ( - - qz - border ) ;
border-radius : var ( - - qz - radius ) ;
padding : 24 px ;
transition : transform 0.2 s , border-color 0.2 s ;
}
. qz-card : hover {
transform : translateY ( -2 px ) ;
border-color : rgba ( 0 , 122 , 255 , 0.3 ) ;
}
/* Footer */
. qz-footer {
border-top : 1 px solid var ( - - qz - border ) ;
padding : 40 px 24 px ;
text-align : center ;
color : var ( - - qz - text - dim ) ;
font-size : 14 px ;
}
/* Banner */
. qz-banner {
background : #001E50 ;
color : rgba ( 255 , 255 , 255 , 0.55 ) ;
text-align : center ;
padding : 10 px ;
font-size : 12 px ;
}
. qz-banner a { color : rgba ( 255 , 255 , 255 , 0.8 ) ; text-decoration : none ; }
@ media ( max-width : 768px ) {
. qz-nav-links { display : none ; }
}
2026-07-05 06:41:32 +00:00
< / 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 ; }
@ media ( max-width : 640px ) {
. hero h1 { font-size : 2 rem !important ; }
. hero p { font-size : 1 rem !important ; }
. card { padding : 1.5 rem !important ; }
. grid { grid-template-columns : 1 fr !important ; }
. btn { padding : 0.75 rem 1.5 rem !important ; font-size : 1 rem !important ; }
}
2026-07-14 15:27:33 +00:00
/* QUIXZOOM STANDARD — Dark Theme */
: root {
--qz-bg : #0a0a0a ;
--qz-surface : #111111 ;
--qz-surface-2 : #1a1a1a ;
--qz-border : rgba ( 255 , 255 , 255 , 0.08 ) ;
--qz-text : #e8e8e8 ;
--qz-text-dim : #a0a0a0 ;
--qz-text-muted : #6b6b6b ;
--qz-blue : #007AFF ;
--qz-blue-dark : #0056CC ;
--qz-radius : 10 px ;
}
* { margin : 0 ; padding : 0 ; box-sizing : border-box ; }
body {
font-family : - apple-system , BlinkMacSystemFont , 'Inter' , sans-serif ;
background : var ( - - qz - bg ) ;
color : var ( - - qz - text ) ;
line-height : 1.6 ;
-webkit- font-smoothing : antialiased ;
}
/* Navigation */
. qz-nav {
position : fixed ; top : 0 ; left : 0 ; right : 0 ; z-index : 100 ;
display : flex ; align-items : center ; justify-content : space-between ;
padding : 0 24 px ; height : 56 px ;
background : rgba ( 255 , 255 , 255 , 0.92 ) ;
backdrop-filter : blur ( 16 px ) ;
border-bottom : 1 px solid var ( - - qz - border ) ;
}
. qz-nav-logo { font-size : 18 px ; font-weight : 700 ; color : #fff ; text-decoration : none ; }
. qz-nav-links { display : flex ; gap : 24 px ; list-style : none ; }
. qz-nav-links a { font-size : 14 px ; color : var ( - - qz - text - dim ) ; text-decoration : none ; transition : color 0.2 s ; }
. qz-nav-links a : hover { color : #fff ; }
/* Buttons */
. qz-btn {
display : inline-flex ; align-items : center ; gap : 6 px ;
padding : 12 px 24 px ; border-radius : var ( - - qz - radius ) ;
font-size : 15 px ; font-weight : 600 ; text-decoration : none ;
transition : all 0.2 s ; cursor : pointer ; border : none ;
}
. qz-btn-primary {
background : var ( - - qz - blue ) ; color : #fff ;
}
. qz-btn-primary : hover {
background : var ( - - qz - blue - dark ) ; transform : translateY ( -1 px ) ;
}
. qz-btn-ghost {
background : transparent ; color : var ( - - qz - text ) ;
border : 1 px solid var ( - - qz - border ) ;
}
. qz-btn-ghost : hover {
border-color : var ( - - qz - blue ) ; color : var ( - - qz - blue ) ;
}
/* Cards */
. qz-card {
background : var ( - - qz - surface ) ;
border : 1 px solid var ( - - qz - border ) ;
border-radius : var ( - - qz - radius ) ;
padding : 24 px ;
transition : transform 0.2 s , border-color 0.2 s ;
}
. qz-card : hover {
transform : translateY ( -2 px ) ;
border-color : rgba ( 0 , 122 , 255 , 0.3 ) ;
}
/* Footer */
. qz-footer {
border-top : 1 px solid var ( - - qz - border ) ;
padding : 40 px 24 px ;
text-align : center ;
color : var ( - - qz - text - dim ) ;
font-size : 14 px ;
}
/* Banner */
. qz-banner {
background : #001E50 ;
color : rgba ( 255 , 255 , 255 , 0.55 ) ;
text-align : center ;
padding : 10 px ;
font-size : 12 px ;
}
. qz-banner a { color : rgba ( 255 , 255 , 255 , 0.8 ) ; text-decoration : none ; }
@ media ( max-width : 768px ) {
. qz-nav-links { display : none ; }
}
2026-07-05 06:41:32 +00:00
< / style >
2026-07-14 09:58:53 +00:00
< script type = "module" src = "https://auth.quixzoom.com/site-auth-snippet.js" > < / script >
2026-07-05 06:41:32 +00:00
< / head >
< body >
<!-- Navigation Bar -->
< div class = "navbar" >
2026-07-07 07:11:50 +00:00
< div class = "navbar-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "navbar-title" > DAC7 Rapportering< / div >
< div class = "navbar-badge" > 2026< / div >
< / div >
< div class = "content" >
<!-- Deadline Alert -->
< div class = "deadline-alert" >
< div class = "alert-icon" > ⏰< / div >
< div class = "alert-body" >
< div class = "alert-title" > Deadline: 31 januari 2027< / div >
< div class = "alert-desc" > DAC7-rapporten för kalenderår 2026 ska vara inlämnad till Skatteverket senast 31 jan 2027.< / div >
< / div >
< div >
< div class = "days-left" id = "daysLeft" > —< / div >
< div class = "days-label" > dagar kvar< / div >
< / div >
< / div >
<!-- What is DAC7 -->
< div class = "section-header" > Om DAC7< / div >
< div class = "info-card" >
2026-07-07 07:11:50 +00:00
< div class = "info-card-title" > < svg width = "16" height = "16" viewBox = "0 0 16 16" fill = "none" > < rect x = "3" y = "2" width = "10" height = "12" rx = "1" stroke = "#666" stroke-width = "1.5" / > < path d = "M6 5H10M6 8H10M6 11H8" stroke = "#666" stroke-width = "1.5" stroke-linecap = "round" / > < / svg > Vad är DAC7?< / div >
2026-07-05 06:41:32 +00:00
< div class = "info-card-text" >
< strong > EU-direktiv 2021/514 (DAC7)< / strong > kräver att digitala plattformar rapporterar säljares (zoomers) intäkter till skattemyndigheterna. quiXzoom är en < strong > rapporteringsskyldig plattformsoperatör< / strong > och måste varje år lämna uppgifter om zoomers som:
< br > < br >
• Genomfört < strong > ≥ 30 transaktioner< / strong > under kalenderåret, < em > eller< / em > < br >
2026-07-14 09:58:53 +00:00
• Tjänat in < strong > ≥ 2 000 USD< / strong > under kalenderåret
2026-07-05 06:41:32 +00:00
< br > < br >
Rapporteringen sker i < strong > XML-format< / strong > enligt Skatteverkets tekniska specifikation. Första rapportering avser kalenderår 2023.
< / div >
< / div >
< div class = "info-card" >
2026-07-07 07:11:50 +00:00
< div class = "info-card-title" > Vår skyldighet< / div >
2026-07-05 06:41:32 +00:00
< div class = "info-card-text" >
quiXzoom samlar in < strong > TIN (skatteregistreringsnummer)< / strong > och personuppgifter från alla aktiva zoomers. Vi verifierar uppgifterna och rapporterar automatiskt till Skatteverket via deras API-integration. Zoomers informeras om rapporteringen i tjänstevillkoren.
< / div >
< / div >
<!-- Period -->
< div class = "section-header" > Rapporteringsperiod< / div >
< div class = "card" >
< div class = "period-row" >
< span class = "period-label" > Rapporteringsår< / span >
< span class = "period-value" > Kalenderår 2026< / span >
< / div >
< div class = "period-row" >
< span class = "period-label" > Period< / span >
< span class = "period-value" > 2026-01-01 — 2026-12-31< / span >
< / div >
< div class = "period-row" >
< span class = "period-label" > Inlämningsfrist< / span >
< span class = "period-value" style = "color: var(--ios-red); font-weight: 600;" > 31 januari 2027< / span >
< / div >
< div class = "period-row" >
< span class = "period-label" > Rapporteringsformat< / span >
< span class = "period-value" > XML (DAC7 schema)< / span >
< / div >
< div class = "period-row" >
< span class = "period-label" > Mottagare< / span >
< span class = "period-value" > Skatteverket< / span >
< / div >
< div class = "period-row" >
< span class = "period-label" > Status< / span >
< span class = "period-value" style = "color: var(--ios-orange);" > ⏳ Pågående insamling< / span >
< / div >
< / div >
<!-- Summary Stats -->
< div class = "section-header" > Sammanfattning< / div >
< div class = "card" >
< div style = "padding: 14px 16px 0; border-bottom: 0.5px solid var(--separator);" >
< div style = "font-size: 13px; color: var(--label-secondary); margin-bottom: 6px;" > Total rapporterad intäkt 2026< / div >
< div style = "font-size: 28px; font-weight: 700; letter-spacing: -1px; color: var(--label-primary); margin-bottom: 4px;" > 43 850 SEK< / div >
< div style = "font-size: 12px; color: var(--label-tertiary); padding-bottom: 12px;" > Summa för 5 rapporterade zoomers< / div >
<!-- Progress bar: TIN verified -->
< div style = "font-size: 12px; color: var(--label-secondary); display: flex; justify-content: space-between; margin-bottom: 4px;" >
< span > TIN-verifiering< / span >
< span style = "font-weight: 600; color: var(--ios-green);" > 3 av 5 klara< / span >
< / div >
< div class = "progress-track" >
< div class = "progress-fill" style = "width: 60%;" > < / div >
< / div >
< / div >
< div class = "stats-grid" >
< div class = "stat-cell" >
< div class = "stat-value" style = "color: var(--ios-green);" > 3< / div >
< div class = "stat-label" > TIN verifierad< / div >
< / div >
< div class = "stat-cell" >
< div class = "stat-value" style = "color: var(--ios-red);" > 1< / div >
< div class = "stat-label" > TIN saknas< / div >
< / div >
< div class = "stat-cell" >
< div class = "stat-value" style = "color: var(--ios-orange);" > 1< / div >
< div class = "stat-label" > Under utredning< / div >
< / div >
< / div >
< / div >
<!-- Zoomer List -->
< div class = "section-header" > Rapporterade zoomers (5)< / div >
< div class = "card" >
<!-- Zoomer 1 - verified -->
< div class = "zoomer-row" onclick = "showZoomerDetail('Alicia Bergström', '198804127654', '12600', 'verified')" >
< div class = "zoomer-avatar" style = "background: linear-gradient(135deg, #007AFF, #5856D6);" > A< / div >
< div class = "zoomer-info" >
< div class = "zoomer-name" > Alicia Bergström< / div >
< div class = "zoomer-tin" > TIN: 8804127654< / div >
2026-07-07 07:11:50 +00:00
< span class = "status-badge status-verified" > < svg width = "16" height = "16" viewBox = "0 0 16 16" fill = "none" > < path d = "M3 8L6.5 11.5L13 4.5" stroke = "#22c55e" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" / > < / svg > TIN verifierad< / span >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "zoomer-right" >
< div class = "zoomer-amount" > 12 600 SEK< / div >
< div style = "font-size: 11px; color: var(--label-tertiary); margin-top: 2px;" > 47 transaktioner< / div >
< / div >
< / div >
<!-- Zoomer 2 - verified -->
< div class = "zoomer-row" onclick = "showZoomerDetail('Mikael Thorsson', '199103284512', '9750', 'verified')" >
< div class = "zoomer-avatar" style = "background: linear-gradient(135deg, #34C759, #30B0C7);" > M< / div >
< div class = "zoomer-info" >
< div class = "zoomer-name" > Mikael Thorsson< / div >
< div class = "zoomer-tin" > TIN: 9103284512< / div >
2026-07-07 07:11:50 +00:00
< span class = "status-badge status-verified" > < svg width = "16" height = "16" viewBox = "0 0 16 16" fill = "none" > < path d = "M3 8L6.5 11.5L13 4.5" stroke = "#22c55e" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" / > < / svg > TIN verifierad< / span >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "zoomer-right" >
< div class = "zoomer-amount" > 9 750 SEK< / div >
< div style = "font-size: 11px; color: var(--label-tertiary); margin-top: 2px;" > 38 transaktioner< / div >
< / div >
< / div >
<!-- Zoomer 3 - missing TIN -->
< div class = "zoomer-row" onclick = "showZoomerDetail('Fatima Okonkwo', 'SAKNAS', '7200', 'missing')" >
< div class = "zoomer-avatar" style = "background: linear-gradient(135deg, #FF3B30, #FF9500);" > F< / div >
< div class = "zoomer-info" >
< div class = "zoomer-name" > Fatima Okonkwo< / div >
< div class = "zoomer-tin" > TIN: EJ REGISTRERAT< / div >
2026-07-07 07:11:50 +00:00
< span class = "status-badge status-missing" > < svg width = "16" height = "16" viewBox = "0 0 16 16" fill = "none" > < path d = "M4 4L12 12M12 4L4 12" stroke = "#ef4444" stroke-width = "2" stroke-linecap = "round" / > < / svg > TIN saknas< / span >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "zoomer-right" >
< div class = "zoomer-amount" > 7 200 SEK< / div >
< div style = "font-size: 11px; color: var(--label-tertiary); margin-top: 2px;" > 31 transaktioner< / div >
< / div >
< / div >
<!-- Zoomer 4 - pending -->
< div class = "zoomer-row" onclick = "showZoomerDetail('Johan Lindkvist', '197612053311', '11900', 'pending')" >
< div class = "zoomer-avatar" style = "background: linear-gradient(135deg, #FF9500, #FFCC00);" > J< / div >
< div class = "zoomer-info" >
< div class = "zoomer-name" > Johan Lindkvist< / div >
< div class = "zoomer-tin" > TIN: 7612053311< / div >
< span class = "status-badge status-pending" > ⏳ Under utredning< / span >
< / div >
< div class = "zoomer-right" >
< div class = "zoomer-amount" > 11 900 SEK< / div >
< div style = "font-size: 11px; color: var(--label-tertiary); margin-top: 2px;" > 44 transaktioner< / div >
< / div >
< / div >
<!-- Zoomer 5 - verified -->
< div class = "zoomer-row" onclick = "showZoomerDetail('Sofia Wennberg', '200002157890', '2400', 'verified')" >
< div class = "zoomer-avatar" style = "background: linear-gradient(135deg, #AF52DE, #5856D6);" > S< / div >
< div class = "zoomer-info" >
< div class = "zoomer-name" > Sofia Wennberg< / div >
< div class = "zoomer-tin" > TIN: 0002157890< / div >
2026-07-07 07:11:50 +00:00
< span class = "status-badge status-verified" > < svg width = "16" height = "16" viewBox = "0 0 16 16" fill = "none" > < path d = "M3 8L6.5 11.5L13 4.5" stroke = "#22c55e" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" / > < / svg > TIN verifierad< / span >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "zoomer-right" >
< div class = "zoomer-amount" > 2 400 SEK< / div >
< div style = "font-size: 11px; color: var(--label-tertiary); margin-top: 2px;" > 32 transaktioner< / div >
< / div >
< / div >
< / div >
< div class = "divider-text" >
2026-07-14 09:58:53 +00:00
Alla zoomers med ≥30 transaktioner eller ≥2 000 USD intäkt under kalenderåret inkluderas i rapporten.
2026-07-05 06:41:32 +00:00
< / div >
<!-- Export Section -->
< div class = "section-header" > Exportera rapport< / div >
< div class = "export-section" >
< button class = "btn-primary" onclick = "exportXML()" >
2026-07-07 07:11:50 +00:00
< span > < / span >
2026-07-05 06:41:32 +00:00
Exportera XML till Skatteverket
< / button >
< button class = "btn-secondary" onclick = "downloadPreview()" >
2026-07-07 07:11:50 +00:00
< span > < / span >
2026-07-05 06:41:32 +00:00
Förhandsgranska XML
< / button >
< / div >
<!-- Footer note -->
< div class = "info-card" style = "margin-bottom: 24px;" >
2026-07-07 07:11:50 +00:00
< div class = "info-card-title" > < svg width = "20" height = "20" viewBox = "0 0 20 20" fill = "none" > < path d = "M10 3L17 17H3L10 3Z" stroke = "#f59e0b" stroke-width = "2" / > < path d = "M10 8V12M10 14V14.5" stroke = "#f59e0b" stroke-width = "2" stroke-linecap = "round" / > < / svg > Viktigt att notera< / div >
2026-07-05 06:41:32 +00:00
< div class = "info-card-text" >
Zoomers med < strong > saknat TIN< / strong > måste kontaktas och komplettera sina uppgifter < strong > innan export< / strong > . Rapporten kan inte inkludera saknade skattenummer.
< br > < br >
Har du frågor om DAC7-rapportering? Kontakta < strong > legal@quixzoom.se< / strong >
< / div >
< / div >
< / div > <!-- /content -->
<!-- Toast -->
< div class = "toast" id = "toast" > < / div >
< script >
2026-07-07 07:11:50 +00:00
// Days Until Deadline
2026-07-05 06:41:32 +00:00
( function ( ) {
const deadline = new Date ( '2027-01-31T23:59:59' ) ;
const now = new Date ( ) ;
const diff = Math . ceil ( ( deadline - now ) / ( 1000 * 60 * 60 * 24 ) ) ;
const el = document . getElementById ( 'daysLeft' ) ;
if ( el ) el . textContent = diff > 0 ? diff : '0' ;
} ) ( ) ;
2026-07-07 07:11:50 +00:00
// Toast Helper
2026-07-05 06:41:32 +00:00
function showToast ( msg , duration = 2500 ) {
const t = document . getElementById ( 'toast' ) ;
t . textContent = msg ;
t . classList . add ( 'show' ) ;
setTimeout ( ( ) => t . classList . remove ( 'show' ) , duration ) ;
}
2026-07-07 07:11:50 +00:00
// Zoomer Detail
2026-07-05 06:41:32 +00:00
function showZoomerDetail ( name , tin , amount , status ) {
const statusMap = {
2026-07-07 07:11:50 +00:00
verified : '<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#22c55e" stroke-width="2"/><path d="M6 10L9 13L14 7" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> TIN verifierad' ,
missing : '<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#ef4444" stroke-width="2"/><path d="M7 7L13 13M13 7L7 13" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> TIN saknas' ,
2026-07-05 06:41:32 +00:00
pending : '⏳ Under utredning'
} ;
showToast ( ` ${ name } · ${ parseInt ( amount ) . toLocaleString ( 'sv-SE' ) } SEK · ${ statusMap [ status ] } ` ) ;
}
2026-07-07 07:11:50 +00:00
// Export XML
2026-07-05 06:41:32 +00:00
function exportXML ( ) {
const btn = document . querySelector ( '.btn-primary' ) ;
const orig = btn . innerHTML ;
btn . innerHTML = '<span>⏳</span> Genererar XML...' ;
btn . style . opacity = '0.7' ;
setTimeout ( ( ) => {
const xml = generateDAC7XML ( ) ;
const blob = new Blob ( [ xml ] , { type : 'application/xml' } ) ;
const url = URL . createObjectURL ( blob ) ;
const a = document . createElement ( 'a' ) ;
a . href = url ;
a . download = ` DAC7_quiXzoom_2026_ ${ new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) } .xml ` ;
a . click ( ) ;
URL . revokeObjectURL ( url ) ;
btn . innerHTML = orig ;
btn . style . opacity = '' ;
2026-07-07 07:11:50 +00:00
showToast ( '<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#22c55e" stroke-width="2"/><path d="M6 10L9 13L14 7" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> XML-fil exporterad!' , 3000 ) ;
2026-07-05 06:41:32 +00:00
} , 1200 ) ;
}
2026-07-07 07:11:50 +00:00
// Preview XML
2026-07-05 06:41:32 +00:00
function downloadPreview ( ) {
2026-07-07 07:11:50 +00:00
showToast ( ' Öppnar förhandsgranskning...' ) ;
2026-07-05 06:41:32 +00:00
setTimeout ( ( ) => {
const xml = generateDAC7XML ( ) ;
const win = window . open ( '' , '_blank' ) ;
if ( win ) {
win . document . write ( '<pre style="font-family:monospace;font-size:12px;padding:20px;white-space:pre-wrap;">' + escapeHtml ( xml ) + '</pre>' ) ;
}
} , 500 ) ;
}
function escapeHtml ( str ) {
return str . replace ( /&/g , '&' ) . replace ( /</g , '<' ) . replace ( />/g , '>' ) ;
}
2026-07-07 07:11:50 +00:00
// DAC7 XML Generator
2026-07-05 06:41:32 +00:00
function generateDAC7XML ( ) {
const now = new Date ( ) . toISOString ( ) ;
const zoomers = [
{ name : 'Alicia Bergström' , tin : '198804127654' , amount : 12600 , currency : 'SEK' , transactions : 47 , status : 'verified' } ,
{ name : 'Mikael Thorsson' , tin : '199103284512' , amount : 9750 , currency : 'SEK' , transactions : 38 , status : 'verified' } ,
{ name : 'Sofia Wennberg' , tin : '200002157890' , amount : 2400 , currency : 'SEK' , transactions : 32 , status : 'verified' } ,
// Excluded: Fatima (missing TIN), Johan (pending)
] ;
const sellerRows = zoomers . map ( z => `
<Seller>
<SellerID IDType="TIN" issuedBy="SE"> ${ z . tin } </SellerID>
<Name> ${ z . name } </Name>
<Address>
<CountryCode>SE</CountryCode>
</Address>
<ResCountryCode>SE</ResCountryCode>
<Consideration currCode=" ${ z . currency } "> ${ z . amount } .00</Consideration>
<Fees currCode=" ${ z . currency } ">0.00</Fees>
<Taxes currCode=" ${ z . currency } ">0.00</Taxes>
<NumberOfActivities> ${ z . transactions } </NumberOfActivities>
</Seller> ` ) . join ( '' ) ;
return ` <?xml version="1.0" encoding="UTF-8"?>
<!-- DAC7 Rapportering - EU-direktiv 2021/514 -->
<!-- Rapporteringsskyldig plattformsoperatör: quiXzoom AB -->
<!-- Genererad: ${ now } -->
<DPI:FATCA_OECD version="2.0"
xmlns:DPI="urn:oecd:ties:dpi:v2"
xmlns:stf="urn:oecd:ties:stf:v4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DPI:MessageSpec>
<DPI:SendingEntityIN>5566778899</DPI:SendingEntityIN>
<DPI:TransmittingCountry>SE</DPI:TransmittingCountry>
<DPI:ReceivingCountry>SE</DPI:ReceivingCountry>
<DPI:MessageType>DPI</DPI:MessageType>
<DPI:MessageRefId>quixzoom-dac7-2026- ${ Date . now ( ) } </DPI:MessageRefId>
<DPI:ReportingPeriod>2026-12-31</DPI:ReportingPeriod>
<DPI:Timestamp> ${ now } </DPI:Timestamp>
</DPI:MessageSpec>
<DPI:DPIBody>
<DPI:PlatformOperator>
<DPI:ResCountryCode>SE</DPI:ResCountryCode>
<DPI:TIN issuedBy="SE">5566778899</DPI:TIN>
<DPI:Name>quiXzoom AB</DPI:Name>
<DPI:PlatformBusinessName>quiXzoom</DPI:PlatformBusinessName>
<DPI:Address>
<DPI:CountryCode>SE</DPI:CountryCode>
</DPI:Address>
</DPI:PlatformOperator>
<DPI:OtherActivities> ${ sellerRows }
</DPI:OtherActivities>
</DPI:DPIBody>
</DPI:FATCA_OECD> ` ;
}
< / script >
2026-07-14 09:58:53 +00:00
<!-- quiXzoom Mina Sidor - Universal Header Component -->
<!-- Injicera detta i <head> på alla quiXzoom - sajter -->
< style >
. qz-auth-bar {
position : fixed ;
top : 0 ;
left : 0 ;
right : 0 ;
height : 48 px ;
background : #0A0A0A ;
border-bottom : 1 px solid rgba ( 255 , 255 , 255 , 0.1 ) ;
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 0 20 px ;
z-index : 9999 ;
font-family : - apple-system , BlinkMacSystemFont , 'SF Pro Display' , 'Segoe UI' , Roboto , sans-serif ;
}
. qz-auth-bar . qz-logo {
font-size : 18 px ;
font-weight : 700 ;
color : #fff ;
text-decoration : none ;
letter-spacing : -0.5 px ;
}
. qz-auth-bar . qz-logo span {
color : #007AFF ;
}
. qz-auth-bar . qz-nav {
display : flex ;
gap : 8 px ;
align-items : center ;
}
. qz-auth-bar . qz-btn {
padding : 8 px 16 px ;
border-radius : 8 px ;
font-size : 14 px ;
font-weight : 500 ;
cursor : pointer ;
transition : all 0.2 s ;
border : none ;
text-decoration : none ;
}
. qz-auth-bar . qz-btn-primary {
background : #007AFF ;
color : white ;
}
. qz-auth-bar . qz-btn-primary : hover {
background : #0056CC ;
}
. qz-auth-bar . qz-btn-ghost {
background : transparent ;
color : rgba ( 255 , 255 , 255 , 0.8 ) ;
}
. qz-auth-bar . qz-btn-ghost : hover {
background : rgba ( 255 , 255 , 255 , 0.1 ) ;
color : white ;
}
. qz-auth-bar . qz-user {
display : flex ;
align-items : center ;
gap : 8 px ;
color : white ;
font-size : 14 px ;
}
. qz-auth-bar . qz-avatar {
width : 32 px ;
height : 32 px ;
border-radius : 50 % ;
background : #007AFF ;
display : flex ;
align-items : center ;
justify-content : center ;
font-weight : 600 ;
font-size : 14 px ;
}
. qz-auth-bar . qz-dropdown {
position : relative ;
}
. qz-auth-bar . qz-dropdown-menu {
position : absolute ;
top : 40 px ;
right : 0 ;
background : #1C1C1E ;
border : 1 px solid rgba ( 255 , 255 , 255 , 0.1 ) ;
border-radius : 12 px ;
padding : 8 px ;
min-width : 200 px ;
display : none ;
box-shadow : 0 8 px 32 px rgba ( 0 , 0 , 0 , 0.4 ) ;
}
. qz-auth-bar . qz-dropdown-menu . active {
display : block ;
}
. qz-auth-bar . qz-dropdown-item {
padding : 10 px 12 px ;
border-radius : 8 px ;
color : white ;
text-decoration : none ;
display : flex ;
align-items : center ;
gap : 10 px ;
font-size : 14 px ;
transition : background 0.2 s ;
}
. qz-auth-bar . qz-dropdown-item : hover {
background : rgba ( 255 , 255 , 255 , 0.1 ) ;
}
. qz-auth-bar . qz-dropdown-divider {
height : 1 px ;
background : rgba ( 255 , 255 , 255 , 0.1 ) ;
margin : 8 px 0 ;
}
. qz-auth-bar . qz-balance {
background : rgba ( 0 , 122 , 255 , 0.15 ) ;
color : #007AFF ;
padding : 4 px 10 px ;
border-radius : 6 px ;
font-size : 13 px ;
font-weight : 600 ;
}
@ media ( max-width : 640px ) {
. qz-auth-bar . qz-nav . qz-btn-ghost : not ( . qz-user ) {
display : none ;
}
}
2026-07-14 15:27:33 +00:00
/* QUIXZOOM STANDARD — Dark Theme */
: root {
--qz-bg : #0a0a0a ;
--qz-surface : #111111 ;
--qz-surface-2 : #1a1a1a ;
--qz-border : rgba ( 255 , 255 , 255 , 0.08 ) ;
--qz-text : #e8e8e8 ;
--qz-text-dim : #a0a0a0 ;
--qz-text-muted : #6b6b6b ;
--qz-blue : #007AFF ;
--qz-blue-dark : #0056CC ;
--qz-radius : 10 px ;
}
* { margin : 0 ; padding : 0 ; box-sizing : border-box ; }
body {
font-family : - apple-system , BlinkMacSystemFont , 'Inter' , sans-serif ;
background : var ( - - qz - bg ) ;
color : var ( - - qz - text ) ;
line-height : 1.6 ;
-webkit- font-smoothing : antialiased ;
}
/* Navigation */
. qz-nav {
position : fixed ; top : 0 ; left : 0 ; right : 0 ; z-index : 100 ;
display : flex ; align-items : center ; justify-content : space-between ;
padding : 0 24 px ; height : 56 px ;
background : rgba ( 255 , 255 , 255 , 0.92 ) ;
backdrop-filter : blur ( 16 px ) ;
border-bottom : 1 px solid var ( - - qz - border ) ;
}
. qz-nav-logo { font-size : 18 px ; font-weight : 700 ; color : #fff ; text-decoration : none ; }
. qz-nav-links { display : flex ; gap : 24 px ; list-style : none ; }
. qz-nav-links a { font-size : 14 px ; color : var ( - - qz - text - dim ) ; text-decoration : none ; transition : color 0.2 s ; }
. qz-nav-links a : hover { color : #fff ; }
/* Buttons */
. qz-btn {
display : inline-flex ; align-items : center ; gap : 6 px ;
padding : 12 px 24 px ; border-radius : var ( - - qz - radius ) ;
font-size : 15 px ; font-weight : 600 ; text-decoration : none ;
transition : all 0.2 s ; cursor : pointer ; border : none ;
}
. qz-btn-primary {
background : var ( - - qz - blue ) ; color : #fff ;
}
. qz-btn-primary : hover {
background : var ( - - qz - blue - dark ) ; transform : translateY ( -1 px ) ;
}
. qz-btn-ghost {
background : transparent ; color : var ( - - qz - text ) ;
border : 1 px solid var ( - - qz - border ) ;
}
. qz-btn-ghost : hover {
border-color : var ( - - qz - blue ) ; color : var ( - - qz - blue ) ;
}
/* Cards */
. qz-card {
background : var ( - - qz - surface ) ;
border : 1 px solid var ( - - qz - border ) ;
border-radius : var ( - - qz - radius ) ;
padding : 24 px ;
transition : transform 0.2 s , border-color 0.2 s ;
}
. qz-card : hover {
transform : translateY ( -2 px ) ;
border-color : rgba ( 0 , 122 , 255 , 0.3 ) ;
}
/* Footer */
. qz-footer {
border-top : 1 px solid var ( - - qz - border ) ;
padding : 40 px 24 px ;
text-align : center ;
color : var ( - - qz - text - dim ) ;
font-size : 14 px ;
}
/* Banner */
. qz-banner {
background : #001E50 ;
color : rgba ( 255 , 255 , 255 , 0.55 ) ;
text-align : center ;
padding : 10 px ;
font-size : 12 px ;
}
. qz-banner a { color : rgba ( 255 , 255 , 255 , 0.8 ) ; text-decoration : none ; }
@ media ( max-width : 768px ) {
. qz-nav-links { display : none ; }
}
2026-07-14 09:58:53 +00:00
< / style >
2026-07-14 15:27:33 +00:00
<!--
quiXzoom Universal Auth Snippet v2.0
Add this to ALL quiXzoom sites for seamless cross - domain login
Features:
- Silent login (auto - refresh tokens)
- Cross - domain cookie sync
- Real - time auth state updates
- Mobile app compatible
-->
<!-- Auth bar styles -->
< style >
# qz-auth-bar {
position : fixed ;
top : 0 ;
left : 0 ;
right : 0 ;
height : 48 px ;
background : #0A0A0A ;
border-bottom : 1 px solid rgba ( 255 , 255 , 255 , 0.1 ) ;
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 0 20 px ;
z-index : 9999 ;
font-family : - apple-system , BlinkMacSystemFont , 'SF Pro Display' , 'Segoe UI' , Roboto , sans-serif ;
}
# qz-auth-bar . qz-logo {
font-size : 18 px ;
font-weight : 700 ;
color : #fff ;
text-decoration : none ;
letter-spacing : -0.5 px ;
}
# qz-auth-bar . qz-logo span { color : #007AFF ; }
# qz-auth-bar . qz-nav {
display : flex ;
gap : 8 px ;
align-items : center ;
}
# qz-auth-bar . qz-btn {
padding : 8 px 16 px ;
border-radius : 8 px ;
font-size : 14 px ;
font-weight : 500 ;
cursor : pointer ;
transition : all 0.2 s ;
border : none ;
text-decoration : none ;
}
# qz-auth-bar . qz-btn-primary {
background : #007AFF ;
color : white ;
}
# qz-auth-bar . qz-btn-primary : hover { background : #0056CC ; }
# qz-auth-bar . qz-btn-ghost {
background : transparent ;
color : rgba ( 255 , 255 , 255 , 0.8 ) ;
}
# qz-auth-bar . qz-btn-ghost : hover {
background : rgba ( 255 , 255 , 255 , 0.1 ) ;
color : white ;
}
# qz-auth-bar . qz-user-menu {
position : relative ;
}
# qz-auth-bar . qz-dropdown {
position : absolute ;
top : 40 px ;
right : 0 ;
background : #1C1C1E ;
border : 1 px solid rgba ( 255 , 255 , 255 , 0.1 ) ;
border-radius : 12 px ;
padding : 8 px ;
min-width : 220 px ;
display : none ;
box-shadow : 0 8 px 32 px rgba ( 0 , 0 , 0 , 0.4 ) ;
}
# qz-auth-bar . qz-dropdown . active { display : block ; }
# qz-auth-bar . qz-dropdown-item {
padding : 10 px 12 px ;
border-radius : 8 px ;
color : white ;
text-decoration : none ;
display : flex ;
align-items : center ;
gap : 10 px ;
font-size : 14 px ;
transition : background 0.2 s ;
}
# qz-auth-bar . qz-dropdown-item : hover { background : rgba ( 255 , 255 , 255 , 0.1 ) ; }
# qz-auth-bar . qz-dropdown-divider {
height : 1 px ;
background : rgba ( 255 , 255 , 255 , 0.1 ) ;
margin : 8 px 0 ;
}
# qz-auth-bar . qz-avatar {
width : 32 px ;
height : 32 px ;
border-radius : 50 % ;
background : #007AFF ;
display : flex ;
align-items : center ;
justify-content : center ;
font-weight : 600 ;
font-size : 14 px ;
color : white ;
}
# qz-auth-bar . qz-balance {
background : rgba ( 0 , 122 , 255 , 0.15 ) ;
color : #007AFF ;
padding : 4 px 10 px ;
border-radius : 6 px ;
font-size : 13 px ;
font-weight : 600 ;
}
/* QUIXZOOM STANDARD — Dark Theme */
: root {
--qz-bg : #0a0a0a ;
--qz-surface : #111111 ;
--qz-surface-2 : #1a1a1a ;
--qz-border : rgba ( 255 , 255 , 255 , 0.08 ) ;
--qz-text : #e8e8e8 ;
--qz-text-dim : #a0a0a0 ;
--qz-text-muted : #6b6b6b ;
--qz-blue : #007AFF ;
--qz-blue-dark : #0056CC ;
--qz-radius : 10 px ;
}
* { margin : 0 ; padding : 0 ; box-sizing : border-box ; }
body {
font-family : - apple-system , BlinkMacSystemFont , 'Inter' , sans-serif ;
background : var ( - - qz - bg ) ;
color : var ( - - qz - text ) ;
line-height : 1.6 ;
-webkit- font-smoothing : antialiased ;
}
/* Navigation */
. qz-nav {
position : fixed ; top : 0 ; left : 0 ; right : 0 ; z-index : 100 ;
display : flex ; align-items : center ; justify-content : space-between ;
padding : 0 24 px ; height : 56 px ;
background : rgba ( 255 , 255 , 255 , 0.92 ) ;
backdrop-filter : blur ( 16 px ) ;
border-bottom : 1 px solid var ( - - qz - border ) ;
}
. qz-nav-logo { font-size : 18 px ; font-weight : 700 ; color : #fff ; text-decoration : none ; }
. qz-nav-links { display : flex ; gap : 24 px ; list-style : none ; }
. qz-nav-links a { font-size : 14 px ; color : var ( - - qz - text - dim ) ; text-decoration : none ; transition : color 0.2 s ; }
. qz-nav-links a : hover { color : #fff ; }
/* Buttons */
. qz-btn {
display : inline-flex ; align-items : center ; gap : 6 px ;
padding : 12 px 24 px ; border-radius : var ( - - qz - radius ) ;
font-size : 15 px ; font-weight : 600 ; text-decoration : none ;
transition : all 0.2 s ; cursor : pointer ; border : none ;
}
. qz-btn-primary {
background : var ( - - qz - blue ) ; color : #fff ;
}
. qz-btn-primary : hover {
background : var ( - - qz - blue - dark ) ; transform : translateY ( -1 px ) ;
}
. qz-btn-ghost {
background : transparent ; color : var ( - - qz - text ) ;
border : 1 px solid var ( - - qz - border ) ;
}
. qz-btn-ghost : hover {
border-color : var ( - - qz - blue ) ; color : var ( - - qz - blue ) ;
}
/* Cards */
. qz-card {
background : var ( - - qz - surface ) ;
border : 1 px solid var ( - - qz - border ) ;
border-radius : var ( - - qz - radius ) ;
padding : 24 px ;
transition : transform 0.2 s , border-color 0.2 s ;
}
. qz-card : hover {
transform : translateY ( -2 px ) ;
border-color : rgba ( 0 , 122 , 255 , 0.3 ) ;
}
/* Footer */
. qz-footer {
border-top : 1 px solid var ( - - qz - border ) ;
padding : 40 px 24 px ;
text-align : center ;
color : var ( - - qz - text - dim ) ;
font-size : 14 px ;
}
/* Banner */
. qz-banner {
background : #001E50 ;
color : rgba ( 255 , 255 , 255 , 0.55 ) ;
text-align : center ;
padding : 10 px ;
font-size : 12 px ;
}
. qz-banner a { color : rgba ( 255 , 255 , 255 , 0.8 ) ; text-decoration : none ; }
@ media ( max-width : 768px ) {
. qz-nav-links { display : none ; }
}
< / style >
<!-- Auth bar HTML -->
< div id = "qz-auth-bar" >
2026-07-14 09:58:53 +00:00
< a href = "https://quixzoom.com" class = "qz-logo" > qui< span > X< / span > zoom< / a >
< div class = "qz-nav" >
2026-07-14 15:27:33 +00:00
<!-- Guest view -->
< div id = "qz-guest-view" >
2026-07-14 09:58:53 +00:00
< a href = "https://app.quixzoom.com/login" class = "qz-btn qz-btn-ghost" > Logga in< / a >
< a href = "https://app.quixzoom.com/register" class = "qz-btn qz-btn-primary" > Bli Zoomer< / a >
< / div >
2026-07-14 15:27:33 +00:00
<!-- Authenticated view -->
< div id = "qz-user-view" style = "display:none;" >
2026-07-14 09:58:53 +00:00
< span class = "qz-balance" id = "qz-balance" > $0.00< / span >
2026-07-14 15:27:33 +00:00
< div class = "qz-user-menu" >
< button class = "qz-btn qz-btn-ghost" onclick = "qzToggleMenu()" style = "display:flex;align-items:center;gap:8px;" >
< div class = "qz-avatar" id = "qz-avatar" > ?< / div >
< span id = "qz-user-name" style = "color:white;" > User< / span >
< svg width = "12" height = "12" viewBox = "0 0 12 12" fill = "none" >
< path d = "M2.5 4.5L6 8L9.5 4.5" stroke = "currentColor" stroke-width = "1.5" stroke-linecap = "round" stroke-linejoin = "round" / >
< / svg >
2026-07-14 09:58:53 +00:00
< / button >
2026-07-14 15:27:33 +00:00
< div class = "qz-dropdown" id = "qz-dropdown" >
2026-07-14 09:58:53 +00:00
< a href = "https://app.quixzoom.com/dashboard" class = "qz-dropdown-item" >
2026-07-14 15:27:33 +00:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" >
< rect x = "3" y = "3" width = "7" height = "7" rx = "1" / > < rect x = "14" y = "3" width = "7" height = "7" rx = "1" / >
< rect x = "14" y = "14" width = "7" height = "7" rx = "1" / > < rect x = "3" y = "14" width = "7" height = "7" rx = "1" / >
< / svg >
2026-07-14 09:58:53 +00:00
Dashboard
< / a >
< a href = "https://app.quixzoom.com/wallet" class = "qz-dropdown-item" >
2026-07-14 15:27:33 +00:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" >
< path d = "M21 12V7H5a2 2 0 0 1 0-4h14v4" / > < path d = "M3 5v14a2 2 0 0 0 2 2h16v-5" / >
< path d = "M18 12a2 2 0 0 0 0 4h4v-4h-4z" / >
< / svg >
2026-07-14 09:58:53 +00:00
Plånbok
< / a >
< a href = "https://app.quixzoom.com/missions" class = "qz-dropdown-item" >
2026-07-14 15:27:33 +00:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" >
< path d = "M12 2L2 7l10 5 10-5-10-5z" / > < path d = "M2 17l10 5 10-5" / > < path d = "M2 12l10 5 10-5" / >
< / svg >
2026-07-14 09:58:53 +00:00
Mina uppdrag
< / a >
< div class = "qz-dropdown-divider" > < / div >
< a href = "https://app.quixzoom.com/settings" class = "qz-dropdown-item" >
2026-07-14 15:27:33 +00:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" >
< circle cx = "12" cy = "12" r = "3" / >
< path d = "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.67 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.67 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.67a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" / >
< / svg >
2026-07-14 09:58:53 +00:00
Inställningar
< / a >
< a href = "#" onclick = "qzLogout(); return false;" class = "qz-dropdown-item" >
2026-07-14 15:27:33 +00:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" >
< path d = "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" / > < polyline points = "16 17 21 12 16 7" / >
< line x1 = "21" y1 = "12" x2 = "9" y2 = "12" / >
< / svg >
2026-07-14 09:58:53 +00:00
Logga ut
< / a >
< / div >
< / div >
< / div >
< / div >
< / div >
2026-07-14 15:27:33 +00:00
<!-- SSO Client Script -->
2026-07-14 09:58:53 +00:00
< script >
( function ( ) {
const SSO _BASE = 'https://auth.quixzoom.com' ;
2026-07-14 15:27:33 +00:00
// Check auth status on load
2026-07-14 09:58:53 +00:00
async function qzCheckAuth ( ) {
try {
2026-07-14 15:27:33 +00:00
const res = await fetch ( SSO _BASE + '/auth/silent' , {
method : 'GET' ,
2026-07-14 09:58:53 +00:00
credentials : 'include' ,
} ) ;
2026-07-14 15:27:33 +00:00
2026-07-14 09:58:53 +00:00
if ( res . ok ) {
const data = await res . json ( ) ;
if ( data . authenticated ) {
2026-07-14 15:27:33 +00:00
qzShowUser ( data . user ) ;
return ;
2026-07-14 09:58:53 +00:00
}
}
2026-07-14 15:27:33 +00:00
// Try check endpoint
const checkRes = await fetch ( SSO _BASE + '/auth/check' , {
credentials : 'include' ,
} ) ;
if ( checkRes . ok ) {
const checkData = await checkRes . json ( ) ;
if ( checkData . authenticated && checkData . user ) {
qzShowUser ( checkData . user ) ;
return ;
}
}
qzShowGuest ( ) ;
2026-07-14 09:58:53 +00:00
} catch ( e ) {
2026-07-14 15:27:33 +00:00
console . log ( '[QZAuth] Check failed, showing guest' ) ;
qzShowGuest ( ) ;
2026-07-14 09:58:53 +00:00
}
}
2026-07-14 15:27:33 +00:00
function qzShowUser ( user ) {
document . getElementById ( 'qz-guest-view' ) . style . display = 'none' ;
document . getElementById ( 'qz-user-view' ) . style . display = 'flex' ;
document . getElementById ( 'qz-user-name' ) . textContent = user . name || user . email ;
document . getElementById ( 'qz-avatar' ) . textContent = ( user . name || user . email ) [ 0 ] . toUpperCase ( ) ;
// Dispatch event for other scripts
window . dispatchEvent ( new CustomEvent ( 'qz-auth-change' , {
detail : { authenticated : true , user }
} ) ) ;
}
function qzShowGuest ( ) {
document . getElementById ( 'qz-guest-view' ) . style . display = 'flex' ;
document . getElementById ( 'qz-user-view' ) . style . display = 'none' ;
window . dispatchEvent ( new CustomEvent ( 'qz-auth-change' , {
detail : { authenticated : false }
} ) ) ;
}
window . qzToggleMenu = function ( ) {
document . getElementById ( 'qz-dropdown' ) . classList . toggle ( 'active' ) ;
2026-07-14 09:58:53 +00:00
} ;
2026-07-14 15:27:33 +00:00
2026-07-14 09:58:53 +00:00
window . qzLogout = async function ( ) {
try {
await fetch ( SSO _BASE + '/auth/logout' , {
method : 'POST' ,
credentials : 'include' ,
} ) ;
} catch ( e ) { }
2026-07-14 15:27:33 +00:00
// Clear all cookies
2026-07-14 09:58:53 +00:00
document . cookie = 'qz_access_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;' ;
document . cookie = 'qz_refresh_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;' ;
2026-07-14 15:27:33 +00:00
document . cookie = 'qz_auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;' ;
qzShowGuest ( ) ;
2026-07-14 09:58:53 +00:00
window . location . reload ( ) ;
} ;
2026-07-14 15:27:33 +00:00
// Close dropdown on outside click
document . addEventListener ( 'click' , function ( e ) {
if ( ! e . target . closest ( '.qz-user-menu' ) ) {
document . getElementById ( 'qz-dropdown' ) . classList . remove ( 'active' ) ;
}
} ) ;
// Check auth on page load
2026-07-14 09:58:53 +00:00
qzCheckAuth ( ) ;
2026-07-14 15:27:33 +00:00
// Re-check auth periodically (every 5 minutes)
setInterval ( qzCheckAuth , 5 * 60 * 1000 ) ;
// Listen for storage events (login from other tabs)
window . addEventListener ( 'storage' , function ( e ) {
if ( e . key === 'qz_auth_event' ) {
const event = JSON . parse ( e . newValue || '{}' ) ;
if ( event . type === 'login' ) {
qzCheckAuth ( ) ;
} else if ( event . type === 'logout' ) {
qzShowGuest ( ) ;
}
}
} ) ;
2026-07-14 09:58:53 +00:00
} ) ( ) ;
< / script >
2026-07-05 06:41:32 +00:00
< / body >
< / html >