451 lines
18 KiB
HTML
451 lines
18 KiB
HTML
{{ define "main" }}
|
||
{{ partial "page-title.html" . }}
|
||
|
||
{{/* ==== BILDER SAMMELN (Front-Matter oder Auto-Discovery) ==== */}}
|
||
{{ $photos := .Params.images }}
|
||
{{ if not $photos }}
|
||
{{ $slug := .Params.slug | default .File.TranslationBaseName }}
|
||
{{ $cands := slice
|
||
(printf "static/images/leistungen/%s1.webp" $slug)
|
||
(printf "static/images/leistungen/%s2.webp" $slug)
|
||
}}
|
||
{{ $auto := slice }}
|
||
{{ range $cands }}
|
||
{{ if fileExists . }}
|
||
{{ $auto = $auto | append (dict "src" (replace . "static" "") "alt" $slug ) }}
|
||
{{ end }}
|
||
{{ end }}
|
||
{{ $photos = $auto }}
|
||
{{ end }}
|
||
|
||
{{/* Erstes Bild für Hero, zweites fürs Ergebnis vormerken */}}
|
||
{{ $heroPhoto := cond (gt (len $photos) 0) (index $photos 0) nil }}
|
||
{{ $ergebnisPhoto := cond (gt (len $photos) 1) (index $photos 1) nil }}
|
||
{{ $.Scratch.Set "ergebnisPhoto" $ergebnisPhoto }}
|
||
|
||
<!-- ===== Inline-Styles ===== -->
|
||
<style>
|
||
.container-wide{width:100%;margin-left:auto;margin-right:auto;padding-left:16px;padding-right:16px}
|
||
@media (min-width:1200px){.container-wide{max-width:1280px}}
|
||
@media (min-width:1400px){.container-wide{max-width:1360px}}
|
||
@media (min-width:1600px){.container-wide{max-width:1440px}}
|
||
.service-hero__media{border-radius:12px;overflow:hidden;box-shadow:0 6px 30px rgba(0,0,0,.06)}
|
||
.service-hero__media img{display:block;width:100%;height:auto}
|
||
.service-hero__text p{margin-bottom:1rem}
|
||
|
||
/* USP inline unter dem Text – Icons oben, #F5A623 */
|
||
.usp-inline{display:grid;grid-template-columns:1fr;gap:12px;margin-top:20px}
|
||
@media (min-width:992px){.usp-inline{grid-template-columns:repeat(3,1fr)}}
|
||
|
||
.usp-item{
|
||
display:flex; flex-direction:column;
|
||
align-items:center; /* vorher: flex-start */
|
||
text-align:center; /* Text mittig */
|
||
gap:8px; padding:12px 14px; border-radius:12px;
|
||
background:#fff; box-shadow:0 2px 12px rgba(0,0,0,.05);
|
||
}
|
||
.usp-icon{
|
||
color:#F5A623; background:rgba(245,166,35,.12);
|
||
width:44px; height:44px; border-radius:12px;
|
||
display:flex; align-items:center; justify-content:center;
|
||
margin:0 auto 8px; /* zentriert die Iconbox */
|
||
}
|
||
|
||
.usp-icon svg{display:block;width:24px;height:24px}
|
||
.usp-text{font-weight:500;margin:0}
|
||
|
||
</style>
|
||
|
||
<!-- =========================
|
||
HERO: Bild links, Intro rechts (breit)
|
||
========================= -->
|
||
<section class="service-hero section" style="margin-top:-24px; padding-top:16px;">
|
||
<div class="container-wide">
|
||
<div class="row align-items-center gx-5">
|
||
|
||
<!-- Bild links -->
|
||
<div class="col-lg-6 order-1 order-lg-1" data-reveal>
|
||
{{ with $heroPhoto }}
|
||
<figure class="service-hero__media">
|
||
<img src='{{ .src | default . | relURL }}'
|
||
alt='{{ .alt | default $.Title }}'
|
||
width="1200" height="800"
|
||
loading="eager" decoding="async" class="img-fluid">
|
||
</figure>
|
||
{{ end }}
|
||
</div>
|
||
|
||
<!-- Intro-Text rechts + USP darunter -->
|
||
<div class="col-lg-6 order-2 order-lg-2" data-reveal>
|
||
{{ if .Content }}
|
||
<div class="service-hero__text">
|
||
{{ .Content }}
|
||
{{ with .Params.usp }}
|
||
<div class="usp-inline" role="list">
|
||
{{ range $i, $u := . }}
|
||
<div class="usp-item" role="listitem">
|
||
<div class="usp-icon" aria-hidden="true">
|
||
{{ if eq (mod $i 3) 0 }}
|
||
<!-- Shield -->
|
||
<svg viewBox="0 0 24 24" role="img" focusable="false">
|
||
<path d="M12 3l7 3v6c0 4.97-3.58 9.43-7 10-3.42-.57-7-5.03-7-10V6l7-3z" fill="currentColor" opacity=".2"/>
|
||
<path d="M12 3l7 3v6c0 4.97-3.58 9.43-7 10-3.42-.57-7-5.03-7-10V6l7-3z" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||
</svg>
|
||
{{ else if eq (mod $i 3) 1 }}
|
||
<!-- Badge -->
|
||
<svg viewBox="0 0 24 24" role="img" focusable="false">
|
||
<circle cx="12" cy="9" r="5" fill="currentColor" opacity=".2"/>
|
||
<circle cx="12" cy="9" r="5" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||
<path d="M8 14l-2 7 6-3 6 3-2-7" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
||
</svg>
|
||
{{ else }}
|
||
<!-- Target -->
|
||
<svg viewBox="0 0 24 24" role="img" focusable="false">
|
||
<circle cx="12" cy="12" r="9" fill="currentColor" opacity=".15"/>
|
||
<circle cx="12" cy="12" r="6" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||
<circle cx="12" cy="12" r="2" fill="currentColor"/>
|
||
</svg>
|
||
{{ end }}
|
||
</div>
|
||
<p class="usp-text">{{ $u }}</p>
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
<!-- =========================
|
||
FEATURES (Icon-Left, keine Cards)
|
||
Quelle: .Params.features (array of {title, text, icon?})
|
||
========================= -->
|
||
{{ with .Params.features }}
|
||
<section class="section service-features" aria-label="Leistungen">
|
||
<style>
|
||
/* ===== Scroll-Snap Carousel – local styles ===== */
|
||
.sf-wrap{--gap:16px;--card-w:86vw}
|
||
@media (min-width:640px){.sf-wrap{--card-w:68vw}}
|
||
@media (min-width:992px){.sf-wrap{--card-w:420px}}
|
||
.sf-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 12px}
|
||
.sf-title-h{margin:0}
|
||
.sf-controls{display:flex;gap:8px}
|
||
.sf-btn{
|
||
appearance:none;border:1px solid rgba(0,0,0,.12);background:#fff;
|
||
width:40px;height:40px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;
|
||
font-weight:700;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.06);transition:box-shadow .2s,transform .04s
|
||
}
|
||
.sf-btn:hover{box-shadow:0 10px 24px rgba(245,166,35,.25);background:#FDF7EC}
|
||
.sf-btn:active{transform:translateY(1px)}
|
||
.sf-viewport{
|
||
overflow:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
|
||
border-radius:14px;scrollbar-width:thin
|
||
}
|
||
.sf-viewport:focus-visible{outline:2px dashed #F5A623;outline-offset:4px}
|
||
.sf-track{display:grid;grid-auto-flow:column;grid-auto-columns:var(--card-w);gap:var(--gap);padding:2px 2px 10px}
|
||
.sf-card{
|
||
scroll-snap-align:start;background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:14px;
|
||
box-shadow:0 6px 22px rgba(0,0,0,.06);padding:16px;display:flex;gap:14px;align-items:flex-start
|
||
}
|
||
.sf-ico{
|
||
flex:0 0 44px;width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;
|
||
color:#F5A623;background:rgba(245,166,35,.12)
|
||
}
|
||
.sf-ico svg{width:22px;height:22px;display:block}
|
||
.sf-body{display:flex;flex-direction:column;gap:4px}
|
||
.sf-card h3{margin:0;font-weight:700;line-height:1.3}
|
||
.sf-card p{margin:0;opacity:.9}
|
||
/* dezente Scrollbar */
|
||
.sf-viewport::-webkit-scrollbar{height:8px}
|
||
.sf-viewport::-webkit-scrollbar-track{background:transparent}
|
||
.sf-viewport::-webkit-scrollbar-thumb{background:rgba(0,0,0,.12);border-radius:8px}
|
||
/* Drag cursor */
|
||
.sf-viewport.is-drag{cursor:grabbing;cursor:-webkit-grabbing}
|
||
</style>
|
||
|
||
<div class="container-wide">
|
||
<div class="sf-wrap">
|
||
<div class="sf-head">
|
||
<h2 class="h3 sf-title-h">Leistungen</h2>
|
||
<div class="sf-controls" aria-label="Carousel-Steuerung">
|
||
<button class="sf-btn" data-dir="-1" type="button" aria-label="Zurück">‹</button>
|
||
<button class="sf-btn" data-dir="1" type="button" aria-label="Weiter">›</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{/* Daten vorbereiten */}}
|
||
{{ $list := . }}
|
||
{{ $total := len $list }}
|
||
|
||
<div class="sf-viewport" id="sf-viewport" tabindex="0" role="region" aria-roledescription="carousel" aria-label="Leistungen Carousel">
|
||
<div class="sf-track" id="sf-track">
|
||
{{ range $i, $f := $list }}
|
||
<article class="sf-card" role="group" aria-roledescription="slide" aria-label='{{ printf "%d von %d" (add $i 1) $total }}'>
|
||
<div class="sf-ico" aria-hidden="true">
|
||
{{ $icon := $f.icon | default (printf "i-%d" (mod $i 5)) }}
|
||
{{ if or (eq $icon "pv") (eq $icon "i-0") }}
|
||
<!-- PV -->
|
||
<svg viewBox="0 0 24 24"><path d="M3 9h18v6H3z" fill="currentColor" opacity=".18"/><path d="M3 9h18v6H3M7 9v6M11 9v6M15 9v6M19 9v6" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
|
||
{{ else if or (eq $icon "speicher") (eq $icon "i-1") }}
|
||
<!-- Battery -->
|
||
<svg viewBox="0 0 24 24"><rect x="3" y="7" width="16" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="1.5"/><rect x="19" y="10" width="2" height="4" fill="currentColor"/></svg>
|
||
{{ else if or (eq $icon "lade") (eq $icon "i-2") }}
|
||
<!-- EV -->
|
||
<svg viewBox="0 0 24 24"><path d="M9 7v4a4 4 0 0 0 4 4h2v4" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M14 3v4M10 3v4M17 7h2a2 2 0 0 1 2 2v2h-4" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
|
||
{{ else if or (eq $icon "study") (eq $icon "i-3") }}
|
||
<!-- Study -->
|
||
<svg viewBox="0 0 24 24"><path d="M4 18V6m4 12V9m4 9v-6m4 6v-8m4 8V8" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
|
||
{{ else }}
|
||
<!-- Doc/Check -->
|
||
<svg viewBox="0 0 24 24"><path d="M7 3h7l5 5v11a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" fill="currentColor" opacity=".14"/><path d="M14 3v6h6M9 14l2 2 4-4" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||
{{ end }}
|
||
</div>
|
||
<div class="sf-body">
|
||
<h3 class="h5">{{ $f.title }}</h3>
|
||
{{ with $f.text }}<p>{{ . | $.Page.RenderString (dict "display" "inline") }}</p>{{ end }}
|
||
</div>
|
||
</article>
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function(){
|
||
var wrap = document.querySelector('.service-features .sf-wrap');
|
||
if(!wrap) return;
|
||
var viewport = wrap.querySelector('.sf-viewport');
|
||
var track = wrap.querySelector('.sf-track');
|
||
var btns = wrap.querySelectorAll('.sf-btn');
|
||
|
||
function cardStep(){
|
||
var gap = parseFloat(getComputedStyle(track).gap) || 16;
|
||
var card = track.querySelector('.sf-card');
|
||
return card ? card.getBoundingClientRect().width + gap : 320;
|
||
}
|
||
|
||
btns.forEach(function(b){
|
||
b.addEventListener('click', function(){
|
||
var dir = this.getAttribute('data-dir') === '1' ? 1 : -1;
|
||
viewport.scrollBy({left: cardStep() * dir, behavior: 'smooth'});
|
||
});
|
||
});
|
||
|
||
// Keyboard navigation
|
||
viewport.addEventListener('keydown', function(e){
|
||
if(e.key === 'ArrowRight'){ viewport.scrollBy({left: cardStep(), behavior:'smooth'}); }
|
||
if(e.key === 'ArrowLeft'){ viewport.scrollBy({left:-cardStep(), behavior:'smooth'}); }
|
||
});
|
||
|
||
// Drag to scroll (desktop)
|
||
var down=false, startX=0, sl=0;
|
||
viewport.addEventListener('mousedown', function(e){ down=true; viewport.classList.add('is-drag'); startX=e.pageX; sl=viewport.scrollLeft; });
|
||
window.addEventListener('mouseup', function(){ down=false; viewport.classList.remove('is-drag'); });
|
||
viewport.addEventListener('mousemove', function(e){ if(!down) return; e.preventDefault(); viewport.scrollLeft = sl - (e.pageX - startX); });
|
||
})();
|
||
</script>
|
||
</section>
|
||
{{ end }}
|
||
|
||
|
||
|
||
|
||
<!-- =========================
|
||
OUTCOMES (Nutzen/Ergebnisse)
|
||
Quelle: .Params.outcomes (array of strings)
|
||
========================= -->
|
||
{{ with .Params.outcomes }}
|
||
<section class="service-outcomes section" aria-label="Ergebnis & Mehrwert">
|
||
<style>
|
||
.out-row{align-items:center}
|
||
.out-media{border-radius:12px;overflow:hidden;box-shadow:0 6px 30px rgba(0,0,0,.06)}
|
||
.out-media img{display:block;width:100%;height:auto}
|
||
.checklist{list-style:none;padding:0;margin:0;display:grid;gap:12px}
|
||
.checklist li{display:flex;gap:10px;align-items:flex-start}
|
||
.checklist .check{flex:0 0 22px;color:#0AA8A7;margin-top:2px}
|
||
</style>
|
||
|
||
<div class="container-wide" >
|
||
<div class="row out-row gx-5">
|
||
|
||
<!-- Text links -->
|
||
<div class="col-lg-6" data-reveal>
|
||
<h3 class="mb-3">Ergebnis & Mehrwert</h3>
|
||
<ul class="checklist">
|
||
{{ range . }}
|
||
<li data-reveal>
|
||
<svg class="check" viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
|
||
<path d="M20 6L9 17l-5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||
</svg>
|
||
<span>{{ . }}</span>
|
||
</li>
|
||
{{ end }}
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Bild rechts (nimmt das 2. Bild aus dem Hero-Setup) -->
|
||
<div class="col-lg-6" data-reveal>
|
||
{{ $erg := $.Scratch.Get "ergebnisPhoto" }}
|
||
{{ with $erg }}
|
||
<figure class="out-media">
|
||
<img src='{{ .src | relURL }}' alt='{{ .alt | default $.Title }}'
|
||
width="1200" height="800" loading="lazy" decoding="async">
|
||
</figure>
|
||
{{ else }}
|
||
{{ with $heroPhoto }}
|
||
<figure class="out-media">
|
||
<img src='{{ .src | relURL }}' alt='{{ .alt | default $.Title }}'
|
||
width="1200" height="800" loading="lazy" decoding="async">
|
||
</figure>
|
||
{{ end }}
|
||
{{ end }}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
{{ end }}
|
||
|
||
|
||
<!-- =========================
|
||
CTA (animierter Hintergrund wie auf Index),
|
||
aber: TEXT/Buttons aus Front-Matter binden.
|
||
========================= -->
|
||
{{ $impressum := site.GetPage "page" "impressum" }}
|
||
{{ $ctaEnabled := or (.Params.cta.enable) (or .Params.cta_text .Params.cta_label) }}
|
||
{{ if $ctaEnabled }}
|
||
<section id="cta" class="cta">
|
||
<!-- Animierter Hintergrund (DEIN bestehendes Markup) -->
|
||
<div class="cta__bg" aria-hidden="true">
|
||
<div class="cta__grid"></div>
|
||
<div class="cta__energy-lines">
|
||
<div class="energy-line-h energy-line-h2"></div>
|
||
<div class="energy-line-h energy-line-h3"></div>
|
||
<div class="energy-line-v energy-line-v1"></div>
|
||
<div class="energy-line-v energy-line-v2"></div>
|
||
<div class="energy-node energy-node1"></div>
|
||
<div class="energy-node energy-node2"></div>
|
||
</div>
|
||
<div class="cta__gradient-top"></div>
|
||
<div class="cta__gradient-bottom"></div>
|
||
</div>
|
||
|
||
<!-- Inhalt: jetzt dynamisch aus Front-Matter -->
|
||
<div class="my-container">
|
||
<div class="cta__wrap" data-reveal>
|
||
<h3 class="cta__title">
|
||
{{ .Params.cta_text | default "Lassen Sie uns Ihre Vision mit unserer Expertise zur Realität machen." }}
|
||
</h3>
|
||
|
||
{{/* Optional: Bei Bedarf zweite Zeile aus subtitle wiederverwenden */}}
|
||
{{ with .Params.subtitle }}
|
||
<p class="cta__lead">{{ . }}</p>
|
||
{{ end }}
|
||
|
||
<div class="cta__actions">
|
||
{{ with .Params.cta_label }}
|
||
<a class="cta__btn" href="{{ $.Params.cta_href | default "/contact/" }}">
|
||
<span aria-hidden="true">⚡</span><span>{{ . }}</span>
|
||
</a>
|
||
{{ end }}
|
||
</div>
|
||
|
||
|
||
{{/* Fallback/Ergänzung: direkte Kontaktwege aus Impressum */}}
|
||
{{ if $impressum }}
|
||
<a class="cta__btn" href="mailto:{{ $impressum.Params.email }}">
|
||
<span aria-hidden="true">✉️</span><span>E-Mail senden</span>
|
||
</a>
|
||
<a class="cta__btn" href="tel:{{ $impressum.Params.telefon }}">
|
||
<span aria-hidden="true">📞</span><span>Anrufen</span>
|
||
</a>
|
||
{{ end }}
|
||
</div>
|
||
|
||
<div class="cta__social">
|
||
<a class="cta__social-link" href="https://www.instagram.com/amperion.at/" target="_blank" rel="noopener" aria-label="Instagram">
|
||
<img src="/images/social/instagram.svg" alt="">
|
||
</a>
|
||
<a class="cta__social-link" href="https://www.linkedin.com/company/amperion-gmbh/" target="_blank" rel="noopener" aria-label="LinkedIn">
|
||
<img src="/images/social/linkedin.svg" alt="">
|
||
</a>
|
||
<a class="cta__social-link" href="https://www.facebook.com/share/1CZ7xm6cdw/?mibextid=wwXIfr" target="_blank" rel="noopener" aria-label="Facebook">
|
||
<img src="/images/social/facebook.svg" alt="">
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
{{ end }}
|
||
|
||
<!-- =========================
|
||
Micro-Animationen (IntersectionObserver)
|
||
- fügt 'is-visible' hinzu, wenn Elemente ins Viewport kommen
|
||
========================= -->
|
||
<script>
|
||
(function(){
|
||
if (window.__serviceRevealInit) return; // vermeiden, dass mehrfach registriert wird
|
||
window.__serviceRevealInit = true;
|
||
|
||
var els = document.querySelectorAll("[data-reveal]");
|
||
if (!('IntersectionObserver' in window) || !els.length) {
|
||
els.forEach(function(el){ el.classList.add('is-visible'); });
|
||
return;
|
||
}
|
||
var io = new IntersectionObserver(function(entries){
|
||
entries.forEach(function(entry){
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add('is-visible');
|
||
io.unobserve(entry.target);
|
||
}
|
||
});
|
||
}, { threshold: 0.12 });
|
||
|
||
els.forEach(function(el){ io.observe(el); });
|
||
})();
|
||
</script>
|
||
|
||
<!-- =========================
|
||
Minimal CSS-Hooks (optional, an deine SCSS anpassen)
|
||
========================= -->
|
||
<style>
|
||
/* Typo hooks */
|
||
.kicker{letter-spacing:.08em;text-transform:uppercase;opacity:.85;margin-bottom:.25rem}
|
||
.lead{opacity:.9}
|
||
|
||
/* Media items (icon-left) */
|
||
.media-item{display:flex;gap:.9rem;align-items:flex-start}
|
||
.media-item .media-icon{flex:0 0 auto;line-height:0;opacity:.9}
|
||
.media-item .media-body{flex:1}
|
||
|
||
/* Features grid spacing */
|
||
.service-features .feature{padding:14px 8px;border-radius:12px;transition:transform .25s ease, box-shadow .25s ease}
|
||
.service-features .feature:hover{transform:translateY(-2px);box-shadow:0 6px 24px rgba(0,0,0,.06)}
|
||
|
||
/* Outcomes checklist */
|
||
.checklist{list-style:none;padding:0;margin:0}
|
||
.checklist li{display:flex;gap:.6rem;align-items:flex-start;margin:.5rem 0}
|
||
.checklist .check{color:#F5A623; margin-top:.2rem}
|
||
|
||
/* Reveal animation */
|
||
[data-reveal]{opacity:0;transform:translateY(12px);transition:opacity .5s ease, transform .5s ease}
|
||
[data-reveal].is-visible{opacity:1;transform:none}
|
||
|
||
.service-photo{border-radius:12px;overflow:hidden}
|
||
.service-photo img{display:block;width:100%;height:auto}
|
||
|
||
.service-hero__media{border-radius:12px;overflow:hidden;box-shadow:0 6px 30px rgba(0,0,0,.06)}
|
||
.service-hero__media img{display:block;width:100%;height:auto}
|
||
.service-hero__text p{margin-bottom:1rem}
|
||
|
||
|
||
|
||
</style>
|
||
|
||
{{ end }}
|