{"id":8698,"date":"2026-03-18T12:45:56","date_gmt":"2026-03-18T16:45:56","guid":{"rendered":"https:\/\/cfcquebec.ca\/?page_id=8698"},"modified":"2026-03-18T12:47:58","modified_gmt":"2026-03-18T16:47:58","slug":"app-color-test","status":"publish","type":"page","link":"https:\/\/cfcquebec.ca\/en\/app-color-test\/","title":{"rendered":"app-color-test"},"content":{"rendered":"<div class=\"fusion-fullwidth fullwidth-box fusion-builder-row-1 fusion-flex-container has-pattern-background has-mask-background nonhundred-percent-fullwidth non-hundred-percent-height-scrolling\" style=\"--awb-border-radius-top-left:0px;--awb-border-radius-top-right:0px;--awb-border-radius-bottom-right:0px;--awb-border-radius-bottom-left:0px;--awb-flex-wrap:wrap;\" ><div class=\"fusion-builder-row fusion-row fusion-flex-align-items-flex-start fusion-flex-content-wrap\" style=\"max-width:2059.2px;margin-left: calc(-4% \/ 2 );margin-right: calc(-4% \/ 2 );\"><div class=\"fusion-layout-column fusion_builder_column fusion-builder-column-0 fusion_builder_column_1_1 1_1 fusion-flex-column\" style=\"--awb-bg-size:cover;--awb-width-large:100%;--awb-margin-top-large:0px;--awb-spacing-right-large:1.92%;--awb-margin-bottom-large:20px;--awb-spacing-left-large:1.92%;--awb-width-medium:100%;--awb-order-medium:0;--awb-spacing-right-medium:1.92%;--awb-spacing-left-medium:1.92%;--awb-width-small:100%;--awb-order-small:0;--awb-spacing-right-small:1.92%;--awb-spacing-left-small:1.92%;\"><div class=\"fusion-column-wrapper fusion-column-has-shadow fusion-flex-justify-content-flex-start fusion-content-layout-column\"><!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\" \/>\n\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" \/>\n  <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\" \/>\n  <meta name=\"theme-color\" content=\"#f4efe9\" \/>\n  <meta name=\"mobile-web-app-capable\" content=\"yes\" \/>\n  <link rel=\"manifest\" href=\"\/site.webmanifest?v=3\" \/>\n  <link rel=\"apple-touch-icon\" href=\"\/icons\/apple-touch-icon-v3.png\" \/>\n\n  <title>Cl\u00f4tur\u00e9o<\/title>\n  <style>\n    :root{\n  --bg:#ece5dc;\n  --phone:#f4efe8;\n  --card1:#fffdfa;\n  --card2:#f4ede5;\n  --dark:#101011;\n  --dark2:#2a1114;\n  --accent:#8f1d22;\n  --muted:#756b62;\n  --line:rgba(0,0,0,.08);\n  --white:#fff;\n  --shadow:0 18px 40px rgba(32,22,18,.10);\n  --heroShadow:0 14px 28px rgba(143,29,34,.22);\n}\n\n*{box-sizing:border-box}\n\nhtml, body{\n  margin:0;\n  min-height:100vh;\n  overflow-x:hidden;\n  touch-action:manipulation;\n}\n\nbody{\n  background:linear-gradient(135deg,#d9d1c8,#ece5dc 40%,#ddd7cf);\n  font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;\n  color:#171717;\n}\n\ninput,\ntextarea,\nselect,\n.input,\n.textarea{\n  font-size:16px !important;\n  -webkit-text-size-adjust:100%;\n}\n\n.top-bar{min-width:0; width:100%}\n.top-bar > *{min-width:0}\n.state-switch{width:auto; max-width:100%; min-width:0; flex:1 1 auto}\n\n.wrap{\n  width:100%;\n  min-height:100vh;\n  display:flex;\n  justify-content:center;\n  align-items:center;\n  padding:24px 0;\n}\n\n.phone{\n  width:100%;\n  max-width:100%;\n  min-height:844px;\n  margin:0;\n  background:var(--phone);\n  border-radius:0 !important;\n  overflow:hidden;\n  position:relative;\n  border:1px solid rgba(255,255,255,.45);\n  box-shadow:0 36px 90px rgba(20,14,12,.24);\n}\n    .top-glow{\n      position:absolute; inset:0 0 auto 0; height:164px;\n      background:linear-gradient(180deg,var(--dark),var(--dark2),transparent);\n      opacity:.98; pointer-events:none;\n    }\n    .screen{padding:18px 20px 152px; position:relative; z-index:1}\n    .header{display:flex; align-items:center; justify-content:space-between; margin-bottom:18px; padding-top:4px}\n    .eyebrow{font-size:11px; letter-spacing:.32em; text-transform:uppercase; color:rgba(255,255,255,.72)}\n    .title{font-size:28px; font-weight:800; color:#fff; margin-top:6px}\n    .header-actions{display:flex; gap:8px}\n    .pill,.icon-btn,.ghost-btn{\n      border:none; cursor:pointer; background:rgba(255,255,255,.82);\n      backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);\n      border-radius:18px; box-shadow:var(--shadow); color:#222;\n    }\n    .pill{height:44px; padding:0 14px; display:flex; align-items:center; gap:8px; font-weight:600}\n    .icon-btn{width:44px; height:44px; display:grid; place-items:center}\n    .ghost-btn{height:40px; padding:0 12px; font-weight:700; font-size:13px}\n    .card{\n      background:linear-gradient(135deg,var(--card1),var(--card2));\n      border:1px solid var(--line); border-radius:30px; padding:18px; box-shadow:var(--shadow); margin-bottom:16px;\n    }\n    .tag{\n      display:inline-flex; align-items:center; gap:8px; color:var(--accent); background:rgba(143,29,34,.10);\n      border-radius:999px; padding:8px 12px; font-size:13px; font-weight:700; margin-bottom:12px;\n    }\n    .hero h2{margin:0 0 8px; font-size:32px; line-height:1.03}\n    .hero p{margin:0 0 16px; color:#5f574f; line-height:1.6; font-size:14px}\n    .btn{\n      width:100%; height:56px; border:none; cursor:pointer; border-radius:18px;\n      font-size:16px; font-weight:700; transition:transform .14s ease,opacity .14s ease;\n    }\n    .btn:active{transform:scale(.99)}\n    .btn-primary{background:var(--accent); color:#fff; box-shadow:var(--heroShadow)}\n    .btn-dark{background:#141414; color:#fff; box-shadow:0 12px 24px rgba(0,0,0,.18)}\n    .btn-light{background:#fff; color:#111}\n    .btn-soft{background:#ebe4db; color:#111}\n    .stack > * + *{margin-top:12px}\n    .grid-2{display:grid; grid-template-columns:1fr 1fr; gap:14px}\n    .mini-card{\n      background:linear-gradient(135deg,#fffdfa,#f3ece4);\n      border:1px solid var(--line); border-radius:26px; padding:16px; box-shadow:var(--shadow);\n      min-height:128px; cursor:pointer;\n    }\n\t.hero .grid-2 .btn{\n  height:auto !important;\n  min-height:72px;\n  line-height:1 !important;\n  overflow:visible !important;\n}\n    .mini-card .icon{font-size:24px; margin-bottom:10px}\n    .mini-card h4{margin:0; font-size:16px}\n    .mini-card p{margin:6px 0 0; color:#6b625a; font-size:13px; line-height:1.45}\n    .section-row{display:flex; align-items:center; justify-content:space-between; margin:10px 0 12px}\n    .section-row h3{margin:0; font-size:18px}\n    .linkish{background:none; border:none; color:var(--accent); font-weight:700; cursor:pointer}\n    .summary-box{\n      border-radius:20px; padding:14px; background:linear-gradient(135deg,#f3ede6,#e8ddd2); border:1px solid rgba(255,255,255,.55)\n    }\n    .summary-box small{display:block; color:#70665e; margin-bottom:4px}\n    .thumbs{display:grid; grid-template-columns:repeat(3,1fr); gap:12px}\n    .thumb{height:82px; border-radius:18px; background:linear-gradient(135deg,#eadfd5,#ddd0c3); border:1px solid rgba(255,255,255,.5)}\n    .timeline-item{display:flex; gap:12px; padding:12px 0}\n    .dot{width:14px; height:14px; border-radius:50%; margin-top:5px; background:#d0c7be}\n    .dot.done{background:var(--accent)}\n    .timeline-item strong{display:block}\n    .muted{color:var(--muted); font-size:13px}\n    .nav{\n      position:absolute; left:0; right:0; bottom:0; z-index:20;\n      padding:10px 12px 14px;\n      background:linear-gradient(180deg,rgba(250,247,244,.52),rgba(244,238,232,.78));\n      backdrop-filter:blur(22px) saturate(1.15); -webkit-backdrop-filter:blur(22px) saturate(1.15);\n      border-top:1px solid rgba(255,255,255,.62);\n      box-shadow:0 -8px 24px rgba(24,18,14,.08), inset 0 1px 0 rgba(255,255,255,.55);\n    }\n    .nav-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:9px}\n    .nav-btn{\n      position:relative;\n      isolation:isolate;\n      aspect-ratio:1 \/ 1;\n      width:100%;\n      min-height:74px;\n      border-radius:18px;\n      border:1px solid rgba(255,255,255,.50);\n      background:linear-gradient(180deg,rgba(255,255,255,.58),rgba(245,240,235,.34));\n      box-shadow:\n        inset 0 1px 0 rgba(255,255,255,.62),\n        inset 0 -1px 0 rgba(255,255,255,.16),\n        0 8px 20px rgba(22,16,12,.08);\n      cursor:pointer;\n      color:#5e5650;\n      display:flex;\n      flex-direction:column;\n      align-items:center;\n      justify-content:center;\n      gap:7px;\n      padding:8px 4px;\n      font-size:11px;\n      font-weight:700;\n      letter-spacing:.01em;\n      transition:transform .14s ease, box-shadow .16s ease, border-color .16s ease, background .16s ease, color .16s ease;\n      -webkit-tap-highlight-color:transparent;\n      overflow:hidden;\n    }\n    .nav-btn::before{\n      content:\"\";\n      position:absolute;\n      inset:0;\n      border-radius:inherit;\n      background:linear-gradient(180deg,rgba(255,255,255,.34),rgba(255,255,255,0) 42%, rgba(255,255,255,.10));\n      pointer-events:none;\n      z-index:-1;\n    }\n    .nav-btn:active{\n      transform:scale(.975);\n      box-shadow:\n        inset 0 1px 0 rgba(255,255,255,.45),\n        inset 0 -1px 0 rgba(255,255,255,.10),\n        0 4px 12px rgba(22,16,12,.09);\n    }\n    .nav-btn .nav-icon{\n      width:32px;\n      height:32px;\n      display:grid;\n      place-items:center;\n      border-radius:12px;\n      font-size:18px;\n      line-height:1;\n      background:rgba(255,255,255,.34);\n      box-shadow:inset 0 1px 0 rgba(255,255,255,.55);\n      border:1px solid rgba(255,255,255,.35);\n    }\n    .nav-btn .nav-label{\n      line-height:1.08;\n      text-align:center;\n      display:block;\n      font-size:10.5px;\n    }\n    .nav-btn.active{\n      color:#7f1219;\n      border-color:rgba(143,29,34,.18);\n      background:linear-gradient(180deg,rgba(255,255,255,.72),rgba(143,29,34,.10));\n      box-shadow:\n        inset 0 1px 0 rgba(255,255,255,.65),\n        inset 0 -1px 0 rgba(255,255,255,.12),\n        0 10px 24px rgba(143,29,34,.12);\n    }\n    .nav-btn.active .nav-icon{\n      background:rgba(143,29,34,.11);\n      border-color:rgba(143,29,34,.14);\n      color:#8f1d22;\n    }\n    .hidden{display:none}\n    .fade{animation:fade .18s ease}\n    @keyframes fade{from{opacity:0; transform:translateY(8px)} to{opacity:1; transform:none}}\n    .desktop-note{\n      position:fixed; left:16px; bottom:16px; background:rgba(255,255,255,.75); backdrop-filter:blur(10px);\n      border:1px solid rgba(0,0,0,.06); border-radius:16px; padding:10px 12px; font-size:13px; color:#564f49;\n      box-shadow:var(--shadow);\n    }\n    .tabs{display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-bottom:14px}\n    .tab{\n      border:none; cursor:pointer; height:42px; border-radius:16px; font-weight:800; font-size:14px;\n      background:#ebe4db; color:#3d3630;\n    }\n    .tab.active{background:var(--accent); color:#fff}\n    .input{\n      width:100%; height:50px; border-radius:18px; border:1px solid var(--line);\n      padding:0 16px; background:#f7f2eb; font-size:15px;\n    }\n    .textarea{\n      width:100%; min-height:132px; border-radius:22px; border:1px solid var(--line);\n      padding:14px 16px; background:#f7f2eb; font-size:15px; resize:none; font-family:inherit; line-height:1.5;\n    }\n    .input-row > * + *{margin-top:12px}\n    .field-row{position:relative}\n    .toggle-pass{\n      position:absolute; right:10px; top:9px; border:none; background:#fff; height:32px; padding:0 10px;\n      border-radius:12px; font-weight:700; cursor:pointer; color:#4a4039; box-shadow:0 4px 10px rgba(0,0,0,.06)\n    }\n    .notice{\n      margin-top:12px; padding:12px 14px; border-radius:16px; font-size:13px; line-height:1.45;\n      background:#f6eee5; color:#5a4e45; border:1px solid rgba(0,0,0,.06);\n    }\n    .error{background:#fff1f1; color:#8a2222}\n    .success{background:#eef8ef; color:#245c2f}\n    .top-bar{display:grid; grid-template-columns:auto minmax(0,1fr); gap:8px; align-items:center; margin-bottom:12px; width:100%}\n    .state-switch{\n      width:100%; max-width:100%; min-width:0; height:42px; border:none; border-radius:16px; padding:0 12px; background:#fff; box-shadow:var(--shadow);\n      font-weight:700; color:#413831;\n    }\n    .signed-in-badge{\n      min-width:0; flex-shrink:0;\n      display:inline-flex; align-items:center; gap:8px; padding:8px 12px; border-radius:999px;\n      background:rgba(143,29,34,.10); color:var(--accent); font-weight:700; font-size:13px;\n    }\n    .overlay{\n      position:absolute; inset:0; background:rgba(12,10,9,.32);\n      backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);\n      z-index:20; display:none;\n    }\n    .overlay.show{display:block}\n    .sheet{\n      position:absolute; left:12px; right:12px; bottom:84px;\n      background:linear-gradient(135deg,#fffdfa,#f4ede5);\n      border:1px solid rgba(0,0,0,.08);\n      border-radius:28px; box-shadow:0 28px 60px rgba(20,14,12,.24);\n      padding:16px; z-index:21; display:none;\n    }\n    .sheet.show{display:block; animation:sheetUp .18s ease}\n    @keyframes sheetUp{from{opacity:0; transform:translateY(12px)} to{opacity:1; transform:none}}\n    .sheet-head{display:flex; align-items:start; justify-content:space-between; gap:12px; margin-bottom:12px}\n    .sheet-head h3{margin:0; font-size:20px}\n    .sheet-head p{margin:6px 0 0; color:#6b625a; font-size:13px; line-height:1.5}\n    .sheet-close{\n      width:38px; height:38px; border:none; border-radius:14px; background:#fff; cursor:pointer;\n      box-shadow:0 8px 20px rgba(0,0,0,.06); font-size:18px;\n    }\n    .sheet-grid{display:grid; grid-template-columns:1fr 1fr; gap:10px}\n    .sheet-action{\n      border:none; background:#fff; border-radius:22px; padding:14px; text-align:left; cursor:pointer;\n      box-shadow:0 8px 20px rgba(0,0,0,.06); border:1px solid rgba(0,0,0,.06);\n      min-height:110px;\n    }\n    .sheet-action .icon{font-size:22px; margin-bottom:10px}\n    .sheet-action .title{font-size:15px; font-weight:800; color:#1f1a17; margin:0}\n    .sheet-action .sub{font-size:12px; color:#6b625a; line-height:1.45; margin-top:6px}\n  \n    .upload-drop{\n      height:192px; display:grid; place-items:center; text-align:center; cursor:pointer;\n      background:linear-gradient(135deg,#f7f2eb,#fff); border:2px dashed rgba(143,29,34,.18);\n      transition:border-color .14s ease, transform .14s ease, box-shadow .14s ease;\n    }\n    .upload-drop:hover{border-color:rgba(143,29,34,.38)}\n    .upload-meta{margin-top:10px}\n    .thumb{\n      position:relative; overflow:hidden; background:linear-gradient(135deg,#eadfd5,#ddd0c3);\n      border:1px solid rgba(255,255,255,.5); display:grid; place-items:center; color:#7a6d63; font-size:12px;\n    }\n    .thumb img{width:100%; height:100%; object-fit:cover; display:block}\n    .thumb-remove{\n      position:absolute; top:6px; right:6px; width:24px; height:24px; border:none; border-radius:999px;\n      background:rgba(16,16,17,.78); color:#fff; cursor:pointer; font-weight:800; line-height:1;\n    }\n    .thumb-empty{opacity:.65}\n    .helper-row{display:flex; gap:10px; margin-top:12px}\n    .helper-row .btn{height:48px}\n\n\n    .input-readonly{\n      background:#f0e9e0;\n      color:#5b5148;\n    }\n    .field-help{\n      margin:8px 2px 0;\n      color:#6f655c;\n      font-size:12px;\n      line-height:1.45;\n    }\n\n\n    @keyframes cfcBlinkPrice{\n      0%,100%{opacity:1;transform:scale(1)}\n      50%{opacity:.6;transform:scale(1.04)}\n    }\n    .cfc-quote-price-alert{\n      color:#f59e0b;\n      font-weight:800;\n      animation:cfcBlinkPrice 1.4s ease-in-out infinite;\n    }\n    .overlay{\n      position:fixed; inset:0; background:rgba(16,16,17,.46); backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);\n      display:none; align-items:center; justify-content:center; z-index:60; padding:18px;\n    }\n    .overlay.show{display:flex}\n    .overlay-card{\n      width:min(360px,100%); border-radius:28px; padding:20px; background:linear-gradient(135deg,#fffdfa,#f4ede5);\n      box-shadow:0 24px 70px rgba(20,14,12,.28); border:1px solid rgba(0,0,0,.08);\n    }\n    .overlay-card h3{margin:0 0 8px;font-size:28px;line-height:1.03}\n    .overlay-card p{margin:0;color:#5f574f;line-height:1.55;font-size:14px}\n    .center-laterally {\n      display:flex;\n      justify-content:center;\n      align-items:stretch;\n    }\n  <\/style>\n<\/head>\n<body data-rsssl=1>\n  <div class=\"wrap\">\n    <div class=\"phone\">\n      <div class=\"top-glow\"><\/div>\n      <div class=\"screen\">\n        <div class=\"header\">\n          <div>\n            <div class=\"eyebrow\">Cl\u00f4tur\u00e9o<\/div>\n            <div class=\"title\" id=\"headerTitle\">Connexion<\/div>\n            <div class=\"muted\" id=\"headerSubline\" style=\"color:rgba(255,255,255,.72);margin-top:6px;font-size:12px\"><\/div>\n          <\/div>\n          <div class=\"header-actions\">\n                        <button class=\"icon-btn\" id=\"authActionBtn\" onclick=\"openAuth()\">\ud83d\udc64<\/button>\n          <\/div>\n        <\/div>\n\n        <section id=\"auth\" class=\"view fade\">\n          <div class=\"card hero\">\n            <div class=\"tag\">\u2726 <span id=\"authTagline\">Cr\u00e9ez votre compte une seule fois<\/span><\/div>\n            <h2 id=\"authHero\">Connexion ou cr\u00e9ation de compte<\/h2>\n            <p id=\"authSubhero\">Confirmez votre identit\u00e9 localement dans ce prototype, puis acc\u00e9dez directement \u00e0 votre tableau de bord.<\/p>\n\n            <div class=\"tabs\">\n              <button class=\"tab active\" id=\"tabSignIn\" onclick=\"setAuthMode('signin')\">Connexion<\/button>\n              <button class=\"tab\" id=\"tabCreate\" onclick=\"setAuthMode('create')\">Cr\u00e9er un compte<\/button>\n            <\/div>\n\n            <div id=\"signinFields\" class=\"input-row\">\n              <input\n  class=\"input\"\n  id=\"signinEmail\"\n  type=\"email\"\n  inputmode=\"email\"\n  autocomplete=\"email\"\n  autocapitalize=\"off\"\n  autocorrect=\"off\"\n  spellcheck=\"false\"\n  placeholder=\"Courriel\" \/>\n              <div class=\"field-row\">\n                <input class=\"input\" id=\"signinPassword\" type=\"password\" placeholder=\"Mot de passe\" \/>\n                <button class=\"toggle-pass\" onclick=\"togglePassword('signinPassword', this)\">Voir<\/button>\n              <\/div>\n              <button class=\"btn btn-primary\" onclick=\"signIn()\" id=\"signinBtn\">Se connecter<\/button>\n            <\/div>\n\n            <div id=\"createFields\" class=\"input-row hidden\">\n              <input class=\"input\" id=\"createName\" placeholder=\"Pr\u00e9nom\" \/>\n              <input\n  class=\"input\"\n  id=\"createEmail\"\n  type=\"email\"\n  inputmode=\"email\"\n  autocomplete=\"email\"\n  autocapitalize=\"off\"\n  autocorrect=\"off\"\n  spellcheck=\"false\"\n  placeholder=\"Courriel\" \/>\n              <div class=\"field-row\">\n                <input class=\"input\" id=\"createPassword\" type=\"password\" placeholder=\"Mot de passe\" \/>\n                <button class=\"toggle-pass\" onclick=\"togglePassword('createPassword', this)\">Voir<\/button>\n              <\/div>\n              <div class=\"field-row\">\n                <input class=\"input\" id=\"createPassword2\" type=\"password\" placeholder=\"Confirmer le mot de passe\" \/>\n                <button class=\"toggle-pass\" onclick=\"togglePassword('createPassword2', this)\">Voir<\/button>\n              <\/div>\n              <button class=\"btn btn-primary\" onclick=\"createAccount()\" id=\"createBtn\">Cr\u00e9er mon compte<\/button>\n            <\/div>\n\n            <button class=\"btn btn-dark\" style=\"margin-top:12px\" onclick=\"quickGoogle()\" id=\"googleBtn\">Continuer avec Google<\/button>\n            <div class=\"notice\" id=\"authNotice\">Utilisez votre courriel et mot de passe pour acc\u00e9der \u00e0 Cl\u00f4tur\u00e9o.<\/div>\n          <\/div>\n        <\/section>\n\n        <section id=\"confirm\" class=\"view hidden fade\">\n          <div class=\"card hero\">\n            <div class=\"tag\">\u2709 <span id=\"confirmTag\">Confirmez votre courriel<\/span><\/div>\n            <h2 id=\"confirmHero\">V\u00e9rifiez votre bo\u00eete de r\u00e9ception<\/h2>\n            <p id=\"confirmSubhero\">Un lien de confirmation a \u00e9t\u00e9 envoy\u00e9. Confirmez votre courriel avant d\u2019entrer dans l\u2019application.<\/p>\n            <div class=\"summary-box\" style=\"margin-bottom:14px\">\n              <small id=\"confirmSentToLabel\">Courriel envoy\u00e9 \u00e0<\/small>\n              <strong id=\"confirmEmailValue\">martin@exemple.com<\/strong>\n            <\/div>\n            <div class=\"grid-2\" style=\"margin-bottom:12px\">\n              <button class=\"btn btn-light\" onclick=\"openInbox()\" id=\"openInboxBtn\">Ouvrir mon courriel<\/button>\n              <button class=\"btn btn-soft\" onclick=\"changeEmail()\" id=\"changeEmailBtn\">Changer d\u2019adresse<\/button>\n            <\/div>\n            <div class=\"stack\">\n              <button class=\"btn btn-primary\" onclick=\"confirmEmail()\" id=\"confirmBtn\">J\u2019ai confirm\u00e9 mon courriel<\/button>\n              <button class=\"btn btn-soft\" onclick=\"resendConfirmation()\" id=\"resendBtn\">Renvoyer le lien<\/button>\n              <button class=\"btn btn-dark\" onclick=\"go('auth')\" id=\"backToAuthBtn\">Retour \u00e0 la connexion<\/button>\n            <\/div>\n            <div class=\"notice\" id=\"confirmNotice\">Apr\u00e8s confirmation, cliquez sur le bouton ci-dessus pour continuer.<\/div>\n          <\/div>\n        <\/section>\n\n        <section id=\"home\" class=\"view hidden fade\">\n          <div class=\"top-bar\">\n            <div class=\"signed-in-badge\" id=\"signedInBadge\">\u2713 Connect\u00e9<\/div>\n            <select class=\"state-switch\" id=\"stateSwitch\" onchange=\"setDashboardState(this.value)\">\n              <option value=\"new\">Nouvel utilisateur<\/option>\n              <option value=\"progress\">Projet en pr\u00e9paration<\/option>\n              <option value=\"submitted\">Demande envoy\u00e9e<\/option>\n              <option value=\"quote\">Soumission re\u00e7ue<\/option>\n            <\/select>\n          <\/div>\n\n          <div class=\"card\" id=\"dashboardTopCard\"><\/div>\n          <div class=\"card\" id=\"dashboardMainCard\"><\/div>\n          <div class=\"grid-2\" id=\"dashboardQuickCards\"><\/div>\n          <div class=\"card\" id=\"dashboardActionsCard\"><\/div>\n          <div class=\"card\" id=\"dashboardHistoryCard\"><\/div>\n          <div class=\"card\" id=\"dashboardAccountCard\" style=\"padding:14px\"><\/div>\n        <\/section>\n\n        <section id=\"project\" class=\"view hidden fade\">\n          <div class=\"card\">\n            <h2 id=\"projectTitle\" style=\"margin:0 0 14px\">D\u00e9tails du projet<\/h2>\n            <div class=\"summary-box\" style=\"margin-bottom:14px\">\n              <small id=\"projectTypeLabel\">Type de cl\u00f4ture<\/small>\n              <select class=\"input\" id=\"fenceTypeSelect\" onchange=\"changeFenceType(this.value)\" style=\"margin-top:8px\">\n                <option value=\"chain\">Maille de cha\u00eene<\/option>\n                <option value=\"wood\">Bois<\/option>\n                <option value=\"pool\">Cl\u00f4ture de piscine<\/option>\n                <option value=\"ranch\">Ranch<\/option>\n                <option value=\"repair\">R\u00e9paration<\/option>\n              <\/select>\n            <\/div>\n            <div class=\"summary-box\" id=\"repairTypeBox\" style=\"margin-bottom:14px;display:none\">\n              <small id=\"repairTypeLabel\">Type de r\u00e9paration<\/small>\n              <select class=\"input\" id=\"repairTypeSelect\" style=\"margin-top:8px\">\n                <option>Cl\u00f4ture<\/option>\n                <option>Porte<\/option>\n                <option>Poteau<\/option>\n                <option>Section<\/option>\n              <\/select>\n            <\/div>\n            <div class=\"input-row\">\n              <input class=\"input\" id=\"lengthInput\" type=\"number\" inputmode=\"decimal\" placeholder=\"Longueur approximative (ex. 160)\">\n<input class=\"input\" id=\"heightInput\" type=\"number\" inputmode=\"decimal\" placeholder=\"Hauteur souhait\u00e9e (ex. 6)\">\n              <input class=\"input\" id=\"gateInput\" placeholder=\"Portes (ex. 1 simple)\" \/>\n              <input class=\"input\" id=\"addressSearchInput\" placeholder=\"Adresse du projet\" autocomplete=\"street-address\" \/>\n              <div class=\"field-help\" id=\"addressHelp\">Commencez \u00e0 taper l\u2019adresse, puis choisissez la suggestion propos\u00e9e.<\/div>\n              <div class=\"grid-2\" style=\"margin-top:12px\">\n                <input class=\"input input-readonly\" id=\"streetNumberInput\" placeholder=\"No civique\" readonly \/>\n                <input class=\"input input-readonly\" id=\"routeInput\" placeholder=\"Rue\" readonly \/>\n              <\/div>\n              <div class=\"grid-2\" style=\"margin-top:12px\">\n                <input class=\"input input-readonly\" id=\"cityInput\" placeholder=\"Ville\" readonly \/>\n                <input class=\"input input-readonly\" id=\"provinceInput\" placeholder=\"Province\" readonly \/>\n              <\/div>\n              <div class=\"grid-2\" style=\"margin-top:12px\">\n                <input class=\"input input-readonly\" id=\"postalCodeInput\" placeholder=\"Code postal\" readonly \/>\n                <input class=\"input\" id=\"suiteInput\" placeholder=\"Appartement \/ suite (facultatif)\" \/>\n              <\/div>\n              <input class=\"input\" id=\"phoneInput\" type=\"tel\" placeholder=\"T\u00e9l\u00e9phone\" inputmode=\"tel\" autocomplete=\"tel\" \/>\n            <\/div>\n            <div class=\"grid-2\" style=\"margin-top:16px\">\n              <button class=\"btn btn-soft\" onclick=\"saveProjectDraft(); go('home')\" id=\"saveDraftBtn\">Enregistrer le brouillon<\/button>\n              <button class=\"btn btn-primary\" onclick=\"saveProjectDraft(); go('photos')\" id=\"next1\">Continuer<\/button>\n            <\/div>\n            <button class=\"btn btn-soft\" type=\"button\" onclick=\"clearProjectFields()\" style=\"margin-top:12px\" id=\"clearProjectBtn\">Tout effacer<\/button>\n          <\/div>\n        <\/section>\n\n        <section id=\"photos\" class=\"view hidden fade\">\n          <div class=\"card\">\n            <h2 id=\"photosTitle\" style=\"margin:0 0 14px\">Photos du projet<\/h2>\n\n            <input id=\"photoInput\" type=\"file\" accept=\"image\/*,.heic,.heif\" multiple class=\"hidden\" onchange=\"handlePhotoSelection(event)\" \/>\n\n            <div class=\"summary-box upload-drop\" id=\"uploadDrop\" onclick=\"openPhotoPicker()\" role=\"button\" tabindex=\"0\" onkeydown=\"if(event.key==='Enter' || event.key===' '){ event.preventDefault(); openPhotoPicker(); }\">\n              <div>\n                <div style=\"font-size:28px\">\ud83d\udcf8<\/div>\n                <strong id=\"uploadTitle\">Zone \u00e0 cl\u00f4turer seulement<\/strong>\n                <div class=\"muted upload-meta\" id=\"uploadMeta\">JPG, PNG, HEIC \u2014 ajoutez jusqu\u2019\u00e0 3 photos<\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"helper-row\">\n              <button class=\"btn btn-soft\" type=\"button\" onclick=\"openPhotoPicker()\" id=\"pickPhotosBtn\">Choisir des photos<\/button>\n              <button class=\"btn btn-light\" type=\"button\" onclick=\"clearPhotos()\" id=\"clearPhotosBtn\">Effacer<\/button>\n            <\/div>\n\n            <div class=\"thumbs\" style=\"margin-top:14px\" id=\"photoThumbs\">\n              <div class=\"thumb thumb-empty\">Aucune photo<\/div>\n              <div class=\"thumb thumb-empty\">Aucune photo<\/div>\n              <div class=\"thumb thumb-empty\">Aucune photo<\/div>\n            <\/div>\n\n            <div class=\"notice\" id=\"photosNotice\">Ajoutez jusqu\u2019\u00e0 3 photos de la zone \u00e0 cl\u00f4turer, des acc\u00e8s, des pentes et des portes existantes si possible.<\/div>\n\n            <div class=\"grid-2\" style=\"margin-top:16px\">\n              <button class=\"btn btn-soft\" onclick=\"go('project')\" id=\"back3\">Retour<\/button>\n              <button class=\"btn btn-primary\" onclick=\"go('summary')\" id=\"next2\">Continuer<\/button>\n            <\/div>\n          <\/div>\n        <\/section>\n\n        <section id=\"summary\" class=\"view hidden fade\">\n          <div class=\"card\">\n            <h2 id=\"summaryTitle\" style=\"margin:0 0 8px\">R\u00e9sum\u00e9 de la demande<\/h2>\n            <p class=\"muted\" id=\"summaryText\" style=\"font-size:14px;line-height:1.6;margin-bottom:14px\">Votre projet est pr\u00eat \u00e0 \u00eatre envoy\u00e9 \u00e0 CFC S\u00e9curit\u00e9.<\/p>\n            <div class=\"summary-box\"><small>Type<\/small><strong id=\"summaryFence\">Maille de cha\u00eene<\/strong><\/div>\n            <div class=\"summary-box\" style=\"margin-top:12px\"><small id=\"summaryPhotosLabel\">Photos<\/small><strong id=\"summaryPhotosCount\">0 photo<\/strong><\/div>\n            <div class=\"grid-2\" style=\"margin-top:16px\">\n              <button class=\"btn btn-soft\" onclick=\"go('photos')\" id=\"back4\">Retour<\/button>\n              <button class=\"btn btn-primary\" onclick=\"submitQuoteRequest()\" id=\"submitBtn\">Envoyer demande<\/button>\n            <\/div>\n          <\/div>\n        <\/section>\n\n        <section id=\"tracking\" class=\"view hidden fade\">\n          <div class=\"card\">\n            <h2 id=\"trackingTitle\" style=\"margin:0 0 10px\">Suivi du projet<\/h2>\n            <div id=\"trackingTimeline\"><\/div>\n            <button class=\"btn btn-soft\" onclick=\"go('home')\" id=\"homeBtn\" style=\"margin-top:14px\">Tableau de bord<\/button>\n          <\/div>\n        <\/section>\n      <\/div>\n\n      <div class=\"nav\">\n        <div class=\"nav-grid\">\n          <button class=\"nav-btn\" data-screen=\"home\" onclick=\"go('home')\"><span class=\"nav-icon\">\u2302<\/span><span class=\"nav-label\" id=\"navHome\">Accueil<\/span><\/button>\n          <button class=\"nav-btn\" data-screen=\"project\" onclick=\"go('project')\"><span class=\"nav-icon\">\u270e<\/span><span class=\"nav-label\" id=\"navProject\">Projet<\/span><\/button>\n          <button class=\"nav-btn\" data-screen=\"tracking\" onclick=\"go('tracking')\"><span class=\"nav-icon\">\u25f7<\/span><span class=\"nav-label\" id=\"navTracking\">Suivi<\/span><\/button>\n          <button class=\"nav-btn\" data-screen=\"auth\" onclick=\"openAuth()\"><span class=\"nav-icon\">\u25ce<\/span><span class=\"nav-label\" id=\"navAccount\">Compte<\/span><\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div class=\"overlay\" id=\"inviteOverlay\" onclick=\"closeInviteSheet()\"><\/div>\n  <div class=\"sheet\" id=\"inviteSheet\">\n    <div class=\"sheet-head\">\n      <div>\n        <h3 id=\"inviteSheetTitle\">Partager<\/h3>\n        <p id=\"inviteSheetSub\">Partagez Cl\u00f4tur\u00e9o normalement par texto, courriel ou lien.<\/p>\n      <\/div>\n      <button class=\"sheet-close\" onclick=\"closeInviteSheet()\">\u00d7<\/button>\n    <\/div>\n    <div class=\"sheet-grid\">\n      <button class=\"sheet-action\" onclick=\"inviteAction('contact')\">\n        <div class=\"icon\">\ud83d\udc64<\/div>\n        <div class=\"title\" id=\"inviteContactTitle\">Partager<\/div>\n        <div class=\"sub\" id=\"inviteContactSub\">Ouvrir les options de partage du t\u00e9l\u00e9phone<\/div>\n      <\/button>\n      <button class=\"sheet-action\" onclick=\"inviteAction('text')\">\n        <div class=\"icon\">\ud83d\udcac<\/div>\n        <div class=\"title\" id=\"inviteTextTitle\">Partager par texto<\/div>\n        <div class=\"sub\" id=\"inviteTextSub\">Envoyer rapidement par message<\/div>\n      <\/button>\n      <button class=\"sheet-action\" onclick=\"inviteAction('email')\">\n        <div class=\"icon\">\u2709\ufe0f<\/div>\n        <div class=\"title\" id=\"inviteEmailTitle\">Partager par courriel<\/div>\n        <div class=\"sub\" id=\"inviteEmailSub\">Partager l\u2019app par email<\/div>\n      <\/button>\n      <button class=\"sheet-action\" onclick=\"inviteAction('link')\">\n        <div class=\"icon\">\ud83d\udd17<\/div>\n        <div class=\"title\" id=\"inviteLinkTitle\">Copier le lien<\/div>\n        <div class=\"sub\" id=\"inviteLinkSub\">Obtenir un lien de partage<\/div>\n      <\/button>\n    <\/div>\n    <div class=\"notice\" id=\"inviteNotice\" style=\"margin-top:12px\">Choisissez une fa\u00e7on de partager Cl\u00f4tur\u00e9o.<\/div>\n  <\/div>\n\n\n  <div class=\"overlay\" id=\"contactOverlay\" onclick=\"closeContactOverlay(event)\">\n    <div class=\"overlay-card\" onclick=\"event.stopPropagation()\">\n      <div class=\"tag\">\u2709\ufe0f Contacter l\u2019\u00e9quipe<\/div>\n      <h3 id=\"contactOverlayTitle\">Envoyer un message<\/h3>\n      <p id=\"contactOverlaySub\">Votre nom et les d\u00e9tails de votre demande seront transmis automatiquement.<\/p>\n      <div class=\"summary-box\" style=\"margin-top:14px\">\n        <small id=\"contactRegardingLabel\">Concernant<\/small>\n        <strong id=\"contactRequestLabel\">Demande active<\/strong>\n      <\/div>\n      <textarea class=\"textarea\" id=\"contactMessageInput\" placeholder=\"Votre message\" style=\"margin-top:14px\"><\/textarea>\n      <div class=\"notice\" id=\"contactNotice\" style=\"margin-top:12px\">\u00c9crivez votre message, puis appuyez sur Envoyer.<\/div>\n      <div class=\"grid-2\" style=\"margin-top:16px\">\n        <button class=\"btn btn-soft\" type=\"button\" id=\"contactCloseBtn\" onclick=\"closeContactOverlay()\">Fermer<\/button>\n        <button class=\"btn btn-primary\" type=\"button\" id=\"contactSendBtn\" onclick=\"sendContactMessage()\">Envoyer<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n\n  <div class=\"overlay\" id=\"quoteOverlay\">\n    <div class=\"overlay-card\">\n      <div class=\"tag\">\ud83d\udce3 Nouveau prix disponible<\/div>\n      <h3>Votre prix est pr\u00eat<\/h3>\n      <div id=\"quoteOverlayAmount\" class=\"cfc-quote-price-alert\" style=\"font-size:40px;line-height:1;margin:10px 0 12px\">5 654,00 $<\/div>\n      <p>Votre demande est pr\u00eate. Appelez-nous pour passer \u00e0 la prochaine \u00e9tape.<\/p>\n      <div class=\"grid-2\" style=\"margin-top:16px\">\n        <a class=\"btn btn-primary\" href=\"tel:4507754897\" style=\"display:flex;align-items:center;justify-content:center;text-decoration:none\">Appelez-nous<\/a>\n        <button class=\"btn btn-soft\" onclick=\"closeQuoteOverlay()\">Plus tard<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n\n  <script type=\"module\">\n    import { initializeApp } from \"https:\/\/www.gstatic.com\/firebasejs\/10.14.1\/firebase-app.js\";\n    import {\n      getAuth,\n      createUserWithEmailAndPassword,\n      signInWithEmailAndPassword,\n      sendEmailVerification,\n      onAuthStateChanged,\n      signOut,\n      updateProfile,\n      reload\n    } from \"https:\/\/www.gstatic.com\/firebasejs\/10.14.1\/firebase-auth.js\";\n    import {\n      getFirestore,\n      collection,\n      addDoc,\n      doc,\n      updateDoc,\n      serverTimestamp,\n      query,\n      where,\n      onSnapshot\n    } from \"https:\/\/www.gstatic.com\/firebasejs\/10.14.1\/firebase-firestore.js\";\n\n    const firebaseConfig = {\n      apiKey: \"AIzaSyAY-X5sufmhHFlSONmUjZ9CpMyYkd5ooUA\",\n      authDomain: \"clotureo-app.firebaseapp.com\",\n      projectId: \"clotureo-app\",\n      storageBucket: \"clotureo-app.firebasestorage.app\",\n      messagingSenderId: \"113743014429\",\n      appId: \"1:113743014429:web:464b6e30ff1279500e34f4\"\n    };\n\n    const app = initializeApp(firebaseConfig);\n    const auth = getAuth(app);\n    const db = getFirestore(app);\n    const STORAGE_PROJECT = \"clotureo_preview_project_v1\";\n    const STORAGE_PHOTOS = \"clotureo_preview_photos_v1\";\n\n    const STORAGE_QUOTE_SEEN = \"clotureo_quote_seen_v1\";\n    const STORAGE_PROJECT_LEGACY = STORAGE_PROJECT;\n    const STORAGE_PHOTOS_LEGACY = STORAGE_PHOTOS;\n    let currentRequestUnsub = null;\n\n    const state = {\n      lang: \"fr\",\n      screen: \"auth\",\n      authMode: \"signin\",\n      fence: \"chain\",\n      dashboardState: \"new\",\n      session: null,\n      photoFiles: [],\n      liveRequest: null,\n      liveQuoteReady: false,\n      requestHistory: []\n    };\n\n    const fences = {\n      chain: { icon:\"\u26d3\ufe0f\", fr:\"Maille de cha\u00eene\" },\n      wood: { icon:\"\ud83e\udeb5\", fr:\"Bois\" },\n      pool: { icon:\"\ud83c\udfca\", fr:\"Cl\u00f4ture de piscine\" },\n      ranch: { icon:\"\ud83e\udd20\", fr:\"Ranch\" },\n      repair: { icon:\"\ud83d\udee0\ufe0f\", fr:\"R\u00e9paration\" },\n    };\n\n    const copy = {\n      fr: {\n        headers:{auth:\"Connexion\",confirm:\"Confirmation\",home:\"Tableau de bord\",project:\"Projet\",photos:\"Projet\",summary:\"Projet\",tracking:\"Suivi\"},\n        authTagline:\"Cr\u00e9ez votre compte une seule fois\",\n        authHero:\"Connexion ou cr\u00e9ation de compte\",\n        authSubhero:\"Cr\u00e9ez votre compte, confirmez votre courriel, puis acc\u00e9dez \u00e0 votre tableau de bord.\",\n        tabSignIn:\"Connexion\", tabCreate:\"Cr\u00e9er un compte\",\n        signinEmail:\"Courriel\", signinPassword:\"Mot de passe\", signinBtn:\"Se connecter\",\n        createName:\"Pr\u00e9nom\", createEmail:\"Courriel\", createPassword:\"Mot de passe\", createPassword2:\"Confirmer le mot de passe\",\n        createBtn:\"Cr\u00e9er mon compte\", googleBtn:\"Continuer avec Google\",\n        authNotice:\"Utilisez votre courriel et mot de passe pour acc\u00e9der \u00e0 Cl\u00f4tur\u00e9o.\",\n        confirmTag:\"Confirmez votre courriel\",\n        confirmHero:\"V\u00e9rifiez votre bo\u00eete de r\u00e9ception\",\n        confirmSubhero:\"Un lien de confirmation a \u00e9t\u00e9 envoy\u00e9. Confirmez votre courriel avant d\u2019entrer dans l\u2019application.\",\n        confirmSentTo:\"Courriel envoy\u00e9 \u00e0\",\n        confirmBtn:\"J\u2019ai confirm\u00e9 mon courriel\",\n        resendBtn:\"Renvoyer le lien\",\n        backToAuth:\"Retour \u00e0 la connexion\",\n        openInbox:\"Ouvrir mon courriel\",\n        changeEmail:\"Changer d\u2019adresse\",\n        confirmNotice:\"Apr\u00e8s confirmation, cliquez sur le bouton ci-dessus pour continuer.\",\n        signedIn:\"\u2713 Connect\u00e9\",\n        stateOptions:{new:\"Nouvel utilisateur\",progress:\"Projet en pr\u00e9paration\",submitted:\"Demande envoy\u00e9e\",quote:\"Soumission re\u00e7ue\"},\n        navHome:\"Tableau de bord\",navProject:\"Projet\",navTracking:\"Suivi\",navAccount:\"Compte\",\n        projectTitle:\"D\u00e9tails du projet\", projectTypeLabel:\"Type de cl\u00f4ture\", repairTypeLabel:\"Type de r\u00e9paration\", repairOptions:\"Cl\u00f4ture|Porte|Poteau|Section\", saveDraft:\"Enregistrer le brouillon\", addressHelp:\"Commencez \u00e0 taper l\u2019adresse, puis choisissez la suggestion propos\u00e9e.\", addressSearch:\"Adresse du projet\", streetNumber:\"No civique\", route:\"Rue\", city:\"Ville\", province:\"Province\", postalCode:\"Code postal\", suite:\"Appartement \/ suite (facultatif)\", phone:\"T\u00e9l\u00e9phone\", photosTitle:\"Ajoutez jusqu\u2019\u00e0 3 photos au besoin.\", uploadTitle:\"Zone \u00e0 cl\u00f4turer seulement\", uploadMeta:\"JPG, PNG, HEIC \u2014 ajoutez jusqu\u2019\u00e0 3 photos\", pickPhotosBtn:\"Choisir des photos\", clearPhotosBtn:\"Effacer\", photosNotice:\"Ajoutez jusqu\u2019\u00e0 3 photos de la zone \u00e0 cl\u00f4turer, des acc\u00e8s, des pentes et des portes existantes si possible.\", noPhoto:\"Aucune photo\",\n        summaryTitle:\"R\u00e9sum\u00e9 de la demande\", summaryText:\"Votre projet est pr\u00eat \u00e0 \u00eatre envoy\u00e9 \u00e0 CFC S\u00e9curit\u00e9.\", summaryPhotos:\"Photos\",\n        submitBtn:\"Envoyer demande\", trackingTitle:\"Suivi du projet\", homeBtn:\"Tableau de bord\",\n        back:\"Retour\", next:\"Continuer\",\n        createdPending:\"Compte cr\u00e9\u00e9. V\u00e9rifiez votre courriel pour entrer dans l\u2019application.\",\n        signedInOk:\"Connexion r\u00e9ussie.\",\n        signedOut:\"Vous avez \u00e9t\u00e9 d\u00e9connect\u00e9.\",\n        invalid:\"Courriel ou mot de passe invalide.\",\n        missing:\"Veuillez remplir tous les champs.\",\n        mismatch:\"Les mots de passe ne correspondent pas.\",\n        unconfirmed:\"Compte trouv\u00e9. Veuillez confirmer votre courriel pour entrer dans l\u2019application.\",\n        resent:\"Courriel de confirmation renvoy\u00e9.\",\n        confirmed:\"Courriel confirm\u00e9. Vous \u00eates maintenant connect\u00e9.\",\n        submitting:\"Envoi en cours\u2026\",\n        submittedOk:\"Votre demande a bien \u00e9t\u00e9 envoy\u00e9e.\",\n        submitError:\"Impossible d\u2019envoyer la demande pour le moment. R\u00e9essayez.\",\n        inboxOpened:\"Bo\u00eete courriel simul\u00e9e ouverte.\",\n        editEmail:\"Retour \u00e0 la cr\u00e9ation de compte pour modifier le courriel.\",\n        signOutBtn:\"Fermer la session\",\n        completed:\"Compl\u00e9t\u00e9\",\n        pending:\"En attente\",\n        inviteSheetTitle:\"Partager\",\n        inviteSheetSub:\"Partagez Cl\u00f4tur\u00e9o normalement par texto, courriel ou lien.\",\n        inviteContactTitle:\"Partager\",\n        inviteContactSub:\"Ouvrir les options de partage du t\u00e9l\u00e9phone\",\n        inviteTextTitle:\"Partager par texto\",\n        inviteTextSub:\"Envoyer rapidement par message\",\n        inviteEmailTitle:\"Partager par courriel\",\n        inviteEmailSub:\"Envoyer l\u2019application par courriel\",\n        inviteLinkTitle:\"Copier le lien\",\n        inviteLinkSub:\"Obtenir un lien de partage\",\n        inviteNotice:\"Choisissez une fa\u00e7on de partager Cl\u00f4tur\u00e9o.\",\n        inviteResultContact:\"Partage pr\u00e9par\u00e9.\",\n        inviteResultText:\"Partage par texto pr\u00e9par\u00e9.\",\n        inviteResultEmail:\"Partage par courriel pr\u00e9par\u00e9.\",\n        inviteResultLink:\"Lien de partage copi\u00e9.\",\n        contactOverlayTitle:\"Envoyer un message\",\n        contactOverlaySub:\"Votre nom et les d\u00e9tails de votre demande seront transmis automatiquement.\",\n        contactOverlayPlaceholder:\"Votre message\",\n        contactOverlayRegarding:\"Concernant\",\n        contactOverlayFallback:\"Demande active\",\n        contactOverlayHint:\"\u00c9crivez votre message, puis appuyez sur Envoyer.\",\n        contactOverlayEmpty:\"Ajoutez un message avant d\u2019envoyer.\",\n        contactOverlayNoRequest:\"Aucune demande active \u00e0 transmettre pour le moment.\",\n        contactOverlaySending:\"Envoi en cours\u2026\",\n        contactOverlaySent:\"Message envoy\u00e9. Notre \u00e9quipe recevra votre message avec les d\u00e9tails de votre demande.\",\n        contactOverlaySendBtn:\"Envoyer\",\n        contactOverlayCloseBtn:\"Fermer\",\n        dashboard:{\n         new:{\n  topTitle:(name)=>`Bonjour, ${name}`,\n  topText:\"Votre projet de cl\u00f4ture commence ici. Choisissez votre type de cl\u00f4ture, ajoutez quelques d\u00e9tails et envoyez votre demande en quelques minutes.\",\n  mainLabel:\"Aucune demande en cours\",\n  mainTitle:\"Vous n\u2019avez pas encore envoy\u00e9 de demande.\",\n  mainText:\"Le meilleur prochain geste est de d\u00e9marrer votre demande.\",\n  primary:\"Commencer mon projet\",\n  secondary:\"Types de cl\u00f4ture\",\n  q1:\"Ajoutez des photos pour un prix plus pr\u00e9cis\", q1s:\"Zone \u00e0 cl\u00f4turer seulement\",\n  q2:\"Derni\u00e8res nouvelles\", q2s:\"Suivez l\u2019\u00e9tat de votre demande\",\n  actionsTitle:\"Actions rapides\", actionsSub:\"Votre espace Cl\u00f4tur\u00e9o\",\n  a1:\"D\u00e9marrer mon projet\", a1s:\"Cr\u00e9er votre premi\u00e8re demande\",\n  a2:\"Partager\", a2s:\"Texto, courriel ou lien\"\n},\n          progress:{\n            topTitle:(name)=>`Bonjour, ${name}`,\n            topText:\"Votre projet est commenc\u00e9. Compl\u00e9tez les \u00e9l\u00e9ments manquants pour envoyer votre demande.\",\n            mainLabel:\"Projet en pr\u00e9paration\",\n            mainTitle:\"Maille de cha\u00eene \u2014 brouillon enregistr\u00e9\",\n            mainText:\"Reprenez exactement o\u00f9 vous vous \u00eates arr\u00eat\u00e9.\",\n            primary:\"Continuer\",\n            secondary:\"Ajouter photos\",\n            q1:\"Compl\u00e9ter les d\u00e9tails\", q1s:\"Longueur, hauteur, portes et options\",\n            q2:\"Ajouter des photos\", q2s:\"Appuyez pour importer rapidement\",\n            actionsTitle:\"Actions rapides\", actionsSub:\"Votre espace Cl\u00f4tur\u00e9o\",\n            a1:\"Continuer mon projet\", a1s:\"Revoir les d\u00e9tails de ma demande\",\n            a2:\"Partager\", a2s:\"Texto, courriel ou lien\"\n          },\n          submitted:{\n            topTitle:(name)=>`Bonjour, ${name}`,\n            topText:\"Votre demande a bien \u00e9t\u00e9 envoy\u00e9e. Suivez son \u00e9volution ici.\",\n            mainLabel:\"Demande envoy\u00e9e\",\n            mainTitle:\"Maille de cha\u00eene \u2014 160 pi\",\n            mainText:\"Votre demande a bien \u00e9t\u00e9 re\u00e7ue. CFC S\u00e9curit\u00e9 pr\u00e9pare la suite de votre projet.\",\n            primary:\"Voir le suivi\",\n            secondary:\"Modifier\",\n            q1:\"Ajouter des photos\", q1s:\"Ajoutez jusqu\u2019\u00e0 3 photos au besoin.\",\n            q2:\"Derni\u00e8res nouvelles\", q2s:\"Suivez l\u2019\u00e9tat de votre demande.\",\n            actionsTitle:\"Actions rapides\", actionsSub:\"Votre espace Cl\u00f4tur\u00e9o\",\n            a1:\"Continuer mon projet\", a1s:\"Revoir les d\u00e9tails de ma demande\",\n            a2:\"Partager\", a2s:\"Texto, courriel ou lien\"\n          },\n          quote:{\n            topTitle:(name)=>`Bonjour, ${name}`,\n            topText:\"Votre demande est pr\u00eate. Consultez-la et confirmez les prochaines \u00e9tapes.\",\n            mainLabel:\"Soumission re\u00e7ue\",\n            mainTitle:\"Votre estimation est disponible\",\n            mainText:\"Tout est pr\u00eat pour passer \u00e0 la suite du projet.\",\n            primary:\"Voir ma demande\",\n            secondary:\"Planifier la suite\",\n            q1:\"Documents du projet\", q1s:\"Consultez votre demande et les d\u00e9tails\",\n            q2:\"Contacter l\u2019\u00e9quipe\", q2s:\"Posez une question rapidement\",\n            actionsTitle:\"Actions rapides\", actionsSub:\"Votre espace Cl\u00f4tur\u00e9o\",\n            a1:\"Voir ma demande\", a1s:\"Acc\u00e9der aux documents de la demande\",\n            a2:\"Partager\", a2s:\"Texto, courriel ou lien\"\n          }\n        },\n        timeline:{\n          new:[\"Compte cr\u00e9\u00e9\",\"Profil pr\u00eat\",\"Projet \u00e0 d\u00e9marrer\",\"Soumission \u00e0 venir\"],\n          progress:[\"Compte cr\u00e9\u00e9\",\"Projet en pr\u00e9paration\",\"Photos \u00e0 ajouter\",\"Soumission \u00e0 envoyer\"],\n          submitted:[\"Compte cr\u00e9\u00e9\",\"Projet soumis\",\"Analyse en cours\",\"Demande \u00e0 l\u2019\u00e9tude\"],\n          quote:[\"Compte cr\u00e9\u00e9\",\"Projet soumis\",\"Soumission pr\u00e9par\u00e9e\",\"Soumission re\u00e7ue\"]\n        }\n      },\n      en: {\n        headers:{auth:\"Sign in\",confirm:\"Confirm email\",home:\"Dashboard\",project:\"Project\",photos:\"Project\",summary:\"Project\",tracking:\"Tracking\"},\n        authTagline:\"Create your account once\",\n        authHero:\"Sign in or create account\",\n        authSubhero:\"Create your account, verify your email, then enter your dashboard.\",\n        tabSignIn:\"Sign in\", tabCreate:\"Create account\",\n        signinEmail:\"Email\", signinPassword:\"Password\", signinBtn:\"Sign in\",\n        createName:\"First name\", createEmail:\"Email\", createPassword:\"Password\", createPassword2:\"Confirm password\",\n        createBtn:\"Create my account\", googleBtn:\"Continue with Google\",\n        authNotice:\"Use your email and password to access Cl\u00f4tur\u00e9o.\",\n        confirmTag:\"Confirm your email\",\n        confirmHero:\"Check your inbox\",\n        confirmSubhero:\"A verification link was sent. Confirm your email before entering the app.\",\n        confirmSentTo:\"Email sent to\",\n        confirmBtn:\"I confirmed my email\",\n        resendBtn:\"Resend link\",\n        backToAuth:\"Back to sign in\",\n        openInbox:\"Open my email\",\n        changeEmail:\"Change address\",\n        confirmNotice:\"After confirming, click the button above to continue.\",\n        signedIn:\"\u2713 Signed in\",\n        stateOptions:{new:\"New user\",progress:\"Project in progress\",submitted:\"Request submitted\",quote:\"Quote received\"},\n        navHome:\"Dashboard\",navProject:\"Project\",navTracking:\"Tracking\",navAccount:\"Account\",\n        projectTitle:\"Project details\", projectTypeLabel:\"Fence type\", repairTypeLabel:\"Repair type\", repairOptions:\"Fence|Gate|Post|Section\", saveDraft:\"Save draft\", addressHelp:\"Start typing the address, then choose the suggested match.\", addressSearch:\"Project address\", streetNumber:\"Street number\", route:\"Street\", city:\"City\", province:\"Province\", postalCode:\"Postal code\", suite:\"Apartment \/ suite (optional)\", phone:\"Phone\", photosTitle:\"Add photos for better pricing\", uploadTitle:\"Fence area only\",\n        summaryTitle:\"Request summary\", summaryText:\"Your project is ready to be sent to CFC S\u00e9curit\u00e9.\",\n        submitBtn:\"Send my request\", trackingTitle:\"Project tracking\", homeBtn:\"Dashboard\",\n        back:\"Back\", next:\"Continue\",\n        createdPending:\"Account created. Check your email to enter the app.\",\n        signedInOk:\"Sign-in successful.\",\n        signedOut:\"You have been signed out.\",\n        invalid:\"Invalid email or password.\",\n        missing:\"Please complete all fields.\",\n        mismatch:\"Passwords do not match.\",\n        unconfirmed:\"Account found. Please confirm your email to enter the app.\",\n        resent:\"Verification email sent again.\",\n        confirmed:\"Email confirmed. You are now signed in.\",\n        inboxOpened:\"Simulated inbox opened.\",\n        editEmail:\"Returning to account creation so you can change the email.\",\n        signOutBtn:\"Sign out\",\n        completed:\"Completed\",\n        pending:\"Pending\",\n        inviteSheetTitle:\"Share\",\n        inviteSheetSub:\"Share Cl\u00f4tur\u00e9o by text, email, or link.\",\n        inviteContactTitle:\"Share\",\n        inviteContactSub:\"Open your phone share options\",\n        inviteTextTitle:\"Share by text\",\n        inviteTextSub:\"Send quickly by message\",\n        inviteEmailTitle:\"Share by email\",\n        inviteEmailSub:\"Send the app by email\",\n        inviteLinkTitle:\"Copy link\",\n        inviteLinkSub:\"Get a shareable link\",\n        inviteNotice:\"Choose a way to share Cl\u00f4tur\u00e9o.\",\n        inviteResultContact:\"Share prepared.\",\n        inviteResultText:\"Text share prepared.\",\n        inviteResultEmail:\"Email share prepared.\",\n        inviteResultLink:\"Share link copied.\",\n        contactOverlayTitle:\"Send a message\",\n        contactOverlaySub:\"Your name and request details will be shared automatically.\",\n        contactOverlayPlaceholder:\"Your message\",\n        contactOverlayRegarding:\"Regarding\",\n        contactOverlayFallback:\"Active request\",\n        contactOverlayHint:\"Write your message, then tap Send.\",\n        contactOverlayEmpty:\"Add a message before sending.\",\n        contactOverlayNoRequest:\"There is no active request to send right now.\",\n        contactOverlaySending:\"Sending\u2026\",\n        contactOverlaySent:\"Message sent. Our team will receive your message with your request details.\",\n        contactOverlaySendBtn:\"Send\",\n        contactOverlayCloseBtn:\"Close\",\n        dashboard:{\n          new:{\n            topTitle:(name)=>`Hello, ${name}`,\n            topText:\"Your fence project starts here. Choose your fence type, add a few details, and send your request in minutes.\",\n            mainLabel:\"No active request\",\n            mainTitle:\"You have not submitted a request yet.\",\n            mainText:\"The best next move is to start your request.\",\n            primary:\"Start my project\",\n            secondary:\"See fence types\",\n            q1:\"Add photos for better pricing\", q1s:\"Fence area only\",\n            q2:\"Latest updates\", q2s:\"Track the status of your request\",\n            actionsTitle:\"Quick actions\", actionsSub:\"Your Cl\u00f4tur\u00e9o space\",\n            a1:\"Continue my project\", a1s:\"Resume where you left off\",\n            a2:\"Share\", a2s:\"Text, email, or link in 1 tap\"\n          },\n          progress:{\n            topTitle:(name)=>`Hello, ${name}`,\n            topText:\"Your project has started. Complete the missing pieces to send your request.\",\n            mainLabel:\"Project in progress\",\n            mainTitle:\"Chain Link \u2014 saved draft\",\n            mainText:\"Resume exactly where you left off.\",\n            primary:\"Continue my project\",\n            secondary:\"Add photos\",\n            q1:\"Complete details\", q1s:\"Length, height, gates, and options\",\n            q2:\"Add photos\", q2s:\"Tap to import quickly\",\n            actionsTitle:\"Quick actions\", actionsSub:\"Your Cl\u00f4tur\u00e9o space\",\n            a1:\"Continue my project\", a1s:\"Review details and options\",\n            a2:\"Share\", a2s:\"Text, email, or link in 1 tap\"\n          },\n          submitted:{\n            topTitle:(name)=>`Hello, ${name}`,\n            topText:\"Your request has been sent. Follow the progress of your quote here.\",\n            mainLabel:\"Submitted quote request\",\n            mainTitle:\"Chain Link \u2014 160 ft\",\n            mainText:\"Your request has been received. CFC S\u00e9curit\u00e9 is preparing the next step of your project.\",\n            primary:\"View tracking\",\n            secondary:\"Edit\",\n            q1:\"Add photos\", q1s:\"Complete your request with more images\",\n            q2:\"Latest updates\", q2s:\"Follow the status of your quote\",\n            actionsTitle:\"Quick actions\", actionsSub:\"Your Cl\u00f4tur\u00e9o space\",\n            a1:\"Continue my project\", a1s:\"Review details and options\",\n            a2:\"Share\", a2s:\"Text, email, or link in 1 tap\"\n          },\n          quote:{\n            topTitle:(name)=>`Hello, ${name}`,\n            topText:\"Your quote is ready. Review it and confirm the next steps.\",\n            mainLabel:\"Quote received\",\n            mainTitle:\"Your estimate is available\",\n            mainText:\"Everything is ready to move forward.\",\n            primary:\"View my quote\",\n            secondary:\"Plan next step\",\n            q1:\"Project documents\", q1s:\"Review your quote and project details\",\n            q2:\"Contact the team\", q2s:\"Ask a quick question\",\n            actionsTitle:\"Quick actions\", actionsSub:\"Your Cl\u00f4tur\u00e9o space\",\n            a1:\"View my quote\", a1s:\"Open project documents\",\n            a2:\"Share\", a2s:\"Text, email, or link in 1 tap\"\n          }\n        },\n        timeline:{\n          new:[\"Account created\",\"Profile ready\",\"Project to start\",\"Quote coming later\"],\n          progress:[\"Account created\",\"Project in progress\",\"Photos to add\",\"Request to send\"],\n          submitted:[\"Account created\",\"Project submitted\",\"Under review\",\"Quote coming soon\"],\n          quote:[\"Account created\",\"Project submitted\",\"Quote prepared\",\"Quote received\"]\n        }\n      }\n    };\n\n    function getSessionStorageKey(baseKey){\n      const uid = auth.currentUser?.uid || state.session?.uid || \"guest\";\n      return `${baseKey}_${uid}`;\n    }\n    function getProject(){\n      const sessionValue = localStorage.getItem(getSessionStorageKey(STORAGE_PROJECT));\n      if (sessionValue) return JSON.parse(sessionValue || \"null\");\n      return null;\n    }\n    function setProject(project){\n      localStorage.setItem(getSessionStorageKey(STORAGE_PROJECT), JSON.stringify(project));\n    }\n    function clearLegacyLocalDrafts(){\n      localStorage.removeItem(STORAGE_PROJECT_LEGACY);\n      localStorage.removeItem(STORAGE_PHOTOS_LEGACY);\n    }\n    function getStoredPhotos(){\n      return JSON.parse(localStorage.getItem(getSessionStorageKey(STORAGE_PHOTOS)) || \"[]\");\n    }\n    function setStoredPhotos(items){\n      localStorage.setItem(getSessionStorageKey(STORAGE_PHOTOS), JSON.stringify(items));\n    }\n\n    function getSeenQuoteKey(){\n      return localStorage.getItem(STORAGE_QUOTE_SEEN) || \"\";\n    }\n    function setSeenQuoteKey(value){\n      localStorage.setItem(STORAGE_QUOTE_SEEN, value || \"\");\n    }\n    function formatCurrencyFR(value){\n      const amount = Number(value || 0);\n      if (!Number.isFinite(amount)) return \"\";\n      return new Intl.NumberFormat(\"fr-CA\", { style:\"currency\", currency:\"CAD\", minimumFractionDigits:2, maximumFractionDigits:2 }).format(amount);\n    }\n    function closeQuoteOverlay(){\n      byId(\"quoteOverlay\")?.classList.remove(\"show\");\n    }\n    window.closeQuoteOverlay = closeQuoteOverlay;\n\n    function showQuoteOverlay(amount, seenKey){\n      const amountEl = byId(\"quoteOverlayAmount\");\n      if (amountEl) amountEl.textContent = formatCurrencyFR(amount);\n      byId(\"quoteOverlay\")?.classList.add(\"show\");\n      setSeenQuoteKey(seenKey);\n    }\n\n    function normalizeFirestoreDate(value){\n      if (!value) return 0;\n      if (typeof value.toMillis === \"function\") return value.toMillis();\n      if (typeof value.seconds === \"number\") return value.seconds * 1000;\n      const parsed = new Date(value).getTime();\n      return Number.isFinite(parsed) ? parsed : 0;\n    }\n\n    function sortRequestsByCreatedAt(docs){\n      return docs.sort((a, b) => normalizeFirestoreDate(b.createdAt) - normalizeFirestoreDate(a.createdAt));\n    }\n\n    function getVisibleRequests(snapshot){\n      const docs = snapshot.docs.map(docSnap => ({ id: docSnap.id, ...docSnap.data() }));\n      return sortRequestsByCreatedAt(docs.filter(doc => !doc.archivedByUser));\n    }\n\n    function pickLatestRequest(snapshot){\n      const docs = getVisibleRequests(snapshot);\n      return docs.length ? docs[0] : null;\n    }\n\n    function syncLiveRequest(requestDoc){\n      state.liveRequest = requestDoc;\n      const quoteReady = requestDoc && requestDoc.status === \"quote_ready\" && Number.isFinite(Number(requestDoc.quoteAmount));\n      state.liveQuoteReady = !!quoteReady;\n\n      if (requestDoc?.fence) state.fence = requestDoc.fence;\n\n      if (quoteReady) {\n        state.dashboardState = \"quote\";\n        const seenKey = `${requestDoc.id}:${requestDoc.quoteAmount}`;\n        if (getSeenQuoteKey() !== seenKey) {\n          showQuoteOverlay(requestDoc.quoteAmount, seenKey);\n        }\n      } else if (requestDoc?.status === \"submitted\" || requestDoc?.status === \"under_review\") {\n        state.dashboardState = \"submitted\";\n        closeQuoteOverlay();\n      } else if (requestDoc) {\n        closeQuoteOverlay();\n      } else {\n        state.dashboardState = getProject() ? \"progress\" : \"new\";\n        closeQuoteOverlay();\n      }\n\n      renderAll();\n    }\n\n    function watchLatestRequest(user){\n      if (currentRequestUnsub) {\n        currentRequestUnsub();\n        currentRequestUnsub = null;\n      }\n      if (!user?.uid) return;\n      const requestsQuery = query(collection(db, \"requests\"), where(\"uid\", \"==\", user.uid));\n      currentRequestUnsub = onSnapshot(requestsQuery, (snapshot) => {\n        const visibleRequests = getVisibleRequests(snapshot);\n        state.requestHistory = visibleRequests;\n        const latest = visibleRequests[0] || null;\n        syncLiveRequest(latest);\n      }, (err) => {\n        console.error(\"watchLatestRequest error:\", err);\n      });\n    }\n\n    const byId = (id) => document.getElementById(id);\n    const setText = (id, value) => { const el = byId(id); if (el) el.textContent = value; };\n    const setPlaceholder = (id, value) => { const el = byId(id); if (el) el.placeholder = value; };\n\n    function showNotice(msg, cls=\"\"){\n      const el = byId(\"authNotice\");\n      if (!el) return;\n      el.textContent = msg;\n      el.className = \"notice \" + cls;\n    }\n\n    window.setAuthMode = (mode) => {\n      state.authMode = mode;\n      byId(\"tabSignIn\")?.classList.toggle(\"active\", mode === \"signin\");\n      byId(\"tabCreate\")?.classList.toggle(\"active\", mode === \"create\");\n      byId(\"signinFields\")?.classList.toggle(\"hidden\", mode !== \"signin\");\n      byId(\"createFields\")?.classList.toggle(\"hidden\", mode !== \"create\");\n    };\n\n    window.togglePassword = (id, btn) => {\n      const input = byId(id);\n      if (!input) return;\n      input.type = input.type === \"password\" ? \"text\" : \"password\";\n      btn.textContent = input.type === \"password\" ? \"Voir\" : \"Masquer\";\n    };\n\n    function normalizeEmail(v){ return (v || \"\").trim().toLowerCase(); }\n\n    function getCurrentProjectPayload(){\n      const repairSelect = byId(\"repairTypeSelect\");\n      return {\n        fence: state.fence,\n        address: byId(\"addressSearchInput\")?.value.trim() || \"\",\n        streetNumber: byId(\"streetNumberInput\")?.value.trim() || \"\",\n        route: byId(\"routeInput\")?.value.trim() || \"\",\n        city: byId(\"cityInput\")?.value.trim() || \"\",\n        province: byId(\"provinceInput\")?.value.trim() || \"\",\n        postalCode: byId(\"postalCodeInput\")?.value.trim() || \"\",\n        suite: byId(\"suiteInput\")?.value.trim() || \"\",\n        phone: byId(\"phoneInput\")?.value.trim() || \"\",\n        length: byId(\"lengthInput\")?.value.trim() || \"\",\n        height: byId(\"heightInput\")?.value.trim() || \"\",\n        gate: byId(\"gateInput\")?.value.trim() || \"\",\n        repairType: repairSelect ? repairSelect.value : \"\",\n        photoCount: (state.photoFiles || []).length\n      };\n    }\n\n    function getAddressComponent(place, type, format = \"long_name\"){\n      const components = place?.address_components || [];\n      const match = components.find(component => (component.types || []).includes(type));\n      return match ? (match[format] || match.long_name || \"\") : \"\";\n    }\n\n    function fillAddressFromPlace(place){\n      if (!place) return;\n      const streetNumber = getAddressComponent(place, \"street_number\", \"short_name\");\n      const route = getAddressComponent(place, \"route\");\n      const city =\n        getAddressComponent(place, \"locality\") ||\n        getAddressComponent(place, \"postal_town\") ||\n        getAddressComponent(place, \"administrative_area_level_3\") ||\n        getAddressComponent(place, \"sublocality\");\n      const province = getAddressComponent(place, \"administrative_area_level_1\", \"short_name\");\n      const postalCode = getAddressComponent(place, \"postal_code\", \"short_name\");\n\n      const addressValue = place.formatted_address || [streetNumber, route, city].filter(Boolean).join(\", \");\n\n      if (byId(\"addressSearchInput\")) byId(\"addressSearchInput\").value = addressValue;\n      if (byId(\"streetNumberInput\")) byId(\"streetNumberInput\").value = streetNumber;\n      if (byId(\"routeInput\")) byId(\"routeInput\").value = route;\n      if (byId(\"cityInput\")) byId(\"cityInput\").value = city;\n      if (byId(\"provinceInput\")) byId(\"provinceInput\").value = province;\n      if (byId(\"postalCodeInput\")) byId(\"postalCodeInput\").value = postalCode;\n    }\n\n    window.initGoogleAddressAutocomplete = () => {\n      const input = byId(\"addressSearchInput\");\n      if (!input || !window.google?.maps?.places?.Autocomplete) return;\n\n      const autocomplete = new google.maps.places.Autocomplete(input, {\n        fields: [\"address_components\", \"formatted_address\", \"geometry\", \"name\"],\n        types: [\"address\"],\n        componentRestrictions: { country: [\"ca\"] }\n      });\n\n      autocomplete.addListener(\"place_changed\", () => {\n        const place = autocomplete.getPlace();\n        if (!place || !place.address_components) return;\n        fillAddressFromPlace(place);\n      });\n    };\n\n\n    function setSubmitButtonState(isLoading){\n      const btn = byId(\"submitBtn\");\n      const c = copy[state.lang];\n      if (!btn) return;\n      btn.disabled = isLoading;\n      btn.style.opacity = isLoading ? \"0.75\" : \"\";\n      btn.textContent = isLoading ? (c.submitting || \"Envoi en cours\u2026\") : c.submitBtn;\n    }\n\n\n    window.openPhotoPicker = () => {\n      byId(\"photoInput\")?.click();\n    };\n\n    function syncPhotoCount(){\n      const count = (state.photoFiles || []).length;\n      const summary = byId(\"summaryPhotosCount\");\n      if (summary) summary.textContent = `${count} photo${count > 1 ? \"s\" : \"\"}`;\n      const meta = byId(\"uploadMeta\");\n      if (meta) {\n        meta.textContent = count\n          ? `${count} photo${count > 1 ? \"s\" : \"\"} s\u00e9lectionn\u00e9e${count > 1 ? \"s\" : \"\"}`\n          : (copy[state.lang].uploadMeta || \"JPG, PNG, HEIC \u2014 ajoutez jusqu\u2019\u00e0 3 photos\");\n      }\n    }\n\n    function renderPhotoThumbs(){\n      const container = byId(\"photoThumbs\");\n      if (!container) return;\n      const c = copy[state.lang];\n      const files = state.photoFiles || [];\n      if (!files.length) {\n        container.innerHTML = `\n          <div class=\"thumb thumb-empty\">${c.noPhoto || \"Aucune photo\"}<\/div>\n          <div class=\"thumb thumb-empty\">${c.noPhoto || \"Aucune photo\"}<\/div>\n          <div class=\"thumb thumb-empty\">${c.noPhoto || \"Aucune photo\"}<\/div>\n        `;\n      } else {\n        const items = files.map((file, index) => `\n          <div class=\"thumb\">\n            <img decoding=\"async\" src=\"${file.objectUrl}\" alt=\"Photo du projet ${index + 1}\" \/>\n            <button class=\"thumb-remove\" type=\"button\" onclick=\"removePhoto(${index})\">\u00d7<\/button>\n          <\/div>\n        `);\n        while (items.length < 3) {\n          items.push(`<div class=\"thumb thumb-empty\">${c.noPhoto || \"Aucune photo\"}<\/div>`);\n        }\n        container.innerHTML = items.join(\"\");\n      }\n      syncPhotoCount();\n    }\n\n    function persistPhotoMetadata(){\n      const items = (state.photoFiles || []).map(file => ({\n        name: file.name || \"photo\",\n        size: file.size || 0,\n        type: file.type || \"\",\n        updatedAt: new Date().toISOString()\n      }));\n      setStoredPhotos(items);\n    }\n\n    function loadStoredPhotoMetadata(){\n      state.photoFiles = [];\n    }\n\n    window.handlePhotoSelection = (event) => {\n      const selected = Array.from(event.target?.files || []).filter(file => (file.type || \"\").startsWith(\"image\/\") || \/\\.(heic|heif)$\/i.test(file.name || \"\"));\n      if (!selected.length) {\n        event.target.value = \"\";\n        return;\n      }\n\n      const existing = Array.isArray(state.photoFiles) ? [...state.photoFiles] : [];\n      const roomLeft = Math.max(0, 3 - existing.length);\n\n      if (!roomLeft) {\n        event.target.value = \"\";\n        return;\n      }\n\n      const incoming = selected.slice(0, roomLeft).map(file => ({\n        name: file.name,\n        size: file.size,\n        type: file.type,\n        objectUrl: URL.createObjectURL(file)\n      }));\n\n      state.photoFiles = [...existing, ...incoming];\n\n      persistPhotoMetadata();\n      renderPhotoThumbs();\n\n      const project = getProject() || {};\n      project.photoCount = state.photoFiles.length;\n      setProject(project);\n      event.target.value = \"\";\n    };\n\n    window.removePhoto = (index) => {\n      const files = [...(state.photoFiles || [])];\n      const removed = files[index];\n      if (removed?.objectUrl) URL.revokeObjectURL(removed.objectUrl);\n      files.splice(index, 1);\n      state.photoFiles = files;\n      persistPhotoMetadata();\n      renderPhotoThumbs();\n\n      const project = getProject() || {};\n      project.photoCount = state.photoFiles.length;\n      setProject(project);\n    };\n\n    window.clearPhotos = () => {\n      (state.photoFiles || []).forEach(file => {\n        if (file.objectUrl) URL.revokeObjectURL(file.objectUrl);\n      });\n      state.photoFiles = [];\n      setStoredPhotos([]);\n      renderPhotoThumbs();\n\n      const input = byId(\"photoInput\");\n      if (input) input.value = \"\";\n\n      const project = getProject() || {};\n      project.photoCount = 0;\n      setProject(project);\n    };\n\n\n    window.createAccount = async () => {\n      const c = copy[state.lang];\n      const name = byId(\"createName\")?.value.trim() || \"\";\n      const email = normalizeEmail(byId(\"createEmail\")?.value);\n      const pass = byId(\"createPassword\")?.value || \"\";\n      const pass2 = byId(\"createPassword2\")?.value || \"\";\n      if(!name || !email || !pass || !pass2){ showNotice(c.missing, \"error\"); return; }\n      if(pass !== pass2){ showNotice(c.mismatch, \"error\"); return; }\n\n      try {\n        const userCredential = await createUserWithEmailAndPassword(auth, email, pass);\n        await updateProfile(userCredential.user, { displayName: name });\n        await sendEmailVerification(userCredential.user);\n        setText(\"confirmEmailValue\", email);\n        setText(\"confirmNotice\", c.createdPending);\n        const notice = byId(\"confirmNotice\");\n        if (notice) notice.className = \"notice success\";\n        go(\"confirm\");\n        showNotice(c.createdPending, \"success\");\n      } catch (err) {\n        showNotice(err.message, \"error\");\n      }\n    };\n\n    window.signIn = async () => {\n      const c = copy[state.lang];\n      const email = normalizeEmail(byId(\"signinEmail\")?.value);\n      const pass = byId(\"signinPassword\")?.value || \"\";\n      if(!email || !pass){ showNotice(c.missing, \"error\"); return; }\n      try {\n        const userCredential = await signInWithEmailAndPassword(auth, email, pass);\n        await reload(userCredential.user);\n        if (!userCredential.user.emailVerified) {\n          setText(\"confirmEmailValue\", email);\n          setText(\"confirmNotice\", c.unconfirmed);\n          const notice = byId(\"confirmNotice\");\n          if (notice) notice.className = \"notice\";\n          go(\"confirm\");\n          showNotice(c.unconfirmed, \"success\");\n          return;\n        }\n        showNotice(c.signedInOk, \"success\");\n        go(\"home\");\n      } catch (err) {\n        showNotice(c.invalid, \"error\");\n      }\n    };\n\n    window.quickGoogle = () => {\n      alert(\"Activez Google dans Firebase plus tard si vous voulez ce parcours r\u00e9el.\");\n    };\n\n    window.openInbox = () => {\n      const c = copy[state.lang];\n      const notice = byId(\"confirmNotice\");\n      if (notice) {\n        notice.textContent = c.inboxOpened;\n        notice.className = \"notice\";\n      }\n    };\n\n    window.changeEmail = async () => {\n      await signOut(auth).catch(() => {});\n      go(\"auth\");\n      window.setAuthMode(\"create\");\n      showNotice(copy[state.lang].editEmail);\n    };\n\n    window.confirmEmail = async () => {\n      const c = copy[state.lang];\n      const user = auth.currentUser;\n      if (!user) {\n        go(\"auth\");\n        return;\n      }\n      await reload(user);\n      if (user.emailVerified) {\n        setText(\"confirmNotice\", c.confirmed);\n        const notice = byId(\"confirmNotice\");\n        if (notice) notice.className = \"notice success\";\n        go(\"home\");\n      } else {\n        setText(\"confirmNotice\", c.unconfirmed);\n        const notice = byId(\"confirmNotice\");\n        if (notice) notice.className = \"notice\";\n      }\n    };\n\n    window.resendConfirmation = async () => {\n      const c = copy[state.lang];\n      if (auth.currentUser && !auth.currentUser.emailVerified) {\n        await sendEmailVerification(auth.currentUser);\n        const notice = byId(\"confirmNotice\");\n        if (notice) {\n          notice.textContent = c.resent;\n          notice.className = \"notice\";\n        }\n      }\n    };\n\n    window.signOut = async () => {\n      await signOut(auth);\n      showNotice(copy[state.lang].signedOut);\n    };\n\n    window.openAuth = async () => {\n      if (state.session) {\n        await signOut(auth);\n      } else {\n        go(\"auth\");\n      }\n    };\n\n    window.setDashboardState = (v) => {\n      state.dashboardState = v;\n      renderDashboard();\n      renderTracking();\n    };\n\n    window.saveProjectDraft = () => {\n      const project = {\n        ...getCurrentProjectPayload(),\n        status: \"progress\",\n        updatedAt: new Date().toISOString(),\n      };\n      setProject(project);\n      state.dashboardState = \"progress\";\n      renderAll();\n    };\n\n    window.clearProjectFields = () => {\n      if (!confirm(\"Effacer tous les d\u00e9tails de ce projet ?\")) return;\n\n      state.fence = state.fence || \"chain\";\n\n      [\"addressSearchInput\",\"streetNumberInput\",\"routeInput\",\"cityInput\",\"provinceInput\",\"postalCodeInput\",\"suiteInput\",\"phoneInput\",\"lengthInput\",\"heightInput\",\"gateInput\"].forEach((id) => {\n        const el = byId(id);\n        if (el) el.value = \"\";\n      });\n\n      const repairSelect = byId(\"repairTypeSelect\");\n      if (repairSelect) repairSelect.selectedIndex = 0;\n\n      state.photoFiles = [];\n      setStoredPhotos([]);\n      syncPhotoCount();\n      renderPhotoThumbs();\n\n      setProject({\n        fence: state.fence,\n        address: \"\",\n        streetNumber: \"\",\n        route: \"\",\n        city: \"\",\n        province: \"\",\n        postalCode: \"\",\n        suite: \"\",\n        phone: \"\",\n        length: \"\",\n        height: \"\",\n        gate: \"\",\n        repairType: repairSelect ? repairSelect.value : \"\",\n        photoCount: 0,\n        status: \"new\",\n        updatedAt: new Date().toISOString(),\n      });\n\n      state.dashboardState = \"new\";\n      renderAll();\n    };\n\n    window.hideRequestFromHistory = async (requestId) => {\n      const user = auth.currentUser;\n      if (!user || !requestId) return;\n      if (!confirm(\"Retirer cette demande de votre historique ?\")) return;\n\n      try {\n        await updateDoc(doc(db, \"requests\", requestId), {\n          archivedByUser: true,\n          archivedAt: serverTimestamp(),\n          updatedAt: serverTimestamp()\n        });\n      } catch (err) {\n        console.error(\"hideRequestFromHistory error:\", err);\n        alert(\"Impossible de retirer cette demande pour le moment.\");\n      }\n    };\n\n    window.submitQuoteRequest = async () => {\n      const c = copy[state.lang];\n      const user = auth.currentUser;\n      if (!user) {\n        go(\"auth\");\n        return;\n      }\n\n      const payload = getCurrentProjectPayload();\n      const project = {\n        ...payload,\n        status: \"submitted\",\n        updatedAt: new Date().toISOString(),\n      };\n\n      try {\n        setSubmitButtonState(true);\n\n        const requestData = {\n          uid: user.uid,\n          clientName: state.session?.name || user.displayName || \"\",\n          email: user.email || \"\",\n          address: payload.address || \"\",\n          streetNumber: payload.streetNumber || \"\",\n          route: payload.route || \"\",\n          city: payload.city || \"\",\n          province: payload.province || \"\",\n          postalCode: payload.postalCode || \"\",\n          suite: payload.suite || \"\",\n          phone: payload.phone || \"\",\n          fence: payload.fence,\n          fenceLabel: fences[payload.fence]?.fr || payload.fence,\n          length: payload.length,\n          height: payload.height,\n          gate: payload.gate,\n          repairType: payload.repairType || \"\",\n          photoCount: payload.photoCount || 0,\n          photoNames: (state.photoFiles || []).map(file => file.name || \"photo\"),\n          status: \"submitted\",\n          source: \"clotureo_standalone\",\n          createdAt: serverTimestamp(),\n          updatedAt: serverTimestamp()\n        };\n\n        const docRef = await addDoc(collection(db, \"requests\"), requestData);\n\n        setProject({\n          ...project,\n          requestId: docRef.id,\n          sentAt: new Date().toISOString(),\n        });\n\n        state.dashboardState = \"submitted\";\n        renderDashboard();\n        renderTracking();\n        go(\"tracking\");\n      } catch (err) {\n        console.error(\"submitQuoteRequest error:\", err);\n        alert(c.submitError || \"Impossible d\u2019envoyer la demande pour le moment. R\u00e9essayez.\");\n      } finally {\n        setSubmitButtonState(false);\n      }\n    };\n\n    function renderDashboard(){\n      if(!state.session) return;\n      const c = copy[state.lang];\n      const d = c.dashboard[state.dashboardState];\n      const name = state.session.name || \"\";\n\n      const topTitle = name ? d.topTitle(name) : (state.lang === \"fr\" ? \"Bonjour\" : \"Hello\");\n      byId(\"dashboardTopCard\").innerHTML = `\n        <div class=\"tag\">\u2726 Tableau de bord<\/div>\n        <h2 style=\"margin:0 0 8px;font-size:32px;line-height:1.03\">${topTitle}<\/h2>\n        <p style=\"margin:0;color:#5f574f;line-height:1.6;font-size:14px\">${d.topText}<\/p>\n      `;\n\n      const project = getProject();\n      const liveRequest = state.liveRequest || {};\n      const effectiveFence = liveRequest.fence || project?.fence;\n      const fenceLabel = effectiveFence && fences[effectiveFence] ? fences[effectiveFence].fr : null;\n      const effectiveLength = liveRequest.length || project?.length || \"\";\n      let dynamicTitle = d.mainTitle;\n      if(state.dashboardState === \"quote\" && state.liveQuoteReady){\n        dynamicTitle = `<span class=\"cfc-quote-price-alert\" style=\"font-size:34px;line-height:1\">${formatCurrencyFR(liveRequest.quoteAmount)}<\/span>`;\n      } else if((state.dashboardState === \"progress\" || state.dashboardState === \"submitted\") && (fenceLabel || effectiveLength)){\n        dynamicTitle = `${fenceLabel || d.mainTitle}${effectiveLength ? \" \u2014 \" + effectiveLength : \"\"}`;\n      }\n      const mainText = (state.dashboardState === \"quote\" && state.liveQuoteReady)\n        ? \"Votre demande est pr\u00eate. Appelez-nous pour passer \u00e0 la prochaine \u00e9tape.\"\n        : d.mainText;\n\n      byId(\"dashboardMainCard\").innerHTML = `\n        <div class=\"summary-box\" style=\"background:linear-gradient(135deg,#191919,#2d1214);color:#fff;border:none\">\n          <small style=\"color:rgba(255,255,255,.62)\">${state.dashboardState === \"quote\" ? \"Votre prix est pr\u00eat\" : d.mainLabel}<\/small>\n          <div style=\"font-size:22px;font-weight:800;margin-bottom:8px\">${dynamicTitle}<\/div>\n          <div style=\"color:rgba(255,255,255,.78);line-height:1.6;font-size:14px\">${mainText}<\/div>\n          <div class=\"grid-2\" style=\"margin-top:14px\">\n            <button class=\"btn btn-light\" onclick=\"${primaryAction()}\">${state.dashboardState === \"quote\" ? \"Appelez-nous\" : d.primary}<\/button>\n            <button class=\"btn\" style=\"background:rgba(255,255,255,.10);color:#fff;border:1px solid rgba(255,255,255,.14)\" onclick=\"${secondaryAction()}\">${state.dashboardState === \"quote\" ? \"Voir les d\u00e9tails\" : d.secondary}<\/button>\n          <\/div>\n        <\/div>\n      `;\n\n      byId(\"dashboardQuickCards\").innerHTML = `\n        <button class=\"mini-card\" onclick=\"go('photos')\">\n          <div class=\"icon\">\ud83d\udcf8<\/div><h4>${d.q1}<\/h4><p>${d.q1s}<\/p>\n        <\/button>\n        <button class=\"mini-card\" type=\"button\" id=\"dashboardContactCard\">\n          <div class=\"icon\">\ud83d\udcec<\/div><h4>${d.q2}<\/h4><p>${d.q2s}<\/p>\n        <\/button>\n      `;\n\n      const dashboardContactCard = byId(\"dashboardContactCard\");\n      if (dashboardContactCard) {\n        const openDashboardContact = (evt) => {\n          evt?.preventDefault?.();\n          evt?.stopPropagation?.();\n          if (state.dashboardState === \"quote\" && state.liveRequest) {\n            window.openContactOverlay?.();\n            return false;\n          }\n          window.dashboardQuickSecondaryAction?.();\n          return false;\n        };\n        dashboardContactCard.onclick = openDashboardContact;\n        dashboardContactCard.onpointerup = openDashboardContact;\n        dashboardContactCard.ontouchend = openDashboardContact;\n      }\n\n      byId(\"dashboardActionsCard\").innerHTML = `\n        <div style=\"margin-bottom:12px\">\n          <div class=\"muted\" style=\"font-weight:700\">${d.actionsTitle}<\/div>\n          <div style=\"font-size:18px;font-weight:800\">${d.actionsSub}<\/div>\n        <\/div>\n        ${actionRow(d.a1, d.a1s, \"go('project')\")}\n        ${actionRow(d.a2, d.a2s, \"inviteNeighbor()\")}\n      `;\n\n      renderRequestHistory();\n\n      byId(\"dashboardAccountCard\").innerHTML = `\n        <button class=\"btn btn-soft\" onclick=\"signOut()\">${c.signOutBtn}<\/button>\n      `;\n\n      const stateSwitch = byId(\"stateSwitch\");\n      if (stateSwitch) stateSwitch.value = state.dashboardState;\n    }\n\n    function actionRow(title, sub, click){\n      return `\n        <button onclick=\"${click}\" style=\"width:100%;text-align:left;border:none;background:#fff;border-radius:24px;padding:14px 16px;box-shadow:0 8px 20px rgba(0,0,0,.06);border:1px solid rgba(0,0,0,.08);display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:10px;cursor:pointer\">\n          <div style=\"min-width:0;flex:1 1 auto\"><div style=\"font-weight:800\">${title}<\/div><div class=\"muted\" style=\"margin-top:4px;overflow-wrap:anywhere\">${sub}<\/div><\/div>\n          <div style=\"font-size:20px;color:#8f1d22;flex:0 0 auto\">\u203a<\/div>\n        <\/button>\n      `;\n    }\n\n    function requestStatusLabel(status){\n      return {\n        submitted: \"Demande envoy\u00e9e\",\n        under_review: \"Demande \u00e0 l\u2019\u00e9tude\",\n        quote_ready: \"Votre prix est pr\u00eat\",\n        approved: \"Projet accept\u00e9\",\n        scheduled: \"Travaux planifi\u00e9s\"\n      }[status] || \"Demande envoy\u00e9e\";\n    }\n\n    function formatRequestDate(value){\n      const ts = normalizeFirestoreDate(value);\n      if (!ts) return \"\";\n      try {\n        return new Intl.DateTimeFormat(\"fr-CA\", { dateStyle:\"medium\" }).format(new Date(ts));\n      } catch {\n        return \"\";\n      }\n    }\n\n    function renderRequestHistory(){\n      const container = byId(\"dashboardHistoryCard\");\n      if (!container) return;\n      const rows = (state.requestHistory || []).slice(0, 6);\n\n      if (!rows.length) {\n        container.innerHTML = `\n          <div style=\"margin-bottom:12px\">\n            <div class=\"muted\" style=\"font-weight:700\">Mes demandes<\/div>\n            <div style=\"font-size:18px;font-weight:800\">Aucune demande enregistr\u00e9e<\/div>\n          <\/div>\n          <div class=\"muted\">Vos demandes appara\u00eetront ici apr\u00e8s l\u2019envoi.<\/div>\n        `;\n        return;\n      }\n\n      container.innerHTML = `\n        <div style=\"margin-bottom:12px\">\n          <div class=\"muted\" style=\"font-weight:700\">Mes demandes<\/div>\n          <div style=\"font-size:18px;font-weight:800\">Historique de mes projets<\/div>\n        <\/div>\n        ${rows.map((req) => {\n          const fenceLabel = req.fence ? (fences[req.fence]?.fr || req.fence) : \"Projet\";\n          const line2 = [req.city || \"\", requestStatusLabel(req.status), formatRequestDate(req.createdAt)].filter(Boolean).join(\" \u2022 \");\n          const right = req.status === \"quote_ready\" && Number.isFinite(Number(req.quoteAmount))\n            ? formatCurrencyFR(req.quoteAmount)\n            : \"\";\n          return `\n            <div style=\"background:#fff;border-radius:22px;padding:14px 16px;box-shadow:0 8px 20px rgba(0,0,0,.06);border:1px solid rgba(0,0,0,.08);margin-top:10px\">\n              <div style=\"display:flex;justify-content:space-between;gap:12px;align-items:flex-start\">\n                <div>\n                  <div style=\"font-weight:800\">${fenceLabel}${req.length ? \" \u2014 \" + req.length : \"\"}<\/div>\n                  <div class=\"muted\" style=\"margin-top:4px\">${line2 || \"Demande envoy\u00e9e\"}<\/div>\n                <\/div>\n                ${right ? `<div style=\"font-weight:800;color:#8f1d22;white-space:nowrap\">${right}<\/div>` : \"\"}\n              <\/div>\n              <div style=\"display:flex;gap:10px;margin-top:12px\">\n                <button class=\"btn btn-soft\" style=\"height:44px\" type=\"button\" onclick=\"go('tracking')\">Voir<\/button>\n                <button class=\"btn btn-light\" style=\"height:44px\" type=\"button\" onclick=\"hideRequestFromHistory('${req.id}')\">Retirer<\/button>\n              <\/div>\n            <\/div>\n          `;\n        }).join(\"\")}\n      `;\n    }\n\n    function primaryAction(){\n      if(state.dashboardState === \"submitted\") return \"go('tracking')\";\n      if(state.dashboardState === \"quote\") return \"window.location.href='tel:4507754897'\";\n      return \"go('project')\";\n    }\n\n    function secondaryAction(){\n      if(state.dashboardState === \"submitted\") return \"go('project')\";\n      if(state.dashboardState === \"quote\") return \"go('tracking')\";\n      if(state.dashboardState === \"new\") return \"go('project')\";\n      return \"go('photos')\";\n    }\n\n\n    function dashboardQuickSecondaryAction(){\n      if(state.dashboardState === \"quote\") {\n        openContactOverlay();\n        return;\n      }\n      go('tracking');\n    }\n\n    function getActiveRequestLabel(){\n      const c = copy[state.lang];\n      const req = state.liveRequest || {};\n      const fenceLabel = req.fence ? (fences[req.fence]?.[state.lang] || fences[req.fence]?.fr || req.fence) : \"\";\n      return [fenceLabel, req.length].filter(Boolean).join(\" \u2014 \") || c.contactOverlayFallback;\n    }\n\n    window.openContactOverlay = () => {\n      const c = copy[state.lang];\n      const overlay = byId(\"contactOverlay\");\n      const input = byId(\"contactMessageInput\");\n      const notice = byId(\"contactNotice\");\n      setText(\"contactOverlayTitle\", c.contactOverlayTitle);\n      setText(\"contactOverlaySub\", c.contactOverlaySub);\n      setText(\"contactRequestLabel\", getActiveRequestLabel());\n      if (input) {\n        input.placeholder = c.contactOverlayPlaceholder;\n        input.value = \"\";\n      }\n      if (notice) {\n        notice.textContent = c.contactOverlayHint;\n        notice.className = \"notice\";\n      }\n      overlay?.classList.add(\"show\");\n      setTimeout(() => input?.focus(), 30);\n    };\n\n    window.closeContactOverlay = (evt) => {\n      if (evt && evt.target && evt.target.id !== \"contactOverlay\") return;\n      byId(\"contactOverlay\")?.classList.remove(\"show\");\n    };\n\n    window.sendContactMessage = async () => {\n      const c = copy[state.lang];\n      const input = byId(\"contactMessageInput\");\n      const notice = byId(\"contactNotice\");\n      const sendBtn = byId(\"contactSendBtn\");\n      const message = String(input?.value || \"\").trim();\n      const liveRequest = state.liveRequest;\n\n      if (!liveRequest?.id) {\n        if (notice) {\n          notice.textContent = c.contactOverlayNoRequest;\n          notice.className = \"notice error\";\n        }\n        return;\n      }\n\n      if (!message) {\n        if (notice) {\n          notice.textContent = c.contactOverlayEmpty;\n          notice.className = \"notice error\";\n        }\n        input?.focus();\n        return;\n      }\n\n      try {\n        if (sendBtn) {\n          sendBtn.disabled = true;\n          sendBtn.textContent = c.contactOverlaySending;\n          sendBtn.style.opacity = \"0.7\";\n        }\n        await addDoc(collection(db, \"requests\", liveRequest.id, \"messages\"), {\n          uid: state.session?.uid || auth.currentUser?.uid || \"\",\n          requestId: liveRequest.id,\n          requestTitle: getActiveRequestLabel(),\n          requestStatus: liveRequest.status || \"\",\n          clientName: state.session?.name || auth.currentUser?.displayName || \"\",\n          email: auth.currentUser?.email || state.session?.email || \"\",\n          phone: liveRequest.phone || getProject()?.phone || \"\",\n          message,\n          source: \"customer_app\",\n          createdAt: serverTimestamp()\n        });\n        if (notice) {\n          notice.textContent = c.contactOverlaySent;\n          notice.className = \"notice success\";\n        }\n        if (input) input.value = \"\";\n        setTimeout(() => closeContactOverlay(), 900);\n      } catch (err) {\n  console.error(\"sendContactMessage error:\", err);\n  if (notice) {\n    notice.textContent = err?.code\n      ? `Erreur Firestore: ${err.code}`\n      : \"Impossible d\u2019envoyer la demande pour le moment. R\u00e9essayez.\";\n    notice.className = \"notice error\";\n  }\n} finally {\n        if (sendBtn) {\n          sendBtn.disabled = false;\n          sendBtn.textContent = c.contactOverlaySendBtn;\n          sendBtn.style.opacity = \"\";\n        }\n      }\n    };\n\n    window.inviteNeighbor = async () => {\n      const lang = state.lang || \"fr\";\n      const shareUrl = `${location.origin}${location.pathname}`;\n      const shareData = lang === \"fr\"\n        ? { title: \"Cl\u00f4tur\u00e9o\", text: \"Demandez votre soumission de cl\u00f4ture avec Cl\u00f4tur\u00e9o.\", url: shareUrl }\n        : { title: \"Cl\u00f4tur\u00e9o\", text: \"Request your fence quote with Cl\u00f4tur\u00e9o.\", url: shareUrl };\n\n      if (navigator.share) {\n        try {\n          await navigator.share(shareData);\n          return;\n        } catch (err) {\n          if (err && err.name === \"AbortError\") return;\n        }\n      }\n\n      byId(\"inviteOverlay\")?.classList.add(\"show\");\n      byId(\"inviteSheet\")?.classList.add(\"show\");\n      const notice = byId(\"inviteNotice\");\n      if (notice) {\n        notice.textContent = copy[lang].inviteNotice;\n        notice.className = \"notice\";\n      }\n    };\n\n    window.closeInviteSheet = () => {\n      byId(\"inviteOverlay\")?.classList.remove(\"show\");\n      byId(\"inviteSheet\")?.classList.remove(\"show\");\n    };\n\n    window.inviteAction = async (kind) => {\n      const c = copy[state.lang];\n      const notice = byId(\"inviteNotice\");\n      const shareUrl = `${location.origin}${location.pathname}`;\n      const messages = {\n        fr: {\n          text: \"Regarde Cl\u00f4tur\u00e9o pour demander une soumission de cl\u00f4ture.\",\n          emailSubject: \"D\u00e9couvre Cl\u00f4tur\u00e9o\",\n          emailBody: `Regarde Cl\u00f4tur\u00e9o pour demander une soumission de cl\u00f4ture : ${shareUrl}`\n        },\n        en: {\n          text: \"Check out Cl\u00f4tur\u00e9o to request a fence quote.\",\n          emailSubject: \"Check out Cl\u00f4tur\u00e9o\",\n          emailBody: `Check out Cl\u00f4tur\u00e9o to request a fence quote: ${shareUrl}`\n        }\n      };\n      const msg = messages[state.lang] || messages.fr;\n      const map = {\n        contact: c.inviteResultContact,\n        text: c.inviteResultText,\n        email: c.inviteResultEmail,\n        link: c.inviteResultLink,\n      };\n\n      try {\n        if (kind === \"text\") {\n          location.href = `sms:?body=${encodeURIComponent(msg.text + ' ' + shareUrl)}`;\n        } else if (kind === \"email\") {\n          location.href = `mailto:?subject=${encodeURIComponent(msg.emailSubject)}&body=${encodeURIComponent(msg.emailBody)}`;\n        } else if (kind === \"link\" && navigator.clipboard) {\n          await navigator.clipboard.writeText(shareUrl);\n        } else if (kind === \"contact\" && navigator.share) {\n          await navigator.share({ title: 'Cl\u00f4tur\u00e9o', text: msg.text, url: shareUrl });\n          closeInviteSheet();\n          return;\n        }\n      } catch (err) {}\n\n      if (notice) {\n        notice.textContent = map[kind] || c.inviteNotice;\n        notice.className = \"notice success\";\n      }\n    };\n\n    function renderTracking(){\n      const c = copy[state.lang];\n      const liveStatus = state.liveRequest?.status || \"\";\n      const steps = c.timeline[state.dashboardState];\n      let doneCount = state.dashboardState === \"new\" ? 1 : state.dashboardState === \"progress\" ? 2 : state.dashboardState === \"submitted\" ? 3 : 4;\n      if (liveStatus === \"quote_ready\") doneCount = 4;\n      const container = byId(\"trackingTimeline\");\n      if (!container) return;\n      container.innerHTML = steps.map((s, i) => `\n        <div class=\"timeline-item\">\n          <div class=\"dot ${i < doneCount ? \"done\" : \"\"}\"><\/div>\n          <div><strong>${s}<\/strong><div class=\"muted\">${i < doneCount ? c.completed : c.pending}<\/div><\/div>\n        <\/div>\n      `).join(\"\");\n    }\n\n    function renderFence(){\n      const f = fences[state.fence];\n      const select = byId(\"fenceTypeSelect\");\n      if(select) select.value = state.fence;\n      const summary = byId(\"summaryFence\");\n      if(summary) summary.textContent = f.fr;\n      const repairBox = byId(\"repairTypeBox\");\n      if(repairBox) repairBox.style.display = state.fence === \"repair\" ? \"block\" : \"none\";\n      const summaryPhotos = byId(\"summaryPhotosCount\");\n      if(summaryPhotos){\n        const count = (state.photoFiles || []).length || 0;\n        summaryPhotos.textContent = `${count} photo${count > 1 ? \"s\" : \"\"}`;\n      }\n\n      const project = getProject();\n      if(project){\n        const address = byId(\"addressSearchInput\");\n        const streetNumber = byId(\"streetNumberInput\");\n        const route = byId(\"routeInput\");\n        const city = byId(\"cityInput\");\n        const province = byId(\"provinceInput\");\n        const postalCode = byId(\"postalCodeInput\");\n        const suite = byId(\"suiteInput\");\n        const phone = byId(\"phoneInput\");\n        const length = byId(\"lengthInput\");\n        const height = byId(\"heightInput\");\n        const gate = byId(\"gateInput\");\n        const repairSelect = byId(\"repairTypeSelect\");\n        if(address && !address.value) address.value = project.address || \"\";\n        if(streetNumber && !streetNumber.value) streetNumber.value = project.streetNumber || \"\";\n        if(route && !route.value) route.value = project.route || \"\";\n        if(city && !city.value) city.value = project.city || \"\";\n        if(province && !province.value) province.value = project.province || \"\";\n        if(postalCode && !postalCode.value) postalCode.value = project.postalCode || \"\";\n        if(suite && !suite.value) suite.value = project.suite || \"\";\n        if(phone && !phone.value) phone.value = project.phone || \"\";\n        if(length && !length.value) length.value = project.length || \"\";\n        if(height && !height.value) height.value = project.height || \"\";\n        if(gate && !gate.value) gate.value = project.gate || \"\";\n        if(repairSelect && project.repairType) repairSelect.value = project.repairType;\n      }\n    }\n\n    window.changeFenceType = (value) => {\n      state.fence = value;\n      renderFence();\n    };\n\n    function renderText(){\n      const c = copy[state.lang];\n      setText(\"headerTitle\", c.headers[state.screen] || c.headers.auth);\n      setText(\"authTagline\", c.authTagline);\n      setText(\"authHero\", c.authHero);\n      setText(\"authSubhero\", c.authSubhero);\n      setText(\"tabSignIn\", c.tabSignIn);\n      setText(\"tabCreate\", c.tabCreate);\n      setPlaceholder(\"signinEmail\", c.signinEmail);\n      setPlaceholder(\"signinPassword\", c.signinPassword);\n      setText(\"signinBtn\", c.signinBtn);\n      setPlaceholder(\"createName\", c.createName);\n      setPlaceholder(\"createEmail\", c.createEmail);\n      setPlaceholder(\"createPassword\", c.createPassword);\n      setPlaceholder(\"createPassword2\", c.createPassword2);\n      setText(\"createBtn\", c.createBtn);\n      setText(\"googleBtn\", c.googleBtn);\n      setText(\"authNotice\", c.authNotice);\n      setText(\"signedInBadge\", c.signedIn);\n      setText(\"inviteSheetTitle\", c.inviteSheetTitle);\n      setText(\"inviteSheetSub\", c.inviteSheetSub);\n      setText(\"inviteContactTitle\", c.inviteContactTitle);\n      setText(\"inviteContactSub\", c.inviteContactSub);\n      setText(\"inviteTextTitle\", c.inviteTextTitle);\n      setText(\"inviteTextSub\", c.inviteTextSub);\n      setText(\"inviteEmailTitle\", c.inviteEmailTitle);\n      setText(\"inviteEmailSub\", c.inviteEmailSub);\n      setText(\"inviteLinkTitle\", c.inviteLinkTitle);\n      setText(\"inviteLinkSub\", c.inviteLinkSub);\n      setText(\"contactOverlayTitle\", c.contactOverlayTitle);\n      setText(\"contactOverlaySub\", c.contactOverlaySub);\n      setText(\"contactRequestLabel\", c.contactOverlayFallback);\n      setText(\"contactRegardingLabel\", c.contactOverlayRegarding);\n      setText(\"contactCloseBtn\", c.contactOverlayCloseBtn);\n      setPlaceholder(\"contactMessageInput\", c.contactOverlayPlaceholder);\n      setText(\"contactNotice\", c.contactOverlayHint);\n      setText(\"contactSendBtn\", c.contactOverlaySendBtn);\n      setText(\"inviteNotice\", c.inviteNotice);\n      const sub = byId(\"headerSubline\");\n      if (sub) sub.textContent = state.session ? state.session.email : \"\";\n      setText(\"confirmTag\", c.confirmTag);\n      setText(\"confirmHero\", c.confirmHero);\n      setText(\"confirmSubhero\", c.confirmSubhero);\n      setText(\"confirmSentToLabel\", c.confirmSentTo);\n      setText(\"confirmBtn\", c.confirmBtn);\n      setText(\"resendBtn\", c.resendBtn);\n      setText(\"backToAuthBtn\", c.backToAuth);\n      setText(\"openInboxBtn\", c.openInbox);\n      setText(\"changeEmailBtn\", c.changeEmail);\n      setText(\"confirmNotice\", c.confirmNotice);\n      setText(\"navHome\", c.navHome);\n      setText(\"navProject\", c.navProject);\n      setText(\"navTracking\", c.navTracking);\n      setText(\"navAccount\", state.session ? \"Quitter\" : c.navAccount);\n\n      const stateSwitch = byId(\"stateSwitch\");\n      if (stateSwitch) {\n        stateSwitch.options[0].text = c.stateOptions.new;\n        stateSwitch.options[1].text = c.stateOptions.progress;\n        stateSwitch.options[2].text = c.stateOptions.submitted;\n        stateSwitch.options[3].text = c.stateOptions.quote;\n      }\n\n      setText(\"projectTitle\", c.projectTitle);\n      setText(\"saveDraftBtn\", c.saveDraft);\n      setText(\"projectTypeLabel\", c.projectTypeLabel);\n      setText(\"repairTypeLabel\", c.repairTypeLabel);\n\n      const repairOptions = c.repairOptions.split(\"|\");\n      const repairSelect = byId(\"repairTypeSelect\");\n      if(repairSelect){\n        Array.from(repairSelect.options).forEach((opt, i) => {\n          if(repairOptions[i]) opt.textContent = repairOptions[i];\n        });\n      }\n\n      const fenceSelect = byId(\"fenceTypeSelect\");\n      if(fenceSelect){\n        fenceSelect.options[0].textContent = \"Maille de cha\u00eene\";\n        fenceSelect.options[1].textContent = \"Bois\";\n        fenceSelect.options[2].textContent = \"Cl\u00f4ture de piscine\";\n        fenceSelect.options[3].textContent = \"Ranch\";\n        fenceSelect.options[4].textContent = \"R\u00e9paration\";\n      }\n\n      setText(\"photosTitle\", c.photosTitle);\n      setText(\"uploadTitle\", c.uploadTitle);\n      setText(\"uploadMeta\", c.uploadMeta || \"JPG, PNG, HEIC \u2014 ajoutez jusqu\u2019\u00e0 3 photos\");\n      setText(\"pickPhotosBtn\", c.pickPhotosBtn || \"Choisir des photos\");\n      setText(\"clearPhotosBtn\", c.clearPhotosBtn || \"Effacer\");\n      setText(\"photosNotice\", c.photosNotice || \"Ajoutez jusqu\u2019\u00e0 3 photos de la zone \u00e0 cl\u00f4turer, des acc\u00e8s, des pentes et des portes existantes si possible.\");\n      setText(\"summaryTitle\", c.summaryTitle);\n      setText(\"summaryText\", c.summaryText);\n      setText(\"summaryPhotosLabel\", c.summaryPhotos || \"Photos\");\n      setText(\"submitBtn\", c.submitBtn);\n      setText(\"trackingTitle\", c.trackingTitle);\n      setText(\"homeBtn\", c.homeBtn);\n      setText(\"back3\", c.back);\n      setText(\"back4\", c.back);\n      setText(\"next1\", c.next);\n      setText(\"next2\", c.next);\n      setText(\"addressHelp\", c.addressHelp || \"\");\n      setPlaceholder(\"addressSearchInput\", c.addressSearch || \"Adresse du projet\");\n      setPlaceholder(\"streetNumberInput\", c.streetNumber || \"No civique\");\n      setPlaceholder(\"routeInput\", c.route || \"Rue\");\n      setPlaceholder(\"cityInput\", c.city || \"Ville\");\n      setPlaceholder(\"provinceInput\", c.province || \"Province\");\n      setPlaceholder(\"postalCodeInput\", c.postalCode || \"Code postal\");\n      setPlaceholder(\"suiteInput\", c.suite || \"Appartement \/ suite (facultatif)\");\n      setPlaceholder(\"phoneInput\", c.phone || \"T\u00e9l\u00e9phone\");\n      setPlaceholder(\"lengthInput\", \"Longueur approximative (ex. 160 pi)\");\n      setPlaceholder(\"heightInput\", \"Hauteur souhait\u00e9e (ex. 6')\");\n      setPlaceholder(\"gateInput\", \"Portes (ex. 1 simple)\");\n      renderDashboard();\n      renderTracking();\n      renderFence();\n      renderPhotoThumbs();\n    }\n\n    function renderSessionUI(){\n      const logged = !!state.session;\n      setText(\"authActionBtn\", logged ? \"\u238b\" : \"\ud83d\udc64\");\n      setText(\"navAccount\", logged ? \"Quitter\" : copy[state.lang].navAccount);\n    }\n\n    function renderAll(){\n      try {\n        renderSessionUI();\n        renderText();\n      } catch (err) {\n        console.error(\"renderAll crash:\", err);\n      }\n    }\n\n    window.go = (screen) => {\n      if(!state.session && screen !== \"auth\" && screen !== \"confirm\"){\n        screen = \"auth\";\n      }\n      state.screen = screen;\n      document.querySelectorAll(\".view\").forEach(v => v.classList.add(\"hidden\"));\n      const el = byId(screen);\n      if(el){ el.classList.remove(\"hidden\"); el.classList.remove(\"fade\"); void el.offsetWidth; el.classList.add(\"fade\"); }\n      document.querySelectorAll(\".nav-btn\").forEach(btn => btn.classList.toggle(\"active\", btn.dataset.screen === screen));\n      setText(\"headerTitle\", copy[state.lang].headers[screen] || copy[state.lang].headers.auth);\n    };\n\n    onAuthStateChanged(auth, async (user) => {\n      const project = getProject();\n      loadStoredPhotoMetadata();\n      state.liveRequest = null;\n      state.liveQuoteReady = false;\n      if(project?.status === \"submitted\"){\n        state.dashboardState = \"submitted\";\n        if(project.fence) state.fence = project.fence;\n      } else if(project?.status === \"progress\"){\n        state.dashboardState = \"progress\";\n        if(project.fence) state.fence = project.fence;\n      } else {\n        state.dashboardState = \"new\";\n      }\n\n      if (currentRequestUnsub) {\n        currentRequestUnsub();\n        currentRequestUnsub = null;\n      }\n\n      if (user) {\n  await reload(user);\n  clearLegacyLocalDrafts();\n  const cleanDisplayName = (user.displayName || \"\").trim();\n  state.session = {\n    uid: user.uid,\n    name: cleanDisplayName || \"\",\n    email: user.email || ''\n  };\n  renderAll();\n        if (user.emailVerified) {\n          watchLatestRequest(user);\n          go(\"home\");\n        } else {\n          setText(\"confirmEmailValue\", user.email || \"\");\n          go(\"confirm\");\n        }\n      } else {\n        state.session = null;\n        closeQuoteOverlay();\n        renderAll();\n        go(\"auth\");\n      }\n    });\n\n    window.setAuthMode(\"create\");\n    renderAll();\n  <\/script>\n\n  <script async src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=AIzaSyBLSfcF6rplFf2jp0C9ht4kU95vFDqr8H0&libraries=places&callback=initGoogleAddressAutocomplete\"><\/script>\n<\/body>\n<\/html>\n<\/div><\/div><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":7,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"100-width.php","meta":{"footnotes":""},"class_list":["post-8698","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/pages\/8698","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/comments?post=8698"}],"version-history":[{"count":0,"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/pages\/8698\/revisions"}],"wp:attachment":[{"href":"https:\/\/cfcquebec.ca\/en\/wp-json\/wp\/v2\/media?parent=8698"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}