{"id":7347,"date":"2026-08-31T22:08:16","date_gmt":"2026-09-01T02:08:16","guid":{"rendered":"https:\/\/www.visionpros.com\/pro\/?p=7347"},"modified":"2026-09-17T23:53:09","modified_gmt":"2026-09-18T03:53:09","slug":"colored-contacts-eye-color-simulator","status":"publish","type":"post","link":"https:\/\/www.visionpros.com\/pro\/colored-contacts-eye-color-simulator\/","title":{"rendered":"Colored Contact Lens Eye Color Simulator"},"content":{"rendered":"\n<meta charset=\"UTF-8\">\n<title>VisionPros \u2014 Before \/ After Lens Color Preview<\/title>\n\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Libre+Baskerville:wght@400;700&family=Source+Sans+3:wght@400;500;600;700&display=swap');\n\n:root {\n  --navy: #1a3a6b;\n  --accent-blue: #0057a8;\n  --amber: #e8a13c;\n  --amber-soft: #e8a13c1a;\n  --bg: #faf9f6;\n  --card: #ffffff;\n  --line: #e2ded4;\n  --ink: #232323;\n  --muted: #6f6a5e;\n}\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  min-height: 100vh;\n  background: var(--bg);\n  color: var(--ink);\n  font-family: 'Source Sans 3', -apple-system, sans-serif;\n  padding: 52px 20px;\n}\n\n.wrap {\n  width: 100%;\n  max-width: 1200px;\n  margin: 0 auto;\n}\n\n\n\/* ==========================================================\n   HEADING\n   ========================================================== *\/\n\nh2 {\n  font-family: 'Libre Baskerville', Georgia, serif;\n  font-weight: 700;\n  font-size: 2rem;\n  margin: 0 0 8px;\n  color: var(--navy);\n}\n\n.sub {\n  color: var(--muted);\n  font-size: 1rem;\n  margin: 0 0 36px;\n  width: 100%;\n  max-width: 1020px;\n  line-height: 1.65;\n  text-align: left;\n}\n\n\n\/* ==========================================================\n   LABELS\n   ========================================================== *\/\n\n.color-row-label {\n  font-family: 'Source Sans 3', -apple-system, sans-serif;\n  font-size: 0.72rem;\n  font-weight: 700;\n  text-transform: uppercase;\n  letter-spacing: 0.08em;\n  color: var(--navy);\n  margin: 0 0 10px;\n}\n\n\n\/* ==========================================================\n   COLOR BUTTONS\n   ========================================================== *\/\n\n.color-row {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 10px;\n  margin-bottom: 30px;\n}\n\n.color-btn {\n  width: 34px;\n  height: 34px;\n  flex: 0 0 34px;\n  border-radius: 50%;\n  border: 2px solid var(--line);\n  cursor: pointer;\n  padding: 0;\n  transition:\n    transform 0.12s ease,\n    border-color 0.12s ease,\n    box-shadow 0.12s ease;\n}\n\n.color-btn:hover {\n  transform: scale(1.1);\n}\n\n.color-btn.active {\n  border-color: var(--navy);\n  box-shadow:\n    0 0 0 2px #ffffff,\n    0 0 0 4px var(--navy);\n}\n\n\n\/* ==========================================================\n   MAIN LAYOUT\n   ========================================================== *\/\n\n.comparison-layout {\n  width: 100%;\n  max-width: 1050px;\n  margin: 0 auto 32px;\n  display: grid;\n  grid-template-columns: 220px 320px 280px;\n  justify-content: center;\n  align-items: center;\n  gap: 48px;\n}\n\n.color-panel {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n\n.color-panel-left {\n  align-items: flex-end;\n  text-align: right;\n}\n\n.color-panel-right {\n  align-items: flex-start;\n  text-align: left;\n}\n\n.color-panel .color-row-label {\n  margin-bottom: 16px;\n}\n\n\n\/* ==========================================================\n   NATURAL EYE COLORS\n   ========================================================== *\/\n\n.color-panel-left .color-row {\n  display: grid;\n  grid-template-columns: repeat(2, 34px);\n  gap: 14px;\n  margin: 0;\n  justify-content: end;\n}\n\n\n\/* ==========================================================\n   BRAND BUTTONS\n   ========================================================== *\/\n\n.brand-buttons {\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n  width: 220px;\n  margin-bottom: 22px;\n}\n\n.brand-btn {\n  width: 100%;\n  border: 1px solid var(--line);\n  background: var(--card);\n  color: var(--navy);\n  border-radius: 6px;\n  padding: 9px 12px;\n  font-family: 'Source Sans 3', -apple-system, sans-serif;\n  font-size: 0.72rem;\n  font-weight: 700;\n  line-height: 1.3;\n  text-align: left;\n  cursor: pointer;\n  transition:\n    background 0.15s ease,\n    border-color 0.15s ease,\n    color 0.15s ease;\n}\n\n.brand-btn:hover {\n  border-color: var(--accent-blue);\n  background: #f5f8fb;\n}\n\n.brand-btn.active {\n  background: var(--navy);\n  border-color: var(--navy);\n  color: #ffffff;\n}\n\n.available-colors-label {\n  margin-top: 0;\n  margin-bottom: 12px !important;\n}\n\n\n\/* ==========================================================\n   LENS COLOR SCROLLER\n   ========================================================== *\/\n\n.lens-color-scroll-wrap {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  width: 280px;\n  max-width: 100%;\n}\n\n.lens-color-row {\n  display: grid !important;\n  grid-template-rows: repeat(2, 34px);\n  grid-auto-flow: column;\n  grid-auto-columns: 34px;\n  column-gap: 12px !important;\n  row-gap: 12px !important;\n  width: 220px;\n  max-width: 220px;\n  overflow-x: auto;\n  overflow-y: hidden;\n  justify-content: start !important;\n  margin: 0 !important;\n  padding: 4px;\n  scroll-behavior: smooth;\n  scrollbar-width: none;\n}\n\n.lens-color-row::-webkit-scrollbar {\n  display: none;\n}\n\n\n\/* ==========================================================\n   COLOR ARROWS\n   ========================================================== *\/\n\n.color-scroll-arrow {\n  width: 26px;\n  height: 44px;\n  flex: 0 0 26px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 0;\n  border: 1px solid var(--line);\n  border-radius: 6px;\n  background: var(--card);\n  color: var(--navy);\n  font-family: Arial, sans-serif;\n  font-size: 1.35rem;\n  font-weight: 700;\n  line-height: 1;\n  cursor: pointer;\n  transition:\n    background 0.15s ease,\n    border-color 0.15s ease,\n    color 0.15s ease,\n    opacity 0.15s ease;\n}\n\n.color-scroll-arrow:hover:not(:disabled) {\n  background: var(--navy);\n  border-color: var(--navy);\n  color: #ffffff;\n}\n\n.color-scroll-arrow:disabled {\n  opacity: 0.22;\n  cursor: default;\n}\n\n\n\/* ==========================================================\n   EYE COMPARISON\n   ========================================================== *\/\n\n.compare-shell {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.compare-stage {\n  position: relative;\n  width: min(300px, 78vw);\n  height: min(300px, 78vw);\n}\n\n.compare-wrap {\n  position: absolute;\n  inset: 0;\n  border-radius: 50%;\n  overflow: hidden;\n  border: 5px solid var(--card);\n  box-shadow:\n    0 16px 40px rgba(26,58,107,0.18),\n    0 0 0 1px var(--line);\n  background: #000;\n}\n\n.layer {\n  position: absolute;\n  inset: 0;\n  border-radius: 50%;\n}\n\n.layer svg {\n  width: 100%;\n  height: 100%;\n  display: block;\n}\n\n.layer-before {\n  clip-path: inset(0 var(--reveal, 50%) 0 0);\n  z-index: 2;\n}\n\n.layer-after {\n  z-index: 1;\n}\n\n\n\/* ==========================================================\n   DIVIDER\n   ========================================================== *\/\n\n.divider {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: calc(100% - var(--reveal, 50%));\n  width: 2px;\n  background: var(--card);\n  z-index: 3;\n  pointer-events: none;\n  box-shadow: 0 0 8px rgba(0,0,0,0.35);\n}\n\n.handle {\n  position: absolute;\n  top: 50%;\n  left: calc(100% - var(--reveal, 50%));\n  transform: translate(-50%, -50%);\n  width: 34px;\n  height: 34px;\n  border-radius: 50%;\n  background: var(--card);\n  color: var(--navy);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 0.9rem;\n  font-weight: 700;\n  z-index: 4;\n  pointer-events: none;\n  box-shadow: 0 2px 10px rgba(0,0,0,0.25);\n}\n\n\n\/* ==========================================================\n   COMPARISON SLIDER\n   ========================================================== *\/\n\n.compare-slider {\n  -webkit-appearance: none;\n  appearance: none;\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  margin: 0;\n  background: transparent;\n  z-index: 5;\n  cursor: ew-resize;\n  opacity: 0;\n}\n\n.compare-slider::-webkit-slider-thumb {\n  -webkit-appearance: none;\n  width: 34px;\n  height: 34px;\n  border-radius: 50%;\n  background: transparent;\n  cursor: ew-resize;\n}\n\n.compare-slider::-moz-range-thumb {\n  width: 34px;\n  height: 34px;\n  border: none;\n  border-radius: 50%;\n  background: transparent;\n  cursor: ew-resize;\n}\n\n.compare-slider::-webkit-slider-runnable-track {\n  background: transparent;\n}\n\n.compare-slider::-moz-range-track {\n  background: transparent;\n}\n\n\n\/* ==========================================================\n   BEFORE \/ AFTER LABELS\n   ========================================================== *\/\n\n.labels {\n  display: flex;\n  justify-content: space-between;\n  width: min(300px, 78vw);\n  margin-top: 16px;\n  font-family: 'Source Sans 3', -apple-system, sans-serif;\n  font-size: 0.72rem;\n  font-weight: 700;\n  text-transform: uppercase;\n  letter-spacing: 0.08em;\n  color: var(--navy);\n}\n\n.label-before {\n  color: var(--navy);\n  font-weight: 700;\n  text-align: left;\n}\n\n.label-after {\n  color: var(--navy);\n  font-weight: 700;\n  text-align: right;\n}\n\n\n\/* ==========================================================\n   RESULT STRIP\n   ========================================================== *\/\n\n.result-strip {\n  width: 100%;\n  margin-top: 28px;\n  display: flex;\n  align-items: center;\n  gap: 14px;\n  background: var(--card);\n  border: 1px solid var(--line);\n  border-radius: 8px;\n  padding: 16px 20px;\n  box-shadow: 0 1px 3px rgba(0,0,0,0.05);\n}\n\n.result-strip .swatch {\n  width: 34px;\n  height: 34px;\n  border-radius: 50%;\n  flex-shrink: 0;\n  background: #c11414;\n  border: 2px solid var(--line);\n}\n\n.result-strip .info {\n  flex: 1;\n}\n\n.result-strip .name {\n  font-family: 'Libre Baskerville', Georgia, serif;\n  font-weight: 700;\n  font-size: 1.1rem;\n  color: var(--navy);\n}\n\n.result-strip .line {\n  font-size: 0.68rem;\n  text-transform: uppercase;\n  letter-spacing: 0.05em;\n  color: var(--amber);\n  font-weight: 700;\n}\n\n.result-strip .shop {\n  font-size: 0.82rem;\n  font-weight: 700;\n  text-transform: uppercase;\n  color: var(--accent-blue);\n  text-decoration: none;\n  white-space: nowrap;\n}\n\n.result-strip .shop:hover {\n  text-decoration: underline;\n}\n\n\n\/* ==========================================================\n   MOBILE\n   ========================================================== *\/\n\n@media (max-width: 820px) {\n\n  .comparison-layout {\n    grid-template-columns: 1fr;\n    justify-items: center;\n    gap: 30px;\n  }\n\n  .color-panel-left,\n  .color-panel-right {\n    align-items: center;\n    text-align: center;\n  }\n\n  .color-panel-left .color-row {\n    justify-content: center;\n  }\n\n  .brand-buttons {\n    width: min(320px, 100%);\n  }\n\n  .brand-btn {\n    text-align: center;\n  }\n\n  .lens-color-scroll-wrap {\n    justify-content: center;\n  }\n\n  .result-strip {\n    flex-wrap: wrap;\n  }\n\n  .result-strip .shop {\n    width: 100%;\n    margin-top: 6px;\n  }\n\n}\n<\/style>\n\n\n\n<div class=\"wrap\">\n\n  <h2>See the Transformation<\/h2>\n\n  <p class=\"sub\">\n    Choose your natural eye color on the left, then select a colored or Halloween contact lens on the right.\n    Drag across the eye preview to compare the before-and-after effect and see how different lens shades and\n    designs can change the overall appearance of your eyes before you shop.\n  <\/p>\n\n\n  <div class=\"comparison-layout\">\n\n    <!-- NATURAL EYE COLOR -->\n\n    <div class=\"color-panel color-panel-left\">\n\n      <p class=\"color-row-label\">\n        Natural eye color\n      <\/p>\n\n      <div class=\"color-row\" id=\"naturalColorRow\">\n\n        <button type=\"button\" class=\"color-btn active\"\n          style=\"background:#2e1a0f;\"\n          data-name=\"Dark Brown\"\n          data-color=\"#2e1a0f\"\n          title=\"Dark Brown\"\n          aria-label=\"Dark Brown\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#5a3821;\"\n          data-name=\"Brown\"\n          data-color=\"#5a3821\"\n          title=\"Brown\"\n          aria-label=\"Brown\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#8a5a34;\"\n          data-name=\"Light Brown\"\n          data-color=\"#8a5a34\"\n          title=\"Light Brown\"\n          aria-label=\"Light Brown\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#a97c4f;\"\n          data-name=\"Hazel\"\n          data-color=\"#a97c4f\"\n          title=\"Hazel\"\n          aria-label=\"Hazel\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#b8863b;\"\n          data-name=\"Amber\"\n          data-color=\"#b8863b\"\n          title=\"Amber\"\n          aria-label=\"Amber\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#4b7043;\"\n          data-name=\"Green\"\n          data-color=\"#4b7043\"\n          title=\"Green\"\n          aria-label=\"Green\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#7a9b6e;\"\n          data-name=\"Hazel-Green\"\n          data-color=\"#7a9b6e\"\n          title=\"Hazel-Green\"\n          aria-label=\"Hazel-Green\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#4f7d99;\"\n          data-name=\"Blue-Gray\"\n          data-color=\"#4f7d99\"\n          title=\"Blue-Gray\"\n          aria-label=\"Blue-Gray\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#5b7fa6;\"\n          data-name=\"Blue\"\n          data-color=\"#5b7fa6\"\n          title=\"Blue\"\n          aria-label=\"Blue\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#a9c4d6;\"\n          data-name=\"Light Blue\"\n          data-color=\"#a9c4d6\"\n          title=\"Light Blue\"\n          aria-label=\"Light Blue\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#8a8a86;\"\n          data-name=\"Gray\"\n          data-color=\"#8a8a86\"\n          title=\"Gray\"\n          aria-label=\"Gray\"><\/button>\n\n        <button type=\"button\" class=\"color-btn\"\n          style=\"background:#6b4a75;\"\n          data-name=\"Violet\"\n          data-color=\"#6b4a75\"\n          title=\"Violet\"\n          aria-label=\"Violet\"><\/button>\n\n      <\/div>\n\n    <\/div>\n\n\n\n    <!-- EYE COMPARISON -->\n\n    <div class=\"compare-shell\">\n\n      <div class=\"compare-stage\">\n\n        <div\n          class=\"compare-wrap\"\n          id=\"compareWrap\"\n          style=\"--reveal:50%;\">\n\n          <div class=\"layer layer-after\" id=\"layerAfter\"><\/div>\n          <div class=\"layer layer-before\" id=\"layerBefore\"><\/div>\n\n          <div class=\"divider\"><\/div>\n\n          <div class=\"handle\">\n            \u2194\n          <\/div>\n\n        <\/div>\n\n        <input\n          type=\"range\"\n          class=\"compare-slider\"\n          id=\"compareSlider\"\n          min=\"0\"\n          max=\"100\"\n          value=\"50\"\n          aria-label=\"Drag to compare before and after\">\n\n      <\/div>\n\n\n      <div class=\"labels\">\n        <span class=\"label-before\" id=\"beforeLabel\">Natural Dark Brown<\/span>\n        <span class=\"label-after\" id=\"afterLabel\">With Hot Red<\/span>\n      <\/div>\n\n    <\/div>\n\n\n\n    <!-- LENS SELECTION -->\n\n    <div class=\"color-panel color-panel-right\">\n\n      <p class=\"color-row-label\">\n        Lens brand\n      <\/p>\n\n      <div class=\"brand-buttons\" id=\"brandButtons\">\n\n        <button\n          type=\"button\"\n          class=\"brand-btn active\"\n          data-brand=\"pure-halloween\">\n          Pure Colors Halloween\n        <\/button>\n\n        <button\n          type=\"button\"\n          class=\"brand-btn\"\n          data-brand=\"pure-hd\">\n          Pure Colors HD\n        <\/button>\n\n        <button\n          type=\"button\"\n          class=\"brand-btn\"\n          data-brand=\"air-optix\">\n          AIR OPTIX COLORS\n        <\/button>\n\n        <button\n          type=\"button\"\n          class=\"brand-btn\"\n          data-brand=\"dailies\">\n          DAILIES COLORS\n        <\/button>\n\n        <button\n          type=\"button\"\n          class=\"brand-btn\"\n          data-brand=\"acuvue-define\">\n          1-DAY ACUVUE DEFINE\n        <\/button>\n\n      <\/div>\n\n      <p class=\"color-row-label available-colors-label\">\n        Lens color\n      <\/p>\n\n      <div class=\"lens-color-scroll-wrap\">\n\n        <button\n          type=\"button\"\n          class=\"color-scroll-arrow\"\n          id=\"colorPrev\"\n          aria-label=\"Previous lens colors\">\n          \u2039\n        <\/button>\n\n        <div\n          class=\"color-row lens-color-row\"\n          id=\"colorRow\"><\/div>\n\n        <button\n          type=\"button\"\n          class=\"color-scroll-arrow\"\n          id=\"colorNext\"\n          aria-label=\"More lens colors\">\n          \u203a\n        <\/button>\n\n      <\/div>\n\n    <\/div>\n\n  <\/div>\n\n\n\n  <!-- RESULT STRIP -->\n\n  <div class=\"result-strip\">\n\n    <div class=\"swatch\" id=\"stripSwatch\"><\/div>\n\n    <div class=\"info\">\n      <div class=\"line\" id=\"stripLine\">\n        PURE COLORS HALLOWEEN CONTACT LENSES\n      <\/div>\n      <div class=\"name\" id=\"stripName\">\n        Hot Red\n      <\/div>\n    <\/div>\n\n    <a\n      class=\"shop\"\n      id=\"stripShop\"\n      href=\"https:\/\/www.visionpros.com\/contact-lenses\/pure-colors-hd-costume-halloween-edition\/\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\">\n      Shop this lens \u2192\n    <\/a>\n\n  <\/div>\n\n\n\n  <!-- PROMOTIONAL BANNER -->\n\n  <div style=\"\n    font-family: Georgia, 'Times New Roman', serif;\n    max-width: 1200px;\n    margin: 40px auto;\n    border: 1px solid #e0e0e0;\n    border-radius: 8px;\n    overflow: hidden;\n  \">\n\n    <div style=\"display:flex; align-items:stretch;\">\n\n      <div style=\"\n        flex: 1;\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding: 40px 44px;\n        background: #ffffff;\n      \">\n\n        <p style=\"\n          font-family: Arial, sans-serif;\n          font-size: 14px;\n          color: #7ba9d1;\n          letter-spacing: 0.08em;\n          text-transform: uppercase;\n          margin: 0 0 10px 0;\n          font-weight: 700;\n        \">\n          See the world more clearly\n        <\/p>\n\n        <p style=\"\n          font-family: Georgia, 'Times New Roman', serif;\n          font-size: 38px;\n          font-weight: 700;\n          color: #0e4773;\n          margin: 0 0 10px 0;\n          line-height: 1.3;\n        \">\n          Premium contacts,<br>\n          delivered to you.\n        <\/p>\n\n        <p style=\"\n          font-family: Arial, sans-serif;\n          font-size: 16px;\n          color: #555;\n          margin: 0 0 24px 0;\n          line-height: 1.6;\n        \">\n          Shop top brands like Acuvue, Bausch + Lomb, and Air Optix at trusted low prices.\n        <\/p>\n\n        <a\n          href=\"https:\/\/www.visionpros.com\/contact-lenses\/\"\n          style=\"\n            display: inline-block;\n            font-family: Arial, sans-serif;\n            font-size: 14px;\n            font-weight: 600;\n            color: #ffffff;\n            background: #3176b4;\n            text-decoration: none;\n            padding: 11px 24px;\n            border-radius: 4px;\n            width: fit-content;\n            letter-spacing: 0.03em;\n          \">\n          Shop Contact Lenses \u2192\n        <\/a>\n\n      <\/div>\n\n      <div style=\"\n        flex: 0 0 45%;\n        overflow: hidden;\n      \">\n\n        <img decoding=\"async\" class=\"lazyload\" data-src=\"https:\/\/www.visionpros.com\/pro\/wp-content\/uploads\/2026\/06\/Contact-Lenses-1.png\"\n          src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n          alt=\"Contact lens boxes with lifestyle props\"\n          style=\"\n            width: 100%;\n            height: 100%;\n            object-fit: cover;\n            object-position: 100% center;\n            display: block;\n          \"><noscript><img decoding=\"async\" src=\"https:\/\/www.visionpros.com\/pro\/wp-content\/uploads\/2026\/06\/Contact-Lenses-1.png\" alt=\"Contact lens boxes with lifestyle props\" style=\"\n            width: 100%;\n            height: 100%;\n            object-fit: cover;\n            object-position: 100% center;\n            display: block;\n          \"><\/noscript>\n\n      <\/div>\n\n    <\/div>\n\n  <\/div>\n\n<\/div>\n\n\n\n<script>\n\/* ==========================================================\n   DOM\n   ========================================================== *\/\n\nconst wrap = document.getElementById('compareWrap');\nconst slider = document.getElementById('compareSlider');\nconst afterLabel = document.getElementById('afterLabel');\nconst beforeLabel = document.getElementById('beforeLabel');\nconst stripName = document.getElementById('stripName');\nconst stripLine = document.getElementById('stripLine');\nconst stripSwatch = document.getElementById('stripSwatch');\nconst stripShop = document.getElementById('stripShop');\nconst colorRow = document.getElementById('colorRow');\nconst naturalColorRow = document.getElementById('naturalColorRow');\nconst layerAfter = document.getElementById('layerAfter');\nconst layerBefore = document.getElementById('layerBefore');\nconst brandButtons = document.getElementById('brandButtons');\nconst colorPrev = document.getElementById('colorPrev');\nconst colorNext = document.getElementById('colorNext');\n\n\n\/* ==========================================================\n   SVG CONSTANTS\n   ========================================================== *\/\n\nconst SVG_NS = \"http:\/\/www.w3.org\/2000\/svg\";\nconst IRIS_CX = 100;\nconst IRIS_CY = 100;\nconst PUPIL_CX = 96;\nconst PUPIL_CY = 104;\n\n\n\/* ==========================================================\n   LENS DATABASE\n   ========================================================== *\/\n\nconst LENS_BRANDS = {\n\n  \"pure-halloween\": {\n    line: \"PURE COLORS HALLOWEEN CONTACT LENSES\",\n    url: \"https:\/\/www.visionpros.com\/contact-lenses\/pure-colors-hd-costume-halloween-edition\/\",\n    colors: [\n      { name: \"Hot Red\", color: \"#ff1616\", strength: 0.92, effect: \"hot-red\" },\n      { name: \"Devil\", color: \"#f8154d\", strength: 0.94, effect: \"devil\" },\n      { name: \"Black Out\", color: \"#111111\", strength: 0.98, effect: \"black-out\" },\n      { name: \"White Out\", color: \"#f4f4f0\", strength: 0.97, effect: \"white-out\" },\n      { name: \"Yellow Wolf\", color: \"#e4ce20\", strength: 0.94, effect: \"yellow-wolf\" },\n      { name: \"Yellow Cat\", color: \"#d8ad3d\", strength: 0.94, effect: \"yellow-cat\" },\n      { name: \"White Cat\", color: \"#f5f5f0\", strength: 0.95, effect: \"white-cat\" },\n      { name: \"Psycho\", color: \"#efefeb\", strength: 0.96, effect: \"psycho\" },\n      { name: \"Spider Web\", color: \"#eeeeea\", strength: 0.95, effect: \"spider-web\" },\n      { name: \"Manson\", color: \"#f3f3ef\", strength: 0.96, effect: \"manson\" }\n    ]\n  },\n\n  \"pure-hd\": {\n    line: \"PURE COLORS HD\",\n    url: \"https:\/\/www.visionpros.com\/contact-lenses\/pure-colors-hd\/\",\n    colors: [\n      { name: \"Amethyst\", color: \"#8a5fc7\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Chestnut Brown\", color: \"#6b4226\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Emerald Green\", color: \"#1f7a4c\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Ocean Blue\", color: \"#1f6f9c\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Grey\", color: \"#9a9a9a\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Hazel\", color: \"#a97c4f\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Honey\", color: \"#c58a3a\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Pure Hazel\", color: \"#a88c5d\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Sapphire Blue\", color: \"#2b4fa0\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Sky Blue\", color: \"#7ec6e6\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Turquoise\", color: \"#2fb5a0\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Vivid Green\", color: \"#57c23a\", strength: 0.72, effect: \"natural-color\" },\n      { name: \"Jade\", color: \"#3f9e77\", strength: 0.72, effect: \"natural-color\" }\n    ]\n  },\n\n  \"air-optix\": {\n    line: \"AIR OPTIX COLORS\",\n    url: \"https:\/\/www.visionpros.com\/contact-lenses\/air-optix-colors\/\",\n    colors: [\n      { name: \"Amethyst\", color: \"#8870a8\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Blue\", color: \"#5b7fa6\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Brown\", color: \"#6b4933\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Green\", color: \"#5d7c54\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Grey\", color: \"#8d8f92\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Honey\", color: \"#c48a3a\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Pure Hazel\", color: \"#a58958\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"True Sapphire\", color: \"#2e5c99\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Turquoise\", color: \"#4b9d9b\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Gemstone Green\", color: \"#408b62\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Brilliant Blue\", color: \"#3d78b8\", strength: 0.64, effect: \"air-optix\" },\n      { name: \"Sterling Grey\", color: \"#a3a7ab\", strength: 0.64, effect: \"air-optix\" }\n    ]\n  },\n\n  \"dailies\": {\n    line: \"DAILIES COLORS\",\n    url: \"https:\/\/www.visionpros.com\/contact-lenses\/dailies-colors\/\",\n    colors: [\n      { name: \"Mystic Blue\", color: \"#5f88b6\", strength: 0.56, effect: \"dailies\" },\n      { name: \"Mystic Hazel\", color: \"#9a7650\", strength: 0.56, effect: \"dailies\" },\n      { name: \"Mystic Gray\", color: \"#8d9197\", strength: 0.56, effect: \"dailies\" },\n      { name: \"Mystic Green\", color: \"#5f8b64\", strength: 0.54, effect: \"dailies-green\" }\n    ]\n  },\n\n  \"acuvue-define\": {\n    line: \"1-DAY ACUVUE DEFINE\",\n    url: \"https:\/\/www.visionpros.com\/contact-lenses\/1-day-acuvue-define\/\",\n    colors: [\n      { name: \"Natural Shine\", color: \"#9a7657\", strength: 0.22, effect: \"define-natural-shine\" },\n      { name: \"Vivid\", color: \"#73533d\", strength: 0.24, effect: \"define-vivid\" },\n      { name: \"Accent\", color: \"#49382d\", strength: 0.20, effect: \"define-accent\" }\n    ]\n  }\n\n};\n\n\n\/* ==========================================================\n   COMPARISON SLIDER\n   ========================================================== *\/\n\nslider.addEventListener('input', () => {\n  const reveal = 100 - slider.value;\n  wrap.style.setProperty('--reveal', reveal + '%');\n});\n\n\n\/* ==========================================================\n   SVG HELPER\n   ========================================================== *\/\n\nfunction svgElement(tag, attrs = {}) {\n  const el = document.createElementNS(SVG_NS, tag);\n\n  Object.entries(attrs).forEach(([key, value]) => {\n    el.setAttribute(key, value);\n  });\n\n  return el;\n}\n\n\n\/* ==========================================================\n   COLOR UTILITIES\n   ========================================================== *\/\n\nfunction clamp(value, min, max) {\n  return Math.max(min, Math.min(max, value));\n}\n\nfunction hexToHsl(hex) {\n  let r = parseInt(hex.slice(1, 3), 16) \/ 255;\n  let g = parseInt(hex.slice(3, 5), 16) \/ 255;\n  let b = parseInt(hex.slice(5, 7), 16) \/ 255;\n\n  const max = Math.max(r, g, b);\n  const min = Math.min(r, g, b);\n\n  let h;\n  let s;\n  let l = (max + min) \/ 2;\n\n  if (max === min) {\n    h = 0;\n    s = 0;\n  } else {\n    const d = max - min;\n\n    s = l > 0.5\n      ? d \/ (2 - max - min)\n      : d \/ (max + min);\n\n    switch (max) {\n      case r:\n        h = (g - b) \/ d + (g < b ? 6 : 0);\n        break;\n\n      case g:\n        h = (b - r) \/ d + 2;\n        break;\n\n      default:\n        h = (r - g) \/ d + 4;\n    }\n\n    h *= 60;\n  }\n\n  return {\n    h,\n    s: s * 100,\n    l: l * 100\n  };\n}\n\nfunction hexToRgbArr(hex) {\n  return [\n    parseInt(hex.slice(1, 3), 16),\n    parseInt(hex.slice(3, 5), 16),\n    parseInt(hex.slice(5, 7), 16)\n  ];\n}\n\nfunction blendHex(hexA, weightA, hexB, weightB) {\n  const [r1, g1, b1] = hexToRgbArr(hexA);\n  const [r2, g2, b2] = hexToRgbArr(hexB);\n  const total = weightA + weightB;\n\n  const r = Math.round((r1 * weightA + r2 * weightB) \/ total);\n  const g = Math.round((g1 * weightA + g2 * weightB) \/ total);\n  const b = Math.round((b1 * weightA + b2 * weightB) \/ total);\n\n  const toHex = value =>\n    clamp(Math.round(value), 0, 255)\n      .toString(16)\n      .padStart(2, '0');\n\n  return \"#\" + toHex(r) + toHex(g) + toHex(b);\n}\n\nfunction hslVariant(hex, lightnessShift = 0, saturationShift = 0) {\n  const { h, s, l } = hexToHsl(hex);\n\n  return `hsl(\n    ${h},\n    ${clamp(s + saturationShift, 0, 100)}%,\n    ${clamp(l + lightnessShift, 0, 100)}%\n  )`;\n}\n\n\n\/* ==========================================================\n   NATURAL EYE BRIGHTNESS\n   ========================================================== *\/\n\nfunction getNaturalEyeBrightness(hex) {\n  const [r, g, b] = hexToRgbArr(hex);\n\n  const brightness = (\n    0.2126 * r +\n    0.7152 * g +\n    0.0722 * b\n  ) \/ 255;\n\n  return clamp(brightness, 0, 1);\n}\n\n\n\/* ==========================================================\n   ADAPTIVE LENS COLOR STRENGTH\n   ========================================================== *\/\n\nfunction getAdaptiveLensStrength(lens, naturalHex) {\n  const brightness = getNaturalEyeBrightness(naturalHex);\n  const base = lens.strength ?? 0.7;\n\n  if (lens.brand === \"pure-halloween\") {\n    const multiplier = 0.88 + (brightness * 0.12);\n\n    return clamp(base * multiplier, 0, 1);\n  }\n\n  if (lens.effect === \"natural-color\") {\n    return clamp(base * (0.62 + brightness * 0.38), 0, 1);\n  }\n\n  if (lens.effect === \"air-optix\") {\n    return clamp(base * (0.60 + brightness * 0.40), 0, 1);\n  }\n\n  if (\n    lens.effect === \"dailies\" ||\n    lens.effect === \"dailies-green\"\n  ) {\n    return clamp(base * (0.58 + brightness * 0.42), 0, 1);\n  }\n\n  if (lens.effect.startsWith(\"define-\")) {\n    return clamp(base * (0.68 + brightness * 0.32), 0, 1);\n  }\n\n  return base;\n}\n\n\n\/* ==========================================================\n   NATURAL-EYE SHOW-THROUGH\n   ========================================================== *\/\n\nfunction getNaturalRevealAmount(lens) {\n  switch (lens.effect) {\n    case \"hot-red\":\n      return 0.18;\n\n    case \"devil\":\n      return 0.16;\n\n    case \"yellow-wolf\":\n      return 0.15;\n\n    case \"yellow-cat\":\n      return 0.16;\n\n    case \"white-cat\":\n      return 0.14;\n\n    case \"spider-web\":\n      return 0.10;\n\n    case \"psycho\":\n      return 0.08;\n\n    case \"manson\":\n      return 0.08;\n\n    case \"white-out\":\n      return 0.06;\n\n    case \"black-out\":\n      return 0.04;\n\n    default:\n      return 0;\n  }\n}\n\n\n\/* ==========================================================\n   EFFECT OPACITY\n   ========================================================== *\/\n\nfunction getAdaptiveEffectOpacity(lens, naturalHex) {\n  if (lens.brand === \"pure-halloween\") {\n    return 1;\n  }\n\n  const brightness = getNaturalEyeBrightness(naturalHex);\n\n  return clamp(\n    0.68 + (brightness * 0.32),\n    0.68,\n    1\n  );\n}\n\n\n\/* ==========================================================\n   BUILD IRIS SVG\n   ========================================================== *\/\n\nfunction buildIrisSvg(id, strandSeed) {\n  const svg = svgElement(\"svg\", { viewBox: \"0 0 200 200\" });\n  svg.id = id;\n\n  const defs = svgElement(\"defs\");\n\n  const grad = svgElement(\"radialGradient\", {\n    id: id + \"-grad\",\n    cx: \"48%\",\n    cy: \"44%\",\n    r: \"62%\"\n  });\n\n  const stop1 = svgElement(\"stop\", { offset: \"0%\" });\n  const stop2 = svgElement(\"stop\", { offset: \"65%\" });\n  const stop3 = svgElement(\"stop\", { offset: \"100%\" });\n\n  grad.appendChild(stop1);\n  grad.appendChild(stop2);\n  grad.appendChild(stop3);\n\n  defs.appendChild(grad);\n  svg.appendChild(defs);\n\n  const base = svgElement(\"circle\", {\n    cx: IRIS_CX,\n    cy: IRIS_CY,\n    r: 98,\n    fill: `url(#${id}-grad)`,\n    class: \"iris-base\"\n  });\n\n  svg.appendChild(base);\n\n  const fibers = svgElement(\"g\", { class: \"fibers\" });\n  let seed = strandSeed;\n\n  function rand() {\n    seed = (seed * 9301 + 49297) % 233280;\n    return seed \/ 233280;\n  }\n\n  const strandCount = 150;\n\n  for (let i = 0; i < strandCount; i++) {\n    const angle =\n      (i \/ strandCount) * Math.PI * 2 +\n      (rand() - 0.5) * 0.05;\n\n    const innerR = 32 + rand() * 4;\n    const outerR = 98 * (0.78 + rand() * 0.22);\n\n    const x1 = IRIS_CX + Math.cos(angle) * innerR;\n    const y1 = IRIS_CY + Math.sin(angle) * innerR;\n    const x2 = IRIS_CX + Math.cos(angle) * outerR;\n    const y2 = IRIS_CY + Math.sin(angle) * outerR;\n\n    const bend = (rand() - 0.5) * 6;\n    const midAngle = angle + bend * 0.01;\n    const midR = (innerR + outerR) \/ 2;\n\n    const mx = IRIS_CX + Math.cos(midAngle) * midR;\n    const my = IRIS_CY + Math.sin(midAngle) * midR;\n\n    const path = svgElement(\"path\", {\n      d: `M ${x1.toFixed(1)} ${y1.toFixed(1)}\n         Q ${mx.toFixed(1)} ${my.toFixed(1)}\n         ${x2.toFixed(1)} ${y2.toFixed(1)}`,\n      fill: \"none\",\n      \"stroke-width\": (0.5 + rand() * 1.1).toFixed(2)\n    });\n\n    path.dataset.lightVariant = (rand() * 40 - 20).toFixed(1);\n    path.dataset.opacityVariant = (0.25 + rand() * 0.45).toFixed(2);\n\n    fibers.appendChild(path);\n  }\n\n  svg.appendChild(fibers);\n\n  const effectLayer = svgElement(\"g\", {\n    class: \"lens-effect-layer\"\n  });\n\n  svg.appendChild(effectLayer);\n\n  const limbal = svgElement(\"circle\", {\n    cx: IRIS_CX,\n    cy: IRIS_CY,\n    r: 96,\n    fill: \"none\",\n    stroke: \"#000000\",\n    \"stroke-width\": \"5\",\n    opacity: \"0.35\",\n    class: \"limbal-ring\"\n  });\n\n  svg.appendChild(limbal);\n\n  const pupil = svgElement(\"circle\", {\n    cx: PUPIL_CX,\n    cy: PUPIL_CY,\n    r: 30,\n    fill: \"#080808\",\n    class: \"pupil\"\n  });\n\n  svg.appendChild(pupil);\n\n  const pupilRing = svgElement(\"circle\", {\n    cx: PUPIL_CX,\n    cy: PUPIL_CY,\n    r: 30,\n    fill: \"none\",\n    stroke: \"#000000\",\n    \"stroke-width\": \"1.5\",\n    opacity: \"0.6\",\n    class: \"pupil-ring\"\n  });\n\n  svg.appendChild(pupilRing);\n\n  svg.appendChild(\n    svgElement(\"ellipse\", {\n      cx: 68,\n      cy: 70,\n      rx: 13,\n      ry: 9,\n      fill: \"#ffffff\",\n      opacity: \"0.55\",\n      class: \"catchlight\"\n    })\n  );\n\n  svg.appendChild(\n    svgElement(\"ellipse\", {\n      cx: 132,\n      cy: 138,\n      rx: 6,\n      ry: 4,\n      fill: \"#ffffff\",\n      opacity: \"0.25\",\n      class: \"catchlight\"\n    })\n  );\n\n  svg.appendChild(\n    svgElement(\"circle\", {\n      cx: IRIS_CX,\n      cy: IRIS_CY,\n      r: 98,\n      fill: \"none\",\n      stroke: \"#000000\",\n      \"stroke-width\": \"14\",\n      opacity: \"0.12\",\n      class: \"vignette\"\n    })\n  );\n\n  return svg;\n}\n\n\n\/* ==========================================================\n   COLORIZE IRIS\n   ========================================================== *\/\n\nfunction colorizeIris(svg, hex) {\n  const { h, s, l } = hexToHsl(hex);\n\n  const stops = svg.querySelectorAll(`#${svg.id}-grad stop`);\n\n  stops[0].setAttribute(\n    'stop-color',\n    `hsl(${h}, ${Math.min(s + 8, 100)}%, ${Math.min(l + 18, 88)}%)`\n  );\n\n  stops[1].setAttribute(\n    'stop-color',\n    `hsl(${h}, ${s}%, ${l}%)`\n  );\n\n  stops[2].setAttribute(\n    'stop-color',\n    `hsl(${h}, ${Math.max(s - 5, 0)}%, ${Math.max(l - 22, 6)}%)`\n  );\n\n  svg.querySelectorAll('.fibers path').forEach(path => {\n    const variant = parseFloat(path.dataset.lightVariant);\n    const opacity = parseFloat(path.dataset.opacityVariant);\n    const strandL = clamp(l + variant, 4, 94);\n\n    path.setAttribute(\n      'stroke',\n      `hsl(${h}, ${s}%, ${strandL}%)`\n    );\n\n    path.setAttribute('stroke-opacity', opacity);\n  });\n}\n\n\n\/* ==========================================================\n   SVG EFFECT HELPERS\n   ========================================================== *\/\n\nfunction getEffectLayer(svg) {\n  return svg.querySelector('.lens-effect-layer');\n}\n\nfunction setFiberOpacity(svg, opacity) {\n  const fibers = svg.querySelector('.fibers');\n  if (fibers) {\n    fibers.setAttribute('opacity', opacity);\n  }\n}\n\nfunction setGradientColors(svg, center, middle, edge) {\n  const stops = svg.querySelectorAll(`#${svg.id}-grad stop`);\n  if (stops.length < 3) return;\n\n  stops[0].setAttribute('stop-color', center);\n  stops[1].setAttribute('stop-color', middle);\n  stops[2].setAttribute('stop-color', edge);\n}\n\nfunction setLimbalRing(svg, color, width, opacity) {\n  const ring = svg.querySelector('.limbal-ring');\n  if (!ring) return;\n\n  ring.setAttribute('stroke', color);\n  ring.setAttribute('stroke-width', width);\n  ring.setAttribute('opacity', opacity);\n}\n\nfunction hideDefaultPupil(svg) {\n  const pupil = svg.querySelector('.pupil');\n  const pupilRing = svg.querySelector('.pupil-ring');\n\n  if (pupil) pupil.setAttribute('opacity', 0);\n  if (pupilRing) pupilRing.setAttribute('opacity', 0);\n}\n\nfunction addRing(group, radius, stroke, width, opacity = 1) {\n  group.appendChild(\n    svgElement(\"circle\", {\n      cx: IRIS_CX,\n      cy: IRIS_CY,\n      r: radius,\n      fill: \"none\",\n      stroke: stroke,\n      \"stroke-width\": width,\n      opacity: opacity\n    })\n  );\n}\n\nfunction addRadialLines(\n  group,\n  innerRadius,\n  outerRadius,\n  count,\n  stroke,\n  width,\n  opacity = 1,\n  offset = 0\n) {\n  for (let i = 0; i < count; i++) {\n    const angle = (i \/ count) * Math.PI * 2 + offset;\n\n    const x1 = IRIS_CX + Math.cos(angle) * innerRadius;\n    const y1 = IRIS_CY + Math.sin(angle) * innerRadius;\n    const x2 = IRIS_CX + Math.cos(angle) * outerRadius;\n    const y2 = IRIS_CY + Math.sin(angle) * outerRadius;\n\n    group.appendChild(\n      svgElement(\"line\", {\n        x1,\n        y1,\n        x2,\n        y2,\n        stroke: stroke,\n        \"stroke-width\": width,\n        opacity: opacity,\n        \"stroke-linecap\": \"round\"\n      })\n    );\n  }\n}\n\n\n\/* ==========================================================\n   NATURAL-EYE TINT LAYER\n   ========================================================== *\/\n\nfunction addNaturalEyeInfluence(svg, naturalColor, opacity) {\n  if (opacity <= 0) return;\n\n  const tint = svgElement(\"circle\", {\n    cx: IRIS_CX,\n    cy: IRIS_CY,\n    r: 98,\n    fill: naturalColor,\n    opacity: opacity,\n    class: \"natural-eye-influence\"\n  });\n\n  const fibers = svg.querySelector('.fibers');\n  if (fibers) {\n    svg.insertBefore(tint, fibers);\n  }\n}\n\n\n\/* ==========================================================\n   REFERENCE SHAPE HELPERS\n   ========================================================== *\/\n\nfunction polarPoint(radius, angle) {\n  return {\n    x: IRIS_CX + Math.cos(angle) * radius,\n    y: IRIS_CY + Math.sin(angle) * radius\n  };\n}\n\nfunction pointsToClosedPath(points) {\n  if (!points.length) return \"\";\n\n  let d = `M ${points[0].x.toFixed(1)} ${points[0].y.toFixed(1)}`;\n\n  for (let i = 1; i < points.length; i++) {\n    d += ` L ${points[i].x.toFixed(1)} ${points[i].y.toFixed(1)}`;\n  }\n\n  d += \" Z\";\n  return d;\n}\n\nfunction setFxBase(\n  svg,\n  center,\n  middle,\n  edge,\n  fiberOpacity = 0,\n  limbalColor = \"#000000\",\n  limbalWidth = 0,\n  limbalOpacity = 0\n) {\n  setGradientColors(svg, center, middle, edge);\n  setFiberOpacity(svg, fiberOpacity);\n  setLimbalRing(svg, limbalColor, limbalWidth, limbalOpacity);\n\n  const pupilRing = svg.querySelector('.pupil-ring');\n  if (pupilRing) {\n    pupilRing.setAttribute('opacity', 0);\n  }\n}\n\nfunction addCatAlmondShape(group, fill = \"#1a1212\", opacity = 1) {\n  const d = `\n    M 96 18\n    C 121 44, 128 73, 126 104\n    C 124 136, 118 165, 96 190\n    C 74 165, 68 136, 66 104\n    C 64 73, 71 44, 96 18\n    Z\n  `;\n\n  group.appendChild(\n    svgElement(\"path\", {\n      d,\n      fill,\n      opacity\n    })\n  );\n}\n\nfunction addDevilGraphic(group) {\n  const leftHorn = `\n    M 63 30\n    C 66 47, 77 57, 92 62\n    C 86 48, 86 34, 94 20\n    C 80 23, 69 25, 63 30\n    Z\n  `;\n\n  const rightHorn = `\n    M 129 30\n    C 126 47, 115 57, 100 62\n    C 106 48, 106 34, 98 20\n    C 112 23, 123 25, 129 30\n    Z\n  `;\n\n  const tail = `\n    M 97 118\n    C 107 128, 111 141, 104 151\n    C 99 158, 90 160, 84 155\n    C 92 155, 99 151, 99 144\n    C 99 136, 92 128, 87 121\n    L 95 120\n    C 99 126, 102 132, 103 138\n    C 105 145, 104 151, 101 157\n    L 111 154\n    L 101 166\n    L 80 160\n    L 89 153\n  `;\n\n  group.appendChild(svgElement(\"path\", { d: leftHorn, fill: \"#111111\" }));\n  group.appendChild(svgElement(\"path\", { d: rightHorn, fill: \"#111111\" }));\n  group.appendChild(svgElement(\"path\", { d: tail, fill: \"#111111\" }));\n}\n\nfunction addPsychoRings(group) {\n  const radii = [84, 76, 68, 60, 52, 44];\n\n  radii.forEach(radius => {\n    addRing(group, radius, \"#000000\", 4.2, 1);\n  });\n}\n\nfunction addSpiderWebGraphic(group) {\n  const spokeCount = 10;\n  const startAngle = -Math.PI \/ 2;\n  const innerRadius = 36;\n  const outerRadius = 84;\n\n  for (let i = 0; i < spokeCount; i++) {\n    const angle = startAngle + (i * Math.PI * 2 \/ spokeCount);\n    const p1 = polarPoint(innerRadius, angle);\n    const p2 = polarPoint(outerRadius, angle);\n\n    group.appendChild(\n      svgElement(\"line\", {\n        x1: p1.x,\n        y1: p1.y,\n        x2: p2.x,\n        y2: p2.y,\n        stroke: \"#000000\",\n        \"stroke-width\": 2.5,\n        \"stroke-linecap\": \"round\"\n      })\n    );\n  }\n\n  const ringRadii = [46, 58, 70, 82];\n\n  ringRadii.forEach(radius => {\n    for (let i = 0; i < spokeCount; i++) {\n      const a1 = startAngle + (i * Math.PI * 2 \/ spokeCount);\n      const a2 = startAngle + ((i + 1) * Math.PI * 2 \/ spokeCount);\n\n      const p1 = polarPoint(radius, a1);\n      const p2 = polarPoint(radius, a2);\n      const control = polarPoint(radius * 1.14, (a1 + a2) \/ 2);\n\n      group.appendChild(\n        svgElement(\"path\", {\n          d: `M ${p1.x.toFixed(1)} ${p1.y.toFixed(1)}\n              Q ${control.x.toFixed(1)} ${control.y.toFixed(1)}\n                ${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`,\n          fill: \"none\",\n          stroke: \"#000000\",\n          \"stroke-width\": 2.2,\n          \"stroke-linecap\": \"round\"\n        })\n      );\n    }\n  });\n}\n\nfunction addYellowWolfGraphic(group) {\n  const outerPoints = [];\n  const innerPoints = [];\n  const count = 24;\n\n  for (let i = 0; i < count; i++) {\n    const angle = -Math.PI \/ 2 + (i * Math.PI * 2 \/ count);\n    const outerRadius = 84 + Math.sin(i * 0.9) * 1.8;\n\n    const innerRadius =\n      54 +\n      (i % 2 === 0 ? -12 : 5) +\n      Math.sin(i * 1.6) * 3;\n\n    outerPoints.push(polarPoint(outerRadius, angle));\n    innerPoints.push(polarPoint(innerRadius, angle));\n  }\n\n  const ringPath = pointsToClosedPath([\n    ...outerPoints,\n    ...innerPoints.reverse()\n  ]);\n\n  group.appendChild(\n    svgElement(\"path\", {\n      d: ringPath,\n      fill: \"#ece11b\"\n    })\n  );\n}\n\n\n\/* ==========================================================\n   HALLOWEEN EFFECTS\n   ========================================================== *\/\n\nfunction addWhiteOutEffect(svg) {\n  setFxBase(\n    svg,\n    \"#ffffff\",\n    \"#f5f5f5\",\n    \"#ededed\",\n    0,\n    \"#d5d5d5\",\n    1.5,\n    0.28\n  );\n}\n\nfunction addBlackOutEffect(svg) {\n  setFxBase(\n    svg,\n    \"#000000\",\n    \"#020202\",\n    \"#050505\",\n    0,\n    \"#000000\",\n    0,\n    0\n  );\n\n  hideDefaultPupil(svg);\n}\n\nfunction addHotRedEffect(svg) {\n  setFxBase(\n    svg,\n    \"#ff2a2a\",\n    \"#ff1616\",\n    \"#ed0909\",\n    0.02,\n    \"#7c0808\",\n    2.5,\n    0.28\n  );\n}\n\nfunction addMansonEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#ffffff\",\n    \"#f7f7f7\",\n    \"#efefef\",\n    0,\n    \"#000000\",\n    0,\n    0\n  );\n\n  const group = getEffectLayer(svg);\n  addRing(group, 86, \"#000000\", 8, 1);\n}\n\nfunction addWhiteCatEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#fcfcfc\",\n    \"#f6f6f4\",\n    \"#ecece8\",\n    0,\n    \"#9a9a9a\",\n    1.5,\n    0.35\n  );\n\n  const group = getEffectLayer(svg);\n  addCatAlmondShape(group, \"#241616\", 0.96);\n}\n\nfunction addYellowCatEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#e0b84a\",\n    \"#d8ad3d\",\n    \"#cc9d29\",\n    0,\n    \"#a87d1e\",\n    1.5,\n    0.28\n  );\n\n  const group = getEffectLayer(svg);\n  addCatAlmondShape(group, \"#241616\", 0.96);\n}\n\nfunction addYellowWolfEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#232126\",\n    \"#201e23\",\n    \"#1a181d\",\n    0,\n    \"#111111\",\n    3,\n    0.35\n  );\n\n  const group = getEffectLayer(svg);\n  addYellowWolfGraphic(group);\n}\n\nfunction addDevilEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#ff3a64\",\n    \"#f8154d\",\n    \"#ef0c43\",\n    0,\n    \"#b30d35\",\n    2,\n    0.18\n  );\n\n  const group = getEffectLayer(svg);\n  addDevilGraphic(group);\n}\n\nfunction addPsychoEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#ffffff\",\n    \"#fafafa\",\n    \"#f0f0f0\",\n    0,\n    \"#000000\",\n    0,\n    0\n  );\n\n  const group = getEffectLayer(svg);\n  addPsychoRings(group);\n}\n\nfunction addSpiderWebEffectReference(svg) {\n  setFxBase(\n    svg,\n    \"#ffffff\",\n    \"#f8f8f8\",\n    \"#efefef\",\n    0,\n    \"#000000\",\n    0,\n    0\n  );\n\n  const group = getEffectLayer(svg);\n  addSpiderWebGraphic(group);\n}\n\n\n\/* ==========================================================\n   REGULAR COLORED LENS EFFECTS\n   ========================================================== *\/\n\nfunction addAirOptixEffect(svg, lens) {\n  const group = getEffectLayer(svg);\n\n  const dark = hslVariant(lens.color, -24, -4);\n  const light = hslVariant(lens.color, 24, -8);\n\n  addRing(group, 88, dark, 9, 0.42);\n  addRing(group, 43, light, 9, 0.34);\n  addRadialLines(group, 43, 85, 34, lens.color, 1.3, 0.17);\n}\n\nfunction addDailiesEffect(svg, lens, softerRing = false) {\n  const group = getEffectLayer(svg);\n  const dark = hslVariant(lens.color, -30, -8);\n\n  addRing(\n    group,\n    88,\n    dark,\n    8,\n    softerRing ? 0.23 : 0.46\n  );\n\n  addRadialLines(group, 53, 84, 26, lens.color, 1.1, 0.15);\n}\n\nfunction addDefineEffect(svg, type, lens) {\n  const group = getEffectLayer(svg);\n  const dark = hslVariant(lens.color, -20, -5);\n  const light = hslVariant(lens.color, 15, -8);\n\n  if (type === \"define-natural-shine\") {\n    addRing(group, 87, dark, 5, 0.28);\n    addRadialLines(group, 55, 85, 28, light, 1.6, 0.28, 0.04);\n  }\n\n  if (type === \"define-vivid\") {\n    addRing(group, 88, dark, 8, 0.44);\n    addRadialLines(group, 47, 84, 32, lens.color, 1.5, 0.25, 0.02);\n  }\n\n  if (type === \"define-accent\") {\n    addRing(group, 88, dark, 10, 0.55);\n    addRing(group, 78, lens.color, 3, 0.25);\n  }\n}\n\n\n\/* ==========================================================\n   APPLY LENS EFFECT\n   ========================================================== *\/\n\nfunction applyLensEffect(svg, lens) {\n  switch (lens.effect) {\n\n    case \"natural-color\":\n      setLimbalRing(svg, \"#111111\", 5, 0.30);\n      break;\n\n    case \"hot-red\":\n      addHotRedEffect(svg);\n      break;\n\n    case \"devil\":\n      addDevilEffectReference(svg);\n      break;\n\n    case \"black-out\":\n      addBlackOutEffect(svg);\n      break;\n\n    case \"white-out\":\n      addWhiteOutEffect(svg);\n      break;\n\n    case \"yellow-wolf\":\n      addYellowWolfEffectReference(svg);\n      break;\n\n    case \"yellow-cat\":\n      addYellowCatEffectReference(svg);\n      break;\n\n    case \"white-cat\":\n      addWhiteCatEffectReference(svg);\n      break;\n\n    case \"psycho\":\n      addPsychoEffectReference(svg);\n      break;\n\n    case \"spider-web\":\n      addSpiderWebEffectReference(svg);\n      break;\n\n    case \"manson\":\n      addMansonEffectReference(svg);\n      break;\n\n    case \"air-optix\":\n      addAirOptixEffect(svg, lens);\n      break;\n\n    case \"dailies\":\n      addDailiesEffect(svg, lens, false);\n      break;\n\n    case \"dailies-green\":\n      addDailiesEffect(svg, lens, true);\n      break;\n\n    case \"define-natural-shine\":\n    case \"define-vivid\":\n    case \"define-accent\":\n      addDefineEffect(svg, lens.effect, lens);\n      break;\n  }\n}\n\n\n\/* ==========================================================\n   BUTTON \/ SWATCH LOOKS\n   ========================================================== *\/\n\nfunction getLensButtonBackground(lens) {\n  switch (lens.effect) {\n\n    case \"white-out\":\n      return \"#f5f5f2\";\n\n    case \"black-out\":\n      return \"#000000\";\n\n    case \"hot-red\":\n      return \"#ff1313\";\n\n    case \"white-cat\":\n      return `\n        linear-gradient(\n          90deg,\n          #f6f6f3 0%,\n          #f6f6f3 38%,\n          #231616 38%,\n          #231616 62%,\n          #f6f6f3 62%,\n          #f6f6f3 100%\n        )\n      `;\n\n    case \"yellow-cat\":\n      return `\n        linear-gradient(\n          90deg,\n          #d8ad3d 0%,\n          #d8ad3d 38%,\n          #231616 38%,\n          #231616 62%,\n          #d8ad3d 62%,\n          #d8ad3d 100%\n        )\n      `;\n\n    case \"yellow-wolf\":\n      return `\n        radial-gradient(\n          circle,\n          #ece11b 0 36%,\n          #1d1b20 37% 100%\n        )\n      `;\n\n    case \"manson\":\n      return `\n        radial-gradient(\n          circle,\n          #f6f6f6 0 62%,\n          #000000 63% 82%,\n          #f6f6f6 83% 100%\n        )\n      `;\n\n    case \"psycho\":\n      return `\n        repeating-radial-gradient(\n          circle,\n          #000000 0 3px,\n          #ffffff 3px 7px\n        )\n      `;\n\n    case \"spider-web\":\n      return `\n        repeating-conic-gradient(\n          #000000 0deg 5deg,\n          #f7f7f7 5deg 30deg\n        )\n      `;\n\n    case \"devil\":\n      return \"#f8164d\";\n\n    default:\n      return lens.color;\n  }\n}\n\n\n\/* ==========================================================\n   NATURAL EYE\n   ========================================================== *\/\n\nconst beforeSvg = buildIrisSvg('irisBefore', 23);\nlayerBefore.appendChild(beforeSvg);\n\n\n\/* ==========================================================\n   CURRENT STATE\n   ========================================================== *\/\n\nlet currentNaturalColor = '#2e1a0f';\nlet currentLens = null;\n\n\n\/* ==========================================================\n   UPDATE WITH-LENS EYE\n   ========================================================== *\/\n\nfunction updateAfterEye() {\n  if (!currentLens) return;\n\n  const afterSvg = buildIrisSvg('irisAfter', 7);\n\n  const adaptiveStrength = getAdaptiveLensStrength(\n    currentLens,\n    currentNaturalColor\n  );\n\n  const blended = blendHex(\n    currentLens.color,\n    adaptiveStrength,\n    currentNaturalColor,\n    1 - adaptiveStrength\n  );\n\n  colorizeIris(afterSvg, blended);\n  applyLensEffect(afterSvg, currentLens);\n\n  if (currentLens.brand === \"pure-halloween\") {\n    addNaturalEyeInfluence(\n      afterSvg,\n      currentNaturalColor,\n      getNaturalRevealAmount(currentLens)\n    );\n  }\n\n  const effectLayer = afterSvg.querySelector('.lens-effect-layer');\n\n  if (effectLayer) {\n    effectLayer.setAttribute(\n      'opacity',\n      getAdaptiveEffectOpacity(currentLens, currentNaturalColor)\n    );\n  }\n\n  layerAfter.replaceChildren(afterSvg);\n}\n\n\n\/* ==========================================================\n   APPLY LENS SELECTION\n   ========================================================== *\/\n\nfunction applyLensSelection(button) {\n  if (!button) return;\n\n  colorRow.querySelectorAll('.color-btn').forEach(btn => {\n    btn.classList.remove('active');\n    btn.setAttribute('aria-pressed', 'false');\n  });\n\n  button.classList.add('active');\n  button.setAttribute('aria-pressed', 'true');\n\n  const brandKey = button.dataset.brand;\n  const index = Number(button.dataset.index);\n  const brand = LENS_BRANDS[brandKey];\n  const lens = brand.colors[index];\n\n  currentLens = {\n    ...lens,\n    brand: brandKey,\n    line: brand.line,\n    url: brand.url\n  };\n\n  updateAfterEye();\n\n  afterLabel.textContent = 'With ' + currentLens.name;\n  stripName.textContent = currentLens.name;\n  stripLine.textContent = currentLens.line;\n  stripSwatch.style.background = getLensButtonBackground(currentLens);\n  stripShop.href = currentLens.url;\n}\n\n\n\/* ==========================================================\n   COLOR SCROLLER\n   ========================================================== *\/\n\nfunction updateColorArrows() {\n  const maxScroll = colorRow.scrollWidth - colorRow.clientWidth;\n\n  colorPrev.disabled = colorRow.scrollLeft <= 2;\n  colorNext.disabled =\n    maxScroll <= 2 ||\n    colorRow.scrollLeft >= maxScroll - 2;\n}\n\n\n\/* ==========================================================\n   RENDER LENS COLORS\n   ========================================================== *\/\n\nfunction renderLensColors(brandKey) {\n  const brand = LENS_BRANDS[brandKey];\n  if (!brand) return;\n\n  colorRow.innerHTML = \"\";\n\n  brand.colors.forEach((item, index) => {\n    const button = document.createElement(\"button\");\n\n    button.type = \"button\";\n    button.className = \"color-btn\";\n    button.style.background = getLensButtonBackground(item);\n    button.dataset.brand = brandKey;\n    button.dataset.index = index;\n    button.title = item.name;\n    button.setAttribute(\"aria-label\", item.name);\n    button.setAttribute(\"aria-pressed\", \"false\");\n\n    colorRow.appendChild(button);\n  });\n\n  const firstColor = colorRow.querySelector('.color-btn');\n\n  if (firstColor) {\n    applyLensSelection(firstColor);\n  }\n\n  colorRow.scrollLeft = 0;\n  requestAnimationFrame(updateColorArrows);\n}\n\n\n\/* ==========================================================\n   BRAND BUTTONS\n   ========================================================== *\/\n\nbrandButtons.addEventListener('click', e => {\n  const button = e.target.closest('.brand-btn');\n  if (!button) return;\n\n  brandButtons.querySelectorAll('.brand-btn').forEach(btn => {\n    btn.classList.remove('active');\n    btn.setAttribute('aria-pressed', 'false');\n  });\n\n  button.classList.add('active');\n  button.setAttribute('aria-pressed', 'true');\n\n  renderLensColors(button.dataset.brand);\n});\n\n\n\/* ==========================================================\n   LENS COLOR CLICKS\n   ========================================================== *\/\n\ncolorRow.addEventListener('click', e => {\n  const button = e.target.closest('.color-btn');\n  if (!button) return;\n\n  applyLensSelection(button);\n});\n\n\n\/* ==========================================================\n   SCROLL BUTTONS\n   ========================================================== *\/\n\ncolorPrev.addEventListener('click', () => {\n  colorRow.scrollBy({\n    left: -138,\n    behavior: 'smooth'\n  });\n});\n\ncolorNext.addEventListener('click', () => {\n  colorRow.scrollBy({\n    left: 138,\n    behavior: 'smooth'\n  });\n});\n\ncolorRow.addEventListener('scroll', updateColorArrows);\n\n\n\/* ==========================================================\n   NATURAL EYE COLOR\n   ========================================================== *\/\n\nnaturalColorRow.addEventListener('click', e => {\n  const button = e.target.closest('.color-btn');\n  if (!button) return;\n\n  naturalColorRow.querySelectorAll('.color-btn').forEach(btn => {\n    btn.classList.remove('active');\n  });\n\n  button.classList.add('active');\n\n  currentNaturalColor = button.dataset.color;\n  const name = button.dataset.name;\n\n  colorizeIris(beforeSvg, currentNaturalColor);\n  updateAfterEye();\n\n  beforeLabel.textContent = 'Natural ' + name;\n});\n\n\n\/* ==========================================================\n   INITIAL STATE\n   ========================================================== *\/\n\ncolorizeIris(beforeSvg, currentNaturalColor);\nrenderLensColors('pure-halloween');\nwindow.addEventListener('resize', updateColorArrows);\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>VisionPros \u2014 Before \/ After Lens Color Preview See the Transformation Choose your natural eye color on the left, then select a colored or Halloween contact lens on the right. Drag across the eye preview to compare the before-and-after effect and see how different lens shades and designs can change the overall appearance of your [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[398],"tags":[],"semantictags":[],"class_list":["post-7347","post","type-post","status-publish","format-standard","hentry","category-cosplay"],"_links":{"self":[{"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/posts\/7347","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/comments?post=7347"}],"version-history":[{"count":23,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/posts\/7347\/revisions"}],"predecessor-version":[{"id":7572,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/posts\/7347\/revisions\/7572"}],"wp:attachment":[{"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/media?parent=7347"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/categories?post=7347"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/tags?post=7347"},{"taxonomy":"semantictags","embeddable":true,"href":"https:\/\/www.visionpros.com\/pro\/wp-json\/wp\/v2\/semantictags?post=7347"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}