// shared.jsx — shared icons, data, helpers

const Icon = {
  arrow: (props) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M5 12h14M13 5l7 7-7 7"/></svg>,
  check: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M20 6L9 17l-5-5"/></svg>,
  menu: (props) => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...props}><path d="M3 6h18M3 12h18M3 18h18"/></svg>,
  close: (props) => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...props}><path d="M18 6L6 18M6 6l12 12"/></svg>,
  mail: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg>,
  phone: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>,
  pin: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>,
  spark: (props) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M12 3v3M12 18v3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M3 12h3M18 12h3M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/></svg>,
  shield: (props) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>,
  bolt: (props) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}><path d="M13 2L3 14h7l-1 8 10-12h-7l1-8z"/></svg>,
  linkedin: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" {...props}><path d="M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM8.34 17H5.67V9.67h2.67V17zm-1.33-8.34a1.55 1.55 0 1 1 0-3.1 1.55 1.55 0 0 1 0 3.1zM18.34 17h-2.67v-3.66c0-1-.36-1.67-1.27-1.67-.69 0-1.1.46-1.28.91-.07.16-.08.39-.08.62V17H10.4s.04-6.95 0-7.33h2.66v1.04c.36-.55.99-1.34 2.4-1.34 1.75 0 3.06 1.14 3.06 3.6V17z"/></svg>,
  facebook: (props) => <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" {...props}><path d="M22 12a10 10 0 1 0-11.56 9.88V14.9H7.9V12h2.55V9.8c0-2.52 1.5-3.91 3.78-3.91 1.1 0 2.24.2 2.24.2v2.46H15.2c-1.24 0-1.63.77-1.63 1.56V12h2.78l-.45 2.9h-2.33v6.98A10 10 0 0 0 22 12z"/></svg>,
};

const SERVICES = [
  {
    slug: 'it-consulting',
    icon: 'assets/service-icon-consulting.png',
    title: 'IT Consulting & Planning',
    blurb: 'Strategic technology roadmaps that align IT spend with business outcomes.',
    long: 'We help leadership teams cut through technology noise — auditing what you have, identifying what you need, and building a clear, costed roadmap. From software stack reviews to vendor consolidation, we turn IT from a cost centre into a growth lever.',
    bullets: [
      ['Technology audits', 'Full inventory of your stack, with savings and risk flagged in plain English.'],
      ['Roadmap & budgeting', 'A 12\u201324 month plan tied to your commercial goals \u2014 not just trend-chasing.'],
      ['Vendor management', 'We manage the vendors so you do not have to.'],
      ['Compliance readiness', 'GDPR, GFSC, and industry-specific guidance for Gibraltar businesses.'],
    ],
  },
  {
    slug: 'network-infrastructure',
    icon: 'assets/service-icon-network.png',
    title: 'Network & Infrastructure',
    blurb: 'Resilient networks designed to scale \u2014 fibre, Wi-Fi, VPN, and switching.',
    long: 'Whether you are wiring a new office or hardening a multi-site network, we design, deploy and manage the infrastructure your business runs on. We favour clean, well-documented installs that future-you will thank present-you for.',
    bullets: [
      ['Office cabling & switching', 'Cat6/fibre runs, structured cabinets, labelled and documented.'],
      ['Enterprise Wi-Fi', 'Coverage maps, seamless roaming, and segmented guest networks.'],
      ['Site-to-site VPN', 'Secure links between branches, remote teams, and the cloud.'],
      ['24/7 monitoring', 'We see issues before your team does.'],
    ],
  },
  {
    slug: 'data-backup-recovery',
    icon: 'assets/service-icon-backup.png',
    title: 'Data Backup & Recovery',
    blurb: 'The 3-2-1 strategy, automated \u2014 so a bad day stays a small day.',
    long: 'Backups only matter when you need them. We build immutable, off-site, regularly-tested backup systems using Veeam, Wasabi and DropSuite \u2014 and run real recovery drills, not just green ticks on a dashboard.',
    bullets: [
      ['Immutable backups', 'Ransomware-resistant snapshots that cannot be tampered with.'],
      ['Off-site replication', 'Geographically separate copies via Wasabi cloud storage.'],
      ['Microsoft 365 backup', 'DropSuite-powered backup of mail, OneDrive and SharePoint.'],
      ['Quarterly recovery drills', 'We test the restore, not just the backup.'],
    ],
  },
  {
    slug: 'it-support',
    icon: 'assets/service-icon-support.png',
    title: 'IT Support & Troubleshooting',
    blurb: 'A real human on the line \u2014 fast, friendly, and rarely surprised.',
    long: 'Our managed support service replaces the ticket-and-wait dance with a small, named team that knows your environment. Average first response under 12 minutes during business hours. After-hours cover available.',
    bullets: [
      ['Named engineers', 'You will not be re-introducing your setup every call.'],
      ['SLA-backed response', '<12 min business hours, <60 min after hours.'],
      ['Remote & on-site', 'In Gibraltar we are minutes away. Elsewhere, we screen-share.'],
      ['Onboarding & offboarding', 'New starters productive on day one. Leavers fully revoked.'],
    ],
  },
  {
    slug: 'cloud-solutions',
    icon: 'assets/service-icon-cloud.png',
    title: 'Cloud Solutions',
    blurb: 'Migrations and modernisation that finish on time and on budget.',
    long: 'We move workloads to Microsoft 365, Azure and private cloud platforms with zero drama. From email cutover at 02:00 on a Sunday to multi-year app modernisation, we plan it, run it, and document it.',
    bullets: [
      ['Microsoft 365 migrations', 'From any platform \u2014 including legacy on-prem Exchange.'],
      ['Azure landing zones', 'Identity, networking and policy done right from day one.'],
      ['Cost optimisation', 'Right-sized resources, reserved capacity, no surprise bills.'],
      ['Hybrid setups', 'Cloud where it makes sense, on-prem where it does not.'],
    ],
  },
  {
    slug: 'cybersecurity',
    icon: 'assets/service-icon-security.png',
    title: 'Cybersecurity Services',
    blurb: 'Layered defence \u2014 endpoint, email, identity, and humans.',
    long: 'We deploy and manage SentinelOne, Sophos, Huntress and Microsoft Defender across your estate, then layer on phishing simulations and policy work. Security is a process, not a product \u2014 and we run the process.',
    bullets: [
      ['Managed EDR', 'SentinelOne and Huntress monitored 24/7 by humans.'],
      ['Email & DNS protection', 'Sophos email gateway, DMARC, and safe-link rewriting.'],
      ['Identity hardening', 'Conditional access, MFA, and least-privilege reviews.'],
      ['Phishing simulations', 'Quarterly tests with bite-sized training for slips.'],
    ],
  },
  {
    slug: 'web-development-design',
    icon: 'assets/service-icon-webdev.svg',
    title: 'Website Development & Design',
    blurb: 'Fast, modern websites that look sharp, rank well, and actually convert.',
    long: 'Your website is your hardest-working salesperson \u2014 it should look the part. We design and build clean, responsive websites tailored to Gibraltar businesses. No bloated templates, no monthly page-builder fees \u2014 just fast, professional sites you actually own, backed by ongoing support when you need it.',
    bullets: [
      ['Custom design', 'Bespoke layouts built around your brand \u2014 not a theme with your logo swapped in.'],
      ['Mobile-first & fast', 'Responsive across every device, optimised for speed and Core Web Vitals.'],
      ['SEO foundations', 'Proper structure, meta data, schema markup, and Google Business integration from day one.'],
      ['Hosting & maintenance', 'We handle domains, SSL, updates and backups so you can focus on running your business.'],
    ],
  },
  {
    slug: 'business-consultancy',
    icon: 'assets/service-icon-consultancy.svg',
    title: 'Business Consultancy',
    blurb: 'Practical advice that turns operational friction into measurable growth.',
    long: 'Technology is only half the picture. We work alongside leadership teams to streamline operations, tighten processes, and identify where the right tool \u2014 or the right change in workflow \u2014 unlocks real commercial value. No jargon-heavy slide decks, just honest, actionable guidance from people who understand how Gibraltar businesses actually run.',
    bullets: [
      ['Process & workflow review', 'We map how your team really works, spot the bottlenecks, and redesign for speed and clarity.'],
      ['Digital transformation', 'Practical automation and tooling that saves hours per week \u2014 not a buzzword exercise.'],
      ['Growth & scaling strategy', 'Capacity planning, market-readiness assessments, and the operational foundations to scale with confidence.'],
      ['Vendor & contract advisory', 'Independent guidance on software, telecoms, and service contracts so you never overpay or under-specify.'],
    ],
  },
  {
    slug: 'microsoft-365',
    icon: 'assets/service-icon-365.svg',
    title: 'Microsoft 365 Administration',
    blurb: 'Expert management of your entire Microsoft 365 ecosystem \u2014 Exchange, Teams, SharePoint and beyond.',
    long: 'Microsoft 365 is the backbone of most modern businesses, but getting real value from it takes more than buying licences. We configure, secure, and manage your entire tenant \u2014 from Exchange Online and Teams to SharePoint, Intune, and Entra ID \u2014 so every user, device, and policy works exactly as it should.',
    bullets: [
      ['Tenant setup & optimisation', 'Clean tenant configuration, licence right-sizing, and domain management so you only pay for what you use.'],
      ['Exchange & email management', 'Mailbox provisioning, shared mailboxes, distribution groups, mail flow rules, and spam filtering tuned to your business.'],
      ['Teams & SharePoint', 'Channel architecture, permissions, external sharing policies, and document libraries structured for how your team actually collaborates.'],
      ['Entra ID & Intune', 'Identity governance, conditional access policies, MFA enforcement, and device management to keep every endpoint compliant and secure.'],
    ],
  },
];

const PARTNERS = [
  { src: 'assets/partner-sentinelone.png', alt: 'SentinelOne' },
  { src: 'assets/partner-veeam.png', alt: 'Veeam' },
  { src: 'assets/partner-sophos.png', alt: 'Sophos' },
  { src: 'assets/partner-dropsuite.png', alt: 'DropSuite' },
  { src: 'assets/partner-365.png', alt: 'Microsoft 365' },
  { src: 'assets/partner-wasabi.png', alt: 'Wasabi' },
  // Huntress placeholder — text chip rendered in PartnerStrip when no image
  { text: 'HUNTRESS', alt: 'Huntress' },
];

const POSTS = [
  {
    slug: 'why-it-support-matters',
    title: 'Why IT Support Matters: Keeping Your Business Running Smoothly',
    category: 'IT Support',
    date: 'March 12, 2026',
    img: 'assets/blog-itsupport.jpg',
    excerpt: 'In a world where a 30-minute outage can cost a small business thousands, reliable IT support is no longer a nice-to-have. Here is what good support actually looks like.',
  },
  {
    slug: 'emergency-it-response',
    title: 'When Things Break: A Calm Guide to IT Emergencies',
    category: 'Operations',
    date: 'February 28, 2026',
    img: 'assets/blog-emergency.jpg',
    excerpt: 'Every business will face an IT emergency eventually. The difference between a minor blip and a catastrophe is preparation. We share the playbook we run for our clients.',
  },
  {
    slug: 'cloud-migration-checklist',
    title: 'The Cloud Migration Checklist We Wish Existed in 2018',
    category: 'Cloud',
    date: 'February 14, 2026',
    img: 'assets/hero-cloud.jpg',
    excerpt: 'Eight years and countless migrations later, here is the practical, no-buzzwords checklist we run before, during, and after every cloud move.',
  },
  {
    slug: 'phishing-evolved',
    title: 'Phishing Has Evolved. Has Your Training?',
    category: 'Cybersecurity',
    date: 'January 30, 2026',
    img: 'assets/about-secure.jpg',
    excerpt: 'AI-generated phishing is here, and it is convincing. Why annual training is no longer enough \u2014 and what to do instead.',
  },
];

window.Icon = Icon;
window.SERVICES = SERVICES;
window.PARTNERS = PARTNERS;
window.POSTS = POSTS;

// CMS data loader — fetches JSON from /data/ and overrides hardcoded arrays
// Falls back to hardcoded data if fetch fails (e.g. local development without PHP)
const CmsContext = React.createContext({ posts: POSTS, partners: PARTNERS, testimonials: [] });

function CmsProvider({ children }) {
  const [posts, setPosts] = React.useState(POSTS);
  const [partners, setPartners] = React.useState(PARTNERS);
  const [testimonials, setTestimonials] = React.useState([]);
  const [loaded, setLoaded] = React.useState(false);

  React.useEffect(() => {
    Promise.all([
      fetch('data/posts.json').then(r => r.ok ? r.json() : null).catch(() => null),
      fetch('data/partners.json').then(r => r.ok ? r.json() : null).catch(() => null),
      fetch('data/testimonials.json').then(r => r.ok ? r.json() : null).catch(() => null),
    ]).then(([p, pa, t]) => {
      if (p && p.length) { setPosts(p); window.POSTS = p; }
      if (pa && pa.length) { setPartners(pa); window.PARTNERS = pa; }
      if (t && t.length) setTestimonials(t);
      setLoaded(true);
    });
  }, []);

  return (
    <CmsContext.Provider value={{ posts, partners, testimonials, loaded }}>
      {children}
    </CmsContext.Provider>
  );
}

function useCms() { return React.useContext(CmsContext); }
window.CmsProvider = CmsProvider;
window.useCms = useCms;

// Scroll-reveal hook
function useReveal() {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          obs.unobserve(e.target);
        }
      });
    }, { threshold: 0.12 });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);
  return ref;
}
window.useReveal = useReveal;

// SEO hook — updates document title and meta description per route
function useSEO(title, description) {
  React.useEffect(() => {
    const suffix = ' — CloudWise';
    document.title = title ? title + suffix : 'CloudWise — Smart, Secure, Scalable IT for Gibraltar';
    const meta = document.querySelector('meta[name="description"]');
    if (meta && description) meta.setAttribute('content', description);
  }, [title, description]);
}
window.useSEO = useSEO;

// Formspree — replace with your real form ID from https://formspree.io
const FORMSPREE_ID = 'xdayjyva';
const FORMSPREE_URL = 'https://formspree.io/f/' + FORMSPREE_ID;

async function submitToFormspree(formData) {
  const data = {};
  formData.forEach((value, key) => { data[key] = value; });
  const res = await fetch(FORMSPREE_URL, {
    method: 'POST',
    headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!res.ok) throw new Error('Form submission failed');
  return res.json();
}
window.submitToFormspree = submitToFormspree;