{"id":2538,"date":"2026-05-23T15:30:15","date_gmt":"2026-05-23T15:30:15","guid":{"rendered":"https:\/\/millepiani.com\/trottoirs-roulants-et-escaliers-mecaniques\/"},"modified":"2026-09-15T18:19:54","modified_gmt":"2026-09-15T18:19:54","slug":"trottoirs-roulants-et-escaliers-mecaniques","status":"publish","type":"page","link":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/","title":{"rendered":"TROTTOIRS ROULANTS ET ESCALIERS M\u00c9CANIQUES"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2538\" class=\"elementor elementor-2538 elementor-340\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7d2e8cd e-con-full e-flex e-con e-parent\" data-id=\"7d2e8cd\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-954048c elementor-widget elementor-widget-html\" data-id=\"954048c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div class=\"mp-scale-page\">\r\n\r\n  <!-- HERO -->\r\n  <section class=\"mp-sm-hero\" id=\"top\">\r\n    <div class=\"mp-sm-hero-bg\"><\/div>\r\n    <div class=\"mp-sm-hero-overlay\"><\/div>\r\n\r\n    <div class=\"mp-sm-hero-content mp-reveal\">\r\n      <p class=\"mp-kicker\">Mobilit\u00e9 continue<\/p>\r\n\r\n      <h1>Tapis roulants et<br\/>escaliers m\u00e9caniques<\/h1>\r\n\r\n      <p>\r\n Solutions silencieuses, confortables et efficaces pour g\u00e9rer le flux de personnes\r\n dans les centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports, gares, m\u00e9tros et espaces publics.\r\n Installations con\u00e7ues pour la s\u00e9curit\u00e9, la continuit\u00e9 de service et une int\u00e9gration architecturale maximale.\r\n      <\/p>\r\n\r\n      <a href=\"#preventivo\" class=\"mp-outline-btn\">Demander un devis<\/a>\r\n    <\/div>\r\n\r\n    <a href=\"#linea-scale\" class=\"mp-scroll-arrow\" aria-label=\"Scorri alla sezione successiva\">\r\n      <span><\/span>\r\n    <\/a>\r\n  <\/section>\r\n\r\n\r\n  <!-- INTRO -->\r\n  <section class=\"mp-sm-intro\" id=\"linea-scale\">\r\n    <div class=\"mp-container\">\r\n\r\n      <div class=\"mp-section-heading mp-reveal\">\r\n        <p>Pourquoi choisir<\/p>\r\n        <h2>Escaliers et tapis<br\/>roulants Millepiani<\/h2>\r\n      <\/div>\r\n\r\n      <div class=\"mp-intro-text mp-reveal\">\r\n        <p>\r\n Con\u00e7us pour offrir des solutions vari\u00e9es\r\n \u00e0 des besoins de mobilit\u00e9 sp\u00e9cifiques. La gamme comprend des installations pour usage priv\u00e9\r\n et public, avec une attention particuli\u00e8re \u00e0 la s\u00e9curit\u00e9, au confort de d\u00e9placement, \u00e0 la discr\u00e9tion sonore, aux performances,\r\n \u00e0 la personnalisation esth\u00e9tique et \u00e0 la continuit\u00e9 de fonctionnement. \r\n        <\/p>\r\n      <\/div>\r\n\r\n      <div class=\"mp-features-grid\">\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M3 19h18\"><\/path>\r\n              <path d=\"M5 16h4l2-3h4l2-3h2\"><\/path>\r\n              <path d=\"M6 16v3\"><\/path>\r\n              <path d=\"M11 13v6\"><\/path>\r\n              <path d=\"M16 10v9\"><\/path>\r\n            <\/path><\/path><\/path><\/path><\/path><\/svg>\r\n          <\/span>\r\n          <h3>Silencieux<\/h3>\r\n          <p>Solutions con\u00e7ues pour offrir un confort de d\u00e9placement et une faible nuisance sonore.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M12 3l7 4v5c0 5-3.5 8-7 9-3.5-1-7-4-7-9V7l7-4z\"><\/path>\r\n              <path d=\"M9 12l2 2 4-5\"><\/path>\r\n            <\/path><\/path><\/svg>\r\n          <\/span>\r\n          <h3>S\u00fbrs<\/h3>\r\n          <p>Installations r\u00e9alis\u00e9es selon la norme EN115 et \u00e9quip\u00e9es de dispositifs de s\u00e9curit\u00e9.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M4 17c4-6 12-6 16 0\"><\/path>\r\n              <path d=\"M7 14c3-3 7-3 10 0\"><\/path>\r\n              <path d=\"M12 20h.01\"><\/path>\r\n            <\/path><\/path><\/path><\/svg>\r\n          <\/span>\r\n          <h3>Fluides<\/h3>\r\n          <p>Facilitent la circulation continue des personnes dans les environnements \u00e0 fort passage.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M13 2L4 14h7l-1 8 10-13h-7V2z\"><\/path>\r\n            <\/path><\/svg>\r\n          <\/span>\r\n          <h3>Efficaces<\/h3>\r\n          <p>Disponibles avec fonctionnement continu, Soft and Go et Stop and Go.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M4 20h16\"><\/path>\r\n              <path d=\"M7 17l10-10\"><\/path>\r\n              <path d=\"M8 7h9v9\"><\/path>\r\n            <\/path><\/path><\/path><\/svg>\r\n          <\/span>\r\n          <h3>Polyvalents<\/h3>\r\n          <p>Adapt\u00e9s aux centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports, m\u00e9tros et gares.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-feature-card mp-reveal\">\r\n          <span class=\"mp-feature-icon\">\r\n            <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M4 4h16v16H4z\"><\/path>\r\n              <path d=\"M8 8h8v8H8z\"><\/path>\r\n              <path d=\"M12 4v4\"><\/path>\r\n              <path d=\"M12 16v4\"><\/path>\r\n              <path d=\"M4 12h4\"><\/path>\r\n              <path d=\"M16 12h4\"><\/path>\r\n            <\/path><\/path><\/path><\/path><\/path><\/path><\/svg>\r\n          <\/span>\r\n          <h3>Personnalisables<\/h3>\r\n          <p>Finitions, mains courantes, balustrades, \u00e9clairages et rev\u00eatements adaptables au projet.<\/p>\r\n        <\/article>\r\n\r\n      <\/div>\r\n    <\/div>\r\n  <\/section>\r\n\r\n\r\n  <!-- 3D EXPERIENCE -->\r\n  <section class=\"mp-3d-section\" id=\"flow-experience\">\r\n    <div class=\"mp-3d-bg\"><\/div>\r\n    <div class=\"mp-3d-grid\"><\/div>\r\n\r\n    <div class=\"mp-3d-copy\">\r\n      <p id=\"mp3dKicker\">Escalier m\u00e9canique S<\/p>\r\n\r\n      <h2 id=\"mp3dTitle\">\r\n Le flux prend<br\/> forme dans l'espace\r\n      <\/h2>\r\n\r\n      <p id=\"mp3dText\">\r\n Une solution silencieuse et efficace pour les centres commerciaux, h\u00f4tels, bureaux\r\n et contextes \u00e0 trafic l\u00e9ger ou moyen.\r\n      <\/p>\r\n\r\n      <div class=\"mp-3d-tags\" id=\"mp3dTags\">\r\n        <span>Int\u00e9rieur \/ Ext\u00e9rieur<\/span>\r\n        <span>EN115<\/span>\r\n        <span>Confort<\/span>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"mp-3d-canvas-wrap\">\r\n      <canvas id=\"mpThreeEscalator\" aria-label=\"Modello 3D interattivo di scala mobile\"><\/canvas>\r\n\r\n      <div class=\"mp-3d-fallback\" id=\"mp3dFallback\">\r\n        <strong>Exp\u00e9rience 3D non disponible<\/strong>\r\n        <span>Le navigateur ne prend pas en charge WebGL ou Three.js n'a pas \u00e9t\u00e9 charg\u00e9.<\/span>\r\n      <\/div>\r\n\r\n      <button class=\"mp-3d-hotspot is-active\" type=\"button\" data-point=\"safety\" style=\"--x: 18%; --y: 63%;\">\r\n        <i><\/i>\r\n        <span>S\u00e9curit\u00e9<\/span>\r\n      <\/button>\r\n\r\n      <button class=\"mp-3d-hotspot\" type=\"button\" data-point=\"comfort\" style=\"--x: 42%; --y: 44%;\">\r\n        <i><\/i>\r\n        <span>Confort<\/span>\r\n      <\/button>\r\n\r\n      <button class=\"mp-3d-hotspot\" type=\"button\" data-point=\"design\" style=\"--x: 69%; --y: 33%;\">\r\n        <i><\/i>\r\n        <span>Design<\/span>\r\n      <\/button>\r\n\r\n      <button class=\"mp-3d-hotspot\" type=\"button\" data-point=\"operation\" style=\"--x: 78%; --y: 56%;\">\r\n        <i><\/i>\r\n        <span>Fonctionnement<\/span>\r\n      <\/button>\r\n    <\/div>\r\n\r\n    <div class=\"mp-3d-panel\">\r\n      <div class=\"mp-3d-switch\">\r\n        <button class=\"is-active\" type=\"button\" data-solution=\"s\">\r\n          <span>01<\/span>\r\n Escalier S\r\n        <\/button>\r\n\r\n        <button type=\"button\" data-solution=\"splus\">\r\n          <span>02<\/span>\r\n Escalier S+\r\n        <\/button>\r\n\r\n        <button type=\"button\" data-solution=\"st\">\r\n          <span>03<\/span>\r\n Tapis roulant ST\r\n        <\/button>\r\n      <\/div>\r\n\r\n      <div class=\"mp-3d-info-card\" id=\"mp3dInfoCard\">\r\n        <p>S\u00e9curit\u00e9<\/p>\r\n        <h3>Dispositifs int\u00e9gr\u00e9s pour utilisateurs et gestionnaires<\/h3>\r\n        <span>\r\n Les installations pr\u00e9voient des dispositifs tels qu'arr\u00eat d'urgence, contr\u00f4les sur les peignes,\r\n mains courantes, cha\u00eenes, survitesse, sens de marche et d\u00e9marcation des marches.\r\n        <\/span>\r\n      <\/div>\r\n\r\n      <div class=\"mp-3d-mode-row\">\r\n        <button class=\"is-active\" type=\"button\" data-mode=\"continuo\">Continu<\/button>\r\n        <button type=\"button\" data-mode=\"soft\">Soft and Go<\/button>\r\n        <button type=\"button\" data-mode=\"stop\">Stop and Go<\/button>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"mp-3d-dashboard\">\r\n      <div>\r\n        <span>Solution<\/span>\r\n        <strong id=\"mpDashSolution\">Escalier m\u00e9canique S<\/strong>\r\n      <\/div>\r\n\r\n      <div>\r\n        <span>Contexte<\/span>\r\n        <strong id=\"mpDashContext\">Trafic l\u00e9ger \/ moyen<\/strong>\r\n      <\/div>\r\n\r\n      <div>\r\n        <span>Modalit\u00e9<\/span>\r\n        <strong id=\"mpDashMode\">Continu<\/strong>\r\n      <\/div>\r\n    <\/div>\r\n  <\/section>\r\n\r\n\r\n  <!-- AMBITI -->\r\n  <section class=\"mp-sectors-section\">\r\n    <div class=\"mp-container\">\r\n\r\n      <div class=\"mp-sectors-heading mp-reveal\">\r\n        <p>Applications<\/p>\r\n        <h2>Solutions pour<br\/>chaque flux<\/h2>\r\n      <\/div>\r\n\r\n      <div class=\"mp-sectors-grid\">\r\n\r\n        <article class=\"mp-sector-card mp-reveal\">\r\n          <span>01<\/span>\r\n          <h3>Centres commerciaux<\/h3>\r\n          <p>Escaliers et tapis roulants pour augmenter le confort, la fluidit\u00e9 et la distribution des flux.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-sector-card mp-reveal\">\r\n          <span>02<\/span>\r\n          <h3>H\u00f4tels et bureaux<\/h3>\r\n          <p>Solutions silencieuses, efficaces et int\u00e9gr\u00e9es dans le contexte architectural.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-sector-card mp-reveal\">\r\n          <span>03<\/span>\r\n          <h3>A\u00e9roports et gares<\/h3>\r\n          <p>Installations pour trafic intense, continuit\u00e9 de service et grands volumes d'utilisateurs.<\/p>\r\n        <\/article>\r\n\r\n        <article class=\"mp-sector-card mp-reveal\">\r\n          <span>04<\/span>\r\n          <h3>M\u00e9tros<\/h3>\r\n          <p>Escaliers m\u00e9caniques S+ con\u00e7us pour les contextes publics et les conditions d'exploitation exigeantes.<\/p>\r\n        <\/article>\r\n\r\n      <\/div>\r\n    <\/div>\r\n  <\/section>\r\n\r\n<\/div>\r\n\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"><\/script>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0a7ffae elementor-widget elementor-widget-shortcode\" data-id=\"0a7ffae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><section class=\"section mp-quote-section\" id=\"preventivo\">\r\n  <div class=\"mp-quote-bg\"><\/div>\r\n  <div class=\"mp-quote-overlay\"><\/div>\r\n\r\n  <div class=\"mp-quote-inner\">\r\n    <div class=\"mp-quote-info\">\r\n      <p class=\"mp-quote-kicker\">Contactez-nous<\/p>\r\n\r\n      <h2 class=\"mp-quote-title\">\r\n        Demandez un<br>\r\n        devis<br>\r\n        gratuit\r\n      <\/h2>\r\n\r\n      <p class=\"mp-quote-description\">\r\n        Vous \u00eates int\u00e9ress\u00e9 par nos produits ou vous recherchez une solution\r\n        personnalis\u00e9e, sp\u00e9cialement con\u00e7ue pour vous ? N'h\u00e9sitez pas \u00e0\r\n        nous contacter : nous sommes \u00e0 votre disposition pour vous accompagner\r\n        et vous guider dans le choix de la solution la mieux adapt\u00e9e \u00e0 vos besoins.\r\n      <\/p>\r\n\r\n      <div class=\"mp-quote-contacts\">\r\n        <a href=\"tel:+390296690901\" class=\"mp-quote-contact\">\r\n          <span class=\"mp-quote-contact-icon\">\r\n            <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2A19.86 19.86 0 0 1 11.19 19 19.5 19.5 0 0 1 5 12.81 19.86 19.86 0 0 1 2.08 4.18 2 2 0 0 1 4.06 2h3a2 2 0 0 1 2 1.72c.12.9.33 1.78.62 2.63a2 2 0 0 1-.45 2.11L8 9.69a16 16 0 0 0 6.31 6.31l1.23-1.23a2 2 0 0 1 2.11-.45c.85.29 1.73.5 2.63.62A2 2 0 0 1 22 16.92z\"><\/path>\r\n            <\/svg>\r\n          <\/span>\r\n\r\n          <span>\r\n            <strong>T\u00e9l\u00e9phone<\/strong>\r\n            +39 02 96690901\r\n          <\/span>\r\n        <\/a>\r\n\r\n        <a href=\"mailto:info@millepiani.com\" class=\"mp-quote-contact\">\r\n          <span class=\"mp-quote-contact-icon\">\r\n            <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\"><\/path>\r\n              <path d=\"m22 6-10 7L2 6\"><\/path>\r\n            <\/svg>\r\n          <\/span>\r\n\r\n          <span>\r\n            <strong>E-mail<\/strong>\r\n            info@millepiani.com\r\n          <\/span>\r\n        <\/a>\r\n\r\n        <div class=\"mp-quote-contact\">\r\n          <span class=\"mp-quote-contact-icon\">\r\n            <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\r\n              <path d=\"M21 10c0 7-9 12-9 12S3 17 3 10a9 9 0 1 1 18 0z\"><\/path>\r\n              <circle cx=\"12\" cy=\"10\" r=\"3\"><\/circle>\r\n            <\/svg>\r\n          <\/span>\r\n\r\n          <span>\r\n            <strong>Bureau<\/strong>\r\n            Via Della Longura, 21 Misinto MB\r\n          <\/span>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"mp-quote-form-card\">\r\n      <form\r\n        class=\"mp-quote-form\"\r\n        id=\"mpQuoteForm\"\r\n        enctype=\"multipart\/form-data\"\r\n        data-success-url=\"\/grazie\/\"\r\n        novalidate\r\n      >\r\n        <div\r\n          class=\"mp-form-status\"\r\n          id=\"mpFormStatus\"\r\n          aria-live=\"polite\"\r\n        ><\/div>\r\n\r\n        <!-- Pi\u00e8ge antispam -->\r\n        <input\r\n          type=\"text\"\r\n          name=\"website\"\r\n          tabindex=\"-1\"\r\n          autocomplete=\"off\"\r\n          aria-hidden=\"true\"\r\n          style=\"position:absolute;left:-9999px;opacity:0;height:0;width:0;\"\r\n        >\r\n\r\n        <div class=\"mp-form-grid\">\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"text\"\r\n              name=\"name\"\r\n              id=\"mpName\"\r\n              placeholder=\" \"\r\n              required\r\n              autocomplete=\"given-name\"\r\n            >\r\n            <label for=\"mpName\">Pr\u00e9nom *<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"text\"\r\n              name=\"surname\"\r\n              id=\"mpSurname\"\r\n              placeholder=\" \"\r\n              required\r\n              autocomplete=\"family-name\"\r\n            >\r\n            <label for=\"mpSurname\">Nom *<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"email\"\r\n              name=\"email\"\r\n              id=\"mpEmail\"\r\n              placeholder=\" \"\r\n              required\r\n              autocomplete=\"email\"\r\n            >\r\n            <label for=\"mpEmail\">E-mail *<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"tel\"\r\n              name=\"phone\"\r\n              id=\"mpPhone\"\r\n              placeholder=\" \"\r\n              required\r\n              autocomplete=\"tel\"\r\n            >\r\n            <label for=\"mpPhone\">Num\u00e9ro de t\u00e9l\u00e9phone<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <select name=\"role\" id=\"mpRole\">\r\n              <option value=\"\" selected>S\u00e9lectionnez<\/option>\r\n              <option value=\"progettista\">Concepteur<\/option>\r\n              <option value=\"impresa_di_costruzioni\">\r\n                Entreprise de construction\r\n              <\/option>\r\n              <option value=\"proprietario_edificio\">\r\n                Propri\u00e9taire de l'immeuble\r\n              <\/option>\r\n              <option value=\"amministratore_edificio\">\r\n                Gestionnaire de l'immeuble\r\n              <\/option>\r\n              <option value=\"consulente_ascensori\">\r\n                Consultant en ascenseurs\r\n              <\/option>\r\n              <option value=\"ente_pubblico\">Organisme public<\/option>\r\n              <option value=\"cerco_lavoro\">Je recherche un emploi<\/option>\r\n              <option value=\"utente_passeggero\">\r\n                Utilisateur\/Passager\r\n              <\/option>\r\n              <option value=\"studente\">\u00c9tudiant<\/option>\r\n              <option value=\"altro\">Autre<\/option>\r\n            <\/select>\r\n\r\n            <label for=\"mpRole\">Quel est votre r\u00f4le ?<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"text\"\r\n              name=\"company\"\r\n              id=\"mpCompany\"\r\n              placeholder=\" \"\r\n              autocomplete=\"organization\"\r\n            >\r\n            <label for=\"mpCompany\">Nom de l'entreprise<\/label>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"mp-form-grid mp-location-grid\">\r\n          <div class=\"mp-field\">\r\n            <select\r\n              name=\"country\"\r\n              id=\"mpCountry\"\r\n              required\r\n              autocomplete=\"country-name\"\r\n            >\r\n              <option value=\"italia\" selected>Italie<\/option>\r\n              <option value=\"estero\">\u00c9tranger<\/option>\r\n            <\/select>\r\n\r\n            <label for=\"mpCountry\">Pays\/R\u00e9gion *<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <select\r\n              name=\"province\"\r\n              id=\"mpProvince\"\r\n              required\r\n              autocomplete=\"address-level2\"\r\n            >\r\n              <option value=\"\" selected disabled>S\u00e9lectionnez<\/option>\r\n              <option value=\"AG\">Agrigente<\/option>\r\n              <option value=\"AL\">Alexandrie<\/option>\r\n              <option value=\"AN\">Anc\u00f4ne<\/option>\r\n              <option value=\"AO\">Aoste<\/option>\r\n              <option value=\"AR\">Arezzo<\/option>\r\n              <option value=\"AP\">Ascoli Piceno<\/option>\r\n              <option value=\"AT\">Asti<\/option>\r\n              <option value=\"AV\">Avellino<\/option>\r\n              <option value=\"BA\">Bari<\/option>\r\n              <option value=\"BT\">Barletta-Andria-Trani<\/option>\r\n              <option value=\"BL\">Belluno<\/option>\r\n              <option value=\"BN\">B\u00e9n\u00e9vent<\/option>\r\n              <option value=\"BG\">Bergame<\/option>\r\n              <option value=\"BI\">Biella<\/option>\r\n              <option value=\"BO\">Bologne<\/option>\r\n              <option value=\"BZ\">Bolzano<\/option>\r\n              <option value=\"BS\">Brescia<\/option>\r\n              <option value=\"BR\">Brindisi<\/option>\r\n              <option value=\"CA\">Cagliari<\/option>\r\n              <option value=\"CL\">Caltanissetta<\/option>\r\n              <option value=\"CB\">Campobasso<\/option>\r\n              <option value=\"CE\">Caserte<\/option>\r\n              <option value=\"CT\">Catane<\/option>\r\n              <option value=\"CZ\">Catanzaro<\/option>\r\n              <option value=\"CH\">Chieti<\/option>\r\n              <option value=\"CO\">C\u00f4me<\/option>\r\n              <option value=\"CS\">Cosenza<\/option>\r\n              <option value=\"CR\">Cr\u00e9mone<\/option>\r\n              <option value=\"KR\">Crotone<\/option>\r\n              <option value=\"CN\">Coni<\/option>\r\n              <option value=\"EN\">Enna<\/option>\r\n              <option value=\"FM\">Fermo<\/option>\r\n              <option value=\"FE\">Ferrare<\/option>\r\n              <option value=\"FI\">Florence<\/option>\r\n              <option value=\"FG\">Foggia<\/option>\r\n              <option value=\"FC\">Forl\u00ec-Cesena<\/option>\r\n              <option value=\"FR\">Frosinone<\/option>\r\n              <option value=\"GE\">G\u00eanes<\/option>\r\n              <option value=\"GO\">Gorizia<\/option>\r\n              <option value=\"GR\">Grosseto<\/option>\r\n              <option value=\"IM\">Imperia<\/option>\r\n              <option value=\"IS\">Isernia<\/option>\r\n              <option value=\"SP\">La Spezia<\/option>\r\n              <option value=\"AQ\">L'Aquila<\/option>\r\n              <option value=\"LT\">Latina<\/option>\r\n              <option value=\"LE\">Lecce<\/option>\r\n              <option value=\"LC\">Lecco<\/option>\r\n              <option value=\"LI\">Livourne<\/option>\r\n              <option value=\"LO\">Lodi<\/option>\r\n              <option value=\"LU\">Lucques<\/option>\r\n              <option value=\"MC\">Macerata<\/option>\r\n              <option value=\"MN\">Mantoue<\/option>\r\n              <option value=\"MS\">Massa-Carrara<\/option>\r\n              <option value=\"MT\">Matera<\/option>\r\n              <option value=\"ME\">Messine<\/option>\r\n              <option value=\"MI\">Milan<\/option>\r\n              <option value=\"MO\">Mod\u00e8ne<\/option>\r\n              <option value=\"MB\">Monza et Brianza<\/option>\r\n              <option value=\"NA\">Naples<\/option>\r\n              <option value=\"NO\">Novare<\/option>\r\n              <option value=\"NU\">Nuoro<\/option>\r\n              <option value=\"OR\">Oristano<\/option>\r\n              <option value=\"PD\">Padoue<\/option>\r\n              <option value=\"PA\">Palerme<\/option>\r\n              <option value=\"PR\">Parme<\/option>\r\n              <option value=\"PV\">Pavie<\/option>\r\n              <option value=\"PG\">P\u00e9rouse<\/option>\r\n              <option value=\"PU\">Pesaro et Urbino<\/option>\r\n              <option value=\"PE\">Pescara<\/option>\r\n              <option value=\"PC\">Plaisance<\/option>\r\n              <option value=\"PI\">Pise<\/option>\r\n              <option value=\"PT\">Pistoia<\/option>\r\n              <option value=\"PN\">Pordenone<\/option>\r\n              <option value=\"PZ\">Potenza<\/option>\r\n              <option value=\"PO\">Prato<\/option>\r\n              <option value=\"RG\">Raguse<\/option>\r\n              <option value=\"RA\">Ravenne<\/option>\r\n              <option value=\"RC\">Reggio de Calabre<\/option>\r\n              <option value=\"RE\">Reggio d'\u00c9milie<\/option>\r\n              <option value=\"RI\">Rieti<\/option>\r\n              <option value=\"RN\">Rimini<\/option>\r\n              <option value=\"RM\">Rome<\/option>\r\n              <option value=\"RO\">Rovigo<\/option>\r\n              <option value=\"SA\">Salerne<\/option>\r\n              <option value=\"SS\">Sassari<\/option>\r\n              <option value=\"SV\">Savone<\/option>\r\n              <option value=\"SI\">Sienne<\/option>\r\n              <option value=\"SR\">Syracuse<\/option>\r\n              <option value=\"SO\">Sondrio<\/option>\r\n              <option value=\"SU\">Sardaigne du Sud<\/option>\r\n              <option value=\"TA\">Tarente<\/option>\r\n              <option value=\"TE\">Teramo<\/option>\r\n              <option value=\"TR\">Terni<\/option>\r\n              <option value=\"TO\">Turin<\/option>\r\n              <option value=\"TP\">Trapani<\/option>\r\n              <option value=\"TN\">Trente<\/option>\r\n              <option value=\"TV\">Tr\u00e9vise<\/option>\r\n              <option value=\"TS\">Trieste<\/option>\r\n              <option value=\"UD\">Udine<\/option>\r\n              <option value=\"VA\">Var\u00e8se<\/option>\r\n              <option value=\"VE\">Venise<\/option>\r\n              <option value=\"VB\">Verbano-Cusio-Ossola<\/option>\r\n              <option value=\"VC\">Verceil<\/option>\r\n              <option value=\"VR\">V\u00e9rone<\/option>\r\n              <option value=\"VV\">Vibo Valentia<\/option>\r\n              <option value=\"VI\">Vicence<\/option>\r\n              <option value=\"VT\">Viterbe<\/option>\r\n              <option value=\"ESTERO\">Province \u00e0 l'\u00e9tranger<\/option>\r\n            <\/select>\r\n\r\n            <label for=\"mpProvince\">Province *<\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-field\">\r\n            <input\r\n              type=\"text\"\r\n              name=\"city\"\r\n              id=\"mpCity\"\r\n              placeholder=\" \"\r\n              required\r\n              autocomplete=\"address-level2\"\r\n            >\r\n            <label for=\"mpCity\">Ville *<\/label>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"mp-field mp-field-full\">\r\n          <select\r\n            name=\"contact_reason\"\r\n            id=\"mpContactReason\"\r\n            required\r\n          >\r\n            <option value=\"\" selected disabled>S\u00e9lectionnez<\/option>\r\n            <option value=\"nuovo_impianto\">\r\n              Installation d'un nouvel ascenseur dans un b\u00e2timent neuf\/existant\r\n            <\/option>\r\n            <option value=\"sostituzione_ascensore\">\r\n              Remplacement d'un ascenseur existant\r\n            <\/option>\r\n            <option value=\"ammodernamento_impianto\">\r\n              Modernisation d'une installation\r\n            <\/option>\r\n            <option value=\"assistenza_manutenzione\">\r\n              Je suis int\u00e9ress\u00e9 par le service d'assistance et de maintenance\r\n            <\/option>\r\n            <option value=\"ricambi\">\r\n              Pi\u00e8ces d\u00e9tach\u00e9es pour ascenseurs Millepiani\r\n            <\/option>\r\n            <option value=\"altro\">Autre<\/option>\r\n          <\/select>\r\n\r\n          <label for=\"mpContactReason\">\r\n            Pour quel sujet souhaitez-vous \u00eatre contact\u00e9 ? *\r\n          <\/label>\r\n        <\/div>\r\n\r\n        <div class=\"mp-field mp-field-full\">\r\n          <textarea\r\n            name=\"message\"\r\n            id=\"mpMessage\"\r\n            rows=\"4\"\r\n            placeholder=\" \"\r\n          ><\/textarea>\r\n\r\n          <label for=\"mpMessage\">Comment pouvons-nous vous aider ?<\/label>\r\n        <\/div>\r\n\r\n        <div class=\"mp-form-foot\">\r\n          <div class=\"mp-privacy-box\">\r\n            <label\r\n              class=\"mp-privacy-check\"\r\n              for=\"mpPrivacyAcceptance\"\r\n            >\r\n              <input\r\n                type=\"checkbox\"\r\n                name=\"privacy_acceptance\"\r\n                id=\"mpPrivacyAcceptance\"\r\n                value=\"accepted\"\r\n                required\r\n              >\r\n\r\n              <span>\r\n                J'accepte la\r\n                <a\r\n                  href=\"\/privacy-policy\/\"\r\n                  target=\"_blank\"\r\n                  rel=\"noopener noreferrer\"\r\n                >\r\n                  Politique de confidentialit\u00e9\r\n                <\/a>. *\r\n              <\/span>\r\n            <\/label>\r\n\r\n            <label\r\n              class=\"mp-privacy-check\"\r\n              for=\"mpExistingContract\"\r\n            >\r\n              <input\r\n                type=\"checkbox\"\r\n                name=\"existing_contract\"\r\n                id=\"mpExistingContract\"\r\n                value=\"yes\"\r\n              >\r\n\r\n              <span>\r\n                J'ai d\u00e9j\u00e0 un contrat en cours avec Millepiani\r\n              <\/span>\r\n            <\/label>\r\n          <\/div>\r\n\r\n          <div class=\"mp-captcha\">\r\n            <div\r\n              class=\"g-recaptcha\"\r\n              data-sitekey=\"6LfxY6ktAAAAAFBbvnofa2IpjG_zaaX5UdOtJuTS\"\r\n            ><\/div>\r\n          <\/div>\r\n\r\n          <button type=\"submit\" class=\"mp-submit-btn\">\r\n            <span>Envoyer le message<\/span>\r\n          <\/button>\r\n        <\/div>\r\n      <\/form>\r\n    <\/div>\r\n  <\/div>\r\n<\/section><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1931b80 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-shortcode\" data-id=\"1931b80\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><script>document.documentElement.classList.add(\"mp-js-ready\");\r\n\r\ndocument.addEventListener(\"DOMContentLoaded\", function () {\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Reveal\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const revealItems = document.querySelectorAll(\".mp-reveal\");\r\n\r\n  if (\"IntersectionObserver\" in window) {\r\n    const revealObserver = new IntersectionObserver(function (entries, observer) {\r\n      entries.forEach(function (entry) {\r\n        if (!entry.isIntersecting) return;\r\n\r\n        entry.target.classList.add(\"is-visible\");\r\n        observer.unobserve(entry.target);\r\n      });\r\n    }, {\r\n      threshold: 0.16\r\n    });\r\n\r\n    revealItems.forEach(function (item) {\r\n      revealObserver.observe(item);\r\n    });\r\n  } else {\r\n    revealItems.forEach(function (item) {\r\n      item.classList.add(\"is-visible\");\r\n    });\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Smooth scroll\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  document.querySelectorAll('a[href^=\"#\"]').forEach(function (anchor) {\r\n    anchor.addEventListener(\"click\", function (event) {\r\n      const targetId = anchor.getAttribute(\"href\");\r\n\r\n      if (!targetId || targetId === \"#\") return;\r\n\r\n      const target = document.querySelector(targetId);\r\n\r\n      if (!target) return;\r\n\r\n      event.preventDefault();\r\n\r\n      target.scrollIntoView({\r\n        behavior: \"smooth\",\r\n        block: \"start\"\r\n      });\r\n    });\r\n  });\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Language\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const pageLang = (document.documentElement.lang || \"it\")\r\n    .toLowerCase()\r\n    .split(\"-\")[0];\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Technical solution data\r\n  |--------------------------------------------------------------------------\r\n  |\r\n  | Questi dati NON vengono tradotti.\r\n  | Servono esclusivamente alla logica e al modello Three.js.\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const solutionTechnicalData = {\r\n    s: {\r\n      angle: 0.34,\r\n      speed: 0.34,\r\n      isWalkway: false,\r\n      camera: {\r\n        x: 3.7,\r\n        y: 2.8,\r\n        z: 8.4\r\n      },\r\n      rotationY: -0.60\r\n    },\r\n\r\n    splus: {\r\n      angle: 0.39,\r\n      speed: 0.42,\r\n      isWalkway: false,\r\n      camera: {\r\n        x: 4.2,\r\n        y: 3.05,\r\n        z: 8.0\r\n      },\r\n      rotationY: -0.68\r\n    },\r\n\r\n    st: {\r\n      angle: 0.12,\r\n      speed: 0.24,\r\n      isWalkway: true,\r\n      camera: {\r\n        x: 3.4,\r\n        y: 2.25,\r\n        z: 8.8\r\n      },\r\n      rotationY: -0.42\r\n    }\r\n  };\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Technical mode data\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const modeTechnicalData = {\r\n    continuo: {\r\n      multiplier: 1\r\n    },\r\n\r\n    soft: {\r\n      multiplier: 0.5\r\n    },\r\n\r\n    stop: {\r\n      multiplier: 0.18\r\n    }\r\n  };\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Translations\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const escalatorTranslations = {\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | ITALIANO\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    it: {\r\n      solutions: {\r\n        s: {\r\n          kicker: \"Scala mobile S\",\r\n          title: \"Il flusso prende<br>forma nello spazio\",\r\n          text: \"Una soluzione silenziosa ed efficiente per centri commerciali, hotel, uffici e contesti con traffico leggero o medio.\",\r\n          tags: [\r\n            \"Indoor \/ Outdoor\",\r\n            \"EN115\",\r\n            \"Comfort\"\r\n          ],\r\n          dashSolution: \"Scala mobile S\",\r\n          dashContext: \"Traffico leggero \/ medio\"\r\n        },\r\n\r\n        splus: {\r\n          kicker: \"Scala mobile S+\",\r\n          title: \"Performance per<br>flussi intensi\",\r\n          text: \"Soluzione versatile e performante per condizioni di esercizio gravose, ideale per aeroporti, stazioni, metropolitane e grandi infrastrutture.\",\r\n          tags: [\r\n            \"Traffico intenso\",\r\n            \"Servizio pubblico\",\r\n            \"Outdoor\"\r\n          ],\r\n          dashSolution: \"Scala mobile S+\",\r\n          dashContext: \"Traffico intenso\"\r\n        },\r\n\r\n        st: {\r\n          kicker: \"Tappeto mobile ST\",\r\n          title: \"Il movimento<br>si distende\",\r\n          text: \"Soluzione pensata per agevolare il passaggio continuo degli utenti su percorsi dedicati e inclinati, in ambienti pubblici e commerciali.\",\r\n          tags: [\r\n            \"Tappeto ST\",\r\n            \"Flussi continui\",\r\n            \"Percorsi inclinati\"\r\n          ],\r\n          dashSolution: \"Tappeto mobile ST\",\r\n          dashContext: \"Percorsi continui\"\r\n        }\r\n      },\r\n\r\n      points: {\r\n        safety: {\r\n          label: \"Sicurezza\",\r\n          title: \"Dispositivi integrati per utenti e gestori\",\r\n          text: \"Gli impianti prevedono dispositivi come stop di emergenza, controlli sui pettini, corrimano, catene, sovravelocit\u00e0, direzione di marcia e demarcazione dei gradini.\"\r\n        },\r\n\r\n        comfort: {\r\n          label: \"Comfort\",\r\n          title: \"Movimento fluido, silenzioso e continuo\",\r\n          text: \"La progettazione \u00e8 orientata a comfort di marcia, silenziosit\u00e0 e continuit\u00e0 del flusso, anche negli ambienti ad alta percorrenza.\"\r\n        },\r\n\r\n        design: {\r\n          label: \"Design\",\r\n          title: \"Finiture integrate nell\u2019architettura\",\r\n          text: \"Balaustre, corrimano, illuminazioni, gradini, zoccolature e rivestimenti possono essere configurati per integrarsi con il progetto.\"\r\n        },\r\n\r\n        operation: {\r\n          label: \"Funzionamento\",\r\n          title: \"Continuo, Soft and Go o Stop and Go\",\r\n          text: \"Le modalit\u00e0 operative consentono di adattare l\u2019impianto al flusso reale degli utenti, con logiche pensate anche per l\u2019efficienza energetica.\"\r\n        }\r\n      },\r\n\r\n      modes: {\r\n        continuo: {\r\n          label: \"Continuo\"\r\n        },\r\n\r\n        soft: {\r\n          label: \"Soft and Go\"\r\n        },\r\n\r\n        stop: {\r\n          label: \"Stop and Go\"\r\n        }\r\n      }\r\n    },\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | ENGLISH\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    en: {\r\n      solutions: {\r\n        s: {\r\n          kicker: \"S Escalator\",\r\n          title: \"Flow takes<br>shape in space\",\r\n          text: \"A quiet and efficient solution for shopping centres, hotels, offices and environments with light to medium passenger traffic.\",\r\n          tags: [\r\n            \"Indoor \/ Outdoor\",\r\n            \"EN115\",\r\n            \"Comfort\"\r\n          ],\r\n          dashSolution: \"S Escalator\",\r\n          dashContext: \"Light \/ medium traffic\"\r\n        },\r\n\r\n        splus: {\r\n          kicker: \"S+ Escalator\",\r\n          title: \"Performance for<br>heavy traffic\",\r\n          text: \"A versatile, high-performance solution for demanding operating conditions, ideal for airports, railway stations, underground systems and major infrastructure.\",\r\n          tags: [\r\n            \"Heavy traffic\",\r\n            \"Public service\",\r\n            \"Outdoor\"\r\n          ],\r\n          dashSolution: \"S+ Escalator\",\r\n          dashContext: \"Heavy traffic\"\r\n        },\r\n\r\n        st: {\r\n          kicker: \"ST Moving Walkway\",\r\n          title: \"Movement<br>stretches out\",\r\n          text: \"A solution designed to facilitate the continuous movement of users along dedicated and inclined routes in public and commercial environments.\",\r\n          tags: [\r\n            \"ST Walkway\",\r\n            \"Continuous flow\",\r\n            \"Inclined routes\"\r\n          ],\r\n          dashSolution: \"ST Moving Walkway\",\r\n          dashContext: \"Continuous routes\"\r\n        }\r\n      },\r\n\r\n      points: {\r\n        safety: {\r\n          label: \"Safety\",\r\n          title: \"Integrated safety devices for users and operators\",\r\n          text: \"The systems include devices such as emergency stops, comb plate monitoring, handrail and chain controls, overspeed monitoring, travel direction controls and step demarcation.\"\r\n        },\r\n\r\n        comfort: {\r\n          label: \"Comfort\",\r\n          title: \"Smooth, quiet and continuous movement\",\r\n          text: \"The design focuses on ride comfort, low noise and continuous passenger flow, even in high-traffic environments.\"\r\n        },\r\n\r\n        design: {\r\n          label: \"Design\",\r\n          title: \"Finishes integrated into the architecture\",\r\n          text: \"Balustrades, handrails, lighting, steps, skirting and cladding can be configured to integrate seamlessly with the architectural project.\"\r\n        },\r\n\r\n        operation: {\r\n          label: \"Operation\",\r\n          title: \"Continuous, Soft and Go or Stop and Go\",\r\n          text: \"The operating modes allow the system to adapt to actual passenger flow, with control strategies also designed to improve energy efficiency.\"\r\n        }\r\n      },\r\n\r\n      modes: {\r\n        continuo: {\r\n          label: \"Continuous\"\r\n        },\r\n\r\n        soft: {\r\n          label: \"Soft and Go\"\r\n        },\r\n\r\n        stop: {\r\n          label: \"Stop and Go\"\r\n        }\r\n      }\r\n    },\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | FRAN\u00c7AIS\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    fr: {\r\n      solutions: {\r\n        s: {\r\n          kicker: \"Escalier m\u00e9canique S\",\r\n          title: \"Le flux prend<br>forme dans l\u2019espace\",\r\n          text: \"Une solution silencieuse et efficace pour les centres commerciaux, h\u00f4tels, bureaux et environnements \u00e0 trafic faible ou moyen.\",\r\n          tags: [\r\n            \"Int\u00e9rieur \/ Ext\u00e9rieur\",\r\n            \"EN115\",\r\n            \"Confort\"\r\n          ],\r\n          dashSolution: \"Escalier m\u00e9canique S\",\r\n          dashContext: \"Trafic faible \/ moyen\"\r\n        },\r\n\r\n        splus: {\r\n          kicker: \"Escalier m\u00e9canique S+\",\r\n          title: \"Des performances pour<br>les flux intensifs\",\r\n          text: \"Une solution polyvalente et performante pour les conditions d\u2019utilisation exigeantes, id\u00e9ale pour les a\u00e9roports, gares, m\u00e9tros et grandes infrastructures.\",\r\n          tags: [\r\n            \"Trafic intense\",\r\n            \"Service public\",\r\n            \"Ext\u00e9rieur\"\r\n          ],\r\n          dashSolution: \"Escalier m\u00e9canique S+\",\r\n          dashContext: \"Trafic intense\"\r\n        },\r\n\r\n        st: {\r\n          kicker: \"Trottoir roulant ST\",\r\n          title: \"Le mouvement<br>se prolonge\",\r\n          text: \"Une solution con\u00e7ue pour faciliter le d\u00e9placement continu des utilisateurs sur des parcours d\u00e9di\u00e9s et inclin\u00e9s, dans les espaces publics et commerciaux.\",\r\n          tags: [\r\n            \"Trottoir ST\",\r\n            \"Flux continus\",\r\n            \"Parcours inclin\u00e9s\"\r\n          ],\r\n          dashSolution: \"Trottoir roulant ST\",\r\n          dashContext: \"Parcours continus\"\r\n        }\r\n      },\r\n\r\n      points: {\r\n        safety: {\r\n          label: \"S\u00e9curit\u00e9\",\r\n          title: \"Dispositifs int\u00e9gr\u00e9s pour les utilisateurs et les exploitants\",\r\n          text: \"Les installations int\u00e8grent notamment des arr\u00eats d\u2019urgence, des contr\u00f4les des plaques \u00e0 peignes, des mains courantes, des cha\u00eenes, de la survitesse, du sens de d\u00e9placement et du marquage des marches.\"\r\n        },\r\n\r\n        comfort: {\r\n          label: \"Confort\",\r\n          title: \"Un mouvement fluide, silencieux et continu\",\r\n          text: \"La conception privil\u00e9gie le confort de d\u00e9placement, le silence de fonctionnement et la continuit\u00e9 des flux, m\u00eame dans les environnements tr\u00e8s fr\u00e9quent\u00e9s.\"\r\n        },\r\n\r\n        design: {\r\n          label: \"Design\",\r\n          title: \"Des finitions int\u00e9gr\u00e9es \u00e0 l\u2019architecture\",\r\n          text: \"Les balustrades, mains courantes, \u00e9clairages, marches, plinthes et rev\u00eatements peuvent \u00eatre configur\u00e9s afin de s\u2019int\u00e9grer au projet architectural.\"\r\n        },\r\n\r\n        operation: {\r\n          label: \"Fonctionnement\",\r\n          title: \"Continu, Soft and Go ou Stop and Go\",\r\n          text: \"Les diff\u00e9rents modes de fonctionnement permettent d\u2019adapter l\u2019installation au flux r\u00e9el des utilisateurs, avec des logiques \u00e9galement con\u00e7ues pour optimiser l\u2019efficacit\u00e9 \u00e9nerg\u00e9tique.\"\r\n        }\r\n      },\r\n\r\n      modes: {\r\n        continuo: {\r\n          label: \"Continu\"\r\n        },\r\n\r\n        soft: {\r\n          label: \"Soft and Go\"\r\n        },\r\n\r\n        stop: {\r\n          label: \"Stop and Go\"\r\n        }\r\n      }\r\n    },\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | \u0420\u0423\u0421\u0421\u041a\u0418\u0419\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    ru: {\r\n      solutions: {\r\n        s: {\r\n          kicker: \"\u042d\u0441\u043a\u0430\u043b\u0430\u0442\u043e\u0440 S\",\r\n          title: \"\u041f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0430\u0435\u0442<br>\u0444\u043e\u0440\u043c\u0443 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435\",\r\n          text: \"\u0422\u0438\u0445\u043e\u0435 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445 \u0446\u0435\u043d\u0442\u0440\u043e\u0432, \u0433\u043e\u0441\u0442\u0438\u043d\u0438\u0446, \u043e\u0444\u0438\u0441\u043e\u0432 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043d\u0438\u0437\u043a\u043e\u0439 \u0438\u043b\u0438 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0430\u0441\u0441\u0430\u0436\u0438\u0440\u043e\u043f\u043e\u0442\u043e\u043a\u0430.\",\r\n          tags: [\r\n            \"\u0412 \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u0438\u0438 \/ \u041d\u0430 \u0443\u043b\u0438\u0446\u0435\",\r\n            \"EN115\",\r\n            \"\u041a\u043e\u043c\u0444\u043e\u0440\u0442\"\r\n          ],\r\n          dashSolution: \"\u042d\u0441\u043a\u0430\u043b\u0430\u0442\u043e\u0440 S\",\r\n          dashContext: \"\u041d\u0438\u0437\u043a\u0438\u0439 \/ \u0441\u0440\u0435\u0434\u043d\u0438\u0439 \u043f\u043e\u0442\u043e\u043a\"\r\n        },\r\n\r\n        splus: {\r\n          kicker: \"\u042d\u0441\u043a\u0430\u043b\u0430\u0442\u043e\u0440 S+\",\r\n          title: \"\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<br>\u0434\u043b\u044f \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\",\r\n          text: \"\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0435 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438, \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u0434\u043b\u044f \u0430\u044d\u0440\u043e\u043f\u043e\u0440\u0442\u043e\u0432, \u0432\u043e\u043a\u0437\u0430\u043b\u043e\u0432, \u043c\u0435\u0442\u0440\u043e\u043f\u043e\u043b\u0438\u0442\u0435\u043d\u043e\u0432 \u0438 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432.\",\r\n          tags: [\r\n            \"\u0418\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a\",\r\n            \"\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\",\r\n            \"\u041d\u0430 \u0443\u043b\u0438\u0446\u0435\"\r\n          ],\r\n          dashSolution: \"\u042d\u0441\u043a\u0430\u043b\u0430\u0442\u043e\u0440 S+\",\r\n          dashContext: \"\u0418\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a\"\r\n        },\r\n\r\n        st: {\r\n          kicker: \"\u0414\u0432\u0438\u0436\u0443\u0449\u0430\u044f\u0441\u044f \u0434\u043e\u0440\u043e\u0436\u043a\u0430 ST\",\r\n          title: \"\u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435<br>\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u043c\",\r\n          text: \"\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043d\u0430\u043a\u043b\u043e\u043d\u043d\u044b\u043c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c \u0432 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430\u0445.\",\r\n          tags: [\r\n            \"\u0414\u043e\u0440\u043e\u0436\u043a\u0430 ST\",\r\n            \"\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a\",\r\n            \"\u041d\u0430\u043a\u043b\u043e\u043d\u043d\u044b\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b\"\r\n          ],\r\n          dashSolution: \"\u0414\u0432\u0438\u0436\u0443\u0449\u0430\u044f\u0441\u044f \u0434\u043e\u0440\u043e\u0436\u043a\u0430 ST\",\r\n          dashContext: \"\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b\"\r\n        }\r\n      },\r\n\r\n      points: {\r\n        safety: {\r\n          label: \"\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\",\r\n          title: \"\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432\",\r\n          text: \"\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0441\u043d\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u043a\u0430\u043a \u0430\u0432\u0430\u0440\u0438\u0439\u043d\u0430\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0433\u0440\u0435\u0431\u0451\u043d\u043e\u043a, \u043f\u043e\u0440\u0443\u0447\u043d\u0435\u0439 \u0438 \u0446\u0435\u043f\u0435\u0439, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439.\"\r\n        },\r\n\r\n        comfort: {\r\n          label: \"\u041a\u043e\u043c\u0444\u043e\u0440\u0442\",\r\n          title: \"\u041f\u043b\u0430\u0432\u043d\u043e\u0435, \u0442\u0438\u0445\u043e\u0435 \u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0435 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\",\r\n          text: \"\u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043a\u043e\u043c\u0444\u043e\u0440\u0442 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f, \u043d\u0438\u0437\u043a\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0448\u0443\u043c\u0430 \u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0441\u0442\u044c \u043f\u0430\u0441\u0441\u0430\u0436\u0438\u0440\u043e\u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u0436\u0435 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u0445 \u0441 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.\"\r\n        },\r\n\r\n        design: {\r\n          label: \"\u0414\u0438\u0437\u0430\u0439\u043d\",\r\n          title: \"\u041e\u0442\u0434\u0435\u043b\u043a\u0430, \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0432 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443\",\r\n          text: \"\u0411\u0430\u043b\u044e\u0441\u0442\u0440\u0430\u0434\u044b, \u043f\u043e\u0440\u0443\u0447\u043d\u0438, \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435, \u0441\u0442\u0443\u043f\u0435\u043d\u0438, \u0446\u043e\u043a\u043e\u043b\u0438 \u0438 \u043e\u0431\u043b\u0438\u0446\u043e\u0432\u043a\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0433\u0430\u0440\u043c\u043e\u043d\u0438\u0447\u043d\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u0442\u044c\u0441\u044f \u0441 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c.\"\r\n        },\r\n\r\n        operation: {\r\n          label: \"\u0420\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b\",\r\n          title: \"\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439, Soft and Go \u0438\u043b\u0438 Stop and Go\",\r\n          text: \"\u0420\u0435\u0436\u0438\u043c\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u0430\u0441\u0441\u0430\u0436\u0438\u0440\u043e\u043f\u043e\u0442\u043e\u043a\u0443, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u0435 \u044d\u043d\u0435\u0440\u0433\u043e\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438.\"\r\n        }\r\n      },\r\n\r\n      modes: {\r\n        continuo: {\r\n          label: \"\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439\"\r\n        },\r\n\r\n        soft: {\r\n          label: \"Soft and Go\"\r\n        },\r\n\r\n        stop: {\r\n          label: \"Stop and Go\"\r\n        }\r\n      }\r\n    }\r\n  };\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Active translations\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const activeTranslations =\r\n    escalatorTranslations[pageLang] ||\r\n    escalatorTranslations.it;\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Build solution data\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const solutions = {};\r\n\r\n  Object.keys(solutionTechnicalData).forEach(function (solutionKey) {\r\n    solutions[solutionKey] = Object.assign(\r\n      {},\r\n      solutionTechnicalData[solutionKey],\r\n      activeTranslations.solutions[solutionKey]\r\n    );\r\n  });\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Build points\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const points = activeTranslations.points;\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Build modes\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const modes = {};\r\n\r\n  Object.keys(modeTechnicalData).forEach(function (modeKey) {\r\n    modes[modeKey] = Object.assign(\r\n      {},\r\n      modeTechnicalData[modeKey],\r\n      activeTranslations.modes[modeKey]\r\n    );\r\n  });\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | DOM\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const canvas = document.querySelector(\"#mpThreeEscalator\");\r\n  const fallback = document.querySelector(\"#mp3dFallback\");\r\n\r\n  const kicker = document.querySelector(\"#mp3dKicker\");\r\n  const title = document.querySelector(\"#mp3dTitle\");\r\n  const text = document.querySelector(\"#mp3dText\");\r\n  const tags = document.querySelector(\"#mp3dTags\");\r\n\r\n  const dashSolution = document.querySelector(\"#mpDashSolution\");\r\n  const dashContext = document.querySelector(\"#mpDashContext\");\r\n  const dashMode = document.querySelector(\"#mpDashMode\");\r\n\r\n  const solutionButtons = document.querySelectorAll(\".mp-3d-switch button\");\r\n  const modeButtons = document.querySelectorAll(\".mp-3d-mode-row button\");\r\n  const hotspotButtons = document.querySelectorAll(\".mp-3d-hotspot\");\r\n  const infoCard = document.querySelector(\"#mp3dInfoCard\");\r\n\r\n  let currentSolutionKey = \"s\";\r\n  let currentModeKey = \"continuo\";\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | UI helpers\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function animateElement(element) {\r\n    if (!element) return;\r\n\r\n    element.animate([\r\n      {\r\n        opacity: 0.35,\r\n        transform: \"translateY(18px)\"\r\n      },\r\n      {\r\n        opacity: 1,\r\n        transform: \"translateY(0)\"\r\n      }\r\n    ], {\r\n      duration: 430,\r\n      easing: \"cubic-bezier(0.22, 1, 0.36, 1)\"\r\n    });\r\n  }\r\n\r\n\r\n  function setTextContent(solutionKey) {\r\n    const solution = solutions[solutionKey];\r\n\r\n    if (!solution) return;\r\n\r\n    if (kicker) {\r\n      kicker.textContent = solution.kicker;\r\n    }\r\n\r\n    if (title) {\r\n      title.innerHTML = solution.title;\r\n    }\r\n\r\n    if (text) {\r\n      text.textContent = solution.text;\r\n    }\r\n\r\n    if (tags) {\r\n      tags.innerHTML = \"\";\r\n\r\n      solution.tags.forEach(function (tag) {\r\n        const span = document.createElement(\"span\");\r\n\r\n        span.textContent = tag;\r\n\r\n        tags.appendChild(span);\r\n      });\r\n    }\r\n\r\n    if (dashSolution) {\r\n      dashSolution.textContent = solution.dashSolution;\r\n    }\r\n\r\n    if (dashContext) {\r\n      dashContext.textContent = solution.dashContext;\r\n    }\r\n\r\n    solutionButtons.forEach(function (button) {\r\n      button.classList.toggle(\r\n        \"is-active\",\r\n        button.getAttribute(\"data-solution\") === solutionKey\r\n      );\r\n    });\r\n\r\n    animateElement(\r\n      document.querySelector(\".mp-3d-copy\")\r\n    );\r\n  }\r\n\r\n\r\n  function setPoint(pointKey) {\r\n    const point = points[pointKey];\r\n\r\n    if (!point || !infoCard) return;\r\n\r\n    infoCard.innerHTML =\r\n      \"<p>\" + point.label + \"<\/p>\" +\r\n      \"<h3>\" + point.title + \"<\/h3>\" +\r\n      \"<span>\" + point.text + \"<\/span>\";\r\n\r\n    hotspotButtons.forEach(function (button) {\r\n      button.classList.toggle(\r\n        \"is-active\",\r\n        button.getAttribute(\"data-point\") === pointKey\r\n      );\r\n    });\r\n\r\n    animateElement(infoCard);\r\n  }\r\n\r\n\r\n  function setMode(modeKey) {\r\n    const mode = modes[modeKey];\r\n\r\n    if (!mode) return;\r\n\r\n    currentModeKey = modeKey;\r\n\r\n    if (dashMode) {\r\n      dashMode.textContent = mode.label;\r\n    }\r\n\r\n    modeButtons.forEach(function (button) {\r\n      button.classList.toggle(\r\n        \"is-active\",\r\n        button.getAttribute(\"data-mode\") === modeKey\r\n      );\r\n    });\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | THREE\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  let renderer;\r\n  let scene;\r\n  let camera;\r\n  let escalatorGroup;\r\n\r\n  let steps = [];\r\n  let returnSteps = [];\r\n  let handrailMarkers = [];\r\n  let lightMarkers = [];\r\n\r\n  let mouse = {\r\n    x: 0,\r\n    y: 0\r\n  };\r\n\r\n  let scrollProgress = 0;\r\n\r\n  let cameraTarget = {\r\n    x: solutions.s.camera.x,\r\n    y: solutions.s.camera.y,\r\n    z: solutions.s.camera.z\r\n  };\r\n\r\n  let modelState = {\r\n    angle: solutions.s.angle,\r\n    targetAngle: solutions.s.angle,\r\n    speed: solutions.s.speed,\r\n    targetSpeed: solutions.s.speed,\r\n    isWalkway: false,\r\n    targetWalkway: false,\r\n    rotationY: solutions.s.rotationY,\r\n    targetRotationY: solutions.s.rotationY\r\n  };\r\n\r\n\r\n  function showFallback() {\r\n    if (fallback) {\r\n      fallback.style.display = \"grid\";\r\n    }\r\n  }\r\n\r\n\r\n  function createMaterial(\r\n    color,\r\n    roughness,\r\n    metalness,\r\n    opacity,\r\n    emissive,\r\n    emissiveIntensity\r\n  ) {\r\n    const material = new THREE.MeshStandardMaterial({\r\n      color: color,\r\n      roughness: roughness,\r\n      metalness: metalness\r\n    });\r\n\r\n    if (typeof emissive !== \"undefined\") {\r\n      material.emissive = new THREE.Color(emissive);\r\n      material.emissiveIntensity = emissiveIntensity || 0;\r\n    }\r\n\r\n    if (opacity < 1) {\r\n      material.transparent = true;\r\n      material.opacity = opacity;\r\n      material.depthWrite = false;\r\n    }\r\n\r\n    return material;\r\n  }\r\n\r\n\r\n  function createBox(\r\n    width,\r\n    height,\r\n    depth,\r\n    material\r\n  ) {\r\n    const geometry = new THREE.BoxGeometry(\r\n      width,\r\n      height,\r\n      depth\r\n    );\r\n\r\n    const mesh = new THREE.Mesh(\r\n      geometry,\r\n      material\r\n    );\r\n\r\n    mesh.castShadow = true;\r\n    mesh.receiveShadow = true;\r\n\r\n    return mesh;\r\n  }\r\n\r\n\r\n  function createCylinderBetween(\r\n    start,\r\n    end,\r\n    radius,\r\n    material,\r\n    radialSegments\r\n  ) {\r\n    const direction = new THREE.Vector3()\r\n      .subVectors(end, start);\r\n\r\n    const length = direction.length();\r\n\r\n    const midpoint = new THREE.Vector3()\r\n      .addVectors(start, end)\r\n      .multiplyScalar(0.5);\r\n\r\n    const geometry = new THREE.CylinderGeometry(\r\n      radius,\r\n      radius,\r\n      length,\r\n      radialSegments || 32\r\n    );\r\n\r\n    const mesh = new THREE.Mesh(\r\n      geometry,\r\n      material\r\n    );\r\n\r\n    mesh.position.copy(midpoint);\r\n\r\n    const quaternion = new THREE.Quaternion();\r\n\r\n    quaternion.setFromUnitVectors(\r\n      new THREE.Vector3(\r\n        0,\r\n        1,\r\n        0\r\n      ),\r\n      direction.clone().normalize()\r\n    );\r\n\r\n    mesh.quaternion.copy(quaternion);\r\n\r\n    mesh.castShadow = true;\r\n    mesh.receiveShadow = true;\r\n\r\n    return mesh;\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Step\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function createStepGroup(\r\n    matTread,\r\n    matRiser,\r\n    matGroove,\r\n    matEdge\r\n  ) {\r\n    const group = new THREE.Group();\r\n\r\n    const tread = createBox(\r\n      0.46,\r\n      0.105,\r\n      1.62,\r\n      matTread\r\n    );\r\n\r\n    tread.position.y = 0.058;\r\n\r\n    group.add(tread);\r\n\r\n\r\n    const riser = createBox(\r\n      0.46,\r\n      0.18,\r\n      1.62,\r\n      matRiser\r\n    );\r\n\r\n    riser.position.set(\r\n      -0.23,\r\n      -0.045,\r\n      0\r\n    );\r\n\r\n    group.add(riser);\r\n\r\n\r\n    const frontEdge = createBox(\r\n      0.035,\r\n      0.035,\r\n      1.66,\r\n      matEdge\r\n    );\r\n\r\n    frontEdge.position.set(\r\n      -0.245,\r\n      0.125,\r\n      0\r\n    );\r\n\r\n    group.add(frontEdge);\r\n\r\n\r\n    const backEdge = createBox(\r\n      0.026,\r\n      0.026,\r\n      1.66,\r\n      matEdge\r\n    );\r\n\r\n    backEdge.position.set(\r\n      0.215,\r\n      0.122,\r\n      0\r\n    );\r\n\r\n    group.add(backEdge);\r\n\r\n\r\n    for (let i = 0; i < 11; i += 1) {\r\n      const groove = createBox(\r\n        0.008,\r\n        0.112,\r\n        1.66,\r\n        matGroove\r\n      );\r\n\r\n      groove.position.set(\r\n        -0.19 + i * 0.038,\r\n        0.118,\r\n        0\r\n      );\r\n\r\n      group.add(groove);\r\n    }\r\n\r\n    return group;\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Comb plate\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function createCombPlate(\r\n    materialDark,\r\n    materialLight\r\n  ) {\r\n    const group = new THREE.Group();\r\n\r\n    const base = createBox(\r\n      0.95,\r\n      0.065,\r\n      1.88,\r\n      materialDark\r\n    );\r\n\r\n    group.add(base);\r\n\r\n    for (let i = 0; i < 16; i += 1) {\r\n      const tooth = createBox(\r\n        0.020,\r\n        0.042,\r\n        1.82,\r\n        materialLight\r\n      );\r\n\r\n      tooth.position.x =\r\n        -0.39 +\r\n        i * 0.052;\r\n\r\n      tooth.position.y =\r\n        0.052;\r\n\r\n      group.add(tooth);\r\n    }\r\n\r\n    return group;\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Build escalator\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function buildEscalatorModel() {\r\n    const matMetal = createMaterial(\r\n      0xa8a8a8,\r\n      0.32,\r\n      0.76,\r\n      1\r\n    );\r\n\r\n    const matDarkMetal = createMaterial(\r\n      0x1a1a1a,\r\n      0.42,\r\n      0.55,\r\n      1\r\n    );\r\n\r\n    const matBlack = createMaterial(\r\n      0x050505,\r\n      0.48,\r\n      0.40,\r\n      1\r\n    );\r\n\r\n    const matStepTread = createMaterial(\r\n      0xd8d8d8,\r\n      0.24,\r\n      0.84,\r\n      1\r\n    );\r\n\r\n    const matStepRiser = createMaterial(\r\n      0x2f2f2f,\r\n      0.48,\r\n      0.48,\r\n      1\r\n    );\r\n\r\n    const matGroove = createMaterial(\r\n      0x111111,\r\n      0.55,\r\n      0.35,\r\n      1\r\n    );\r\n\r\n    const matStepEdge = createMaterial(\r\n      0xffffff,\r\n      0.18,\r\n      0.22,\r\n      1,\r\n      0xffffff,\r\n      0.18\r\n    );\r\n\r\n    const matGlass = createMaterial(\r\n      0xcbefff,\r\n      0.04,\r\n      0.02,\r\n      0.18\r\n    );\r\n\r\n    const matLight = createMaterial(\r\n      0xffffff,\r\n      0.10,\r\n      0.05,\r\n      1,\r\n      0xffffff,\r\n      0.42\r\n    );\r\n\r\n    const matSoftLight = createMaterial(\r\n      0xffffff,\r\n      0.18,\r\n      0.04,\r\n      1,\r\n      0xffffff,\r\n      0.25\r\n    );\r\n\r\n    const matFloor = createMaterial(\r\n      0x181818,\r\n      0.62,\r\n      0.18,\r\n      1\r\n    );\r\n\r\n    const matTile = createMaterial(\r\n      0x2a2a2a,\r\n      0.64,\r\n      0.12,\r\n      1\r\n    );\r\n\r\n    const matReturn = createMaterial(\r\n      0x151515,\r\n      0.54,\r\n      0.36,\r\n      1\r\n    );\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Main group\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    escalatorGroup = new THREE.Group();\r\n\r\n    scene.add(escalatorGroup);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Platforms\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const lowerPlatform = createBox(\r\n      4.4,\r\n      0.18,\r\n      3.9,\r\n      matFloor\r\n    );\r\n\r\n    lowerPlatform.position.set(\r\n      -4.15,\r\n      -1.30,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(lowerPlatform);\r\n\r\n\r\n    const upperPlatform = createBox(\r\n      4.4,\r\n      0.18,\r\n      3.9,\r\n      matFloor\r\n    );\r\n\r\n    upperPlatform.position.set(\r\n      4.15,\r\n      1.32,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(upperPlatform);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Floor details\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    for (let i = 0; i < 10; i += 1) {\r\n      const tileLow = createBox(\r\n        0.018,\r\n        0.012,\r\n        3.86,\r\n        matTile\r\n      );\r\n\r\n      tileLow.position.set(\r\n        -5.95 + i * 0.42,\r\n        -1.20,\r\n        0\r\n      );\r\n\r\n      escalatorGroup.add(tileLow);\r\n\r\n\r\n      const tileHigh = createBox(\r\n        0.018,\r\n        0.012,\r\n        3.86,\r\n        matTile\r\n      );\r\n\r\n      tileHigh.position.set(\r\n        2.35 + i * 0.42,\r\n        1.43,\r\n        0\r\n      );\r\n\r\n      escalatorGroup.add(tileHigh);\r\n    }\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Chassis\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const chassis = createBox(\r\n      8.15,\r\n      0.46,\r\n      2.72,\r\n      matDarkMetal\r\n    );\r\n\r\n    chassis.position.set(\r\n      0,\r\n      -0.07,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(chassis);\r\n\r\n\r\n    const innerBed = createBox(\r\n      7.45,\r\n      0.20,\r\n      1.86,\r\n      matBlack\r\n    );\r\n\r\n    innerBed.position.set(\r\n      0,\r\n      0.015,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(innerBed);\r\n\r\n\r\n    const returnBed = createBox(\r\n      7.35,\r\n      0.12,\r\n      1.58,\r\n      matReturn\r\n    );\r\n\r\n    returnBed.position.set(\r\n      0,\r\n      -0.34,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(returnBed);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Side structures\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const leftSide = createBox(\r\n      8.1,\r\n      0.62,\r\n      0.18,\r\n      matMetal\r\n    );\r\n\r\n    leftSide.position.set(\r\n      0,\r\n      0.22,\r\n      -1.42\r\n    );\r\n\r\n    escalatorGroup.add(leftSide);\r\n\r\n\r\n    const rightSide = createBox(\r\n      8.1,\r\n      0.62,\r\n      0.18,\r\n      matMetal\r\n    );\r\n\r\n    rightSide.position.set(\r\n      0,\r\n      0.22,\r\n      1.42\r\n    );\r\n\r\n    escalatorGroup.add(rightSide);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Glass\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const glassLeft = createBox(\r\n      7.8,\r\n      1.22,\r\n      0.05,\r\n      matGlass\r\n    );\r\n\r\n    glassLeft.position.set(\r\n      0,\r\n      0.94,\r\n      -1.22\r\n    );\r\n\r\n    escalatorGroup.add(glassLeft);\r\n\r\n\r\n    const glassRight = createBox(\r\n      7.8,\r\n      1.22,\r\n      0.05,\r\n      matGlass\r\n    );\r\n\r\n    glassRight.position.set(\r\n      0,\r\n      0.94,\r\n      1.22\r\n    );\r\n\r\n    escalatorGroup.add(glassRight);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Handrails\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const railLeft = createCylinderBetween(\r\n      new THREE.Vector3(\r\n        -3.98,\r\n        1.60,\r\n        -1.28\r\n      ),\r\n      new THREE.Vector3(\r\n        3.98,\r\n        1.60,\r\n        -1.28\r\n      ),\r\n      0.068,\r\n      matBlack,\r\n      32\r\n    );\r\n\r\n    const railRight = createCylinderBetween(\r\n      new THREE.Vector3(\r\n        -3.98,\r\n        1.60,\r\n        1.28\r\n      ),\r\n      new THREE.Vector3(\r\n        3.98,\r\n        1.60,\r\n        1.28\r\n      ),\r\n      0.068,\r\n      matBlack,\r\n      32\r\n    );\r\n\r\n    escalatorGroup.add(railLeft);\r\n    escalatorGroup.add(railRight);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Handrail markers\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    for (let i = 0; i < 10; i += 1) {\r\n      const markerLeft = createBox(\r\n        0.18,\r\n        0.018,\r\n        0.035,\r\n        matSoftLight\r\n      );\r\n\r\n      markerLeft.position.set(\r\n        -3.45 + i * 0.76,\r\n        1.68,\r\n        -1.28\r\n      );\r\n\r\n      escalatorGroup.add(markerLeft);\r\n      handrailMarkers.push(markerLeft);\r\n\r\n\r\n      const markerRight = createBox(\r\n        0.18,\r\n        0.018,\r\n        0.035,\r\n        matSoftLight\r\n      );\r\n\r\n      markerRight.position.set(\r\n        -3.45 + i * 0.76,\r\n        1.68,\r\n        1.28\r\n      );\r\n\r\n      escalatorGroup.add(markerRight);\r\n      handrailMarkers.push(markerRight);\r\n    }\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Lighting\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const lightLeftLine = createCylinderBetween(\r\n      new THREE.Vector3(\r\n        -3.55,\r\n        0.34,\r\n        -1.02\r\n      ),\r\n      new THREE.Vector3(\r\n        3.55,\r\n        0.34,\r\n        -1.02\r\n      ),\r\n      0.018,\r\n      matLight,\r\n      16\r\n    );\r\n\r\n    const lightRightLine = createCylinderBetween(\r\n      new THREE.Vector3(\r\n        -3.55,\r\n        0.34,\r\n        1.02\r\n      ),\r\n      new THREE.Vector3(\r\n        3.55,\r\n        0.34,\r\n        1.02\r\n      ),\r\n      0.018,\r\n      matLight,\r\n      16\r\n    );\r\n\r\n    escalatorGroup.add(lightLeftLine);\r\n    escalatorGroup.add(lightRightLine);\r\n\r\n\r\n    for (let i = 0; i < 8; i += 1) {\r\n      const l1 = createBox(\r\n        0.22,\r\n        0.024,\r\n        0.024,\r\n        matLight\r\n      );\r\n\r\n      l1.position.set(\r\n        -3 + i * 0.86,\r\n        0.40,\r\n        -1.02\r\n      );\r\n\r\n      escalatorGroup.add(l1);\r\n      lightMarkers.push(l1);\r\n\r\n\r\n      const l2 = createBox(\r\n        0.22,\r\n        0.024,\r\n        0.024,\r\n        matLight\r\n      );\r\n\r\n      l2.position.set(\r\n        -3 + i * 0.86,\r\n        0.40,\r\n        1.02\r\n      );\r\n\r\n      escalatorGroup.add(l2);\r\n      lightMarkers.push(l2);\r\n    }\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Comb plates\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const combLow = createCombPlate(\r\n      matDarkMetal,\r\n      matLight\r\n    );\r\n\r\n    combLow.position.set(\r\n      -3.63,\r\n      0.18,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(combLow);\r\n\r\n\r\n    const combHigh = createCombPlate(\r\n      matDarkMetal,\r\n      matLight\r\n    );\r\n\r\n    combHigh.position.set(\r\n      3.63,\r\n      0.18,\r\n      0\r\n    );\r\n\r\n    escalatorGroup.add(combHigh);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Steps\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const stepCount = 24;\r\n\r\n    for (let i = 0; i < stepCount; i += 1) {\r\n      const step = createStepGroup(\r\n        matStepTread,\r\n        matStepRiser,\r\n        matGroove,\r\n        matStepEdge\r\n      );\r\n\r\n      step.userData.progress =\r\n        i \/ stepCount;\r\n\r\n      escalatorGroup.add(step);\r\n\r\n      steps.push(step);\r\n    }\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Return steps\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    for (let i = 0; i < 14; i += 1) {\r\n      const returnStep = createBox(\r\n        0.42,\r\n        0.045,\r\n        1.54,\r\n        matReturn\r\n      );\r\n\r\n      returnStep.userData.progress =\r\n        i \/ 14;\r\n\r\n      escalatorGroup.add(returnStep);\r\n\r\n      returnSteps.push(returnStep);\r\n    }\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Model transform\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    escalatorGroup.rotation.y =\r\n      modelState.rotationY;\r\n\r\n    escalatorGroup.rotation.x =\r\n      0.12;\r\n\r\n    escalatorGroup.position.set(\r\n      1.10,\r\n      -0.18,\r\n      0\r\n    );\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Set model by solution\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function setModelBySolution(solutionKey) {\r\n    const solution = solutions[solutionKey];\r\n\r\n    if (!solution) return;\r\n\r\n    currentSolutionKey = solutionKey;\r\n\r\n    modelState.targetAngle =\r\n      solution.angle;\r\n\r\n    modelState.targetSpeed =\r\n      solution.speed;\r\n\r\n    modelState.targetWalkway =\r\n      solution.isWalkway;\r\n\r\n    modelState.targetRotationY =\r\n      solution.rotationY;\r\n\r\n    cameraTarget.x =\r\n      solution.camera.x;\r\n\r\n    cameraTarget.y =\r\n      solution.camera.y;\r\n\r\n    cameraTarget.z =\r\n      solution.camera.z;\r\n\r\n    setTextContent(solutionKey);\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Scroll progress\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function updateScrollProgress() {\r\n    const section =\r\n      document.querySelector(\".mp-3d-section\");\r\n\r\n    if (!section) return;\r\n\r\n    const rect =\r\n      section.getBoundingClientRect();\r\n\r\n    const viewport =\r\n      window.innerHeight ||\r\n      document.documentElement.clientHeight;\r\n\r\n    const total =\r\n      rect.height +\r\n      viewport;\r\n\r\n    const visible =\r\n      viewport -\r\n      rect.top;\r\n\r\n    scrollProgress =\r\n      Math.max(\r\n        0,\r\n        Math.min(\r\n          1,\r\n          visible \/ total\r\n        )\r\n      );\r\n  }\r\n\r\n  window.addEventListener(\r\n    \"scroll\",\r\n    updateScrollProgress,\r\n    {\r\n      passive: true\r\n    }\r\n  );\r\n\r\n  updateScrollProgress();\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Update step positions\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function updateStepPositions(delta) {\r\n    const modeMultiplier =\r\n      modes[currentModeKey]\r\n        ? modes[currentModeKey].multiplier\r\n        : 1;\r\n\r\n    modelState.angle +=\r\n      (\r\n        modelState.targetAngle -\r\n        modelState.angle\r\n      ) *\r\n      0.045;\r\n\r\n    modelState.speed +=\r\n      (\r\n        modelState.targetSpeed -\r\n        modelState.speed\r\n      ) *\r\n      0.045;\r\n\r\n    modelState.rotationY +=\r\n      (\r\n        modelState.targetRotationY -\r\n        modelState.rotationY\r\n      ) *\r\n      0.045;\r\n\r\n    modelState.isWalkway =\r\n      modelState.targetWalkway;\r\n\r\n    const lowerX = -3.22;\r\n    const upperX = 3.22;\r\n    const lowerY = -0.22;\r\n\r\n    const travelHeight =\r\n      modelState.isWalkway\r\n        ? 0.55\r\n        : 1.34;\r\n\r\n    const velocity =\r\n      delta *\r\n      0.000075 *\r\n      modelState.speed *\r\n      modeMultiplier;\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Visible steps\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    steps.forEach(function (step, index) {\r\n      step.userData.progress =\r\n        (\r\n          step.userData.progress +\r\n          velocity\r\n        ) %\r\n        1;\r\n\r\n      const p =\r\n        step.userData.progress;\r\n\r\n      const x =\r\n        lowerX +\r\n        (\r\n          upperX -\r\n          lowerX\r\n        ) *\r\n        p;\r\n\r\n      const y =\r\n        lowerY +\r\n        travelHeight *\r\n        p;\r\n\r\n      step.position.set(\r\n        x,\r\n        y,\r\n        0\r\n      );\r\n\r\n      const tread =\r\n        step.children[0];\r\n\r\n      const riser =\r\n        step.children[1];\r\n\r\n      const frontEdge =\r\n        step.children[2];\r\n\r\n      const backEdge =\r\n        step.children[3];\r\n\r\n\r\n      \/*\r\n      |--------------------------------------------------------------------------\r\n      | Walkway\r\n      |--------------------------------------------------------------------------\r\n      *\/\r\n\r\n      if (modelState.isWalkway) {\r\n        if (tread) {\r\n          tread.scale.x = 1.55;\r\n          tread.scale.y = 0.58;\r\n          tread.position.y = 0.035;\r\n        }\r\n\r\n        if (riser) {\r\n          riser.visible = false;\r\n        }\r\n\r\n        if (frontEdge) {\r\n          frontEdge.scale.x = 1.25;\r\n          frontEdge.position.y = 0.082;\r\n        }\r\n\r\n        if (backEdge) {\r\n          backEdge.scale.x = 1.25;\r\n          backEdge.position.y = 0.082;\r\n        }\r\n      }\r\n\r\n\r\n      \/*\r\n      |--------------------------------------------------------------------------\r\n      | Escalator\r\n      |--------------------------------------------------------------------------\r\n      *\/\r\n\r\n      else {\r\n        if (tread) {\r\n          tread.scale.x = 1;\r\n          tread.scale.y = 1;\r\n          tread.position.y = 0.058;\r\n        }\r\n\r\n        if (riser) {\r\n          riser.visible = true;\r\n          riser.scale.y = 1;\r\n        }\r\n\r\n        if (frontEdge) {\r\n          frontEdge.scale.x = 1;\r\n          frontEdge.position.y = 0.125;\r\n        }\r\n\r\n        if (backEdge) {\r\n          backEdge.scale.x = 1;\r\n          backEdge.position.y = 0.122;\r\n        }\r\n      }\r\n\r\n\r\n      \/*\r\n      |--------------------------------------------------------------------------\r\n      | Step grooves\r\n      |--------------------------------------------------------------------------\r\n      *\/\r\n\r\n      for (\r\n        let i = 4;\r\n        i < step.children.length;\r\n        i += 1\r\n      ) {\r\n        step.children[i].scale.x =\r\n          modelState.isWalkway\r\n            ? 1.45\r\n            : 1;\r\n\r\n        step.children[i].visible = true;\r\n      }\r\n\r\n      step.rotation.z = 0;\r\n\r\n      const mechanicalShift =\r\n        Math.sin(\r\n          (\r\n            p *\r\n            Math.PI *\r\n            2\r\n          ) +\r\n          index *\r\n          0.42\r\n        ) *\r\n        0.004;\r\n\r\n      step.position.z =\r\n        mechanicalShift;\r\n    });\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Return steps\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    returnSteps.forEach(function (step) {\r\n      step.userData.progress =\r\n        (\r\n          step.userData.progress -\r\n          velocity *\r\n          0.75 +\r\n          1\r\n        ) %\r\n        1;\r\n\r\n      const p =\r\n        step.userData.progress;\r\n\r\n      const x =\r\n        lowerX +\r\n        (\r\n          upperX -\r\n          lowerX\r\n        ) *\r\n        p;\r\n\r\n      const y =\r\n        -0.47 +\r\n        (\r\n          modelState.isWalkway\r\n            ? 0.12\r\n            : 0.22\r\n        ) *\r\n        p;\r\n\r\n      step.position.set(\r\n        x,\r\n        y,\r\n        0\r\n      );\r\n\r\n      step.scale.x =\r\n        modelState.isWalkway\r\n          ? 1.45\r\n          : 1;\r\n\r\n      step.visible =\r\n        !modelState.isWalkway;\r\n    });\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Handrail markers\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    handrailMarkers.forEach(function (marker, index) {\r\n      const offset =\r\n        (\r\n          (\r\n            performance.now() *\r\n            0.000013 *\r\n            modelState.speed *\r\n            modeMultiplier\r\n          ) +\r\n          index *\r\n          0.10\r\n        ) %\r\n        1;\r\n\r\n      marker.position.x =\r\n        -3.55 +\r\n        offset *\r\n        7.1;\r\n    });\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Lighting animation\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    lightMarkers.forEach(function (light, index) {\r\n      const pulse =\r\n        0.8 +\r\n        Math.sin(\r\n          performance.now() *\r\n          0.00075 +\r\n          index\r\n        ) *\r\n        0.12;\r\n\r\n      light.scale.x =\r\n        pulse;\r\n    });\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Init Three Scene\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function initThreeScene() {\r\n    if (\r\n      !canvas ||\r\n      !window.THREE\r\n    ) {\r\n      showFallback();\r\n      return;\r\n    }\r\n\r\n    scene = new THREE.Scene();\r\n\r\n    scene.fog = new THREE.FogExp2(\r\n      0x050505,\r\n      0.048\r\n    );\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Camera\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    camera = new THREE.PerspectiveCamera(\r\n      36,\r\n      1,\r\n      0.1,\r\n      100\r\n    );\r\n\r\n    camera.position.set(\r\n      cameraTarget.x,\r\n      cameraTarget.y,\r\n      cameraTarget.z\r\n    );\r\n\r\n    camera.lookAt(\r\n      0,\r\n      0.2,\r\n      0\r\n    );\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Renderer\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    renderer = new THREE.WebGLRenderer({\r\n      canvas: canvas,\r\n      antialias: true,\r\n      alpha: true,\r\n      powerPreference: \"high-performance\"\r\n    });\r\n\r\n    renderer.setPixelRatio(\r\n      Math.min(\r\n        window.devicePixelRatio || 1,\r\n        2\r\n      )\r\n    );\r\n\r\n    renderer.setClearColor(\r\n      0x000000,\r\n      0\r\n    );\r\n\r\n    renderer.shadowMap.enabled =\r\n      true;\r\n\r\n    renderer.shadowMap.type =\r\n      THREE.PCFSoftShadowMap;\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Lights\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const ambient =\r\n      new THREE.AmbientLight(\r\n        0xffffff,\r\n        0.58\r\n      );\r\n\r\n    scene.add(ambient);\r\n\r\n\r\n    const keyLight =\r\n      new THREE.DirectionalLight(\r\n        0xffffff,\r\n        1.45\r\n      );\r\n\r\n    keyLight.position.set(\r\n      4.5,\r\n      6.8,\r\n      5.5\r\n    );\r\n\r\n    keyLight.castShadow = true;\r\n\r\n    keyLight.shadow.mapSize.width =\r\n      2048;\r\n\r\n    keyLight.shadow.mapSize.height =\r\n      2048;\r\n\r\n    scene.add(keyLight);\r\n\r\n\r\n    const fillLight =\r\n      new THREE.PointLight(\r\n        0xffffff,\r\n        0.9,\r\n        14\r\n      );\r\n\r\n    fillLight.position.set(\r\n      -4.6,\r\n      2.5,\r\n      -3.6\r\n    );\r\n\r\n    scene.add(fillLight);\r\n\r\n\r\n    const rimLight =\r\n      new THREE.PointLight(\r\n        0xffffff,\r\n        1.25,\r\n        10\r\n      );\r\n\r\n    rimLight.position.set(\r\n      3.5,\r\n      2.8,\r\n      -4.2\r\n    );\r\n\r\n    scene.add(rimLight);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Shadow floor\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    const shadowFloor =\r\n      new THREE.Mesh(\r\n        new THREE.PlaneGeometry(\r\n          15,\r\n          12\r\n        ),\r\n        new THREE.ShadowMaterial({\r\n          opacity: 0.20\r\n        })\r\n      );\r\n\r\n    shadowFloor.rotation.x =\r\n      -Math.PI \/ 2;\r\n\r\n    shadowFloor.position.y =\r\n      -1.45;\r\n\r\n    shadowFloor.receiveShadow =\r\n      true;\r\n\r\n    scene.add(shadowFloor);\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Build\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    buildEscalatorModel();\r\n    resizeThree();\r\n\r\n    let lastTime =\r\n      performance.now();\r\n\r\n\r\n    \/*\r\n    |--------------------------------------------------------------------------\r\n    | Animation loop\r\n    |--------------------------------------------------------------------------\r\n    *\/\r\n\r\n    function animate(now) {\r\n      const delta =\r\n        Math.min(\r\n          33,\r\n          now - lastTime\r\n        );\r\n\r\n      lastTime = now;\r\n\r\n      updateScrollProgress();\r\n      updateStepPositions(delta);\r\n\r\n      const scrollCameraLift =\r\n        scrollProgress *\r\n        0.75;\r\n\r\n      const scrollCameraSide =\r\n        (\r\n          scrollProgress -\r\n          0.5\r\n        ) *\r\n        0.55;\r\n\r\n\r\n      \/*\r\n      |--------------------------------------------------------------------------\r\n      | Camera movement\r\n      |--------------------------------------------------------------------------\r\n      *\/\r\n\r\n      if (camera) {\r\n        camera.position.x +=\r\n          (\r\n            (\r\n              cameraTarget.x +\r\n              mouse.x *\r\n              0.22 +\r\n              scrollCameraSide\r\n            ) -\r\n            camera.position.x\r\n          ) *\r\n          0.035;\r\n\r\n        camera.position.y +=\r\n          (\r\n            (\r\n              cameraTarget.y +\r\n              mouse.y *\r\n              0.12 +\r\n              scrollCameraLift\r\n            ) -\r\n            camera.position.y\r\n          ) *\r\n          0.035;\r\n\r\n        camera.position.z +=\r\n          (\r\n            (\r\n              cameraTarget.z -\r\n              scrollProgress *\r\n              0.75\r\n            ) -\r\n            camera.position.z\r\n          ) *\r\n          0.035;\r\n\r\n        camera.lookAt(\r\n          0,\r\n          0.25 +\r\n          scrollProgress *\r\n          0.25,\r\n          0\r\n        );\r\n      }\r\n\r\n\r\n      \/*\r\n      |--------------------------------------------------------------------------\r\n      | Model movement\r\n      |--------------------------------------------------------------------------\r\n      *\/\r\n\r\n      if (escalatorGroup) {\r\n        escalatorGroup.rotation.y +=\r\n          (\r\n            (\r\n              modelState.rotationY +\r\n              mouse.x *\r\n              0.065 +\r\n              scrollProgress *\r\n              0.10\r\n            ) -\r\n            escalatorGroup.rotation.y\r\n          ) *\r\n          0.035;\r\n\r\n        escalatorGroup.rotation.x +=\r\n          (\r\n            (\r\n              0.12 +\r\n              mouse.y *\r\n              0.03\r\n            ) -\r\n            escalatorGroup.rotation.x\r\n          ) *\r\n          0.035;\r\n      }\r\n\r\n      renderer.render(\r\n        scene,\r\n        camera\r\n      );\r\n\r\n      requestAnimationFrame(\r\n        animate\r\n      );\r\n    }\r\n\r\n    requestAnimationFrame(\r\n      animate\r\n    );\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Resize Three\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  function resizeThree() {\r\n    if (\r\n      !canvas ||\r\n      !renderer ||\r\n      !camera\r\n    ) {\r\n      return;\r\n    }\r\n\r\n    const rect =\r\n      canvas.getBoundingClientRect();\r\n\r\n    if (\r\n      !rect.width ||\r\n      !rect.height\r\n    ) {\r\n      return;\r\n    }\r\n\r\n    renderer.setSize(\r\n      rect.width,\r\n      rect.height,\r\n      false\r\n    );\r\n\r\n    camera.aspect =\r\n      rect.width \/\r\n      rect.height;\r\n\r\n    camera.updateProjectionMatrix();\r\n  }\r\n\r\n  window.addEventListener(\r\n    \"resize\",\r\n    resizeThree\r\n  );\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Mouse movement\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  const canvasWrap =\r\n    document.querySelector(\r\n      \".mp-3d-canvas-wrap\"\r\n    );\r\n\r\n  if (canvasWrap) {\r\n    canvasWrap.addEventListener(\r\n      \"mousemove\",\r\n      function (event) {\r\n        const rect =\r\n          canvasWrap.getBoundingClientRect();\r\n\r\n        mouse.x =\r\n          (\r\n            (\r\n              event.clientX -\r\n              rect.left\r\n            ) \/\r\n            rect.width -\r\n            0.5\r\n          ) *\r\n          2;\r\n\r\n        mouse.y =\r\n          (\r\n            (\r\n              event.clientY -\r\n              rect.top\r\n            ) \/\r\n            rect.height -\r\n            0.5\r\n          ) *\r\n          -2;\r\n      }\r\n    );\r\n\r\n    canvasWrap.addEventListener(\r\n      \"mouseleave\",\r\n      function () {\r\n        mouse.x = 0;\r\n        mouse.y = 0;\r\n      }\r\n    );\r\n  }\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Start Three.js\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  initThreeScene();\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Controlli 3D\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  solutionButtons.forEach(function (button) {\r\n    button.addEventListener(\r\n      \"click\",\r\n      function () {\r\n        setModelBySolution(\r\n          button.getAttribute(\r\n            \"data-solution\"\r\n          )\r\n        );\r\n      }\r\n    );\r\n  });\r\n\r\n\r\n  modeButtons.forEach(function (button) {\r\n    button.addEventListener(\r\n      \"click\",\r\n      function () {\r\n        setMode(\r\n          button.getAttribute(\r\n            \"data-mode\"\r\n          )\r\n        );\r\n      }\r\n    );\r\n  });\r\n\r\n\r\n  hotspotButtons.forEach(function (button) {\r\n    button.addEventListener(\r\n      \"click\",\r\n      function () {\r\n        setPoint(\r\n          button.getAttribute(\r\n            \"data-point\"\r\n          )\r\n        );\r\n      }\r\n    );\r\n  });\r\n\r\n\r\n  \/*\r\n  |--------------------------------------------------------------------------\r\n  | Initial state\r\n  |--------------------------------------------------------------------------\r\n  *\/\r\n\r\n  setModelBySolution(\"s\");\r\n  setPoint(\"safety\");\r\n  setMode(\"continuo\");\r\n\r\n});<\/script><\/div>\n\t\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>Mobilit\u00e9 continue Tapis roulants etescaliers m\u00e9caniques Solutions silencieuses, confortables et efficaces pour g\u00e9rer le flux de personnes dans les centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports, gares, m\u00e9tros et espaces publics. Installations con\u00e7ues pour la s\u00e9curit\u00e9, la continuit\u00e9 de service et une int\u00e9gration architecturale maximale. Demander un devis Pourquoi choisir Escaliers et tapisroulants Millepiani Con\u00e7us pour offrir [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-2538","page","type-page","status-publish","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"millepiani.com -\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani\" \/>\n\t\t<meta property=\"og:description\" content=\"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-05-23T15:30:15+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-09-15T18:19:54+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani\" \/>\n\t\t<meta name=\"twitter:description\" content=\"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/#listItem\",\"name\":\"TROTTOIRS ROULANTS ET ESCALIERS M\\u00c9CANIQUES\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/#listItem\",\"position\":2,\"name\":\"TROTTOIRS ROULANTS ET ESCALIERS M\\u00c9CANIQUES\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#listItem\",\"name\":\"Home\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#organization\",\"name\":\"millepiani.com\",\"url\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/#webpage\",\"url\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/\",\"name\":\"Tapis roulants et escaliers m\\u00e9caniques sur mesure | Millepiani\",\"description\":\"D\\u00e9couvrez les trottoirs roulants et escaliers m\\u00e9caniques Millepiani pour centres commerciaux, h\\u00f4tels, bureaux, a\\u00e9roports et gares : des solutions s\\u00fbres, silencieuses et efficaces.\",\"inLanguage\":\"fr-FR\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/trottoirs-roulants-et-escaliers-mecaniques\\\/#breadcrumblist\"},\"datePublished\":\"2026-05-23T15:30:15+00:00\",\"dateModified\":\"2026-09-15T18:19:54+00:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#website\",\"url\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/\",\"name\":\"millepiani.com\",\"inLanguage\":\"fr-FR\",\"publisher\":{\"@id\":\"https:\\\/\\\/millepiani.com\\\/fr\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani","description":"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.","canonical_url":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BreadcrumbList","@id":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/millepiani.com\/fr\/#listItem","position":1,"name":"Home","item":"https:\/\/millepiani.com\/fr\/","nextItem":{"@type":"ListItem","@id":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/#listItem","name":"TROTTOIRS ROULANTS ET ESCALIERS M\u00c9CANIQUES"}},{"@type":"ListItem","@id":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/#listItem","position":2,"name":"TROTTOIRS ROULANTS ET ESCALIERS M\u00c9CANIQUES","previousItem":{"@type":"ListItem","@id":"https:\/\/millepiani.com\/fr\/#listItem","name":"Home"}}]},{"@type":"Organization","@id":"https:\/\/millepiani.com\/fr\/#organization","name":"millepiani.com","url":"https:\/\/millepiani.com\/fr\/"},{"@type":"WebPage","@id":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/#webpage","url":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/","name":"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani","description":"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.","inLanguage":"fr-FR","isPartOf":{"@id":"https:\/\/millepiani.com\/fr\/#website"},"breadcrumb":{"@id":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/#breadcrumblist"},"datePublished":"2026-05-23T15:30:15+00:00","dateModified":"2026-09-15T18:19:54+00:00"},{"@type":"WebSite","@id":"https:\/\/millepiani.com\/fr\/#website","url":"https:\/\/millepiani.com\/fr\/","name":"millepiani.com","inLanguage":"fr-FR","publisher":{"@id":"https:\/\/millepiani.com\/fr\/#organization"}}]},"og:locale":"fr_FR","og:site_name":"millepiani.com -","og:type":"article","og:title":"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani","og:description":"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.","og:url":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/","article:published_time":"2026-05-23T15:30:15+00:00","article:modified_time":"2026-09-15T18:19:54+00:00","twitter:card":"summary_large_image","twitter:title":"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani","twitter:description":"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces."},"aioseo_meta_data":{"post_id":"2538","title":"Tapis roulants et escaliers m\u00e9caniques sur mesure | Millepiani","description":"D\u00e9couvrez les trottoirs roulants et escaliers m\u00e9caniques Millepiani pour centres commerciaux, h\u00f4tels, bureaux, a\u00e9roports et gares : des solutions s\u00fbres, silencieuses et efficaces.","keywords":null,"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_image_url":null,"twitter_title":null,"twitter_description":null,"schema_type":"default","schema_type_options":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"WebPage","isEnabled":true},"graphs":[]},"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"limit_modified_date":false,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":[],"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"breadcrumb_settings":null,"seo_analyzer_scan_date":null,"created":"2026-09-14 20:23:48","updated":"2026-09-15 18:48:12","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/millepiani.com\/fr\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tTROTTOIRS ROULANTS ET ESCALIERS M\u00c9CANIQUES\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/millepiani.com\/fr\/"},{"label":"TROTTOIRS ROULANTS ET ESCALIERS M\u00c9CANIQUES","link":"https:\/\/millepiani.com\/fr\/trottoirs-roulants-et-escaliers-mecaniques\/"}],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/pages\/2538","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/comments?post=2538"}],"version-history":[{"count":4,"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/pages\/2538\/revisions"}],"predecessor-version":[{"id":2581,"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/pages\/2538\/revisions\/2581"}],"wp:attachment":[{"href":"https:\/\/millepiani.com\/fr\/wp-json\/wp\/v2\/media?parent=2538"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}