diff --git a/konesaliturku/.gitignore b/konesaliturku/.gitignore new file mode 100644 index 0000000..dd50837 --- /dev/null +++ b/konesaliturku/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +*.swp +*.swo +.env diff --git a/konesaliturku/api.php b/konesaliturku/api.php new file mode 100644 index 0000000..6dba450 --- /dev/null +++ b/konesaliturku/api.php @@ -0,0 +1,126 @@ + $entries) { + $limits[$key] = array_filter($entries, fn($t) => $now - $t < $windowSeconds); + if (empty($limits[$key])) { + unset($limits[$key]); + } + } + + $count = count($limits[$ip] ?? []); + if ($count >= $maxRequests) { + return false; + } + + $limits[$ip][] = $now; + + $dir = dirname($file); + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } + file_put_contents($file, json_encode($limits)); + + return true; +} + +$action = $_GET['action'] ?? ''; + +switch ($action) { + case 'contact': + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(405); + echo json_encode(['error' => 'Method not allowed']); + exit; + } + + // Honeypot + if (!empty($_POST['website'])) { + echo json_encode(['success' => true]); + exit; + } + + // Rate limit + $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; + if (!checkRateLimit($ip)) { + http_response_code(429); + echo json_encode(['error' => 'Liian monta viestiä. Yritä myöhemmin uudelleen.']); + exit; + } + + // Validate + $name = trim($_POST['name'] ?? ''); + $company = trim($_POST['company'] ?? ''); + $email = trim($_POST['email'] ?? ''); + $phone = trim($_POST['phone'] ?? ''); + $message = trim($_POST['message'] ?? ''); + + if (!$name || !$email || !$message) { + echo json_encode(['error' => 'Täytä kaikki pakolliset kentät.']); + exit; + } + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + echo json_encode(['error' => 'Tarkista sähköpostiosoite.']); + exit; + } + + // Save to file + $contactFile = __DIR__ . '/data/contacts.json'; + $contacts = []; + if (file_exists($contactFile)) { + $contacts = json_decode(file_get_contents($contactFile), true) ?: []; + } + + $contacts[] = [ + 'id' => uniqid(), + 'name' => $name, + 'company' => $company, + 'email' => $email, + 'phone' => $phone, + 'message' => $message, + 'ip' => $ip, + 'created_at' => date('Y-m-d H:i:s') + ]; + + $dir = dirname($contactFile); + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } + file_put_contents($contactFile, json_encode($contacts, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + + // Send email + $to = 'info@konesaliturku.fi'; + $subject = 'Yhteydenotto: ' . $name . ($company ? " ($company)" : ''); + $body = "Uusi yhteydenotto konesaliturku.fi:n kautta\n\n"; + $body .= "Nimi: $name\n"; + if ($company) $body .= "Yritys: $company\n"; + $body .= "Sähköposti: $email\n"; + if ($phone) $body .= "Puhelin: $phone\n"; + $body .= "\nViesti:\n$message\n"; + + $headers = "From: noreply@konesaliturku.fi\r\n"; + $headers .= "Reply-To: $email\r\n"; + $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; + + @mail($to, $subject, $body, $headers); + + echo json_encode(['success' => true]); + break; + + default: + http_response_code(404); + echo json_encode(['error' => 'Unknown action']); + break; +} diff --git a/konesaliturku/index.html b/konesaliturku/index.html new file mode 100644 index 0000000..44ece50 --- /dev/null +++ b/konesaliturku/index.html @@ -0,0 +1,450 @@ + + + + + + Konesali Turku — Colocation & konesalipalvelut Turussa + + + + + + + + +
+
+
+

Luotettavat konesalipalvelut Turussa

+

Colocation-laitepaikkoja ammattimaisessa laitetilassa. Redundantti sähkönsyöttö, nopeat tietoliikenneyhteydet ja henkilökohtainen palvelu.

+ +
+
+ 99,9% + Käytettävyys SLA +
+
+ 24/7 + Valvonta +
+
+ 10 Gbit/s + Yhteysnopeus +
+
+
+
+
+ + +
+
+

Palvelut

+

Tarjoamme colocation-laitepaikkoja kaikenkokoisille tarpeille

+
+
+
+ + + + + +
+

1U Laitepaikka

+

Yksittäinen palvelinpaikka 42U kaapissa. Sopii pienille palvelimille ja verkkolaitteille.

+
    +
  • 1 rack unit (1U)
  • +
  • Jaettu 1 Gbit/s yhteys
  • +
  • 1x 230V sähkösyöttö
  • +
  • Rajoittamaton liikenne
  • +
+
+ +
+
+ + + + + + + + +
+

Kokokaappi (42U)

+

Kokonainen 42U kaappi omassa lukitussa tilassa. Täysi hallinta ja maksimikapasiteetti.

+
    +
  • 42 rack unitia (42U)
  • +
  • Oma 10 Gbit/s yhteys
  • +
  • 2x 230V / 32A A/B-syöttö
  • +
  • Rajoittamaton liikenne
  • +
+
+
+
+
+ + +
+
+

Miksi Konesali Turku?

+

Pienen konesalin edut isoihin ketjuihin verrattuna

+
+
+
+ + + + +
+

Paikallinen palvelu

+

Laitteesi ovat lähellä. Voit käydä konesalilla milloin vain ja tapaat aina tutun henkilökunnan.

+
+
+
+ + + +
+

Redundantti infrastruktuuri

+

Kahdennettu sähkönsyöttö, UPS-järjestelmä ja varavoimageneraattori takaavat katkeamattoman toiminnan.

+
+
+
+ + + +
+

Nopeat yhteydet

+

Moniliittymäinen tietoliikenne usealta operaattorilta. 1–10 Gbit/s porttinopeudet.

+
+
+
+ + + +
+

24/7 tuki

+

Remote hands -palvelu ja tekninen tuki ympäri vuorokauden. Ongelmatilanteissa reagoimme nopeasti.

+
+
+
+ + + +
+

Turvallisuus

+

Kulunvalvonta, kameravalvonta ja lukitut kaapit. Laitteesi ovat turvassa ympäri vuorokauden.

+
+
+
+ + + +
+

Selkeä hinnoittelu

+

Ei piilokustannuksia. Kuukausihintaan sisältyy laitepaikka, yhteys ja peruspalvelut.

+
+
+
+
+ + +
+
+

Hinnat

+

Kaikki hinnat alv 0%. Sähkö laskutetaan erikseen kulutuksen mukaan.

+
+
+
+

1U Laitepaikka

+
+ €49 + /kk +
+
+
    +
  • + + 1 rack unit (1U) +
  • +
  • + + Jaettu 1 Gbit/s +
  • +
  • + + 1x 230V sähkösyöttö +
  • +
  • + + Rajoittamaton liikenne +
  • +
  • + + 1x IPv4-osoite +
  • +
  • + + 99,9% SLA +
  • +
+ Pyydä tarjous +
+ +
+
+

Kokokaappi

+
+ €490 + /kk +
+
+
    +
  • + + 42 rack unitia (42U) +
  • +
  • + + Oma 10 Gbit/s +
  • +
  • + + 2x 230V / 32A A/B-syöttö +
  • +
  • + + Rajoittamaton liikenne +
  • +
  • + + 8x IPv4-osoitetta +
  • +
  • + + IPv6 /48 -verkko +
  • +
  • + + Remote hands sisältyy +
  • +
  • + + 99,9% SLA +
  • +
+ Pyydä tarjous +
+
+

Sähkönkulutus laskutetaan erikseen toteutuneen kulutuksen mukaan hintaan 0,25 €/kWh (alv 0%). Kaikki hinnat ovat kuukausihintoja, alv 0%. Sopimuksen minimikesto 1 kuukausi.

+
+
+ + +
+
+

Ota yhteyttä

+

Kerro tarpeistasi, niin teemme sinulle tarjouksen

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + +
+
+
+
+ + + + +
+ Osoite +

Esimerkkikatu 1
20100 Turku

+
+
+
+ + + +
+ Sähköposti +

info@konesaliturku.fi

+
+
+
+ + + +
+ Puhelin +

+358 2 123 4567

+
+
+
+ + + +
+ Aukioloajat +

Ma-Pe 8:00-17:00
Konesali 24/7

+
+
+
+
+
+
+ + + + + + + diff --git a/konesaliturku/konesali.html b/konesaliturku/konesali.html new file mode 100644 index 0000000..fd0f8a2 --- /dev/null +++ b/konesaliturku/konesali.html @@ -0,0 +1,382 @@ + + + + + + Konesali — Tekniset tiedot | Konesali Turku + + + + + + + + +
+
+

Konesalin tekniset tiedot

+

Ammattimaisesti suunniteltu ja ylläpidetty laitetila Turussa

+
+
+ + +
+
+
+
+
99,9%
+
Käytettävyys (SLA)
+
+
+
N+1
+
Redundanssi
+
+
+
24/7
+
Valvonta
+
+
+
10 Gbit/s
+
Yhteysnopeus
+
+
+
+
+ + +
+
+
+
+
+ + + +
+
+

Sähköjärjestelmät

+

Kahdennettu sähkönsyöttö varmistaa katkeamattoman toiminnan

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SähkönsyöttöKahdennettu A/B-syöttö kahdelta eri muuntajalta
UPS-järjestelmäOnline double-conversion UPS, N+1 redundantti
Akuston kapasiteettiVähintään 15 minuuttia täydellä kuormalla
VaravoimageneraattoriDieselgeneraattori, automaattinen käynnistys sähkökatkossa
Teho per kaappi2–8 kW (räätälöitävissä tarpeen mukaan)
Liitännät230V / 16A tai 32A, C13/C19 -pistokkeet
PDUMonitoroidut PDU:t (virrankulutuksen seuranta)
+
+
+
+
+ + +
+
+
+
+
+ + + +
+
+

Jäähdytys

+

Tehokas ja energiaoptimoitu jäähdytysjärjestelmä

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
JäähdytystyyppiPrecision air cooling, Cold Aisle Containment
RedundanssiN+1 jäähdytyskapasiteetti
LämpötilaTavoite 20–24 °C (ASHRAE A1 -suositus)
Ilmankosteus40–60% suhteellinen kosteus
ValvontaJatkuva lämpötila- ja kosteusseuranta, hälytykset
Free coolingUlkoilman hyödyntäminen Suomen ilmaston ansiosta
+
+
+
+
+ + +
+
+
+
+
+ + + +
+
+

Tietoliikenne

+

Moniliittymäinen verkko usealta operaattorilta

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Porttinopeudet1 Gbit/s – 10 Gbit/s (päivitettävissä 100 Gbit/s)
OperaattoritMoniliittymäinen (useampi operaattori redundanssia varten)
LiikenneRajoittamaton sisäänpäin/ulospäin
IPv41–8 osoitetta paketista riippuen (lisäosoitteet saatavilla)
IPv6/64 – /48 -verkot saatavilla
ReititysBGP-reititys, oma AS-numero saatavilla
Cross-connectSuorat yhteydet muihin operaattoreihin ja asiakkaisiin
SLA99,9% verkon käytettävyys
+
+
+
+
+ + +
+
+
+
+
+ + + +
+
+

Turvallisuus

+

Monikerroksiset turvallisuusjärjestelmät suojaavat laitteita

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
KulunvalvontaSähköinen kulunvalvonta, avainkortti + PIN-koodi
Kameravalvonta24/7 kameravalvonta sisä- ja ulkotiloissa, tallentava
PalontorjuntaAutomaattinen palonilmaisinjärjestelmä, inerttikaasu-sammutusjärjestelmä
Kaappien lukitusLukittavat 42U-kaapit, asiakaskohtaiset avaimet
HälytysjärjestelmäReaaliaikaiset hälytykset: lämpötila, kosteus, sähkö, murto
PääsylokiKaikki käynnit kirjataan ja aikaleimotaan
+
+
+
+
+ + +
+
+
+
+
+ + + +
+
+

Tilat ja kaapit

+

Ammattitason laitetila suunniteltu vaativaan käyttöön

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
SijaintiTurku, Suomi
KaapitStandardi 42U / 600mm x 1000mm serverikaapit
IlmavirtausHot Aisle / Cold Aisle -erottelu
Korotettu lattiaKorotettu lattia kaapelointia ja ilmavirtausta varten
KantavuusRiittävä raskaimmillekin palvelinratkaisuille
Pääsy24/7 pääsy konesalille etukäteisilmoituksella
+
+
+
+
+ + +
+
+

Kiinnostuitko?

+

Kerro tarpeistasi ja teemme sinulle räätälöidyn tarjouksen

+
+ Pyydä tarjous + Katso hinnat +
+
+
+ + + + + + + diff --git a/konesaliturku/script.js b/konesaliturku/script.js new file mode 100644 index 0000000..2480463 --- /dev/null +++ b/konesaliturku/script.js @@ -0,0 +1,126 @@ +document.addEventListener('DOMContentLoaded', () => { + + // === Mobile nav toggle === + const navToggle = document.getElementById('nav-toggle'); + const nav = document.getElementById('nav'); + + if (navToggle && nav) { + navToggle.addEventListener('click', () => { + nav.classList.toggle('open'); + navToggle.classList.toggle('open'); + }); + + // Close nav on link click + nav.querySelectorAll('a').forEach(link => { + link.addEventListener('click', () => { + nav.classList.remove('open'); + navToggle.classList.remove('open'); + }); + }); + } + + // === Sticky header === + const header = document.getElementById('header'); + if (header) { + window.addEventListener('scroll', () => { + header.classList.toggle('scrolled', window.scrollY > 50); + }, { passive: true }); + } + + // === Scroll animations === + const observerOptions = { + threshold: 0.1, + rootMargin: '0px 0px -50px 0px' + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + observer.unobserve(entry.target); + } + }); + }, observerOptions); + + // Add fade-in to sections + document.querySelectorAll('.service-card, .feature, .pricing-card, .contact-form, .contact-info').forEach(el => { + el.classList.add('fade-in'); + observer.observe(el); + }); + + // === Contact form === + const form = document.getElementById('contact-form'); + const formStatus = document.getElementById('form-status'); + + if (form) { + form.addEventListener('submit', async (e) => { + e.preventDefault(); + + const submitBtn = form.querySelector('.btn-submit'); + const originalText = submitBtn.textContent; + submitBtn.textContent = 'Lähetetään...'; + submitBtn.disabled = true; + + // Honeypot check + const honeypot = form.querySelector('input[name="website"]'); + if (honeypot && honeypot.value) { + formStatus.textContent = 'Kiitos viestistäsi!'; + formStatus.className = 'form-status success'; + form.reset(); + submitBtn.textContent = originalText; + submitBtn.disabled = false; + return; + } + + const formData = new FormData(form); + + try { + const response = await fetch('api.php?action=contact', { + method: 'POST', + body: formData + }); + + const data = await response.json(); + + if (data.success) { + formStatus.textContent = 'Kiitos viestistäsi! Otamme yhteyttä pian.'; + formStatus.className = 'form-status success'; + form.reset(); + } else { + formStatus.textContent = data.error || 'Viestin lähetys epäonnistui. Yritä uudelleen.'; + formStatus.className = 'form-status error'; + } + } catch { + formStatus.textContent = 'Viestin lähetys epäonnistui. Yritä uudelleen.'; + formStatus.className = 'form-status error'; + } + + submitBtn.textContent = originalText; + submitBtn.disabled = false; + }); + } + + // === Active nav link on scroll === + const sections = document.querySelectorAll('section[id]'); + const navLinks = document.querySelectorAll('.nav a[href^="#"]'); + + if (sections.length && navLinks.length) { + window.addEventListener('scroll', () => { + let current = ''; + sections.forEach(section => { + const top = section.offsetTop - 100; + if (window.scrollY >= top) { + current = section.getAttribute('id'); + } + }); + + navLinks.forEach(link => { + link.classList.remove('active'); + if (link.getAttribute('href') === '#' + current) { + link.classList.add('active'); + } + }); + }, { passive: true }); + } + +}); diff --git a/konesaliturku/server.py b/konesaliturku/server.py new file mode 100644 index 0000000..3f7f1a0 --- /dev/null +++ b/konesaliturku/server.py @@ -0,0 +1,15 @@ +import subprocess +import sys + +def main(): + try: + subprocess.run( + ["php", "-S", "localhost:3001"], + check=True + ) + except KeyboardInterrupt: + print("\nServer stopped.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/konesaliturku/style.css b/konesaliturku/style.css new file mode 100644 index 0000000..7f04cfb --- /dev/null +++ b/konesaliturku/style.css @@ -0,0 +1,970 @@ +/* === Reset & Base === */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --color-bg: #0a1628; + --color-bg-light: #0f1f3d; + --color-bg-card: #132244; + --color-primary: #1a73e8; + --color-primary-light: #4a9af5; + --color-primary-dark: #1557b0; + --color-accent: #00d4aa; + --color-text: #e2e8f0; + --color-text-muted: #94a3b8; + --color-text-heading: #f1f5f9; + --color-border: #1e3a5f; + --color-surface: #162a4a; + --color-white: #ffffff; + --font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif; + --max-width: 1200px; + --header-height: 72px; + --radius: 12px; + --radius-sm: 8px; + --shadow: 0 4px 24px rgba(0, 0, 0, 0.3); + --shadow-lg: 0 8px 48px rgba(0, 0, 0, 0.4); + --transition: 0.3s ease; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: var(--header-height); +} + +body { + font-family: var(--font-family); + background: var(--color-bg); + color: var(--color-text); + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +a { + color: var(--color-primary-light); + text-decoration: none; + transition: color var(--transition); +} + +a:hover { + color: var(--color-accent); +} + +.container { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 24px; +} + +/* === Header === */ +.header { + position: fixed; + top: 0; + left: 0; + right: 0; + height: var(--header-height); + background: rgba(10, 22, 40, 0.9); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--color-border); + z-index: 1000; + transition: background var(--transition); +} + +.header.scrolled { + background: rgba(10, 22, 40, 0.98); + box-shadow: 0 2px 20px rgba(0, 0, 0, 0.3); +} + +.header-inner { + display: flex; + align-items: center; + justify-content: space-between; + height: 100%; +} + +.logo { + display: flex; + align-items: center; + gap: 10px; + color: var(--color-white); + font-size: 1.25rem; + font-weight: 400; + letter-spacing: -0.01em; +} + +.logo:hover { + color: var(--color-white); +} + +.logo strong { + font-weight: 700; +} + +.logo-icon { + color: var(--color-primary-light); +} + +.nav { + display: flex; + gap: 32px; +} + +.nav a { + color: var(--color-text-muted); + font-size: 0.95rem; + font-weight: 500; + transition: color var(--transition); + position: relative; +} + +.nav a:hover, +.nav a.active { + color: var(--color-white); +} + +.nav a::after { + content: ''; + position: absolute; + bottom: -4px; + left: 0; + width: 0; + height: 2px; + background: var(--color-primary); + transition: width var(--transition); +} + +.nav a:hover::after { + width: 100%; +} + +.nav-toggle { + display: none; + flex-direction: column; + gap: 5px; + background: none; + border: none; + cursor: pointer; + padding: 8px; +} + +.nav-toggle span { + display: block; + width: 24px; + height: 2px; + background: var(--color-white); + transition: all var(--transition); +} + +/* === Hero === */ +.hero { + padding: 160px 0 100px; + background: linear-gradient(135deg, var(--color-bg) 0%, var(--color-bg-light) 50%, var(--color-bg) 100%); + position: relative; + overflow: hidden; +} + +.hero::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: + radial-gradient(ellipse 800px 600px at 20% 50%, rgba(26, 115, 232, 0.08) 0%, transparent 70%), + radial-gradient(ellipse 600px 400px at 80% 30%, rgba(0, 212, 170, 0.05) 0%, transparent 70%); + pointer-events: none; +} + +.hero-content { + position: relative; + max-width: 720px; +} + +.hero h1 { + font-size: clamp(2.2rem, 5vw, 3.5rem); + font-weight: 800; + line-height: 1.15; + color: var(--color-white); + margin-bottom: 20px; + letter-spacing: -0.02em; +} + +.highlight { + color: var(--color-primary-light); +} + +.hero-subtitle { + font-size: 1.2rem; + color: var(--color-text-muted); + line-height: 1.7; + margin-bottom: 36px; + max-width: 560px; +} + +.hero-actions { + display: flex; + gap: 16px; + margin-bottom: 56px; +} + +.hero-stats { + display: flex; + gap: 48px; +} + +.stat { + display: flex; + flex-direction: column; +} + +.stat-value { + font-size: 1.5rem; + font-weight: 800; + color: var(--color-white); +} + +.stat-label { + font-size: 0.85rem; + color: var(--color-text-muted); + margin-top: 4px; +} + +/* === Buttons === */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 14px 28px; + border-radius: var(--radius-sm); + font-size: 1rem; + font-weight: 600; + border: none; + cursor: pointer; + transition: all var(--transition); + text-decoration: none; +} + +.btn-primary { + background: var(--color-primary); + color: var(--color-white); +} + +.btn-primary:hover { + background: var(--color-primary-dark); + color: var(--color-white); + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(26, 115, 232, 0.4); +} + +.btn-secondary { + background: var(--color-surface); + color: var(--color-text); + border: 1px solid var(--color-border); +} + +.btn-secondary:hover { + background: var(--color-bg-card); + color: var(--color-white); + border-color: var(--color-primary); +} + +.btn-outline { + background: transparent; + color: var(--color-primary-light); + border: 2px solid var(--color-primary); +} + +.btn-outline:hover { + background: var(--color-primary); + color: var(--color-white); + transform: translateY(-2px); +} + +/* === Sections === */ +.section { + padding: 100px 0; +} + +.section-dark { + background: var(--color-bg-light); +} + +.section-title { + font-size: 2.2rem; + font-weight: 800; + color: var(--color-text-heading); + text-align: center; + margin-bottom: 12px; + letter-spacing: -0.02em; +} + +.section-subtitle { + font-size: 1.1rem; + color: var(--color-text-muted); + text-align: center; + margin-bottom: 56px; + max-width: 600px; + margin-left: auto; + margin-right: auto; +} + +/* === Services === */ +.services-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px; +} + +.service-card { + background: var(--color-bg-card); + border: 1px solid var(--color-border); + border-radius: var(--radius); + padding: 36px 28px; + transition: all var(--transition); + position: relative; +} + +.service-card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-lg); + border-color: var(--color-primary); +} + +.service-card.featured { + border-color: var(--color-primary); + background: linear-gradient(180deg, rgba(26, 115, 232, 0.08) 0%, var(--color-bg-card) 100%); +} + +.service-badge { + position: absolute; + top: -12px; + right: 20px; + background: var(--color-primary); + color: var(--color-white); + font-size: 0.8rem; + font-weight: 700; + padding: 4px 14px; + border-radius: 20px; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.service-icon { + color: var(--color-primary-light); + margin-bottom: 20px; +} + +.service-card h3 { + font-size: 1.35rem; + font-weight: 700; + color: var(--color-text-heading); + margin-bottom: 12px; +} + +.service-card p { + color: var(--color-text-muted); + margin-bottom: 20px; + font-size: 0.95rem; +} + +.service-features { + list-style: none; +} + +.service-features li { + padding: 6px 0; + color: var(--color-text); + font-size: 0.9rem; + border-bottom: 1px solid rgba(30, 58, 95, 0.5); +} + +.service-features li:last-child { + border-bottom: none; +} + +/* === Features (Miksi me) === */ +.features-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 32px; +} + +.feature { + text-align: center; + padding: 24px; +} + +.feature-icon { + color: var(--color-primary-light); + margin-bottom: 16px; + display: flex; + justify-content: center; +} + +.feature h3 { + font-size: 1.15rem; + font-weight: 700; + color: var(--color-text-heading); + margin-bottom: 10px; +} + +.feature p { + color: var(--color-text-muted); + font-size: 0.95rem; + line-height: 1.6; +} + +/* === Pricing === */ +.pricing-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px; + align-items: start; +} + +.pricing-card { + background: var(--color-bg-card); + border: 1px solid var(--color-border); + border-radius: var(--radius); + padding: 36px 28px; + text-align: center; + transition: all var(--transition); + position: relative; +} + +.pricing-card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-lg); +} + +.pricing-featured { + border-color: var(--color-primary); + background: linear-gradient(180deg, rgba(26, 115, 232, 0.1) 0%, var(--color-bg-card) 100%); + transform: scale(1.04); +} + +.pricing-featured:hover { + transform: scale(1.04) translateY(-4px); +} + +.pricing-badge { + position: absolute; + top: -12px; + left: 50%; + transform: translateX(-50%); + background: var(--color-primary); + color: var(--color-white); + font-size: 0.8rem; + font-weight: 700; + padding: 4px 18px; + border-radius: 20px; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.pricing-header h3 { + font-size: 1.3rem; + font-weight: 700; + color: var(--color-text-heading); + margin-bottom: 16px; +} + +.price { + margin-bottom: 28px; +} + +.price-amount { + font-size: 3rem; + font-weight: 800; + color: var(--color-white); + line-height: 1; +} + +.price-period { + font-size: 1.1rem; + color: var(--color-text-muted); + font-weight: 400; +} + +.pricing-features { + list-style: none; + text-align: left; + margin-bottom: 28px; +} + +.pricing-features li { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 0; + font-size: 0.95rem; + color: var(--color-text); + border-bottom: 1px solid rgba(30, 58, 95, 0.4); +} + +.pricing-features li:last-child { + border-bottom: none; +} + +.pricing-features svg { + color: var(--color-accent); + flex-shrink: 0; +} + +.pricing-note { + text-align: center; + color: var(--color-text-muted); + font-size: 0.9rem; + margin-top: 40px; + max-width: 700px; + margin-left: auto; + margin-right: auto; +} + +/* === Contact === */ +.contact-grid { + display: grid; + grid-template-columns: 1.2fr 0.8fr; + gap: 48px; + align-items: start; +} + +.contact-form { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; +} + +.form-group { + display: flex; + flex-direction: column; +} + +.form-group-full { + grid-column: 1 / -1; +} + +.form-group label { + font-size: 0.9rem; + font-weight: 600; + color: var(--color-text); + margin-bottom: 6px; +} + +.form-group input, +.form-group textarea { + background: var(--color-bg-card); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + padding: 12px 16px; + color: var(--color-text); + font-family: inherit; + font-size: 1rem; + transition: border-color var(--transition); +} + +.form-group input:focus, +.form-group textarea:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.15); +} + +.form-group textarea { + resize: vertical; + min-height: 120px; +} + +.btn-submit { + grid-column: 1 / -1; + margin-top: 4px; +} + +.form-status { + grid-column: 1 / -1; + font-size: 0.95rem; + padding: 8px 0; +} + +.form-status.success { + color: var(--color-accent); +} + +.form-status.error { + color: #f87171; +} + +.contact-info { + display: flex; + flex-direction: column; + gap: 28px; +} + +.contact-item { + display: flex; + gap: 16px; + align-items: flex-start; +} + +.contact-item svg { + color: var(--color-primary-light); + flex-shrink: 0; + margin-top: 2px; +} + +.contact-item strong { + display: block; + color: var(--color-text-heading); + font-size: 0.95rem; + margin-bottom: 4px; +} + +.contact-item p { + color: var(--color-text-muted); + font-size: 0.9rem; + line-height: 1.5; +} + +/* === Footer === */ +.footer { + background: var(--color-bg); + border-top: 1px solid var(--color-border); + padding-top: 56px; +} + +.footer-inner { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: 48px; + padding-bottom: 40px; +} + +.footer-brand .logo { + margin-bottom: 12px; +} + +.footer-brand p { + color: var(--color-text-muted); + font-size: 0.95rem; +} + +.footer-links h4 { + color: var(--color-text-heading); + font-size: 0.95rem; + font-weight: 700; + margin-bottom: 16px; +} + +.footer-links a { + display: block; + color: var(--color-text-muted); + font-size: 0.9rem; + padding: 4px 0; +} + +.footer-links a:hover { + color: var(--color-primary-light); +} + +.footer-bottom { + border-top: 1px solid var(--color-border); + padding: 20px 0; +} + +.footer-bottom p { + color: var(--color-text-muted); + font-size: 0.85rem; + text-align: center; +} + +/* === Konesali Page === */ +.page-hero { + padding: 140px 0 60px; + background: linear-gradient(135deg, var(--color-bg) 0%, var(--color-bg-light) 100%); + text-align: center; +} + +.page-hero h1 { + font-size: clamp(1.8rem, 4vw, 2.8rem); + font-weight: 800; + color: var(--color-white); + margin-bottom: 12px; + letter-spacing: -0.02em; +} + +.page-hero p { + font-size: 1.15rem; + color: var(--color-text-muted); +} + +.specs-overview { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + text-align: center; +} + +.spec-highlight { + background: var(--color-bg-card); + border: 1px solid var(--color-border); + border-radius: var(--radius); + padding: 32px 20px; +} + +.spec-highlight-value { + font-size: 2rem; + font-weight: 800; + color: var(--color-primary-light); + margin-bottom: 8px; +} + +.spec-highlight-label { + font-size: 0.9rem; + color: var(--color-text-muted); +} + +.spec-section { + max-width: 800px; + margin: 0 auto; +} + +.spec-section-header { + display: flex; + gap: 20px; + align-items: flex-start; + margin-bottom: 32px; +} + +.spec-section-icon { + color: var(--color-primary-light); + flex-shrink: 0; +} + +.spec-section-header h2 { + font-size: 1.8rem; + font-weight: 800; + color: var(--color-text-heading); + margin-bottom: 8px; +} + +.spec-section-header p { + color: var(--color-text-muted); + font-size: 1rem; +} + +.spec-table { + background: var(--color-bg-card); + border: 1px solid var(--color-border); + border-radius: var(--radius); + overflow: hidden; +} + +.spec-table table { + width: 100%; + border-collapse: collapse; +} + +.spec-table tr { + border-bottom: 1px solid var(--color-border); +} + +.spec-table tr:last-child { + border-bottom: none; +} + +.spec-table td { + padding: 16px 20px; + font-size: 0.95rem; + color: var(--color-text); + vertical-align: top; +} + +.spec-label { + font-weight: 600; + color: var(--color-text-heading); + width: 200px; + white-space: nowrap; +} + +@media (max-width: 768px) { + .specs-overview { + grid-template-columns: repeat(2, 1fr); + } + + .spec-section-header { + flex-direction: column; + align-items: center; + text-align: center; + } + + .spec-label { + width: auto; + white-space: normal; + display: block; + padding-bottom: 4px; + } + + .spec-table td { + display: block; + padding: 8px 16px; + } + + .spec-table tr { + padding: 8px 0; + } + + .spec-table td:first-child { + padding-bottom: 0; + } +} + +@media (max-width: 480px) { + .specs-overview { + grid-template-columns: 1fr 1fr; + } +} + +/* === Animations === */ +.fade-in { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* === Responsive === */ +@media (max-width: 1024px) { + .services-grid, + .pricing-grid, + .features-grid { + grid-template-columns: repeat(2, 1fr); + } + + .pricing-featured { + transform: none; + } + + .pricing-featured:hover { + transform: translateY(-4px); + } +} + +@media (max-width: 768px) { + .nav { + display: none; + position: fixed; + top: var(--header-height); + left: 0; + right: 0; + background: var(--color-bg); + flex-direction: column; + padding: 24px; + gap: 0; + border-bottom: 1px solid var(--color-border); + box-shadow: var(--shadow); + } + + .nav.open { + display: flex; + } + + .nav a { + padding: 14px 0; + border-bottom: 1px solid var(--color-border); + font-size: 1.05rem; + } + + .nav a:last-child { + border-bottom: none; + } + + .nav a::after { + display: none; + } + + .nav-toggle { + display: flex; + } + + .nav-toggle.open span:nth-child(1) { + transform: rotate(45deg) translate(5px, 5px); + } + + .nav-toggle.open span:nth-child(2) { + opacity: 0; + } + + .nav-toggle.open span:nth-child(3) { + transform: rotate(-45deg) translate(5px, -5px); + } + + .hero { + padding: 120px 0 60px; + } + + .hero h1 { + font-size: 2rem; + } + + .hero-subtitle { + font-size: 1.05rem; + } + + .hero-actions { + flex-direction: column; + gap: 12px; + } + + .hero-stats { + gap: 24px; + } + + .services-grid, + .pricing-grid, + .features-grid { + grid-template-columns: 1fr; + } + + .section { + padding: 64px 0; + } + + .section-title { + font-size: 1.75rem; + } + + .contact-grid { + grid-template-columns: 1fr; + gap: 40px; + } + + .contact-form { + grid-template-columns: 1fr; + } + + .footer-inner { + grid-template-columns: 1fr; + gap: 32px; + } +} + +@media (max-width: 480px) { + .hero-stats { + flex-direction: column; + gap: 16px; + } + + .stat { + flex-direction: row; + gap: 12px; + align-items: center; + } +}