2026-07-05 06:41:32 +00:00
<!DOCTYPE html>
< html lang = "sv" >
< head >
< meta charset = "UTF-8" >
< link rel = "icon" type = "image/x-icon" href = "/favicon.ico" >
< link rel = "icon" type = "image/svg+xml" href = "/favicon.svg" >
< link rel = "icon" type = "image/png" sizes = "32x32" href = "/favicon-32x32.png" >
< link rel = "apple-touch-icon" sizes = "180x180" href = "/apple-touch-icon.png" >
< meta name = "viewport" content = "width=device-width, initial-scale=1, viewport-fit=cover" >
< meta name = "color-scheme" content = "light dark" >
< title > LandveX — Inspektörsportal< / title >
< link rel = "stylesheet" >
< style >
2026-07-07 07:11:50 +00:00
/*
2026-07-05 06:41:32 +00:00
LANDVEX INSPEKTÖRSPORTAL — iOS Native
2026-07-07 07:11:50 +00:00
*/
2026-07-05 06:41:32 +00:00
* { box-sizing : border-box ; margin : 0 ; padding : 0 ; -webkit- font-smoothing : antialiased ; }
body {
font-family : var ( - - font - text ) ;
background : var ( - - grouped - background - primary ) ;
color : var ( - - label - primary ) ;
min-height : 100 vh ;
padding-bottom : calc ( 60 px + env ( safe - area - inset - bottom ) ) ;
}
2026-07-07 07:11:50 +00:00
/* NAV */
2026-07-05 06:41:32 +00:00
. nav-bar {
position : sticky ;
top : 0 ;
z-index : 100 ;
background : var ( - - glass - bg ) ;
backdrop-filter : var ( - - glass - blur ) ;
-webkit- backdrop-filter : var ( - - glass - blur ) ;
border-bottom : 0.5 px solid var ( - - separator ) ;
padding : 0 16 px ;
}
. nav-top {
height : 44 px ;
display : flex ;
align-items : center ;
justify-content : space-between ;
}
. nav-brand {
display : flex ;
align-items : center ;
gap : 8 px ;
}
. brand-icon {
width : 28 px ;
height : 28 px ;
background : linear-gradient ( 135 deg , #0055CC , #007AFF ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - sm ) ;
2026-07-05 06:41:32 +00:00
display : flex ;
align-items : center ;
justify-content : center ;
color : white ;
font-size : 12 px ;
font-weight : 800 ;
}
. brand-label {
font-size : 17 px ;
font-weight : 600 ;
letter-spacing : -0.4 px ;
}
. badge-inspector {
font-size : 10 px ;
font-weight : 700 ;
padding : 3 px 7 px ;
background : rgba ( 88 , 86 , 214 , 0.15 ) ;
color : var ( - - ios - indigo ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - xl ) ;
2026-07-05 06:41:32 +00:00
letter-spacing : 0.3 px ;
}
2026-07-07 07:11:50 +00:00
/* DATE HEADER */
2026-07-05 06:41:32 +00:00
. date-header {
padding : 16 px 16 px 4 px ;
font-size : 13 px ;
font-weight : 600 ;
color : var ( - - label - secondary ) ;
text-transform : uppercase ;
letter-spacing : 0.5 px ;
}
. day-title {
font-family : var ( - - font - display ) ;
font-size : 28 px ;
font-weight : 700 ;
letter-spacing : -0.5 px ;
padding : 2 px 16 px 16 px ;
}
2026-07-07 07:11:50 +00:00
/* MISSION CARD */
2026-07-05 06:41:32 +00:00
. mission-card {
margin : 0 16 px 12 px ;
background : var ( - - grouped - background - secondary ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
border : 0.5 px solid var ( - - separator ) ;
overflow : hidden ;
}
. mission-header {
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 14 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
cursor : pointer ;
transition : background 0.15 s ;
}
. mission-header : active { background : var ( - - fill - quaternary ) ; }
. mission-title {
font-size : 17 px ;
font-weight : 600 ;
letter-spacing : -0.3 px ;
}
. mission-sub {
font-size : 13 px ;
color : var ( - - label - secondary ) ;
margin-top : 2 px ;
}
. mission-number {
width : 44 px ;
height : 44 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - full ) ;
2026-07-05 06:41:32 +00:00
background : linear-gradient ( 135 deg , #007AFF , #0055CC ) ;
display : flex ;
align-items : center ;
justify-content : center ;
color : white ;
font-size : 20 px ;
font-weight : 700 ;
flex-shrink : 0 ;
}
. mission-body {
padding : 0 16 px ;
}
. mission-row {
display : flex ;
align-items : center ;
gap : 10 px ;
padding : 10 px 0 ;
border-bottom : 0.5 px solid var ( - - separator ) ;
font-size : 15 px ;
}
. mission-row : last-child { border-bottom : none ; }
. mission-row-icon {
font-size : 18 px ;
width : 24 px ;
text-align : center ;
flex-shrink : 0 ;
}
. mission-row-label { flex : 1 ; }
. mission-row-value {
font-size : 15 px ;
color : var ( - - label - secondary ) ;
font-weight : 500 ;
}
. mission-actions {
padding : 14 px 16 px ;
display : flex ;
gap : 10 px ;
border-top : 0.5 px solid var ( - - separator ) ;
}
. btn-start {
flex : 2 ;
height : 44 px ;
background : var ( - - ios - green ) ;
color : white ;
border : none ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
font-size : 15 px ;
font-weight : 600 ;
font-family : var ( - - font - text ) ;
cursor : pointer ;
transition : opacity 0.15 s ;
}
. btn-start : active { opacity : 0.8 ; }
. btn-nav {
flex : 1 ;
height : 44 px ;
background : var ( - - fill - secondary ) ;
color : var ( - - ios - blue ) ;
border : none ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
font-size : 15 px ;
font-weight : 600 ;
font-family : var ( - - font - text ) ;
cursor : pointer ;
}
2026-07-07 07:11:50 +00:00
/* FORM SECTIONS */
2026-07-05 06:41:32 +00:00
. form-section {
margin : 24 px 16 px 0 ;
}
. section-title {
font-size : 20 px ;
font-weight : 700 ;
letter-spacing : -0.4 px ;
margin-bottom : 10 px ;
}
. form-card {
background : var ( - - grouped - background - secondary ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - lg ) ;
2026-07-05 06:41:32 +00:00
border : 0.5 px solid var ( - - separator ) ;
overflow : hidden ;
}
. form-row {
display : flex ;
align-items : center ;
padding : 12 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
gap : 12 px ;
}
. form-row : last-child { border-bottom : none ; }
. form-row-label {
font-size : 15 px ;
font-weight : 500 ;
flex : 1 ;
}
. form-row-input {
text-align : right ;
flex : 1 ;
background : none ;
border : none ;
outline : none ;
font-size : 15 px ;
font-family : var ( - - font - text ) ;
color : var ( - - label - secondary ) ;
min-width : 0 ;
}
. form-row-input :: placeholder { color : var ( - - label - quaternary ) ; }
. form-row-select {
flex : 1 ;
text-align : right ;
background : none ;
border : none ;
outline : none ;
font-size : 15 px ;
font-family : var ( - - font - text ) ;
color : var ( - - label - secondary ) ;
cursor : pointer ;
appearance : none ;
}
. form-textarea-wrap {
padding : 12 px 16 px ;
}
. form-textarea {
width : 100 % ;
min-height : 100 px ;
background : none ;
border : none ;
outline : none ;
font-size : 15 px ;
font-family : var ( - - font - text ) ;
color : var ( - - label - primary ) ;
resize : vertical ;
line-height : 1.5 ;
}
. form-textarea :: placeholder { color : var ( - - label - quaternary ) ; }
2026-07-07 07:11:50 +00:00
/* CHECKLIST */
2026-07-05 06:41:32 +00:00
. checklist-item {
display : flex ;
align-items : center ;
padding : 12 px 16 px ;
border-bottom : 0.5 px solid var ( - - separator ) ;
gap : 12 px ;
cursor : pointer ;
transition : background 0.15 s ;
}
. checklist-item : last-child { border-bottom : none ; }
. checklist-item : active { background : var ( - - fill - quaternary ) ; }
. check-box {
width : 24 px ;
height : 24 px ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - full ) ;
2026-07-05 06:41:32 +00:00
border : 2 px solid var ( - - ios - blue ) ;
flex-shrink : 0 ;
display : flex ;
align-items : center ;
justify-content : center ;
transition : all 0.2 s ;
}
. check-box . checked {
background : var ( - - ios - blue ) ;
border-color : var ( - - ios - blue ) ;
}
. check-mark {
color : white ;
font-size : 12 px ;
font-weight : 700 ;
opacity : 0 ;
transition : opacity 0.2 s ;
}
. check-box . checked . check-mark { opacity : 1 ; }
. checklist-text { flex : 1 ; font-size : 15 px ; }
. checklist-text . checked { color : var ( - - label - secondary ) ; text-decoration : line-through ; }
2026-07-07 07:11:50 +00:00
/* PHOTO UPLOAD */
2026-07-05 06:41:32 +00:00
. photo-grid {
display : grid ;
grid-template-columns : repeat ( 3 , 1 fr ) ;
gap : 3 px ;
padding : 12 px 16 px ;
}
. photo-thumb {
aspect-ratio : 1 ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - md ) ;
2026-07-05 06:41:32 +00:00
overflow : hidden ;
background : var ( - - fill - secondary ) ;
display : flex ;
align-items : center ;
justify-content : center ;
cursor : pointer ;
position : relative ;
transition : opacity 0.15 s ;
}
. photo-thumb : active { opacity : 0.7 ; }
. photo-thumb . add-photo {
border : 2 px dashed var ( - - separator ) ;
background : transparent ;
flex-direction : column ;
gap : 4 px ;
}
. photo-thumb . add-photo . add-icon {
font-size : 28 px ;
color : var ( - - ios - blue ) ;
}
. photo-thumb . add-photo . add-label {
font-size : 11 px ;
color : var ( - - ios - blue ) ;
font-weight : 500 ;
}
. photo-placeholder {
width : 100 % ;
height : 100 % ;
display : flex ;
align-items : center ;
justify-content : center ;
font-size : 32 px ;
background : var ( - - fill - secondary ) ;
}
2026-07-07 07:11:50 +00:00
/* SUBMIT AREA */
2026-07-05 06:41:32 +00:00
. submit-area {
padding : 20 px 16 px 32 px ;
}
. submit-btn {
width : 100 % ;
height : 54 px ;
background : linear-gradient ( 135 deg , #007AFF , #0055CC ) ;
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 : 700 ;
font-family : var ( - - font - display ) ;
cursor : pointer ;
letter-spacing : -0.3 px ;
transition : opacity 0.15 s , transform 0.1 s ;
box-shadow : 0 4 px 20 px rgba ( 0 , 122 , 255 , 0.35 ) ;
}
. submit-btn : active {
opacity : 0.85 ;
transform : scale ( 0.98 ) ;
}
. submit-note {
text-align : center ;
font-size : 12 px ;
color : var ( - - label - tertiary ) ;
margin-top : 10 px ;
}
2026-07-07 07:11:50 +00:00
/* PROGRESS BAR */
2026-07-05 06:41:32 +00:00
. progress-wrap {
padding : 0 16 px 16 px ;
}
. progress-header {
display : flex ;
justify-content : space-between ;
font-size : 13 px ;
color : var ( - - label - secondary ) ;
margin-bottom : 6 px ;
}
. progress-track {
height : 4 px ;
background : var ( - - fill - tertiary ) ;
2026-07-07 07:11:50 +00:00
border-radius : var ( - - radius - sm ) ;
2026-07-05 06:41:32 +00:00
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.4 s ;
}
2026-07-07 07:11:50 +00:00
/* TAB BAR */
2026-07-05 06:41:32 +00:00
. tab-bar {
position : fixed ;
bottom : 0 ;
left : 0 ;
right : 0 ;
height : calc ( 49 px + env ( safe - area - inset - bottom ) ) ;
padding-bottom : env ( safe - area - inset - bottom ) ;
background : var ( - - glass - bg ) ;
backdrop-filter : var ( - - glass - blur ) ;
-webkit- backdrop-filter : var ( - - glass - blur ) ;
border-top : 0.5 px solid var ( - - separator ) ;
display : flex ;
align-items : flex-start ;
justify-content : space-around ;
padding-top : 8 px ;
z-index : 90 ;
}
. tab-item {
display : flex ;
flex-direction : column ;
align-items : center ;
gap : 2 px ;
cursor : pointer ;
flex : 1 ;
opacity : 0.55 ;
transition : opacity 0.15 s ;
}
. tab-item . active { opacity : 1 ; }
. tab-icon { font-size : 22 px ; }
. tab-label { font-size : 10 px ; font-weight : 500 ; color : var ( - - label - secondary ) ; }
. tab-item . active . tab-label { color : var ( - - ios - blue ) ; }
2026-07-07 07:11:50 +00:00
/* NOTIFICATION DOT */
2026-07-05 06:41:32 +00:00
. notif-dot {
position : relative ;
}
. notif-dot :: after {
content : '3' ;
position : absolute ;
top : -4 px ;
right : -8 px ;
background : var ( - - ios - red ) ;
color : white ;
font-size : 9 px ;
font-weight : 700 ;
width : 16 px ;
height : 16 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 ;
border : 2 px solid var ( - - grouped - background - primary ) ;
}
@ 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 ; }
}
< / 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(0,0,0,0.4)" ] { color : rgba ( 0 , 0 , 0 , 0.72 ) !important ; }
[ style * = "rgba(0,0,0,0.3)" ] { color : rgba ( 0 , 0 , 0 , 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 ; }
}
< / style >
< / head >
< body >
<!-- NAV -->
< nav class = "nav-bar" >
< div class = "nav-top" >
< div class = "nav-brand" >
< div class = "brand-icon" > LX< / div >
< span class = "brand-label" > LandveX< / span >
< / div >
< span class = "badge-inspector" > INSPEKTÖR< / span >
2026-07-07 07:11:50 +00:00
< div style = "width:32px;height:32px;border-radius: var(--radius-full);background:linear-gradient(135deg,#5856D6,#AF52DE);display:flex;align-items:center;justify-content:center;color:white;font-size:14px;font-weight:700;" > M< / div >
2026-07-05 06:41:32 +00:00
< / div >
< / nav >
<!-- DAILY MISSIONS -->
< div class = "date-header" > Måndag 18 maj 2026< / div >
< div class = "day-title" > Dagens uppdrag< / div >
<!-- MISSION 1 -->
< div class = "mission-card" >
< div class = "mission-header" >
< div >
< div class = "mission-title" > E4 Norrtull Avsnitt 12< / div >
2026-07-07 07:11:50 +00:00
< div class = "mission-sub" > Ytinspektion · Stockholm< / div >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "mission-number" > 1< / div >
< / div >
< div class = "mission-body" >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Starttid< / div >
< div class = "mission-row-value" > 09:00< / div >
< / div >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > ⏱< / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Beräknad tid< / div >
< div class = "mission-row-value" > 90 min< / div >
< / div >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Plats< / div >
< div class = "mission-row-value" > E4, km 164– 166< / div >
< / div >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > < 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 > < / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Typ< / div >
< div class = "mission-row-value" > Standard ytinspektion< / div >
< / div >
< / div >
< div class = "mission-actions" >
2026-07-07 07:11:50 +00:00
< button class = "btn-start" onclick = "startMission(1)" > Starta uppdrag< / button >
< button class = "btn-nav" onclick = "navigate('E4 Norrtull')" > Navigera< / button >
2026-07-05 06:41:32 +00:00
< / div >
< / div >
<!-- MISSION 2 -->
< div class = "mission-card" >
< div class = "mission-header" >
< div >
< div class = "mission-title" > Kungliga Slottet Tak< / div >
2026-07-07 07:11:50 +00:00
< div class = "mission-sub" > Takinspektion · Kritisk · Stockholm< / div >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "mission-number" style = "background:linear-gradient(135deg,#FF3B30,#CC1100)" > 2< / div >
< / div >
< div class = "mission-body" >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Starttid< / div >
< div class = "mission-row-value" > 13:00< / div >
< / div >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > ⏱< / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Beräknad tid< / div >
< div class = "mission-row-value" > 120 min< / div >
< / div >
< div class = "mission-row" >
2026-07-07 07:11:50 +00:00
< div class = "mission-row-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "mission-row-label" > Plats< / div >
< div class = "mission-row-value" > Kungliga Slottet, Gamla Stan< / div >
< / div >
< div class = "mission-row" >
< div class = "mission-row-icon" > < svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "#f59e0b" stroke-width = "2" > < path d = "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" / > < line x1 = "12" y1 = "9" x2 = "12" y2 = "13" / > < line x1 = "12" y1 = "17" x2 = "12.01" y2 = "17" / > < / svg > < / div >
< div class = "mission-row-label" > Prioritet< / div >
< div class = "mission-row-value" style = "color:var(--ios-red);font-weight:600" > KRITISK< / div >
< / div >
< / div >
< div class = "mission-actions" >
2026-07-07 07:11:50 +00:00
< button class = "btn-start" onclick = "startMission(2)" style = "background:var(--ios-red)" > Starta uppdrag< / button >
< button class = "btn-nav" onclick = "navigate('Kungliga Slottet')" > Navigera< / button >
2026-07-05 06:41:32 +00:00
< / div >
< / div >
<!-- PROGRESS -->
< div style = "padding: 8px 16px 0;" >
< div class = "progress-wrap" style = "padding: 0;" >
< div class = "progress-header" >
< span > Daglig progress< / span >
< span > 0 / 2 uppdrag klara< / span >
< / div >
< div class = "progress-track" >
< div class = "progress-fill" id = "dayProgress" style = "width:0%" > < / div >
< / div >
< / div >
< / div >
<!-- INSPECTION FORM -->
< div class = "form-section" id = "inspectionForm" style = "display:none;" >
2026-07-07 07:11:50 +00:00
< div class = "section-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 > Inspektionsprotokoll< / div >
2026-07-05 06:41:32 +00:00
< div class = "form-card" style = "margin-bottom:12px;" >
< div class = "form-row" >
< div class = "form-row-label" > Objekt< / div >
< input class = "form-row-input" type = "text" id = "objektNamn" placeholder = "Välj objekt..." readonly >
< / div >
< div class = "form-row" >
< div class = "form-row-label" > Inspektionstyp< / div >
< select class = "form-row-select" id = "inspType" >
< option > Ytinspektion< / option >
< option > Strukturkontroll< / option >
< option > Takinspektion< / option >
< option > Fasadinspektion< / option >
< / select >
< / div >
< div class = "form-row" >
< div class = "form-row-label" > Datum< / div >
< input class = "form-row-input" type = "date" id = "inspDate" value = "2026-05-18" >
< / div >
< div class = "form-row" >
< div class = "form-row-label" > Väder< / div >
< select class = "form-row-select" >
2026-07-07 07:11:50 +00:00
< option > Klart< / option >
< option > Molnigt< / option >
< option > Regn< / option >
< option > Snö< / option >
< option > Blåsigt< / option >
2026-07-05 06:41:32 +00:00
< / select >
< / div >
< div class = "form-row" >
< div class = "form-row-label" > Riskbedömning< / div >
< select class = "form-row-select" id = "riskLevel" >
< option value = "low" > < svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "#00C853" stroke-width = "3" > < path d = "M20 6L9 17l-5-5" / > < / svg > Låg (0– 30)< / option >
< option value = "medium" > < svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "#f59e0b" stroke-width = "2" > < path d = "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" / > < line x1 = "12" y1 = "9" x2 = "12" y2 = "13" / > < line x1 = "12" y1 = "17" x2 = "12.01" y2 = "17" / > < / svg > Medium (31– 65)< / option >
2026-07-07 07:11:50 +00:00
< option value = "high" > Hög (66– 100)< / option >
2026-07-05 06:41:32 +00:00
< / select >
< / div >
< / div >
<!-- CHECKLIST -->
< div style = "font-size:13px;font-weight:600;color:var(--label-secondary);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;padding:0 4px;" > Checklista< / div >
< div class = "form-card" style = "margin-bottom:12px;" >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Yttre skador dokumenterade< / div >
< / div >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Strukturell integritet kontrollerad< / div >
< / div >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Dränering och avlopp inspekterade< / div >
< / div >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Korrosion och fuktskador noterade< / div >
< / div >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Säkerhetsrisker bedömda< / div >
< / div >
< div class = "checklist-item" onclick = "toggleCheck(this)" >
2026-07-07 07:11:50 +00:00
< div class = "check-box" > < span class = "check-mark" > < 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 > < / span > < / div >
2026-07-05 06:41:32 +00:00
< div class = "checklist-text" > Jämförelse med föregående inspektion< / div >
< / div >
< / div >
<!-- PHOTOS -->
< div style = "font-size:13px;font-weight:600;color:var(--label-secondary);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;padding:0 4px;" > Foto (min 3 st)< / div >
< div class = "form-card" style = "margin-bottom:12px;" >
< div class = "photo-grid" >
< div class = "photo-thumb" onclick = "addPhoto(this)" >
2026-07-07 07:11:50 +00:00
< div class = "photo-placeholder" > < / div >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "photo-thumb" onclick = "addPhoto(this)" >
2026-07-07 07:11:50 +00:00
< div class = "photo-placeholder" > < / div >
2026-07-05 06:41:32 +00:00
< / div >
< div class = "photo-thumb add-photo" onclick = "takePhoto()" >
< div class = "add-icon" > +< / div >
< div class = "add-label" > Lägg till< / div >
< / div >
< / div >
< div style = "padding:0 16px 12px;font-size:12px;color:var(--label-tertiary);" >
Foton lagras säkert och bifogas rapporten automatiskt.
< / div >
< / div >
<!-- NOTES -->
< div style = "font-size:13px;font-weight:600;color:var(--label-secondary);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;padding:0 4px;" > Observationer & anteckningar< / div >
< div class = "form-card" style = "margin-bottom:12px;" >
< div class = "form-textarea-wrap" >
< textarea class = "form-textarea" placeholder = "Beskriv observationer, avvikelser och rekommenderade åtgärder...
Exempel:
- Sprickor identifierade på nordvästra hörn (20 cm lång, 2– 3 mm bred)
- Fuktinträngning synlig under bro-sektionens ände
- Rekommendation: Täta sprickor inom 14 dagar, följ upp om 30 dagar" > < / textarea >
< / div >
< / div >
<!-- SUBMIT -->
< div class = "submit-area" >
< button class = "submit-btn" onclick = "submitReport()" >
2026-07-07 07:11:50 +00:00
< 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 > Skicka inspektionsrapport
2026-07-05 06:41:32 +00:00
< / button >
< div class = "submit-note" > Rapporten skickas till LandveX och objektägaren. Du kan ej ändra efter inskickning.< / div >
< / div >
< / div >
<!-- PLACEHOLDER WHEN NO FORM -->
< div id = "formPlaceholder" style = "padding: 32px 16px; text-align: center; color: var(--label-tertiary);" >
2026-07-07 07:11:50 +00:00
< div style = "font-size: 48px; margin-bottom: 12px;" > < 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 > < / div >
2026-07-05 06:41:32 +00:00
< div style = "font-size: 17px; font-weight: 600; color: var(--label-secondary);" > Protokollformulär< / div >
< div style = "font-size: 14px; margin-top: 6px;" > Starta ett uppdrag ovan för att öppna inspektionsformuläret.< / div >
< / div >
<!-- TAB BAR -->
< nav class = "tab-bar" >
< div class = "tab-item active" >
2026-07-07 07:11:50 +00:00
< div class = "tab-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "tab-label" > Uppdrag< / div >
< / div >
< div class = "tab-item" onclick = "showForm()" >
2026-07-07 07:11:50 +00:00
< div class = "tab-icon" > < 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 > < / div >
2026-07-05 06:41:32 +00:00
< div class = "tab-label" > Protokoll< / div >
< / div >
< div class = "tab-item" >
2026-07-07 07:11:50 +00:00
< div class = "tab-icon notif-dot" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "tab-label" > Notiser< / div >
< / div >
< div class = "tab-item" >
2026-07-07 07:11:50 +00:00
< div class = "tab-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "tab-label" > Arkiv< / div >
< / div >
< div class = "tab-item" >
2026-07-07 07:11:50 +00:00
< div class = "tab-icon" > < / div >
2026-07-05 06:41:32 +00:00
< div class = "tab-label" > Profil< / div >
< / div >
< / nav >
< script >
let completedMissions = 0 ;
function startMission ( n ) {
const missions = {
1 : 'E4 Norrtull Avsnitt 12' ,
2 : 'Kungliga Slottet Tak'
} ;
const form = document . getElementById ( 'inspectionForm' ) ;
const placeholder = document . getElementById ( 'formPlaceholder' ) ;
document . getElementById ( 'objektNamn' ) . value = missions [ n ] ;
form . style . display = 'block' ;
placeholder . style . display = 'none' ;
// Scroll to form
setTimeout ( ( ) => form . scrollIntoView ( { behavior : 'smooth' } ) , 100 ) ;
// Feedback
const toast = document . createElement ( 'div' ) ;
2026-07-07 07:11:50 +00:00
toast . style . cssText = 'position:fixed;top:60px;left:50%;transform:translateX(-50%);background:#F2F2F7;color:white;padding:10px 18px;border-radius: var(--radius-xl);font-size:14px;font-weight:600;z-index:500;' ;
toast . textContent = ` Uppdrag ${ n } startat ` ;
2026-07-05 06:41:32 +00:00
document . body . appendChild ( toast ) ;
setTimeout ( ( ) => toast . remove ( ) , 2000 ) ;
}
function navigate ( place ) {
alert ( ` Öppnar navigation till: \n ${ place } \n \n (Integreras med Maps/Waze i produktion) ` ) ;
}
function toggleCheck ( item ) {
const box = item . querySelector ( '.check-box' ) ;
const text = item . querySelector ( '.checklist-text' ) ;
box . classList . toggle ( 'checked' ) ;
text . classList . toggle ( 'checked' ) ;
updateProgress ( ) ;
}
function updateProgress ( ) {
const checked = document . querySelectorAll ( '.check-box.checked' ) . length ;
const total = document . querySelectorAll ( '.check-box' ) . length ;
const pct = total > 0 ? Math . round ( ( checked / total ) * 100 ) : 0 ;
document . getElementById ( 'dayProgress' ) . style . width = pct + '%' ;
}
function addPhoto ( thumb ) {
// Simulate photo capture
2026-07-07 07:11:50 +00:00
const emojis = [ '' , '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 14H14M4 14V8L8 4L12 8V14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 14V10H10V14" stroke="#666" stroke-width="1.5"/></svg>' , '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>' , '' , '' , '' ] ;
2026-07-05 06:41:32 +00:00
thumb . innerHTML = ` <div style="font-size:32px"> ${ emojis [ Math . floor ( Math . random ( ) * emojis . length ) ] } </div> ` ;
thumb . style . background = 'var(--fill-tertiary)' ;
}
function takePhoto ( ) {
const grid = document . querySelector ( '.photo-grid' ) ;
const addBtn = grid . querySelector ( '.add-photo' ) ;
const newThumb = document . createElement ( 'div' ) ;
newThumb . className = 'photo-thumb' ;
newThumb . onclick = function ( ) { addPhoto ( this ) ; } ;
2026-07-07 07:11:50 +00:00
const emojis = [ '' , '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 14H14M4 14V8L8 4L12 8V14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 14V10H10V14" stroke="#666" stroke-width="1.5"/></svg>' , '' , '' , '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="5" stroke="#666" stroke-width="2"/><path d="M11 11L14 14" stroke="#666" stroke-width="2" stroke-linecap="round"/></svg>' , '' ] ;
2026-07-05 06:41:32 +00:00
newThumb . innerHTML = ` <div style="font-size:32px"> ${ emojis [ Math . floor ( Math . random ( ) * emojis . length ) ] } </div> ` ;
newThumb . style . background = 'var(--fill-secondary)' ;
grid . insertBefore ( newThumb , addBtn ) ;
}
function showForm ( ) {
document . getElementById ( 'inspectionForm' ) . style . display = 'block' ;
document . getElementById ( 'formPlaceholder' ) . style . display = 'none' ;
document . getElementById ( 'inspectionForm' ) . scrollIntoView ( { behavior : 'smooth' } ) ;
}
function submitReport ( ) {
const objekt = document . getElementById ( 'objektNamn' ) . value ;
if ( ! objekt ) {
alert ( 'Välj ett objekt och starta uppdrag först.' ) ;
return ;
}
const confirmed = confirm ( ` Skicka inspektionsrapport? \n \n Objekt: ${ objekt } \n Datum: ${ document . getElementById ( 'inspDate' ) . value } \n \n Rapporten kan inte ändras efter inskickning. ` ) ;
if ( confirmed ) {
completedMissions ++ ;
// Update progress
const pct = Math . min ( completedMissions / 2 * 100 , 100 ) ;
document . getElementById ( 'dayProgress' ) . style . width = pct + '%' ;
// Hide form
document . getElementById ( 'inspectionForm' ) . style . display = 'none' ;
document . getElementById ( 'formPlaceholder' ) . style . display = 'block' ;
// Feedback
const toast = document . createElement ( 'div' ) ;
2026-07-07 07:11:50 +00:00
toast . style . cssText = 'position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:var(--ios-green);color:white;padding:14px 24px;border-radius: var(--radius-xl);font-size:15px;font-weight:600;z-index:500;box-shadow:0 4px 20px rgba(52,199,89,0.4);text-align:center;' ;
toast . innerHTML = ` <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> Rapport inskickad<br><span style="font-size:12px;opacity:0.85"> ${ objekt } </span> ` ;
2026-07-05 06:41:32 +00:00
document . body . appendChild ( toast ) ;
setTimeout ( ( ) => toast . remove ( ) , 3000 ) ;
// Scroll top
window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
}
}
// Tab switching
document . querySelectorAll ( '.tab-item' ) . forEach ( tab => {
tab . addEventListener ( 'click' , ( ) => {
document . querySelectorAll ( '.tab-item' ) . forEach ( t => t . classList . remove ( 'active' ) ) ;
tab . classList . add ( 'active' ) ;
} ) ;
} ) ;
< / script >
< / body >
< / html >