Cenā iekļauts viss darbs un materiāli par tekošo metru. Precīzu cenu apstiprinām pēc apsekošanas.
Pieprasīt tāmi
Atsūtīsim precizētu tāmi 3 darba dienu laikāE-pastā automātiski ielīmējas pieprasījums un saite uz zīmējumu ar tavām atzīmētajām šuvēm. Zīmējumu ar tāmi vari arī lejupielādēt (PNG vai PDF) un pievienot e-pastam. Tālr. +371 27870013 · info@alpinisti.lv
Nehermetizētas šuves, plaisas un savienojumu vietas fasādē ir viens no biežākajiem iemesliem, kāpēc mitrums iekļūst sienā — apdare zaudē izskatu, veidojas pelējums, ziemā pieaug apkures izmaksas, bet ilgtermiņā tiek bojāta pati nesošā konstrukcija. Fasādes hermetizācija ar kvalitatīviem, elastīgiem hermētiķiem novērš ūdens iekļūšanu un pagarina fasādes kalpošanas laiku par desmitiem gadu — par daļu no vēlāka kapitālā remonta cenas.

Kalkulātors
Izmanto cenu kalkulatoru un veic aptuvenus aprēķinus pats!
<!-- ============================================================================
SIA ALPĪNISTI · STARPPANEĻU ŠUVJU KALKULATORS v8.2 (dizains saskaņots ar Cenu kalkulatoru:
Inter, balts fons, #121417 teksts, dzeltenais akcents #ffb703, kartītes ar 14 px stūriem)
· ielīmē WordPress Be Builder "HTML" elementā (vai Gutenberg "Custom HTML" blokā) — bez <html>/<body>, viss viens fragments
============================================================================ -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
[hidden]{display:none!important}
#suvk{
background:#FFFFFF;font-family:'Inter','IBM Plex Sans',system-ui,sans-serif;color:#121417;
font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased;
--betons:#F3F5F7;--terauds:#121417;--terauds2:#20242B;--virve:#ffb703;--virve2:#E8A400;
--virve-g:#FFF6DE;--virve-t:#8A6410;--cinks:#5C6470;--cinks2:#8A93A0;--linija:#CDD2D9;--linija2:#E9ECF0;
--ok:#2F8F5B;--ok-g:#E7F5EC;--brid:#C79A1E;--kluda:#C0392B;--lodz:#2563C9;
--ena:0 1px 2px rgba(18,20,23,.04),0 10px 28px rgba(18,20,23,.06);
--ena2:0 6px 16px rgba(18,20,23,.10),0 18px 44px rgba(18,20,23,.14);
--fokuss:0 0 0 3px rgba(255,183,3,.30);
/* aizmugursaderība ar JS inline stiliem */
--muted:#5C6470;--fg:#121417;--accent:#E8A400;
}
#suvk *,#suvk *::before,#suvk *::after{box-sizing:border-box;margin:0;padding:0}
#suvk .wrap{max-width:1180px;margin:0 auto;padding:18px 16px 48px}
@media(max-width:560px){#suvk .wrap{padding-left:10px;padding-right:10px}}
#suvk h1,#suvk h2,#suvk h3{font-family:'Inter',sans-serif;letter-spacing:-0.01em;font-weight:600;color:var(--terauds)}
#suvk h2{font-size:16px}
#suvk h3{font-size:14px}
#suvk p{margin:0}
/* --- SOĻU JOSLA (segmentēta kā Cenu analītikas cilnes) --- */
#suvk .stepper{display:flex;gap:2px;background:var(--betons);border:1px solid var(--linija2);border-radius:12px;padding:4px;margin:0;flex-wrap:wrap;flex:1;min-width:0}
#suvk .card-head.steps{padding:12px 14px}
#suvk .stepper button{flex:1 1 auto;font:inherit;font-size:13px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;gap:8px;
padding:8px 12px;border-radius:9px;border:0;background:transparent;color:var(--cinks);cursor:pointer;white-space:nowrap;
transition:background .15s ease,color .15s ease,box-shadow .15s ease}
#suvk .stepper button .n{font-size:12px;font-weight:700;width:22px;height:22px;border-radius:50%;display:inline-grid;place-items:center;background:#E3E7EC;color:var(--cinks);flex:none}
#suvk .stepper button:hover:not(:disabled){color:var(--terauds)}
#suvk .stepper button[aria-current="step"]{background:#fff;color:var(--terauds);box-shadow:0 1px 3px rgba(18,20,23,.12)}
#suvk .stepper button[aria-current="step"] .n{background:var(--virve);color:#121417}
#suvk .stepper button.done{color:var(--terauds)}
#suvk .stepper button.done .n{background:var(--ok);color:#fff}
#suvk .stepper button:disabled{opacity:.5;cursor:default}
#suvk .stepper button:focus-visible{outline:none;box-shadow:var(--fokuss)}
@media(max-width:700px){#suvk .stepper button span:not(.n){display:none}#suvk .stepper button{flex:1 1 0;padding:8px 6px}}
/* --- KARTĪTES --- */
#suvk section.card{background:#fff;border:1px solid var(--linija2);border-radius:14px;box-shadow:var(--ena);overflow:hidden;margin-bottom:16px}
#suvk .card-head{padding:13px 18px;border-bottom:1px solid #EFF1F4;display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:#fff}
#suvk .card-head h2{font-size:16px;font-weight:600;margin-right:auto}
#suvk .card-head .stepn{width:26px;height:26px;border-radius:8px;background:var(--virve);color:#121417;font-weight:800;font-size:13px;display:inline-grid;place-items:center;flex:none}
#suvk .card-body{padding:18px}
@media(max-width:640px){#suvk .card-head{padding:11px 12px}#suvk .card-body{padding:12px}}
/* --- IZVĒLĒTAIS (pills) --- */
#suvk .chosen{display:flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:13px;color:var(--cinks);margin:0 0 12px}
#suvk .chosen b{display:inline-block;background:var(--virve-g);color:var(--virve-t);border-radius:999px;padding:3px 10px;font-weight:600;font-size:12.5px}
/* --- SĒRIJU KARTĪTES --- */
#suvk .series{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
#suvk .card{background:#fff;border:1px solid var(--linija);border-radius:12px;padding:10px;cursor:pointer;text-align:left;font:inherit;color:inherit;
display:flex;flex-direction:column;gap:7px;transition:border-color .15s ease,box-shadow .15s ease,transform .15s ease;position:relative}
#suvk .card:hover{border-color:#AEB5BF;box-shadow:var(--ena);transform:translateY(-1px)}
#suvk .card[aria-pressed="true"]{border-color:var(--virve);box-shadow:var(--fokuss);background:#FFFDF4}
#suvk .card:focus-visible{outline:none;box-shadow:var(--fokuss)}
#suvk .card svg{width:100%;height:96px;display:block;background:#fff;border-radius:8px;border:1px solid var(--linija2)}
#suvk .card b{font-size:14.5px;font-weight:600;line-height:1.25}
#suvk .card small{color:var(--cinks);font-size:12px;line-height:1.4}
#suvk .flag{position:absolute;top:8px;right:8px;font-size:10.5px;font-weight:600;padding:2px 8px;border-radius:999px;background:var(--virve-g);color:var(--virve-t);border:1px solid #EEDDA0}
#suvk .flag.ok{background:var(--ok-g);color:#1E7A46;border-color:#BFE3CC}
/* --- IEKŠĒJAIS BLOKS (kā .poz) --- */
#suvk .stage{background:var(--betons);border:1px solid var(--linija2);border-radius:12px;padding:14px;min-width:0}
#suvk .stage+.stage{margin-top:12px}
#suvk .layout2>.stage+.stage{margin-top:0}
#suvk .controls{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:end;margin:0 0 12px}
/* 2. solis: forma kreisajā kolonnā (rindas kā "Sarežģītības faktori"), zīmējums labajā */
#suvk .layout2{display:grid;grid-template-columns:minmax(230px,270px) minmax(0,1fr);gap:14px;align-items:start}
#suvk .layout2>.stage.form{position:sticky;top:12px}
@media(max-width:860px){#suvk .layout2{grid-template-columns:1fr}#suvk .layout2>.stage.form{position:static}}
#suvk .stage.form{padding:4px 14px}
#suvk .fx{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 0;border-bottom:1px dashed var(--linija)}
#suvk .fx:last-of-type{border-bottom:none}
#suvk .fx.col{flex-direction:column;align-items:stretch;gap:8px}
#suvk .fx .n{font-weight:600;font-size:14px;color:var(--terauds);flex:1;min-width:0}
#suvk .fx .d{font-size:12px;color:var(--cinks);display:block;font-weight:400;margin-top:1px}
#suvk .fx select{width:auto;flex:none;min-width:110px;max-width:58%;font-size:14px;padding:8px 32px 8px 11px;cursor:pointer;appearance:none;-webkit-appearance:none;
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1.5l5 5 5-5' fill='none' stroke='%23121417' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
background-repeat:no-repeat;background-position:right 11px center}
#suvk .choice.mode{display:grid;gap:6px;background:none;border:0;padding:0}
#suvk .choice.mode button{display:flex;align-items:center;gap:10px;text-align:left;font-size:13.5px;font-weight:500;color:var(--terauds);background:#fff;border:1px solid var(--linija);border-radius:9px;padding:9px 12px;transition:border-color .15s ease,background .15s ease,box-shadow .15s ease}
#suvk .choice.mode button::before{content:"";width:16px;height:16px;border-radius:50%;border:2px solid #B9C1CA;background:#fff;flex:none;transition:border-color .15s ease,box-shadow .15s ease}
#suvk .choice.mode button:hover{border-color:#AEB5BF;color:var(--terauds)}
#suvk .choice.mode button[aria-pressed="true"]{background:#FFFDF4;border-color:var(--virve);box-shadow:none;font-weight:600}
#suvk .choice.mode button[aria-pressed="true"]::before{border-color:var(--virve2);box-shadow:inset 0 0 0 3.5px #fff;background:var(--virve2)}
#suvk .choice.mode button:focus-visible{box-shadow:var(--fokuss)}
#suvk .controls.grid4 .field select{width:100%;min-width:0}
#suvk .mode.full{display:flex;width:100%}
#suvk .mode.full button{flex:1 1 0;text-align:center}
@media(max-width:560px){#suvk .controls.grid4{grid-template-columns:1fr 1fr}}
#suvk .field{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:500;color:var(--cinks)}
#suvk .field select,#suvk .field input,#suvk .settings input,#suvk .request input,#suvk .request textarea{
font-family:inherit;font-size:15px;font-weight:400;padding:9px 12px;border:1px solid var(--linija);border-radius:9px;background:#fff;color:var(--terauds);
line-height:1.3;min-width:0;transition:border-color .15s ease,box-shadow .15s ease}
#suvk .field select{min-width:110px;cursor:pointer;appearance:none;-webkit-appearance:none;padding-right:34px;
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1.5l5 5 5-5' fill='none' stroke='%23121417' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
background-repeat:no-repeat;background-position:right 11px center}
#suvk select:hover,#suvk input:hover,#suvk textarea:hover{border-color:#AEB5BF}
#suvk select:focus,#suvk input:focus,#suvk textarea:focus{outline:none;border-color:var(--virve);box-shadow:var(--fokuss)}
#suvk input[type=number]{-moz-appearance:textfield;appearance:textfield}
#suvk input[type=number]::-webkit-outer-spin-button,#suvk input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
/* --- SEGMENTĒTIE PĀRSLĒGI (kā Rēķins | FP) --- */
#suvk .mode{display:inline-flex;background:#E6E9ED;border:1px solid var(--linija2);border-radius:11px;padding:3px;gap:2px;flex-wrap:wrap}
#suvk .mode button{font:inherit;font-size:13px;font-weight:600;padding:7px 13px;border:0;border-radius:8px;background:transparent;color:var(--cinks);cursor:pointer;transition:background .15s ease,color .15s ease}
#suvk .mode button:hover:not([aria-pressed="true"]){color:var(--terauds)}
#suvk .mode button[aria-pressed="true"]{background:#fff;color:var(--terauds);box-shadow:0 1px 3px rgba(18,20,23,.12)}
#suvk .mode button:focus-visible{outline:none;box-shadow:var(--fokuss)}
/* --- FASĀŽU CILNES --- */
#suvk .tabs{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 10px}
#suvk .tab{font:inherit;font-weight:600;font-size:12.5px;padding:6px 12px;border-radius:999px;border:1px solid var(--linija);background:#fff;color:var(--cinks);cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
#suvk .tab:hover{border-color:#AEB5BF;color:var(--terauds)}
#suvk .tab[aria-selected="true"]{background:var(--terauds);color:#fff;border-color:var(--terauds)}
#suvk .tab:focus-visible{outline:none;box-shadow:var(--fokuss)}
/* --- POGAS --- */
#suvk .btn{font-family:'Inter',sans-serif;font-size:13.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;gap:7px;
padding:8px 13px;border-radius:8px;border:1px solid var(--linija);background:#fff;color:var(--terauds);cursor:pointer;text-decoration:none;line-height:1.2;
transition:background .15s ease,border-color .15s ease,color .15s ease,transform .06s ease,box-shadow .15s ease}
#suvk .btn:hover{border-color:var(--virve);color:var(--virve-t);background:var(--virve-g)}
#suvk .btn:active{transform:translateY(1px)}
#suvk .btn.primary{background:var(--virve);border-color:var(--virve);color:#121417;font-size:14.5px;padding:10px 18px}
#suvk .btn.primary:hover{background:var(--virve2);border-color:var(--virve2);color:#121417}
#suvk .btn.dark{background:var(--terauds);border-color:var(--terauds);color:#fff}
#suvk .btn.dark:hover{background:#000;color:#fff}
#suvk .btn:focus-visible{outline:none;box-shadow:var(--fokuss)}
#suvk .btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
#suvk .tools{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 10px}
#suvk .tools .tl{font-size:12px;font-weight:500;color:var(--cinks);margin-right:2px}
#suvk .tools .sp{flex:1}
#suvk .btn.danger{color:var(--kluda);border-color:#F0C7C3;background:#fff}
#suvk .btn.danger:hover{background:#FDECEA;border-color:#E9B4AE;color:var(--kluda)}
#suvk .btn.sm{font-size:12.5px;padding:6px 10px}
/* 3. soļa rīkjosla: 1. rinda — navigācija + skaitītājs; 2. rinda — fasādes cilnes + režīms */
#suvk .bar{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;margin:0 0 10px}
#suvk .bar2{padding-top:10px;border-top:1px dashed var(--linija)}
#suvk .bar2 .mode{margin-left:auto}
#suvk .crumb{margin:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
#suvk .crumb .sub{color:var(--cinks);font-size:12.5px}
#suvk .strip{display:inline-flex;align-items:center;gap:2px;background:#E6E9ED;border:1px solid var(--linija2);border-radius:11px;padding:3px;flex-wrap:wrap}
#suvk .strip .sl{font-size:11.5px;font-weight:500;color:var(--cinks);padding:0 6px 0 10px;white-space:nowrap}
#suvk .strip .seg{font:inherit;font-size:13px;font-weight:600;min-width:34px;padding:7px 11px;border:0;border-radius:8px;background:transparent;color:var(--cinks);cursor:pointer;position:relative;transition:background .15s ease,color .15s ease}
#suvk .strip .seg:hover{color:var(--terauds)}
#suvk .strip .seg.akt{background:#fff;color:var(--terauds);box-shadow:0 1px 3px rgba(18,20,23,.12)}
#suvk .strip .seg.has::after{content:"";position:absolute;top:5px;right:5px;width:6px;height:6px;border-radius:50%;background:var(--virve2)}
#suvk .pager{display:inline-flex;align-items:center;gap:2px;background:#fff;border:1px solid var(--linija);border-radius:10px;padding:3px}
#suvk .pager b{font-size:14px;font-weight:600;padding:0 10px;white-space:nowrap}
#suvk .pager b small{font-weight:400;color:var(--cinks);font-size:12px;margin-left:4px}
#suvk .strip .pg{width:30px;height:32px;border:0;border-radius:8px;background:transparent;color:var(--terauds);cursor:pointer;font-size:17px;line-height:1;display:grid;place-items:center;transition:background .15s ease}
#suvk .strip .pg:hover:not(:disabled){background:#fff;color:var(--virve-t)}
#suvk .strip .pg:disabled{opacity:.3;cursor:default}
#suvk .pager .pg{width:30px;height:30px;border:0;border-radius:7px;background:transparent;color:var(--terauds);cursor:pointer;font-size:16px;line-height:1;display:grid;place-items:center;transition:background .15s ease}
#suvk .pager .pg:hover:not(:disabled){background:var(--virve-g);color:var(--virve-t)}
#suvk .pager .pg:disabled{opacity:.3;cursor:default}
#suvk .tabs{margin:0;display:inline-flex;background:#E6E9ED;border:1px solid var(--linija2);border-radius:11px;padding:3px;gap:2px}
#suvk .tab{border:0;background:transparent;border-radius:8px;color:var(--cinks);padding:7px 13px}
#suvk .tab:hover{border-color:transparent;color:var(--terauds)}
#suvk .tab[aria-selected="true"]{background:#fff;color:var(--terauds);border-color:transparent;box-shadow:0 1px 3px rgba(18,20,23,.12)}
#suvk .tab .m{font-weight:500;color:var(--cinks);margin-left:4px}
#suvk .tab[aria-selected="true"] .m{color:var(--virve-t)}
#suvk .legend{margin:0 0 8px}
@media(max-width:560px){#suvk .strip{width:100%;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}#suvk .strip .sl{display:none}#suvk .bar2 .mode{width:100%;display:flex}#suvk .bar2 .mode button{flex:1}#suvk .tabs{width:100%;display:flex}#suvk .tab{flex:1;text-align:center;padding:7px 6px}}
#suvk .nav{display:flex;justify-content:space-between;align-items:center;gap:10px;margin:16px 0 0}
/* --- TEKSTI --- */
#suvk .hint{font-size:12.5px;color:var(--cinks);margin:0 0 8px;line-height:1.5}
#suvk .note{font-size:12.5px;color:var(--cinks);margin-top:10px;line-height:1.5}
#suvk .warn{background:var(--virve-g);border-left:3px solid var(--virve);color:var(--virve-t);padding:10px 13px;font-size:13px;border-radius:0 10px 10px 0;margin:0 0 12px;line-height:1.5}
#suvk .warn.ok{background:var(--ok-g);border-left-color:var(--ok);color:#1E7A46}
#suvk .crumb{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 10px;font-size:13.5px}
#suvk .crumb b{font-size:15px;font-weight:600}
#suvk .counter{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 9px;margin:12px 0 10px;background:var(--virve-g);border:1px solid #EEDDA0;border-radius:12px;padding:8px 14px;font-variant-numeric:tabular-nums}
#suvk .counter .cl{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--virve-t);font-weight:600}
#suvk .counter b{font-size:21px;font-weight:700;color:var(--terauds);line-height:1}
#suvk .counter b i{font-style:normal;font-size:13px;font-weight:600;color:var(--virve-t);margin-left:3px}
#suvk .counter .ce{font-size:13px;font-weight:600;color:var(--virve-t);border-left:1px solid #EEDDA0;padding-left:9px}
/* --- ZĪMĒJUMS --- */
#suvk .svgbox{background:#fff;border:1px solid var(--linija2);border-radius:10px;overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none;padding:6px}
#suvk .svgbox svg{display:block;width:100%;height:auto}
#suvk .joint{stroke:var(--terauds);stroke-width:1.3;vector-effect:non-scaling-stroke;pointer-events:none}
#suvk .joint.l{stroke:var(--lodz);stroke-dasharray:4 2;stroke-width:1.6}
#suvk .joint.on{stroke:var(--virve2);stroke-width:4.5;stroke-dasharray:none}
#suvk .hit{stroke:transparent;stroke-width:14;vector-effect:non-scaling-stroke;cursor:pointer;fill:none}
#suvk .hit:hover + .joint{stroke:var(--virve);stroke-width:3;stroke-dasharray:none}
#suvk .cell{fill:transparent;cursor:pointer}
#suvk .cell:hover{fill:rgba(255,183,3,.22)}
#suvk .sector{fill:transparent;stroke:transparent;cursor:pointer}
#suvk .sector:hover{fill:rgba(255,183,3,.16);stroke:var(--virve2);stroke-width:2;vector-effect:non-scaling-stroke}
#suvk .sector.done{fill:rgba(255,183,3,.08)}
#suvk .legend{display:flex;flex-wrap:wrap;gap:14px;font-size:12.5px;color:var(--cinks)}
#suvk .legend span{display:inline-flex;align-items:center;gap:6px}
#suvk .legend i{display:inline-block;width:22px;height:0;border-top:3px solid var(--terauds)}
#suvk .legend i.on{border-color:var(--virve2);border-top-width:4px}
#suvk .legend i.l{border-color:var(--lodz);border-top-style:dashed}
#suvk .svgbox .ov{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"front front" "back ends";gap:12px 14px;align-items:end}
#suvk .svgbox .prow{display:grid;gap:2px;min-width:0}
#suvk .svgbox .ov > .prow:nth-child(1){grid-area:front}
#suvk .svgbox .ov > .prow:nth-child(2){grid-area:back}
#suvk .svgbox .ov .ends{grid-area:ends;display:grid;grid-template-columns:1fr 1fr;gap:10px;align-items:end;max-width:220px;justify-self:start}
@media(max-width:560px){#suvk .svgbox .ov{grid-template-columns:1fr;grid-template-areas:"front" "back" "ends"}#suvk .svgbox .ov .ends{max-width:60%}}
/* torņi (šauras, augstas ēkas): fasādes blakus, augstums ierobežots */
#suvk .svgbox.tall .ov{display:flex;flex-wrap:wrap;gap:12px 22px;align-items:end;justify-content:center}
#suvk .svgbox.tall .ov .ends{display:contents}
#suvk .svgbox.tall .ov .prow{display:flex;flex-direction:column;align-items:center;gap:4px}
#suvk .svgbox.tall .ov svg{height:min(500px,56vh);width:auto;max-width:100%}
#suvk .svgbox.tall .ov .ends .prow svg{height:min(360px,40vh)}
#suvk .svgbox.tall > svg{height:min(760px,78vh);width:auto;max-width:100%;margin:0 auto;display:block}
@media(max-width:560px){#suvk .svgbox.tall .ov svg,#suvk .svgbox.tall > svg{height:min(420px,60vh)}#suvk .svgbox.tall .ov .ends .prow svg{height:300px}}
#suvk .plab{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--cinks)}
@media(max-width:560px){#suvk .preview{grid-template-columns:1fr;grid-template-areas:"front" "back" "ends"}#suvk .preview .ends{max-width:60%}}
/* --- IZMAKSAS (kā Kopsavilkums) --- */
#suvk .layout{display:grid;gap:16px;align-items:start;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
@media(max-width:860px){#suvk .layout{grid-template-columns:1fr}}
#suvk .total{background:#fff;border:1px solid var(--linija2);border-radius:12px;padding:16px}
#suvk .total .big{background:var(--virve-g);border:1px solid #EEDDA0;border-radius:12px;padding:16px 18px 14px;text-align:center;
font-weight:700;font-size:44px;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-0.02em;color:var(--terauds)}
#suvk .total .big .u{font-size:20px;font-weight:600;color:var(--virve-t);margin-left:4px}
#suvk .total .big small{font-size:13px;color:var(--virve-t);font-weight:500;display:block;margin-top:8px;letter-spacing:0}
#suvk .total .big small.lb{margin:0 0 8px;text-transform:uppercase;letter-spacing:.07em;font-size:11px;font-weight:600}
#suvk .total .big small.eur{color:var(--terauds);font-size:15px;font-weight:600;border-top:1px solid #EEDDA0;padding-top:10px;margin-top:10px}
#suvk .rows{display:grid;grid-template-columns:1fr auto;gap:0;font-size:13.5px;margin-top:10px;font-variant-numeric:tabular-nums}
#suvk .rows .k,#suvk .rows .v{padding:8px 0;border-bottom:1px dashed var(--linija)}
#suvk .rows .k{color:var(--cinks);padding-right:12px}
#suvk .rows .v{text-align:right;font-weight:600;font-size:15px;white-space:nowrap}
#suvk .rows .sum{border-bottom:none;border-top:2px solid var(--terauds);padding-top:10px;margin-top:2px}
#suvk .rows .k.sum{color:var(--terauds);font-weight:600;text-transform:uppercase;font-size:12.5px;letter-spacing:.04em;display:flex;align-items:center}
#suvk .rows .v.sum{font-size:26px;font-weight:700;color:var(--terauds)}
#suvk .settings{background:#fff;border:1px solid var(--linija2);border-radius:12px;padding:12px 16px;margin-top:12px}
#suvk .settings summary{cursor:pointer;font-weight:600;font-size:13.5px;color:var(--virve-t);list-style:none;display:flex;align-items:center;gap:7px}
#suvk .settings summary::-webkit-details-marker{display:none}
#suvk .settings summary::before{content:"▸";font-size:12px;transition:transform .18s ease}
#suvk .settings[open] summary::before{transform:rotate(90deg)}
#suvk .settings .grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px;margin-top:12px}
#suvk .settings label{font-size:12px;font-weight:500;color:var(--cinks);display:flex;flex-direction:column;gap:6px}
#suvk .settings input{width:100%;font-size:14px;padding:8px 10px}
/* --- PIEPRASĪJUMS --- */
#suvk .request{background:#fff;border:1px solid var(--linija2);border-radius:12px;padding:16px}
#suvk .request h2{font-size:16px;margin-bottom:2px}
#suvk .request .lbl{display:block;font-size:12px;font-weight:500;color:var(--cinks);margin:0 0 10px}
#suvk .request .grid{display:grid;gap:10px}
#suvk .request input,#suvk .request textarea{width:100%;font-size:14px}
#suvk .request textarea{min-height:70px;resize:vertical}
#suvk .summary{font-size:12px;white-space:pre-wrap;background:var(--betons);border:1px solid var(--linija2);border-radius:8px;padding:10px 12px;max-height:180px;overflow:auto;margin-top:10px;font-family:ui-monospace,Menlo,monospace;color:var(--terauds2)}
#suvk .toast{font-size:13px;color:var(--ok);font-weight:600;min-height:18px;margin-top:6px}
@media(hover:none) and (pointer:coarse){#suvk input,#suvk select,#suvk textarea{font-size:16px}}
@media(prefers-reduced-motion:reduce){#suvk *,#suvk *::before,#suvk *::after{transition:none!important;animation:none!important}}
</style>
<div id="suvk"><div class="wrap">
<section class="card main">
<div class="card-head steps">
<nav class="stepper" id="stepper" aria-label="Soļi">
<button type="button" data-go="1"><span class="n">1</span><span>Māja</span></button>
<button type="button" data-go="2"><span class="n">2</span><span>Ēka un šuves</span></button>
<button type="button" data-go="3"><span class="n">3</span><span>Izmaksas un tāme</span></button>
</nav>
</div>
<div class="panel" data-step="1">
<div class="card-body">
<div class="series" id="series"></div>
<div class="nav"><span></span><button type="button" class="btn primary" data-go="2">Tālāk →</button></div>
</div>
</div>
<div class="panel" data-step="2" hidden>
<div class="card-body">
<div class="layout2">
<div class="stage form">
<label class="fx"><span class="n">Kāpņu telpas<span class="d">ieejas ēkā</span></span><select id="sections"></select></label>
<label class="fx"><span class="n">Stāvi</span><select id="floors"></select></label>
<label class="fx" id="variantField"><span class="n">Variants<span class="d">fasādes izpildījums</span></span><select id="variant"></select></label>
<div class="fx col"><span class="n">Ko hermetizēt</span>
<div class="choice mode scope" role="group" aria-label="Apjoms">
<button type="button" data-scope="custom" aria-pressed="true">Atzīmēšu pats uz zīmējuma</button>
<button type="button" data-scope="apt" aria-pressed="false">Tikai manu dzīvokli</button>
<button type="button" data-scope="sec" aria-pressed="false">Vienu kāpņu telpu</button>
<button type="button" data-scope="all" aria-pressed="false">Visu ēku</button>
</div>
</div>
<label class="fx" id="scopeRow" hidden><span class="n">Kura kāpņu telpa?</span><select id="whichSec"></select></label>
<p class="hint" id="scopeHint" style="margin:10px 0 0"></p>
<div class="counter" id="counter"><span class="cl">Atzīmēts</span><b>0<i>m</i></b></div>
</div>
<div class="stage">
<div class="bar">
<div class="crumb" id="crumb"></div>
</div>
<div class="bar bar2">
<div class="tabs" id="tabs" role="tablist"></div>
<div class="mode" role="group" aria-label="Atzīmēšanas režīms" title="Kā atzīmēt: pa dzīvokļiem vai pa atsevišķiem šuvju posmiem">
<button type="button" data-mode="seg" aria-pressed="true">Posmi</button>
<button type="button" data-mode="apt" aria-pressed="false">Dzīvoklis</button>
</div>
</div>
<div class="tools" id="tools"></div>
<p class="hint" id="hint"></p>
<div class="legend">
<span><i></i> starppaneļu šuve</span>
<span><i class="l"></i> lodžijas sānu šuve</span>
<span><i class="on"></i> atzīmēta</span>
</div>
<div class="svgbox" id="svgbox"></div>
</div>
</div>
<div class="nav"><button type="button" class="btn" data-go="1">← Atpakaļ</button><button type="button" class="btn primary" data-go="3">Tālāk →</button></div>
</div>
</div>
<div class="panel" data-step="3" hidden>
<div class="card-body">
<div class="warn" id="emptyWarn" hidden>Nekas vēl nav atzīmēts. Atgriezies pie zīmējuma un atzīmē šuves vai izvēlies apjomu "Visu ēku" / "Vienu kāpņu telpu".</div>
<div class="layout">
<div>
<div class="total">
<div class="big" id="bigMeters">0 <small>m</small></div>
<div class="rows" id="rows"></div>
<p class="note">Cenā iekļauts viss darbs un materiāli par tekošo metru. Precīzu cenu apstiprinām pēc apsekošanas.</p>
</div>
<!-- CENA: šeit maini cenu par tekošo metru (darbs + materiāli) un PVN % — klientam šie lauki nav redzami -->
<div hidden><input id="pWarm" type="number" value="34"><input id="pVat" type="number" value="21"></div>
</div>
<div class="request">
<h2>Pieprasīt tāmi</h2>
<span class="lbl">Atsūtīsim precizētu tāmi 3 darba dienu laikā</span>
<div class="grid">
<input id="fName" placeholder="Vārds" autocomplete="name">
<input id="fPhone" placeholder="Tālrunis" autocomplete="tel">
<input id="fAddr" placeholder="Mājas adrese">
<textarea id="fNote" placeholder="Stāvs, dzīvoklis, piezīmes"></textarea>
</div>
<div class="tools" style="margin-top:12px">
<a class="btn primary" id="mailto" href="#">Sūtīt e-pastu</a>
<button type="button" class="btn" id="png">Lejupielādēt (PNG)</button>
<button type="button" class="btn" id="pdf">Lejupielādēt (PDF)</button>
</div>
<div class="toast" id="toast"></div>
<div class="summary" id="summaryText" hidden></div>
<p class="note">E-pastā automātiski ielīmējas pieprasījums un saite uz zīmējumu ar tavām atzīmētajām šuvēm. Zīmējumu ar tāmi vari arī lejupielādēt (PNG vai PDF) un pievienot e-pastam. Tālr. +371 27870013 · info@alpinisti.lv</p>
</div>
</div>
<div class="nav"><button type="button" class="btn" data-go="2">← Atpakaļ</button><span></span></div>
</div>
</div>
</section>
</div></div>
<script>
(function(){
// ---------------------------------------------------------------------------
// SĒRIJU DATI. Katra sekcija = ailes (bays) ar platumu metros un saturu:
// w2 = istabas logs 1,46×1,51 · w3 = 1,76×1,51 · wk = virtuve 1,16×1,51 · w22 = divi logi 1,46 (6,4 m panelī)
// st = kāpņu telpa (logi starpstāvos, ieeja 1. st.) · st64 = 6,4 m kāpņu/lifta bloks · lz = lodžija (durvis+logs, 2 sānu šuves)
// bc = izvirzīts balkons (durvis+logs, bez papildu šuvēm) · bl = panelis bez loga
// rows: 1 = viens panelis uz stāvu (visām sērijām — 467A/467A-4L lentveida dalījuma vidusšuve noņemta pēc pasūtītāja norādes); 2 = lentveida dalījums ar 2 horizontālām šuvēm stāvā
// verified: 'augsta' | 'vidēja' | 'zema' → kalkulatorā rāda "jāprecizē" brīdinājumu, ja nav 'augsta'
// ---------------------------------------------------------------------------
const B = (w,k)=>({w,k});
const SERIES = {
'464': {name:'Lietuviešu projekts (464)', sub:'5 stāvi · 1964–1978 · ar balkoniem', floors:[5], h:2.7, tech:0, lift:false, plinth:0.6, rows:1, W:11.52,
endBays:[2.9,2.9,2.9,2.9], endWins:[1], sec:{min:2,max:8,def:4}, apts:3,
front:[B(3.2,'w2'),B(2.6,'wk'),B(3.2,'st'),B(2.6,'wk'),B(3.2,'w2')],
back:[B(3.2,'bc'),B(2.6,'w2'),B(3.2,'w2'),B(2.6,'w2'),B(3.2,'bc')],
verified:'vidēja', note:'Sekcija 14,8 m un paneļu solis 3,2/2,6/3,2/2,6/3,2 nolasīts no BIS 464. sērijas rasējumiem. Kāpņu telpas aile un balkonu vietas — pieņēmums.'},
'464A': {name:'Lietuviešu projekts (464A)', sub:'5 stāvi · no 1966 · ar lodžijām', floors:[5], h:2.7, tech:0.6, lift:false, plinth:0.6, rows:1, W:11.52,
endBays:[2.9,2.9,2.9,2.9], endWins:[1], sec:{min:2,max:8,def:4}, apts:3,
front:[B(3.2,'w2'),B(2.6,'wk'),B(3.2,'st'),B(2.6,'wk'),B(3.2,'w2')],
back:[B(3.2,'lz'),B(2.6,'w2'),B(3.2,'w2'),B(2.6,'w2'),B(3.2,'lz')],
verified:'vidēja', note:'Tie paši izmēri kā 464; lodžiju vietas — pieņēmums.'},
'467A': {name:'467A sērija', sub:'9 stāvi · Rīga 1973–1988 · lentveida paneļi, lodžijas', floors:[9], h:2.8, tech:1.4, lift:true, plinth:0.6, rows:1, W:11.68,
endBays:[2.92,2.92,2.92,2.92], endWins:[1,2], sec:{min:1,max:6,def:3}, apts:4,
front:[B(6.4,'w22'),B(3.2,'lz'),B(3.2,'st'),B(6.4,'w22'),B(3.2,'lz'),B(3.2,'wk')],
back:[B(3.2,'lz'),B(6.4,'w22'),B(3.2,'wk'),B(3.2,'wk'),B(6.4,'w22'),B(3.2,'lz')],
verified:'vidēja', note:'Sekcija 25,6 m (ārmērs 26,4), stāvs 2,8 m, solis 3,2/6,4 m un lentveida (divrindu) paneļu dalījums — no EM/BIS 467A izpētes. Precīza 6,4/3,2 paneļu secība un lodžiju vietas Rīgas 9 st. variantam — pieņēmums pēc 1-467A rasējumiem.'},
'467A5': {name:'467A-4L (5 stāvi)', sub:'5 stāvi · Daugavpils, Jelgava, Liepāja · lentveida paneļi', floors:[5], h:2.8, tech:0.6, lift:false, plinth:0.6, rows:1, W:10.1,
endBays:[2.525,2.525,2.525,2.525], endWins:[1], sec:{min:2,max:8,def:6}, apts:3,
front:[B(6.4,'w22'),B(3.2,'st'),B(6.4,'w22')],
back:[B(6.4,'bc'),B(3.2,'wk'),B(6.4,'w22')],
verified:'augsta', note:'Sekcija 16,0 m = 6,4 + 3,2 + 6,4, divas 1,4 m joslas stāvā — no 1-467A-17 tipveida projekta fasādes rasējuma; Daugavpils 6 sekc. ēka 96,6 × 10,1 m.'},
'602': {name:'602. sērija (9 st.)', sub:'9 stāvi · 1974–1990 · Rīgā visizplatītākā', floors:[9], h:2.7, tech:1.4, lift:true, plinth:0.6, rows:1, W:11.2,
endBays:[2.8,2.8,2.8,2.8], endWins:[], sec:{min:2,max:6,def:4}, apts:4,
front:[B(3.2,'w2'),B(3.2,'wk'),B(3.2,'w2'),B(6.4,'st64'),B(3.2,'w2'),B(3.2,'wk'),B(3.2,'w2')],
back:[B(3.2,'lz'),B(3.2,'lz'),B(3.2,'w2'),B(3.2,'wk'),B(3.2,'wk'),B(3.2,'w2'),B(3.2,'lz'),B(3.2,'lz')],
verified:'augsta', note:'Sekcija 25,6 × 11,2 m, solis 3,2 m, ieejas fasāde 3×3,2 + 6,4 (kāpnes+lifts) + 3×3,2, pagalma fasāde 8×3,2 ar lodžijām ārējās ailēs — no RTU apsekojuma (Dammes iela 8) un EM 602 izpētes. Gala sienas bez logiem.',
variants:[{label:'Lodžijas (standarts)',patch:{}},{label:'Balkoni tikai pāra stāvos (agrīnais)',patch:{back:[B(3.2,'bc2'),B(3.2,'bc2'),B(3.2,'w2'),B(3.2,'wk'),B(3.2,'wk'),B(3.2,'w2'),B(3.2,'bc2'),B(3.2,'bc2')]}}]},
'602L': {name:'602. sērija (6–7 st.)', sub:'6, 7 vai 8 stāvi · zemākais variants', floors:[6,7,8], h:2.7, tech:1.4, lift:true, plinth:0.6, rows:1, W:11.2,
endBays:[2.8,2.8,2.8,2.8], endWins:[], sec:{min:2,max:6,def:3}, apts:4,
front:[B(3.2,'w2'),B(3.2,'wk'),B(3.2,'w2'),B(6.4,'st64'),B(3.2,'w2'),B(3.2,'wk'),B(3.2,'w2')],
back:[B(3.2,'lz'),B(3.2,'lz'),B(3.2,'w2'),B(3.2,'wk'),B(3.2,'wk'),B(3.2,'w2'),B(3.2,'lz'),B(3.2,'lz')],
verified:'vidēja', note:'Tā pati sekcija kā 9 st. 602; stāvu skaits 6–8 pēc EM izpētes (3 no 18 apsekotajām — sešstāvu).'},
'103': {name:'103. sērija', sub:'5 stāvi · 1970–1993 · ķieģeļu gali, piekārti paneļi', floors:[5,3,7,9], h:2.8, tech:0.6, lift:false, plinth:1.0, rows:1, W:11.5,
endBays:[], endWins:[], sec:{min:2,max:8,def:4}, apts:3,
front:[B(3.2,'w2'),B(6.4,'w22'),B(3.2,'st'),B(6.4,'w22')],
back:[B(3.2,'lz'),B(6.4,'w22'),B(3.2,'wk'),B(6.4,'lz64')],
verified:'zema', note:'Šķērssienas un GALA sienas ir ķieģeļu (tur šuvju nav); garenfasādēs piekārti gāzbetona/keramzītbetona paneļi 25–35 cm. Sekcijas garums 19,2 m un paneļu secība — aplēse (BIS: sekcijas apbūves laukums ~207 m²). Cokola paneļi 1,78 m.'},
'104': {name:'104. sērija (5 st.)', sub:'5 stāvi · gāzbetona paneļi, lielas lodžijas', floors:[5], h:2.8, tech:0.6, lift:false, plinth:0.6, rows:1, W:12.0,
endBays:[3.0,3.0,3.0,3.0], endWins:[1,2], sec:{min:2,max:8,def:4}, apts:3,
front:[B(6.4,'lz64'),B(3.2,'wk'),B(3.2,'st'),B(3.2,'wk'),B(6.4,'lz64'),B(3.2,'w2')],
back:[B(3.2,'w2'),B(6.4,'w22'),B(3.2,'wk'),B(3.2,'wk'),B(6.4,'w22'),B(3.2,'w2')],
verified:'zema', note:'Gāzbetona paneļi 25–30 cm, solis 3,2/6,4 m, lodžijas visā istabas garumā (~6,2 m) — no RTIAN 20. pielikuma. Zīmēts ar vienu paneli uz stāvu (bez starpjoslas šuves). Sekcijas garums un paneļu secība — aplēse.'},
'104T': {name:'104. sērija (9–16 st.)', sub:'9, 12 vai 16 stāvi · torņi ar 1 kāpņu telpu, 2 lifti', floors:[12,9,16], h:2.8, tech:1.4, lift:true, plinth:0.6, rows:1, W:14.0,
endBays:[3.5,3.5,3.5,3.5], endWins:[1,2], sec:{min:1,max:2,def:1}, apts:6,
front:[B(6.4,'lz64'),B(3.2,'wk'),B(3.2,'st'),B(3.2,'wk'),B(6.4,'lz64')],
back:[B(6.4,'lz64'),B(3.2,'wk'),B(3.2,'w2'),B(3.2,'wk'),B(6.4,'lz64')],
verified:'zema', note:'12/16 st. torņi ar 6 dzīvokļiem stāvā (2×1, 2×2, 2×3 ist.), 9 st. variants Viestura prospektā. Torņa plāna izmēri publiski nav atrasti — aplēse 22,4 × 14 m.'},
'119': {name:'119. sērija', sub:'9 stāvi · 1980–1992 · "latviešu projekts", 2 lodžijas dzīvoklim', floors:[9,5,6,10], h:2.8, tech:1.4, lift:true, plinth:0.6, rows:1, W:12.0,
endBays:[3.0,3.0,3.0,3.0], endWins:[1,2], sec:{min:2,max:8,def:4}, apts:3,
front:[B(3.6,'lz'),B(3.0,'w2'),B(2.4,'st'),B(3.0,'w2'),B(3.6,'lz'),B(3.0,'wk'),B(3.6,'lz'),B(3.0,'w2')],
back:[B(3.0,'w2'),B(3.6,'lz'),B(3.0,'wk'),B(2.4,'wk'),B(3.0,'w2'),B(3.6,'lz'),B(3.0,'w2'),B(3.6,'lz')],
verified:'zema', note:'Šķērssienu solis 2,4/3,0/3,6 m (RTIAN), fasādes ritmu veido vertikālas lodžiju joslas, 2 lodžijas katram dzīvoklim. Sekcijas garums 25,2 m un aiļu secība — aplēse.'},
};
const ORDER = ['464','464A','467A','467A5','602','602L','103','104','104T','119'];
const WIN = {w2:{w:1.46,n:2}, w3:{w:1.76,n:3}, wk:{w:1.16,n:2}, e:{w:1.16,n:2}};
const SILL = 0.8, WH = 1.51;
const FAC = [['front','Priekšpuse (ieejas)'],['back','Aizmugure']];
const state = {series:'602', sections:4, floors:9, variant:0, view:'overview', sector:0, facade:'front', mode:'seg', scope:'custom', sel:new Set(), last:null};
let model = null;
function cfg(){ const S = SERIES[state.series]; const v = (S.variants||[])[state.variant]; return v ? Object.assign({}, S, v.patch) : S; }
// ------------------------------------------------------------ MODEL
function buildModel(){
const S = cfg(), F = state.floors, h = S.h, rows = S.rows, bandH = h/rows;
const fac = {};
const mk = (fid, bays, secs, isEnd)=>{
const cols = []; let x = 0;
for (let s=0;s<secs;s++){
const nApt = fid==='front' ? Math.ceil(S.apts/2) : Math.max(1, Math.floor(S.apts/2));
const free = bays.map((b,i)=>i).filter(i=>!bays[i].k.startsWith('st'));
bays.forEach((b,i)=>{
const isStair = b.k.startsWith('st');
const apt = isStair ? -1 : Math.min(nApt-1, Math.floor(free.indexOf(i)*nApt/free.length));
cols.push({x0:x, x1:x+b.w, k:b.k, sec:s, apt, lodz: b.k==='lz'||b.k==='lz64', win: isEnd ? (S.endWins.includes(i)?'e':null) : null});
x += b.w;
});
}
const width = x, joints = [];
const nb = F*rows; // number of horizontal bands
for (let k=0;k<=nb;k++) for (let c=0;c<cols.length;c++){
const col = cols[c];
joints.push({id:`${fid}-h-${k}-${c}`, t:'h', fid, k, c, sec:col.sec, len: col.x1-col.x0, x1:col.x0, y1:k*bandH, x2:col.x1, y2:k*bandH});
}
const b0 = isEnd?1:0, b1 = isEnd?cols.length-1:cols.length;
for (let b=b0;b<=b1;b++) for (let k=0;k<nb;k++){
const x = b<cols.length ? cols[b].x0 : cols[cols.length-1].x1;
const sec = b<cols.length ? cols[b].sec : cols[cols.length-1].sec;
joints.push({id:`${fid}-v-${b}-${k}`, t:'v', fid, b, k, sec, f:Math.floor(k/rows), len:bandH, x1:x, y1:k*bandH, x2:x, y2:(k+1)*bandH});
}
cols.forEach((col,c)=>{ if(!col.lodz) return; for (let f=0;f<F;f++) for (const side of [0,1]){
const x = side? col.x1-0.3 : col.x0+0.3;
joints.push({id:`${fid}-l-${c}-${side}-${f}`, t:'l', fid, c, f, sec:col.sec, len:h, x1:x, y1:f*h, x2:x, y2:(f+1)*h});
}});
return {cols, width, height:F*h, joints, byId:Object.fromEntries(joints.map(j=>[j.id,j])), isEnd};
};
fac.front = mk('front', S.front, state.sections, false);
fac.back = mk('back', S.back, state.sections, false);
const endBays = S.endBays.map(w=>B(w,'bl'));
fac.endA = S.endBays.length ? mk('endA', endBays, 1, true) : null;
fac.endB = S.endBays.length ? mk('endB', endBays, 1, true) : null;
model = fac;
}
// ------------------------------------------------------------ RENDER (tehniskais zīmējums)
const svgNS = 'http://www.w3.org/2000/svg';
function el(n,a){ const e=document.createElementNS(svgNS,n); for(const k in a) e.setAttribute(k,a[k]); return e; }
function drawFacade(fid, opts){
// opts: {mini, secOnly (index|null), interactive}
const S = cfg(), f = model[fid], F = state.floors, h = S.h, rows = S.rows, bandH = h/rows;
const sc = 10, isEnd = f.isEnd, mini = !!opts.mini;
const cols = opts.secOnly==null ? f.cols : f.cols.filter(c=>c.sec===opts.secOnly);
const xoff = cols[0].x0, width = cols[cols.length-1].x1 - xoff;
const plinth = S.plinth, tech = S.tech, roofBox = S.lift ? (mini?1.2:2.6) : 0.9;
const padX = mini?1.0:(opts.secOnly!=null?2.6:2.0), padT = 0.8, padB = mini?0.8:3.2;
const W = (width + padX*2)*sc, H = (padT+roofBox+0.3+tech+f.height+plinth+padB)*sc;
const svg = el('svg',{viewBox:`0 0 ${W} ${H}`, 'aria-label':'Fasāde '+fid});
const ox = padX*sc, oy = (padT+roofBox+0.3+tech)*sc;
const X = m=>ox+(m-xoff)*sc, Y = m=>oy+m*sc;
const ln = (x1,y1,x2,y2,w,extra)=>{ svg.appendChild(el('line',Object.assign({x1,y1,x2,y2,stroke:'#121417','stroke-width':w,'vector-effect':'non-scaling-stroke','stroke-linecap':'square'},extra||{}))); };
const rc = (x,y,w,hh,sw,extra)=>{ const e=el('rect',Object.assign({x,y,width:w,height:hh,fill:'#fff',stroke:'#121417','stroke-width':sw,'vector-effect':'non-scaling-stroke'},extra||{})); svg.appendChild(e); return e; };
const winRect = (xm, ym, w, hh, n)=>{ rc(X(xm), Y(ym), w*sc, hh*sc, 0.9); for (let i=1;i<n;i++) ln(X(xm+i*w/n), Y(ym), X(xm+i*w/n), Y(ym+hh), 0.6); ln(X(xm), Y(ym+hh*0.62), X(xm+w), Y(ym+hh*0.62), 0.5); };
const x0m = cols[0].x0, x1m = cols[cols.length-1].x1;
// roof: lift rooms above stair bays, vents
cols.forEach(col=>{ if (S.lift && col.k.startsWith('st')){ const bw = col.x1-col.x0; rc(X(col.x0+(bw-4.2)/2), Y(-tech-2.6), 4.2*sc, 2.6*sc, 1.1); rc(X(col.x0+(bw-4.2)/2+1.2), Y(-tech-2.0), 0.9*sc, 2.0*sc, 0.7); } });
if (!isEnd){ const seen=new Set(); cols.forEach(col=>{ if(!seen.has(col.sec)){ seen.add(col.sec); const sx = f.cols.find(c=>c.sec===col.sec).x0; const sl = f.cols.filter(c=>c.sec===col.sec).reduce((a,c)=>a+(c.x1-c.x0),0); for (const r of [0.33,0.8]) rc(X(sx+sl*r), Y(-tech-0.9), 0.6*sc, 0.9*sc, 0.8); } }); }
else if (S.lift) rc(X(x0m+width*0.3), Y(-tech-2.6), 3.6*sc, 2.6*sc, 1.1);
// wall outline
rc(X(x0m), Y(-tech), width*sc, (tech+f.height+plinth)*sc, 1.6);
if (tech>0){ ln(X(x0m), Y(0), X(x1m), Y(0), 1.1); if(!isEnd) cols.forEach((col,i)=>{ if(!col.k.startsWith('st') && i%2===1) rc(X(col.x0+(col.x1-col.x0)/2-0.3), Y(-tech+tech*0.32), 0.6*sc, Math.min(0.4,tech*0.5)*sc, 0.7); }); }
ln(X(x0m)-0.1*sc, Y(-tech)-0.25*sc, X(x1m)+0.1*sc, Y(-tech)-0.25*sc, 1.6);
ln(X(x0m)-0.1*sc, Y(-tech)-0.25*sc, X(x0m)-0.1*sc, Y(-tech), 1.6); ln(X(x1m)+0.1*sc, Y(-tech)-0.25*sc, X(x1m)+0.1*sc, Y(-tech), 1.6);
ln(X(x0m), Y(f.height), X(x1m), Y(f.height), 1.2);
cols.forEach((col,i)=>{ if (i%2===0 && !col.k.startsWith('st') && plinth>=0.5) rc(X(col.x0+0.9), Y(f.height+0.12), 0.9*sc, 0.36*sc, 0.7); });
ln(X(x0m)-1.5*sc, Y(f.height+plinth), X(x1m)+1.5*sc, Y(f.height+plinth), 1.8);
// windows etc.
cols.forEach(col=>{
const bw = col.x1-col.x0;
for (let fl=0;fl<F;fl++){
const yf = (fl+1)*h, wh = rows===2 ? Math.min(WH, bandH-0.3) : WH, sill = rows===2 ? bandH + (bandH - wh)/2 : SILL;
const win1 = (w,n,cx)=> winRect(cx-w/2, yf-sill-wh, w, wh, n);
const k = col.k;
if (k==='st' || k==='st64'){
const cx = col.x0 + bw/2;
if (fl<F-1) winRect(cx-0.58, yf-(h/2+0.75), 1.16, 1.51, 2); else winRect(cx-0.58, yf-SILL-WH, 1.16, WH, 2);
if (k==='st64'){ win1(WIN.w2.w,2,col.x0+1.1); win1(WIN.w2.w,2,col.x1-1.1); }
if (fl===F-1 && fid==='front'){
const dx = cx-0.65;
rc(X(dx), Y(yf-2.2), 1.3*sc, 2.2*sc, 1.1); ln(X(dx+0.65), Y(yf-2.2), X(dx+0.65), Y(yf), 0.7);
ln(X(dx-0.85), Y(yf-2.5), X(dx+2.15), Y(yf-2.5), 1.6); ln(X(dx-0.85), Y(yf-2.5), X(dx-0.85), Y(yf), 0.8); ln(X(dx+2.15), Y(yf-2.5), X(dx+2.15), Y(yf), 0.8);
}
} else if (k==='lz' || k==='lz64'){
rc(X(col.x0+0.3), Y(yf-h), (bw-0.6)*sc, h*sc, 0.8, {'stroke-dasharray':'3 2'});
rc(X(col.x0+0.3), Y(yf-1.15), (bw-0.6)*sc, 1.1*sc, 0.9);
for (let i=1;i<4;i++) ln(X(col.x0+0.3), Y(yf-1.15+i*1.1/4), X(col.x1-0.3), Y(yf-1.15+i*1.1/4), 0.45);
winRect(col.x0+0.7, yf-2.15, 0.75, 2.15, 1); winRect(col.x0+1.55, yf-SILL-WH, 1.16, WH, 1);
if (k==='lz64'){ winRect(col.x1-2.3, yf-SILL-WH, 1.46, WH, 2); }
} else if (k==='bc' || (k==='bc2' && fl%2===1)){
winRect(col.x0+0.7, yf-2.15, 0.75, 2.15, 1); winRect(col.x0+1.55, yf-SILL-WH, 1.16, WH, 1);
rc(X(col.x0+0.25), Y(yf-1.15), (bw-0.5)*sc, 1.1*sc, 1.1);
for (let i=1;i<4;i++) ln(X(col.x0+0.25), Y(yf-1.15+i*1.1/4), X(col.x1-0.25), Y(yf-1.15+i*1.1/4), 0.45);
ln(X(col.x0+0.25), Y(yf-0.05), X(col.x1-0.25), Y(yf-0.05), 1.4);
} else if (k==='bc2'){ win1(WIN.w2.w,2,col.x0+bw/2); }
else if (k==='w22'){ win1(WIN.w2.w,2,col.x0+bw*0.27); win1(WIN.w2.w,2,col.x0+bw*0.73); }
else if (WIN[k]){ win1(WIN[k].w, WIN[k].n, col.x0+bw/2); }
else if (k==='bl' && col.win){ win1(WIN.e.w, 2, col.x0+bw/2); }
}
});
const inView = j => (opts.secOnly==null) || j.sec===opts.secOnly;
if (mini || !opts.interactive){
f.joints.filter(inView).forEach(j=>{ const on = state.sel.has(j.id); ln(X(j.x1),Y(j.y1),X(j.x2),Y(j.y2), on?3.2:0.7, on?{stroke:'#E8A400'}:(j.t==='l'?{stroke:'#2563C9','stroke-dasharray':'3 2'}:{})); });
} else {
const gCells = el('g',{});
cols.forEach(col=>{ const c = f.cols.indexOf(col); for (let fl=0;fl<F;fl++){
const r = el('rect',{x:X(col.x0),y:Y(fl*h),width:(col.x1-col.x0)*sc,height:h*sc,'class':'cell','data-c':c,'data-f':fl});
r.hidden = state.mode!=='apt'; gCells.appendChild(r);
}});
svg.appendChild(gCells);
const gJ = el('g',{});
f.joints.filter(inView).forEach(j=>{
gJ.appendChild(el('line',{x1:X(j.x1),y1:Y(j.y1),x2:X(j.x2),y2:Y(j.y2),'class':'hit','data-id':j.id}));
gJ.appendChild(el('line',{x1:X(j.x1),y1:Y(j.y1),x2:X(j.x2),y2:Y(j.y2),'class':'joint '+j.t+(state.sel.has(j.id)?' on':''),'data-line':j.id}));
});
svg.appendChild(gJ);
}
// sector overlays (overview) + labels
if (!mini){
if (!isEnd){
const secs = [...new Set(cols.map(c=>c.sec))];
secs.forEach(s=>{
const sc0 = f.cols.filter(c=>c.sec===s), sx0 = sc0[0].x0, sx1 = sc0[sc0.length-1].x1;
const m = sectorMeters(s);
const t = el('text',{x:X((sx0+sx1)/2),y:Y(f.height+plinth)+1.7*sc,'text-anchor':'middle','font-size':opts.secOnly!=null?'3.6':'4.2','fill':'#121417','font-family':'Inter, sans-serif','font-weight':'600'});
t.textContent = (s+1)+'. kāpņu telpa · '+(sx1-sx0).toLocaleString('lv-LV',{maximumFractionDigits:1})+' m'+(m>0?' · '+fmt1(m)+' m šuvju':''); svg.appendChild(t);
if (s>0 && opts.secOnly==null) ln(X(sx0), Y(f.height+plinth)+0.5*sc, X(sx0), Y(f.height+plinth)+2.3*sc, 0.6);
if (opts.sectors){
const r = el('rect',{x:X(sx0),y:Y(-tech)-(roofBox+0.3)*sc,width:(sx1-sx0)*sc,height:(roofBox+0.3+tech+f.height+plinth)*sc,'class':'sector'+(m>0?' done':''),'data-sec':s,rx:2});
svg.appendChild(r);
}
});
} else {
const t = el('text',{x:X(x0m+width/2),y:Y(f.height+plinth)+1.7*sc,'text-anchor':'middle','font-size':'4.2','fill':'#121417','font-family':'Inter, sans-serif','font-weight':'600'});
t.textContent = 'Gals · '+S.W.toLocaleString('lv-LV')+' m'; svg.appendChild(t);
if (opts.sectors) svg.appendChild(el('rect',{x:X(x0m),y:Y(-tech)-(roofBox+0.3)*sc,width:width*sc,height:(roofBox+0.3+tech+f.height+plinth)*sc,'class':'sector','data-sec':fid,rx:2}));
}
if (opts.secOnly!=null || isEnd){
const hx = X(x0m)-1.5*sc;
ln(hx, Y(0), hx, Y(f.height), 0.6); ln(hx-0.4*sc, Y(0), hx+0.4*sc, Y(0), 0.6); ln(hx-0.4*sc, Y(f.height), hx+0.4*sc, Y(f.height), 0.6);
const ht = el('text',{x:hx-0.5*sc,y:Y(f.height/2),'text-anchor':'middle','font-size':'3.6','fill':'#121417','font-family':'Inter, sans-serif',transform:`rotate(-90 ${hx-0.5*sc} ${Y(f.height/2)})`});
ht.textContent = F+' st. × '+h.toLocaleString('lv-LV')+' m = '+(F*h).toLocaleString('lv-LV',{maximumFractionDigits:1})+' m'; svg.appendChild(ht);
}
}
return svg;
}
// ------------------------------------------------------------ SELECTION
function aptGroup(fid, c, fl){
const S = cfg(), rows = S.rows, f = model[fid], col = f.cols[c];
if (col.k.startsWith('st')) return null;
const idx = f.cols.map((x,i)=>i).filter(i=>f.cols[i].sec===col.sec && f.cols[i].apt===col.apt && !f.cols[i].k.startsWith('st'));
const c0 = Math.min(...idx), c1 = Math.max(...idx), ids = [];
for (let cc=c0;cc<=c1;cc++){ for (let k=fl*rows;k<=(fl+1)*rows;k++) ids.push(`${fid}-h-${k}-${cc}`); if (f.cols[cc].lodz) ids.push(`${fid}-l-${cc}-0-${fl}`,`${fid}-l-${cc}-1-${fl}`); }
for (let b=c0;b<=c1+1;b++) for (let k=fl*rows;k<(fl+1)*rows;k++) ids.push(`${fid}-v-${b}-${k}`);
return ids.filter(id=>f.byId[id]);
}
function toggleIds(ids){ const all = ids.every(id=>state.sel.has(id)); ids.forEach(id=> all ? state.sel.delete(id) : state.sel.add(id)); }
function rangeIds(a, b){
const A = model[a.fid].byId[a.id], Bj = model[b.fid].byId[b.id]; if (!A||!Bj||A.fid!==Bj.fid||A.t!==Bj.t) return null;
const f = model[A.fid];
if (A.t==='h' && A.k===Bj.k){ const [c0,c1]=[Math.min(A.c,Bj.c),Math.max(A.c,Bj.c)]; return f.joints.filter(j=>j.t==='h'&&j.k===A.k&&j.c>=c0&&j.c<=c1).map(j=>j.id); }
if (A.t==='v' && A.b===Bj.b){ const [k0,k1]=[Math.min(A.k,Bj.k),Math.max(A.k,Bj.k)]; return f.joints.filter(j=>j.t==='v'&&j.b===A.b&&j.k>=k0&&j.k<=k1).map(j=>j.id); }
return null;
}
function sectorMeters(s){ let m=0; for (const fid of ['front','back']) model[fid].joints.forEach(j=>{ if(j.sec===s && state.sel.has(j.id)) m+=j.len; }); return m; }
function facadeMeters(fid){ let m=0; if(!model[fid]) return 0; model[fid].joints.forEach(j=>{ if(state.sel.has(j.id)) m+=j.len; }); return m; }
// ------------------------------------------------------------ TOTALS
const fmt = n => n.toLocaleString('lv-LV',{maximumFractionDigits:0});
const fmt1 = n => n.toLocaleString('lv-LV',{minimumFractionDigits:1,maximumFractionDigits:1});
const fmtEur = n => Math.round(n).toLocaleString('lv-LV')+' €';
// šauras un augstas ēkas (torņi): fasādes liek blakus, nevis vienu zem otras
const isTall = svg => { const vb=(svg.getAttribute('viewBox')||'0 0 1 1').split(' ').map(Number); return vb[2]/vb[3] < 1.15; };
function totals(){
const t = {h:0,v:0,l:0,n:0};
for (const fid in model) if (model[fid]) for (const j of model[fid].joints) if (state.sel.has(j.id)){ t[j.t]+=j.len; t.n++; }
t.sum = t.h+t.v+t.l;
t.price = +document.getElementById('pWarm').value;
const vat = +document.getElementById('pVat').value/100;
t.net = t.sum*t.price; t.vat = t.net*vat; t.gross = t.net+t.vat; t.days = t.sum>0 ? Math.max(1, Math.ceil(t.sum/60)) : 0;
return t;
}
function renderTotals(){
const t = totals();
document.getElementById('bigMeters').innerHTML = '<small class="lb">Atzīmētās šuves</small>'+fmt1(t.sum)+'<span class="u">m</span><small class="eur">≈ '+fmtEur(t.gross)+' ar PVN</small>';
const ctr = document.getElementById('counter'); if (ctr) ctr.innerHTML = '<span class="cl">Atzīmēts</span><b>'+fmt1(t.sum)+'<i>m</i></b><span class="ce">≈ '+fmtEur(t.gross)+'</span>';
const rows = [['Horizontālās šuves', fmt1(t.h)+' m'],['Vertikālās šuves', fmt1(t.v)+' m'],['Lodžiju šuves', fmt1(t.l)+' m'],
['Cena par tekošo metru (darbs + materiāli)', t.price.toLocaleString('lv-LV')+' €'],['Summa bez PVN', fmt(t.net)+' €'],['PVN '+document.getElementById('pVat').value+' %', fmt(t.vat)+' €']];
let html = rows.map(([k,v])=>`<span class="k">${k}</span><span class="v">${v}</span>`).join('');
html += `<span class="k sum">Kopā ar PVN</span><span class="v sum">${fmt(t.gross)} €</span>`;
document.getElementById('rows').innerHTML = html;
renderSummary(t);
}
// ------------------------------------------------------------ SAITE AR ATZĪMĒJUMU + PNG
const FAC_ORDER = ['front','back','endA','endB'];
function allJoints(){ const out=[]; for (const fid of FAC_ORDER) if (model[fid]) model[fid].joints.forEach(j=>out.push(j.id)); return out; }
function encodeSel(){
const ids = allJoints(); const bytes = new Uint8Array(Math.ceil(ids.length/8));
ids.forEach((id,i)=>{ if (state.sel.has(id)) bytes[i>>3] |= 1<<(i&7); });
let bin=''; bytes.forEach(b=>bin+=String.fromCharCode(b));
return btoa(bin).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'');
}
function decodeSel(b64){
try{ const bin = atob(b64.replace(/-/g,'+').replace(/_/g,'/')); const ids = allJoints(); state.sel.clear();
ids.forEach((id,i)=>{ const byte = bin.charCodeAt(i>>3); if (byte & (1<<(i&7))) state.sel.add(id); }); return true; }catch(e){ return false; }
}
function stateLink(){
const q = new URLSearchParams({s:state.series, n:state.sections, f:state.floors, v:state.variant, b:encodeSel()});
return location.origin + location.pathname + location.search + '#suvk=' + q.toString();
}
function restoreFromHash(){
const m = /#suvk=(.+)$/.exec(location.hash); if (!m) return false;
const q = new URLSearchParams(m[1]); const sid = q.get('s'); if (!SERIES[sid]) return false;
state.series = sid; const S = SERIES[sid];
state.sections = Math.min(S.sec.max, Math.max(S.sec.min, +q.get('n')||S.sec.def));
state.floors = S.floors.includes(+q.get('f')) ? +q.get('f') : S.floors[0];
state.variant = Math.max(0, Math.min((S.variants||[]).length-1, +q.get('v')||0));
buildModel(); fillControls(); if (q.get('b')) decodeSel(q.get('b'));
state.scope='custom'; state.view='overview'; state.facade='front';
document.querySelectorAll('[data-scope]').forEach(b=>b.setAttribute('aria-pressed', String(b.dataset.scope==='custom')));
return true;
}
function exportPNG(){
const parts = []; for (const fid of FAC_ORDER) if (model[fid]) parts.push(fid);
const W = 1600, pad = 40, gap = 30; let y = pad; const items = [];
const svgs = parts.map(fid=>{ const svg = drawFacade(fid,{interactive:false}); const vb = svg.getAttribute('viewBox').split(' ').map(Number); return {fid, svg, vw:vb[2], vh:vb[3]}; });
const longs = svgs.filter(x=>!model[x.fid].isEnd), ends = svgs.filter(x=>model[x.fid].isEnd);
longs.forEach(x=>{ const w = W-2*pad, h = w*x.vh/x.vw; items.push({x:x,px:pad,py:y,pw:w,ph:h}); y += h+gap; });
if (ends.length){ const w = Math.min(240, (W-2*pad-gap)/ends.length); let xx = pad; let maxh=0; ends.forEach(x=>{ const h = w*x.vh/x.vw; items.push({x:x,px:xx,py:y,pw:w,ph:h}); xx += w+gap; maxh=Math.max(maxh,h); }); y += maxh; }
const S = cfg(), t = totals();
const info = [
`${S.name} · ${state.sections} kāpņu telpas · ${state.floors} stāvi${S.variants?' · '+S.variants[state.variant].label:''}`,
`Atzīmētās šuves: ${fmt1(t.sum)} m (horizontālās ${fmt1(t.h)} · vertikālās ${fmt1(t.v)} · lodžiju ${fmt1(t.l)})`,
`Cena ${t.price} €/m (darbs + materiāli) · bez PVN ${fmt(t.net)} € · PVN ${fmt(t.vat)} € · kopā ${fmt(t.gross)} €`,
[document.getElementById('fName').value, document.getElementById('fPhone').value, document.getElementById('fAddr').value].filter(Boolean).join(' · '),
document.getElementById('fNote').value
].filter(Boolean);
const foot = 60 + info.length*24;
const canvas = document.createElement('canvas'); canvas.width = W; canvas.height = Math.ceil(y+pad+foot);
const ctx = canvas.getContext('2d'); ctx.fillStyle='#fff'; ctx.fillRect(0,0,canvas.width,canvas.height);
const labels = {front:'Priekšpuse (ieejas)', back:'Aizmugure', endA:'Gals A', endB:'Gals B'};
let done = 0;
return new Promise(resolve=>{
items.forEach(it=>{
const src = new XMLSerializer().serializeToString(it.x.svg);
const img = new Image();
img.onload = ()=>{ ctx.drawImage(img, it.px, it.py, it.pw, it.ph); ctx.fillStyle='#5C6470'; ctx.font='600 16px Inter, Arial, sans-serif'; ctx.fillText(labels[it.x.fid]+' · '+fmt1(facadeMeters(it.x.fid))+' m', it.px, it.py+it.ph+18);
if (++done===items.length){
let ty = canvas.height - foot + 8;
ctx.fillStyle='#E9ECF0'; ctx.fillRect(pad, ty, W-2*pad, 2); ty += 26;
info.forEach((line,i)=>{ ctx.fillStyle = i===0 ? '#121417' : '#2b3a4a'; ctx.font = (i===0?'700 20px':'500 16px')+' Inter, Arial, sans-serif'; ctx.fillText(line, pad, ty); ty += 24; });
ctx.fillStyle='#8A93A0'; ctx.font='13px Inter, Arial, sans-serif'; ctx.fillText('Šuvju hermetizācijas pieprasījums · alpinisti.lv kalkulators · '+new Date().toLocaleDateString('lv-LV')+' · +371 27870013 · info@alpinisti.lv', pad, canvas.height-14);
resolve(canvas); } };
img.src = 'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(src);
});
});
}
function downloadPNG(){ exportPNG().then(c=>new Promise(r=>c.toBlob(r,'image/png')).then(b=>downloadFile('suvju-atzimejums-'+state.series+'.png', b, 'Zīmējums saglabāts — pievieno to e-pastam kā pielikumu.'))); }
// PDF bez bibliotēkām: viena lapa ar JPEG attēlu (DCTDecode), lapas izmērs pēc attēla proporcijām (A4 platums)
function canvasToPDF(canvas){
const jpeg = canvas.toDataURL('image/jpeg', 0.9); const b64 = jpeg.split(',')[1]; const bin = atob(b64);
const bytes = new Uint8Array(bin.length); for (let i=0;i<bin.length;i++) bytes[i]=bin.charCodeAt(i);
const pw = 595.28, ph = Math.round(pw*canvas.height/canvas.width*100)/100; // A4 platums, augstums pēc attēla
const enc = new TextEncoder(); const parts = []; const offs = []; let len = 0;
const push = (x)=>{ const u = typeof x==='string' ? enc.encode(x) : x; parts.push(u); len += u.length; };
push('%PDF-1.4\n%\xE2\xE3\xCF\xD3\n');
const obj = (n, body)=>{ offs[n]=len; push(`${n} 0 obj\n`); if (typeof body==='string') push(body); else { push(body.head); push(body.data); push('\nendstream'); } push('\nendobj\n'); };
obj(1,'<< /Type /Catalog /Pages 2 0 R >>');
obj(2,'<< /Type /Pages /Kids [3 0 R] /Count 1 >>');
obj(3,`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${pw} ${ph}] /Resources << /XObject << /Im1 5 0 R >> >> /Contents 4 0 R >>`);
const content = `q ${pw} 0 0 ${ph} 0 0 cm /Im1 Do Q`;
obj(4,{head:`<< /Length ${content.length} >>\nstream\n`, data:enc.encode(content)});
obj(5,{head:`<< /Type /XObject /Subtype /Image /Width ${canvas.width} /Height ${canvas.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${bytes.length} >>\nstream\n`, data:bytes});
const xref = len;
push(`xref\n0 6\n0000000000 65535 f \n`); for (let i=1;i<=5;i++) push(String(offs[i]).padStart(10,'0')+' 00000 n \n');
push(`trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`);
return new Blob(parts, {type:'application/pdf'});
}
function downloadFile(name, blob, okMsg){
const tt=document.getElementById('toast'), say=m=>{ if(tt){ tt.textContent=m; setTimeout(()=>tt.textContent='',4000); } };
return (async()=>{
const dl = (window.claude && window.claude.use) ? await window.claude.use('downloads') : null;
if (dl){ try{ await dl.save({filename:name, data:blob}); say(okMsg); }catch(e){ if(!(e&&e.code==='declined')) say('Neizdevās saglabāt failu.'); } return; }
const a=document.createElement('a'); a.download=name; a.href=URL.createObjectURL(blob); document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(a.href),3000); say(okMsg);
})();
}
function downloadPDF(){ exportPNG().then(c=>downloadFile('suvju-pieprasijums-'+state.series+'.pdf', canvasToPDF(c), 'PDF saglabāts — pievieno to e-pastam kā pielikumu.')); }
function renderSummary(t){
const S = cfg();
const parts = [];
for (let s=0;s<state.sections;s++){ const m = sectorMeters(s); if (m>0) parts.push(` ${s+1}. kāpņu telpa: ${fmt1(m)} m`); }
for (const [fid,lab] of [['endA','Gals A'],['endB','Gals B']]){ const m = facadeMeters(fid); if (m>0) parts.push(` ${lab}: ${fmt1(m)} m`); }
const txt = `Šuvju hermetizācijas pieprasījums (alpinisti.lv kalkulators)
Vārds: ${document.getElementById('fName').value||'-'}
Tālrunis: ${document.getElementById('fPhone').value||'-'}
Adrese: ${document.getElementById('fAddr').value||'-'}
Māja: ${S.name}, ${state.sections} kāpņu telpas, ${state.floors} stāvi${S.variants?', '+S.variants[state.variant].label:''}
Atzīmētās šuves: ${fmt1(t.sum)} m (horiz. ${fmt1(t.h)}, vert. ${fmt1(t.v)}, lodžiju ${fmt1(t.l)})
${parts.join('\n')||' (nav atzīmēts)'}
Cena: ${t.price} €/m (darbs + materiāli)
Orientējoši: ${fmt(t.net)} € + PVN = ${fmt(t.gross)} €
Piezīmes: ${document.getElementById('fNote').value||'-'}
Zīmējums ar atzīmētajām šuvēm (atveras kalkulatorā): ${stateLink()}`;
document.getElementById('summaryText').textContent = txt;
document.getElementById('mailto').href = 'mailto:info@alpinisti.lv?subject='+encodeURIComponent('Šuvju hermetizācija — '+(document.getElementById('fAddr').value||'pieprasījums'))+'&body='+encodeURIComponent(txt);
}
// ------------------------------------------------------------ UI
function renderSeriesCards(){
const box = document.getElementById('series'); box.innerHTML='';
const saved = {...state, sel:state.sel};
for (const id of ORDER){
const S = SERIES[id];
const b = document.createElement('button'); b.type='button'; b.className='card'; b.setAttribute('aria-pressed', String(id===state.series)); b.dataset.id=id;
state.series=id; state.sections=Math.min(S.sec.def,3); state.floors=S.floors[0]; state.variant=0; buildModel();
b.appendChild(drawFacade('front',{mini:true}));
const t = document.createElement('div'); t.innerHTML = `<b>${S.name}</b><br><small>${S.sub}</small>`; b.appendChild(t);
b.addEventListener('click', ()=>{ selectSeries(id); goStep(2); });
box.appendChild(b);
}
Object.assign(state, saved); buildModel();
}
function selectSeries(id){
const S = SERIES[id];
state.series=id; state.sections=S.sec.def; state.floors=S.floors[0]; state.variant=0; state.sel.clear(); state.last=null; state.view='overview'; state.sector=0; state.facade='front';
document.querySelectorAll('#series .card').forEach(c=>c.setAttribute('aria-pressed', String(c.dataset.id===id)));
buildModel(); fillControls(); document.getElementById('whichSec').value='0'; applyScope();
}
function fillControls(){
const S = SERIES[state.series];
const sec = document.getElementById('sections'); sec.innerHTML='';
for (let n=S.sec.min;n<=S.sec.max;n++){ const o=document.createElement('option'); o.value=n; o.textContent=n; if(n===state.sections) o.selected=true; sec.appendChild(o); }
sec.disabled = S.sec.min===S.sec.max;
const fl = document.getElementById('floors'); fl.innerHTML='';
S.floors.forEach(n=>{ const o=document.createElement('option'); o.value=n; o.textContent=n; if(n===state.floors) o.selected=true; fl.appendChild(o); });
fl.disabled = S.floors.length===1;
const v = document.getElementById('variant'); v.innerHTML='';
const vf = document.getElementById('variantField'); vf.hidden = !S.variants;
(S.variants||[]).forEach((va,i)=>{ const o=document.createElement('option'); o.value=i; o.textContent=va.label; if(i===state.variant) o.selected=true; v.appendChild(o); });
fillWhichSec();
}
function renderTabs(){
const tabs = document.getElementById('tabs'); tabs.innerHTML='';
const items = state.view==='overview' ? FAC : (state.view==='end' ? [] : FAC);
items.forEach(([fid,label])=>{
const b=document.createElement('button'); b.type='button'; b.className='tab'; b.setAttribute('role','tab'); b.setAttribute('aria-selected', String(fid===state.facade));
const m = facadeMeters(fid); b.innerHTML = label + (m>0?`<span class="m">${fmt1(m)} m</span>`:''); b.addEventListener('click',()=>{ state.facade=fid; renderStage(); });
tabs.appendChild(b);
});
tabs.hidden = !items.length || state.view==='overview';
}
function renderStage(){
renderTabs();
const box = document.getElementById('svgbox'); box.innerHTML='';
const crumb = document.getElementById('crumb'), tools = document.getElementById('tools'), hint = document.getElementById('hint');
tools.innerHTML='';
// navigācijas josla: Visa ēka · kāpņu telpas 1…n · gali, ar ‹ › pāršķiršanu
(function(){
const n = state.sections, isSec = state.view==='sector', isEnd = state.view==='end';
const seq = ['ov'].concat(Array.from({length:n},(_,i)=>i)).concat(model.endA?['endA','endB']:[]);
const cur = state.view==='overview' ? 'ov' : (isEnd ? state.facade : state.sector);
const ci = seq.indexOf(cur);
const go = v=>{ if (v==='ov'){ state.view='overview'; state.facade='front'; } else if (v==='endA'||v==='endB'){ state.view='end'; state.facade=v; } else { state.view='sector'; state.sector=v; if (state.facade==='endA'||state.facade==='endB') state.facade='front'; } renderStage(); };
const seg = (v,label,title)=>{ const b=document.createElement('button'); b.type='button'; b.className='seg'+(v===cur?' akt':''); b.textContent=label; if(title) b.title=title; const m = v==='ov'?0:(v==='endA'||v==='endB'?facadeMeters(v):sectorMeters(v)); if (m>0) b.classList.add('has'); b.addEventListener('click',()=>go(v)); return b; };
crumb.innerHTML='';
const strip=document.createElement('div'); strip.className='strip';
const mk=(t,d,title)=>{ const b=document.createElement('button'); b.type='button'; b.className='pg'; b.textContent=t; b.title=title; b.disabled = ci+d<0 || ci+d>=seq.length; b.addEventListener('click',()=>go(seq[ci+d])); strip.appendChild(b); };
mk('‹',-1,'Iepriekšējā');
strip.appendChild(seg('ov','Visa ēka'));
const lbl=document.createElement('span'); lbl.className='sl'; lbl.textContent='Kāpņu telpa'; strip.appendChild(lbl);
for (let i=0;i<n;i++) strip.appendChild(seg(i, String(i+1), (i+1)+'. kāpņu telpa'));
if (model.endA){ strip.appendChild(seg('endA','Gals A')); strip.appendChild(seg('endB','Gals B')); }
mk('›',1,'Nākamā');
crumb.appendChild(strip);
})();
const mkBtn = (label, fn, cls)=>{ const b=document.createElement('button'); b.type='button'; b.className='btn sm'+(cls?' '+cls:''); b.textContent=label; b.addEventListener('click',fn); tools.appendChild(b); return b; };
const mkLbl = t=>{ const e=document.createElement('span'); e.className='tl'; e.textContent=t; tools.appendChild(e); };
const mkSp = ()=>{ const e=document.createElement('span'); e.className='sp'; tools.appendChild(e); };
if (state.view==='overview'){
const wrap = document.createElement('div'); wrap.className='ov';
const lab = t=>{ const e=document.createElement('div'); e.className='plab'; e.textContent=t; return e; };
const main = drawFacade('front',{interactive:false, sectors:true});
const r1 = document.createElement('div'); r1.className='prow'; r1.appendChild(lab('Priekšpuse (ieejas)')); r1.appendChild(main); wrap.appendChild(r1);
const r2 = document.createElement('div'); r2.className='prow'; r2.appendChild(lab('Aizmugure')); r2.appendChild(drawFacade('back',{interactive:false, sectors:true})); wrap.appendChild(r2);
if (model.endA){
const row = document.createElement('div'); row.className='ends';
['endA','endB'].forEach((fid,i)=>{ const w=document.createElement('div'); w.className='prow'; w.appendChild(lab(i?'Gals B':'Gals A')); w.appendChild(drawFacade(fid,{interactive:false, sectors:true})); row.appendChild(w); });
wrap.appendChild(row);
}
box.appendChild(wrap); box.classList.toggle('tall', isTall(main));
mkLbl('Atzīmēt:'); mkBtn('Visu ēku', ()=>{ for (const fid in model) if(model[fid]) model[fid].joints.forEach(j=>state.sel.add(j.id)); renderStage(); });
mkSp(); mkBtn('Notīrīt visu', ()=>{ state.sel.clear(); renderStage(); }, 'danger');
hint.textContent = 'Pārskats: kāpņu telpas ar atzīmētām šuvēm ir iekrāsotas. Klikšķis uz kāpņu telpas atver to lielā mērogā.';
} else if (state.view==='sector'){
const s = state.sector, n = state.sections;
{ const sv = drawFacade(state.facade,{interactive:true, secOnly:s}); box.appendChild(sv); box.classList.toggle('tall', isTall(sv)); }
mkLbl('Atzīmēt:');
mkBtn('Šo fasādi', ()=>{ model[state.facade].joints.forEach(j=>{ if(j.sec===s) state.sel.add(j.id); }); renderStage(); });
mkBtn('Visu kāpņu telpu (abas puses)', ()=>{ for (const fid of ['front','back']) model[fid].joints.forEach(j=>{ if(j.sec===s) state.sel.add(j.id); }); renderStage(); });
mkSp(); mkBtn('Notīrīt kāpņu telpu', ()=>{ for (const fid of ['front','back']) model[fid].joints.forEach(j=>{ if(j.sec===s) state.sel.delete(j.id); }); renderStage(); }, 'danger');
hint.textContent = state.mode==='apt' ? 'Klikšķini uz dzīvokļa logiem — atzīmēsies visas šuves ap tā ārsienas paneļiem. Vēlreiz — noņems.' : 'Klikšķini uz šuves, velc pār vairākiem posmiem, vai turi Shift un klikšķini otru posmu tajā pašā līnijā.';
} else { // end
const fid = state.facade;
const other = fid==='endA'?'endB':'endA';
{ const sv = drawFacade(fid,{interactive:true}); box.appendChild(sv); box.classList.toggle('tall', true); }
mkLbl('Atzīmēt:'); mkBtn('Visu galu', ()=>{ model[fid].joints.forEach(j=>state.sel.add(j.id)); renderStage(); });
mkSp(); mkBtn('Notīrīt galu', ()=>{ model[fid].joints.forEach(j=>state.sel.delete(j.id)); renderStage(); }, 'danger');
hint.textContent = state.mode==='apt' ? 'Klikšķini uz gala dzīvokļa paneļiem vai pārslēdzies uz "Posmi".' : 'Klikšķini uz šuves vai velc pār vairākiem posmiem.';
}
renderTotals();
}
function renderPreview(){} // 2. un 3. solis apvienoti — atsevišķa priekšskata vairs nav
function rebuild(){ buildModel(); fillWhichSec(); if (state.scope==='all' || state.scope==='sec') applyScope(); else { renderStage(); renderPreview(); } if (typeof updateChosen==='function') updateChosen(); }
// ------------------------------------------------------------ APJOMS (scope)
function fillWhichSec(){
const w = document.getElementById('whichSec'); w.innerHTML='';
for (let n=0;n<state.sections;n++){ const o=document.createElement('option'); o.value=n; o.textContent=(n+1)+'. kāpņu telpa'; if(n===state.sector) o.selected=true; w.appendChild(o); }
if (model && model.endA){ for (const [v,l] of [['endA','Gals A'],['endB','Gals B']]){ const o=document.createElement('option'); o.value=v; o.textContent=l; w.appendChild(o); } }
}
function applyScope(){
const sc = state.scope, hint = document.getElementById('scopeHint'), row = document.getElementById('scopeRow');
document.querySelectorAll('.mode.scope button').forEach(b=>b.setAttribute('aria-pressed', String(b.dataset.scope===sc)));
row.hidden = !(sc==='sec' || sc==='apt');
if (sc==='all'){
state.sel.clear(); for (const fid in model) if(model[fid]) model[fid].joints.forEach(j=>state.sel.add(j.id));
state.view='overview'; hint.textContent = 'Atzīmētas visas šuves visā ēkā — abas garenfasādes un abi gali. Zīmējumā vari kaut ko noņemt.';
} else if (sc==='sec'){
const v = document.getElementById('whichSec').value; state.sel.clear();
if (v==='endA'||v==='endB'){ model[v].joints.forEach(j=>state.sel.add(j.id)); state.view='end'; state.facade=v; }
else { const s=+v; state.sector=s; for (const fid of ['front','back']) model[fid].joints.forEach(j=>{ if(j.sec===s) state.sel.add(j.id); }); state.view='sector'; state.facade='front'; }
hint.textContent = 'Atzīmētas visas šuves izvēlētajā kāpņu telpā (abas puses). Zīmējumā vari precizēt.';
} else if (sc==='apt'){
const v = document.getElementById('whichSec').value; state.sel.clear(); state.mode='apt';
document.querySelectorAll('.mode:not(.scope) button').forEach(x=>x.setAttribute('aria-pressed',String(x.dataset.mode==='apt')));
if (v==='endA'||v==='endB'){ state.view='end'; state.facade=v; } else { state.sector=+v; state.view='sector'; state.facade='front'; }
hint.textContent = 'Zīmējumā uzklikšķini uz sava dzīvokļa logiem — atzīmēsies šuves ap tā ārsienas paneļiem. Ja dzīvoklis ir stūra, atzīmē arī gala sienā (izvēlnē "Gals A/B").';
} else {
hint.textContent = 'Zīmējumā uzklikšķini uz kāpņu telpas vai gala un atzīmē vajadzīgās šuves pa posmiem.';
state.view='overview'; state.mode='seg';
document.querySelectorAll('.mode:not(.scope) button').forEach(x=>x.setAttribute('aria-pressed',String(x.dataset.mode==='seg')));
}
renderStage(); renderPreview(); if (typeof updateChosen==='function') updateChosen();
}
document.querySelectorAll('.mode.scope button').forEach(b=>b.addEventListener('click',()=>{ state.scope=b.dataset.scope; applyScope(); }));
document.getElementById('whichSec').addEventListener('change', ()=>applyScope());
// ------------------------------------------------------------ SOĻI (wizard)
let stepNow = 1, stepMax = 1;
function chosenText(){
const S = SERIES[state.series];
const scope = {all:'visa ēka', sec:'viena kāpņu telpa', apt:'viens dzīvoklis', custom:'pēc atzīmējuma'}[state.scope];
return `Māja: <b>${S.name}</b> · ${state.sections} kāpņu telpas · ${state.floors} stāvi${S.variants?' · '+S.variants[state.variant].label:''} · Apjoms: <b>${scope}</b>`;
}
function updateChosen(){ ['chosen1','chosen2','chosen3'].forEach(id=>{ const e=document.getElementById(id); if(e) e.innerHTML = chosenText(); }); }
function goStep(n){
n = Math.max(1, Math.min(4, n));
stepNow = n; stepMax = Math.max(stepMax, n);
document.querySelectorAll('.panel').forEach(p=>{ p.hidden = +p.dataset.step !== n; });
document.querySelectorAll('#stepper button').forEach(b=>{ const k=+b.dataset.go; b.setAttribute('aria-current', k===n?'step':'false'); b.classList.toggle('done', k<n); b.disabled = k>stepMax; });
updateChosen();
if (n===2) renderStage();
if (n===3){ renderTotals(); document.getElementById('emptyWarn').hidden = totals().sum>0; }
window.scrollTo({top:0, behavior:'smooth'});
}
document.querySelectorAll('[data-go]').forEach(b=>b.addEventListener('click',()=>goStep(+b.dataset.go)));
// interactions
let painting = null;
const svgbox = document.getElementById('svgbox');
svgbox.addEventListener('pointerdown', e=>{
const sector = e.target.closest('.sector');
if (sector){ const ds = sector.dataset.sec; if (ds==='endA'||ds==='endB'){ state.view='end'; state.facade=ds; } else { state.view='sector'; state.sector=+ds; } renderStage(); return; }
const hit = e.target.closest('.hit'); const cell = e.target.closest('.cell');
const fid = state.facade;
if (cell && state.mode==='apt'){ const ids = aptGroup(fid, +cell.dataset.c, +cell.dataset.f); if (ids){ toggleIds(ids); renderStage(); } return; }
if (hit){
const id = hit.dataset.id;
if (e.shiftKey && state.last){ const ids = rangeIds(state.last,{fid,id}); if (ids){ ids.forEach(i=>state.sel.add(i)); state.last={fid,id}; renderStage(); return; } }
painting = !state.sel.has(id); painting ? state.sel.add(id) : state.sel.delete(id); state.last = {fid,id};
updateJoint(id); renderTotals(); e.preventDefault();
}
});
svgbox.addEventListener('pointermove', e=>{
if (painting===null) return;
const t = document.elementFromPoint(e.clientX,e.clientY); const hit = t && t.closest ? t.closest('.hit') : null;
if (hit){ const id=hit.dataset.id; if (painting!==state.sel.has(id)){ painting?state.sel.add(id):state.sel.delete(id); updateJoint(id); renderTotals(); } }
});
window.addEventListener('pointerup', ()=>{ if (painting!==null){ painting=null; renderTabs(); } });
function updateJoint(id){ const l = svgbox.querySelector(`[data-line="${id}"]`); if (l) l.classList.toggle('on', state.sel.has(id)); }
document.querySelectorAll('.mode:not(.scope) button').forEach(b=>b.addEventListener('click',()=>{ state.mode=b.dataset.mode; document.querySelectorAll('.mode:not(.scope) button').forEach(x=>x.setAttribute('aria-pressed',String(x===b))); renderStage(); }));
document.getElementById('sections').addEventListener('change', e=>{ state.sections=+e.target.value; state.sel.clear(); state.view='overview'; rebuild(); });
document.getElementById('floors').addEventListener('change', e=>{ state.floors=+e.target.value; state.sel.clear(); rebuild(); });
document.getElementById('variant').addEventListener('change', e=>{ state.variant=+e.target.value; state.sel.clear(); rebuild(); });
['pWarm','pVat','fName','fPhone','fAddr','fNote'].forEach(id=>document.getElementById(id).addEventListener('input', renderTotals));
// init: 602, 4 sections, example apartment on the front of the 2nd stairwell, 5th floor
renderSeriesCards(); buildModel(); fillControls();
document.getElementById('png').addEventListener('click', downloadPNG);
document.getElementById('pdf').addEventListener('click', downloadPDF);
if (restoreFromHash()){
renderSeriesCards(); fillWhichSec(); updateChosen(); stepMax = 3; renderStage(); goStep(2);
} else {
state.sector = 1; document.getElementById('whichSec').value = '1'; applyScope();
renderStage(); goStep(1);
}
})();
</script>Cena
Fasādes hermetizācija maksā 35 € par metru atkarībā piekļuves sarežģītības. Lielākiem apjomiem (daudzdzīvokļu un komercēkām) piedāvājam atsevišķu aprēķinu pēc apsekošanas.
Kā notiek hermetizācija
Vispirms noņemam veco, sasprēgājušo hermētiķi un notīram šuvi no putekļiem un vecām apdares atliekām. Pēc tam uzklājam gruntējumu labākai saķerei un aizpildām šuvi ar elastīgu poliuretāna, kas iztur ēkas konstrukcijas kustību un temperatūras svārstības, nesaplaisājot. Augstumā strādājam ar industriālā alpīnisma virvju piekļuves tehniku — bez sastatnēm un pacēlājiem, tāpēc darbs ir ātrāks, lētāks un nebojā apkārtējo teritoriju.


Kad nepieciešama hermetizācija
Pazīmes, ka hermetizācija vairs nepieciešama: redzamas plaisas vai atlūzis vecais hermētiķis, mitruma traipi uz iekšējām sienām, caurvējš pie logu vai balkonu savienojumiem, vai arī kopš pēdējās hermetizācijas pagājuši vairāk nekā 15–20 gadi. Optimālais darba laiks ir siltajā un sausajā sezonā (aprīlis–oktobris).

Kāpēc izvēlēties mūs
Strādājam ar industriālā alpīnisma metodēm — bez sastatnēm un pacēlājiem, tāpēc netiek bojāts zāliens, apstādījumi vai bruģis, un darbs izmaksā lētāk nekā ar tradicionālo tehniku. Mūsu alpīnisti ir IRATA sertificēti profesionāļi ar vairāk nekā 10 gadu pieredzi darbā ar dažāda veida fasādēm — no paneļu mājām līdz vēsturiskām ēkām. Katram objektam sagatavojam foto atskaiti par paveikto.



Biežākie jautājumi
Cik ilgi kalpo hermetizācija?
Kvalitatīvs elastīgais hermētiķis kalpo 15–25 gadus atkarībā no materiāla un ekspluatācijas apstākļiem. Lētāki, neelastīgie materiāli sasprēgā jau pēc dažiem gadiem — tāpēc iesakām neekonomēt uz materiāla kvalitātes.
Vai strādājat arī ziemā?
Lielākā daļa hermētiķu prasa temperatūru virs +5°C sacietēšanai, tāpēc ziemā darbus veicam tikai izņēmuma gadījumos ar speciāliem zemas temperatūras materiāliem. Ieteicams plānot darbus siltajā sezonā.
Vai jums jāizmanto pacēlājs vai sastatnes?
Nē — strādājam ar virvju piekļuves (rope access) tehniku, tāpēc tiekam klāt jebkuram fasādes augstumam un sarežģītai konfigurācijai bez sastatņu celšanas.
Vai hermetizējat arī logu rāmju un balkonu savienojumus?
Jā, papildus fasādes šuvēm veicam arī logu rāmju, balkonu un dilatācijas šuvju hermetizāciju, kā arī fasādes remontdarbus, ja bojājumi jau radušies.
Cik ilgi aizņem darbs?
Vidējai daudzdzīvokļu ēkai — 1–3 dienas atkarībā no šuvju garuma un stāvokļa. Precīzu termiņu paziņojam pēc apsekošanas.
Piesaki hermetizāciju
Zvani +371 27870013 vai raksti info@alpinisti.lv — atsūti ēkas adresi un pāris bildes no šuvju stāvokļa, un vienas dienas laikā saņemsi cenu.
