var/cache/dev/twig/6f/6fb915bf0d11f0638aaf9361214069ed.php line 61

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* application/whileresume/application/jobs/dashboard.html.twig */
  16. class __TwigTemplate_b70d2b7d70f9acfdff7b6890503b1ce2 extends Template
  17. {
  18.     private Source $source;
  19.     /**
  20.      * @var array<string, Template>
  21.      */
  22.     private array $macros = [];
  23.     public function __construct(Environment $env)
  24.     {
  25.         parent::__construct($env);
  26.         $this->source $this->getSourceContext();
  27.         $this->blocks = [
  28.             'title' => [$this'block_title'],
  29.             'description' => [$this'block_description'],
  30.             'robots' => [$this'block_robots'],
  31.             'css' => [$this'block_css'],
  32.             'body' => [$this'block_body'],
  33.             'footerjs' => [$this'block_footerjs'],
  34.         ];
  35.     }
  36.     protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  37.     {
  38.         // line 1
  39.         return "application/whileresume/application/jobs/layout-social.html.twig";
  40.     }
  41.     protected function doDisplay(array $context, array $blocks = []): iterable
  42.     {
  43.         $macros $this->macros;
  44.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  45.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""application/whileresume/application/jobs/dashboard.html.twig"));
  46.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  47.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""application/whileresume/application/jobs/dashboard.html.twig"));
  48.         // line 5
  49.         $macros["promo"] = $this->macros["promo"] = $this->load("application/whileresume/_macros/promo_card.html.twig"5)->unwrap();
  50.         // line 1
  51.         $this->parent $this->load("application/whileresume/application/jobs/layout-social.html.twig"1);
  52.         yield from $this->parent->unwrap()->yield($contextarray_merge($this->blocks$blocks));
  53.         
  54.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  55.         
  56.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  57.     }
  58.     // line 7
  59.     /**
  60.      * @return iterable<null|scalar|\Stringable>
  61.      */
  62.     public function block_title(array $context, array $blocks = []): iterable
  63.     {
  64.         $macros $this->macros;
  65.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  66.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  67.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  68.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  69.         if ((((array_key_exists("currentSubKeyword"$context) &&  !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'7$this->source); })()))) && array_key_exists("currentCityFilter"$context)) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'7$this->source); })())))) {
  70.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'7$this->source); })()), "html"nulltrue);
  71.             yield " ";
  72.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'7$this->source); })()), "label", [], "any"falsefalsefalse7), "html"nulltrue);
  73.         } elseif ((array_key_exists("currentFilter"$context) &&  !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'7$this->source); })())))) {
  74.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source, ($context["currentFilter"] ?? null), "shortTitle", [], "any"truetruefalse7)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'7$this->source); })()), "shortTitle", [], "any"falsefalsefalse7), CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'7$this->source); })()), "label", [], "any"falsefalsefalse7))) : (CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'7$this->source); })()), "label", [], "any"falsefalsefalse7))), "html"nulltrue);
  75.             yield " — WhileResume";
  76.         } else {
  77.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.title", [], "whr-public"), "html"nulltrue);
  78.         }
  79.         
  80.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  81.         
  82.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  83.         yield from [];
  84.     }
  85.     // line 8
  86.     /**
  87.      * @return iterable<null|scalar|\Stringable>
  88.      */
  89.     public function block_description(array $context, array $blocks = []): iterable
  90.     {
  91.         $macros $this->macros;
  92.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  93.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""description"));
  94.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  95.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""description"));
  96.         if ((((array_key_exists("currentSubKeyword"$context) &&  !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'8$this->source); })()))) && array_key_exists("currentCityFilter"$context)) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'8$this->source); })())))) {
  97.             yield "Découvrez les offres \"";
  98.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'8$this->source); })()), "html"nulltrue);
  99.             yield "\" à ";
  100.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'8$this->source); })()), "label", [], "any"falsefalsefalse8), "html"nulltrue);
  101.             yield ".";
  102.         } elseif (((array_key_exists("currentFilter"$context) &&  !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'8$this->source); })()))) &&  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'8$this->source); })()), "shortDescription", [], "any"falsefalsefalse8)))) {
  103.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'8$this->source); })()), "shortDescription", [], "any"falsefalsefalse8), "html"nulltrue);
  104.         } else {
  105.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.description", [], "whr-public"), "html"nulltrue);
  106.         }
  107.         
  108.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  109.         
  110.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  111.         yield from [];
  112.     }
  113.     // line 9
  114.     /**
  115.      * @return iterable<null|scalar|\Stringable>
  116.      */
  117.     public function block_robots(array $context, array $blocks = []): iterable
  118.     {
  119.         $macros $this->macros;
  120.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  121.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""robots"));
  122.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  123.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""robots"));
  124.         yield "index,follow";
  125.         
  126.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  127.         
  128.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  129.         yield from [];
  130.     }
  131.     // line 11
  132.     /**
  133.      * @return iterable<null|scalar|\Stringable>
  134.      */
  135.     public function block_css(array $context, array $blocks = []): iterable
  136.     {
  137.         $macros $this->macros;
  138.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  139.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""css"));
  140.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  141.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""css"));
  142.         // line 12
  143.         yield "    <style>
  144.         /* ─── Page dashboard /jobs ─── */
  145.         .jobs-dash{max-width:880px;margin:0 auto}
  146.         .jobs-dash-header{margin-bottom:18px}
  147.         .jobs-dash-title{font-size:24px;font-weight:800;color:#1E1B2E;line-height:1.2;letter-spacing:-0.02em;margin:0 0 6px}
  148.         @media(min-width:768px){.jobs-dash-title{font-size:28px}}
  149.         .jobs-dash-subtitle{font-size:14px;color:#6B7280;margin:0 0 18px}
  150.         /* ─── Bandeau contexte ville (badge + bouton ALL) ─── */
  151.         .city-context-bar{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 16px;padding:10px 14px;background:#F5F3FF;border:1px solid rgba(108,58,237,.15);border-radius:12px}
  152.         .city-context-label{font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:.06em}
  153.         .city-context-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:100px;background:#fff;color:var(--theme-color,#6C3AED);font-size:13px;font-weight:600;border:1px solid rgba(108,58,237,.2)}
  154.         .city-context-badge-icon{font-size:14px;line-height:1}
  155.         .city-context-clear-btn{margin-left:auto;display:inline-flex;align-items:center;gap:4px;padding:5px 12px;border-radius:100px;background:transparent;color:var(--theme-color,#6C3AED);font-size:12px;font-weight:600;border:1px dashed rgba(108,58,237,.4);cursor:pointer;text-decoration:none;font-family:inherit;transition:background .15s,border-style .15s,border-color .15s}
  156.         .city-context-clear-btn:hover{background:#fff;border-style:solid;border-color:var(--theme-color,#6C3AED);color:var(--theme-color,#6C3AED)}
  157.         .city-context-clear-btn svg{width:11px;height:11px}
  158.         /* Widget recherche */
  159.         .wr-search-widget{background:#fff;border-radius:14px;box-shadow:0 0 20px 0 rgba(0,0,0,0.05);padding:10px;margin-bottom:14px;position:relative;z-index:50}
  160.         .wr-search-input-wrap{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:10px;background:#F9FAFB;border:1px solid #E5E7EB;transition:border-color .2s,background .2s}
  161.         .wr-search-input-wrap:focus-within{border-color:rgba(108,58,237,.3);background:#fff}
  162.         .wr-search-icon{color:#9CA3AF;display:flex;flex-shrink:0}
  163.         .wr-search-input{flex:1;border:none;outline:none;background:transparent;font-size:14px;color:#1E1B2E;padding:4px 0;font-family:inherit;min-width:0}
  164.         .wr-search-input::placeholder{color:#9CA3AF}
  165.         .wr-search-clear{background:none;border:none;color:#9CA3AF;cursor:pointer;padding:4px;display:none;font-family:inherit}
  166.         .wr-search-clear.visible{display:flex;align-items:center}
  167.         .wr-search-clear:hover{color:#6B7280}
  168.         .wr-search-clear svg{width:14px;height:14px}
  169.         .wr-search-kbd-hint{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:#6B7280;font-family:inherit;letter-spacing:.02em;white-space:nowrap;flex-shrink:0}
  170.         .wr-search-input-wrap:focus-within .wr-search-kbd-hint{display:inline-flex}
  171.         /* Chips keywords */
  172.         .search-keywords{display:flex;flex-wrap:wrap;gap:6px;margin:0 4px 18px}
  173.         .search-keyword-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:100px;background:#F5F3FF;color:var(--theme-color,#6C3AED);font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,transform .15s;font-family:inherit}
  174.         .search-keyword-chip:hover{background:#EDE9FE;border-color:rgba(108,58,237,.2);transform:translateY(-1px);color:var(--theme-color,#6C3AED)}
  175.         .search-keyword-chip.active{background:var(--theme-color,#6C3AED);color:#fff;border-color:var(--theme-color,#6C3AED)}
  176.         .search-keyword-chip-icon{font-size:13px;line-height:1}
  177.         .search-keywords-label{font-size:11px;font-weight:600;color:#9CA3AF;text-transform:uppercase;letter-spacing:.06em;margin-right:4px;align-self:center}
  178.         /* ─── Sections de filtres SEO (chips → liens directs vers /jobs/{slug}) ─── */
  179.         .filter-section{margin:0 0 14px}
  180.         .filter-section-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;padding:0 4px;flex-wrap:wrap}
  181.         @media(max-width:540px){
  182.             .dash-filter-search{max-width:100%;width:100%}
  183.         }
  184.         .filter-section-title{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;color:#6B7280;text-transform:uppercase;letter-spacing:.06em;margin:0}
  185.         .filter-section-title-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:#F5F3FF;color:var(--theme-color,#6C3AED)}
  186.         .filter-section-title-icon svg{width:11px;height:11px}
  187.         .filter-section-toggle{background:none;border:none;font-size:11px;color:var(--theme-color,#6C3AED);font-weight:600;cursor:pointer;font-family:inherit;padding:4px 8px;border-radius:6px;transition:background .15s}
  188.         .filter-section-toggle:hover{background:#F5F3FF}
  189.         .filter-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 4px}
  190.         .filter-chip{display:inline-flex;align-items:center;gap:5px;padding:7px 13px;border-radius:100px;background:#fff;color:#374151;font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid #E5E7EB;text-decoration:none;transition:background .15s,border-color .15s,transform .15s,color .15s;font-family:inherit;white-space:nowrap}
  191.         .filter-chip:hover{background:#F5F3FF;border-color:rgba(108,58,237,.3);color:var(--theme-color,#6C3AED);transform:translateY(-1px)}
  192.         .filter-chip.active{background:var(--theme-color,#6C3AED);border-color:var(--theme-color,#6C3AED);color:#fff}
  193.         .filter-chip.active:hover{background:#5B21B6;color:#fff}
  194.         .filter-chip-icon{font-size:14px;line-height:1}
  195.         .filter-chip-arrow{display:inline-flex;color:currentColor;opacity:.5;margin-left:2px}
  196.         .filter-chip-arrow svg{width:10px;height:10px}
  197.         /* Mode \"compact\" : sections initialement collapsées si > 6 items */
  198.         .filter-chips.collapsed{max-height:80px;overflow:hidden;position:relative}
  199.         .filter-chips.collapsed::after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:30px;background:linear-gradient(to bottom,transparent,#FAFAFA);pointer-events:none}
  200.         /* ─── Bouton \"Voir plus\" sous les chips villes/métiers ─── */
  201.         .dash-filter-more-wrap{display:flex;justify-content:center;margin-top:10px;padding:0 4px}
  202.         .dash-filter-more-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;background:transparent;color:var(--theme-color,#6C3AED);border:1px dashed rgba(108,58,237,.35);border-radius:100px;font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;transition:background .15s,border-style .15s,border-color .15s}
  203.         .dash-filter-more-btn:hover{background:#F5F3FF;border-style:solid;border-color:var(--theme-color,#6C3AED)}
  204.         .dash-filter-more-icon{display:inline-flex;align-items:center;color:currentColor;transition:transform .2s}
  205.         .dash-filter-more-icon svg{width:12px;height:12px}
  206.         .dash-filter-more-btn.is-expanded .dash-filter-more-icon{transform:rotate(180deg)}
  207.         /* ─── Input de recherche dans le header (toujours visible) ─── */
  208.         .dash-filter-search{display:block;position:relative;flex:1;max-width:240px}
  209.         @keyframes dashFilterFadeIn{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}
  210.         .dash-filter-search-input{width:100%;padding:5px 10px 5px 28px;border:1px solid #E5E7EB;border-radius:100px;font-size:12px;color:#1E1B2E;background:#FAFAFA;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s,background .15s}
  211.         .dash-filter-search-input:focus{border-color:rgba(108,58,237,.4);background:#fff}
  212.         .dash-filter-search-input::placeholder{color:#9CA3AF}
  213.         .dash-filter-search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;pointer-events:none;display:flex}
  214.         .dash-filter-search-icon svg{width:11px;height:11px}
  215.         /* État \"aucun résultat\" sous le filtre live */
  216.         .dash-filter-empty{display:none;padding:14px 12px;font-size:12.5px;color:#9CA3AF;font-style:italic;text-align:center;width:100%}
  217.         .filter-chips.is-no-results .dash-filter-empty{display:block}
  218.         /* Bandeau résultats */
  219.         .jobs-results-info{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 4px 14px;font-size:12px;color:#6B7280}
  220.         .jobs-results-info strong{color:#1E1B2E;font-weight:700}
  221.         /* Liste cards (style \"similar-card\" comme dans show.html.twig) */
  222.         .jobs-list{display:flex;flex-direction:column;gap:10px}
  223.         .jobs-card{background:#fff;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}
  224.         .jobs-card:hover{transform:translateY(-1px);box-shadow:0 4px 20px rgba(108,58,237,.1);color:inherit}
  225.         .jobs-card-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(135deg,#EDE9FE,#DDD6FE);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:20px;color:var(--theme-color,#6C3AED);flex-shrink:0;overflow:hidden}
  226.         .jobs-card-logo img{width:100%;height:100%;object-fit:cover;border-radius:8px}
  227.         .jobs-card-logo svg{width:24px;height:24px;opacity:.85}
  228.         .jobs-card-info{flex:1;min-width:0}
  229.         .jobs-card-title{font-size:14px;font-weight:700;color:#1E1B2E;line-height:1.3;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  230.         .jobs-card-meta{font-size:12px;color:#6B7280;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  231.         .jobs-card-salary{font-size:11px;font-weight:600;color:var(--theme-color,#6C3AED);background:#F5F3FF;padding:3px 9px;border-radius:100px;white-space:nowrap;flex-shrink:0}
  232.         .jobs-card-arrow{flex-shrink:0;color:#9CA3AF;transition:color .15s,transform .15s}
  233.         .jobs-card:hover .jobs-card-arrow{color:var(--theme-color,#6C3AED);transform:translateX(2px)}
  234.         .jobs-card-arrow svg{width:18px;height:18px}
  235.         /* Skeleton (pendant chargement) */
  236.         .jobs-skeleton{display:flex;flex-direction:column;gap:10px}
  237.         .jobs-skel-card{background:#fff;border-radius:14px;padding:14px;display:flex;align-items:center;gap:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)}
  238.         .jobs-skel-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;flex-shrink:0}
  239.         .jobs-skel-info{flex:1}
  240.         .jobs-skel-line{height:14px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;border-radius:4px;margin-bottom:6px}
  241.         .jobs-skel-line.s1{width:60%}
  242.         .jobs-skel-line.s2{width:40%;height:12px;margin-bottom:0}
  243.         @keyframes jobsSkelShim{0%{background-position:200% 0}100%{background-position:-200% 0}}
  244.         /* Bouton charger plus */
  245.         .jobs-load-more{display:flex;width:100%;padding:14px;margin-top:16px;background:#fff;color:var(--theme-color,#6C3AED);border:1.5px dashed rgba(108,58,237,.35);border-radius:12px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:inherit;align-items:center;justify-content:center;gap:8px;transition:background .15s,border-color .15s}
  246.         .jobs-load-more:hover{background:#F5F3FF;border-color:var(--theme-color,#6C3AED);border-style:solid;color:var(--theme-color,#6C3AED)}
  247.         .jobs-load-more svg{width:14px;height:14px}
  248.         .jobs-load-more:disabled{opacity:.6;cursor:not-allowed}
  249.         .jobs-load-more.loading{cursor:wait}
  250.         .jobs-load-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(108,58,237,.2);border-top-color:var(--theme-color,#6C3AED);border-radius:50%;animation:jobsLoadSpin .7s linear infinite}
  251.         @keyframes jobsLoadSpin{to{transform:rotate(360deg)}}
  252.         /* État vide */
  253.         .jobs-empty{text-align:center;padding:40px 20px;background:#fff;border-radius:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)}
  254.         .jobs-empty-icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:16px;background:#F5F3FF;color:var(--theme-color,#6C3AED);margin-bottom:14px}
  255.         .jobs-empty-icon svg{width:24px;height:24px}
  256.         .jobs-empty-title{font-size:16px;font-weight:700;color:#1E1B2E;margin:0 0 6px}
  257.         .jobs-empty-text{font-size:13px;color:#6B7280;margin:0}
  258.     </style>
  259.     ";
  260.         // line 143
  261.         yield "    ";
  262.         yield $macros["promo"]->getTemplateForMacro("macro_styles"$context143$this->getSourceContext())->macro_styles(...[]);
  263.         yield "
  264. ";
  265.         
  266.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  267.         
  268.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  269.         yield from [];
  270.     }
  271.     // line 146
  272.     /**
  273.      * @return iterable<null|scalar|\Stringable>
  274.      */
  275.     public function block_body(array $context, array $blocks = []): iterable
  276.     {
  277.         $macros $this->macros;
  278.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  279.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  280.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  281.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  282.         // line 147
  283.         yield "    <div class=\"jobs-dash\">
  284.         <div class=\"jobs-dash-header\">
  285.             ";
  286.         // line 150
  287.         if ((((array_key_exists("currentSubKeyword"$context) &&  !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'150$this->source); })()))) && array_key_exists("currentCityFilter"$context)) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'150$this->source); })())))) {
  288.             // line 151
  289.             yield "                ";
  290.             // line 152
  291.             yield "                <h1 class=\"jobs-dash-title\">
  292.                     ";
  293.             // line 153
  294.             if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'153$this->source); })()), "icon", [], "any"falsefalsefalse153))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  295.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'153$this->source); })()), "icon", [], "any"falsefalsefalse153), "html"nulltrue);
  296.                 yield " ";
  297.             }
  298.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'153$this->source); })()), "html"nulltrue);
  299.             yield " ";
  300.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.cityHeadingIn", [], "whr-public"), "html"nulltrue);
  301.             yield " ";
  302.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'153$this->source); })()), "label", [], "any"falsefalsefalse153), "html"nulltrue);
  303.             yield "
  304.                 </h1>
  305.                 <p class=\"jobs-dash-subtitle\">";
  306.             // line 155
  307.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.cityKeywordSubtitle", ["%keyword%" => (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword"$context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.'155$this->source); })()), "%city%" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'155$this->source); })()), "label", [], "any"falsefalsefalse155)], "whr-public"), "html"nulltrue);
  308.             yield "</p>
  309.             ";
  310.         } elseif ((        // line 156
  311. array_key_exists("currentFilter"$context) &&  !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'156$this->source); })())))) {
  312.             // line 157
  313.             yield "                <h1 class=\"jobs-dash-title\">
  314.                     ";
  315.             // line 158
  316.             if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'158$this->source); })()), "icon", [], "any"falsefalsefalse158))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  317.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'158$this->source); })()), "icon", [], "any"falsefalsefalse158), "html"nulltrue);
  318.                 yield " ";
  319.             }
  320.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source, ($context["currentFilter"] ?? null), "shortTitle", [], "any"truetruefalse158)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'158$this->source); })()), "shortTitle", [], "any"falsefalsefalse158), CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'158$this->source); })()), "label", [], "any"falsefalsefalse158))) : (CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'158$this->source); })()), "label", [], "any"falsefalsefalse158))), "html"nulltrue);
  321.             yield "
  322.                 </h1>
  323.                 ";
  324.             // line 160
  325.             if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'160$this->source); })()), "shortDescription", [], "any"falsefalsefalse160))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  326.                 // line 161
  327.                 yield "                    <p class=\"jobs-dash-subtitle\">";
  328.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'161$this->source); })()), "shortDescription", [], "any"falsefalsefalse161), "html"nulltrue);
  329.                 yield "</p>
  330.                 ";
  331.             } else {
  332.                 // line 163
  333.                 yield "                    <p class=\"jobs-dash-subtitle\">";
  334.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.subtitle", [], "whr-public"), "html"nulltrue);
  335.                 yield "</p>
  336.                 ";
  337.             }
  338.             // line 165
  339.             yield "            ";
  340.         } else {
  341.             // line 166
  342.             yield "                <h1 class=\"jobs-dash-title\">";
  343.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.heading", [], "whr-public"), "html"nulltrue);
  344.             yield "</h1>
  345.                 <p class=\"jobs-dash-subtitle\">";
  346.             // line 167
  347.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.subtitle", [], "whr-public"), "html"nulltrue);
  348.             yield "</p>
  349.             ";
  350.         }
  351.         // line 169
  352.         yield "
  353.             ";
  354.         // line 171
  355.         yield "            ";
  356.         if ((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'171$this->source); })())))) {
  357.             // line 172
  358.             yield "                <div class=\"city-context-bar\">
  359.                     <span class=\"city-context-label\">";
  360.             // line 173
  361.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.contextLabel", [], "whr-public"), "html"nulltrue);
  362.             yield "</span>
  363.                     <span class=\"city-context-badge\">
  364.                         ";
  365.             // line 175
  366.             if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'175$this->source); })()), "icon", [], "any"falsefalsefalse175))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  367.                 yield "<span class=\"city-context-badge-icon\">";
  368.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'175$this->source); })()), "icon", [], "any"falsefalsefalse175), "html"nulltrue);
  369.                 yield "</span>";
  370.             }
  371.             // line 176
  372.             yield "                        <span>";
  373.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'176$this->source); })()), "label", [], "any"falsefalsefalse176), "html"nulltrue);
  374.             yield "</span>
  375.                     </span>
  376.                     <a href=\"";
  377.             // line 178
  378.             if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'178$this->source); })()), "request", [], "any"falsefalsefalse178), "locale", [], "any"falsefalsefalse178) == "en")) {
  379.                 yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("whileresume_jobs_list");
  380.             } else {
  381.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_whileresume_jobs_list", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'178$this->source); })()), "request", [], "any"falsefalsefalse178), "locale", [], "any"falsefalsefalse178)]), "html"nulltrue);
  382.             }
  383.             yield "\"
  384.                        class=\"city-context-clear-btn\"
  385.                        title=\"";
  386.             // line 180
  387.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.clearCity", [], "whr-public"), "html"nulltrue);
  388.             yield "\">
  389.                         <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\" transform=\"rotate(180 12 12)\"/></svg>
  390.                         ";
  391.             // line 182
  392.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.allCities", [], "whr-public"), "html"nulltrue);
  393.             yield "
  394.                     </a>
  395.                 </div>
  396.             ";
  397.         }
  398.         // line 186
  399.         yield "        </div>
  400.         ";
  401.         // line 189
  402.         yield "        <div class=\"wr-search-widget\">
  403.             <div class=\"wr-search-input-wrap\">
  404.                 <span class=\"wr-search-icon\">
  405.                     <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  406.                 </span>
  407.                 <input type=\"text\" id=\"dashSearchInput\" class=\"wr-search-input\"
  408.                        placeholder=\"";
  409.         // line 195
  410.         if ((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'195$this->source); })())))) {
  411.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.searchInCity", ["%city%" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'195$this->source); })()), "label", [], "any"falsefalsefalse195)], "whr-public"), "html"nulltrue);
  412.         } else {
  413.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.show.searchPlaceholder", [], "whr-public"), "html"nulltrue);
  414.         }
  415.         yield "\"
  416.                        value=\"";
  417.         // line 196
  418.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("initialQuery"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["initialQuery"]) || array_key_exists("initialQuery"$context) ? $context["initialQuery"] : (function () { throw new RuntimeError('Variable "initialQuery" does not exist.'196$this->source); })()), "")) : ("")), "html"nulltrue);
  419.         yield "\"
  420.                        autocomplete=\"off\">
  421.                 <span class=\"wr-search-kbd-hint\" id=\"dashSearchKbdHint\">";
  422.         // line 198
  423.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.pressEnter", [], "whr-public"), "html"nulltrue);
  424.         yield "</span>
  425.                 <button type=\"button\" id=\"dashSearchClear\" class=\"wr-search-clear\" aria-label=\"Clear\">
  426.                     <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>
  427.                 </button>
  428.             </div>
  429.         </div>
  430.         ";
  431.         // line 206
  432.         yield "        ";
  433.         if ((array_key_exists("searchKeywords"$context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["searchKeywords"]) || array_key_exists("searchKeywords"$context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.'206$this->source); })())) > 0))) {
  434.             // line 207
  435.             yield "            <div class=\"search-keywords\">
  436.                 <span class=\"search-keywords-label\">";
  437.             // line 208
  438.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.show.keywordsLabel", [], "whr-public"), "html"nulltrue);
  439.             yield "</span>
  440.                 ";
  441.             // line 209
  442.             $context['_parent'] = $context;
  443.             $context['_seq'] = CoreExtension::ensureTraversable((isset($context["searchKeywords"]) || array_key_exists("searchKeywords"$context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.'209$this->source); })()));
  444.             foreach ($context['_seq'] as $context["_key"] => $context["kw"]) {
  445.                 // line 210
  446.                 yield "                    ";
  447.                 // line 211
  448.                 yield "                    ";
  449.                 $context["kwSlug"] = Twig\Extension\CoreExtension::trim(Twig\Extension\CoreExtension::replace(Twig\Extension\CoreExtension::lower($this->env->getCharset(), Twig\Extension\CoreExtension::replace(CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse211), ["à" => "a""â" => "a""ä" => "a""á" => "a""ã" => "a""å" => "a""À" => "a""Â" => "a""Ä" => "a""Á" => "a""Ã" => "a""Å" => "a""é" => "e""è" => "e""ê" => "e""ë" => "e""ẽ" => "e""É" => "e""È" => "e""Ê" => "e""Ë" => "e""î" => "i""ï" => "i""ì" => "i""í" => "i""Î" => "i""Ï" => "i""Ì" => "i""Í" => "i""ô" => "o""ö" => "o""ò" => "o""ó" => "o""õ" => "o""ø" => "o""Ô" => "o""Ö" => "o""Ò" => "o""Ó" => "o""Õ" => "o""Ø" => "o""û" => "u""ü" => "u""ù" => "u""ú" => "u""Û" => "u""Ü" => "u""Ù" => "u""Ú" => "u""ÿ" => "y""ý" => "y""Ÿ" => "y""Ý" => "y""ç" => "c""Ç" => "c""ñ" => "n""Ñ" => "n""œ" => "oe""Œ" => "oe""æ" => "ae""Æ" => "ae""'" => "-"" " => "-""/" => "-""_" => "-""." => "-""," => "-""(" => """*" => """)" => """&" => "-and-""+" => "-plus-""#" => """?" => """!" => """\"" => """’" => "-""`" => "-"])), ["--" => "-""---" => "-"]), "-");
  450.                 // line 234
  451.                 yield "
  452.                     ";
  453.                 // line 235
  454.                 if ((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'235$this->source); })())))) {
  455.                     // line 236
  456.                     yield "                        ";
  457.                     // line 237
  458.                     yield "                        <a href=\"";
  459.                     if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'237$this->source); })()), "request", [], "any"falsefalsefalse237), "locale", [], "any"falsefalsefalse237) == "en")) {
  460.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter_keyword", ["slug" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'237$this->source); })()), "slug", [], "any"falsefalsefalse237), "keyword" => (isset($context["kwSlug"]) || array_key_exists("kwSlug"$context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.'237$this->source); })())]), "html"nulltrue);
  461.                     } else {
  462.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter_keyword", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'237$this->source); })()), "request", [], "any"falsefalsefalse237), "locale", [], "any"falsefalsefalse237), "slug" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'237$this->source); })()), "slug", [], "any"falsefalsefalse237), "keyword" => (isset($context["kwSlug"]) || array_key_exists("kwSlug"$context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.'237$this->source); })())]), "html"nulltrue);
  463.                     }
  464.                     yield "\"
  465.                            class=\"search-keyword-chip";
  466.                     // line 238
  467.                     if ((array_key_exists("currentSubKeywordSlug"$context) && ((isset($context["currentSubKeywordSlug"]) || array_key_exists("currentSubKeywordSlug"$context) ? $context["currentSubKeywordSlug"] : (function () { throw new RuntimeError('Variable "currentSubKeywordSlug" does not exist.'238$this->source); })()) == (isset($context["kwSlug"]) || array_key_exists("kwSlug"$context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.'238$this->source); })())))) {
  468.                         yield " active";
  469.                     }
  470.                     yield "\">
  471.                             ";
  472.                     // line 239
  473.                     if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source$context["kw"], "icon", [], "any"falsefalsefalse239))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  474.                         yield "<span class=\"search-keyword-chip-icon\">";
  475.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["kw"], "icon", [], "any"falsefalsefalse239), "html"nulltrue);
  476.                         yield "</span>";
  477.                     }
  478.                     // line 240
  479.                     yield "                            <span>";
  480.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse240), "html"nulltrue);
  481.                     yield "</span>
  482.                         </a>
  483.                     ";
  484.                 } else {
  485.                     // line 243
  486.                     yield "                        ";
  487.                     // line 244
  488.                     yield "                        <button type=\"button\"
  489.                                 class=\"search-keyword-chip\"
  490.                                 data-keyword=\"";
  491.                     // line 246
  492.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["kw"], "searchKeyword", [], "any"truetruefalse246)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["kw"], "searchKeyword", [], "any"falsefalsefalse246), CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse246))) : (CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse246))), "html"nulltrue);
  493.                     yield "\">
  494.                             ";
  495.                     // line 247
  496.                     if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source$context["kw"], "icon", [], "any"falsefalsefalse247))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  497.                         yield "<span class=\"search-keyword-chip-icon\">";
  498.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["kw"], "icon", [], "any"falsefalsefalse247), "html"nulltrue);
  499.                         yield "</span>";
  500.                     }
  501.                     // line 248
  502.                     yield "                            <span>";
  503.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse248), "html"nulltrue);
  504.                     yield "</span>
  505.                         </button>
  506.                     ";
  507.                 }
  508.                 // line 251
  509.                 yield "                ";
  510.             }
  511.             $_parent $context['_parent'];
  512.             unset($context['_seq'], $context['_key'], $context['kw'], $context['_parent']);
  513.             $context array_intersect_key($context$_parent) + $_parent;
  514.             // line 252
  515.             yield "            </div>
  516.         ";
  517.         }
  518.         // line 254
  519.         yield "
  520.         ";
  521.         // line 256
  522.         yield "        ";
  523.         if ((array_key_exists("sidebarFiltersCities"$context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'256$this->source); })())) > 0))) {
  524.             // line 257
  525.             yield "            ";
  526.             $context["citiesInitial"] = 14;
  527.             // line 258
  528.             yield "            <div class=\"filter-section\" id=\"filterSectionCities\">
  529.                 <div class=\"filter-section-head\">
  530.                     <h3 class=\"filter-section-title\">
  531.                         <span class=\"filter-section-title-icon\">
  532.                             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>
  533.                         </span>
  534.                         ";
  535.             // line 264
  536.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.popularCities", [], "whr-public"), "html"nulltrue);
  537.             yield "
  538.                     </h3>
  539.                     ";
  540.             // line 267
  541.             yield "                    ";
  542.             if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'267$this->source); })())) > (isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'267$this->source); })()))) {
  543.                 // line 268
  544.                 yield "                        <div class=\"dash-filter-search\">
  545.                             <span class=\"dash-filter-search-icon\">
  546.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  547.                             </span>
  548.                             <input type=\"text\"
  549.                                    class=\"dash-filter-search-input\"
  550.                                    data-search-target=\"filterChipsCities\"
  551.                                    placeholder=\"";
  552.                 // line 275
  553.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterSearchCity", [], "whr-public"), "html"nulltrue);
  554.                 yield "\"
  555.                                    autocomplete=\"off\">
  556.                         </div>
  557.                     ";
  558.             }
  559.             // line 279
  560.             yield "                </div>
  561.                 <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCities\" data-initial=\"";
  562.             // line 280
  563.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'280$this->source); })()), "html"nulltrue);
  564.             yield "\">
  565.                     ";
  566.             // line 281
  567.             $context['_parent'] = $context;
  568.             $context['_seq'] = CoreExtension::ensureTraversable((isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'281$this->source); })()));
  569.             $context['loop'] = [
  570.               'parent' => $context['_parent'],
  571.               'index0' => 0,
  572.               'index'  => 1,
  573.               'first'  => true,
  574.             ];
  575.             if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  576.                 $length count($context['_seq']);
  577.                 $context['loop']['revindex0'] = $length 1;
  578.                 $context['loop']['revindex'] = $length;
  579.                 $context['loop']['length'] = $length;
  580.                 $context['loop']['last'] = === $length;
  581.             }
  582.             foreach ($context['_seq'] as $context["_key"] => $context["f"]) {
  583.                 // line 282
  584.                 yield "                        <a href=\"";
  585.                 if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'282$this->source); })()), "request", [], "any"falsefalsefalse282), "locale", [], "any"falsefalsefalse282) == "en")) {
  586.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse282)]), "html"nulltrue);
  587.                 } else {
  588.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'282$this->source); })()), "request", [], "any"falsefalsefalse282), "locale", [], "any"falsefalsefalse282), "slug" => CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse282)]), "html"nulltrue);
  589.                 }
  590.                 yield "\"
  591.                            class=\"filter-chip dash-filter-item";
  592.                 // line 283
  593.                 if (((array_key_exists("currentFilter"$context) &&  !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'283$this->source); })()))) && (CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'283$this->source); })()), "slug", [], "any"falsefalsefalse283) == CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse283)))) {
  594.                     yield " active";
  595.                 }
  596.                 yield "\"
  597.                            data-filter-slug=\"";
  598.                 // line 284
  599.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse284), "html"nulltrue);
  600.                 yield "\"
  601.                            data-filter-label=\"";
  602.                 // line 285
  603.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "label", [], "any"falsefalsefalse285), "html"nulltrue);
  604.                 yield "\"
  605.                            data-index=\"";
  606.                 // line 286
  607.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index0", [], "any"falsefalsefalse286), "html"nulltrue);
  608.                 yield "\"";
  609.                 if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "index0", [], "any"falsefalsefalse286) >= (isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'286$this->source); })()))) {
  610.                     yield " style=\"display:none\"";
  611.                 }
  612.                 yield ">
  613.                             ";
  614.                 // line 287
  615.                 if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source$context["f"], "icon", [], "any"falsefalsefalse287))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  616.                     yield "<span class=\"filter-chip-icon\">";
  617.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "icon", [], "any"falsefalsefalse287), "html"nulltrue);
  618.                     yield "</span>";
  619.                 }
  620.                 // line 288
  621.                 yield "                            <span>";
  622.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "label", [], "any"falsefalsefalse288), "html"nulltrue);
  623.                 yield "</span>
  624.                             <span class=\"filter-chip-arrow\">
  625.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg>
  626.                             </span>
  627.                         </a>
  628.                     ";
  629.                 ++$context['loop']['index0'];
  630.                 ++$context['loop']['index'];
  631.                 $context['loop']['first'] = false;
  632.                 if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  633.                     --$context['loop']['revindex0'];
  634.                     --$context['loop']['revindex'];
  635.                     $context['loop']['last'] = === $context['loop']['revindex0'];
  636.                 }
  637.             }
  638.             $_parent $context['_parent'];
  639.             unset($context['_seq'], $context['_key'], $context['f'], $context['_parent'], $context['loop']);
  640.             $context array_intersect_key($context$_parent) + $_parent;
  641.             // line 294
  642.             yield "                    <div class=\"dash-filter-empty\">";
  643.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterNoResults", [], "whr-public"), "html"nulltrue);
  644.             yield "</div>
  645.                 </div>
  646.                 ";
  647.             // line 296
  648.             if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'296$this->source); })())) > (isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'296$this->source); })()))) {
  649.                 // line 297
  650.                 yield "                    <div class=\"dash-filter-more-wrap\">
  651.                         <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCities\" data-section=\"filterSectionCities\">
  652.                             <span class=\"dash-filter-more-icon\">
  653.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  654.                             </span>
  655.                             <span class=\"dash-filter-more-label\" data-more=\"";
  656.                 // line 302
  657.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCities", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'302$this->source); })())) - (isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'302$this->source); })()))], "whr-public"), "html"nulltrue);
  658.                 yield "\" data-less=\"";
  659.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showLessCities", [], "whr-public"), "html"nulltrue);
  660.                 yield "\">";
  661.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCities", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities"$context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.'302$this->source); })())) - (isset($context["citiesInitial"]) || array_key_exists("citiesInitial"$context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.'302$this->source); })()))], "whr-public"), "html"nulltrue);
  662.                 yield "</span>
  663.                         </button>
  664.                     </div>
  665.                 ";
  666.             }
  667.             // line 306
  668.             yield "            </div>
  669.         ";
  670.         }
  671.         // line 308
  672.         yield "
  673.         ";
  674.         // line 310
  675.         yield "        ";
  676.         if ((array_key_exists("sidebarFiltersCategories"$context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'310$this->source); })())) > 0))) {
  677.             // line 311
  678.             yield "            ";
  679.             $context["categoriesInitial"] = 8;
  680.             // line 312
  681.             yield "            <div class=\"filter-section\" id=\"filterSectionCategories\">
  682.                 <div class=\"filter-section-head\">
  683.                     <h3 class=\"filter-section-title\">
  684.                         <span class=\"filter-section-title-icon\">
  685.                             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\"/><path d=\"M16 7V5a4 4 0 00-8 0v2\"/></svg>
  686.                         </span>
  687.                         ";
  688.             // line 318
  689.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.popularCategories", [], "whr-public"), "html"nulltrue);
  690.             yield "
  691.                     </h3>
  692.                     ";
  693.             // line 321
  694.             yield "                    ";
  695.             if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'321$this->source); })())) > (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'321$this->source); })()))) {
  696.                 // line 322
  697.                 yield "                        <div class=\"dash-filter-search\">
  698.                             <span class=\"dash-filter-search-icon\">
  699.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  700.                             </span>
  701.                             <input type=\"text\"
  702.                                    class=\"dash-filter-search-input\"
  703.                                    data-search-target=\"filterChipsCategories\"
  704.                                    placeholder=\"";
  705.                 // line 329
  706.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterSearchCategory", [], "whr-public"), "html"nulltrue);
  707.                 yield "\"
  708.                                    autocomplete=\"off\">
  709.                         </div>
  710.                     ";
  711.             }
  712.             // line 333
  713.             yield "                </div>
  714.                 <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCategories\" data-initial=\"";
  715.             // line 334
  716.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'334$this->source); })()), "html"nulltrue);
  717.             yield "\">
  718.                     ";
  719.             // line 335
  720.             $context['_parent'] = $context;
  721.             $context['_seq'] = CoreExtension::ensureTraversable((isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'335$this->source); })()));
  722.             $context['loop'] = [
  723.               'parent' => $context['_parent'],
  724.               'index0' => 0,
  725.               'index'  => 1,
  726.               'first'  => true,
  727.             ];
  728.             if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  729.                 $length count($context['_seq']);
  730.                 $context['loop']['revindex0'] = $length 1;
  731.                 $context['loop']['revindex'] = $length;
  732.                 $context['loop']['length'] = $length;
  733.                 $context['loop']['last'] = === $length;
  734.             }
  735.             foreach ($context['_seq'] as $context["_key"] => $context["f"]) {
  736.                 // line 336
  737.                 yield "                        <a href=\"";
  738.                 if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'336$this->source); })()), "request", [], "any"falsefalsefalse336), "locale", [], "any"falsefalsefalse336) == "en")) {
  739.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse336)]), "html"nulltrue);
  740.                 } else {
  741.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'336$this->source); })()), "request", [], "any"falsefalsefalse336), "locale", [], "any"falsefalsefalse336), "slug" => CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse336)]), "html"nulltrue);
  742.                 }
  743.                 yield "\"
  744.                            class=\"filter-chip dash-filter-item";
  745.                 // line 337
  746.                 if (((array_key_exists("currentFilter"$context) &&  !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'337$this->source); })()))) && (CoreExtension::getAttribute($this->env$this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter"$context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.'337$this->source); })()), "slug", [], "any"falsefalsefalse337) == CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse337)))) {
  747.                     yield " active";
  748.                 }
  749.                 yield "\"
  750.                            data-filter-slug=\"";
  751.                 // line 338
  752.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "slug", [], "any"falsefalsefalse338), "html"nulltrue);
  753.                 yield "\"
  754.                            data-filter-label=\"";
  755.                 // line 339
  756.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "label", [], "any"falsefalsefalse339), "html"nulltrue);
  757.                 yield "\"
  758.                            data-index=\"";
  759.                 // line 340
  760.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index0", [], "any"falsefalsefalse340), "html"nulltrue);
  761.                 yield "\"";
  762.                 if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "index0", [], "any"falsefalsefalse340) >= (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'340$this->source); })()))) {
  763.                     yield " style=\"display:none\"";
  764.                 }
  765.                 yield ">
  766.                             ";
  767.                 // line 341
  768.                 if ((($tmp =  !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env$this->source$context["f"], "icon", [], "any"falsefalsefalse341))) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  769.                     yield "<span class=\"filter-chip-icon\">";
  770.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "icon", [], "any"falsefalsefalse341), "html"nulltrue);
  771.                     yield "</span>";
  772.                 }
  773.                 // line 342
  774.                 yield "                            <span>";
  775.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["f"], "label", [], "any"falsefalsefalse342), "html"nulltrue);
  776.                 yield "</span>
  777.                             <span class=\"filter-chip-arrow\">
  778.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg>
  779.                             </span>
  780.                         </a>
  781.                     ";
  782.                 ++$context['loop']['index0'];
  783.                 ++$context['loop']['index'];
  784.                 $context['loop']['first'] = false;
  785.                 if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  786.                     --$context['loop']['revindex0'];
  787.                     --$context['loop']['revindex'];
  788.                     $context['loop']['last'] = === $context['loop']['revindex0'];
  789.                 }
  790.             }
  791.             $_parent $context['_parent'];
  792.             unset($context['_seq'], $context['_key'], $context['f'], $context['_parent'], $context['loop']);
  793.             $context array_intersect_key($context$_parent) + $_parent;
  794.             // line 348
  795.             yield "                    <div class=\"dash-filter-empty\">";
  796.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterNoResults", [], "whr-public"), "html"nulltrue);
  797.             yield "</div>
  798.                 </div>
  799.                 ";
  800.             // line 350
  801.             if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'350$this->source); })())) > (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'350$this->source); })()))) {
  802.                 // line 351
  803.                 yield "                    <div class=\"dash-filter-more-wrap\">
  804.                         <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCategories\" data-section=\"filterSectionCategories\">
  805.                             <span class=\"dash-filter-more-icon\">
  806.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  807.                             </span>
  808.                             <span class=\"dash-filter-more-label\" data-more=\"";
  809.                 // line 356
  810.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCategories", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'356$this->source); })())) - (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'356$this->source); })()))], "whr-public"), "html"nulltrue);
  811.                 yield "\" data-less=\"";
  812.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showLessCategories", [], "whr-public"), "html"nulltrue);
  813.                 yield "\">";
  814.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCategories", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories"$context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.'356$this->source); })())) - (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial"$context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.'356$this->source); })()))], "whr-public"), "html"nulltrue);
  815.                 yield "</span>
  816.                         </button>
  817.                     </div>
  818.                 ";
  819.             }
  820.             // line 360
  821.             yield "            </div>
  822.         ";
  823.         }
  824.         // line 362
  825.         yield "
  826.         ";
  827.         // line 364
  828.         yield "        <div class=\"jobs-results-info\" id=\"jobsResultsInfo\">
  829.             <span id=\"jobsResultsCount\">";
  830.         // line 365
  831.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loading", [], "whr-public"), "html"nulltrue);
  832.         yield "</span>
  833.         </div>
  834.         ";
  835.         // line 369
  836.         yield "        <div class=\"jobs-list\" id=\"jobsList\">
  837.             <div class=\"jobs-skeleton\">
  838.                 ";
  839.         // line 371
  840.         $context['_parent'] = $context;
  841.         $context['_seq'] = CoreExtension::ensureTraversable(range(15));
  842.         foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
  843.             // line 372
  844.             yield "                    <div class=\"jobs-skel-card\">
  845.                         <div class=\"jobs-skel-logo\"></div>
  846.                         <div class=\"jobs-skel-info\">
  847.                             <div class=\"jobs-skel-line s1\"></div>
  848.                             <div class=\"jobs-skel-line s2\"></div>
  849.                         </div>
  850.                     </div>
  851.                 ";
  852.         }
  853.         $_parent $context['_parent'];
  854.         unset($context['_seq'], $context['_key'], $context['i'], $context['_parent']);
  855.         $context array_intersect_key($context$_parent) + $_parent;
  856.         // line 380
  857.         yield "            </div>
  858.         </div>
  859.         ";
  860.         // line 384
  861.         yield "        <button type=\"button\" class=\"jobs-load-more\" id=\"jobsLoadMore\" style=\"display:none;\">
  862.             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  863.             <span id=\"jobsLoadMoreLabel\">";
  864.         // line 386
  865.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadMore", [], "whr-public"), "html"nulltrue);
  866.         yield "</span>
  867.         </button>
  868.         ";
  869.         // line 392
  870.         yield "        ";
  871.         if ((null === CoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'392$this->source); })()), "user", [], "any"falsefalsefalse392))) {
  872.             // line 393
  873.             yield "            ";
  874.             yield $macros["promo"]->getTemplateForMacro("macro_card_template"$context393$this->getSourceContext())->macro_card_template(...[["template_id" => "jobs-promo-card-template""login_url" => (((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,             // line 395
  875. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'395$this->source); })()), "request", [], "any"falsefalsefalse395), "locale", [], "any"falsefalsefalse395) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_gestion_candidates_dashboard")) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_gestion_candidates_dashboard", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,             // line 397
  876. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'397$this->source); })()), "request", [], "any"falsefalsefalse397), "locale", [], "any"falsefalsefalse397)])))]]);
  877.             // line 398
  878.             yield "
  879.         ";
  880.         }
  881.         // line 400
  882.         yield "
  883.     </div>
  884. ";
  885.         
  886.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  887.         
  888.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  889.         yield from [];
  890.     }
  891.     // line 404
  892.     /**
  893.      * @return iterable<null|scalar|\Stringable>
  894.      */
  895.     public function block_footerjs(array $context, array $blocks = []): iterable
  896.     {
  897.         $macros $this->macros;
  898.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  899.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""footerjs"));
  900.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  901.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""footerjs"));
  902.         // line 405
  903.         yield "    <script>
  904.         (function(){
  905.             'use strict';
  906.             try {
  907.                 var LOCALE = '";
  908.         // line 410
  909.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'410$this->source); })()), "request", [], "any"falsefalsefalse410), "locale", [], "any"falsefalsefalse410), "html"nulltrue);
  910.         yield "';
  911.                 var IS_AUTHENTICATED = ";
  912.         // line 411
  913.         yield (((($tmp CoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'411$this->source); })()), "user", [], "any"falsefalsefalse411)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ("true") : ("false"));
  914.         yield ";
  915.                 var SEARCH_API_URL = '";
  916.         // line 413
  917.         yield (((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'413$this->source); })()), "request", [], "any"falsefalsefalse413), "locale", [], "any"falsefalsefalse413) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_api_search")) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_api_search", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'413$this->source); })()), "request", [], "any"falsefalsefalse413), "locale", [], "any"falsefalsefalse413)]), "html"nulltrue)));
  918.         yield "';
  919.                 var JOB_SHOW_URL_TEMPLATE = '";
  920.         // line 414
  921.         yield (((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'414$this->source); })()), "request", [], "any"falsefalsefalse414), "locale", [], "any"falsefalsefalse414) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_api_search", ["slug" => "__SLUG__"])) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_job_show", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'414$this->source); })()), "request", [], "any"falsefalsefalse414), "locale", [], "any"falsefalsefalse414), "slug" => "__SLUG__"]), "html"nulltrue)));
  922.         yield "';
  923.                 var PAGE_SIZE = 10;
  924.                 var currentQuery = ";
  925.         // line 417
  926.         yield json_encode(((array_key_exists("initialQuery"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["initialQuery"]) || array_key_exists("initialQuery"$context) ? $context["initialQuery"] : (function () { throw new RuntimeError('Variable "initialQuery" does not exist.'417$this->source); })()), "")) : ("")));
  927.         yield ";
  928.                 var currentOffset = 0;
  929.                 var currentTotal = 0;
  930.                 var isFetching = false;
  931.                 // Contexte ville (vient du serveur si on est sur /jobs/paris/... sinon vide)
  932.                 var CITY_KEYWORD = ";
  933.         // line 423
  934.         yield json_encode(((array_key_exists("currentCityKeyword"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["currentCityKeyword"]) || array_key_exists("currentCityKeyword"$context) ? $context["currentCityKeyword"] : (function () { throw new RuntimeError('Variable "currentCityKeyword" does not exist.'423$this->source); })()), "")) : ("")));
  935.         yield ";
  936.                 // Slug ville pour générer les URLs de redirection au submit
  937.                 var CITY_SLUG = ";
  938.         // line 426
  939.         yield (((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'426$this->source); })())))) ? (json_encode(CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'426$this->source); })()), "slug", [], "any"falsefalsefalse426))) : ("null"));
  940.         yield ";
  941.                 // URL pour le dashboard global (sans ville)
  942.                 var DASHBOARD_URL = '";
  943.         // line 429
  944.         yield (((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'429$this->source); })()), "request", [], "any"falsefalsefalse429), "locale", [], "any"falsefalsefalse429) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("whileresume_jobs_list")) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_whileresume_jobs_list", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'429$this->source); })()), "request", [], "any"falsefalsefalse429), "locale", [], "any"falsefalsefalse429)]), "html"nulltrue)));
  945.         yield "';
  946.                 // Templates URL pour /jobs/{citySlug} et /jobs/{citySlug}/{keyword}
  947.                 var CITY_LANDING_URL_TEMPLATE = ";
  948.         // line 432
  949.         yield (((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'432$this->source); })())))) ? (json_encode((((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 433
  950. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'433$this->source); })()), "request", [], "any"falsefalsefalse433), "locale", [], "any"falsefalsefalse433) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env$this->source,         // line 434
  951. (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'434$this->source); })()), "slug", [], "any"falsefalsefalse434)])) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 435
  952. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'435$this->source); })()), "request", [], "any"falsefalsefalse435), "locale", [], "any"falsefalsefalse435), "slug" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'435$this->source); })()), "slug", [], "any"falsefalsefalse435)]))))) : ("null"));
  953.         // line 436
  954.         yield ";
  955.                 var CITY_KEYWORD_URL_TEMPLATE = ";
  956.         // line 437
  957.         yield (((array_key_exists("currentCityFilter"$context) &&  !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'437$this->source); })())))) ? (json_encode((((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 438
  958. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'438$this->source); })()), "request", [], "any"falsefalsefalse438), "locale", [], "any"falsefalsefalse438) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter_keyword", ["slug" => CoreExtension::getAttribute($this->env$this->source,         // line 439
  959. (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'439$this->source); })()), "slug", [], "any"falsefalsefalse439), "keyword" => "kwplaceholder"])) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter_keyword", ["_locale" => CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source,         // line 440
  960. (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'440$this->source); })()), "request", [], "any"falsefalsefalse440), "locale", [], "any"falsefalsefalse440), "slug" => CoreExtension::getAttribute($this->env$this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter"$context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.'440$this->source); })()), "slug", [], "any"falsefalsefalse440), "keyword" => "kwplaceholder"]))))) : ("null"));
  961.         // line 441
  962.         yield ";
  963.                 // Liste des keywords BDD avec leur slug (pour le matching côté client au submit)
  964.                 var KEYWORDS_DATA = [
  965.                     ";
  966.         // line 445
  967.         $context['_parent'] = $context;
  968.         $context['_seq'] = CoreExtension::ensureTraversable(((array_key_exists("searchKeywords"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["searchKeywords"]) || array_key_exists("searchKeywords"$context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.'445$this->source); })()), [])) : ([])));
  969.         $context['loop'] = [
  970.           'parent' => $context['_parent'],
  971.           'index0' => 0,
  972.           'index'  => 1,
  973.           'first'  => true,
  974.         ];
  975.         if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  976.             $length count($context['_seq']);
  977.             $context['loop']['revindex0'] = $length 1;
  978.             $context['loop']['revindex'] = $length;
  979.             $context['loop']['length'] = $length;
  980.             $context['loop']['last'] = === $length;
  981.         }
  982.         foreach ($context['_seq'] as $context["_key"] => $context["kw"]) {
  983.             // line 446
  984.             yield "                    ";
  985.             $context["kwSlugForJs"] = Twig\Extension\CoreExtension::trim(Twig\Extension\CoreExtension::replace(Twig\Extension\CoreExtension::lower($this->env->getCharset(), Twig\Extension\CoreExtension::replace(CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse446), ["à" => "a""â" => "a""ä" => "a""á" => "a""ã" => "a""å" => "a""À" => "a""Â" => "a""Ä" => "a""Á" => "a""Ã" => "a""Å" => "a""é" => "e""è" => "e""ê" => "e""ë" => "e""ẽ" => "e""É" => "e""È" => "e""Ê" => "e""Ë" => "e""î" => "i""ï" => "i""ì" => "i""í" => "i""Î" => "i""Ï" => "i""Ì" => "i""Í" => "i""ô" => "o""ö" => "o""ò" => "o""ó" => "o""õ" => "o""ø" => "o""Ô" => "o""Ö" => "o""Ò" => "o""Ó" => "o""Õ" => "o""Ø" => "o""û" => "u""ü" => "u""ù" => "u""ú" => "u""Û" => "u""Ü" => "u""Ù" => "u""Ú" => "u""ÿ" => "y""ý" => "y""Ÿ" => "y""Ý" => "y""ç" => "c""Ç" => "c""ñ" => "n""Ñ" => "n""œ" => "oe""Œ" => "oe""æ" => "ae""Æ" => "ae""'" => "-"" " => "-""/" => "-""_" => "-""." => "-""," => "-""(" => """*" => """)" => """&" => "-and-""+" => "-plus-""#" => """?" => """!" => """\"" => """’" => "-""`" => "-"])), ["--" => "-""---" => "-"]), "-");
  986.             // line 468
  987.             yield "                    { label: ";
  988.             yield json_encode(CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse468));
  989.             yield ", searchKeyword: ";
  990.             yield json_encode(((CoreExtension::getAttribute($this->env$this->source$context["kw"], "searchKeyword", [], "any"falsefalsefalse468)) ? (CoreExtension::getAttribute($this->env$this->source$context["kw"], "searchKeyword", [], "any"falsefalsefalse468)) : (CoreExtension::getAttribute($this->env$this->source$context["kw"], "label", [], "any"falsefalsefalse468))));
  991.             yield ", slug: ";
  992.             yield json_encode((isset($context["kwSlugForJs"]) || array_key_exists("kwSlugForJs"$context) ? $context["kwSlugForJs"] : (function () { throw new RuntimeError('Variable "kwSlugForJs" does not exist.'468$this->source); })()));
  993.             yield " }";
  994.             if ((($tmp =  !CoreExtension::getAttribute($this->env$this->source$context["loop"], "last", [], "any"falsefalsefalse468)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  995.                 yield ",";
  996.             }
  997.             // line 469
  998.             yield "                    ";
  999.             ++$context['loop']['index0'];
  1000.             ++$context['loop']['index'];
  1001.             $context['loop']['first'] = false;
  1002.             if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  1003.                 --$context['loop']['revindex0'];
  1004.                 --$context['loop']['revindex'];
  1005.                 $context['loop']['last'] = === $context['loop']['revindex0'];
  1006.             }
  1007.         }
  1008.         $_parent $context['_parent'];
  1009.         unset($context['_seq'], $context['_key'], $context['kw'], $context['_parent'], $context['loop']);
  1010.         $context array_intersect_key($context$_parent) + $_parent;
  1011.         // line 470
  1012.         yield "                ];
  1013.                 var input = document.getElementById('dashSearchInput');
  1014.                 var clearBtn = document.getElementById('dashSearchClear');
  1015.                 var listEl = document.getElementById('jobsList');
  1016.                 var infoEl = document.getElementById('jobsResultsCount');
  1017.                 var loadMoreBtn = document.getElementById('jobsLoadMore');
  1018.                 var loadMoreLabel = document.getElementById('jobsLoadMoreLabel');
  1019.                 function escapeHtml(s){
  1020.                     if(s == null) return '';
  1021.                     return String(s).replace(/[&<>\"']/g, function(c){
  1022.                         return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];
  1023.                     });
  1024.                 }
  1025.                 function buildJobCard(item){
  1026.                     // Fallback logo : icône \"immeuble\" stylisée si pas de logo entreprise
  1027.                     var fallbackLogo =
  1028.                         '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +
  1029.                         '<path d=\"M3 21h18\"/>' +
  1030.                         '<path d=\"M5 21V7l8-4v18\"/>' +
  1031.                         '<path d=\"M19 21V11l-6-4\"/>' +
  1032.                         '<path d=\"M9 9h.01\"/>' +
  1033.                         '<path d=\"M9 13h.01\"/>' +
  1034.                         '<path d=\"M9 17h.01\"/>' +
  1035.                         '</svg>';
  1036.                     var logoHtml = item.logo
  1037.                         ? '<img src=\"' + escapeHtml(item.logo) + '\" alt=\"\" onerror=\"this.parentNode.innerHTML=\\'' + fallbackLogo.replace(/'/g, \"\\\\'\") + '\\';\">'
  1038.                         : fallbackLogo;
  1039.                     var meta = [];
  1040.                     if(item.companyName) meta.push(escapeHtml(item.companyName));
  1041.                     if(item.city) meta.push(escapeHtml(item.city));
  1042.                     if(item.employmentType) meta.push(escapeHtml(item.employmentType));
  1043.                     var salaryHtml = (item.salaryMin && item.salaryMax)
  1044.                         ? '<span class=\"jobs-card-salary\">' + item.salaryMin + '–' + item.salaryMax + ' ' + escapeHtml(item.devise || '') + '</span>'
  1045.                         : '';
  1046.                     var url = item.url || JOB_SHOW_URL_TEMPLATE.replace('__SLUG__', encodeURIComponent(item.slug));
  1047.                     var a = document.createElement('a');
  1048.                     a.href = url;
  1049.                     a.className = 'jobs-card';
  1050.                     a.innerHTML =
  1051.                         '<div class=\"jobs-card-logo\">' + logoHtml + '</div>' +
  1052.                         '<div class=\"jobs-card-info\">' +
  1053.                         '<div class=\"jobs-card-title\">' + escapeHtml(item.title || '') + '</div>' +
  1054.                         '<div class=\"jobs-card-meta\">' + meta.join(' · ') + '</div>' +
  1055.                         '</div>' +
  1056.                         salaryHtml +
  1057.                         '<span class=\"jobs-card-arrow\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"/></svg></span>';
  1058.                     return a;
  1059.                 }
  1060.                 /**
  1061.                  * Clone la promo card depuis le <template> rendu par la macro Twig.
  1062.                  * Le HTML est défini une seule fois dans _macros/promo_card.html.twig.
  1063.                  * Retourne null si le template n'est pas présent (ex: user connecté).
  1064.                  */
  1065.                 function buildPromoCard(){
  1066.                     var tpl = document.getElementById('jobs-promo-card-template');
  1067.                     if(!tpl || !tpl.content) return null;
  1068.                     var node = tpl.content.firstElementChild;
  1069.                     return node ? node.cloneNode(true) : null;
  1070.                 }
  1071.                 function renderEmpty(){
  1072.                     listEl.innerHTML =
  1073.                         '<div class=\"jobs-empty\">' +
  1074.                         '<div class=\"jobs-empty-icon\">' +
  1075.                         '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>' +
  1076.                         '</div>' +
  1077.                         '<div class=\"jobs-empty-title\">";
  1078.         // line 543
  1079.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.emptyTitle", [], "whr-public"), "js"), "html"nulltrue);
  1080.         yield "</div>' +
  1081.                         '<div class=\"jobs-empty-text\">";
  1082.         // line 544
  1083.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.emptyText", [], "whr-public"), "js"), "html"nulltrue);
  1084.         yield "</div>' +
  1085.                         '</div>';
  1086.                 }
  1087.                 function setLoadMoreState(state){
  1088.                     if(!loadMoreBtn) return;
  1089.                     if(state === 'loading'){
  1090.                         loadMoreBtn.classList.add('loading');
  1091.                         loadMoreBtn.disabled = true;
  1092.                         loadMoreLabel.innerHTML = '<span class=\"jobs-load-spinner\"></span> ";
  1093.         // line 553
  1094.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadingMore", [], "whr-public"), "js"), "html"nulltrue);
  1095.         yield "';
  1096.                     } else {
  1097.                         loadMoreBtn.classList.remove('loading');
  1098.                         loadMoreBtn.disabled = false;
  1099.                         loadMoreLabel.textContent = '";
  1100.         // line 557
  1101.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadMore", [], "whr-public"), "js"), "html"nulltrue);
  1102.         yield "';
  1103.                     }
  1104.                 }
  1105.                 function fetchJobs(query, offset, append){
  1106.                     if(isFetching) return;
  1107.                     isFetching = true;
  1108.                     if(!append){
  1109.                         // Nouvelle recherche : on remet à zéro et affiche skeleton
  1110.                         listEl.innerHTML =
  1111.                             '<div class=\"jobs-skeleton\">' +
  1112.                             Array(5).fill(0).map(function(){
  1113.                                 return '<div class=\"jobs-skel-card\"><div class=\"jobs-skel-logo\"></div><div class=\"jobs-skel-info\"><div class=\"jobs-skel-line s1\"></div><div class=\"jobs-skel-line s2\"></div></div></div>';
  1114.                             }).join('') +
  1115.                             '</div>';
  1116.                         if(infoEl) infoEl.textContent = '";
  1117.         // line 573
  1118.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loading", [], "whr-public"), "js"), "html"nulltrue);
  1119.         yield "';
  1120.                         if(loadMoreBtn) loadMoreBtn.style.display = 'none';
  1121.                     } else {
  1122.                         setLoadMoreState('loading');
  1123.                     }
  1124.                     var url = SEARCH_API_URL + '?q=' + encodeURIComponent(query || '') + '&locale=' + LOCALE + '&limit=' + PAGE_SIZE + '&offset=' + offset;
  1125.                     if(CITY_KEYWORD){ url += '&city=' + encodeURIComponent(CITY_KEYWORD); }
  1126.                     // Dashboard sans filtre : on demande explicitement les dernières offres
  1127.                     if(!query && !CITY_KEYWORD){ url += '&all=1'; }
  1128.                     fetch(url, {headers:{'Accept':'application/json'}})
  1129.                         .then(function(r){ return r.ok ? r.json() : null; })
  1130.                         .then(function(data){
  1131.                             isFetching = false;
  1132.                             if(!data){
  1133.                                 if(!append) renderEmpty();
  1134.                                 setLoadMoreState('idle');
  1135.                                 return;
  1136.                             }
  1137.                             var items = data.items || [];
  1138.                             currentTotal = data.total || 0;
  1139.                             if(!append){
  1140.                                 listEl.innerHTML = '';
  1141.                                 if(items.length === 0){
  1142.                                     renderEmpty();
  1143.                                     if(infoEl) infoEl.innerHTML = '<strong>0</strong> ";
  1144.         // line 600
  1145.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.resultsCount", [], "whr-public"), "js"), "html"nulltrue);
  1146.         yield "';
  1147.                                     if(loadMoreBtn) loadMoreBtn.style.display = 'none';
  1148.                                     return;
  1149.                                 }
  1150.                             }
  1151.                             // Insérer la promo card après la 5ème offre (uniquement au 1er chargement,
  1152.                             // si user non connecté et qu'on a au moins 5 offres)
  1153.                             var insertPromoAt = (!append && !IS_AUTHENTICATED && items.length >= 5) ? 5 : -1;
  1154.                             items.forEach(function(item, idx){
  1155.                                 listEl.appendChild(buildJobCard(item));
  1156.                                 if(idx === insertPromoAt - 1){
  1157.                                     var promoNode = buildPromoCard();
  1158.                                     if(promoNode) listEl.appendChild(promoNode);
  1159.                                 }
  1160.                             });
  1161.                             currentOffset = offset + items.length;
  1162.                             if(infoEl){
  1163.                                 infoEl.innerHTML = '<strong>' + currentTotal + '</strong> ";
  1164.         // line 621
  1165.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.resultsCount", [], "whr-public"), "js"), "html"nulltrue);
  1166.         yield "';
  1167.                             }
  1168.                             // Afficher / cacher \"Charger plus\"
  1169.                             if(loadMoreBtn){
  1170.                                 if(currentOffset < currentTotal){
  1171.                                     loadMoreBtn.style.display = 'flex';
  1172.                                 } else {
  1173.                                     loadMoreBtn.style.display = 'none';
  1174.                                 }
  1175.                                 setLoadMoreState('idle');
  1176.                             }
  1177.                         })
  1178.                         .catch(function(err){
  1179.                             isFetching = false;
  1180.                             console.error('[whr-dash] fetch error', err);
  1181.                             setLoadMoreState('idle');
  1182.                         });
  1183.                 }
  1184.                 /**
  1185.                  * Slugifie un texte côté client. DOIT produire EXACTEMENT le même slug
  1186.                  * que la méthode PHP slugify() du JobsController et que le filtre Twig
  1187.                  * utilisé pour rendre les chips.
  1188.                  */
  1189.                 function slugify(text){
  1190.                     if(!text) return '';
  1191.                     var t = String(text);
  1192.                     // Pré-remplacements sémantiques
  1193.                     t = t.replace(/&/g, '-and-').replace(/\\+/g, '-plus-')
  1194.                         .replace(/[œŒ]/g, 'oe').replace(/[æÆ]/g, 'ae');
  1195.                     // Translitération accents → ASCII via NFD + strip diacritics
  1196.                     t = t.normalize ? t.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '') : t;
  1197.                     t = t.toLowerCase();
  1198.                     // Tout ce qui n'est pas a-z 0-9 → tiret
  1199.                     t = t.replace(/[^a-z0-9]+/g, '-');
  1200.                     return t.replace(/^-+|-+\$/g, '');
  1201.                 }
  1202.                 /**
  1203.                  * Tente de matcher un texte tapé avec un keyword en BDD (par slug ou label).
  1204.                  * Retourne l'objet keyword si trouvé, null sinon.
  1205.                  */
  1206.                 function findMatchingKeyword(text){
  1207.                     if(!text || !KEYWORDS_DATA || !KEYWORDS_DATA.length) return null;
  1208.                     var slug = slugify(text);
  1209.                     if(!slug) return null;
  1210.                     for(var i = 0; i < KEYWORDS_DATA.length; i++){
  1211.                         var kw = KEYWORDS_DATA[i];
  1212.                         // Match sur slug exact OU label/searchKeyword exact (case insensitive)
  1213.                         if(kw.slug === slug) return kw;
  1214.                         if(slugify(kw.searchKeyword) === slug) return kw;
  1215.                     }
  1216.                     return null;
  1217.                 }
  1218.                 /**
  1219.                  * Au submit : décide où rediriger l'utilisateur en fonction du contexte.
  1220.                  *  - Si on est sur une ville et le texte matche un keyword BDD → /jobs/{ville}/{slug-kw}
  1221.                  *  - Sinon si on est sur une ville → /jobs/{ville}?search={texte}
  1222.                  *  - Sinon (pas de ville) → /jobs?q={texte}
  1223.                  *  - Si texte vide ET ville définie → /jobs/{ville} (reset)
  1224.                  *  - Si texte vide ET pas de ville → /jobs (reset)
  1225.                  */
  1226.                 function submitSearch(query){
  1227.                     query = (query || '').trim();
  1228.                     // Reset (recherche vide)
  1229.                     if(!query){
  1230.                         if(CITY_SLUG && CITY_LANDING_URL_TEMPLATE){
  1231.                             window.location.href = CITY_LANDING_URL_TEMPLATE;
  1232.                         } else {
  1233.                             window.location.href = DASHBOARD_URL;
  1234.                         }
  1235.                         return;
  1236.                     }
  1237.                     // Cas 1 : on est sur une ville
  1238.                     if(CITY_SLUG && CITY_KEYWORD_URL_TEMPLATE){
  1239.                         var matched = findMatchingKeyword(query);
  1240.                         if(matched && matched.slug){
  1241.                             // Match BDD → URL slug propre /jobs/paris/developpeur
  1242.                             window.location.href = CITY_KEYWORD_URL_TEMPLATE.replace('kwplaceholder', encodeURIComponent(matched.slug));
  1243.                             return;
  1244.                         }
  1245.                         // Pas de match → fallback ?search=texte
  1246.                         window.location.href = CITY_LANDING_URL_TEMPLATE + '?search=' + encodeURIComponent(query);
  1247.                         return;
  1248.                     }
  1249.                     // Cas 2 : pas de ville → dashboard global avec ?q=
  1250.                     window.location.href = DASHBOARD_URL + '?q=' + encodeURIComponent(query);
  1251.                 }
  1252.                 /**
  1253.                  * Lance la search côté UI (sans redirection — utilisée pour les chips et
  1254.                  * pour la \"Charger plus\").
  1255.                  */
  1256.                 function startSearch(query){
  1257.                     currentQuery = query;
  1258.                     currentOffset = 0;
  1259.                     currentTotal = 0;
  1260.                     fetchJobs(query, 0, false);
  1261.                     // Update clear button
  1262.                     if(clearBtn){
  1263.                         if(query) clearBtn.classList.add('visible');
  1264.                         else clearBtn.classList.remove('visible');
  1265.                     }
  1266.                     // Update active chip (uniquement les chips qui sont des <button>, pas les <a>)
  1267.                     document.querySelectorAll('button.search-keyword-chip').forEach(function(c){
  1268.                         if(c.getAttribute('data-keyword') === query) c.classList.add('active');
  1269.                         else c.classList.remove('active');
  1270.                     });
  1271.                 }
  1272.                 // ═══ Submit-only : Entrée déclenche la search ET change l'URL ═══
  1273.                 if(input){
  1274.                     input.addEventListener('keydown', function(e){
  1275.                         if(e.key === 'Enter' || e.keyCode === 13){
  1276.                             e.preventDefault();
  1277.                             submitSearch(input.value);
  1278.                         }
  1279.                     });
  1280.                     // Affiche bouton clear si query initiale
  1281.                     if(input.value.trim()){
  1282.                         if(clearBtn) clearBtn.classList.add('visible');
  1283.                     }
  1284.                 }
  1285.                 // Bouton clear : reset complet → redirection vers /jobs ou /jobs/{ville}
  1286.                 if(clearBtn){
  1287.                     clearBtn.addEventListener('click', function(){
  1288.                         submitSearch('');
  1289.                     });
  1290.                 }
  1291.                 // Chips keywords (cas dashboard global, sans contexte ville → comportement local)
  1292.                 // En contexte ville, les chips sont des <a href> directs gérés par le navigateur.
  1293.                 document.querySelectorAll('button.search-keyword-chip').forEach(function(chip){
  1294.                     chip.addEventListener('click', function(){
  1295.                         var kw = chip.getAttribute('data-keyword');
  1296.                         if(!kw) return;
  1297.                         // Sur dashboard global : on submit (redirige vers /jobs?q=kw)
  1298.                         submitSearch(kw);
  1299.                     });
  1300.                 });
  1301.                 // Bouton \"Charger plus\"
  1302.                 if(loadMoreBtn){
  1303.                     loadMoreBtn.addEventListener('click', function(){
  1304.                         if(isFetching) return;
  1305.                         fetchJobs(currentQuery, currentOffset, true);
  1306.                     });
  1307.                 }
  1308.                 // ═══ Bouton \"Voir plus\" + Recherche live des chips ═══
  1309.                 /**
  1310.                  * Slugify simple côté UI pour matching tolérant aux accents
  1311.                  * (ex: \"developpeur\" matche \"Développeur\")
  1312.                  */
  1313.                 function dashSlug(str){
  1314.                     if(!str) return '';
  1315.                     var t = String(str);
  1316.                     t = t.normalize ? t.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '') : t;
  1317.                     return t.toLowerCase().trim();
  1318.                 }
  1319.                 document.querySelectorAll('.dash-filter-more-btn').forEach(function(btn){
  1320.                     var targetId = btn.getAttribute('data-target');
  1321.                     var sectionId = btn.getAttribute('data-section');
  1322.                     var container = document.getElementById(targetId);
  1323.                     var section = sectionId ? document.getElementById(sectionId) : null;
  1324.                     if(!container) return;
  1325.                     var label = btn.querySelector('.dash-filter-more-label');
  1326.                     if(!label) return;
  1327.                     var initial = parseInt(container.getAttribute('data-initial'), 10) || 14;
  1328.                     var items = container.querySelectorAll('.dash-filter-item');
  1329.                     var searchInput = section ? section.querySelector('.dash-filter-search-input') : null;
  1330.                     // 2 états indépendants :
  1331.                     //  - userExpanded : l'utilisateur a cliqué sur \"Voir plus\"
  1332.                     //  - searchActive : l'input contient du texte (auto-expand temporaire)
  1333.                     // Mode développé = userExpanded || searchActive
  1334.                     var userExpanded = false;
  1335.                     function isEffectivelyExpanded(){
  1336.                         var hasSearch = searchInput && searchInput.value.trim().length > 0;
  1337.                         return userExpanded || hasSearch;
  1338.                     }
  1339.                     function applyDisplay(){
  1340.                         var filterText = searchInput ? searchInput.value : '';
  1341.                         var query = dashSlug(filterText || '');
  1342.                         var expanded = isEffectivelyExpanded();
  1343.                         var visibleCount = 0;
  1344.                         items.forEach(function(it, i){
  1345.                             var label = it.getAttribute('data-filter-label') || '';
  1346.                             var matches = !query || dashSlug(label).indexOf(query) !== -1;
  1347.                             if(expanded){
  1348.                                 // Mode développé : on affiche tous les items qui matchent la recherche
  1349.                                 it.style.display = matches ? '' : 'none';
  1350.                                 if(matches) visibleCount++;
  1351.                             } else {
  1352.                                 // Mode collapsé : on affiche les N premiers (pas de filtrage)
  1353.                                 it.style.display = (i < initial) ? '' : 'none';
  1354.                                 if(i < initial) visibleCount++;
  1355.                             }
  1356.                         });
  1357.                         // Toggle \"aucun résultat\" (uniquement quand recherche active)
  1358.                         if(query && visibleCount === 0){
  1359.                             container.classList.add('is-no-results');
  1360.                         } else {
  1361.                             container.classList.remove('is-no-results');
  1362.                         }
  1363.                         // Synchroniser le bouton \"Voir plus/moins\" avec l'état effectif
  1364.                         if(expanded){
  1365.                             btn.classList.add('is-expanded');
  1366.                             label.textContent = label.getAttribute('data-less');
  1367.                         } else {
  1368.                             btn.classList.remove('is-expanded');
  1369.                             label.textContent = label.getAttribute('data-more');
  1370.                         }
  1371.                     }
  1372.                     btn.addEventListener('click', function(){
  1373.                         userExpanded = !userExpanded;
  1374.                         if(!userExpanded){
  1375.                             // Reset input quand l'utilisateur collapse manuellement
  1376.                             if(searchInput){ searchInput.value = ''; }
  1377.                             // Scroll vers le bouton
  1378.                             btn.scrollIntoView({behavior:'smooth', block:'nearest'});
  1379.                         }
  1380.                         applyDisplay();
  1381.                     });
  1382.                     // Recherche live dans les chips quand on tape dans l'input
  1383.                     // → auto-expand pendant la recherche, retour à l'état userExpanded quand on vide
  1384.                     if(searchInput){
  1385.                         searchInput.addEventListener('input', function(){
  1386.                             applyDisplay();
  1387.                         });
  1388.                     }
  1389.                 });
  1390.                 // Premier chargement (vide ou avec query initiale)
  1391.                 fetchJobs(currentQuery, 0, false);
  1392.             } catch(err){
  1393.                 console.error('[whr-dash] init error', err);
  1394.             }
  1395.         })();
  1396.     </script>
  1397. ";
  1398.         
  1399.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  1400.         
  1401.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  1402.         yield from [];
  1403.     }
  1404.     /**
  1405.      * @codeCoverageIgnore
  1406.      */
  1407.     public function getTemplateName(): string
  1408.     {
  1409.         return "application/whileresume/application/jobs/dashboard.html.twig";
  1410.     }
  1411.     /**
  1412.      * @codeCoverageIgnore
  1413.      */
  1414.     public function isTraitable(): bool
  1415.     {
  1416.         return false;
  1417.     }
  1418.     /**
  1419.      * @codeCoverageIgnore
  1420.      */
  1421.     public function getDebugInfo(): array
  1422.     {
  1423.         return array (  1250 => 621,  1226 => 600,  1196 => 573,  1177 => 557,  1170 => 553,  1158 => 544,  1154 => 543,  1079 => 470,  1065 => 469,  1054 => 468,  1051 => 446,  1034 => 445,  1028 => 441,  1026 => 440,  1025 => 439,  1024 => 438,  1023 => 437,  1020 => 436,  1018 => 435,  1017 => 434,  1016 => 433,  1015 => 432,  1009 => 429,  1003 => 426,  997 => 423,  988 => 417,  982 => 414,  978 => 413,  973 => 411,  969 => 410,  962 => 405,  949 => 404,  936 => 400,  932 => 398,  930 => 397,  929 => 395,  927 => 393,  924 => 392,  918 => 386,  914 => 384,  909 => 380,  896 => 372,  892 => 371,  888 => 369,  882 => 365,  879 => 364,  876 => 362,  872 => 360,  861 => 356,  854 => 351,  852 => 350,  846 => 348,  825 => 342,  819 => 341,  811 => 340,  807 => 339,  803 => 338,  797 => 337,  788 => 336,  771 => 335,  767 => 334,  764 => 333,  757 => 329,  748 => 322,  745 => 321,  740 => 318,  732 => 312,  729 => 311,  726 => 310,  723 => 308,  719 => 306,  708 => 302,  701 => 297,  699 => 296,  693 => 294,  672 => 288,  666 => 287,  658 => 286,  654 => 285,  650 => 284,  644 => 283,  635 => 282,  618 => 281,  614 => 280,  611 => 279,  604 => 275,  595 => 268,  592 => 267,  587 => 264,  579 => 258,  576 => 257,  573 => 256,  570 => 254,  566 => 252,  560 => 251,  553 => 248,  547 => 247,  543 => 246,  539 => 244,  537 => 243,  530 => 240,  524 => 239,  518 => 238,  509 => 237,  507 => 236,  505 => 235,  502 => 234,  499 => 211,  497 => 210,  493 => 209,  489 => 208,  486 => 207,  483 => 206,  473 => 198,  468 => 196,  460 => 195,  452 => 189,  448 => 186,  441 => 182,  436 => 180,  427 => 178,  421 => 176,  415 => 175,  410 => 173,  407 => 172,  404 => 171,  401 => 169,  396 => 167,  391 => 166,  388 => 165,  382 => 163,  376 => 161,  374 => 160,  365 => 158,  362 => 157,  360 => 156,  356 => 155,  343 => 153,  340 => 152,  338 => 151,  336 => 150,  331 => 147,  318 => 146,  304 => 143,  172 => 12,  159 => 11,  136 => 9,  103 => 8,  71 => 7,  60 => 1,  58 => 5,  45 => 1,);
  1424.     }
  1425.     public function getSourceContext(): Source
  1426.     {
  1427.         return new Source("{% extends 'application/whileresume/application/jobs/layout-social.html.twig' %}
  1428. {% trans_default_domain 'whr-public' %}
  1429. {% import 'application/whileresume/_macros/promo_card.html.twig' as promo %}
  1430. {% block title %}{% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %}{{ currentSubKeyword }} {{ currentCityFilter.label }}{% elseif currentFilter is defined and currentFilter is not null %}{{ currentFilter.shortTitle|default(currentFilter.label) }} — WhileResume{% else %}{{ 'job.dashboard.title'|trans }}{% endif %}{% endblock title %}
  1431. {% block description %}{% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %}Découvrez les offres \"{{ currentSubKeyword }}\" à {{ currentCityFilter.label }}.{% elseif currentFilter is defined and currentFilter is not null and currentFilter.shortDescription is not empty %}{{ currentFilter.shortDescription }}{% else %}{{ 'job.dashboard.description'|trans }}{% endif %}{% endblock description %}
  1432. {% block robots %}index,follow{% endblock robots %}
  1433. {% block css %}
  1434.     <style>
  1435.         /* ─── Page dashboard /jobs ─── */
  1436.         .jobs-dash{max-width:880px;margin:0 auto}
  1437.         .jobs-dash-header{margin-bottom:18px}
  1438.         .jobs-dash-title{font-size:24px;font-weight:800;color:#1E1B2E;line-height:1.2;letter-spacing:-0.02em;margin:0 0 6px}
  1439.         @media(min-width:768px){.jobs-dash-title{font-size:28px}}
  1440.         .jobs-dash-subtitle{font-size:14px;color:#6B7280;margin:0 0 18px}
  1441.         /* ─── Bandeau contexte ville (badge + bouton ALL) ─── */
  1442.         .city-context-bar{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 16px;padding:10px 14px;background:#F5F3FF;border:1px solid rgba(108,58,237,.15);border-radius:12px}
  1443.         .city-context-label{font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:.06em}
  1444.         .city-context-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:100px;background:#fff;color:var(--theme-color,#6C3AED);font-size:13px;font-weight:600;border:1px solid rgba(108,58,237,.2)}
  1445.         .city-context-badge-icon{font-size:14px;line-height:1}
  1446.         .city-context-clear-btn{margin-left:auto;display:inline-flex;align-items:center;gap:4px;padding:5px 12px;border-radius:100px;background:transparent;color:var(--theme-color,#6C3AED);font-size:12px;font-weight:600;border:1px dashed rgba(108,58,237,.4);cursor:pointer;text-decoration:none;font-family:inherit;transition:background .15s,border-style .15s,border-color .15s}
  1447.         .city-context-clear-btn:hover{background:#fff;border-style:solid;border-color:var(--theme-color,#6C3AED);color:var(--theme-color,#6C3AED)}
  1448.         .city-context-clear-btn svg{width:11px;height:11px}
  1449.         /* Widget recherche */
  1450.         .wr-search-widget{background:#fff;border-radius:14px;box-shadow:0 0 20px 0 rgba(0,0,0,0.05);padding:10px;margin-bottom:14px;position:relative;z-index:50}
  1451.         .wr-search-input-wrap{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:10px;background:#F9FAFB;border:1px solid #E5E7EB;transition:border-color .2s,background .2s}
  1452.         .wr-search-input-wrap:focus-within{border-color:rgba(108,58,237,.3);background:#fff}
  1453.         .wr-search-icon{color:#9CA3AF;display:flex;flex-shrink:0}
  1454.         .wr-search-input{flex:1;border:none;outline:none;background:transparent;font-size:14px;color:#1E1B2E;padding:4px 0;font-family:inherit;min-width:0}
  1455.         .wr-search-input::placeholder{color:#9CA3AF}
  1456.         .wr-search-clear{background:none;border:none;color:#9CA3AF;cursor:pointer;padding:4px;display:none;font-family:inherit}
  1457.         .wr-search-clear.visible{display:flex;align-items:center}
  1458.         .wr-search-clear:hover{color:#6B7280}
  1459.         .wr-search-clear svg{width:14px;height:14px}
  1460.         .wr-search-kbd-hint{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:#6B7280;font-family:inherit;letter-spacing:.02em;white-space:nowrap;flex-shrink:0}
  1461.         .wr-search-input-wrap:focus-within .wr-search-kbd-hint{display:inline-flex}
  1462.         /* Chips keywords */
  1463.         .search-keywords{display:flex;flex-wrap:wrap;gap:6px;margin:0 4px 18px}
  1464.         .search-keyword-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:100px;background:#F5F3FF;color:var(--theme-color,#6C3AED);font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,transform .15s;font-family:inherit}
  1465.         .search-keyword-chip:hover{background:#EDE9FE;border-color:rgba(108,58,237,.2);transform:translateY(-1px);color:var(--theme-color,#6C3AED)}
  1466.         .search-keyword-chip.active{background:var(--theme-color,#6C3AED);color:#fff;border-color:var(--theme-color,#6C3AED)}
  1467.         .search-keyword-chip-icon{font-size:13px;line-height:1}
  1468.         .search-keywords-label{font-size:11px;font-weight:600;color:#9CA3AF;text-transform:uppercase;letter-spacing:.06em;margin-right:4px;align-self:center}
  1469.         /* ─── Sections de filtres SEO (chips → liens directs vers /jobs/{slug}) ─── */
  1470.         .filter-section{margin:0 0 14px}
  1471.         .filter-section-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;padding:0 4px;flex-wrap:wrap}
  1472.         @media(max-width:540px){
  1473.             .dash-filter-search{max-width:100%;width:100%}
  1474.         }
  1475.         .filter-section-title{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;color:#6B7280;text-transform:uppercase;letter-spacing:.06em;margin:0}
  1476.         .filter-section-title-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:#F5F3FF;color:var(--theme-color,#6C3AED)}
  1477.         .filter-section-title-icon svg{width:11px;height:11px}
  1478.         .filter-section-toggle{background:none;border:none;font-size:11px;color:var(--theme-color,#6C3AED);font-weight:600;cursor:pointer;font-family:inherit;padding:4px 8px;border-radius:6px;transition:background .15s}
  1479.         .filter-section-toggle:hover{background:#F5F3FF}
  1480.         .filter-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 4px}
  1481.         .filter-chip{display:inline-flex;align-items:center;gap:5px;padding:7px 13px;border-radius:100px;background:#fff;color:#374151;font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid #E5E7EB;text-decoration:none;transition:background .15s,border-color .15s,transform .15s,color .15s;font-family:inherit;white-space:nowrap}
  1482.         .filter-chip:hover{background:#F5F3FF;border-color:rgba(108,58,237,.3);color:var(--theme-color,#6C3AED);transform:translateY(-1px)}
  1483.         .filter-chip.active{background:var(--theme-color,#6C3AED);border-color:var(--theme-color,#6C3AED);color:#fff}
  1484.         .filter-chip.active:hover{background:#5B21B6;color:#fff}
  1485.         .filter-chip-icon{font-size:14px;line-height:1}
  1486.         .filter-chip-arrow{display:inline-flex;color:currentColor;opacity:.5;margin-left:2px}
  1487.         .filter-chip-arrow svg{width:10px;height:10px}
  1488.         /* Mode \"compact\" : sections initialement collapsées si > 6 items */
  1489.         .filter-chips.collapsed{max-height:80px;overflow:hidden;position:relative}
  1490.         .filter-chips.collapsed::after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:30px;background:linear-gradient(to bottom,transparent,#FAFAFA);pointer-events:none}
  1491.         /* ─── Bouton \"Voir plus\" sous les chips villes/métiers ─── */
  1492.         .dash-filter-more-wrap{display:flex;justify-content:center;margin-top:10px;padding:0 4px}
  1493.         .dash-filter-more-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;background:transparent;color:var(--theme-color,#6C3AED);border:1px dashed rgba(108,58,237,.35);border-radius:100px;font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;transition:background .15s,border-style .15s,border-color .15s}
  1494.         .dash-filter-more-btn:hover{background:#F5F3FF;border-style:solid;border-color:var(--theme-color,#6C3AED)}
  1495.         .dash-filter-more-icon{display:inline-flex;align-items:center;color:currentColor;transition:transform .2s}
  1496.         .dash-filter-more-icon svg{width:12px;height:12px}
  1497.         .dash-filter-more-btn.is-expanded .dash-filter-more-icon{transform:rotate(180deg)}
  1498.         /* ─── Input de recherche dans le header (toujours visible) ─── */
  1499.         .dash-filter-search{display:block;position:relative;flex:1;max-width:240px}
  1500.         @keyframes dashFilterFadeIn{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}
  1501.         .dash-filter-search-input{width:100%;padding:5px 10px 5px 28px;border:1px solid #E5E7EB;border-radius:100px;font-size:12px;color:#1E1B2E;background:#FAFAFA;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s,background .15s}
  1502.         .dash-filter-search-input:focus{border-color:rgba(108,58,237,.4);background:#fff}
  1503.         .dash-filter-search-input::placeholder{color:#9CA3AF}
  1504.         .dash-filter-search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;pointer-events:none;display:flex}
  1505.         .dash-filter-search-icon svg{width:11px;height:11px}
  1506.         /* État \"aucun résultat\" sous le filtre live */
  1507.         .dash-filter-empty{display:none;padding:14px 12px;font-size:12.5px;color:#9CA3AF;font-style:italic;text-align:center;width:100%}
  1508.         .filter-chips.is-no-results .dash-filter-empty{display:block}
  1509.         /* Bandeau résultats */
  1510.         .jobs-results-info{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 4px 14px;font-size:12px;color:#6B7280}
  1511.         .jobs-results-info strong{color:#1E1B2E;font-weight:700}
  1512.         /* Liste cards (style \"similar-card\" comme dans show.html.twig) */
  1513.         .jobs-list{display:flex;flex-direction:column;gap:10px}
  1514.         .jobs-card{background:#fff;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}
  1515.         .jobs-card:hover{transform:translateY(-1px);box-shadow:0 4px 20px rgba(108,58,237,.1);color:inherit}
  1516.         .jobs-card-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(135deg,#EDE9FE,#DDD6FE);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:20px;color:var(--theme-color,#6C3AED);flex-shrink:0;overflow:hidden}
  1517.         .jobs-card-logo img{width:100%;height:100%;object-fit:cover;border-radius:8px}
  1518.         .jobs-card-logo svg{width:24px;height:24px;opacity:.85}
  1519.         .jobs-card-info{flex:1;min-width:0}
  1520.         .jobs-card-title{font-size:14px;font-weight:700;color:#1E1B2E;line-height:1.3;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  1521.         .jobs-card-meta{font-size:12px;color:#6B7280;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  1522.         .jobs-card-salary{font-size:11px;font-weight:600;color:var(--theme-color,#6C3AED);background:#F5F3FF;padding:3px 9px;border-radius:100px;white-space:nowrap;flex-shrink:0}
  1523.         .jobs-card-arrow{flex-shrink:0;color:#9CA3AF;transition:color .15s,transform .15s}
  1524.         .jobs-card:hover .jobs-card-arrow{color:var(--theme-color,#6C3AED);transform:translateX(2px)}
  1525.         .jobs-card-arrow svg{width:18px;height:18px}
  1526.         /* Skeleton (pendant chargement) */
  1527.         .jobs-skeleton{display:flex;flex-direction:column;gap:10px}
  1528.         .jobs-skel-card{background:#fff;border-radius:14px;padding:14px;display:flex;align-items:center;gap:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)}
  1529.         .jobs-skel-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;flex-shrink:0}
  1530.         .jobs-skel-info{flex:1}
  1531.         .jobs-skel-line{height:14px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;border-radius:4px;margin-bottom:6px}
  1532.         .jobs-skel-line.s1{width:60%}
  1533.         .jobs-skel-line.s2{width:40%;height:12px;margin-bottom:0}
  1534.         @keyframes jobsSkelShim{0%{background-position:200% 0}100%{background-position:-200% 0}}
  1535.         /* Bouton charger plus */
  1536.         .jobs-load-more{display:flex;width:100%;padding:14px;margin-top:16px;background:#fff;color:var(--theme-color,#6C3AED);border:1.5px dashed rgba(108,58,237,.35);border-radius:12px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:inherit;align-items:center;justify-content:center;gap:8px;transition:background .15s,border-color .15s}
  1537.         .jobs-load-more:hover{background:#F5F3FF;border-color:var(--theme-color,#6C3AED);border-style:solid;color:var(--theme-color,#6C3AED)}
  1538.         .jobs-load-more svg{width:14px;height:14px}
  1539.         .jobs-load-more:disabled{opacity:.6;cursor:not-allowed}
  1540.         .jobs-load-more.loading{cursor:wait}
  1541.         .jobs-load-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(108,58,237,.2);border-top-color:var(--theme-color,#6C3AED);border-radius:50%;animation:jobsLoadSpin .7s linear infinite}
  1542.         @keyframes jobsLoadSpin{to{transform:rotate(360deg)}}
  1543.         /* État vide */
  1544.         .jobs-empty{text-align:center;padding:40px 20px;background:#fff;border-radius:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)}
  1545.         .jobs-empty-icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:16px;background:#F5F3FF;color:var(--theme-color,#6C3AED);margin-bottom:14px}
  1546.         .jobs-empty-icon svg{width:24px;height:24px}
  1547.         .jobs-empty-title{font-size:16px;font-weight:700;color:#1E1B2E;margin:0 0 6px}
  1548.         .jobs-empty-text{font-size:13px;color:#6B7280;margin:0}
  1549.     </style>
  1550.     {# Styles partagés de la promo card (définis dans la macro) #}
  1551.     {{ promo.styles() }}
  1552. {% endblock css %}
  1553. {% block body %}
  1554.     <div class=\"jobs-dash\">
  1555.         <div class=\"jobs-dash-header\">
  1556.             {% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %}
  1557.                 {# Cas combiné : ville + keyword #}
  1558.                 <h1 class=\"jobs-dash-title\">
  1559.                     {% if currentCityFilter.icon is not empty %}{{ currentCityFilter.icon }} {% endif %}{{ currentSubKeyword }} {{ 'job.dashboard.cityHeadingIn'|trans }} {{ currentCityFilter.label }}
  1560.                 </h1>
  1561.                 <p class=\"jobs-dash-subtitle\">{{ 'job.dashboard.cityKeywordSubtitle'|trans({'%keyword%': currentSubKeyword, '%city%': currentCityFilter.label}) }}</p>
  1562.             {% elseif currentFilter is defined and currentFilter is not null %}
  1563.                 <h1 class=\"jobs-dash-title\">
  1564.                     {% if currentFilter.icon is not empty %}{{ currentFilter.icon }} {% endif %}{{ currentFilter.shortTitle|default(currentFilter.label) }}
  1565.                 </h1>
  1566.                 {% if currentFilter.shortDescription is not empty %}
  1567.                     <p class=\"jobs-dash-subtitle\">{{ currentFilter.shortDescription }}</p>
  1568.                 {% else %}
  1569.                     <p class=\"jobs-dash-subtitle\">{{ 'job.dashboard.subtitle'|trans }}</p>
  1570.                 {% endif %}
  1571.             {% else %}
  1572.                 <h1 class=\"jobs-dash-title\">{{ 'job.dashboard.heading'|trans }}</h1>
  1573.                 <p class=\"jobs-dash-subtitle\">{{ 'job.dashboard.subtitle'|trans }}</p>
  1574.             {% endif %}
  1575.             {# Badge \"Ville active\" + bouton \"Tout voir\" / ALL pour reset #}
  1576.             {% if currentCityFilter is defined and currentCityFilter is not null %}
  1577.                 <div class=\"city-context-bar\">
  1578.                     <span class=\"city-context-label\">{{ 'job.dashboard.contextLabel'|trans }}</span>
  1579.                     <span class=\"city-context-badge\">
  1580.                         {% if currentCityFilter.icon is not empty %}<span class=\"city-context-badge-icon\">{{ currentCityFilter.icon }}</span>{% endif %}
  1581.                         <span>{{ currentCityFilter.label }}</span>
  1582.                     </span>
  1583.                     <a href=\"{% if app.request.locale == 'en' %}{{ path('whileresume_jobs_list') }}{% else %}{{ path('locale_whileresume_jobs_list',{'_locale':app.request.locale}) }}{% endif %}\"
  1584.                        class=\"city-context-clear-btn\"
  1585.                        title=\"{{ 'job.dashboard.clearCity'|trans }}\">
  1586.                         <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\" transform=\"rotate(180 12 12)\"/></svg>
  1587.                         {{ 'job.dashboard.allCities'|trans }}
  1588.                     </a>
  1589.                 </div>
  1590.             {% endif %}
  1591.         </div>
  1592.         {# ═══ Widget recherche ═══ #}
  1593.         <div class=\"wr-search-widget\">
  1594.             <div class=\"wr-search-input-wrap\">
  1595.                 <span class=\"wr-search-icon\">
  1596.                     <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  1597.                 </span>
  1598.                 <input type=\"text\" id=\"dashSearchInput\" class=\"wr-search-input\"
  1599.                        placeholder=\"{% if currentCityFilter is defined and currentCityFilter is not null %}{{ 'job.dashboard.searchInCity'|trans({'%city%': currentCityFilter.label}) }}{% else %}{{ 'job.show.searchPlaceholder'|trans }}{% endif %}\"
  1600.                        value=\"{{ initialQuery|default('') }}\"
  1601.                        autocomplete=\"off\">
  1602.                 <span class=\"wr-search-kbd-hint\" id=\"dashSearchKbdHint\">{{ 'job.dashboard.pressEnter'|trans }}</span>
  1603.                 <button type=\"button\" id=\"dashSearchClear\" class=\"wr-search-clear\" aria-label=\"Clear\">
  1604.                     <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>
  1605.                 </button>
  1606.             </div>
  1607.         </div>
  1608.         {# Chips keywords cliquables #}
  1609.         {% if searchKeywords is defined and searchKeywords|length > 0 %}
  1610.             <div class=\"search-keywords\">
  1611.                 <span class=\"search-keywords-label\">{{ 'job.show.keywordsLabel'|trans }}</span>
  1612.                 {% for kw in searchKeywords %}
  1613.                     {# Slug pour l'URL : translitération des accents FR + lowercase + remplacement caractères spéciaux #}
  1614.                     {% set kwSlug = kw.label
  1615.                         |replace({
  1616.                         'à':'a','â':'a','ä':'a','á':'a','ã':'a','å':'a',
  1617.                         'À':'a','Â':'a','Ä':'a','Á':'a','Ã':'a','Å':'a',
  1618.                         'é':'e','è':'e','ê':'e','ë':'e','ẽ':'e',
  1619.                         'É':'e','È':'e','Ê':'e','Ë':'e',
  1620.                         'î':'i','ï':'i','ì':'i','í':'i',
  1621.                         'Î':'i','Ï':'i','Ì':'i','Í':'i',
  1622.                         'ô':'o','ö':'o','ò':'o','ó':'o','õ':'o','ø':'o',
  1623.                         'Ô':'o','Ö':'o','Ò':'o','Ó':'o','Õ':'o','Ø':'o',
  1624.                         'û':'u','ü':'u','ù':'u','ú':'u',
  1625.                         'Û':'u','Ü':'u','Ù':'u','Ú':'u',
  1626.                         'ÿ':'y','ý':'y','Ÿ':'y','Ý':'y',
  1627.                         'ç':'c','Ç':'c',
  1628.                         'ñ':'n','Ñ':'n',
  1629.                         'œ':'oe','Œ':'oe','æ':'ae','Æ':'ae',
  1630.                         \"'\":'-',' ':'-','/':'-','_':'-','.':'-',',':'-',
  1631.                         '(':'','*':'',')':'','&':'-and-','+':'-plus-',
  1632.                         '#':'','?':'','!':'','\"':'','’':'-','`':'-'
  1633.                     })
  1634.                         |lower
  1635.                         |replace({'--':'-','---':'-'})
  1636.                         |trim('-') %}
  1637.                     {% if currentCityFilter is defined and currentCityFilter is not null %}
  1638.                         {# Contexte ville : chip = lien vers /jobs/ville/keyword #}
  1639.                         <a href=\"{% if app.request.locale == 'en' %}{{ path('cvs_application_jobs_filter_keyword',{'slug':currentCityFilter.slug,'keyword':kwSlug}) }}{% else %}{{ path('locale_cvs_application_jobs_filter_keyword',{'_locale':app.request.locale,'slug':currentCityFilter.slug,'keyword':kwSlug}) }}{% endif %}\"
  1640.                            class=\"search-keyword-chip{% if currentSubKeywordSlug is defined and currentSubKeywordSlug == kwSlug %} active{% endif %}\">
  1641.                             {% if kw.icon is not empty %}<span class=\"search-keyword-chip-icon\">{{ kw.icon }}</span>{% endif %}
  1642.                             <span>{{ kw.label }}</span>
  1643.                         </a>
  1644.                     {% else %}
  1645.                         {# Pas de contexte ville : chip pré-remplit la search (comportement existant) #}
  1646.                         <button type=\"button\"
  1647.                                 class=\"search-keyword-chip\"
  1648.                                 data-keyword=\"{{ kw.searchKeyword|default(kw.label) }}\">
  1649.                             {% if kw.icon is not empty %}<span class=\"search-keyword-chip-icon\">{{ kw.icon }}</span>{% endif %}
  1650.                             <span>{{ kw.label }}</span>
  1651.                         </button>
  1652.                     {% endif %}
  1653.                 {% endfor %}
  1654.             </div>
  1655.         {% endif %}
  1656.         {# ═══ Filtres SEO : Villes (chips → /jobs/{slug}) — 14 visibles + reste cliqué pour révéler ═══ #}
  1657.         {% if sidebarFiltersCities is defined and sidebarFiltersCities|length > 0 %}
  1658.             {% set citiesInitial = 14 %}
  1659.             <div class=\"filter-section\" id=\"filterSectionCities\">
  1660.                 <div class=\"filter-section-head\">
  1661.                     <h3 class=\"filter-section-title\">
  1662.                         <span class=\"filter-section-title-icon\">
  1663.                             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>
  1664.                         </span>
  1665.                         {{ 'job.dashboard.popularCities'|trans }}
  1666.                     </h3>
  1667.                     {# Input de recherche (visible uniquement quand expanded) #}
  1668.                     {% if sidebarFiltersCities|length > citiesInitial %}
  1669.                         <div class=\"dash-filter-search\">
  1670.                             <span class=\"dash-filter-search-icon\">
  1671.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  1672.                             </span>
  1673.                             <input type=\"text\"
  1674.                                    class=\"dash-filter-search-input\"
  1675.                                    data-search-target=\"filterChipsCities\"
  1676.                                    placeholder=\"{{ 'job.dashboard.filterSearchCity'|trans }}\"
  1677.                                    autocomplete=\"off\">
  1678.                         </div>
  1679.                     {% endif %}
  1680.                 </div>
  1681.                 <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCities\" data-initial=\"{{ citiesInitial }}\">
  1682.                     {% for f in sidebarFiltersCities %}
  1683.                         <a href=\"{% if app.request.locale == 'en' %}{{ path('cvs_application_jobs_filter',{'slug':f.slug}) }}{% else %}{{ path('locale_cvs_application_jobs_filter',{'_locale':app.request.locale,'slug':f.slug}) }}{% endif %}\"
  1684.                            class=\"filter-chip dash-filter-item{% if currentFilter is defined and currentFilter is not null and currentFilter.slug == f.slug %} active{% endif %}\"
  1685.                            data-filter-slug=\"{{ f.slug }}\"
  1686.                            data-filter-label=\"{{ f.label }}\"
  1687.                            data-index=\"{{ loop.index0 }}\"{% if loop.index0 >= citiesInitial %} style=\"display:none\"{% endif %}>
  1688.                             {% if f.icon is not empty %}<span class=\"filter-chip-icon\">{{ f.icon }}</span>{% endif %}
  1689.                             <span>{{ f.label }}</span>
  1690.                             <span class=\"filter-chip-arrow\">
  1691.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg>
  1692.                             </span>
  1693.                         </a>
  1694.                     {% endfor %}
  1695.                     <div class=\"dash-filter-empty\">{{ 'job.dashboard.filterNoResults'|trans }}</div>
  1696.                 </div>
  1697.                 {% if sidebarFiltersCities|length > citiesInitial %}
  1698.                     <div class=\"dash-filter-more-wrap\">
  1699.                         <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCities\" data-section=\"filterSectionCities\">
  1700.                             <span class=\"dash-filter-more-icon\">
  1701.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  1702.                             </span>
  1703.                             <span class=\"dash-filter-more-label\" data-more=\"{{ 'job.dashboard.showMoreCities'|trans({'%n%': sidebarFiltersCities|length - citiesInitial}) }}\" data-less=\"{{ 'job.dashboard.showLessCities'|trans }}\">{{ 'job.dashboard.showMoreCities'|trans({'%n%': sidebarFiltersCities|length - citiesInitial}) }}</span>
  1704.                         </button>
  1705.                     </div>
  1706.                 {% endif %}
  1707.             </div>
  1708.         {% endif %}
  1709.         {# ═══ Filtres SEO : Métiers (chips → /jobs/{slug}) — 8 visibles + reste cliqué pour révéler ═══ #}
  1710.         {% if sidebarFiltersCategories is defined and sidebarFiltersCategories|length > 0 %}
  1711.             {% set categoriesInitial = 8 %}
  1712.             <div class=\"filter-section\" id=\"filterSectionCategories\">
  1713.                 <div class=\"filter-section-head\">
  1714.                     <h3 class=\"filter-section-title\">
  1715.                         <span class=\"filter-section-title-icon\">
  1716.                             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\"/><path d=\"M16 7V5a4 4 0 00-8 0v2\"/></svg>
  1717.                         </span>
  1718.                         {{ 'job.dashboard.popularCategories'|trans }}
  1719.                     </h3>
  1720.                     {# Input de recherche (visible uniquement quand expanded) #}
  1721.                     {% if sidebarFiltersCategories|length > categoriesInitial %}
  1722.                         <div class=\"dash-filter-search\">
  1723.                             <span class=\"dash-filter-search-icon\">
  1724.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>
  1725.                             </span>
  1726.                             <input type=\"text\"
  1727.                                    class=\"dash-filter-search-input\"
  1728.                                    data-search-target=\"filterChipsCategories\"
  1729.                                    placeholder=\"{{ 'job.dashboard.filterSearchCategory'|trans }}\"
  1730.                                    autocomplete=\"off\">
  1731.                         </div>
  1732.                     {% endif %}
  1733.                 </div>
  1734.                 <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCategories\" data-initial=\"{{ categoriesInitial }}\">
  1735.                     {% for f in sidebarFiltersCategories %}
  1736.                         <a href=\"{% if app.request.locale == 'en' %}{{ path('cvs_application_jobs_filter',{'slug':f.slug}) }}{% else %}{{ path('locale_cvs_application_jobs_filter',{'_locale':app.request.locale,'slug':f.slug}) }}{% endif %}\"
  1737.                            class=\"filter-chip dash-filter-item{% if currentFilter is defined and currentFilter is not null and currentFilter.slug == f.slug %} active{% endif %}\"
  1738.                            data-filter-slug=\"{{ f.slug }}\"
  1739.                            data-filter-label=\"{{ f.label }}\"
  1740.                            data-index=\"{{ loop.index0 }}\"{% if loop.index0 >= categoriesInitial %} style=\"display:none\"{% endif %}>
  1741.                             {% if f.icon is not empty %}<span class=\"filter-chip-icon\">{{ f.icon }}</span>{% endif %}
  1742.                             <span>{{ f.label }}</span>
  1743.                             <span class=\"filter-chip-arrow\">
  1744.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg>
  1745.                             </span>
  1746.                         </a>
  1747.                     {% endfor %}
  1748.                     <div class=\"dash-filter-empty\">{{ 'job.dashboard.filterNoResults'|trans }}</div>
  1749.                 </div>
  1750.                 {% if sidebarFiltersCategories|length > categoriesInitial %}
  1751.                     <div class=\"dash-filter-more-wrap\">
  1752.                         <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCategories\" data-section=\"filterSectionCategories\">
  1753.                             <span class=\"dash-filter-more-icon\">
  1754.                                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  1755.                             </span>
  1756.                             <span class=\"dash-filter-more-label\" data-more=\"{{ 'job.dashboard.showMoreCategories'|trans({'%n%': sidebarFiltersCategories|length - categoriesInitial}) }}\" data-less=\"{{ 'job.dashboard.showLessCategories'|trans }}\">{{ 'job.dashboard.showMoreCategories'|trans({'%n%': sidebarFiltersCategories|length - categoriesInitial}) }}</span>
  1757.                         </button>
  1758.                     </div>
  1759.                 {% endif %}
  1760.             </div>
  1761.         {% endif %}
  1762.         {# Bandeau d'info (compteur de résultats) #}
  1763.         <div class=\"jobs-results-info\" id=\"jobsResultsInfo\">
  1764.             <span id=\"jobsResultsCount\">{{ 'job.dashboard.loading'|trans }}</span>
  1765.         </div>
  1766.         {# Liste des offres (peuplée en JS) #}
  1767.         <div class=\"jobs-list\" id=\"jobsList\">
  1768.             <div class=\"jobs-skeleton\">
  1769.                 {% for i in 1..5 %}
  1770.                     <div class=\"jobs-skel-card\">
  1771.                         <div class=\"jobs-skel-logo\"></div>
  1772.                         <div class=\"jobs-skel-info\">
  1773.                             <div class=\"jobs-skel-line s1\"></div>
  1774.                             <div class=\"jobs-skel-line s2\"></div>
  1775.                         </div>
  1776.                     </div>
  1777.                 {% endfor %}
  1778.             </div>
  1779.         </div>
  1780.         {# Bouton \"Charger plus\" #}
  1781.         <button type=\"button\" class=\"jobs-load-more\" id=\"jobsLoadMore\" style=\"display:none;\">
  1782.             <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg>
  1783.             <span id=\"jobsLoadMoreLabel\">{{ 'job.dashboard.loadMore'|trans }}</span>
  1784.         </button>
  1785.         {# Template HTML invisible cloné par le JS pour intercaler la promo card.
  1786.            Affiché uniquement aux utilisateurs non connectés via la logique JS.
  1787.            Les textes/bullets viennent automatiquement des clés job.show.promo* du YAML. #}
  1788.         {% if app.user is null %}
  1789.             {{ promo.card_template({
  1790.                 template_id: 'jobs-promo-card-template',
  1791.                 login_url: app.request.locale == 'en'
  1792.                 ? path('cvs_gestion_candidates_dashboard')
  1793.                 : path('locale_cvs_gestion_candidates_dashboard',{'_locale':app.request.locale})
  1794.             }) }}
  1795.         {% endif %}
  1796.     </div>
  1797. {% endblock body %}
  1798. {% block footerjs %}
  1799.     <script>
  1800.         (function(){
  1801.             'use strict';
  1802.             try {
  1803.                 var LOCALE = '{{ app.request.locale }}';
  1804.                 var IS_AUTHENTICATED = {{ app.user ? 'true' : 'false' }};
  1805.                 var SEARCH_API_URL = '{{ app.request.locale == \"en\" ? path(\"cvs_application_jobs_api_search\") : path(\"locale_cvs_application_jobs_api_search\",{\"_locale\":app.request.locale}) }}';
  1806.                 var JOB_SHOW_URL_TEMPLATE = '{{ app.request.locale == \"en\" ? path(\"cvs_application_jobs_api_search\",{\"slug\":\"__SLUG__\"}) : path(\"locale_cvs_application_job_show\",{\"_locale\":app.request.locale,\"slug\":\"__SLUG__\"}) }}';
  1807.                 var PAGE_SIZE = 10;
  1808.                 var currentQuery = {{ initialQuery|default('')|json_encode|raw }};
  1809.                 var currentOffset = 0;
  1810.                 var currentTotal = 0;
  1811.                 var isFetching = false;
  1812.                 // Contexte ville (vient du serveur si on est sur /jobs/paris/... sinon vide)
  1813.                 var CITY_KEYWORD = {{ currentCityKeyword|default('')|json_encode|raw }};
  1814.                 // Slug ville pour générer les URLs de redirection au submit
  1815.                 var CITY_SLUG = {{ currentCityFilter is defined and currentCityFilter is not null ? currentCityFilter.slug|json_encode|raw : 'null' }};
  1816.                 // URL pour le dashboard global (sans ville)
  1817.                 var DASHBOARD_URL = '{{ app.request.locale == \"en\" ? path(\"whileresume_jobs_list\") : path(\"locale_whileresume_jobs_list\",{\"_locale\":app.request.locale}) }}';
  1818.                 // Templates URL pour /jobs/{citySlug} et /jobs/{citySlug}/{keyword}
  1819.                 var CITY_LANDING_URL_TEMPLATE = {{ currentCityFilter is defined and currentCityFilter is not null
  1820.                 ? (app.request.locale == 'en'
  1821.                 ? path('cvs_application_jobs_filter',{'slug':currentCityFilter.slug})
  1822.                 : path('locale_cvs_application_jobs_filter',{'_locale':app.request.locale,'slug':currentCityFilter.slug}))|json_encode|raw
  1823.                 : 'null' }};
  1824.                 var CITY_KEYWORD_URL_TEMPLATE = {{ currentCityFilter is defined and currentCityFilter is not null
  1825.                 ? (app.request.locale == 'en'
  1826.                 ? path('cvs_application_jobs_filter_keyword',{'slug':currentCityFilter.slug,'keyword':'kwplaceholder'})
  1827.                 : path('locale_cvs_application_jobs_filter_keyword',{'_locale':app.request.locale,'slug':currentCityFilter.slug,'keyword':'kwplaceholder'}))|json_encode|raw
  1828.                 : 'null' }};
  1829.                 // Liste des keywords BDD avec leur slug (pour le matching côté client au submit)
  1830.                 var KEYWORDS_DATA = [
  1831.                     {% for kw in searchKeywords|default([]) %}
  1832.                     {% set kwSlugForJs = kw.label
  1833.                         |replace({
  1834.                         'à':'a','â':'a','ä':'a','á':'a','ã':'a','å':'a',
  1835.                         'À':'a','Â':'a','Ä':'a','Á':'a','Ã':'a','Å':'a',
  1836.                         'é':'e','è':'e','ê':'e','ë':'e','ẽ':'e',
  1837.                         'É':'e','È':'e','Ê':'e','Ë':'e',
  1838.                         'î':'i','ï':'i','ì':'i','í':'i',
  1839.                         'Î':'i','Ï':'i','Ì':'i','Í':'i',
  1840.                         'ô':'o','ö':'o','ò':'o','ó':'o','õ':'o','ø':'o',
  1841.                         'Ô':'o','Ö':'o','Ò':'o','Ó':'o','Õ':'o','Ø':'o',
  1842.                         'û':'u','ü':'u','ù':'u','ú':'u',
  1843.                         'Û':'u','Ü':'u','Ù':'u','Ú':'u',
  1844.                         'ÿ':'y','ý':'y','Ÿ':'y','Ý':'y',
  1845.                         'ç':'c','Ç':'c','ñ':'n','Ñ':'n',
  1846.                         'œ':'oe','Œ':'oe','æ':'ae','Æ':'ae',
  1847.                         \"'\":'-',' ':'-','/':'-','_':'-','.':'-',',':'-',
  1848.                         '(':'','*':'',')':'','&':'-and-','+':'-plus-',
  1849.                         '#':'','?':'','!':'','\"':'','’':'-','`':'-'
  1850.                     })
  1851.                         |lower
  1852.                         |replace({'--':'-','---':'-'})
  1853.                         |trim('-') %}
  1854.                     { label: {{ kw.label|json_encode|raw }}, searchKeyword: {{ (kw.searchKeyword ?: kw.label)|json_encode|raw }}, slug: {{ kwSlugForJs|json_encode|raw }} }{% if not loop.last %},{% endif %}
  1855.                     {% endfor %}
  1856.                 ];
  1857.                 var input = document.getElementById('dashSearchInput');
  1858.                 var clearBtn = document.getElementById('dashSearchClear');
  1859.                 var listEl = document.getElementById('jobsList');
  1860.                 var infoEl = document.getElementById('jobsResultsCount');
  1861.                 var loadMoreBtn = document.getElementById('jobsLoadMore');
  1862.                 var loadMoreLabel = document.getElementById('jobsLoadMoreLabel');
  1863.                 function escapeHtml(s){
  1864.                     if(s == null) return '';
  1865.                     return String(s).replace(/[&<>\"']/g, function(c){
  1866.                         return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];
  1867.                     });
  1868.                 }
  1869.                 function buildJobCard(item){
  1870.                     // Fallback logo : icône \"immeuble\" stylisée si pas de logo entreprise
  1871.                     var fallbackLogo =
  1872.                         '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +
  1873.                         '<path d=\"M3 21h18\"/>' +
  1874.                         '<path d=\"M5 21V7l8-4v18\"/>' +
  1875.                         '<path d=\"M19 21V11l-6-4\"/>' +
  1876.                         '<path d=\"M9 9h.01\"/>' +
  1877.                         '<path d=\"M9 13h.01\"/>' +
  1878.                         '<path d=\"M9 17h.01\"/>' +
  1879.                         '</svg>';
  1880.                     var logoHtml = item.logo
  1881.                         ? '<img src=\"' + escapeHtml(item.logo) + '\" alt=\"\" onerror=\"this.parentNode.innerHTML=\\'' + fallbackLogo.replace(/'/g, \"\\\\'\") + '\\';\">'
  1882.                         : fallbackLogo;
  1883.                     var meta = [];
  1884.                     if(item.companyName) meta.push(escapeHtml(item.companyName));
  1885.                     if(item.city) meta.push(escapeHtml(item.city));
  1886.                     if(item.employmentType) meta.push(escapeHtml(item.employmentType));
  1887.                     var salaryHtml = (item.salaryMin && item.salaryMax)
  1888.                         ? '<span class=\"jobs-card-salary\">' + item.salaryMin + '–' + item.salaryMax + ' ' + escapeHtml(item.devise || '') + '</span>'
  1889.                         : '';
  1890.                     var url = item.url || JOB_SHOW_URL_TEMPLATE.replace('__SLUG__', encodeURIComponent(item.slug));
  1891.                     var a = document.createElement('a');
  1892.                     a.href = url;
  1893.                     a.className = 'jobs-card';
  1894.                     a.innerHTML =
  1895.                         '<div class=\"jobs-card-logo\">' + logoHtml + '</div>' +
  1896.                         '<div class=\"jobs-card-info\">' +
  1897.                         '<div class=\"jobs-card-title\">' + escapeHtml(item.title || '') + '</div>' +
  1898.                         '<div class=\"jobs-card-meta\">' + meta.join(' · ') + '</div>' +
  1899.                         '</div>' +
  1900.                         salaryHtml +
  1901.                         '<span class=\"jobs-card-arrow\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"/></svg></span>';
  1902.                     return a;
  1903.                 }
  1904.                 /**
  1905.                  * Clone la promo card depuis le <template> rendu par la macro Twig.
  1906.                  * Le HTML est défini une seule fois dans _macros/promo_card.html.twig.
  1907.                  * Retourne null si le template n'est pas présent (ex: user connecté).
  1908.                  */
  1909.                 function buildPromoCard(){
  1910.                     var tpl = document.getElementById('jobs-promo-card-template');
  1911.                     if(!tpl || !tpl.content) return null;
  1912.                     var node = tpl.content.firstElementChild;
  1913.                     return node ? node.cloneNode(true) : null;
  1914.                 }
  1915.                 function renderEmpty(){
  1916.                     listEl.innerHTML =
  1917.                         '<div class=\"jobs-empty\">' +
  1918.                         '<div class=\"jobs-empty-icon\">' +
  1919.                         '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>' +
  1920.                         '</div>' +
  1921.                         '<div class=\"jobs-empty-title\">{{ 'job.dashboard.emptyTitle'|trans|escape('js') }}</div>' +
  1922.                         '<div class=\"jobs-empty-text\">{{ 'job.dashboard.emptyText'|trans|escape('js') }}</div>' +
  1923.                         '</div>';
  1924.                 }
  1925.                 function setLoadMoreState(state){
  1926.                     if(!loadMoreBtn) return;
  1927.                     if(state === 'loading'){
  1928.                         loadMoreBtn.classList.add('loading');
  1929.                         loadMoreBtn.disabled = true;
  1930.                         loadMoreLabel.innerHTML = '<span class=\"jobs-load-spinner\"></span> {{ 'job.dashboard.loadingMore'|trans|escape('js') }}';
  1931.                     } else {
  1932.                         loadMoreBtn.classList.remove('loading');
  1933.                         loadMoreBtn.disabled = false;
  1934.                         loadMoreLabel.textContent = '{{ 'job.dashboard.loadMore'|trans|escape('js') }}';
  1935.                     }
  1936.                 }
  1937.                 function fetchJobs(query, offset, append){
  1938.                     if(isFetching) return;
  1939.                     isFetching = true;
  1940.                     if(!append){
  1941.                         // Nouvelle recherche : on remet à zéro et affiche skeleton
  1942.                         listEl.innerHTML =
  1943.                             '<div class=\"jobs-skeleton\">' +
  1944.                             Array(5).fill(0).map(function(){
  1945.                                 return '<div class=\"jobs-skel-card\"><div class=\"jobs-skel-logo\"></div><div class=\"jobs-skel-info\"><div class=\"jobs-skel-line s1\"></div><div class=\"jobs-skel-line s2\"></div></div></div>';
  1946.                             }).join('') +
  1947.                             '</div>';
  1948.                         if(infoEl) infoEl.textContent = '{{ 'job.dashboard.loading'|trans|escape('js') }}';
  1949.                         if(loadMoreBtn) loadMoreBtn.style.display = 'none';
  1950.                     } else {
  1951.                         setLoadMoreState('loading');
  1952.                     }
  1953.                     var url = SEARCH_API_URL + '?q=' + encodeURIComponent(query || '') + '&locale=' + LOCALE + '&limit=' + PAGE_SIZE + '&offset=' + offset;
  1954.                     if(CITY_KEYWORD){ url += '&city=' + encodeURIComponent(CITY_KEYWORD); }
  1955.                     // Dashboard sans filtre : on demande explicitement les dernières offres
  1956.                     if(!query && !CITY_KEYWORD){ url += '&all=1'; }
  1957.                     fetch(url, {headers:{'Accept':'application/json'}})
  1958.                         .then(function(r){ return r.ok ? r.json() : null; })
  1959.                         .then(function(data){
  1960.                             isFetching = false;
  1961.                             if(!data){
  1962.                                 if(!append) renderEmpty();
  1963.                                 setLoadMoreState('idle');
  1964.                                 return;
  1965.                             }
  1966.                             var items = data.items || [];
  1967.                             currentTotal = data.total || 0;
  1968.                             if(!append){
  1969.                                 listEl.innerHTML = '';
  1970.                                 if(items.length === 0){
  1971.                                     renderEmpty();
  1972.                                     if(infoEl) infoEl.innerHTML = '<strong>0</strong> {{ 'job.dashboard.resultsCount'|trans|escape('js') }}';
  1973.                                     if(loadMoreBtn) loadMoreBtn.style.display = 'none';
  1974.                                     return;
  1975.                                 }
  1976.                             }
  1977.                             // Insérer la promo card après la 5ème offre (uniquement au 1er chargement,
  1978.                             // si user non connecté et qu'on a au moins 5 offres)
  1979.                             var insertPromoAt = (!append && !IS_AUTHENTICATED && items.length >= 5) ? 5 : -1;
  1980.                             items.forEach(function(item, idx){
  1981.                                 listEl.appendChild(buildJobCard(item));
  1982.                                 if(idx === insertPromoAt - 1){
  1983.                                     var promoNode = buildPromoCard();
  1984.                                     if(promoNode) listEl.appendChild(promoNode);
  1985.                                 }
  1986.                             });
  1987.                             currentOffset = offset + items.length;
  1988.                             if(infoEl){
  1989.                                 infoEl.innerHTML = '<strong>' + currentTotal + '</strong> {{ 'job.dashboard.resultsCount'|trans|escape('js') }}';
  1990.                             }
  1991.                             // Afficher / cacher \"Charger plus\"
  1992.                             if(loadMoreBtn){
  1993.                                 if(currentOffset < currentTotal){
  1994.                                     loadMoreBtn.style.display = 'flex';
  1995.                                 } else {
  1996.                                     loadMoreBtn.style.display = 'none';
  1997.                                 }
  1998.                                 setLoadMoreState('idle');
  1999.                             }
  2000.                         })
  2001.                         .catch(function(err){
  2002.                             isFetching = false;
  2003.                             console.error('[whr-dash] fetch error', err);
  2004.                             setLoadMoreState('idle');
  2005.                         });
  2006.                 }
  2007.                 /**
  2008.                  * Slugifie un texte côté client. DOIT produire EXACTEMENT le même slug
  2009.                  * que la méthode PHP slugify() du JobsController et que le filtre Twig
  2010.                  * utilisé pour rendre les chips.
  2011.                  */
  2012.                 function slugify(text){
  2013.                     if(!text) return '';
  2014.                     var t = String(text);
  2015.                     // Pré-remplacements sémantiques
  2016.                     t = t.replace(/&/g, '-and-').replace(/\\+/g, '-plus-')
  2017.                         .replace(/[œŒ]/g, 'oe').replace(/[æÆ]/g, 'ae');
  2018.                     // Translitération accents → ASCII via NFD + strip diacritics
  2019.                     t = t.normalize ? t.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '') : t;
  2020.                     t = t.toLowerCase();
  2021.                     // Tout ce qui n'est pas a-z 0-9 → tiret
  2022.                     t = t.replace(/[^a-z0-9]+/g, '-');
  2023.                     return t.replace(/^-+|-+\$/g, '');
  2024.                 }
  2025.                 /**
  2026.                  * Tente de matcher un texte tapé avec un keyword en BDD (par slug ou label).
  2027.                  * Retourne l'objet keyword si trouvé, null sinon.
  2028.                  */
  2029.                 function findMatchingKeyword(text){
  2030.                     if(!text || !KEYWORDS_DATA || !KEYWORDS_DATA.length) return null;
  2031.                     var slug = slugify(text);
  2032.                     if(!slug) return null;
  2033.                     for(var i = 0; i < KEYWORDS_DATA.length; i++){
  2034.                         var kw = KEYWORDS_DATA[i];
  2035.                         // Match sur slug exact OU label/searchKeyword exact (case insensitive)
  2036.                         if(kw.slug === slug) return kw;
  2037.                         if(slugify(kw.searchKeyword) === slug) return kw;
  2038.                     }
  2039.                     return null;
  2040.                 }
  2041.                 /**
  2042.                  * Au submit : décide où rediriger l'utilisateur en fonction du contexte.
  2043.                  *  - Si on est sur une ville et le texte matche un keyword BDD → /jobs/{ville}/{slug-kw}
  2044.                  *  - Sinon si on est sur une ville → /jobs/{ville}?search={texte}
  2045.                  *  - Sinon (pas de ville) → /jobs?q={texte}
  2046.                  *  - Si texte vide ET ville définie → /jobs/{ville} (reset)
  2047.                  *  - Si texte vide ET pas de ville → /jobs (reset)
  2048.                  */
  2049.                 function submitSearch(query){
  2050.                     query = (query || '').trim();
  2051.                     // Reset (recherche vide)
  2052.                     if(!query){
  2053.                         if(CITY_SLUG && CITY_LANDING_URL_TEMPLATE){
  2054.                             window.location.href = CITY_LANDING_URL_TEMPLATE;
  2055.                         } else {
  2056.                             window.location.href = DASHBOARD_URL;
  2057.                         }
  2058.                         return;
  2059.                     }
  2060.                     // Cas 1 : on est sur une ville
  2061.                     if(CITY_SLUG && CITY_KEYWORD_URL_TEMPLATE){
  2062.                         var matched = findMatchingKeyword(query);
  2063.                         if(matched && matched.slug){
  2064.                             // Match BDD → URL slug propre /jobs/paris/developpeur
  2065.                             window.location.href = CITY_KEYWORD_URL_TEMPLATE.replace('kwplaceholder', encodeURIComponent(matched.slug));
  2066.                             return;
  2067.                         }
  2068.                         // Pas de match → fallback ?search=texte
  2069.                         window.location.href = CITY_LANDING_URL_TEMPLATE + '?search=' + encodeURIComponent(query);
  2070.                         return;
  2071.                     }
  2072.                     // Cas 2 : pas de ville → dashboard global avec ?q=
  2073.                     window.location.href = DASHBOARD_URL + '?q=' + encodeURIComponent(query);
  2074.                 }
  2075.                 /**
  2076.                  * Lance la search côté UI (sans redirection — utilisée pour les chips et
  2077.                  * pour la \"Charger plus\").
  2078.                  */
  2079.                 function startSearch(query){
  2080.                     currentQuery = query;
  2081.                     currentOffset = 0;
  2082.                     currentTotal = 0;
  2083.                     fetchJobs(query, 0, false);
  2084.                     // Update clear button
  2085.                     if(clearBtn){
  2086.                         if(query) clearBtn.classList.add('visible');
  2087.                         else clearBtn.classList.remove('visible');
  2088.                     }
  2089.                     // Update active chip (uniquement les chips qui sont des <button>, pas les <a>)
  2090.                     document.querySelectorAll('button.search-keyword-chip').forEach(function(c){
  2091.                         if(c.getAttribute('data-keyword') === query) c.classList.add('active');
  2092.                         else c.classList.remove('active');
  2093.                     });
  2094.                 }
  2095.                 // ═══ Submit-only : Entrée déclenche la search ET change l'URL ═══
  2096.                 if(input){
  2097.                     input.addEventListener('keydown', function(e){
  2098.                         if(e.key === 'Enter' || e.keyCode === 13){
  2099.                             e.preventDefault();
  2100.                             submitSearch(input.value);
  2101.                         }
  2102.                     });
  2103.                     // Affiche bouton clear si query initiale
  2104.                     if(input.value.trim()){
  2105.                         if(clearBtn) clearBtn.classList.add('visible');
  2106.                     }
  2107.                 }
  2108.                 // Bouton clear : reset complet → redirection vers /jobs ou /jobs/{ville}
  2109.                 if(clearBtn){
  2110.                     clearBtn.addEventListener('click', function(){
  2111.                         submitSearch('');
  2112.                     });
  2113.                 }
  2114.                 // Chips keywords (cas dashboard global, sans contexte ville → comportement local)
  2115.                 // En contexte ville, les chips sont des <a href> directs gérés par le navigateur.
  2116.                 document.querySelectorAll('button.search-keyword-chip').forEach(function(chip){
  2117.                     chip.addEventListener('click', function(){
  2118.                         var kw = chip.getAttribute('data-keyword');
  2119.                         if(!kw) return;
  2120.                         // Sur dashboard global : on submit (redirige vers /jobs?q=kw)
  2121.                         submitSearch(kw);
  2122.                     });
  2123.                 });
  2124.                 // Bouton \"Charger plus\"
  2125.                 if(loadMoreBtn){
  2126.                     loadMoreBtn.addEventListener('click', function(){
  2127.                         if(isFetching) return;
  2128.                         fetchJobs(currentQuery, currentOffset, true);
  2129.                     });
  2130.                 }
  2131.                 // ═══ Bouton \"Voir plus\" + Recherche live des chips ═══
  2132.                 /**
  2133.                  * Slugify simple côté UI pour matching tolérant aux accents
  2134.                  * (ex: \"developpeur\" matche \"Développeur\")
  2135.                  */
  2136.                 function dashSlug(str){
  2137.                     if(!str) return '';
  2138.                     var t = String(str);
  2139.                     t = t.normalize ? t.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '') : t;
  2140.                     return t.toLowerCase().trim();
  2141.                 }
  2142.                 document.querySelectorAll('.dash-filter-more-btn').forEach(function(btn){
  2143.                     var targetId = btn.getAttribute('data-target');
  2144.                     var sectionId = btn.getAttribute('data-section');
  2145.                     var container = document.getElementById(targetId);
  2146.                     var section = sectionId ? document.getElementById(sectionId) : null;
  2147.                     if(!container) return;
  2148.                     var label = btn.querySelector('.dash-filter-more-label');
  2149.                     if(!label) return;
  2150.                     var initial = parseInt(container.getAttribute('data-initial'), 10) || 14;
  2151.                     var items = container.querySelectorAll('.dash-filter-item');
  2152.                     var searchInput = section ? section.querySelector('.dash-filter-search-input') : null;
  2153.                     // 2 états indépendants :
  2154.                     //  - userExpanded : l'utilisateur a cliqué sur \"Voir plus\"
  2155.                     //  - searchActive : l'input contient du texte (auto-expand temporaire)
  2156.                     // Mode développé = userExpanded || searchActive
  2157.                     var userExpanded = false;
  2158.                     function isEffectivelyExpanded(){
  2159.                         var hasSearch = searchInput && searchInput.value.trim().length > 0;
  2160.                         return userExpanded || hasSearch;
  2161.                     }
  2162.                     function applyDisplay(){
  2163.                         var filterText = searchInput ? searchInput.value : '';
  2164.                         var query = dashSlug(filterText || '');
  2165.                         var expanded = isEffectivelyExpanded();
  2166.                         var visibleCount = 0;
  2167.                         items.forEach(function(it, i){
  2168.                             var label = it.getAttribute('data-filter-label') || '';
  2169.                             var matches = !query || dashSlug(label).indexOf(query) !== -1;
  2170.                             if(expanded){
  2171.                                 // Mode développé : on affiche tous les items qui matchent la recherche
  2172.                                 it.style.display = matches ? '' : 'none';
  2173.                                 if(matches) visibleCount++;
  2174.                             } else {
  2175.                                 // Mode collapsé : on affiche les N premiers (pas de filtrage)
  2176.                                 it.style.display = (i < initial) ? '' : 'none';
  2177.                                 if(i < initial) visibleCount++;
  2178.                             }
  2179.                         });
  2180.                         // Toggle \"aucun résultat\" (uniquement quand recherche active)
  2181.                         if(query && visibleCount === 0){
  2182.                             container.classList.add('is-no-results');
  2183.                         } else {
  2184.                             container.classList.remove('is-no-results');
  2185.                         }
  2186.                         // Synchroniser le bouton \"Voir plus/moins\" avec l'état effectif
  2187.                         if(expanded){
  2188.                             btn.classList.add('is-expanded');
  2189.                             label.textContent = label.getAttribute('data-less');
  2190.                         } else {
  2191.                             btn.classList.remove('is-expanded');
  2192.                             label.textContent = label.getAttribute('data-more');
  2193.                         }
  2194.                     }
  2195.                     btn.addEventListener('click', function(){
  2196.                         userExpanded = !userExpanded;
  2197.                         if(!userExpanded){
  2198.                             // Reset input quand l'utilisateur collapse manuellement
  2199.                             if(searchInput){ searchInput.value = ''; }
  2200.                             // Scroll vers le bouton
  2201.                             btn.scrollIntoView({behavior:'smooth', block:'nearest'});
  2202.                         }
  2203.                         applyDisplay();
  2204.                     });
  2205.                     // Recherche live dans les chips quand on tape dans l'input
  2206.                     // → auto-expand pendant la recherche, retour à l'état userExpanded quand on vide
  2207.                     if(searchInput){
  2208.                         searchInput.addEventListener('input', function(){
  2209.                             applyDisplay();
  2210.                         });
  2211.                     }
  2212.                 });
  2213.                 // Premier chargement (vide ou avec query initiale)
  2214.                 fetchJobs(currentQuery, 0, false);
  2215.             } catch(err){
  2216.                 console.error('[whr-dash] init error', err);
  2217.             }
  2218.         })();
  2219.     </script>
  2220. {% endblock footerjs %}
  2221. ""application/whileresume/application/jobs/dashboard.html.twig""/var/www/vhosts/mirtillostudio.fr/b1.mirtillostudio.fr/version-1/templates/application/whileresume/application/jobs/dashboard.html.twig");
  2222.     }
  2223. }