{"id":3993,"date":"2026-07-20T00:33:26","date_gmt":"2026-07-20T00:33:26","guid":{"rendered":"https:\/\/bosonsystems.store\/?page_id=3993"},"modified":"2026-08-18T01:48:37","modified_gmt":"2026-08-18T01:48:37","slug":"omni","status":"publish","type":"page","link":"https:\/\/bosonsystems.store\/fr\/omni\/","title":{"rendered":"Proton Omni"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"3993\" class=\"elementor elementor-3993\" data-elementor-post-type=\"page\">\n\t\t\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-5680dd5 e-con-full video-scroll-section e-flex e-con e-parent\" data-id=\"5680dd5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-da1c8e3 elementor-widget elementor-widget-html\" data-id=\"da1c8e3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section class=\"proton-mobile-features\">\r\n  <div class=\"proton-mobile-hero\">\r\n    <div class=\"proton-mobile-hero__content\">\r\n      <h2 class=\"proton-mobile-hero__title\">Introducing Proton Omni<\/h2>\r\n    <\/div>\r\n\r\n    <img data-recalc-dims=\"1\" decoding=\"async\"\r\n      class=\"proton-mobile-hero__image\"\r\n      src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/omni-features-v2_0000.webp?w=800&#038;ssl=1\"\r\n      srcset=\"\"\r\n      sizes=\"100vw\"\r\n      alt=\"Proton Omni\"\r\n    >\r\n  <\/div>\r\n\r\n  <div class=\"proton-mobile-features__grid\">\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/ecosystem.webp?w=800&#038;ssl=1\" alt=\"Proton ecosystem\">\r\n      <div>\r\n        <span>01<\/span>\r\n        <h3>Modularity<\/h3>\r\n        <p>The Proton Omni bridge is fully compatible with all Proton Optical Pods. Standard PVS, 16mm, thermal and more.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/fliponoff.webp?w=800&#038;ssl=1\" alt=\"Independent flip on off\">\r\n      <div>\r\n        <span>02<\/span>\r\n        <h3>Independent flip on\/off<\/h3>\r\n        <p>Each pod can be flipped on or off independently and turns off when out of the way.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/fischer.webp?w=800&#038;ssl=1\" alt=\"Electron 4-pin Fischer Port\">\r\n      <div>\r\n        <span>03<\/span>\r\n        <h3>Electron 4-pin Fischer Port<\/h3>\r\n        <p>Connect external battery packs and powering solutions through the integrated Fischer interface.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/rotaryknob.png?w=800&#038;ssl=1\" alt=\"Dual function rotary knob\">\r\n      <div>\r\n        <span>04<\/span>\r\n        <h3>Dual function rotary knob<\/h3>\r\n        <p>Fine tactile adjustment for manual gain or IR illuminator power.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/illuminator.png?w=800&#038;ssl=1\" alt=\"IR illuminator\">\r\n      <div>\r\n        <span>05<\/span>\r\n        <h3>VCSEL illuminator<\/h3>\r\n        <p>Integrated adjustable VCSEL illumination for low-light and no-light environments.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n\r\n    <article class=\"proton-mobile-feature\">\r\n      <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/batteries.webp?w=800&#038;ssl=1\" alt=\"Multiple battery compatibility\">\r\n      <div>\r\n        <span>06<\/span>\r\n        <h3>Multiple battery compatibility<\/h3>\r\n        <p>Support for CR123A, AA and future power configurations.<\/p>\r\n      <\/div>\r\n    <\/article>\r\n  <\/div>\r\n<\/section>\r\n\r\n<style>\r\n.proton-mobile-features {\r\n  display: none;\r\n}\r\n\r\n@media (max-width: 767px) {\r\n  .proton-mobile-features {\r\n    width: 100vw !important;\r\n    max-width: 100vw !important;\r\n    margin-left: calc(50% - 50vw) !important;\r\n    margin-right: calc(50% - 50vw) !important;\r\n    display: block !important;\r\n    overflow: hidden;\r\n    background: #000;\r\n    color: #fff;\r\n    font-family: Helvetica, Arial, sans-serif;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  .proton-mobile-hero {\r\n    position: relative;\r\n    width: 100vw;\r\n    height: 88vh;\r\n    min-height: 620px;\r\n    overflow: hidden;\r\n    background: #000;\r\n  }\r\n\r\n  .proton-mobile-hero__content {\r\n    position: absolute;\r\n    left: 0;\r\n    right: 0;\r\n    top: 92px;\r\n    z-index: 2;\r\n    width: 100%;\r\n    padding: 0 18px;\r\n    box-sizing: border-box;\r\n    text-align: center;\r\n  }\r\n\r\n  .proton-mobile-hero__title {\r\n    margin: 0 auto;\r\n    max-width: 420px;\r\n    font-size: clamp(42px, 12vw, 62px);\r\n    line-height: 0.92;\r\n    font-weight: 700;\r\n    letter-spacing: 0;\r\n    text-align: center;\r\n    color: #fff;\r\n  }\r\n\r\n  .proton-mobile-hero__image {\r\n    position: absolute;\r\n    left: 50%;\r\n    top: 58%;\r\n    width: 200vw;\r\n    max-width: none !important;\r\n    height: auto;\r\n    display: block;\r\n    transform: translate(-50%, -50%);\r\n    object-fit: contain;\r\n    filter: brightness(0.98) saturate(0.94) contrast(1.04);\r\n  }\r\n\r\n  .proton-mobile-features__grid {\r\n    display: grid;\r\n    grid-template-columns: 1fr;\r\n    gap: 10px;\r\n    padding: 10px;\r\n    background: #000;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n.proton-mobile-feature {\r\n  position: relative;\r\n  min-height: 390px;\r\n  aspect-ratio: 1 \/ 1;\r\n  display: flex;\r\n  align-items: flex-end;\r\n  overflow: hidden;\r\n  background: #080808;\r\n  color: #fff;\r\n}\r\n\r\n.proton-mobile-feature img {\r\n  position: absolute;\r\n  inset: 0;\r\n  width: 100%;\r\n  height: 100%;\r\n  object-fit: cover;\r\n  object-position: center;\r\n}\r\n\r\n  .proton-mobile-feature::after {\r\n    content: \"\";\r\n    position: absolute;\r\n    inset: 0;\r\n    background:\r\n      linear-gradient(to top, rgba(0, 0, 0, 0.86), rgba(0, 0, 0, 0.18) 62%),\r\n      rgba(0, 0, 0, 0.08);\r\n  }\r\n\r\n  .proton-mobile-feature > div {\r\n    position: relative;\r\n    z-index: 2;\r\n    width: 100%;\r\n    padding: 24px;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  .proton-mobile-feature span {\r\n    display: block;\r\n    margin-bottom: 14px;\r\n    font-size: 12px;\r\n    line-height: 1;\r\n    font-weight: 700;\r\n    letter-spacing: 0.08em;\r\n    color: rgba(255, 255, 255, 0.52);\r\n  }\r\n\r\n  .proton-mobile-feature h3 {\r\n    margin: 0 0 12px;\r\n    font-size: clamp(30px, 9vw, 44px);\r\n    line-height: 0.98;\r\n    font-weight: 700;\r\n    letter-spacing: 0;\r\n    color: #fff;\r\n  }\r\n\r\n  .proton-mobile-feature p {\r\n    margin: 0;\r\n    font-size: 15px;\r\n    line-height: 1.35;\r\n    font-weight: 400;\r\n    color: rgba(255, 255, 255, 0.74);\r\n  }\r\n}\r\n\r\n@media (max-width: 420px) {\r\n  .proton-mobile-feature {\r\n    min-height: 400px;\r\n    aspect-ratio: 4 \/ 5;\r\n  }\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-aa22a62 sticky-stage e-flex e-con-boxed e-con e-child\" data-id=\"aa22a62\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fc19187 elementor-widget elementor-widget-html\" data-id=\"fc19187\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div class=\"scroll-title\" data-start-time=\"0:00:00:00\" data-end-time=\"0:00:01:00\">\r\n  <h2>Introducing Proton Omni<\/h2>\r\n<\/div>\r\n\r\n<div class=\"video-annotations\">\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:02:25\"\r\n    data-end-time=\"0:00:03:25\"\r\n    data-x=\"55\"\r\n    data-y=\"65\"\r\n    data-offset-x=\"350\"\r\n    data-offset-y=\"0\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>Modularity<\/h3>\r\n      <p>The Proton Omni bridge is fully compatible with all Proton Optical Pods. Standard PVS, 16mm, thermal and more.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:06:20\"\r\n    data-end-time=\"0:00:07:20\"\r\n    data-x=\"72\"\r\n    data-y=\"48\"\r\n    data-offset-x=\"-125\"\r\n    data-offset-y=\"250\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>Independent flip on\/off<\/h3>\r\n      <p>Each pod can be flipped on or off independently and turns off when out of the way.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:08:25\"\r\n    data-end-time=\"0:00:10:05\"\r\n    data-x=\"45\"\r\n    data-y=\"50\"\r\n    data-offset-x=\"-250\"\r\n    data-offset-y=\"50\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>Electron 4-pin Fischer Port<\/h3>\r\n      <p>Connect external battery packs and many more powering solutions through the integrated Fischer interface.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:11:10\"\r\n    data-end-time=\"0:00:12:20\"\r\n    data-x=\"40\"\r\n    data-y=\"50\"\r\n    data-offset-x=\"-250\"\r\n    data-offset-y=\"-250\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>Dual function rotary knob<\/h3>\r\n      <p>Fine tactile adjustment for manual gain or IR illuminator power.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:16:00\"\r\n    data-end-time=\"0:00:17:10\"\r\n    data-x=\"58\"\r\n    data-y=\"44\"\r\n    data-offset-x=\"220\"\r\n    data-offset-y=\"-90\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>VCSEL IR illuminator<\/h3>\r\n      <p>Integrated adjustable VCSEL illumination for low-light and no-light environments.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div\r\n    class=\"annotation\"\r\n    data-start-time=\"0:00:19:20\"\r\n    data-end-time=\"0:00:20:25\"\r\n    data-x=\"20\"\r\n    data-y=\"50\"\r\n    data-offset-x=\"45\"\r\n    data-offset-y=\"250\"\r\n  >\r\n    <span class=\"dot\"><\/span>\r\n    <span class=\"line\"><\/span>\r\n    <div class=\"content\">\r\n      <h3>Multiple battery compatibility<\/h3>\r\n      <p>Support for CR123A, AA and future power configurations.<\/p>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-388ef15 scroll-video e-transform elementor-widget elementor-widget-video\" data-id=\"388ef15\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;video_type&quot;:&quot;hosted&quot;,&quot;mute&quot;:&quot;yes&quot;,&quot;_transform_translateX_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"video.default\">\n\t\t\t\t\t\t\t<div class=\"e-hosted-video elementor-wrapper elementor-open-inline\">\n\t\t\t\t\t<video class=\"elementor-video\" src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/features_1-1.webm\" preload=\"metadata\" muted=\"muted\" controlsList=\"nodownload\"><\/video>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c0d6e22 elementor-widget elementor-widget-html\" data-id=\"c0d6e22\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n  const section = document.querySelector(\".video-scroll-section\");\r\n  const sticky = document.querySelector(\".scroll-video\");\r\n  const video = sticky ? sticky.querySelector(\"video\") : null;\r\n  if (window.matchMedia(\"(max-width: 767px)\").matches) return;\r\n  const annotations = [...document.querySelectorAll(\".annotation\")];\r\n  const scrollTitle = document.querySelector(\".scroll-title\");\r\n\r\n  if (!section || !sticky || !video) return;\r\n\r\n  const snapControls = document.createElement(\"div\");\r\n  snapControls.className = \"snap-controls\";\r\n\r\n  const prevSnapButton = document.createElement(\"button\");\r\n  prevSnapButton.className = \"snap-arrow snap-prev\";\r\n  prevSnapButton.type = \"button\";\r\n  prevSnapButton.setAttribute(\"aria-label\", \"Previous snap\");\r\n  prevSnapButton.textContent = \"\u2039\";\r\n\r\n  const nextSnapButton = document.createElement(\"button\");\r\n  nextSnapButton.className = \"snap-arrow snap-next\";\r\n  nextSnapButton.type = \"button\";\r\n  nextSnapButton.setAttribute(\"aria-label\", \"Next snap\");\r\n  nextSnapButton.textContent = \"\u203a\";\r\n\r\n  snapControls.appendChild(prevSnapButton);\r\n  snapControls.appendChild(nextSnapButton);\r\n  sticky.appendChild(snapControls);\r\n\r\n  const timecodeFps = 30;\r\n\r\n  const snapTimecodes = [\r\n      \"0:00:00:00\",\r\n      \"0:00:03:05\",\r\n      \"0:00:07:00\",\r\n      \"0:00:09:15\",\r\n      \"0:00:12:00\",\r\n      \"0:00:16:20\",\r\n      \"0:00:20:10\"\r\n    ];\r\n    \r\n  const snapDelay = 200;\r\n  const snapMinDistance = 0.02;\r\n  const maxProgress = 1;\r\n  const snapDuration = 1300;\r\n\r\n  let duration = 0;\r\n  let ticking = false;\r\n  let snapTimer = null;\r\n  let isSnapping = false;\r\n  let snapAnimationFrame = null;\r\n  let videoUnlocked = false;\r\n\r\n  const isMobile = () => window.matchMedia(\"(max-width: 767px)\").matches;\r\n  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);\r\n\r\n  video.pause();\r\n  video.currentTime = 0;\r\n  video.muted = true;\r\n  video.preload = \"auto\";\r\n  video.playsInline = true;\r\n  video.setAttribute(\"muted\", \"\");\r\n  video.setAttribute(\"playsinline\", \"\");\r\n  video.setAttribute(\"webkit-playsinline\", \"\");\r\n  video.removeAttribute(\"autoplay\");\r\n\r\n  const timecodeToSeconds = (timecode) => {\r\n    const [hours, minutes, seconds, frames] = timecode.split(\":\").map(Number);\r\n    return hours * 3600 + minutes * 60 + seconds + frames \/ timecodeFps;\r\n  };\r\n\r\n  const getSnapPoints = () => {\r\n    duration = video.duration || duration;\r\n    if (!duration) return [0];\r\n\r\n    return snapTimecodes.map((timecode) => {\r\n      return clamp(timecodeToSeconds(timecode) \/ duration, 0, maxProgress);\r\n    });\r\n  };\r\n\r\n  const getMetrics = () => {\r\n    const sectionTop = section.getBoundingClientRect().top + window.scrollY;\r\n    const scrollLength = section.offsetHeight - window.innerHeight * 1.25;\r\n    return { sectionTop, scrollLength };\r\n  };\r\n\r\n  const getProgress = () => {\r\n    const { sectionTop, scrollLength } = getMetrics();\r\n    return clamp((window.scrollY - sectionTop) \/ scrollLength, 0, maxProgress);\r\n  };\r\n\r\n  const getTimedProgress = (element, key, fallback) => {\r\n    duration = video.duration || duration;\r\n    if (!duration) return fallback;\r\n\r\n    const timeValue = element.dataset[key];\r\n    if (!timeValue) return fallback;\r\n\r\n    return clamp(timecodeToSeconds(timeValue) \/ duration, 0, maxProgress);\r\n  };\r\n\r\n  const unlockVideo = () => {\r\n    if (videoUnlocked) return;\r\n    videoUnlocked = true;\r\n\r\n    video.play()\r\n      .then(() => {\r\n        video.pause();\r\n        video.currentTime = video.currentTime || 0.001;\r\n        updateScene(true);\r\n      })\r\n      .catch(() => {\r\n        updateScene(true);\r\n      });\r\n  };\r\n\r\n  const updateTitle = (progress) => {\r\n    if (!scrollTitle) return;\r\n\r\n    const titleStart = getTimedProgress(scrollTitle, \"startTime\", 0);\r\n    const titleEnd = getTimedProgress(scrollTitle, \"endTime\", 0.14);\r\n\r\n    scrollTitle.classList.toggle(\r\n      \"is-visible\",\r\n      progress >= titleStart && progress <= titleEnd\r\n    );\r\n  };\r\n\r\n  const positionAnnotations = () => {\r\n    const videoRect = video.getBoundingClientRect();\r\n    const stickyRect = sticky.getBoundingClientRect();\r\n\r\n    annotations.forEach((annotation) => {\r\n      const x = parseFloat(annotation.dataset.x || 50);\r\n      const y = parseFloat(annotation.dataset.y || 50);\r\n      let offsetX = parseFloat(annotation.dataset.offsetX || 180);\r\n      let offsetY = parseFloat(annotation.dataset.offsetY || -80);\r\n    \r\n       const isTablet = window.matchMedia(\"(min-width: 768px) and (max-width: 1180px)\").matches;\r\n    \r\n       if (isTablet) {\r\n        offsetX *= 0.52;\r\n        offsetY *= 0.72;\r\n      }  \r\n\r\n      const pointX = videoRect.left - stickyRect.left + videoRect.width * (x \/ 100);\r\n      const pointY = videoRect.top - stickyRect.top + videoRect.height * (y \/ 100);\r\n\r\n      const lineLength = Math.sqrt(offsetX * offsetX + offsetY * offsetY);\r\n      const lineAngle = Math.atan2(offsetY, offsetX) * (180 \/ Math.PI);\r\n\r\n      annotation.style.left = `${pointX}px`;\r\n      annotation.style.top = `${pointY}px`;\r\n      annotation.style.setProperty(\"--offset-x\", `${offsetX}px`);\r\n      annotation.style.setProperty(\"--offset-y\", `${offsetY}px`);\r\n      annotation.style.setProperty(\"--line-length\", `${lineLength}px`);\r\n      annotation.style.setProperty(\"--line-angle\", `${lineAngle}deg`);\r\n    });\r\n  };\r\n\r\n  const isAtSnapPoint = (progress) => {\r\n    const snapPoints = getSnapPoints();\r\n    const snapTolerance = 0.01;\r\n\r\n    return snapPoints.some((point) => {\r\n      return Math.abs(point - progress) <= snapTolerance;\r\n    });\r\n  };\r\n\r\n  const updateAnnotations = (progress) => {\r\n    const mobile = isMobile();\r\n\r\n    if (!mobile) {\r\n      positionAnnotations();\r\n    }\r\n\r\n    annotations.forEach((annotation) => {\r\n      const start = getTimedProgress(\r\n        annotation,\r\n        \"startTime\",\r\n        parseFloat(annotation.dataset.start || 0)\r\n      );\r\n\r\n      const end = getTimedProgress(\r\n        annotation,\r\n        \"endTime\",\r\n        parseFloat(annotation.dataset.end || 1)\r\n      );\r\n\r\n      const isInRange = progress >= start && progress <= end;\r\n\r\n      annotation.classList.toggle(\r\n        \"is-visible\",\r\n        mobile ? isInRange : isInRange && isAtSnapPoint(progress) && !isSnapping\r\n      );\r\n    });\r\n  };\r\n\r\n  const updateVideoTime = (progress, force = false) => {\r\n    duration = video.duration || duration;\r\n    if (!duration) return;\r\n\r\n    const safeTime = Math.min(duration * progress, duration - 0.05);\r\n    const threshold = isMobile() ? 0.08 : 0.02;\r\n\r\n    if (force || Math.abs(video.currentTime - safeTime) > threshold) {\r\n      try {\r\n        video.currentTime = safeTime;\r\n      } catch (error) {}\r\n    }\r\n  };\r\n\r\n  const updateScene = (forceVideo = false) => {\r\n    ticking = false;\r\n\r\n    const progress = getProgress();\r\n\r\n    updateTitle(progress);\r\n    updateAnnotations(progress);\r\n    updateVideoTime(progress, forceVideo);\r\n  };\r\n\r\n  const nearestSnapPoint = (progress) => {\r\n    const snapPoints = getSnapPoints();\r\n\r\n    return snapPoints.reduce((nearest, point) => {\r\n      return Math.abs(point - progress) < Math.abs(nearest - progress)\r\n        ? point\r\n        : nearest;\r\n    }, snapPoints[0]);\r\n  };\r\n\r\n  const easeInOutCubic = (t) => {\r\n    return t < 0.5\r\n      ? 4 * t * t * t\r\n      : 1 - Math.pow(-2 * t + 2, 3) \/ 2;\r\n  };\r\n\r\n  const cancelSnap = () => {\r\n    if (snapAnimationFrame) {\r\n      cancelAnimationFrame(snapAnimationFrame);\r\n      snapAnimationFrame = null;\r\n    }\r\n\r\n    clearTimeout(snapTimer);\r\n    snapTimer = null;\r\n    isSnapping = false;\r\n  };\r\n\r\n  const animateScrollTo = (targetY, durationMs) => {\r\n    const startY = window.scrollY;\r\n    const distance = targetY - startY;\r\n    const startTime = performance.now();\r\n\r\n    const step = (currentTime) => {\r\n      if (!isSnapping) return;\r\n\r\n      const elapsed = currentTime - startTime;\r\n      const progress = clamp(elapsed \/ durationMs, 0, 1);\r\n      const eased = easeInOutCubic(progress);\r\n\r\n      window.scrollTo(0, startY + distance * eased);\r\n\r\n      if (progress < 1) {\r\n        snapAnimationFrame = requestAnimationFrame(step);\r\n      } else {\r\n        snapAnimationFrame = null;\r\n        isSnapping = false;\r\n        updateScene(true);\r\n      }\r\n    };\r\n\r\n    snapAnimationFrame = requestAnimationFrame(step);\r\n  };\r\n\r\n  const goToSnap = (direction) => {\r\n    const snapPoints = getSnapPoints();\r\n    const progress = getProgress();\r\n\r\n    const currentIndex = snapPoints.reduce((nearestIndex, point, index) => {\r\n      return Math.abs(point - progress) < Math.abs(snapPoints[nearestIndex] - progress)\r\n        ? index\r\n        : nearestIndex;\r\n    }, 0);\r\n\r\n    const targetIndex = clamp(currentIndex + direction, 0, snapPoints.length - 1);\r\n    const targetProgress = snapPoints[targetIndex];\r\n\r\n    const { sectionTop, scrollLength } = getMetrics();\r\n    const targetY = sectionTop + scrollLength * targetProgress;\r\n\r\n    cancelSnap();\r\n    isSnapping = true;\r\n    animateScrollTo(targetY, snapDuration);\r\n  };\r\n\r\n  const snapToNearest = () => {\r\n    if (isSnapping || isMobile()) return;\r\n\r\n    const progress = getProgress();\r\n    const targetProgress = nearestSnapPoint(progress);\r\n\r\n    const distance = Math.abs(targetProgress - progress);\r\n    if (distance < snapMinDistance) return;\r\n\r\n    const { sectionTop, scrollLength } = getMetrics();\r\n    const targetY = sectionTop + scrollLength * targetProgress;\r\n\r\n    isSnapping = true;\r\n    animateScrollTo(targetY, snapDuration);\r\n  };\r\n\r\n  const requestUpdate = () => {\r\n    if (!ticking) {\r\n      ticking = true;\r\n      requestAnimationFrame(() => updateScene(false));\r\n    }\r\n\r\n    clearTimeout(snapTimer);\r\n\r\n    if (!isSnapping && !isMobile()) {\r\n      snapTimer = setTimeout(snapToNearest, snapDelay);\r\n    }\r\n  };\r\n\r\n  const handleManualInput = () => {\r\n    unlockVideo();\r\n\r\n    if (isSnapping) {\r\n      cancelSnap();\r\n      requestUpdate();\r\n    }\r\n  };\r\n\r\n  prevSnapButton.addEventListener(\"pointerdown\", (event) => {\r\n    event.stopPropagation();\r\n  });\r\n\r\n  prevSnapButton.addEventListener(\"click\", (event) => {\r\n    event.stopPropagation();\r\n    goToSnap(-1);\r\n  });\r\n\r\n  nextSnapButton.addEventListener(\"pointerdown\", (event) => {\r\n    event.stopPropagation();\r\n  });\r\n\r\n  nextSnapButton.addEventListener(\"click\", (event) => {\r\n    event.stopPropagation();\r\n    goToSnap(1);\r\n  });\r\n\r\n  video.addEventListener(\"loadedmetadata\", () => {\r\n    duration = video.duration;\r\n    updateScene(true);\r\n  });\r\n\r\n  video.addEventListener(\"canplay\", () => updateScene(true));\r\n\r\n  window.addEventListener(\"scroll\", requestUpdate, { passive: true });\r\n  window.addEventListener(\"wheel\", handleManualInput, { passive: true });\r\n  window.addEventListener(\"touchstart\", handleManualInput, { passive: true });\r\n  window.addEventListener(\"touchmove\", requestUpdate, { passive: true });\r\n  window.addEventListener(\"pointerdown\", handleManualInput, { passive: true });\r\n  window.addEventListener(\"mousedown\", handleManualInput);\r\n  window.addEventListener(\"keydown\", handleManualInput);\r\n  window.addEventListener(\"resize\", () => updateScene(true));\r\n\r\n  setTimeout(() => updateScene(true), 500);\r\n});\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-941a1e5 e-con-full e-flex e-con e-parent\" data-id=\"941a1e5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-82b7c3a elementor-widget elementor-widget-html\" data-id=\"82b7c3a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section class=\"product-carousel-section\">\r\n  <div class=\"carousel-head\">\r\n    <span class=\"carousel-eyebrow\">[FEATURES]<\/span>\r\n    <h2>One system, all the answers.<\/h2>\r\n  <\/div>\r\n\r\n  <div class=\"product-carousel-shell\">\r\n    <button class=\"product-carousel-arrow product-carousel-arrow--prev\" type=\"button\" aria-label=\"Previous slide\">\r\n      <span aria-hidden=\"true\"><\/span>\r\n    <\/button>\r\n\r\n    <div class=\"product-carousel\" aria-label=\"Product features\">\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <video muted playsinline autoplay loop preload=\"metadata\">\r\n            <source src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/ecosystem.webm\" type=\"video\/webm\">\r\n          <\/video>\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">01<\/span>\r\n          <h3>Still part of the Proton ecosystem<\/h3>\r\n          <p>Designed to work seamlessly with all Proton pods, accessories and power sources.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <video muted playsinline autoplay loop preload=\"metadata\">\r\n            <source src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/07\/rotary-knob.webm\" type=\"video\/webm\">\r\n          <\/video>\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">02<\/span>\r\n          <h3>Dual purpose rotary knob<\/h3>\r\n          <p>Adjust manual gain by default, or switch to IR Adjust mode to control VCSEL IR illuminator intensity with the same knob.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <video muted playsinline autoplay loop preload=\"metadata\">\r\n            <source src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/07\/mag-switch-modular-1.webm\" type=\"video\/webm\">\r\n          <\/video>\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">03<\/span>\r\n          <h3>Magnetic controls<\/h3>\r\n          <p>Interchangeable magnetic knobs for optimal ergonomics.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n      \r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <video muted playsinline autoplay loop preload=\"metadata\">\r\n            <source src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/diffusers.webm\" type=\"video\/webm\">\r\n          <\/video>\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">04<\/span>\r\n          <h3>Interchangeable illuminator lens<\/h3>\r\n          <p>Screw in a diffuser for wide, even coverage, a focusing lens for range, or a neutral lens when no shaping is needed.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/07\/tube.jpg?w=800&#038;ssl=1\" alt=\"\">\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">05<\/span>\r\n          <h3>Manual gain compatible<\/h3>\r\n          <p>Full compatibility with 3-pin manual gain image intensifier tubes.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/slide-omnifischer.jpg?w=800&#038;ssl=1\" alt=\"\">\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">06<\/span>\r\n          <h3>Fischer port for battery pack<\/h3>\r\n          <p>Industry-standard Fischer 4-pin port, optimized for the Electron power management system.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n\r\n      <article class=\"product-slide\">\r\n        <div class=\"slide-media\">\r\n          <video muted playsinline autoplay loop preload=\"metadata\">\r\n            <source src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/purge.webm\" type=\"video\/webm\">\r\n          <\/video>\r\n        <\/div>\r\n        <div class=\"slide-copy\">\r\n          <span class=\"slide-index\">07<\/span>\r\n          <h3>Independent purge<\/h3>\r\n          <p>Each component retains its own atmosphere, allowing you to swap configurations with minimal servicing.<\/p>\r\n        <\/div>\r\n      <\/article>\r\n    <\/div>\r\n\r\n    <button class=\"product-carousel-arrow product-carousel-arrow--next\" type=\"button\" aria-label=\"Next slide\">\r\n      <span aria-hidden=\"true\"><\/span>\r\n    <\/button>\r\n  <\/div>\r\n<\/section>\r\n\r\n\r\n<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n  document.querySelectorAll(\".product-carousel\").forEach((carousel) => {\r\n    const originals = [...carousel.querySelectorAll(\".product-slide\")];\r\n    const count = originals.length;\r\n    if (!count) return;\r\n\r\n    const shell = carousel.closest(\".product-carousel-shell\");\r\n    const prevButton = shell ? shell.querySelector(\".product-carousel-arrow--prev\") : null;\r\n    const nextButton = shell ? shell.querySelector(\".product-carousel-arrow--next\") : null;\r\n\r\n    carousel.innerHTML = \"\";\r\n\r\n    const makeClone = (slide, index, group) => {\r\n      const clone = slide.cloneNode(true);\r\n      clone.dataset.slideIndex = index;\r\n      clone.dataset.slideGroup = group;\r\n      return clone;\r\n    };\r\n\r\n    originals.forEach((slide, index) => carousel.appendChild(makeClone(slide, index, \"before\")));\r\n    originals.forEach((slide, index) => carousel.appendChild(makeClone(slide, index, \"main\")));\r\n    originals.forEach((slide, index) => carousel.appendChild(makeClone(slide, index, \"after\")));\r\n\r\n    const slides = [...carousel.querySelectorAll(\".product-slide\")];\r\n\r\n    let isDragging = false;\r\n    let didDrag = false;\r\n    let startX = 0;\r\n    let startScrollLeft = 0;\r\n    let pointerDownSlide = null;\r\n    let snapTimer = null;\r\n    let isProgrammaticScroll = false;\r\n\r\n    const getGap = () => {\r\n      const styles = window.getComputedStyle(carousel);\r\n      return parseFloat(styles.columnGap || styles.gap || 0) || 0;\r\n    };\r\n\r\n    const getStep = () => {\r\n      const first = slides[0];\r\n      return first ? first.offsetWidth + getGap() : 0;\r\n    };\r\n\r\n    const getLoopWidth = () => getStep() * count;\r\n    const getMainStart = () => getLoopWidth();\r\n\r\n    const normalizeLoop = () => {\r\n      const loopWidth = getLoopWidth();\r\n      const mainStart = getMainStart();\r\n\r\n      if (!loopWidth) return;\r\n\r\n      if (carousel.scrollLeft < mainStart - loopWidth * 0.5) {\r\n        carousel.scrollLeft += loopWidth;\r\n      }\r\n\r\n      if (carousel.scrollLeft > mainStart + loopWidth * 1.5) {\r\n        carousel.scrollLeft -= loopWidth;\r\n      }\r\n    };\r\n\r\n    const getNearestSlide = () => {\r\n      const carouselCenter = carousel.scrollLeft + carousel.clientWidth \/ 2;\r\n\r\n      return slides.reduce((nearest, slide) => {\r\n        const slideCenter = slide.offsetLeft + slide.offsetWidth \/ 2;\r\n        const nearestCenter = nearest.offsetLeft + nearest.offsetWidth \/ 2;\r\n\r\n        return Math.abs(slideCenter - carouselCenter) <\r\n          Math.abs(nearestCenter - carouselCenter)\r\n          ? slide\r\n          : nearest;\r\n      }, slides[0]);\r\n    };\r\n\r\n    const snapToSlide = (slide, behavior = \"smooth\") => {\r\n      if (!slide) return;\r\n\r\n      clearTimeout(snapTimer);\r\n      isProgrammaticScroll = true;\r\n\r\n      const target = slide.offsetLeft - carousel.clientWidth \/ 2 + slide.offsetWidth \/ 2;\r\n\r\n      carousel.scrollTo({\r\n        left: target,\r\n        behavior\r\n      });\r\n\r\n      setTimeout(() => {\r\n        normalizeLoop();\r\n        isProgrammaticScroll = false;\r\n      }, behavior === \"auto\" ? 0 : 650);\r\n    };\r\n\r\n    const snapToNearest = () => {\r\n      normalizeLoop();\r\n      snapToSlide(getNearestSlide(), \"smooth\");\r\n    };\r\n\r\n    const goToAdjacentSlide = (direction) => {\r\n      normalizeLoop();\r\n\r\n      const nearest = getNearestSlide();\r\n      const currentIndex = slides.indexOf(nearest);\r\n      const target = slides[currentIndex + direction];\r\n\r\n      if (target) {\r\n        snapToSlide(target, \"smooth\");\r\n      }\r\n    };\r\n\r\n    if (prevButton) {\r\n      prevButton.addEventListener(\"click\", () => goToAdjacentSlide(-1));\r\n    }\r\n\r\n    if (nextButton) {\r\n      nextButton.addEventListener(\"click\", () => goToAdjacentSlide(1));\r\n    }\r\n\r\n    const initPosition = () => {\r\n      carousel.scrollLeft = getMainStart();\r\n      snapToSlide(slides[count], \"auto\");\r\n      carousel.classList.add(\"is-ready\");\r\n    };\r\n\r\n    requestAnimationFrame(() => {\r\n      requestAnimationFrame(initPosition);\r\n    });\r\n\r\n    carousel.addEventListener(\"scroll\", () => {\r\n      normalizeLoop();\r\n\r\n      if (!isDragging && !isProgrammaticScroll) {\r\n        clearTimeout(snapTimer);\r\n        snapTimer = setTimeout(snapToNearest, 180);\r\n      }\r\n    });\r\n\r\n    carousel.addEventListener(\"pointerdown\", (event) => {\r\n      pointerDownSlide = event.target.closest(\".product-slide\");\r\n      if (!pointerDownSlide || !carousel.contains(pointerDownSlide)) return;\r\n\r\n      isDragging = true;\r\n      didDrag = false;\r\n      startX = event.clientX;\r\n      startScrollLeft = carousel.scrollLeft;\r\n\r\n      carousel.classList.add(\"is-dragging\");\r\n      clearTimeout(snapTimer);\r\n\r\n      try {\r\n        carousel.setPointerCapture(event.pointerId);\r\n      } catch (error) {}\r\n    });\r\n\r\n    carousel.addEventListener(\"pointermove\", (event) => {\r\n      if (!isDragging) return;\r\n\r\n      const deltaX = event.clientX - startX;\r\n\r\n      if (Math.abs(deltaX) > 6) {\r\n        didDrag = true;\r\n      }\r\n\r\n      carousel.scrollLeft = startScrollLeft - deltaX;\r\n    });\r\n\r\n    const stopPointer = (event) => {\r\n      if (!isDragging) return;\r\n\r\n      isDragging = false;\r\n      carousel.classList.remove(\"is-dragging\");\r\n\r\n      try {\r\n        carousel.releasePointerCapture(event.pointerId);\r\n      } catch (error) {}\r\n\r\n      if (didDrag) {\r\n        snapToNearest();\r\n      } else if (pointerDownSlide) {\r\n        snapToSlide(pointerDownSlide, \"smooth\");\r\n      }\r\n\r\n      pointerDownSlide = null;\r\n    };\r\n\r\n    carousel.addEventListener(\"pointerup\", stopPointer);\r\n    carousel.addEventListener(\"pointercancel\", stopPointer);\r\n\r\n    window.addEventListener(\"resize\", () => {\r\n      carousel.classList.remove(\"is-ready\");\r\n\r\n      requestAnimationFrame(() => {\r\n        carousel.scrollLeft = getMainStart();\r\n        snapToSlide(slides[count], \"auto\");\r\n        carousel.classList.add(\"is-ready\");\r\n      });\r\n    });\r\n  });\r\n});\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-d4ade1f e-con-full e-flex e-con e-parent\" data-id=\"d4ade1f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2fd6a6c elementor-widget elementor-widget-html\" data-id=\"2fd6a6c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section class=\"feature-video-section\">\r\n  <div class=\"feature-video-inner\">\r\n    <div class=\"feature-copy\">\r\n      <span class=\"eyebrow\">[ELECTRON PLATFORM]<\/span>\r\n\r\n      <h2>Powered by Electron<\/h2>\r\n\r\n      <p class=\"intro\">\r\n        The Proton Omni integrates the Electron power management system, delivering unmatched flexibility, intelligent power distribution, and a future-proof energy architecture for analog night vision systems.\r\n      <\/p>\r\n\r\n      <div class=\"feature-list\">\r\n        <button class=\"feature-item is-active\" type=\"button\">\r\n          <span class=\"feature-title\">Intelligent Power Management<\/span>\r\n          <span class=\"feature-icon\"><\/span>\r\n          <span class=\"feature-body\">\r\n            Electron continuously monitors and optimizes power delivery across the system for maximum runtime and reliable operation. Automatic source selection and efficient power regulation ensure seamless performance in the field.\r\n          <\/span>\r\n        <\/button>\r\n\r\n        <button class=\"feature-item\" type=\"button\">\r\n          <span class=\"feature-title\">Universal Battery Compatibility<\/span>\r\n          <span class=\"feature-icon\"><\/span>\r\n          <span class=\"feature-body\">\r\n            Electron is designed around battery freedom. From AA and CR123A today to future battery formats tomorrow, Proton Omni adapts without changing the device itself. Power evolves. Your platform is ready for it.\r\n          <\/span>\r\n        <\/button>\r\n\r\n        <button class=\"feature-item\" type=\"button\">\r\n          <span class=\"feature-title\">External Power Without Limits<\/span>\r\n          <span class=\"feature-icon\"><\/span>\r\n          <span class=\"feature-body\">\r\n            The rear 4 pin power interface accepts external input up to 5V, enabling compatibility with a wide range of battery packs, battery banks and specific power solutions while maintaining full system functionality.\r\n          <\/span>\r\n        <\/button>\r\n\r\n        <button class=\"feature-item\" type=\"button\">\r\n          <span class=\"feature-title\">Future Ready Power Architecture<\/span>\r\n          <span class=\"feature-icon\"><\/span>\r\n          <span class=\"feature-body\">\r\n            Electron is more than just a wider range of compatible batteries. It is a scalable power platform built to support future accessories, new battery technologies, and expanded capabilities without replacing your core equipment.\r\n          <\/span>\r\n        <\/button>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"feature-media\">\r\n      <div\r\n        class=\"feature-lottie\"\r\n        data-lottie-src=\"https:\/\/bosonsystems.store\/wp-content\/uploads\/2026\/08\/schematic.json\"\r\n        aria-hidden=\"true\"\r\n      ><\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/section>\r\n\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/lottie-web\/5.12.2\/lottie.min.js\"><\/script>\r\n\r\n<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n  const HEIGHT_BUFFER = 24;\r\n\r\n  function setBodyHeight(item, open) {\r\n    const body = item.querySelector(\".feature-body\");\r\n    if (!body) return;\r\n\r\n    if (!open) {\r\n      body.style.maxHeight = \"0px\";\r\n      return;\r\n    }\r\n\r\n    body.style.maxHeight = body.scrollHeight + HEIGHT_BUFFER + \"px\";\r\n  }\r\n\r\n  function closeItem(item) {\r\n    item.classList.remove(\"is-active\");\r\n    item.setAttribute(\"aria-expanded\", \"false\");\r\n    setBodyHeight(item, false);\r\n  }\r\n\r\n  function openItem(item) {\r\n    item.classList.add(\"is-active\");\r\n    item.setAttribute(\"aria-expanded\", \"true\");\r\n    setBodyHeight(item, true);\r\n  }\r\n\r\n  function initAccordions() {\r\n    document.querySelectorAll(\".feature-video-section\").forEach((section) => {\r\n      const items = Array.from(section.querySelectorAll(\".feature-item\"));\r\n\r\n      items.forEach((item) => {\r\n        const isActive = item.classList.contains(\"is-active\");\r\n\r\n        item.setAttribute(\"aria-expanded\", isActive ? \"true\" : \"false\");\r\n        setBodyHeight(item, isActive);\r\n\r\n        if (item.dataset.accordionReady === \"true\") return;\r\n        item.dataset.accordionReady = \"true\";\r\n\r\n        item.addEventListener(\"click\", () => {\r\n          const isOpen = item.classList.contains(\"is-active\");\r\n\r\n          items.forEach(closeItem);\r\n\r\n          if (!isOpen) {\r\n            openItem(item);\r\n          }\r\n        });\r\n      });\r\n    });\r\n  }\r\n\r\n  function initLotties() {\r\n    if (!window.lottie) return;\r\n\r\n    document.querySelectorAll(\".feature-lottie\").forEach((el) => {\r\n      if (el.dataset.lottieReady === \"true\") return;\r\n      el.dataset.lottieReady = \"true\";\r\n\r\n      window.lottie.loadAnimation({\r\n        container: el,\r\n        renderer: \"svg\",\r\n        loop: true,\r\n        autoplay: true,\r\n        path: el.dataset.lottieSrc\r\n      });\r\n    });\r\n  }\r\n\r\n  initAccordions();\r\n  initLotties();\r\n\r\n  window.addEventListener(\"load\", () => {\r\n    initAccordions();\r\n    initLotties();\r\n  });\r\n\r\n  window.addEventListener(\"resize\", () => {\r\n    document.querySelectorAll(\".feature-item.is-active\").forEach((item) => {\r\n      setBodyHeight(item, true);\r\n    });\r\n  });\r\n\r\n  if (document.fonts && document.fonts.ready) {\r\n    document.fonts.ready.then(() => {\r\n      document.querySelectorAll(\".feature-item.is-active\").forEach((item) => {\r\n        setBodyHeight(item, true);\r\n      });\r\n    });\r\n  }\r\n});\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-a142bd8 e-con-full e-flex e-con e-parent\" data-id=\"a142bd8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5233b50 elementor-widget elementor-widget-html\" data-id=\"5233b50\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section class=\"proton-specs-section\">\r\n  <div class=\"proton-section-inner\">\r\n    <div class=\"proton-specs-head\">\r\n      <p class=\"proton-specs-kicker\">Technical specs<\/p>\r\n      <h2 class=\"proton-specs-title\">Specifications<\/h2>\r\n    <\/div>\r\n\r\n    <div class=\"proton-specs-table-wrap\">\r\n      <table class=\"proton-specs-table\">\r\n        <tbody>\r\n          <tr>\r\n            <th>Optics<\/th>\r\n            <td>Modular, Proton Optical Pod<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Manual gain<\/th>\r\n            <td>Yes<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Tubes<\/th>\r\n            <td>2-pin autogain or 3-pin manual gain<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Weight<\/th>\r\n            <td>~500g <\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>External power<\/th>\r\n            <td>Yes<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Infrared illuminator<\/th>\r\n            <td>Yes, VCSEL adjustable<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Onboard battery type<\/th>\r\n            <td><strong>CR123A, AA<\/strong><\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Runtime<\/th>\r\n            <td><strong>30h with CR123A<\/strong><\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Infrared indicator<\/th>\r\n            <td>Yes, in FOV<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Low battery indicator<\/th>\r\n            <td>Yes, in FOV<\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Material<\/th>\r\n            <td><strong>7075-T6 Aluminium &amp; Grade 5 Titanium<\/strong><\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Coating<\/th>\r\n            <td><strong>Anodizing Type III Hardcoat<\/strong><\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Ingress<\/th>\r\n            <td><strong>IP-68 \/ 20m (66ft) for 2h<\/strong><\/td>\r\n          <\/tr>\r\n          <tr>\r\n            <th>Standard<\/th>\r\n            <td><strong>MIL-STD-810H<\/strong><\/td>\r\n          <\/tr>\r\n        <\/tbody>\r\n      <\/table>\r\n    <\/div>\r\n  <\/div>\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-6f65486 e-flex e-con-boxed e-con e-parent\" data-id=\"6f65486\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Introducing Proton Omni 01 Modularity The Proton Omni bridge is fully compatible with all Proton Optical Pods. Standard PVS, 16mm, thermal and more. 02 Independent flip on\/off Each pod can be flipped on or off independently and turns off when out of the way. 03 Electron 4-pin Fischer Port Connect external battery packs and powering [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_angie_page":false,"ai_generated_summary":"","wpai_meta_description":"","footnotes":""},"class_list":["post-3993","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/pages\/3993","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/comments?post=3993"}],"version-history":[{"count":897,"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/pages\/3993\/revisions"}],"predecessor-version":[{"id":5431,"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/pages\/3993\/revisions\/5431"}],"wp:attachment":[{"href":"https:\/\/bosonsystems.store\/fr\/wp-json\/wp\/v2\/media?parent=3993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}