templates/application/whileresume/website/candidates/landing.html.twig line 1

Open in your IDE?
  1. {% extends 'application/whileresume/website/layout-social.html.twig' %}
  2. {% set isFR = app.request.locale == 'fr' %}
  3. {% set _keys = [
  4.     'hero_search_placeholder','hero_popular_label',
  5.     'hero_byline_jobs','hero_byline_apps','hero_byline_free','hero_kbd_enter',
  6.     'hero_cta_signup','hero_cta_login',
  7.     'search_loading','search_no_results','search_no_results_hint','search_results_count','search_view_all','search_view_offer','search_clear',
  8.     'how_title',
  9.     'apps_ios','apps_android','apps_web','apps_ios_desc','apps_android_desc','apps_web_desc',
  10.     'articles_title','articles_view_all','read_article',
  11.     'final_title',
  12.     'final_recruiter_label','final_recruiter_title','final_recruiter_desc',
  13.     'final_candidate_label','final_candidate_title','final_candidate_desc',
  14.     'final_candidate','final_recruiter'
  15. ] %}
  16. {% set t = {} %}
  17. {% for k in _keys %}
  18.     {% set t = t|merge({(k): ('homepage.' ~ k)|trans({}, 'whr-public')}) %}
  19. {% endfor %}
  20. {% block title %}{{ landing.shortTitle }}{% endblock %}
  21. {% block description %}{{ landing.shortDescription }}{% endblock %}
  22. {% block robots %}index,follow{% endblock %}
  23. {% block canonical %}{#% include "/vitrine/lexend/components/languages/canonical_classic.html.twig" %#}{% endblock %}
  24. {% block css %}
  25.     {{ parent() }}
  26.     <style>
  27.         :root{
  28.             --wr-bg:#FBFCFE;
  29.             --wr-bg-2:#F4F6FB;
  30.             --wr-card:#FFFFFF;
  31.             --wr-violet:#8A63C1;
  32.             --wr-violet-2:#A98AD3;
  33.             --wr-violet-soft:#F2EDFA;
  34.             --wr-violet-softer:#F8F4FD;
  35.             --wr-violet-dark:#6B47A6;
  36.             --wr-ink:#1E1B2E;
  37.             --wr-ink-2:#374151;
  38.             --wr-muted:#6B7280;
  39.             --wr-muted-2:#9CA3AF;
  40.             --wr-line:#EEF1F7;
  41.             --wr-line-2:#E5E9F0;
  42.             --wr-shadow:0 1px 2px rgba(30,27,46,.04),0 4px 16px rgba(30,27,46,.04);
  43.             --wr-shadow-hover:0 4px 8px rgba(138,99,192,.08),0 12px 32px rgba(138,99,192,.1);
  44.             --wr-acc-yellow:#FEF3C7;  --wr-acc-yellow-fg:#B45309;
  45.             --wr-acc-green:#D1FAE5;   --wr-acc-green-fg:#047857;
  46.             --wr-acc-pink:#FCE7F3;    --wr-acc-pink-fg:#BE185D;
  47.             --wr-acc-blue:#DBEAFE;    --wr-acc-blue-fg:#1E40AF;
  48.             --wr-acc-orange:#FED7AA;  --wr-acc-orange-fg:#C2410C;
  49.             --wr-acc-violet:#EDE9FE;  --wr-acc-violet-fg:#6D28D9;
  50.             --wr-acc-cyan:#CFFAFE;    --wr-acc-cyan-fg:#0E7490;
  51.         }
  52.         body .main-content.right-chat-active{padding-right:0!important}
  53.         body .main-content{padding-right:0!important}
  54.         body .right-chat{display:none!important}
  55.         body .middle-sidebar-bottom .middle-sidebar-left{padding-right:0!important;max-width:none!important;width:100%!important}
  56.         body .middle-sidebar-bottom{max-width:none!important}
  57.         .wr{margin:-15px -15px 0;background:var(--wr-bg);color:var(--wr-ink);font-family:inherit;font-size:15px;line-height:1.6;-webkit-font-smoothing:antialiased}
  58.         @media(max-width:991px){.wr{margin:0 -15px}}
  59.         .wr *{box-sizing:border-box}
  60.         .wr a{color:inherit;text-decoration:none}
  61.         .wr-section{padding:80px 32px;background:var(--wr-bg);position:relative}
  62.         .wr-section--tight{padding:48px 32px}
  63.         @media(max-width:768px){.wr-section{padding:56px 20px}.wr-section--tight{padding:36px 20px}}
  64.         .wr-section + .wr-section::before{
  65.             content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
  66.             width:80px;height:1px;
  67.             background:linear-gradient(90deg,transparent,var(--wr-line-2),transparent);
  68.         }
  69.         .wr-container{max-width:1200px;margin:0 auto;position:relative}
  70.         .wr-eyebrow{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:100px;background:var(--wr-violet-soft);color:var(--wr-violet-dark);font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.12em;margin-bottom:22px}
  71.         .wr-eyebrow-dot{width:6px;height:6px;border-radius:50%;background:var(--wr-violet);animation:wrPulse 2.4s ease-in-out infinite}
  72.         @keyframes wrPulse{0%,100%{opacity:.5;transform:scale(1)}50%{opacity:1;transform:scale(1.3)}}
  73.         .wr-title{font-family:inherit !important;font-weight:700 !important;font-size:28px;line-height:1.15;letter-spacing:-0.025em;color:var(--wr-ink) !important;margin:0 auto 16px;max-width:1200px;text-align:center}
  74.         @media(min-width:768px){.wr-title{font-size:34px}}
  75.         @media(min-width:1024px){.wr-title{font-size:40px}}
  76.         .wr-title--sm{font-size:24px}
  77.         @media(min-width:768px){.wr-title--sm{font-size:30px}}
  78.         .wr-title em{font-style:normal;font-weight:700 !important;color:var(--wr-violet) !important}
  79.         .wr-lede{font-size:17px;line-height:1.55;font-weight:400;color:var(--wr-ink-2) !important;margin:0 auto;max-width:680px}
  80.         .wr-section-head{text-align:center;margin-bottom:56px}
  81.         @keyframes wrFadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
  82.         @keyframes wrPulse2{0%{box-shadow:0 0 0 0 rgba(16,185,129,.4)}70%{box-shadow:0 0 0 8px rgba(16,185,129,0)}100%{box-shadow:0 0 0 0 rgba(16,185,129,0)}}
  83.         .reveal{opacity:0;transform:translateY(24px);transition:opacity .8s cubic-bezier(.2,.7,.2,1),transform .8s cubic-bezier(.2,.7,.2,1)}
  84.         .reveal.is-revealed{opacity:1;transform:translateY(0)}
  85.         .reveal--left{transform:translateX(-32px) translateY(0)}
  86.         .reveal--left.is-revealed{transform:translateX(0)}
  87.         .reveal--right{transform:translateX(32px) translateY(0)}
  88.         .reveal--right.is-revealed{transform:translateX(0)}
  89.         .reveal--scale{transform:scale(.96);opacity:0}
  90.         .reveal--scale.is-revealed{transform:scale(1);opacity:1}
  91.         .reveal[data-reveal-delay="1"]{transition-delay:.08s}
  92.         .reveal[data-reveal-delay="2"]{transition-delay:.16s}
  93.         .reveal[data-reveal-delay="3"]{transition-delay:.24s}
  94.         .reveal[data-reveal-delay="4"]{transition-delay:.32s}
  95.         @media(prefers-reduced-motion:reduce){.reveal{opacity:1!important;transform:none!important;transition:none!important}}
  96.         /* ═══ HERO ═══ */
  97.         .hero{position:relative;background:var(--wr-bg);padding:24px 32px 0;overflow:hidden}
  98.         @media(max-width:768px){.hero{padding:18px 18px 0}}
  99.         .hero::before{content:"";position:absolute;top:-260px;right:-180px;width:560px;height:560px;background:radial-gradient(circle,rgba(138,99,192,.14) 0%,transparent 65%);pointer-events:none;filter:blur(50px)}
  100.         .hero::after{content:"";position:absolute;top:120px;left:-180px;width:480px;height:480px;background:radial-gradient(circle,rgba(138,99,192,.09) 0%,transparent 65%);pointer-events:none;filter:blur(50px)}
  101.         .hero-inner{position:relative;z-index:2;max-width:1200px;margin:0 auto;text-align:center}
  102.         .hero-badge{display:inline-flex;align-items:center;gap:8px;padding:7px 16px;border-radius:100px;background:var(--wr-violet-soft);color:var(--wr-violet-dark);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.1em;margin-bottom:10px;opacity:0;transform:translateY(8px);animation:wrFadeUp .8s ease forwards}
  103.         .hero-badge-dot{width:6px;height:6px;border-radius:50%;background:var(--wr-violet);animation:wrPulse2 2s ease infinite}
  104.         /* H1 — on force la couleur et la taille pour battre les styles globaux du layout social */
  105.         .wr .hero-title{font-family:inherit !important;font-weight:700 !important;font-size:32px;line-height:1.05;letter-spacing:-0.04em;color:var(--wr-ink) !important;margin:0 auto 12px;width:100%;max-width:1200px;opacity:0;transform:translateY(12px);animation:wrFadeUp .9s cubic-bezier(.2,.7,.2,1) .15s forwards;text-align:center}
  106.         @media(min-width:768px){.wr .hero-title{font-size:48px;letter-spacing:-0.045em}}
  107.         @media(min-width:1100px){.wr .hero-title{font-size:57px;letter-spacing:-0.045em}}
  108.         .wr .hero-title-accent{color:var(--wr-violet) !important;font-weight:700 !important}
  109.         .wr .hero-lede{font-size:16px;line-height:1.5;color:var(--wr-ink-2) !important;font-weight:400;margin:0 auto 16px;max-width:680px;opacity:0;animation:wrFadeUp .9s ease .4s forwards;text-align:center}
  110.         @media(min-width:768px){.wr .hero-lede{font-size:18px}}
  111.         .wr .hero-lede-accent{color:var(--wr-violet) !important;font-weight:600}
  112.         .hero-search-wrap{max-width:1200px;margin:0 auto 12px;opacity:0;animation:wrFadeUp .9s ease .55s forwards;position:relative;z-index:5}
  113.         .hero-search{background:var(--wr-card);border-radius:14px;box-shadow:0 0 20px 0 rgba(0,0,0,0.05),0 16px 40px rgba(138,99,192,.06);padding:10px;position:relative}
  114.         .hero-search-inner{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:10px;background:#F9FAFB;border:1px solid #E5E7EB;transition:border-color .2s,background .2s}
  115.         .hero-search-inner:focus-within{border-color:rgba(138,99,192,.4);background:#fff}
  116.         .hero-search-icon{color:var(--wr-muted-2);display:flex;flex-shrink:0}
  117.         .hero-search-icon svg{width:16px;height:16px}
  118.         .hero-search-input{flex:1;border:0;outline:0;background:transparent;font-size:14.5px;font-family:inherit;color:var(--wr-ink);padding:6px 0;min-width:0}
  119.         .hero-search-input::placeholder{color:var(--wr-muted-2)}
  120.         .hero-search-clear{background:none;border:0;color:var(--wr-muted-2);cursor:pointer;padding:4px;display:none;font-family:inherit;border-radius:6px;transition:background .15s,color .15s}
  121.         .hero-search-clear:hover{background:var(--wr-violet-soft);color:var(--wr-violet)}
  122.         .hero-search-clear.is-visible{display:flex;align-items:center}
  123.         .hero-search-clear svg{width:14px;height:14px}
  124.         .hero-search-kbd{display:none;align-items:center;padding:3px 8px;background:#fff;border:1px solid #E5E7EB;border-radius:6px;font-size:10.5px;font-weight:600;color:var(--wr-muted);font-family:inherit;letter-spacing:.02em;white-space:nowrap;flex-shrink:0}
  125.         .hero-search-inner:focus-within .hero-search-kbd{display:inline-flex}
  126.         .hero-jobs-header{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 22px 10px;border-bottom:1px solid var(--wr-line);margin-bottom:4px}
  127.         @media(max-width:540px){.hero-jobs-header{padding:12px 16px 8px}}
  128.         .hero-jobs-count{font-size:11.5px;color:var(--wr-muted);text-transform:uppercase;letter-spacing:.08em;font-weight:600}
  129.         .hero-jobs-count strong{color:var(--wr-violet);font-weight:800;font-size:13px;margin-right:4px}
  130.         .hero-jobs-link{font-size:11px;font-weight:700;color:var(--wr-violet);text-transform:uppercase;letter-spacing:.08em;text-decoration:none;display:inline-flex;align-items:center;gap:5px;transition:color .15s,transform .15s}
  131.         .hero-jobs-link:hover{color:var(--wr-violet-dark);text-decoration:none;transform:translateX(2px)}
  132.         .hero-jobs-link svg{width:11px;height:11px}
  133.         .hero-jobs-empty{text-align:center;padding:48px 20px;color:var(--wr-muted)}
  134.         .hero-jobs-empty-icon{width:48px;height:48px;border-radius:14px;background:var(--wr-violet-soft);color:var(--wr-violet);display:inline-flex;align-items:center;justify-content:center;margin-bottom:14px}
  135.         .hero-jobs-empty-icon svg{width:22px;height:22px}
  136.         .hero-jobs-empty-title{font-weight:600;font-size:14px;color:var(--wr-ink);margin:0 0 4px}
  137.         .hero-jobs-empty-hint{font-size:13px;margin:0;color:var(--wr-muted)}
  138.         .hero-jobs-loading{text-align:center;padding:36px 20px;color:var(--wr-muted);font-size:13px;display:flex;align-items:center;justify-content:center;gap:10px}
  139.         .hero-jobs-spinner{width:16px;height:16px;border-radius:50%;border:2px solid var(--wr-violet-soft);border-top-color:var(--wr-violet);animation:wrSpin .7s linear infinite}
  140.         @keyframes wrSpin{to{transform:rotate(360deg)}}
  141.         .hero-popular{display:flex;align-items:center;justify-content:center;gap:6px;flex-wrap:wrap;margin-bottom:18px;opacity:0;animation:wrFadeUp .9s ease .7s forwards}
  142.         .hero-popular-label{font-size:11px;font-weight:600;color:var(--wr-muted);text-transform:uppercase;letter-spacing:.06em;margin-right:4px}
  143.         .hero-popular-pill{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:100px;background:var(--wr-violet-soft);color:var(--wr-violet);font-size:12.5px;font-weight:500;font-family:inherit;text-decoration:none;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,transform .15s,color .15s}
  144.         .hero-popular-pill:hover{background:#EDE9FE;border-color:rgba(138,99,192,.2);transform:translateY(-1px);color:var(--wr-violet);text-decoration:none}
  145.         .hero-popular-pill.is-active{background:var(--wr-violet);color:#fff;border-color:var(--wr-violet)}
  146.         .hero-popular-pill.is-active:hover{background:var(--wr-violet-dark);color:#fff}
  147.         .hero-popular-pill-icon{font-size:13px;line-height:1}
  148.         .hero-cta{display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap;margin:24px 0 8px;opacity:0;animation:wrFadeUp .9s ease 1.1s forwards}
  149.         .hero-cta-btn,.hero-cta-btn:link,.hero-cta-btn:visited,.hero-cta-btn:hover,.hero-cta-btn:focus,.hero-cta-btn:active{color:#fff !important;text-decoration:none !important}
  150.         .hero-cta-btn{display:inline-flex;align-items:center;gap:8px;padding:11px 20px;border-radius:11px;font-size:13.5px;font-weight:700;font-family:inherit;line-height:1;background:var(--wr-violet);border:1px solid var(--wr-violet);box-shadow:0 4px 14px rgba(138,99,193,.32);transition:background .15s,border-color .15s,transform .15s,box-shadow .15s}
  151.         .hero-cta-btn:hover{background:var(--wr-violet-dark);border-color:var(--wr-violet-dark);transform:translateY(-2px);box-shadow:0 6px 20px rgba(138,99,193,.4)}
  152.         .hero-cta-btn svg{width:15px;height:15px;flex-shrink:0;stroke:#fff !important;color:#fff !important}
  153.         .hero-cta-btn span{color:#fff !important}
  154.         @media(max-width:540px){.hero-cta{flex-direction:column;align-items:stretch}.hero-cta-btn{justify-content:center}}
  155.         .hero-default-jobs{position:relative;z-index:2;max-width:1200px;margin:0 auto;background:var(--wr-card);border:1px solid var(--wr-line);border-radius:18px;padding:8px 0;box-shadow:var(--wr-shadow);opacity:0;animation:wrFadeUp .9s ease 1s forwards;text-align:left}
  156.         .hero-default-job{display:flex;align-items:center;gap:16px;padding:14px 22px;text-decoration:none;color:inherit;border-bottom:1px solid var(--wr-line);transition:background .15s}
  157.         .hero-default-job:last-child{border-bottom:0}
  158.         .hero-default-job:hover{background:var(--wr-violet-softer);text-decoration:none;color:inherit}
  159.         .hero-default-job-logo{width:42px;height:42px;border-radius:11px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:16px;overflow:hidden}
  160.         .hero-default-job-logo img{width:100%;height:100%;object-fit:cover}
  161.         .hero-default-job:nth-child(7n+1) .hero-default-job-logo{background:var(--wr-acc-yellow);color:var(--wr-acc-yellow-fg)}
  162.         .hero-default-job:nth-child(7n+2) .hero-default-job-logo{background:var(--wr-acc-green);color:var(--wr-acc-green-fg)}
  163.         .hero-default-job:nth-child(7n+3) .hero-default-job-logo{background:var(--wr-acc-pink);color:var(--wr-acc-pink-fg)}
  164.         .hero-default-job:nth-child(7n+4) .hero-default-job-logo{background:var(--wr-acc-blue);color:var(--wr-acc-blue-fg)}
  165.         .hero-default-job:nth-child(7n+5) .hero-default-job-logo{background:var(--wr-acc-orange);color:var(--wr-acc-orange-fg)}
  166.         .hero-default-job:nth-child(7n+6) .hero-default-job-logo{background:var(--wr-acc-violet);color:var(--wr-acc-violet-fg)}
  167.         .hero-default-job:nth-child(7n+7) .hero-default-job-logo{background:var(--wr-acc-cyan);color:var(--wr-acc-cyan-fg)}
  168.         .hero-default-job-info{flex:1;min-width:0}
  169.         .hero-default-job-title{font-weight:600 !important;font-size:14.5px;color:var(--wr-ink) !important;margin:0 0 2px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  170.         .hero-default-job-meta{font-size:12.5px;color:var(--wr-muted);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:8px}
  171.         .hero-default-job-meta-sep{display:inline-block;width:3px;height:3px;border-radius:50%;background:var(--wr-muted-2);flex-shrink:0}
  172.         .hero-default-job-arrow{flex-shrink:0;color:var(--wr-muted-2);transition:color .15s,transform .15s}
  173.         .hero-default-job-arrow svg{width:15px;height:15px}
  174.         .hero-default-job:hover .hero-default-job-arrow{color:var(--wr-violet);transform:translateX(3px)}
  175.         @media(max-width:768px){.hero-default-jobs{margin:0 -18px;border-radius:14px}.hero-default-job{padding:12px 16px;gap:12px}.hero-default-job-logo{width:36px;height:36px;font-size:13px}.hero-default-job-title{font-size:13.5px}.hero-default-job-meta{font-size:11.5px;gap:6px;flex-wrap:wrap;white-space:normal}}
  176.         /* ═══ HOW IT WORKS ═══ */
  177.         .how-card{background:#F4ECE1;border-radius:24px;padding:32px 24px;display:grid;grid-template-columns:repeat(3,1fr);gap:24px;position:relative}
  178.         @media(max-width:991px){.how-card{grid-template-columns:1fr;gap:8px;padding:24px 16px}}
  179.         @media(min-width:992px){.how-card .how-step + .how-step{border-left:1px solid rgba(28,25,22,.08)}}
  180.         .how-step{display:flex;flex-direction:column;align-items:center;text-align:center;padding:16px 20px;gap:16px}
  181.         .how-step-illu{width:100%;max-width:280px;aspect-ratio:1/1;border-radius:16px;background:rgba(255,255,255,.5);display:flex;align-items:center;justify-content:center;margin-bottom:4px;overflow:hidden}
  182.         .how-step-illu img{width:100%;height:100%;object-fit:contain;display:block}
  183.         .how-step-title{font-weight:700 !important;font-size:18px;line-height:1.3;letter-spacing:-0.01em;color:var(--wr-ink) !important;margin:0}
  184.         @media(min-width:992px){.how-step-title{font-size:20px}}
  185.         .how-step-desc{font-size:14px;line-height:1.55;color:var(--wr-ink-2) !important;margin:0;max-width:320px}
  186.         /* ═══ FEATURES 01-04 ═══ */
  187.         .feat-block{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:center;margin-bottom:64px}
  188.         .feat-block:last-child{margin-bottom:0}
  189.         @media(max-width:991px){.feat-block{grid-template-columns:1fr;gap:24px;margin-bottom:48px}}
  190.         .feat-block:nth-child(odd) .feat-illu{order:2}
  191.         .feat-block:nth-child(odd) .feat-content{order:1}
  192.         .feat-block:nth-child(even) .feat-illu{order:1}
  193.         .feat-block:nth-child(even) .feat-content{order:2}
  194.         @media(max-width:991px){.feat-block .feat-illu{order:1}.feat-block .feat-content{order:2}}
  195.         .feat-illu{background:#F5EDE3;border-radius:20px;aspect-ratio:1/1;display:flex;align-items:center;justify-content:center;color:var(--wr-violet);overflow:hidden;position:relative}
  196.         .feat-illu img{width:100%;height:100%;object-fit:contain;display:block}
  197.         .feat-content{display:flex;flex-direction:column;gap:18px}
  198.         .feat-label{font-size:30px;font-weight:800 !important;color:var(--wr-ink) !important;letter-spacing:-0.02em;margin:0;line-height:1}
  199.         .feat-title{font-weight:700 !important;font-size:24px;line-height:1.2;letter-spacing:-0.02em;color:var(--wr-ink) !important;margin:0}
  200.         @media(min-width:768px){.feat-title{font-size:28px}}
  201.         @media(min-width:1100px){.feat-title{font-size:30px}}
  202.         .feat-desc{display:flex;flex-direction:column;gap:14px}
  203.         .feat-desc p,.feat-desc li,.feat-desc span,.feat-desc div,.feat-desc strong,.feat-desc em{font-size:16px;line-height:1.6;color:var(--wr-ink-2);margin:0;opacity:.85}
  204.         .feat-desc p{margin:0 0 8px}
  205.         .feat-desc p:last-child{margin-bottom:0}
  206.         /* Bloc HTML riche descriptionPage2/3 — forcer 16px sur tout le contenu */
  207.         .wr-rich-description{margin-top:18px;text-align:center;color:var(--wr-muted)}
  208.         .wr-rich-description,
  209.         .wr-rich-description p,
  210.         .wr-rich-description li,
  211.         .wr-rich-description span,
  212.         .wr-rich-description div,
  213.         .wr-rich-description strong,
  214.         .wr-rich-description em,
  215.         .wr-rich-description a{font-size:16px;line-height:1.6}
  216.         .wr-rich-description p{margin:0 0 10px}
  217.         .wr-rich-description p:last-child{margin-bottom:0}
  218.         .feat-desc strong{color:var(--wr-ink);font-weight:700;opacity:1}
  219.         .feat-quote{background:var(--wr-card);border:1px solid var(--wr-line);border-radius:14px;padding:18px 20px;display:flex;flex-direction:column;gap:10px;margin-top:8px}
  220.         .feat-quote-text{font-size:14px;line-height:1.55;color:var(--wr-ink-2);margin:0;font-style:italic}
  221.         .feat-quote-author{display:flex;flex-direction:column}
  222.         .feat-quote-name{font-size:13px;font-weight:700;color:var(--wr-ink);margin:0}
  223.         .feat-quote-role{font-size:12px;color:var(--wr-muted);margin:0}
  224.         /* ═══ APPS ═══ */
  225.         .apps-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
  226.         @media(max-width:768px){.apps-grid{grid-template-columns:1fr}}
  227.         .app-card{background:var(--wr-card);border:1px solid var(--wr-line);border-radius:18px;padding:24px;display:flex;flex-direction:column;align-items:flex-start;transition:transform .2s,border-color .2s,box-shadow .2s}
  228.         .app-card:hover{transform:translateY(-3px);border-color:var(--wr-violet-2);box-shadow:var(--wr-shadow-hover);color:inherit;text-decoration:none}
  229.         .app-card-icon{width:48px;height:48px;border-radius:14px;background:var(--wr-violet-soft);color:var(--wr-violet);display:inline-flex;align-items:center;justify-content:center;margin-bottom:18px}
  230.         .app-card-icon svg{width:22px;height:22px}
  231.         .app-card-name{font-weight:500 !important;font-size:18px;letter-spacing:-0.01em;color:var(--wr-ink) !important;margin:0 0 6px}
  232.         .app-card-desc{font-size:13px;line-height:1.5;color:var(--wr-muted);margin:0 0 16px;flex:1}
  233.         .app-card-cta{font-size:12px;font-weight:600;color:var(--wr-violet);text-transform:uppercase;letter-spacing:.1em;display:inline-flex;align-items:center;gap:6px}
  234.         .app-card-cta svg{width:11px;height:11px;transition:transform .15s}
  235.         .app-card:hover .app-card-cta svg{transform:translateX(3px)}
  236.         /* ═══ ARTICLES ═══ */
  237.         .articles-list{display:flex;flex-direction:column;gap:10px;max-width:1200px;margin:0 auto}
  238.         .wr-article{background:var(--wr-card);border-radius:14px;padding:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04);display:flex;align-items:center;gap:14px;text-decoration:none;color:inherit;transition:transform .15s,box-shadow .2s}
  239.         .wr-article:hover{transform:translateY(-1px);box-shadow:0 4px 20px rgba(138,99,192,.1);color:inherit;text-decoration:none}
  240.         .wr-article-logo{width:50px;height:50px;border-radius:12px;flex-shrink:0;background:linear-gradient(135deg,#EDE9FE,#DDD6FE);display:flex;align-items:center;justify-content:center;color:var(--wr-violet);overflow:hidden}
  241.         .wr-article-logo svg{width:24px;height:24px;opacity:.9}
  242.         .wr-article-info{flex:1;min-width:0}
  243.         .wr-article-title{font-size:14px;font-weight:700 !important;color:var(--wr-ink) !important;line-height:1.3;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  244.         .wr-article-meta{font-size:12px;color:var(--wr-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:8px;margin:0}
  245.         .wr-article-meta-sep{display:inline-block;width:3px;height:3px;border-radius:50%;background:#D1D5DB;flex-shrink:0}
  246.         .wr-article-badge{font-size:11px;font-weight:600;color:var(--wr-violet);background:var(--wr-violet-soft);padding:3px 9px;border-radius:100px;white-space:nowrap;flex-shrink:0;text-transform:uppercase;letter-spacing:.04em}
  247.         .wr-article-arrow{flex-shrink:0;color:var(--wr-muted-2);transition:color .15s,transform .15s}
  248.         .wr-article:hover .wr-article-arrow{color:var(--wr-violet);transform:translateX(2px)}
  249.         .wr-article-arrow svg{width:18px;height:18px}
  250.         @media(max-width:540px){.wr-article{padding:12px;gap:10px}.wr-article-logo{width:42px;height:42px}.wr-article-logo svg{width:20px;height:20px}.wr-article-title{font-size:13px}.wr-article-meta{font-size:11px;gap:6px;flex-wrap:wrap;white-space:normal}.wr-article-badge{display:none}}
  251.         .articles-cta{text-align:center;margin-top:36px}
  252.         .articles-cta a{display:inline-flex;align-items:center;gap:8px;padding:12px 22px;border-radius:11px;background:var(--wr-violet);color:#fff;font-size:13px;font-weight:600;text-decoration:none;box-shadow:0 4px 12px rgba(138,99,192,.3);transition:background .15s,transform .15s,box-shadow .15s}
  253.         .articles-cta a:hover{background:var(--wr-violet-dark);transform:translateY(-2px);box-shadow:0 6px 18px rgba(138,99,192,.4);text-decoration:none;color:#fff}
  254.         .articles-cta svg{width:12px;height:12px;transition:transform .15s}
  255.         .articles-cta a:hover svg{transform:translateX(3px)}
  256.         /* ═══ CTA FINAL ═══ */
  257.         .final-card{position:relative;background:linear-gradient(135deg,#8A63C0 0%,#9D7BCC 100%);border-radius:28px;padding:48px 40px;color:#fff;overflow:hidden;box-shadow:0 20px 60px -12px rgba(138,99,192,.4)}
  258.         @media(max-width:768px){.final-card{padding:32px 22px;border-radius:22px}}
  259.         .final-title{font-weight:800 !important;font-size:28px;line-height:1.15;letter-spacing:-0.02em;color:#fff !important;margin:0 0 36px;max-width:780px}
  260.         @media(min-width:768px){.final-title{font-size:38px}}
  261.         .final-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
  262.         @media(max-width:768px){.final-grid{grid-template-columns:1fr;gap:14px}}
  263.         .final-sub{background:#fff;border-radius:18px;padding:28px;display:flex;flex-direction:column}
  264.         @media(max-width:768px){.final-sub{padding:22px}}
  265.         .final-sub-head{display:flex;align-items:center;gap:14px;margin-bottom:18px}
  266.         .final-sub-icon{width:44px;height:44px;border-radius:11px;background:var(--wr-violet-soft);color:var(--wr-violet);display:flex;align-items:center;justify-content:center;flex-shrink:0}
  267.         .final-sub-icon svg{width:22px;height:22px}
  268.         .final-sub-label{font-size:12.5px;font-weight:700;color:var(--wr-violet);text-transform:uppercase;letter-spacing:.1em}
  269.         .final-sub-title{font-weight:800 !important;font-size:18px;line-height:1.3;letter-spacing:-0.01em;color:var(--wr-ink) !important;margin:0 0 10px}
  270.         .final-sub-desc{font-size:14px;line-height:1.55;color:var(--wr-muted);margin:0 0 24px;flex:1}
  271.         .final-sub-btn{display:flex;align-items:center;justify-content:center;gap:8px;background:var(--wr-violet);color:#fff;padding:14px 18px;border-radius:11px;font-size:14px;font-weight:700;text-decoration:none;transition:background .15s,transform .15s,box-shadow .15s;box-shadow:0 4px 12px rgba(138,99,192,.3)}
  272.         .final-sub-btn:hover{background:var(--wr-violet-dark);color:#fff;transform:translateY(-2px);box-shadow:0 6px 18px rgba(138,99,192,.4);text-decoration:none}
  273.         .final-sub-btn svg{width:14px;height:14px;transition:transform .15s}
  274.         .final-sub-btn:hover svg{transform:translateX(3px)}
  275.     </style>
  276. {% endblock css %}
  277. {% block body %}
  278.     <div class="wr">
  279.         {# ═══════════════ HERO ═══════════════ #}
  280.         <section class="hero" style="padding-top:60px;">
  281.             <div class="hero-inner">
  282.                 <h1 class="hero-title">{{ landing.titlePage|raw }}</h1>
  283.                 <p class="hero-lede">{{ landing.descriptionPage|raw }}</p>
  284.                 {# Pills "Populaire" — au-dessus de la recherche.
  285.                    Le 1er keyword est utilisé comme valeur par défaut du champ de recherche. #}
  286.                 {% set _firstKeyword = '' %}
  287.                 {% if popularKeywords is defined and popularKeywords|length > 0 %}
  288.                     {% set _firstKw = popularKeywords|first %}
  289.                     {% set _firstKeyword = _firstKw.keyword ?? _firstKw.searchKeyword ?? _firstKw.label ?? '' %}
  290.                     <div class="hero-popular">
  291.                         <span class="hero-popular-label">{{ t.hero_popular_label }}</span>
  292.                         {% for kw in popularKeywords|slice(0, 5) %}
  293.                             <button type="button" class="hero-popular-pill{% if loop.first %} is-active{% endif %}"
  294.                                     data-keyword="{{ kw.keyword ?? kw.searchKeyword }}"
  295.                                     data-label="{{ kw.label }}">
  296.                                 {% if kw.icon %}<span class="hero-popular-pill-icon">{{ kw.icon|raw }}</span>{% endif %}
  297.                                 <span>{{ kw.label }}</span>
  298.                             </button>
  299.                         {% endfor %}
  300.                     </div>
  301.                 {% endif %}
  302.                 {# Recherche inline AJAX #}
  303.                 <div class="hero-search-wrap">
  304.                     <div class="hero-search" id="wrHeroSearch"
  305.                          data-search-url="{% if isFR %}{{ path('locale_api_jobs_search',{'_locale':'fr'}) }}{% else %}{{ path('api_jobs_search') }}{% endif %}"
  306.                          data-jobs-list-url="{% if isFR %}{{ path('locale_whileresume_jobs_list',{'_locale':'fr'}) }}{% else %}{{ path('whileresume_jobs_list') }}{% endif %}">
  307.                         <div class="hero-search-inner">
  308.                             <span class="hero-search-icon">
  309.                                 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  310.                                     <circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/>
  311.                                 </svg>
  312.                             </span>
  313.                             <input type="text" name="q" id="wrHeroSearchInput" class="hero-search-input"
  314.                                    placeholder="{{ t.hero_search_placeholder }}"
  315.                                    value="{{ _firstKeyword }}"
  316.                                    autocomplete="off" />
  317.                             <span class="hero-search-kbd">↵ {{ isFR ? 'Entrée' : 'Enter' }}</span>
  318.                             <button type="button" class="hero-search-clear" id="wrHeroSearchClear" aria-label="{{ t.search_clear }}">
  319.                                 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  320.                                     <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
  321.                                 </svg>
  322.                             </button>
  323.                         </div>
  324.                     </div>
  325.                 </div>
  326.                 {# Liste de jobs — par défaut popularJobsForVisitor #}
  327.                 {% set _heroCount = 0 %}
  328.                 {% set _heroTotal = 0 %}
  329.                 {% if popularJobsForVisitor is defined %}
  330.                     {% for block in popularJobsForVisitor %}
  331.                         {% if block.jobs is defined %}{% set _heroTotal = _heroTotal + block.jobs|length %}{% endif %}
  332.                     {% endfor %}
  333.                 {% endif %}
  334.                 <div class="hero-default-jobs" id="wrHeroJobsList">
  335.                     <div class="hero-jobs-header" id="wrHeroJobsHeader">
  336.                         <span class="hero-jobs-count" id="wrHeroJobsCount">
  337.                             <strong>{{ _heroTotal ?: (totalJobs ?? '') }}</strong>{{ t.search_results_count }}
  338.                         </span>
  339.                         <a href="{% if isFR %}{{ path('locale_whileresume_jobs_list',{'_locale':'fr'}) }}{% else %}{{ path('whileresume_jobs_list') }}{% endif %}" class="hero-jobs-link" id="wrHeroJobsLink">
  340.                             {{ t.search_view_all }}
  341.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  342.                                 <line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>
  343.                             </svg>
  344.                         </a>
  345.                     </div>
  346.                     <div id="wrHeroJobsBody">
  347.                         {% if popularJobsForVisitor is defined and popularJobsForVisitor|length > 0 %}
  348.                             {% for block in popularJobsForVisitor %}
  349.                                 {% if block.jobs is defined and block.jobs|length > 0 %}
  350.                                     {% for j in block.jobs %}
  351.                                         {% if _heroCount < 6 %}
  352.                                             <a href="#" class="hero-default-job">
  353.                                                 <div class="hero-default-job-logo">
  354.                                                     {{ (j.jobTitle ?? '?')|slice(0,1)|upper }}
  355.                                                 </div>
  356.                                                 <div class="hero-default-job-info">
  357.                                                     <h3 class="hero-default-job-title">{{ j.jobTitle }}</h3>
  358.                                                     <p class="hero-default-job-meta">
  359.                                                         {% if j.city %}<span>{{ j.city }}</span>{% endif %}
  360.                                                         {% if j.employmentType %}
  361.                                                             <span class="hero-default-job-meta-sep"></span>
  362.                                                             <span>{{ j.employmentType }}</span>
  363.                                                         {% endif %}
  364.                                                     </p>
  365.                                                 </div>
  366.                                                 <span class="hero-default-job-arrow">
  367.                                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
  368.                                                 </span>
  369.                                             </a>
  370.                                             {% set _heroCount = _heroCount + 1 %}
  371.                                         {% endif %}
  372.                                     {% endfor %}
  373.                                 {% endif %}
  374.                             {% endfor %}
  375.                         {% endif %}
  376.                     </div>
  377.                 </div>
  378.                 {# CTA pour utilisateurs non connectés #}
  379.                 {% if app.user is null %}
  380.                     <div class="hero-cta">
  381.                         <a href="{{ path('whileresume_resume_' ~ app.request.locale) }}" class="hero-cta-btn">
  382.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  383.                                 <path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><line x1="20" y1="8" x2="20" y2="14"/><line x1="23" y1="11" x2="17" y2="11"/>
  384.                             </svg>
  385.                             {{ t.hero_cta_signup }}
  386.                         </a>
  387.                         <a href="{% if isFR %}{{ path('locale_app_login',{'_locale':'fr'}) }}{% else %}{{ path('app_login') }}{% endif %}" class="hero-cta-btn">
  388.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  389.                                 <path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/>
  390.                             </svg>
  391.                             {{ t.hero_cta_login }}
  392.                         </a>
  393.                     </div>
  394.                 {% endif %}
  395.                 {% if landing.descriptionPage2 or landing.descriptionPage3 %}
  396.                     <div class="wr-rich-description">
  397.                         {% if landing.descriptionPage2 %}<div>{{ landing.descriptionPage2|raw }}</div>{% endif %}
  398.                         {% if landing.descriptionPage3 %}<div>{{ landing.descriptionPage3|raw }}</div>{% endif %}
  399.                     </div>
  400.                 {% endif %}
  401.             </div>
  402.         </section>
  403.         {# ═══════════════ COMMENT ÇA MARCHE ═══════════════ #}
  404.         <section class="wr-section">
  405.             <div class="wr-container">
  406.                 <div class="wr-section-head">
  407.                     <h2 class="wr-title">{{ t.how_title }}</h2>
  408.                 </div>
  409.                 <div class="how-card">
  410.                     <div class="how-step reveal" data-reveal-delay="1">
  411.                         <div class="how-step-illu">
  412.                             <img src="/uploads/rh/mascotte_register.png" alt="{{ landing.titleWork1 }}" loading="lazy">
  413.                         </div>
  414.                         <h3 class="how-step-title">{{ landing.titleWork1|raw }}</h3>
  415.                         <p class="how-step-desc">{{ landing.descriptionWork1|raw }}</p>
  416.                     </div>
  417.                     <div class="how-step reveal" data-reveal-delay="2">
  418.                         <div class="how-step-illu">
  419.                             <img src="/uploads/rh/mascotte_upload2.png" alt="{{ landing.titleWork2 }}" loading="lazy">
  420.                         </div>
  421.                         <h3 class="how-step-title">{{ landing.titleWork2|raw }}</h3>
  422.                         <p class="how-step-desc">{{ landing.descriptionWork2|raw }}</p>
  423.                     </div>
  424.                     <div class="how-step reveal" data-reveal-delay="3">
  425.                         <div class="how-step-illu">
  426.                             <img src="/uploads/rh/mascotte_reunion.png" alt="{{ landing.titleWork3 }}" loading="lazy">
  427.                         </div>
  428.                         <h3 class="how-step-title">{{ landing.titleWork3|raw }}</h3>
  429.                         <p class="how-step-desc">{{ landing.descriptionWork3|raw }}</p>
  430.                     </div>
  431.                 </div>
  432.             </div>
  433.         </section>
  434.         {# ═══════════════ FEATURES 01-04 ═══════════════ #}
  435.         <section class="wr-section">
  436.             <div class="wr-container">
  437.                 {% set _featImages = [
  438.                     '/uploads/rh/mascotte_filtrage3.png',
  439.                     '/uploads/rh/mascotte_upload.png',
  440.                     '/uploads/rh/mascotte_register.png',
  441.                     '/uploads/rh/mascotte_reunion.png'
  442.                 ] %}
  443.                 {% for i in 1..4 %}
  444.                     {% set _label = attribute(landing, 'labelPresentation' ~ i) ?: ('0' ~ i ~ '.') %}
  445.                     {% set _title = attribute(landing, 'titlePresentation' ~ i) %}
  446.                     {% set _desc = attribute(landing, 'descriptionPresentation' ~ i) %}
  447.                     {% set _quote = attribute(landing, 'citationPresentation' ~ i) %}
  448.                     {% set _author = attribute(landing, 'authorPresentation' ~ i) %}
  449.                     {% set _role = attribute(landing, 'rolePresentation' ~ i) %}
  450.                     {% if _title or _desc or _quote %}
  451.                         <div class="feat-block reveal">
  452.                             <div class="feat-illu">
  453.                                 <img src="{{ _featImages[i-1] }}" alt="{{ _title }}" loading="lazy">
  454.                             </div>
  455.                             <div class="feat-content">
  456.                                 {% if _label %}<span class="feat-label">{{ _label }}</span>{% endif %}
  457.                                 {% if _title %}<h3 class="feat-title">{{ _title|raw }}</h3>{% endif %}
  458.                                 {% if _desc %}
  459.                                     <div class="feat-desc">
  460.                                         <p>{{ _desc|raw }}</p>
  461.                                     </div>
  462.                                 {% endif %}
  463.                                 {% if _quote %}
  464.                                     <div class="feat-quote">
  465.                                         <p class="feat-quote-text">{{ _quote|raw }}</p>
  466.                                         {% if _author or _role %}
  467.                                             <div class="feat-quote-author">
  468.                                                 {% if _author %}<p class="feat-quote-name">{{ _author }}</p>{% endif %}
  469.                                                 {% if _role %}<p class="feat-quote-role">{{ _role }}</p>{% endif %}
  470.                                             </div>
  471.                                         {% endif %}
  472.                                     </div>
  473.                                 {% endif %}
  474.                             </div>
  475.                         </div>
  476.                     {% endif %}
  477.                 {% endfor %}
  478.             </div>
  479.         </section>
  480.         {# ═══════════════ APPS ═══════════════ #}
  481.         <section class="wr-section">
  482.             <div class="wr-container">
  483.                 <div class="apps-grid">
  484.                     <a href="{{ isFR ? (ios_fr|default('#')) : (ios_us|default('#')) }}" class="app-card">
  485.                         <span class="app-card-icon">
  486.                             <svg viewBox="0 0 24 24" fill="currentColor"><path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/></svg>
  487.                         </span>
  488.                         <h3 class="app-card-name">{{ t.apps_ios }}</h3>
  489.                         <p class="app-card-desc">{{ t.apps_ios_desc }}</p>
  490.                         <span class="app-card-cta">App Store
  491.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  492.                         </span>
  493.                     </a>
  494.                     <a href="{{ isFR ? (android_fr|default('#')) : (android_us|default('#')) }}" class="app-card">
  495.                         <span class="app-card-icon">
  496.                             <svg viewBox="0 0 24 24" fill="currentColor"><path d="M17.523 15.34c-.583 0-1.06-.477-1.06-1.06 0-.582.477-1.06 1.06-1.06.583 0 1.06.478 1.06 1.06 0 .583-.477 1.06-1.06 1.06m-11.046 0c-.583 0-1.06-.477-1.06-1.06 0-.582.477-1.06 1.06-1.06.583 0 1.06.478 1.06 1.06 0 .583-.477 1.06-1.06 1.06m11.427-6.176l2.114-3.66a.439.439 0 0 0-.16-.6.439.439 0 0 0-.6.16l-2.142 3.71a13.07 13.07 0 0 0-5.116-1.034c-1.823 0-3.55.376-5.116 1.034l-2.14-3.71a.439.439 0 1 0-.76.44l2.113 3.66C2.486 10.78.659 13.658.5 17h23c-.16-3.342-1.987-6.22-5.595-7.836"/></svg>
  497.                         </span>
  498.                         <h3 class="app-card-name">{{ t.apps_android }}</h3>
  499.                         <p class="app-card-desc">{{ t.apps_android_desc }}</p>
  500.                         <span class="app-card-cta">Google Play
  501.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  502.                         </span>
  503.                     </a>
  504.                     <a href="{% if app.request.locale == 'en' %}{{ path('whileresume_homepage') }}{% else %}{{ path('locale_whileresume_homepage',{'_locale':app.request.locale}) }}{% endif %}#register" class="app-card">
  505.                         <span class="app-card-icon">
  506.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
  507.                         </span>
  508.                         <h3 class="app-card-name">{{ t.apps_web }}</h3>
  509.                         <p class="app-card-desc">{{ t.apps_web_desc }}</p>
  510.                         <span class="app-card-cta">whileresume.com
  511.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  512.                         </span>
  513.                     </a>
  514.                 </div>
  515.             </div>
  516.         </section>
  517.         {# ═══════════════ ARTICLES ═══════════════ #}
  518.         {% if articles is defined and articles|length > 0 %}
  519.             <section class="wr-section">
  520.                 <div class="wr-container">
  521.                     <div class="wr-section-head">
  522.                         <h2 class="wr-title wr-title--sm">{{ t.articles_title }}</h2>
  523.                     </div>
  524.                     <div class="articles-list">
  525.                         {% for a in articles|slice(0,6) %}
  526.                             {% set prefix = "" %}
  527.                             {% set urlA = path('cvs_website_article',{'slug': a.slug}) %}
  528.                             {% if app.request.locale != default_locale %}
  529.                                 {% set urlA = path('locale_cvs_website_article',{'_locale':app.request.locale,'slug': a.slug}) %}
  530.                                 {% set prefix = "/" ~ app.request.locale %}
  531.                             {% endif %}
  532.                             {% if a.pageslug3 is not empty %}
  533.                                 {% set urlA = prefix ~ '/' ~ a.pageslug ~ '/' ~ a.pageslug2 ~ '/' ~ a.pageslug3 %}
  534.                             {% elseif a.pageslug2 is not empty %}
  535.                                 {% set urlA = prefix ~ '/' ~ a.pageslug ~ '/' ~ a.pageslug2 %}
  536.                             {% elseif a.pageslug is not empty %}
  537.                                 {% set urlA = prefix ~ '/' ~ a.pageslug %}
  538.                             {% endif %}
  539.                             <a href="{{ urlA }}" class="wr-article">
  540.                                 <div class="wr-article-logo">
  541.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  542.                                         <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
  543.                                         <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
  544.                                     </svg>
  545.                                 </div>
  546.                                 <div class="wr-article-info">
  547.                                     <h3 class="wr-article-title">{{ a.title }}</h3>
  548.                                     <div class="wr-article-meta">
  549.                                         {% if a.subtitle is not empty %}
  550.                                             <span>{{ a.subtitle|length > 60 ? a.subtitle|slice(0,60) ~ '…' : a.subtitle }}</span>
  551.                                         {% endif %}
  552.                                     </div>
  553.                                 </div>
  554.                                 <span class="wr-article-badge">{{ t.read_article }}</span>
  555.                                 <span class="wr-article-arrow">
  556.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  557.                                         <polyline points="9 18 15 12 9 6"/>
  558.                                     </svg>
  559.                                 </span>
  560.                             </a>
  561.                         {% endfor %}
  562.                     </div>
  563.                     <div class="articles-cta">
  564.                         <a href="{% if isFR %}{{ path('locale_cvs_website_articles',{'_locale':'fr'}) }}{% else %}{{ path('cvs_website_articles') }}{% endif %}">
  565.                             {{ t.articles_view_all }}
  566.                             <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  567.                         </a>
  568.                     </div>
  569.                 </div>
  570.             </section>
  571.         {% endif %}
  572.         {# ═══════════════ CTA FINAL (visiteurs anonymes uniquement) ═══════════════ #}
  573.         {% if app.user is null %}
  574.             <section class="wr-section">
  575.                 <div class="wr-container">
  576.                     <div class="final-card">
  577.                         <h2 class="final-title">{{ t.final_title }}</h2>
  578.                         <div class="final-grid">
  579.                             {# Recruteur #}
  580.                             <div class="final-sub">
  581.                                 <div class="final-sub-head">
  582.                                 <span class="final-sub-icon">
  583.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
  584.                                         <rect x="2" y="7" width="20" height="14" rx="2" ry="2"/>
  585.                                         <path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
  586.                                     </svg>
  587.                                 </span>
  588.                                     <span class="final-sub-label">{{ t.final_recruiter_label }}</span>
  589.                                 </div>
  590.                                 <h3 class="final-sub-title">{{ t.final_recruiter_title }}</h3>
  591.                                 <p class="final-sub-desc">{{ t.final_recruiter_desc }}</p>
  592.                                 <a href="{{ path('whileresume_business_' ~ app.request.locale) }}" class="final-sub-btn">
  593.                                     {{ t.final_recruiter }}
  594.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  595.                                 </a>
  596.                             </div>
  597.                             {# Candidat #}
  598.                             <div class="final-sub">
  599.                                 <div class="final-sub-head">
  600.                                 <span class="final-sub-icon">
  601.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
  602.                                         <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
  603.                                         <circle cx="12" cy="7" r="4"/>
  604.                                     </svg>
  605.                                 </span>
  606.                                     <span class="final-sub-label">{{ t.final_candidate_label }}</span>
  607.                                 </div>
  608.                                 <h3 class="final-sub-title">{{ t.final_candidate_title }}</h3>
  609.                                 <p class="final-sub-desc">{{ t.final_candidate_desc }}</p>
  610.                                 <a href="{{ path('whileresume_resume_' ~ app.request.locale) }}" class="final-sub-btn">
  611.                                     {{ t.final_candidate }}
  612.                                     <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
  613.                                 </a>
  614.                             </div>
  615.                         </div>
  616.                     </div>
  617.                 </div>
  618.             </section>
  619.         {% endif %}
  620.     </div>
  621. {% endblock body %}
  622. {% block footer_js %}
  623.     {{ parent() }}
  624.     <script>
  625.         (function(){
  626.             var search   = document.getElementById('wrHeroSearch');
  627.             var input    = document.getElementById('wrHeroSearchInput');
  628.             var clearBtn = document.getElementById('wrHeroSearchClear');
  629.             var jobsBody = document.getElementById('wrHeroJobsBody');
  630.             var countEl  = document.getElementById('wrHeroJobsCount');
  631.             var linkEl   = document.getElementById('wrHeroJobsLink');
  632.             if (!search || !input || !jobsBody) return;
  633.             var searchUrl   = search.dataset.searchUrl;
  634.             var jobsListUrl = search.dataset.jobsListUrl;
  635.             var defaultBodyHtml  = jobsBody.innerHTML;
  636.             var defaultCountHtml = countEl ? countEl.innerHTML : '';
  637.             var defaultLinkHref  = linkEl ? linkEl.getAttribute('href') : jobsListUrl;
  638.             var debounceTimer = null;
  639.             var currentRequest = null;
  640.             var lastQuery = '';
  641.             var T = {
  642.                 loading:      '{{ t.search_loading|escape('js') }}',
  643.                 empty:        '{{ t.search_no_results|escape('js') }}',
  644.                 emptyHint:    '{{ t.search_no_results_hint|escape('js') }}',
  645.                 count:        '{{ t.search_results_count|escape('js') }}',
  646.                 viewAll:      '{{ t.search_view_all|escape('js') }}',
  647.                 view:         '{{ t.search_view_offer|escape('js') }}'
  648.             };
  649.             function escHtml(s){
  650.                 if (s == null) return '';
  651.                 return String(s).replace(/[&<>"']/g, function(c){
  652.                     return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c];
  653.                 });
  654.             }
  655.             function setHeaderCount(total){
  656.                 if (!countEl) return;
  657.                 countEl.innerHTML = '<strong>' + total + '</strong>' + escHtml(T.count);
  658.             }
  659.             function setHeaderLink(href){ if (!linkEl) return; linkEl.setAttribute('href', href); }
  660.             function setLoading(){
  661.                 jobsBody.innerHTML = '<div class="hero-jobs-loading"><span class="hero-jobs-spinner"></span><span>' + escHtml(T.loading) + '</span></div>';
  662.             }
  663.             function setEmpty(){
  664.                 jobsBody.innerHTML =
  665.                     '<div class="hero-jobs-empty">' +
  666.                     '<div class="hero-jobs-empty-icon">' +
  667.                     '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  668.                     '<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>' +
  669.                     '</svg></div>' +
  670.                     '<p class="hero-jobs-empty-title">' + escHtml(T.empty) + '</p>' +
  671.                     '<p class="hero-jobs-empty-hint">' + escHtml(T.emptyHint) + '</p>' +
  672.                     '</div>';
  673.             }
  674.             function restoreDefault(){
  675.                 jobsBody.innerHTML = defaultBodyHtml;
  676.                 if (countEl) countEl.innerHTML = defaultCountHtml;
  677.                 if (linkEl) linkEl.setAttribute('href', defaultLinkHref);
  678.             }
  679.             function renderResults(payload, query){
  680.                 var jobs  = (payload && payload.jobs)  || [];
  681.                 var total = (payload && typeof payload.total === 'number') ? payload.total : jobs.length;
  682.                 setHeaderCount(total);
  683.                 setHeaderLink(jobsListUrl + '?q=' + encodeURIComponent(query));
  684.                 if (!jobs.length){ setEmpty(); return; }
  685.                 var html = '';
  686.                 jobs.slice(0, 6).forEach(function(j){
  687.                     var title   = j.jobTitle || j.title || '';
  688.                     var company = j.companyName || j.company || '';
  689.                     var city    = j.city || '';
  690.                     var country = j.country || '';
  691.                     var et      = j.employmentType || '';
  692.                     var img     = j.image || j.imageUrl || '';
  693.                     var url     = j.url || (jobsListUrl + '?q=' + encodeURIComponent(query));
  694.                     var initial = (company || title || '?').charAt(0).toUpperCase();
  695.                     var location = city + (country ? ', ' + country : '');
  696.                     var metaParts = [];
  697.                     if (company)  metaParts.push('<span>' + escHtml(company) + '</span>');
  698.                     if (location) metaParts.push('<span class="hero-default-job-meta-sep"></span><span>' + escHtml(location) + '</span>');
  699.                     if (et)       metaParts.push('<span class="hero-default-job-meta-sep"></span><span>' + escHtml(et) + '</span>');
  700.                     html +=
  701.                         '<a href="' + escHtml(url) + '" class="hero-default-job">' +
  702.                         '<div class="hero-default-job-logo">' +
  703.                         (img ? '<img src="' + escHtml(img) + '" alt="">' : escHtml(initial)) +
  704.                         '</div>' +
  705.                         '<div class="hero-default-job-info">' +
  706.                         '<h3 class="hero-default-job-title">' + escHtml(title) + '</h3>' +
  707.                         '<p class="hero-default-job-meta">' + metaParts.join('') + '</p>' +
  708.                         '</div>' +
  709.                         '<span class="hero-default-job-arrow">' +
  710.                         '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>' +
  711.                         '</span>' +
  712.                         '</a>';
  713.                 });
  714.                 jobsBody.innerHTML = html;
  715.             }
  716.             function doSearch(query){
  717.                 if (currentRequest && currentRequest.abort) { try { currentRequest.abort(); } catch(e){} }
  718.                 setLoading();
  719.                 var url = searchUrl + (searchUrl.indexOf('?') > -1 ? '&' : '?') + 'q=' + encodeURIComponent(query);
  720.                 var ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;
  721.                 currentRequest = ctrl;
  722.                 fetch(url, { headers: { 'Accept': 'application/json' }, signal: ctrl ? ctrl.signal : undefined })
  723.                     .then(function(r){ return r.ok ? r.json() : Promise.reject(r.status); })
  724.                     .then(function(data){ renderResults(data, query); })
  725.                     .catch(function(err){
  726.                         if (err && err.name === 'AbortError') return;
  727.                         setEmpty();
  728.                     });
  729.             }
  730.             input.addEventListener('input', function(){
  731.                 var q = input.value.trim();
  732.                 clearBtn.classList.toggle('is-visible', q.length > 0);
  733.                 if (debounceTimer) clearTimeout(debounceTimer);
  734.                 if (q.length < 2){ restoreDefault(); lastQuery = ''; return; }
  735.                 if (q === lastQuery) return;
  736.                 debounceTimer = setTimeout(function(){ lastQuery = q; doSearch(q); }, 280);
  737.             });
  738.             input.addEventListener('keydown', function(e){
  739.                 if (e.key === 'Enter'){
  740.                     e.preventDefault();
  741.                     var q = input.value.trim();
  742.                     if (!q) return;
  743.                     window.location.href = jobsListUrl + '?q=' + encodeURIComponent(q);
  744.                 }
  745.                 if (e.key === 'Escape'){
  746.                     input.value = ''; clearBtn.classList.remove('is-visible'); restoreDefault(); lastQuery = ''; input.blur();
  747.                 }
  748.             });
  749.             clearBtn.addEventListener('click', function(){
  750.                 input.value = ''; clearBtn.classList.remove('is-visible'); restoreDefault(); lastQuery = ''; input.focus();
  751.             });
  752.             document.querySelectorAll('.hero-popular-pill').forEach(function(pill){
  753.                 pill.addEventListener('click', function(){
  754.                     var keyword = pill.dataset.keyword || pill.dataset.label || '';
  755.                     if (!keyword) return;
  756.                     document.querySelectorAll('.hero-popular-pill').forEach(function(p){ p.classList.remove('is-active'); });
  757.                     pill.classList.add('is-active');
  758.                     input.value = keyword;
  759.                     clearBtn.classList.add('is-visible');
  760.                     lastQuery = keyword;
  761.                     doSearch(keyword);
  762.                     input.focus();
  763.                 });
  764.             });
  765.             // Si l'input est pré-rempli (1er keyword populaire), on lance la recherche automatiquement
  766.             var initialQuery = input.value.trim();
  767.             if (initialQuery.length >= 2) {
  768.                 clearBtn.classList.add('is-visible');
  769.                 lastQuery = initialQuery;
  770.                 doSearch(initialQuery);
  771.             }
  772.         })();
  773.         (function(){
  774.             var els = document.querySelectorAll('.reveal');
  775.             if (!els.length) return;
  776.             if (!('IntersectionObserver' in window)){
  777.                 els.forEach(function(el){ el.classList.add('is-revealed'); });
  778.                 return;
  779.             }
  780.             var io = new IntersectionObserver(function(entries){
  781.                 entries.forEach(function(entry){
  782.                     if (entry.isIntersecting){
  783.                         entry.target.classList.add('is-revealed');
  784.                         io.unobserve(entry.target);
  785.                     }
  786.                 });
  787.             }, { threshold: 0.12, rootMargin: '0px 0px -60px 0px' });
  788.             els.forEach(function(el){ io.observe(el); });
  789.         })();
  790.     </script>
  791. {% endblock footer_js %}